Adds 67 missing en/ imports to main.go and marks their checkboxes in the phase4 checklist.
25 KiB
Executable File
Phase 4 — Standalone Sources
Complete port checklist. Check a box when the source passes a basic smoke test (popular/latest list returns ≥1 result, or detail+pages resolve for a known URL).
After implementing each source: mark its checkbox [x] in this doc and add it to the import list in cmd/server/main.go.
Important: Source Types
Base Sources (lib-multisrc)
Shared implementations in:
/Users/achmad/Documents/Belajar/Android/extensions-source/lib-multisrc//Users/achmad/Documents/Belajar/Web/goyomi/sources/base/
These are the core implementations that standalone sources may use.
Standalone Sources (all/ and en/)
Individual extensions in:
/Users/achmad/Documents/Belajar/Android/extensions-source/src/all//Users/achmad/Documents/Belajar/Android/extensions-source/src/en/
These may or may not use a base source from lib-multisrc — and even when they do, they often add their own
implementation on top (overriding methods, adding extra parsing, custom filters, etc.).
When porting, check if the Kotlin source extends a base class (e.g., MangaReader, Madara, ComicGeek) —
if so, use the corresponding Go base implementation as the foundation, then layer the source-specific overrides.
Otherwise, implement fully standalone.
Reference:
/Users/achmad/Documents/Belajar/Android/extensions-source/src/all//Users/achmad/Documents/Belajar/Android/extensions-source/src/en/
HTTP Client Architecture
The HTTP client uses a hybrid approach: httpcloak for Chrome TLS fingerprint emulation, with FlareSolverr as a fallback for challenge solving.
TLS Fingerprint Problem
Go's net/http has a different TLS fingerprint (JA3/JA4 ciphers, HTTP/2 settings) than Chrome.
When Go sends a cf_clearance cookie obtained from FlareSolverr's Chrome, Cloudflare rejects
it because the TLS fingerprint doesn't match Chrome's. Every direct request gets re-challenged.
The fix: use httpcloak as the transport, which mimics Chrome's TLS fingerprint perfectly.
Now when FlareSolverr solves a challenge and returns cf_clearance, the cookie is fed into
httpcloak's session. Subsequent requests via httpcloak (with matching TLS fingerprint + cookie)
pass Cloudflare without re-challenge.
Architecture
httpclient.DefaultClient()
├── httpcloak.Session (Chrome TLS fingerprint + cookie jar)
│ ├── 200 → return response (fast path, no re-challenge)
│ └── 403/503 → FlareSolverr fallback
└── FlareSolverr raw mode (auto-detected from FLARESOLVERR_URL env var)
└── Cookies fed back into httpcloak session for next request
Flows
- Non-Cloudflare site: httpcloak → 200. Fast, ~0.5s.
- Cloudflare site, first request: httpcloak → 403 → FS solves challenge (~12-60s) →
cf_clearancecookie stored in httpcloak session. - Cloudflare site, subsequent requests: httpcloak (with Chrome TLS + clearance cookie) → 200. Fast, ~1-2s.
FlareSolverr Integration
FlareSolverr is auto-configured from FLARESOLVERR_URL env var (e.g.,
http://localhost:8191). If unset, the client works in direct-only mode.
| Env Var | Default | Description |
|---|---|---|
FLARESOLVERR_URL |
— | FlareSolverr endpoint |
FLARESOLVERR_SESSION |
goyomi |
FS browser session ID; reuses one Chrome instance. Set empty for per-request sessions (more parallel, more memory) |
FLARESOLVERR_LOG_LEVEL |
info |
FS log verbosity |
The flare package (internal/httpclient/flare/) is a backward-compatible alias for
httpclient.Client. Sources that already import flare continue to compile.
Kotlin vs Go Mapping
Kotlin (cloudflareClient) |
Go (httpclient.Client) |
|---|---|
| Android WebView (Chrome) → solves 503 → retries with cookies | httpcloak (Chrome TLS fingerprint) → on 403 → FS fallback → cookies fed to httpcloak |
| WebView + OkHttp share Android's TLS stack | httpcloak mimics Chrome's JA3 fingerprint |
| Challenge solved once, cookies reused | Challenge solved once, cookies reused via httpcloak session |
| Returns raw server response | Returns FS raw body or httpcloak body |
| Shared across all extensions | DefaultClient() singleton shared across all sources |
Design Decisions
- Why httpcloak? — Go's net/http TLS fingerprint doesn't match Chrome's, so Cloudflare clearance cookies from FS are rejected on direct requests. httpcloak emulates Chrome's JA3/JA4 fingerprint, making subsequent requests pass Cloudflare.
- Why not go-cfscraper? — The pure-Go JS challenge solver (goja) and external
runtimes (Node.js) both lack browser DOM APIs (
location,document,window) that Cloudflare challenge scripts require. The DOM shims are fragile and break when Cloudflare updates. FlareSolverr with real Chrome is the only reliable solver. - Why FlareSolverr at all? — The first request to a Cloudflare site always gets
challenged (no
cf_clearancecookie yet). FlareSolverr's real Chrome solves it. - Why a singleton? — Shared httpcloak session = cookies from FS (solved challenges) benefit all sources. Shared rate limiter prevents hammering the same host.
- Why strip FS wrapper? — FS routes requests through Chrome, which wraps JSON
responses in
<html>…<pre>…</pre>…</html>. Without stripping, JSON parsers fail. - Why FS session matters — With
FLARESOLVERR_SESSION, FS reuses one Chrome instance. After the first challenge,cf_clearanceis cached. Subsequent requests to the same domain are near-instant. Without a session, each request spawns a fresh Chrome, solving the challenge from scratch every time (~13s each).
Known goquery Limitation — :has() + Attribute Selectors
goquery (via the cascadia CSS engine) does not support :has() combined with
attribute selectors like a[href*=/video/]. This works in Jsoup (Kotlin) but silently
returns 0 matches in Go.
Wrong (CSS-only, works in Kotlin, returns 0 in Go):
doc.Find("figure:not(:has(a[href*=/video/]))")
Correct (programmatic filtering):
doc.Find("figure").Each(func(_ int, el *goquery.Selection) {
if hasAttr(el, "a", "href", "/video/") { return }
// process entry
})
func hasAttr(el *goquery.Selection, tag, attr, substr string) bool {
found := false
el.Find(tag).EachWithBreak(func(_ int, a *goquery.Selection) bool {
if v, ok := a.Attr(attr); ok && strings.Contains(v, substr) {
found = true; return false
}
return true
})
return found
}
Always check Kotlin references for :has() selectors and convert them to
programmatic filtering when porting.
Detailed implementation notes for complex sources are in the Notes section at the bottom.
sources/all/ — 125 sources
all/ahottieall/akumaall/allporncomicscoall/asmhentaiall/baobuaall/beauty3600000all/buonduaall/comicfuryall/comicgrowlall/comickliveall/comicskingdom⚠️ no Kotlin reference found — skipall/comicsvalleyall/comikeyall/commitstripall/coomerall/coronaexall/cosplayteleall/cubariall/danbooru⚠️ see notesall/deviantartall/dragonballmultiverseall/e621⚠️ see notesall/elitebabesall/everiacluball/everiaclubcomall/femjoyhunterall/foamgirlall/foolslidecustomizableall/fourkhdall/ftvhunterall/fuwayomi⚠️ skip — server-side Fuwayomi integration, not a scraperall/globalcomix⚠️ see notesall/grabberzoneall/hdoujinall/hennojinall/hentai3all/hentaicosplayall/hentaienvyall/hentaieraall/hentaifoxall/hentaihandall/hentairoxall/hentaizapall/hniscantradall/holonometriaall/honeytoonall/imhentaiall/izneoall/jjcosall/joymiihuball/junmeituall/kemono⚠️ see notesall/kiutakuall/kodokustudioall/koharuall/komga⚠️ see notesall/lanraragiall/leagueoflegendsall/lunaranimeall/luscious⚠️ see notesall/magicaltranslatorsall/manga18meall/mangaballall/mangacrazyall/mangadex⚠️ see notesall/mangadraftall/mangafireall/mangaforfreeall/mangaplus⚠️ see notesall/mangapluscreatorsall/mangataroall/mangatoonall/mangaupall/mangoall/manhuarmall/manhwa18ccall/manhwa18netall/manhwa18uncensoredall/manhwaclubnetall/manhwadashrawall/mayotuneall/metarthunterall/miauscanall/misskonall/mitakuall/myreadingmangaall/namicomiall/nhentaicom⚠️ see notesall/nhentaixxxall/niaddall/ninemangaall/novelcoolall/ososedkiall/pandachaikaall/peppercarrotall/photos18all/pixiv⚠️ see notesall/playmatehunterall/pornpicsall/projectsukiall/qtoonall/rokuhentaiall/sakuramanhwaall/sandraandwooall/seraphicdeviltryall/simplycosplayall/simplyhentaiall/stashapp⚠️ see notesall/taddyinkall/tappytoonall/thelibraryofoharaall/thunderscansall/toomicsall/twicomiall/uncensoredmanhwaall/vinnieVeritasall/webtoons⚠️ see notesall/xarthunterall/xasiatalbumsall/xgmnall/xinmeituluall/xiutakuall/xkcdall/yabaiall/yaoimangaonlineall/yellownoteall/yskcomics
sources/en/ — 430 sources
en/akaicomicen/alandalen/allanime⚠️ see notesen/allporncomicen/allporncomicioen/anisascansen/apcomicsen/aquamangaen/arcrelight→ base: MangAdventureen/arenascansen/armageddonen/artlapsaen/arvencomicsen/arvenscansen/aryascansen/asiatoonen/asmotoonen/assortedscansen/asurascans⚠️ see notesen/athreascansen/atsumaru→ standalone HttpSourceen/aurora→ standalone HttpSourceen/azcomic→ standalone HttpSourceen/azukien/baektoonsen/bakkin⚠️ see notesen/bakkinselfhosteden/batcaveen/battleinfivesecondsaftermeetingen/beehentai→ base: MadThemeen/bookwalker⚠️ see notesen/boratscans→ base: Madaraen/boxmanhwa→ base: MadThemeen/broccolisoup→ standalone HttpSourceen/bunmanga→ base: Madaraen/buttsmithy→ standalone HttpSourceen/clonemanga→ standalone HttpSourceen/clowncorps→ standalone HttpSourceen/cmanhuaen/cocomicen/coffeemanga→ base: Madara (complex)en/collectedcuriosen/comicasuraen/comiccxen/comichubfreeen/comickfanen/comickibaen/comiclanden/comicslanden/comixen/crowscansen/cucumbermanga→ base: Madaraen/culturedworksen/cutiecomicsen/dankefurslesenen/darklegacycomicsen/darkscansen/darkscienceen/darthsdroidsen/deathtollscansen/decadencescans→ base: Madaraen/dflowscansen/digitalcomicmuseumen/divascansen/doujinioen/doujinsen/dragonteaen/drakescansen/dynastyen/eggporncomicsen/egscomicsen/eighteenporncomicen/eightmusesen/elanschoolen/elftoonen/epicmangaen/erisscansen/ero18xen/erofusen/erosscansen/evascansen/evilflowersen/existentialcomicsen/explosmen/ezmangaen/fablescansen/fairyscansen/firescans→ base: Madara (complex)en/flamecomicsen/frierenonlineen/gakamangasen/galaxydegenscansen/galaxymangaen/gedecomixen/gingertoonen/godaen/gourmetscansen/greedscansen/grimscansen/grrlpoweren/gunnerkriggcourten/guya⚠️ see notesen/gwtben/hachirumien/hadesscansen/harimangaen/hentai3zccen/hentai4freeen/hentaidexen/hentaihereen/hentaikunen/hentainexusen/hentairead→ base: Madara (complex)en/hentaireadioen/hentaiscoen/hentaixcomicen/hentaixdickgirlen/hentaixyurien/hentaraen/heytoonen/hijalascansen/hiperdexen/hiveworksen/hm2den/honkaiimpacten/hotcomicsen/hyakuroen/infernalvoidscansen/infinityscansen/irovedouten/isekaiscantopen/jinmangasen/jnovelen/kaganeen/kaizenscanen/kaliscancom→ base: MadThemeen/kaliscanio→ base: MadThemeen/kaliscanmeen/kappabeasten/kaynscansen/keenspoten/kenscansen/kewnscansen/killsixbilliondemonsen/kingcomixen/kingofshojoen/kissmangainen/kmangaen/kodanshaen/ksgroupscansen/kunmangaen/kuramangaen/lagoonscansen/leslievictimsen/lhtranslationen/likemangaen/likemangainen/lilymangaen/linkmanga→ base: Madaraen/loadingartisten/luascansen/luminaretranslationsen/lunatoonsen/madaradexen/madarascansen/madokamien/magusmangaen/mahouirexnohentaikarteen/manga18cluben/manga18freeen/manga18fxen/manga18xen/mangabaten/mangablazeen/mangabolten/mangabtten/mangabuddy→ base: MadThemeen/mangabuddyme→ base: MadThemeen/mangaclashen/mangaclouden/mangacute→ base: MadThemeen/mangadassen/mangadeen/mangademonen/mangadiaen/mangadistricten/mangadotneten/mangadramaen/mangafab→ base: MadThemeen/mangaforest→ base: MadThemeen/mangaforfreecomen/mangafoxen/mangafoxfun→ base: MangaHuben/mangafreaken/mangafreeen/mangaggen/mangagoen/mangagofunen/mangaheen/mangahenen/mangahentaien/mangahereen/mangahereonl→ base: MangaHuben/mangahubio→ base: MangaHuben/mangakaen/mangakakaloten/mangakakalotfun→ base: MangaHuben/mangakatanaen/mangakissen/mangamaniacsen/mangamoen/mangamoben/mangamonk→ base: MadThemeen/manganel→ base: MangaHuben/manganeloen/manganowen/mangaonlinefun→ base: MangaHuben/mangaowlioen/mangapandaonl→ base: MangaHuben/mangapillen/mangapumaen/mangarawcluben/mangareaden/mangareaderccen/mangareadersite→ base: MangaHuben/mangareadorgen/mangasaga→ base: MadThemeen/mangasecten/mangaspin→ base: MadThemeen/mangasushien/mangatellersen/mangatoday→ base: MangaHuben/mangatownen/mangatrenden/mangatxen/mangaxyz→ base: MadThemeen/manhuafasten/manhuafastneten/manhuahoten/manhuanexten/manhuanow→ base: MadThemeen/manhuaplusen/manhuaplusorgen/manhuarushen/manhuascanusen/manhuasite→ base: MadThemeen/manhuatopen/manhuausen/manhuazongheen/manhwa18en/manhwa18orgen/manhwa68en/manhwabuddyen/manhwaclanen/manhwacomicsen/manhwadenen/manhwageten/manhwahuben/manhwajoyen/manhwalikeen/manhwaloveren/manhwamanhuaen/manhwareaden/manhwareadsen/manhwatoonen/manhwatopen/manhwaxen/manhwaxxlen/manhwazen/manhwazoneen/mantaen/megatokyoen/mehgazoneen/meitoonen/mgjinxen/mgreadioen/milftoonen/mistscansen/mlbbloreen/monochromecustomen/monochromescansen/multpornen/murimscanen/myhentaicomicsen/myhentaigalleryen/necroscansen/newmanhwaen/nexcomicen/nikatoonsen/nineanimeen/ninehentaien/ninekonen/novel24hen/novelcrowen/noxenscansen/nuxscansen/nyanukafeen/nyrascansen/nyxscansen/octopusmangaen/oglafen/ohjoysextoyen/omegascansen/onemangaco→ base: MangaHuben/onemangainfo→ base: MangaHuben/onepunchmanonlineen/onlythebesthentaien/ootsen/oppaistreamen/orchisasiaen/orionscansen/paradisescansen/paragonscansen/paritehaberen/patchfridayen/pawmangaen/petrotechsocietyen/philiascansen/plutoscansen/pmscansen/porncomixen/qiscansen/questionablecontenten/ragescansen/randowizen/ravenscansen/razureen/rdscansen/readallcomicscomen/readattackontitanshingekinokyojinmangaen/readberserkmangaen/readblackclovermangaonlineen/readbokunoheroacademiamyheroacademiamangaen/readchainsawmanmangaonlineen/readcomiconlineen/readcomicsonlineen/readfairytailedenszeromangaonlineen/readhaikyuumangaonlineen/readjujutsukaisenmangaonlineen/readkingdommangaonlineen/readnanatsunotaizai7deadlysinsmangaonlineen/readnarutoborutosamurai8mangaonlineen/readonepiecemangaonlineen/readonepunchmanmangaonlinetwoen/readsololevelingmangamanhwaonlineen/readtokyoghoulretokyoghoulmangaonlineen/readvagabondmangaen/reallifecomicsen/reimangaen/renascansen/resetscansen/restscansen/retsuen/revivalscansen/rinkocomicsen/ritharscansen/rizzcomicen/rizzcomicunoriginalen/rokaricomicsen/roliascanen/rosesquadscansen/ryumangaen/s2mangaen/sanascansen/saturdaymorningbreakfastcomicsen/schlockmercenaryen/setsuscansen/shibamangaen/shojoscansen/sirenscansen/skymangaen/sleepytranslations→ base: Madaraen/solarandsundryen/spmanhwaen/spyfakkuen/stonescapeen/sunshinebutterflyscansen/supermegaen/suryascansen/swordscomicen/tapasticen/tcbscansen/tcbscansunoriginalen/teamshadowien/templescanen/theblanken/theduckwebcomicsen/thepropertyofhateen/timelesstoonsen/todaymangaen/toon18en/toongoden/toonilyen/toonilymeen/toonitubeen/toonizyen/topmanhuaen/topmanhuafanen/topmanhuaneten/tritiniascansen/utoonen/valirscansen/vanillascansen/vgpersonen/vizshonenjumpen/voycemeen/vyvymangaen/vyvymangaorgen/warforrayubaen/wearehungeren/webcomicsen/webdexscansen/webnovelen/webtoonscanen/webtoonxyzen/weebcentralen/whalemangaen/witchscansen/woopreaden/writerscansen/wuxiaworlden/xlecxen/xomangaen/xoxocomicsen/yakshacomicsen/yaoihoten/yaoihuben/yaoiscanen/yaoitoonen/yoraien/zazamangaen/zinchanmangaen/zinchanmangacomen/zinmangaen/zinmanganet
Notes — Complex Sources
HTTP Client Selection
All sources use the same unified client — httpclient.DefaultClient(). You no longer need
to decide between direct HTTP and FlareSolverr; the client handles both automatically.
In Kotlin, override val client = network.cloudflareClient signals the source needs
Cloudflare bypass — but in Go, the adaptive Do() method provides it transparently.
all/mangadex ⚠️
- Rate limit: 5 req/s (
golang.org/x/time/rate) GetPopularManga—GET /manga?order[rating]=desc&includes[]=cover_art&limit=20&offset={(n-1)*20}GetLatestUpdates—GET /manga?order[updatedAt]=desc&includes[]=cover_artGetSearchManga— tag filters (includedTags[],excludedTags[]), demographic, content rating, status, sortGetMangaDetails—GET /manga/{id}?includes[]=cover_art&includes[]=author&includes[]=artist; cover URL from relationshipsGetChapterList—GET /manga/{id}/feed?translatedLanguage[]=en&limit=500; paginate until all chapters fetchedGetPageList—GET /at-home/server/{chapterId}→{baseUrl}/{quality}/{hash}/{filename}; quality =dataordata-saverGetFilterList—GET /manga/tag; cache tag list- Language configurable via
MANGADEX_LANGenv var (defaulten)
all/nhentaicom ⚠️
- FlareSolverr required
GetPageList— extract JSON blob fromdocument.getElementById(...)in<script>tag; reconstruct URLs as{imageServer}/galleries/{mediaId}/{pageNum}.{ext}
all/kemono ⚠️
- FlareSolverr required
- Service + creator = manga; posts = chapters; attachment files = pages
- File URLs: prefix relative paths with
{base}/data GetChapterList— paginate in 50-post increments via?o={offset}
all/komga ⚠️
- Self-hosted;
KOMGA_BASE_URL,KOMGA_USERNAME,KOMGA_PASSWORDenv vars; Basic Auth - Series = manga; Books = chapters; pages via
GET /api/v1/books/{bookId}/pages/{n}/thumbnail
all/e621 ⚠️
- Optional Basic Auth (
E621_USERNAME,E621_API_KEY); required for Gold content - Pools = manga; posts = pages;
GET /pools.json,GET /posts.json?tags=pool:{id}
all/danbooru ⚠️
- Optional Basic Auth; free accounts limited to 2 tags per search
- Pools = manga; pool post_ids = pages; image URL from
file_urlfield
all/pixiv ⚠️
- Auth:
PIXIV_PHPSESSIDenv var → Cookie header GetPageList—GET /ajax/illust/{illustId}/pages; extracturls.original- Must set
Referer: https://www.pixiv.net/on all image requests or get 403
all/luscious ⚠️
- GraphQL POST to
https://members.luscious.net/graphql/playground - Albums = manga;
SearchAlbumPicturespaginated for page list
all/mangaplus ⚠️
- JSON endpoint:
GET https://jumpg-webapi.tokyo-cdn.com/api/title_detail?title_id={id} GetPageList— XOR page URL decryption using per-pageencryptionKey(hex string); implement inGetImageURL- Required header:
Origin: https://mangaplus.shueisha.co.jp
all/stashapp ⚠️
- Self-hosted;
STASHAPP_BASE_URL,STASHAPP_API_KEYenv vars - GraphQL POST to
{base}/graphql;ApiKeyheader
all/globalcomix ⚠️
- Signed CDN URLs with short expiry — do NOT cache
image_urlin DB; always fetch fresh page URLs
all/webtoons ⚠️
- HMAC-SHA256
Sec-Webtoon-Client-Dataheader:HMAC-SHA256(fixedKey, "{url}_{timestamp}")→ base64; fixed key in extension source - Web API:
https://global.apis.naver.com/webtoonSvc/v1/...
en/allanime ⚠️
- GraphQL POST to
https://api.allanime.day/api - Episode-based chapters;
episodeStringused as chapter number - Multiple CDN quality tiers in page response; pick highest
en/asurascans ⚠️
- FlareSolverr required
- Page selector varies by layout version; check extension source for current selector
en/bakkin ⚠️
- No list/search; all manga from a single JSON URL; enumerate from object keys
GetSearchMangadoes client-side title filtering only
en/bookwalker ⚠️
- DRM-protected; metadata only
GetPageListreturns empty slice; pages not accessible without purchase
en/guya ⚠️
GET {base}/api/get_all_series/returns all manga at once; no pagination- Scanlation group filter applied client-side in response parsing