phase4: add standalone source wrappers and mark checklist progress

Register new all/en standalone wrappers from base sources and add initial smoke tests; several sources are still unverified in live environment.
This commit is contained in:
achmad
2026-05-11 13:36:36 +07:00
parent 90fd773ff1
commit 1f7e229493
22 changed files with 474 additions and 19 deletions
+19
View File
@@ -9,6 +9,25 @@ import (
"goyomi/internal/config" "goyomi/internal/config"
"goyomi/internal/db" "goyomi/internal/db"
_ "goyomi/internal/registry" _ "goyomi/internal/registry"
_ "goyomi/sources/all/hentaihand"
_ "goyomi/sources/all/kemono"
_ "goyomi/sources/all/mangataro"
_ "goyomi/sources/en/bakkin"
_ "goyomi/sources/en/divascans"
_ "goyomi/sources/en/guya"
_ "goyomi/sources/en/hijalascans"
_ "goyomi/sources/en/kaizenscan"
_ "goyomi/sources/en/kewnscans"
_ "goyomi/sources/en/lunatoons"
_ "goyomi/sources/en/mistscans"
_ "goyomi/sources/en/necroscans"
_ "goyomi/sources/en/nyanukafe"
_ "goyomi/sources/en/nyxscans"
_ "goyomi/sources/en/orionscans"
_ "goyomi/sources/en/renascans"
_ "goyomi/sources/en/sanascans"
_ "goyomi/sources/en/sirenscans"
_ "goyomi/sources/en/vanillascans"
) )
func main() { func main() {
+19 -19
View File
@@ -53,7 +53,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `all/hentaienvy` - [ ] `all/hentaienvy`
- [ ] `all/hentaiera` - [ ] `all/hentaiera`
- [ ] `all/hentaifox` - [ ] `all/hentaifox`
- [ ] `all/hentaihand` - [x] `all/hentaihand`
- [ ] `all/hentairox` - [ ] `all/hentairox`
- [ ] `all/hentaizap` - [ ] `all/hentaizap`
- [ ] `all/hniscantrad` - [ ] `all/hniscantrad`
@@ -64,7 +64,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `all/jjcos` - [ ] `all/jjcos`
- [ ] `all/joymiihub` - [ ] `all/joymiihub`
- [ ] `all/junmeitu` - [ ] `all/junmeitu`
- [ ] `all/kemono` ⚠️ see notes - [x] `all/kemono` ⚠️ see notes
- [ ] `all/kiutaku` - [ ] `all/kiutaku`
- [ ] `all/kodokustudio` - [ ] `all/kodokustudio`
- [ ] `all/koharu` - [ ] `all/koharu`
@@ -83,7 +83,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `all/mangaforfree` - [ ] `all/mangaforfree`
- [ ] `all/mangaplus` ⚠️ see notes - [ ] `all/mangaplus` ⚠️ see notes
- [ ] `all/mangapluscreators` - [ ] `all/mangapluscreators`
- [ ] `all/mangataro` - [x] `all/mangataro`
- [ ] `all/mangatoon` - [ ] `all/mangatoon`
- [ ] `all/mangaup` - [ ] `all/mangaup`
- [ ] `all/mango` - [ ] `all/mango`
@@ -170,7 +170,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/azcomic` - [ ] `en/azcomic`
- [ ] `en/azuki` - [ ] `en/azuki`
- [ ] `en/baektoons` - [ ] `en/baektoons`
- [ ] `en/bakkin` ⚠️ see notes - [x] `en/bakkin` ⚠️ see notes
- [ ] `en/bakkinselfhosted` - [ ] `en/bakkinselfhosted`
- [ ] `en/batcave` - [ ] `en/batcave`
- [ ] `en/battleinfivesecondsaftermeeting` - [ ] `en/battleinfivesecondsaftermeeting`
@@ -208,7 +208,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/decadencescans` - [ ] `en/decadencescans`
- [ ] `en/dflowscans` - [ ] `en/dflowscans`
- [ ] `en/digitalcomicmuseum` - [ ] `en/digitalcomicmuseum`
- [ ] `en/divascans` - [x] `en/divascans`
- [ ] `en/doujinio` - [ ] `en/doujinio`
- [ ] `en/doujins` - [ ] `en/doujins`
- [ ] `en/dragontea` - [ ] `en/dragontea`
@@ -246,7 +246,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/grimscans` - [ ] `en/grimscans`
- [ ] `en/grrlpower` - [ ] `en/grrlpower`
- [ ] `en/gunnerkriggcourt` - [ ] `en/gunnerkriggcourt`
- [ ] `en/guya` ⚠️ see notes - [x] `en/guya` ⚠️ see notes
- [ ] `en/gwtb` - [ ] `en/gwtb`
- [ ] `en/hachirumi` - [ ] `en/hachirumi`
- [ ] `en/hadesscans` - [ ] `en/hadesscans`
@@ -265,7 +265,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/hentaixyuri` - [ ] `en/hentaixyuri`
- [ ] `en/hentara` - [ ] `en/hentara`
- [ ] `en/heytoon` - [ ] `en/heytoon`
- [ ] `en/hijalascans` - [x] `en/hijalascans`
- [ ] `en/hiperdex` - [ ] `en/hiperdex`
- [ ] `en/hiveworks` - [ ] `en/hiveworks`
- [ ] `en/hm2d` - [ ] `en/hm2d`
@@ -279,7 +279,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/jinmangas` - [ ] `en/jinmangas`
- [ ] `en/jnovel` - [ ] `en/jnovel`
- [ ] `en/kagane` - [ ] `en/kagane`
- [ ] `en/kaizenscan` - [x] `en/kaizenscan`
- [ ] `en/kaliscancom` - [ ] `en/kaliscancom`
- [ ] `en/kaliscanio` - [ ] `en/kaliscanio`
- [ ] `en/kaliscanme` - [ ] `en/kaliscanme`
@@ -287,7 +287,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/kaynscans` - [ ] `en/kaynscans`
- [ ] `en/keenspot` - [ ] `en/keenspot`
- [ ] `en/kenscans` - [ ] `en/kenscans`
- [ ] `en/kewnscans` - [x] `en/kewnscans`
- [ ] `en/killsixbilliondemons` - [ ] `en/killsixbilliondemons`
- [ ] `en/kingcomix` - [ ] `en/kingcomix`
- [ ] `en/kingofshojo` - [ ] `en/kingofshojo`
@@ -307,7 +307,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/loadingartist` - [ ] `en/loadingartist`
- [ ] `en/luascans` - [ ] `en/luascans`
- [ ] `en/luminaretranslations` - [ ] `en/luminaretranslations`
- [ ] `en/lunatoons` - [x] `en/lunatoons`
- [ ] `en/madaradex` - [ ] `en/madaradex`
- [ ] `en/madarascans` - [ ] `en/madarascans`
- [ ] `en/madokami` - [ ] `en/madokami`
@@ -422,7 +422,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/mgjinx` - [ ] `en/mgjinx`
- [ ] `en/mgreadio` - [ ] `en/mgreadio`
- [ ] `en/milftoon` - [ ] `en/milftoon`
- [ ] `en/mistscans` - [x] `en/mistscans`
- [ ] `en/mlbblore` - [ ] `en/mlbblore`
- [ ] `en/monochromecustom` - [ ] `en/monochromecustom`
- [ ] `en/monochromescans` - [ ] `en/monochromescans`
@@ -430,7 +430,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/murimscan` - [ ] `en/murimscan`
- [ ] `en/myhentaicomics` - [ ] `en/myhentaicomics`
- [ ] `en/myhentaigallery` - [ ] `en/myhentaigallery`
- [ ] `en/necroscans` - [x] `en/necroscans`
- [ ] `en/newmanhwa` - [ ] `en/newmanhwa`
- [ ] `en/nexcomic` - [ ] `en/nexcomic`
- [ ] `en/nikatoons` - [ ] `en/nikatoons`
@@ -441,9 +441,9 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/novelcrow` - [ ] `en/novelcrow`
- [ ] `en/noxenscans` - [ ] `en/noxenscans`
- [ ] `en/nuxscans` - [ ] `en/nuxscans`
- [ ] `en/nyanukafe` - [x] `en/nyanukafe`
- [ ] `en/nyrascans` - [ ] `en/nyrascans`
- [ ] `en/nyxscans` - [x] `en/nyxscans`
- [ ] `en/octopusmanga` - [ ] `en/octopusmanga`
- [ ] `en/oglaf` - [ ] `en/oglaf`
- [ ] `en/ohjoysextoy` - [ ] `en/ohjoysextoy`
@@ -455,7 +455,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/oots` - [ ] `en/oots`
- [ ] `en/oppaistream` - [ ] `en/oppaistream`
- [ ] `en/orchisasia` - [ ] `en/orchisasia`
- [ ] `en/orionscans` - [x] `en/orionscans`
- [ ] `en/paradisescans` - [ ] `en/paradisescans`
- [ ] `en/paragonscans` - [ ] `en/paragonscans`
- [ ] `en/paritehaber` - [ ] `en/paritehaber`
@@ -494,7 +494,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/readvagabondmanga` - [ ] `en/readvagabondmanga`
- [ ] `en/reallifecomics` - [ ] `en/reallifecomics`
- [ ] `en/reimanga` - [ ] `en/reimanga`
- [ ] `en/renascans` - [x] `en/renascans`
- [ ] `en/resetscans` - [ ] `en/resetscans`
- [ ] `en/restscans` - [ ] `en/restscans`
- [ ] `en/retsu` - [ ] `en/retsu`
@@ -508,13 +508,13 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/rosesquadscans` - [ ] `en/rosesquadscans`
- [ ] `en/ryumanga` - [ ] `en/ryumanga`
- [ ] `en/s2manga` - [ ] `en/s2manga`
- [ ] `en/sanascans` - [x] `en/sanascans`
- [ ] `en/saturdaymorningbreakfastcomics` - [ ] `en/saturdaymorningbreakfastcomics`
- [ ] `en/schlockmercenary` - [ ] `en/schlockmercenary`
- [ ] `en/setsuscans` - [ ] `en/setsuscans`
- [ ] `en/shibamanga` - [ ] `en/shibamanga`
- [ ] `en/shojoscans` - [ ] `en/shojoscans`
- [ ] `en/sirenscans` - [x] `en/sirenscans`
- [ ] `en/skymanga` - [ ] `en/skymanga`
- [ ] `en/sleepytranslations` - [ ] `en/sleepytranslations`
- [ ] `en/solarandsundry` - [ ] `en/solarandsundry`
@@ -547,7 +547,7 @@ Detailed implementation notes for complex sources are in the **Notes** section a
- [ ] `en/tritiniascans` - [ ] `en/tritiniascans`
- [ ] `en/utoon` - [ ] `en/utoon`
- [ ] `en/valirscans` - [ ] `en/valirscans`
- [ ] `en/vanillascans` - [x] `en/vanillascans`
- [ ] `en/vgperson` - [ ] `en/vgperson`
- [ ] `en/vizshonenjump` - [ ] `en/vizshonenjump`
- [ ] `en/voyceme` - [ ] `en/voyceme`
+18
View File
@@ -0,0 +1,18 @@
package hentaihand
import (
"goyomi/internal/registry"
base "goyomi/sources/base/hentaihand"
)
func New() *base.Source {
return base.New(base.Config{
Name: "HentaiHand",
BaseURL: "https://hentaihand.com",
Lang: "all",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package kemono
import (
"goyomi/internal/registry"
base "goyomi/sources/base/kemono"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Kemono",
BaseURL: "https://kemono.cr",
Lang: "all",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package mangataro
import (
"goyomi/internal/registry"
base "goyomi/sources/base/mangataro"
)
func New() *base.Source {
return base.New(base.Config{
Name: "MangaTaro",
BaseURL: "https://mangataro.org",
Lang: "en",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package bakkin
import (
"goyomi/internal/registry"
base "goyomi/sources/base/bakkin"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Bakkin",
BaseURL: "https://bakkin.moe/reader/",
Lang: "en",
})
}
func init() {
registry.Register(New())
}
+19
View File
@@ -0,0 +1,19 @@
package divascans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/iken"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Diva Scans",
BaseURL: "https://divatoon.com",
Lang: "en",
APIURL: "https://api.divatoon.com",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package guya
import (
"goyomi/internal/registry"
base "goyomi/sources/base/guya"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Guya",
BaseURL: "https://guya.cubari.moe",
Lang: "en",
})
}
func init() {
registry.Register(New())
}
+19
View File
@@ -0,0 +1,19 @@
package hijalascans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/iken"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Hijala Scans",
BaseURL: "https://en-hijala.com",
Lang: "en",
APIURL: "https://api.en-hijala.com",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package kaizenscan
import (
"goyomi/internal/registry"
base "goyomi/sources/base/keyoapp"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Kaizen Scan",
BaseURL: "https://kaizenscan.com",
Lang: "en",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package kewnscans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/keyoapp"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Kewn Scans",
BaseURL: "https://kewnscans.org",
Lang: "en",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package lunatoons
import (
"goyomi/internal/registry"
base "goyomi/sources/base/keyoapp"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Luna Toons",
BaseURL: "https://lunatoons.org",
Lang: "en",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package mistscans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/keyoapp"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Mist Scans",
BaseURL: "https://mistscans.com",
Lang: "en",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package necroscans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/keyoapp"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Necro Scans",
BaseURL: "https://necroscans.com",
Lang: "en",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package nyanukafe
import (
"goyomi/internal/registry"
base "goyomi/sources/base/keyoapp"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Nyanu Kafe",
BaseURL: "https://nyanukafe.com",
Lang: "en",
})
}
func init() {
registry.Register(New())
}
+19
View File
@@ -0,0 +1,19 @@
package nyxscans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/iken"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Nyx Scans",
BaseURL: "https://nyxscans.com",
Lang: "en",
APIURL: "https://api.nyxscans.com",
})
}
func init() {
registry.Register(New())
}
+19
View File
@@ -0,0 +1,19 @@
package orionscans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/iken"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Orion Scans",
BaseURL: "https://orion-scans.com",
Lang: "en",
APIURL: "https://api.orion-scans.com",
})
}
func init() {
registry.Register(New())
}
+19
View File
@@ -0,0 +1,19 @@
package renascans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/iken"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Renascans",
BaseURL: "https://renascans.net",
Lang: "en",
APIURL: "https://api.renascans.net",
})
}
func init() {
registry.Register(New())
}
+19
View File
@@ -0,0 +1,19 @@
package sanascans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/iken"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Sana Scans",
BaseURL: "https://sanascans.com",
Lang: "en",
APIURL: "https://api.sanascans.com",
})
}
func init() {
registry.Register(New())
}
+18
View File
@@ -0,0 +1,18 @@
package sirenscans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/keyoapp"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Siren Scans",
BaseURL: "https://sirenscans.com",
Lang: "en",
})
}
func init() {
registry.Register(New())
}
+19
View File
@@ -0,0 +1,19 @@
package vanillascans
import (
"goyomi/internal/registry"
base "goyomi/sources/base/iken"
)
func New() *base.Source {
return base.New(base.Config{
Name: "Vanilla Scans",
BaseURL: "https://vanillascans.org",
Lang: "en",
APIURL: "https://api.vanillascans.org",
})
}
func init() {
registry.Register(New())
}
+87
View File
@@ -0,0 +1,87 @@
package sources_test
import (
"os"
"testing"
"goyomi/internal/source"
"goyomi/sources/en/kaizenscan"
"goyomi/sources/en/kewnscans"
"goyomi/sources/en/lunatoons"
"goyomi/sources/en/mistscans"
"goyomi/sources/en/necroscans"
"goyomi/sources/en/nyanukafe"
"goyomi/sources/en/sirenscans"
)
type smokeCase struct {
name string
mode string
kotlinRef string
newSource func() source.CatalogueSource
}
func TestStandaloneKeyoappSmoke(t *testing.T) {
if os.Getenv("GOYOMI_SMOKE") != "1" {
t.Skip("set GOYOMI_SMOKE=1 to run live source smoke tests")
}
tests := []smokeCase{
{
name: "en/kaizenscan",
mode: "plain_http",
kotlinRef: "extensions-source/src/en/kaizenscan/.../KaizenScan.kt",
newSource: func() source.CatalogueSource { return kaizenscan.New() },
},
{
name: "en/kewnscans",
mode: "plain_http",
kotlinRef: "extensions-source/src/en/kewnscans/.../KewnScans.kt",
newSource: func() source.CatalogueSource { return kewnscans.New() },
},
{
name: "en/lunatoons",
mode: "plain_http",
kotlinRef: "extensions-source/src/en/lunatoons/.../LunaToons.kt",
newSource: func() source.CatalogueSource { return lunatoons.New() },
},
{
name: "en/mistscans",
mode: "plain_http",
kotlinRef: "extensions-source/src/en/mistscans/.../MistScans.kt",
newSource: func() source.CatalogueSource { return mistscans.New() },
},
{
name: "en/necroscans",
mode: "plain_http",
kotlinRef: "extensions-source/src/en/necroscans/.../NecroScans.kt",
newSource: func() source.CatalogueSource { return necroscans.New() },
},
{
name: "en/nyanukafe",
mode: "plain_http",
kotlinRef: "extensions-source/src/en/nyanukafe/.../NyanuKafe.kt",
newSource: func() source.CatalogueSource { return nyanukafe.New() },
},
{
name: "en/sirenscans",
mode: "plain_http",
kotlinRef: "extensions-source/src/en/sirenscans/.../SirenScans.kt",
newSource: func() source.CatalogueSource { return sirenscans.New() },
},
}
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
s := tc.newSource()
mp, err := s.GetPopularManga(1)
if err != nil {
t.Fatalf("mode=%s kotlin=%s popular failed: %v", tc.mode, tc.kotlinRef, err)
}
if len(mp.Mangas) == 0 {
t.Fatalf("mode=%s kotlin=%s popular returned 0 mangas", tc.mode, tc.kotlinRef)
}
})
}
}