Compare commits

...

130 Commits

Author SHA1 Message Date
Chopper 5ecf338be0
DiskusScan: Fix headers (#4568)
CI / Prepare job (push) Successful in 6s Details
CI / Build individual modules (push) Successful in 4m11s Details
CI / Publish repo (push) Successful in 46s Details
Fix headers
2024-08-13 02:32:09 +01:00
子斗子 d2ad77c0a3
[NHentai] fix group info (#4567)
* fix group name.

* update extVersionCode
2024-08-13 02:32:09 +01:00
Vetle Ledaal ac55757327
Add ManhwaFreak.xyz (#4547)
* Add Manhwa Freak

* rename

* rename2
2024-08-13 02:32:02 +01:00
KenjieDec a1c813a40d
HentaiDex | Added HentaiDex (#4534)
* Add HentaiDex

* Thumbnail

* Use mangathemesia

* Use mangathemesia

* Use mangathemesia

* Apply suggestion

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>

* Fix chapters location

---------

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-08-13 02:32:02 +01:00
AwkwardPeak7 9211ccee37
ZinChanManga: cleaner titles (#4560) 2024-08-13 02:32:02 +01:00
AwkwardPeak7 10a0b67bf4
HentaiWebtoon: fix chapter list & search (#4559) 2024-08-13 02:32:02 +01:00
Vetle Ledaal e67653580e
Add Manhwalist.org (#4555) 2024-08-13 02:32:02 +01:00
Vetle Ledaal 69ace8bba9
Remove KomikNesia (#4554) 2024-08-13 02:32:02 +01:00
Vetle Ledaal b1f0d14217
Add Void Scans (#4552) 2024-08-13 02:32:02 +01:00
Vetle Ledaal 9ee1be41b8
Add YD-Comics (#4551) 2024-08-13 02:32:02 +01:00
Vetle Ledaal 89dbb360d3
ManhwaLand.mom: update domain (#4550) 2024-08-13 02:32:02 +01:00
Vetle Ledaal 15aebe8edb
Add Varna Scan (#4549) 2024-08-13 02:32:02 +01:00
Vetle Ledaal b4dd656175
Add Snow Scans (#4548) 2024-08-13 02:32:02 +01:00
AwkwardPeak7 c62cec150f
HentaiManga: fix chapter list & search (#4546) 2024-08-13 02:32:02 +01:00
AwkwardPeak7 77ac036786
StrayFansub: update theme (#4545) 2024-08-13 02:32:02 +01:00
AwkwardPeak7 39b1e20401
update domains (#4544)
* MangaSwat: update domain
	closes #4543

* HattoriManga: update domain
	closes #4541

* bump

* jiangzaitoon: update domain
	closes #4537

* fleurblanche: update domain
2024-08-13 02:32:02 +01:00
KenjieDec b65681b8b7
SpyFakku | Fix SpyFakku (#4540)
FIx Spyfakku

- Use api again
2024-08-13 02:32:02 +01:00
KenjieDec db149972bd
Koharu | Fix Pages (#4539)
Fix Pages

- Fix Chapter Images
- Fix Chapter not being viewable when quality's `id` or `public_key` is not provided
2024-08-13 02:32:02 +01:00
AwkwardPeak7 b99fc8af0d
MangaPro: deproxify images (#4533)
* MangaPro: deproxify images

* remove log
2024-08-13 02:32:02 +01:00
AwkwardPeak7 41cebfbf1d
TempleScan: fix comic list (#4531)
bruh
2024-08-13 02:32:02 +01:00
AwkwardPeak7 ca739c2278
HentaiCosplay: update domain (#4530) 2024-08-13 02:32:02 +01:00
AwkwardPeak7 10a970a56d
remove instamanhwa (#4528) 2024-08-13 02:32:02 +01:00
AwkwardPeak7 32220c1673
MangaDistrict: get absolute dates from page list (#4527)
* MangaDistrict: get absolute dates from page list

* tfw
2024-08-13 02:32:01 +01:00
KenjieDec d63c947ca7
ColoredManga | Increase extVersionCode to match for older versions (#4526)
Apply suggestion
2024-08-13 02:32:01 +01:00
AwkwardPeak7 48b0101075
ManhwaIndo: update domain & deduplicate images (#4513) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 a14bf9cc8b
WebDexScans: update manga url directory (#4512) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 fc27271192
InstaManhwa: fix (#4511) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 18863bcd7f
EnryuManga: update domain (#4510) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 292bcc93bd
ngkomik: update domain (#4508) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 6b764484d6
Kiryuu: fix image mime (#4507) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 490a7b1c0c
BlogTruyen: update page list selector (#4506)
BlogTruyen: update domain
2024-08-13 02:31:58 +01:00
AwkwardPeak7 afe2bf4e55
HunlightScans: reverse chapter list (#4504) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 e0a7051166
manjanoon: update domain (#4503) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 f4124bb944
alceascan: update domain (#4502) 2024-08-13 02:31:58 +01:00
KenjieDec 159bee785a
ManyToon & ManhwaHentaiMe | Fix Next Page Selector (#4500)
Fix Next Page Selector

- ManyToon: Fix Next Page Selector and Filters
- ManwhaHentaiMe: Fix Next Page Selector
2024-08-13 02:31:58 +01:00
TheKingTermux 2bab0cccdb
Add Crotpedia (#4489)
* Add CrotPedia

This is my first Ext
CMIIW

* Update CrotPedia.kt
2024-08-13 02:31:58 +01:00
KenjieDec a27b852546
ManyToon | Fix Search (#4480)
* Fix Search

* Little Change

* lint
2024-08-13 02:31:58 +01:00
Chopper 4955c0f1e5
SushiScan: Add random UA (#4479)
Add UA
2024-08-13 02:31:58 +01:00
AwkwardPeak7 fa0910b72c
ManhwaDesu: update domain (#4477) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 425d6e839d
RocksManga: fix selectors and domain (#4476) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 93c5a106c4
Hentai2Read: update filters (#4475) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 4a7de77df7
Gri Melek: update domain (#4474) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 847f8d084f
Comicaso: change domain and fix page list (#4473) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 6711c29e74
MangaClick -> MangaHall: update domain (#4472)
MangaClick -> MangaHill: update domain
2024-08-13 02:31:58 +01:00
KenjieDec b6cf811a63
ManhwaHentaiMe | Fixed Latest & Filters (#4450)
* Fix Latest, Fix Filters

- Their website is kinda broken right now | 'Latest' and 'Newest' have the same result

* Apply suggestion?

- Apply AwkwardPeak's suggestion

* lint
2024-08-13 02:31:58 +01:00
Chopper 18b6668b54
Remove AgiToon (#4465) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 987aa83570
ManyToons: fix chapter list & search (#4459) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 7ac206a61a
MikrokosmosFansub: fix page list (#4458) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 fdcae35d12
nekopost: fix webview urls (#4456) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 5fca0cb71f
kaiscans -> luascans (unoriginal): update domain (#4455)
* kaiscans -> luascans (unoriginal): update domain

* oops
2024-08-13 02:31:58 +01:00
AwkwardPeak7 271855037e
komiktap: correct image mime type (#4454) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 0ea2b99616
Utoon: filter paid chapters (#4453) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 c16c663fba
remove: TheGuild (#4452) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 b50b2c3275
MangaTop -> MangaScans: update domain (#4451) 2024-08-13 02:31:58 +01:00
AwkwardPeak7 6f51e9d50f
Vortex: fix page list (#4449) 2024-08-13 02:31:58 +01:00
are-are-are 45ec1a302d
Update NettruyenCO URL Change (#4448) 2024-08-13 02:31:58 +01:00
Wackery 6f98841b14
HeanCMS: Add chapter title support (#4447) 2024-08-13 02:31:58 +01:00
KenjieDec cdb8de9fbf
Spyfakku | Fixed Some Images Not Loading (#4444)
* Fixed Some Images Not Loading

- Also Fixed Manga & Chapter Webview URL

* Update extVersionCode

* Fix?

* Little Change

- The website itself already provides cased tags
2024-08-13 02:31:58 +01:00
Chopper 9730a445c8
BlackoutComics: Fix loading pages (#4440)
* Fix loading pages

* Cleanup
2024-08-13 02:31:58 +01:00
Pedro Azevedo a4558c60eb
HuntersScans: Updated Domain (#4438) 2024-08-13 02:31:58 +01:00
bapeey 6b8d072c6c
AsuraScans: Fix pages selector (#4432)
lel
2024-08-13 02:31:58 +01:00
bapeey 8b0ff6e537
IkigaiMangas: Update domain (#4427)
update domain again
2024-08-13 02:31:58 +01:00
Chopper 99caea527a
Add AltayScans (#4420) 2024-08-13 02:31:58 +01:00
Chopper f765a61aa4
LunarScan(PT): Update domain (#4419)
Update domain
2024-08-13 02:31:58 +01:00
Vetle Ledaal fb6bd6a041
PussyToons: fix duplicate entries (#4417) 2024-08-13 02:31:57 +01:00
Chaos Pjeles 39f83d1d77
foamgirl impl (#4407)
* impl

* Update src/all/foamgirl/src/eu/kanade/tachiyomi/extension/all/foamgirl/FoamGirl.kt

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>

* resolve suggestions

---------

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-08-13 02:31:57 +01:00
Chopper c78f0e45f1
Add DarkRoomFansub (#4406)
* Add DarkRoomFansub

* Some changes

* Remove URI fragment
2024-08-13 02:31:57 +01:00
kana-shii cea1f3c81c
More scanlator stuff for batoto (#4398)
* scanlator stuff

* Update build.gradle

* Update BatoTo.kt

* fix

this was the only way I found to make the "unknown" work tbh.
prayge
2024-08-13 02:31:57 +01:00
bapeey cca5e276d2
TMO / LectorManga: Move to factory (fix http 530) (#4393)
* damn

* shouldn't newBuilder() create a new instance?

* 1 second is enough

* remove lazy

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>

* imports

---------

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-08-13 02:31:57 +01:00
jckli 118a905cef
fix: rebrand fire scans to firecomics (#4412)
* fix: rebrand fire scans to firecomics

* fix: change gradle

* chore: add old id
2024-08-13 02:31:57 +01:00
lamaxama c02273905e
Remove MangaTopSite (#4411) 2024-08-13 02:31:57 +01:00
lamaxama 56aa26d330
Remove ComicScans and AnshScans (#4410) 2024-08-13 02:31:57 +01:00
Chopper 2d41904b79
Remove Eflee (#4405) 2024-08-13 02:31:41 +01:00
Chopper 3030e0c74f
Add MangaHub (#4404) 2024-08-13 02:31:40 +01:00
Chopper 8c4ee90ccc
Add HyperionScans (#4401) 2024-08-13 02:31:40 +01:00
Chopper 90ba562e46
Add Magerin (#4399) 2024-08-13 02:31:40 +01:00
Chopper 329738e39d
AncientComics: Theme changed (#4397)
Theme changed
2024-08-13 02:31:40 +01:00
Vetle Ledaal ebdcdea164
Add Manga Okusana (#4396) 2024-08-13 02:31:40 +01:00
Vetle Ledaal aece7b3d39
Add LumosKomik (#4395)
* Add LumosKomik

* update useLoadMoreRequest/useNEwChapterEndpoint
2024-08-13 02:31:40 +01:00
Vetle Ledaal 4dac2439f8
Add PussyToons (#4394) 2024-08-13 02:31:40 +01:00
Vetle Ledaal a60cd07d45
Remove Manga-Raw.info (unoriginal) (#4387) 2024-08-13 02:31:40 +01:00
KenjieDec da46ebfa9a
Reaperscans: Fix Latest (#4383)
* Fix latest

* Update

* Lint Fix?
2024-08-13 02:31:40 +01:00
AwkwardPeak7 1a1566be23
Reaper Scans: fix covers and date (#4382) 2024-08-13 02:31:40 +01:00
AwkwardPeak7 7a4fa5d46a
Reaper Scans: actually change id 2024-08-13 02:31:40 +01:00
Wackery 4554a0c717
Reaper Scans: Update to new website (#4359)
* Update reaper scans to new website

* Reaper Scans: Fix requested changes

* Reaper Scans: remove unused property.

* Reaper Scans: Fix no pages found error

they broke it already???

* Reaper Scans: Fix extra images in chapters.

* Reaper Scans: Replace scraping chapter pages with api

* Reaper Scans: Fix lint

hopefully

* HeanCms: Add cdnUrl option

for sources who host thumbnails/pages outside of the api domain

* Reaper Scans: it was a multisrc this whole time

pain.

* Reaper Scans: Remove id override

* Reaper Scans: Correct version number
2024-08-13 02:31:40 +01:00
CriosChan 7e3d185dab
AnimeSama: Add support for multiple scan versions (#4156) (#4325)
* feat(AnimeSama): Support multiple version of scan (Color and colorless for exemple)

* update(AnimeSama)

* fix(AnimeSama): Use Scanlators not multiple entries

* fix(AnimeSama): No more requests in chapterListRequest only in chapterListParse
2024-08-13 02:31:40 +01:00
Chopper 5824d4adfa
Add ErosScan (#4369) 2024-08-13 02:31:40 +01:00
Yush0DAN ea99a44cf3
ManhwaWeb: Add header fix some covers (#4373)
add header, some covers did not load
2024-08-13 02:31:40 +01:00
AwkwardPeak7 a82548860a
Comick: attempt cache busting (#4363) 2024-08-13 02:31:40 +01:00
Secozzi 20b9eff851
Madokami: use relative chapter urls (#4362)
Use relative chapter urls
2024-08-13 02:31:40 +01:00
Chopper e8d27b655e
DemonSect: Migrate theme (#4352)
* Migrate theme

* Use fetchChapterList
2024-08-13 02:31:40 +01:00
KenjieDec 869afb9534
Fix Spyfakku (#4345) 2024-08-13 02:31:40 +01:00
KirinRaikage 311bea3a8a
Manga-Scan (FR): Update domain (#4351) 2024-08-13 02:31:40 +01:00
KenjieDec 860155e34d
ManhwaHentai.me: Fix Search (#4348)
Fix Search
2024-08-13 02:31:40 +01:00
Chopper 5ba43beecc
Hentaing(HentaiKeyfi): Rebranding (#4336)
Rebranding
2024-08-13 02:31:40 +01:00
Chopper 709769b171
Add LimitedTimeProject (#4335) 2024-08-13 02:31:40 +01:00
Secozzi e9d0013df3
Add atsumaru (#4330)
* add atsumaru

* remove unnecessary stuff
2024-08-13 02:31:40 +01:00
Norsze 0251a55109
Remove MangaHot (#4328) 2024-08-13 02:31:40 +01:00
Norsze 530e5500da
Remove ReadManga.at (#4327) 2024-08-13 02:31:40 +01:00
Norsze 5ae345113f
Remove Immortal Updates (#4326) 2024-08-13 02:31:40 +01:00
AwkwardPeak7 fa37d45021
MangaGalaxy/Iken: don't proxy thumbnail urls (#4322) 2024-08-13 02:31:40 +01:00
Luqman 4fc5107823
Kiryuu: update domain (#4320) 2024-08-13 02:31:40 +01:00
Chopper 01f3fa0191
Add ExHentai (#4313)
* Add ExHentai

* Rename
2024-08-13 02:31:40 +01:00
AwkwardPeak7 902e0242dd
TempleScan (#4316)
* temple

* rewrite

* description & tags cleanup

* readd ratelimit

* cloudflareclient

* optimize
2024-08-13 02:31:40 +01:00
Chopper 9e8187cd1f
Add ReaperScansUnoriginal (#4315)
* Add ReaperScansUnoriginal

* Update ext name
2024-08-13 02:31:40 +01:00
Chopper 362b739c88
Add TecnoScans (#4314) 2024-08-13 02:31:40 +01:00
Vetle Ledaal e171d141f0
Add Xmanhwa (#4312) 2024-08-13 02:31:40 +01:00
AwkwardPeak7 401e53d45a
Asura: add type to genres (#4311) 2024-08-13 02:31:40 +01:00
AwkwardPeak7 e5a68f8ba4
MangaThemesiaAlt: use slug map (#4310)
* MangaThemesiaAlt: use slug map

* selector variable

* better name
2024-08-13 02:31:40 +01:00
Chopper d07fbd5294
TsukiMangas: Fix (#4295)
* Fix content loading for the logged-in user

* Some changes

* Remove annotation

* Remove unneeded code

* Fix indentation

* Add suppress lint

* Enable blockNetworkImage

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>

---------

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-08-13 02:31:40 +01:00
Chopper ee3d182a5f
Remove RawMangas (#4303) 2024-08-13 02:31:40 +01:00
Chopper 40f2170702
Add PrunusScans (#4302) 2024-08-13 02:31:40 +01:00
Chopper f0e17a6531
TeamLanhLung: Update domain (#4301)
Update domain
2024-08-13 02:31:40 +01:00
Chopper 5dbcb16307
Add AstraScans (#4298) 2024-08-13 02:31:40 +01:00
KenjieDec ef7ff81f1b
18Kami: Fix Pages (#4292)
* Fix Pages

* Update extVersionCode

* Typo Fix
2024-08-13 02:31:40 +01:00
AwkwardPeak7 8cb6533dcd
Webnovel: revert old behaviour (#4288)
bruh moment
2024-08-13 02:31:40 +01:00
Vetle Ledaal 0e2d9bf970
ReadManga (RU): update domain (#4285) 2024-08-13 02:31:40 +01:00
Vetle Ledaal 7dbe265e52
Thunder Scans (AR): update domain (#4284) 2024-08-13 02:31:39 +01:00
Vetle Ledaal 2623bf72c5
TeamX: update domain, baseUrl config, author + status fields (#4283)
* Team X: update domain

* add status, author

* add baseUrl override
2024-08-13 02:31:39 +01:00
Vetle Ledaal 13fcfc6996
MANGARAW+: update domain (#4282)
Cover images are broken on the site, fixing this by requesting the full
res cover instead.
2024-08-13 02:31:39 +01:00
Vetle Ledaal 0bf59dd5e8
Gri Melek: update domain (#4281) 2024-08-13 02:31:39 +01:00
KenjieDec 38ef5386a6
Koharu: Fix Pages Not Loading, Removed Faulty Filters (#4280)
Fix Pages Not Loading, Removed Faulty Filters
2024-08-13 02:31:39 +01:00
AwkwardPeak7 4eacdd057e
LuaScans: update domain (#4278) 2024-08-13 02:31:39 +01:00
KenjieDec a5e5ccceec
Add 18Kami (#4262)
* Add 18Kami

* Apply suggestions

- Apply vetleledaal's suggestions

* Apply suggestion

- Apply bapeey's suggestion

Co-authored-by: bapeey <90949336+bapeey@users.noreply.github.com>

* Lint Fix

---------

Co-authored-by: bapeey <90949336+bapeey@users.noreply.github.com>
2024-08-13 02:31:39 +01:00
kana-shii 10ddb3734f
mangago add scanlator / remove suffix from titles (#4242)
* fix for 2 issues on mangago

* fix

* fix

forgot to remove the comment from when I was testing it out

* fix

* Update src/en/mangago/src/eu/kanade/tachiyomi/extension/en/mangago/Mangago.kt

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>

* Update src/en/mangago/src/eu/kanade/tachiyomi/extension/en/mangago/Mangago.kt

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>

* fix

---------

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-08-13 02:31:39 +01:00
AwkwardPeak7 3e6c9170ab
webnovel: fix relative date parsing (#4275)
webnovel: adjust date parsing
2024-08-13 02:31:39 +01:00
bapeey 4d291d571d
InfernalVoidScans: Fix cloudflare (#4273)
fix cloudflare
2024-08-13 02:31:39 +01:00
bapeey 303f6d7737
AsuraScans: Update chapter list selector (#4268)
fix
2024-08-13 02:31:39 +01:00
KenjieDec 88fffed4f9
Koharu: Fix Pages (#4256)
* Fix Pages

* LF
2024-08-13 02:31:39 +01:00
KenjieDec 2f9ebadb08
MangaGeko: Fix Filters (#4221)
* Fix Filters

* Apply suggestion1

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>

* Apply suggestion2

* Apply Suggetions

- Apply AwkwardPeak7's suggestions

---------

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-08-13 02:31:39 +01:00
468 changed files with 3745 additions and 2902 deletions

View File

@ -2,4 +2,4 @@ plugins {
id("lib-multisrc")
}
baseVersionCode = 1
baseVersionCode = 2

View File

@ -291,7 +291,7 @@ abstract class BlogTruyen(
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
document.select("#content > img").forEachIndexed { i, e ->
document.select(".content > img, #content > img").forEachIndexed { i, e ->
pages.add(Page(i, imageUrl = e.absUrl("src")))
}

View File

@ -7,7 +7,7 @@ import android.os.Bundle
import android.util.Log
import kotlin.system.exitProcess
/**
* Springboard that accepts https://readmanga.live/xxx intents and redirects them to
* Springboard that accepts https://1.readmanga.io/xxx intents and redirects them to
* the main tachiyomi process. The idea is to not install the intent filter unless
* you have this extension installed, but still let the main tachiyomi app control
* things.

View File

@ -2,7 +2,7 @@ plugins {
id("lib-multisrc")
}
baseVersionCode = 25
baseVersionCode = 27
dependencies {
api(project(":lib:i18n"))

View File

@ -72,6 +72,8 @@ abstract class HeanCms(
protected open val coverPath: String = ""
protected open val cdnUrl = apiUrl
protected open val mangaSubDirectory: String = "series"
protected open val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ", Locale.US)
@ -206,7 +208,7 @@ abstract class HeanCms(
val result = json.parseAs<HeanCmsQuerySearchDto>()
val mangaList = result.data.map {
it.toSManga(apiUrl, coverPath, mangaSubDirectory)
it.toSManga(cdnUrl, coverPath, mangaSubDirectory)
}
return MangasPage(mangaList, result.meta?.hasNextPage() ?: false)
@ -242,7 +244,7 @@ abstract class HeanCms(
val seriesResult = result.getOrNull()
?: throw Exception(intl.format("url_changed_error", name, name))
val seriesDetails = seriesResult.toSManga(apiUrl, coverPath, mangaSubDirectory)
val seriesDetails = seriesResult.toSManga(cdnUrl, coverPath, mangaSubDirectory)
return seriesDetails.apply {
status = status.takeUnless { it == SManga.UNKNOWN }
@ -345,8 +347,8 @@ abstract class HeanCms(
}
}
private fun String.toAbsoluteUrl(): String {
return if (startsWith("https://") || startsWith("http://")) this else "$apiUrl/$coverPath$this"
protected open fun String.toAbsoluteUrl(): String {
return if (startsWith("https://") || startsWith("http://")) this else "$cdnUrl/$coverPath$this"
}
override fun fetchImageUrl(page: Page): Observable<String> = Observable.just(page.imageUrl!!)

View File

@ -63,7 +63,7 @@ class HeanCmsSeriesDto(
) {
fun toSManga(
apiUrl: String,
cdnUrl: String,
coverPath: String,
mangaSubDirectory: String,
): SManga = SManga.create().apply {
@ -79,7 +79,7 @@ class HeanCmsSeriesDto(
.sortedBy(HeanCmsTagDto::name)
.joinToString { it.name }
thumbnail_url = thumbnail.ifEmpty { null }
?.toAbsoluteThumbnailUrl(apiUrl, coverPath)
?.toAbsoluteThumbnailUrl(cdnUrl, coverPath)
status = this@HeanCmsSeriesDto.status?.toStatus() ?: SManga.UNKNOWN
url = "/$mangaSubDirectory/$slug#$id"
}
@ -103,6 +103,7 @@ class HeanCmsChapterPayloadDto(
class HeanCmsChapterDto(
private val id: Int,
@SerialName("chapter_name") private val name: String,
@SerialName("chapter_title") private val title: String? = null,
@SerialName("chapter_slug") private val slug: String,
@SerialName("created_at") private val createdAt: String,
val price: Int? = null,
@ -114,6 +115,10 @@ class HeanCmsChapterDto(
): SChapter = SChapter.create().apply {
name = this@HeanCmsChapterDto.name.trim()
if (title != null) {
name += " - ${title.trim()}"
}
if (price != 0) {
name += " \uD83D\uDD12"
}
@ -161,8 +166,8 @@ class HeanCmsGenreDto(
val name: String,
)
private fun String.toAbsoluteThumbnailUrl(apiUrl: String, coverPath: String): String {
return if (startsWith("https://") || startsWith("http://")) this else "$apiUrl/$coverPath$this"
private fun String.toAbsoluteThumbnailUrl(cdnUrl: String, coverPath: String): String {
return if (startsWith("https://") || startsWith("http://")) this else "$cdnUrl/$coverPath$this"
}
fun String.toStatus(): Int = when (this) {

View File

@ -2,4 +2,4 @@ plugins {
id("lib-multisrc")
}
baseVersionCode = 1
baseVersionCode = 3

View File

@ -4,7 +4,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonPrimitive
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.jsoup.Jsoup
import java.text.ParseException
import java.text.SimpleDateFormat
@ -31,14 +30,10 @@ class Manga(
private val seriesStatus: String? = null,
val genres: List<Genre> = emptyList(),
) {
fun toSManga(baseUrl: String) = SManga.create().apply {
fun toSManga() = SManga.create().apply {
url = "$slug#$id"
title = postTitle
thumbnail_url = "$baseUrl/_next/image".toHttpUrl().newBuilder().apply {
addQueryParameter("url", featuredImage)
addQueryParameter("w", "828")
addQueryParameter("q", "75")
}.toString()
thumbnail_url = featuredImage
author = this@Manga.author?.takeUnless { it.isEmpty() }
artist = this@Manga.artist?.takeUnless { it.isEmpty() }
description = buildString {

View File

@ -14,6 +14,7 @@ import kotlinx.serialization.json.Json
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import rx.Observable
import uy.kohesive.injekt.injectLazy
abstract class Iken(
@ -43,7 +44,7 @@ abstract class Iken(
it.genres.map { genre ->
genre.name to genre.id.toString()
}
}
}.distinct()
}
.associateBy { it.slug }
}
@ -56,7 +57,7 @@ abstract class Iken(
.map { it.absUrl("href").substringAfterLast("/series/") }
val entries = slugs.mapNotNull {
titleCache[it]?.toSManga(baseUrl)
titleCache[it]?.toSManga()
}
return MangasPage(entries, false)
@ -84,7 +85,7 @@ abstract class Iken(
val entries = data.posts
.filterNot { it.isNovel }
.map { it.toSManga(baseUrl) }
.map { it.toSManga() }
val hasNextPage = data.totalCount > (page * perPage)
@ -98,32 +99,28 @@ abstract class Iken(
Filter.Header("Open popular mangas if genre filter is empty"),
)
override fun mangaDetailsRequest(manga: SManga): Request {
val id = manga.url.substringAfterLast("#")
val url = "$baseUrl/api/chapters?postId=$id&skip=0&take=1000&order=desc&userid="
return GET(url, headers)
}
override fun getMangaUrl(manga: SManga): String {
val slug = manga.url.substringBeforeLast("#")
return "$baseUrl/series/$slug"
}
override fun mangaDetailsParse(response: Response): SManga {
val data = response.parseAs<Post<Manga>>()
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
val slug = manga.url.substringBeforeLast("#")
val update = titleCache[slug]?.toSManga() ?: manga
assert(!data.post.isNovel) { "Novels are unsupported" }
// genres are only returned in search call
// and not when fetching details
return data.post.toSManga(baseUrl).apply {
genre = titleCache[data.post.slug]?.getGenres()
}
return Observable.just(update)
}
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
override fun mangaDetailsParse(response: Response) =
throw UnsupportedOperationException()
override fun chapterListRequest(manga: SManga): Request {
val id = manga.url.substringAfterLast("#")
val url = "$baseUrl/api/chapters?postId=$id&skip=0&take=1000&order=desc&userid="
return GET(url, headers)
}
override fun chapterListParse(response: Response): List<SChapter> {
val data = response.parseAs<Post<ChapterListResponse>>()
@ -138,7 +135,7 @@ abstract class Iken(
override fun pageListParse(response: Response): List<Page> {
val document = response.asJsoup()
return document.select("main section > img").mapIndexed { idx, img ->
return document.select("main section img").mapIndexed { idx, img ->
Page(idx, imageUrl = img.absUrl("src"))
}
}

View File

@ -1,5 +0,0 @@
plugins {
id("lib-multisrc")
}
baseVersionCode = 6

View File

@ -5,7 +5,6 @@ import android.content.SharedPreferences
import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreferenceCompat
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.SManga
@ -32,8 +31,18 @@ abstract class MangaThemesiaAlt(
private val randomUrlPrefKey: String = "pref_auto_random_url",
) : MangaThemesia(name, baseUrl, lang, mangaUrlDirectory, dateFormat), ConfigurableSource {
protected open val listUrl = "$mangaUrlDirectory/list-mode/"
protected open val listSelector = "div#content div.soralist ul li a.series"
protected val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000).also {
if (it.contains("__random_part_cache")) {
it.edit().remove("__random_part_cache").apply()
}
if (it.contains("titles_without_random_part")) {
it.edit().remove("titles_without_random_part").apply()
}
}
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
@ -47,183 +56,11 @@ abstract class MangaThemesiaAlt(
private fun getRandomUrlPref() = preferences.getBoolean(randomUrlPrefKey, true)
private var randomPartCache = SuspendLazy(::getUpdatedRandomPart) { preferences.randomPartCache = it }
// cache in preference for webview urls
private var SharedPreferences.randomPartCache: String
get() = getString("__random_part_cache", "")!!
set(newValue) = edit().putString("__random_part_cache", newValue).apply()
// some new titles don't have random part
// se we save their slug and when they
// finally add it, we remove the slug in the interceptor
private var SharedPreferences.titlesWithoutRandomPart: MutableSet<String>
get() {
val value = getString("titles_without_random_part", null)
?: return mutableSetOf()
return json.decodeFromString(value)
}
set(newValue) {
val encodedValue = json.encodeToString(newValue)
edit().putString("titles_without_random_part", encodedValue).apply()
}
protected open fun getRandomPartFromUrl(url: String): String {
val slug = url
.removeSuffix("/")
.substringAfterLast("/")
return slugRegex.find(slug)?.groupValues?.get(1) ?: ""
}
protected open fun getRandomPartFromResponse(response: Response): String {
return response.asJsoup()
.selectFirst(searchMangaSelector())!!
.select("a").attr("href")
.let(::getRandomPartFromUrl)
}
protected suspend fun getUpdatedRandomPart(): String =
client.newCall(GET("$baseUrl$mangaUrlDirectory/", headers))
.await()
.use(::getRandomPartFromResponse)
override fun searchMangaParse(response: Response): MangasPage {
val mp = super.searchMangaParse(response)
if (!getRandomUrlPref()) return mp
// extract random part during browsing to avoid extra call
mp.mangas.firstOrNull()?.run {
val randomPart = getRandomPartFromUrl(url)
if (randomPart.isNotEmpty()) {
randomPartCache.set(randomPart)
}
}
val mangas = mp.mangas.toPermanentMangaUrls()
return MangasPage(mangas, mp.hasNextPage)
}
protected fun List<SManga>.toPermanentMangaUrls(): List<SManga> {
// some absolutely new titles don't have the random part yet
// save them so we know where to not apply it
val foundTitlesWithoutRandomPart = mutableSetOf<String>()
for (i in indices) {
val slug = this[i].url
.removeSuffix("/")
.substringAfterLast("/")
if (slugRegex.find(slug)?.groupValues?.get(1) == null) {
foundTitlesWithoutRandomPart.add(slug)
}
val permaSlug = slug
.replaceFirst(slugRegex, "")
this[i].url = "$mangaUrlDirectory/$permaSlug/"
}
if (foundTitlesWithoutRandomPart.isNotEmpty()) {
foundTitlesWithoutRandomPart.addAll(preferences.titlesWithoutRandomPart)
preferences.titlesWithoutRandomPart = foundTitlesWithoutRandomPart
}
return this
}
protected open val slugRegex = Regex("""^(\d+-)""")
override val client = super.client.newBuilder()
.addInterceptor { chain ->
val request = chain.request()
val response = chain.proceed(request)
if (request.url.fragment != "titlesWithoutRandomPart") {
return@addInterceptor response
}
if (!response.isSuccessful && response.code == 404) {
response.close()
val slug = request.url.toString()
.substringBefore("#")
.removeSuffix("/")
.substringAfterLast("/")
preferences.titlesWithoutRandomPart.run {
remove(slug)
preferences.titlesWithoutRandomPart = this
}
val randomPart = randomPartCache.blockingGet()
val newRequest = request.newBuilder()
.url("$baseUrl$mangaUrlDirectory/$randomPart$slug/")
.build()
return@addInterceptor chain.proceed(newRequest)
}
return@addInterceptor response
}
.build()
override fun mangaDetailsRequest(manga: SManga): Request {
if (!getRandomUrlPref()) return super.mangaDetailsRequest(manga)
val slug = manga.url
.substringBefore("#")
.removeSuffix("/")
.substringAfterLast("/")
.replaceFirst(slugRegex, "")
if (preferences.titlesWithoutRandomPart.contains(slug)) {
return GET("$baseUrl${manga.url}#titlesWithoutRandomPart")
}
val randomPart = randomPartCache.blockingGet()
return GET("$baseUrl$mangaUrlDirectory/$randomPart$slug/", headers)
}
override fun getMangaUrl(manga: SManga): String {
if (!getRandomUrlPref()) return super.getMangaUrl(manga)
val slug = manga.url
.substringBefore("#")
.removeSuffix("/")
.substringAfterLast("/")
.replaceFirst(slugRegex, "")
if (preferences.titlesWithoutRandomPart.contains(slug)) {
return "$baseUrl${manga.url}"
}
val randomPart = randomPartCache.peek() ?: preferences.randomPartCache
return "$baseUrl$mangaUrlDirectory/$randomPart$slug/"
}
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
}
internal class SuspendLazy(
private val initializer: suspend () -> String,
private val saveCache: (String) -> Unit,
) {
private val mutex = Mutex()
private var cachedValue: SoftReference<String>? = null
private var cachedValue: SoftReference<Map<String, String>>? = null
private var fetchTime = 0L
suspend fun get(): String {
private suspend fun getUrlMapInternal(): Map<String, String> {
if (fetchTime + 3600000 < System.currentTimeMillis()) {
// reset cache
cachedValue = null
@ -238,22 +75,104 @@ internal class SuspendLazy(
return it
}
initializer().also { set(it) }
}
}
fun set(newVal: String) {
cachedValue = SoftReference(newVal)
fetchUrlMap().also {
cachedValue = SoftReference(it)
fetchTime = System.currentTimeMillis()
saveCache(newVal)
preferences.urlMapCache = it
}
}
}
fun peek(): String? {
return cachedValue?.get()
protected open fun fetchUrlMap(): Map<String, String> {
client.newCall(GET("$baseUrl$listUrl", headers)).execute().use { response ->
val document = response.asJsoup()
return document.select(listSelector).associate {
val url = it.absUrl("href")
val slug = url.removeSuffix("/")
.substringAfterLast("/")
val permaSlug = slug
.replaceFirst(slugRegex, "")
permaSlug to slug
}
}
}
fun blockingGet(): String {
return runBlocking { get() }
protected fun getUrlMap(cached: Boolean = false): Map<String, String> {
return if (cached && cachedValue == null) {
preferences.urlMapCache
} else {
runBlocking { getUrlMapInternal() }
}
}
// cache in preference for webview urls
private var SharedPreferences.urlMapCache: Map<String, String>
get(): Map<String, String> {
val value = getString("url_map_cache", "{}")!!
return try {
json.decodeFromString(value)
} catch (_: Exception) {
emptyMap()
}
}
set(newMap) = edit().putString("url_map_cache", json.encodeToString(newMap)).apply()
override fun searchMangaParse(response: Response): MangasPage {
val mp = super.searchMangaParse(response)
if (!getRandomUrlPref()) return mp
val mangas = mp.mangas.toPermanentMangaUrls()
return MangasPage(mangas, mp.hasNextPage)
}
protected fun List<SManga>.toPermanentMangaUrls(): List<SManga> {
return onEach {
val slug = it.url
.removeSuffix("/")
.substringAfterLast("/")
val permaSlug = slug
.replaceFirst(slugRegex, "")
it.url = "$mangaUrlDirectory/$permaSlug/"
}
}
protected open val slugRegex = Regex("""^(\d+-)""")
override fun mangaDetailsRequest(manga: SManga): Request {
if (!getRandomUrlPref()) return super.mangaDetailsRequest(manga)
val slug = manga.url
.substringBefore("#")
.removeSuffix("/")
.substringAfterLast("/")
.replaceFirst(slugRegex, "")
val randomSlug = getUrlMap()[slug] ?: slug
return GET("$baseUrl$mangaUrlDirectory/$randomSlug/", headers)
}
override fun getMangaUrl(manga: SManga): String {
if (!getRandomUrlPref()) return super.getMangaUrl(manga)
val slug = manga.url
.substringBefore("#")
.removeSuffix("/")
.substringAfterLast("/")
.replaceFirst(slugRegex, "")
val randomSlug = getUrlMap(true)[slug] ?: slug
return "$baseUrl$mangaUrlDirectory/$randomSlug/"
}
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
}

View File

@ -1,7 +1,7 @@
ext {
extName = 'Bato.to'
extClass = '.BatoToFactory'
extVersionCode = 36
extVersionCode = 37
isNsfw = true
}

View File

@ -384,11 +384,14 @@ open class BatoTo(
val chapter = SChapter.create()
val urlElement = element.select("a.chapt")
val group = element.select("div.extra > a:not(.ps-3)").text()
val user = element.select("div.extra > a.ps-3").text()
val time = element.select("div.extra > i.ps-3").text()
chapter.setUrlWithoutDomain(urlElement.attr("href"))
chapter.name = urlElement.text()
if (group != "") {
chapter.scanlator = group
chapter.scanlator = when {
group.isNotBlank() -> group
user.isNotBlank() -> user
else -> "Unknown"
}
if (time != "") {
chapter.date_upload = parseChapterDate(time)

View File

@ -1,7 +1,7 @@
ext {
extName = 'Comick'
extClass = '.ComickFactory'
extVersionCode = 46
extVersionCode = 47
isNsfw = true
}

View File

@ -463,7 +463,16 @@ abstract class Comick(
override fun pageListParse(response: Response): List<Page> {
val result = response.parseAs<PageList>()
return result.chapter.images.mapIndexedNotNull { index, data ->
val images = result.chapter.images.ifEmpty {
// cache busting
val url = response.request.url.newBuilder()
.addQueryParameter("_", System.currentTimeMillis().toString())
.build()
client.newCall(GET(url, headers)).execute()
.parseAs<PageList>().chapter.images
}
return images.mapIndexedNotNull { index, data ->
if (data.url == null) null else Page(index = index, imageUrl = data.url)
}
}

View File

@ -1,6 +1,6 @@
ext {
extName = 'MangaHot'
extClass = '.MangaHot'
extName = 'FoamGirl'
extClass = '.FoamGirl'
extVersionCode = 1
isNsfw = true
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,127 @@
package eu.kanade.tachiyomi.extension.all.foamgirl
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
class FoamGirl() : ParsedHttpSource() {
override val baseUrl = "https://foamgirl.net"
override val lang = "all"
override val name = "FoamGirl"
override val supportsLatest = false
override fun headersBuilder() = super.headersBuilder()
.add("Referer", "$baseUrl/")
// Popular
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
thumbnail_url = element.select("img").attr("data-original")
title = element.select("a.meta-title").text()
setUrlWithoutDomain(element.select("a").attr("href"))
initialized = true
}
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return Observable.just(manga)
}
override fun mangaDetailsParse(document: Document): SManga {
throw UnsupportedOperationException()
}
override fun popularMangaNextPageSelector() = "a.next"
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/page/$page", headers)
}
override fun popularMangaSelector() = ".update_area .i_list"
// Search
override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
return GET(
baseUrl.toHttpUrl().newBuilder().apply {
addPathSegment("page")
addPathSegment("$page")
addQueryParameter("post_type", "post")
addQueryParameter("s", query)
}.build(),
headers,
)
}
override fun searchMangaSelector() = popularMangaSelector()
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
val imageCount = document.select(".post_title_topimg").text().substringAfter("(").substringBefore("P").toInt()
val imageUrl = document.select(".imageclick-imgbox").attr("href").toHttpUrl()
val imagePrefix = imageUrl.pathSegments.last().substringBefore(".").toLong() / 10
for (i in 0 until imageCount) {
pages.add(
Page(
i,
imageUrl = imageUrl.newBuilder().apply {
removePathSegment(imageUrl.pathSize - 1)
addPathSegment("${imagePrefix}${i + 2}.jpg")
}.build().toString(),
),
)
}
return pages
}
override fun chapterFromElement(element: Element) = SChapter.create().apply {
setUrlWithoutDomain(element.select("link[rel=canonical]").attr("abs:href"))
chapter_number = 0F
name = "GALLERY"
date_upload = getDate(element.select("span.image-info-time").text().substring(1))
}
override fun chapterListSelector() = "html"
// Pages
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
override fun latestUpdatesFromElement(element: Element): SManga {
throw UnsupportedOperationException()
}
override fun latestUpdatesNextPageSelector(): String? {
throw UnsupportedOperationException()
}
override fun latestUpdatesRequest(page: Int): Request {
throw UnsupportedOperationException()
}
override fun latestUpdatesSelector(): String {
throw UnsupportedOperationException()
}
private fun getDate(str: String): Long {
return try {
DATE_FORMAT.parse(str)?.time ?: 0L
} catch (e: ParseException) {
0L
}
}
companion object {
private val DATE_FORMAT by lazy {
SimpleDateFormat("yyyy.M.d", Locale.ENGLISH)
}
}
}

View File

@ -1,7 +1,7 @@
ext {
extName = 'Hentai Cosplay'
extClass = '.HentaiCosplay'
extVersionCode = 3
extVersionCode = 4
isNsfw = true
}

View File

@ -24,7 +24,7 @@ class HentaiCosplay : HttpSource() {
override val name = "Hentai Cosplay"
override val baseUrl = "https://hentai-cosplays.com"
override val baseUrl = "https://hentai-cosplay-xxx.com"
override val lang = "all"

View File

@ -1,15 +0,0 @@
package eu.kanade.tachiyomi.extension.all.mangatopsite
import eu.kanade.tachiyomi.multisrc.madara.Madara
import java.text.SimpleDateFormat
import java.util.Locale
class MangaTopSite : Madara(
"MangaTop.site",
"https://mangatop.site",
"all",
dateFormat = SimpleDateFormat("d MMM yyyy", Locale.ENGLISH),
) {
override val useNewChapterEndpoint = false
override val chapterUrlSuffix = ""
}

View File

@ -1,7 +1,7 @@
ext {
extName = 'NHentai'
extClass = '.NHFactory'
extVersionCode = 40
extVersionCode = 41
isNsfw = true
}

View File

@ -220,7 +220,7 @@ open class NHentai(
thumbnail_url = document.select("#cover > a > img").attr("data-src")
status = SManga.COMPLETED
artist = getArtists(document)
author = artist
author = getGroups(document)
// Some people want these additional details in description
description = "Full English and Japanese titles:\n"
.plus("$fullTitle\n")

View File

@ -2,8 +2,8 @@ ext {
extName = 'Thunder Scans'
extClass = '.ThunderScansFactory'
themePkg = 'mangathemesia'
baseUrl = 'https://en-thunderepic.com'
overrideVersionCode = 2
baseUrl = 'https://en-thunderscans.com'
overrideVersionCode = 4
}
apply from: "$rootDir/common.gradle"

View File

@ -14,14 +14,14 @@ class ThunderScansFactory : SourceFactory {
class ThunderScansAR : MangaThemesiaAlt(
"Thunder Scans",
"https://ar-thunderepic.com",
"https://thunderscans.com",
"ar",
dateFormat = SimpleDateFormat("MMM d, yyy", Locale("ar")),
)
class ThunderScansEN : MangaThemesiaAlt(
"Thunder Scans",
"https://en-thunderepic.com",
"https://en-thunderscans.com",
"en",
mangaUrlDirectory = "/comics",
)

View File

@ -0,0 +1,10 @@
ext {
extName = 'MangaHub'
extClass = '.MangaHub'
themePkg = 'zeistmanga'
baseUrl = 'https://www.mangahub.link'
overrideVersionCode = 0
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,23 @@
package eu.kanade.tachiyomi.extension.ar.mangahub
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
import eu.kanade.tachiyomi.network.interceptor.rateLimit
class MangaHub : ZeistManga(
"MangaHub",
"https://www.mangahub.link",
"ar",
) {
override val client = super.client.newBuilder()
.rateLimit(3)
.build()
override val popularMangaSelector = "div#PopularPosts2 article"
override val popularMangaSelectorTitle = "h3"
override val popularMangaSelectorUrl = "a"
override val mangaDetailsSelector = ".grid.gap-5.gta-series"
override val mangaDetailsSelectorGenres = "dt:contains(التصنيف) + dd a[rel=tag]"
override val pageListSelector = "article#reader .separator, div.image-container"
}

View File

@ -2,8 +2,8 @@ ext {
extName = 'MangaNoon'
extClass = '.MangaNoon'
themePkg = 'mangathemesia'
baseUrl = 'https://manjanoon.co'
overrideVersionCode = 3
baseUrl = 'https://noonscan.net'
overrideVersionCode = 4
isNsfw = false
}

View File

@ -7,7 +7,7 @@ import java.util.Calendar
class MangaNoon : MangaThemesia(
"مانجا نون",
"https://manjanoon.co",
"https://noonscan.net",
"ar",
) {

View File

@ -3,7 +3,7 @@ ext {
extClass = '.MangaPro'
themePkg = 'mangathemesia'
baseUrl = 'https://promanga.pro'
overrideVersionCode = 2
overrideVersionCode = 3
}
apply from: "$rootDir/common.gradle"

View File

@ -1,6 +1,9 @@
package eu.kanade.tachiyomi.extension.ar.mangapro
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.source.model.Page
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.jsoup.nodes.Document
import java.text.SimpleDateFormat
import java.util.Locale
@ -11,4 +14,30 @@ class MangaPro : MangaThemesia(
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
) {
override val versionId = 3
override fun pageListParse(document: Document): List<Page> {
return super.pageListParse(document).onEach {
val httpUrl = it.imageUrl!!.toHttpUrl()
if (wpImgRegex.containsMatchIn(httpUrl.host)) {
it.imageUrl = StringBuilder().apply {
val ssl = httpUrl.queryParameter("ssl")
when (ssl) {
null -> append(httpUrl.scheme)
"0" -> append("http")
else -> append("https")
}
append("://")
append(httpUrl.pathSegments.joinToString("/"))
val search = httpUrl.queryParameter("q")
if (search != null) {
append("?q=")
append(search)
}
}.toString()
}
}
}
}
private val wpImgRegex = Regex("""i\d+\.wp\.com""")

View File

@ -2,8 +2,8 @@ ext {
extName = 'MangaSwat'
extClass = '.MangaSwat'
themePkg = 'mangathemesia'
baseUrl = 'https://maxlevelteam.com'
overrideVersionCode = 20
baseUrl = 'https://tatwt.com'
overrideVersionCode = 21
}
apply from: "$rootDir/common.gradle"

View File

@ -24,7 +24,7 @@ import java.util.Locale
class MangaSwat :
MangaThemesia(
"MangaSwat",
"https://maxlevelteam.com",
"https://tatwt.com",
"ar",
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
),

View File

@ -2,8 +2,8 @@ ext {
extName = 'Rocks Manga'
extClass = '.RocksManga'
themePkg = 'madara'
baseUrl = 'https://rocks-manga.com'
overrideVersionCode = 0
baseUrl = 'https://rocksmanga.com'
overrideVersionCode = 1
isNsfw = false
}

View File

@ -2,39 +2,65 @@ package eu.kanade.tachiyomi.extension.ar.rocksmanga
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class RocksManga : Madara(
"Rocks Manga",
"https://rocks-manga.com",
"https://rocksmanga.com",
"ar",
dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar")),
) {
override fun popularMangaSelector() = ".shido-manga"
override val popularMangaUrlSelector = "a.s-manga-title"
override val mangaDetailsSelectorTitle = ".title"
override val mangaDetailsSelectorAuthor = ".heading:contains(المؤلف:) + .content a"
override val mangaDetailsSelectorArtist = ".heading:contains(الرسام:) + .content a"
override fun popularMangaSelector() = "div.page-content-listing > .manga"
override val popularMangaUrlSelector = "div.manga-poster a"
override fun popularMangaFromElement(element: Element): SManga {
return super.popularMangaFromElement(element).apply {
title = element.selectFirst(popularMangaUrlSelector)!!.attr("title")
}
}
override fun searchMangaSelector() = "#manga-search-results .manga-item"
override fun searchMangaFromElement(element: Element): SManga {
val manga = SManga.create()
with(element) {
selectFirst("a.cover")!!.let {
manga.setUrlWithoutDomain(it.attr("abs:href"))
manga.title = it.attr("title")
}
selectFirst("img")?.let {
manga.thumbnail_url = imageFromElement(it)
}
}
return manga
}
override val mangaDetailsSelectorTitle = ".manga-title"
override val mangaDetailsSelectorAuthor = "div.meta span:contains(المؤلف:) + span a"
override val mangaDetailsSelectorArtist = "div.meta span:contains(الرسام:) + span a"
override val mangaDetailsSelectorStatus = ".status"
override val mangaDetailsSelectorDescription = ".story"
override val mangaDetailsSelectorThumbnail = ".profile-manga .poster img"
override val mangaDetailsSelectorGenre = ".heading:contains(التصنيف:) + .content a"
override val altNameSelector = ".other-name"
override fun chapterListSelector() = "#chapter-list li.chapter-item"
override fun chapterDateSelector() = ".ch-post-time"
override val pageListParseSelector = ".reading-content img"
override val mangaDetailsSelectorDescription = "div.description"
override val mangaDetailsSelectorThumbnail = ".manga-poster img"
override val mangaDetailsSelectorGenre = "div.meta span:contains(التصنيف:) + span a"
override val altNameSelector = "div.alternative"
override fun chapterListSelector() = ".chapters-list li.chapter-item"
override fun chapterDateSelector() = ".chapter-release-date"
override val pageListParseSelector = ".chapter-reading-page img"
override val useLoadMoreRequest = LoadMoreStrategy.Never
override val useNewChapterEndpoint = false
override val fetchGenres = false
override val filterNonMangaItems = false
override fun chapterFromElement(element: Element): SChapter {
val chapter = super.chapterFromElement(element)
chapter.name = element.selectFirst(".detail-ch")!!.text()
chapter.name = element.selectFirst(".num")!!.text()
return chapter
}
}

View File

@ -1,7 +1,7 @@
ext {
extName = 'Team X'
extClass = '.TeamX'
extVersionCode = 17
extVersionCode = 18
isNsfw = false
}

View File

@ -1,7 +1,12 @@
package eu.kanade.tachiyomi.extension.ar.teamx
import android.app.Application
import android.content.SharedPreferences
import android.widget.Toast
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
@ -14,15 +19,19 @@ import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class TeamX : ParsedHttpSource() {
class TeamX : ParsedHttpSource(), ConfigurableSource {
override val name = "Team X"
override val baseUrl = "https://teamxnovel.com"
private val defaultBaseUrl = "https://teamoney.site"
override val baseUrl by lazy { getPrefBaseUrl() }
override val lang = "ar"
@ -34,6 +43,10 @@ class TeamX : ParsedHttpSource() {
.rateLimit(10, 1, TimeUnit.SECONDS)
.build()
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
// Popular
override fun popularMangaRequest(page: Int): Request {
@ -130,6 +143,14 @@ class TeamX : ParsedHttpSource() {
}
genre = document.select("div.review-author-info a").joinToString { it.text() }
thumbnail_url = document.select("div.text-right img").first()!!.absUrl("src")
status = document
.selectFirst(".full-list-info > small:first-child:contains(الحالة) + small")
?.text()
.toStatus()
author = document
.selectFirst(".full-list-info > small:first-child:contains(الرسام) + small")
?.text()
?.takeIf { it != "غير معروف" }
}
}
@ -187,6 +208,14 @@ class TeamX : ParsedHttpSource() {
}.getOrNull() ?: 0
}
private fun String?.toStatus() = when (this) {
"مستمرة" -> SManga.ONGOING
"قادم قريبًا" -> SManga.ONGOING // "coming soon"
"مكتمل" -> SManga.COMPLETED
"متوقف" -> SManga.ON_HIATUS
else -> SManga.UNKNOWN
}
// Pages
override fun pageListParse(document: Document): List<Page> {
@ -196,4 +225,41 @@ class TeamX : ParsedHttpSource() {
}
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
companion object {
private const val RESTART_APP = ".لتطبيق الإعدادات الجديدة أعد تشغيل التطبيق"
private const val BASE_URL_PREF_TITLE = "تعديل الرابط"
private const val BASE_URL_PREF = "overrideBaseUrl"
private const val BASE_URL_PREF_SUMMARY = ".للاستخدام المؤقت. تحديث التطبيق سيؤدي الى حذف الإعدادات"
private const val DEFAULT_BASE_URL_PREF = "defaultBaseUrl"
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val baseUrlPref = androidx.preference.EditTextPreference(screen.context).apply {
key = BASE_URL_PREF
title = BASE_URL_PREF_TITLE
summary = BASE_URL_PREF_SUMMARY
this.setDefaultValue(defaultBaseUrl)
dialogTitle = BASE_URL_PREF_TITLE
dialogMessage = "Default: $defaultBaseUrl"
setOnPreferenceChangeListener { _, _ ->
Toast.makeText(screen.context, RESTART_APP, Toast.LENGTH_LONG).show()
true
}
}
screen.addPreference(baseUrlPref)
}
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!!
init {
preferences.getString(DEFAULT_BASE_URL_PREF, null).let { prefDefaultBaseUrl ->
if (prefDefaultBaseUrl != defaultBaseUrl) {
preferences.edit()
.putString(BASE_URL_PREF, defaultBaseUrl)
.putString(DEFAULT_BASE_URL_PREF, defaultBaseUrl)
.apply()
}
}
}
}

View File

@ -0,0 +1,9 @@
ext {
extName = 'Altay Scans'
extClass = '.AltayScans'
themePkg = 'mangathemesia'
baseUrl = 'https://altayscans.com'
overrideVersionCode = 0
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,14 @@
package eu.kanade.tachiyomi.extension.en.altayscans
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.interceptor.rateLimit
class AltayScans : MangaThemesia(
"Altay Scans",
"https://altayscans.com",
"en",
) {
override val client = super.client.newBuilder()
.rateLimit(3)
.build()
}

View File

@ -1,9 +0,0 @@
ext {
extName = 'Ansh Scans'
extClass = '.AnshScans'
themePkg = 'madara'
baseUrl = 'https://anshscans.org'
overrideVersionCode = 1
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,11 +0,0 @@
package eu.kanade.tachiyomi.extension.en.anshscans
import eu.kanade.tachiyomi.multisrc.madara.Madara
class AnshScans : Madara("Ansh Scans", "https://anshscans.org", "en") {
override val useNewChapterEndpoint = true
override val mangaDetailsSelectorStatus = "div.summary-heading:contains(Status) + div.summary-content"
override val mangaSubString = "comic"
}

View File

@ -0,0 +1,9 @@
ext {
extName = 'Astra Scans'
extClass = '.AstraScans'
themePkg = 'mangathemesia'
baseUrl = 'https://astrascans.org'
overrideVersionCode = 0
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -0,0 +1,15 @@
package eu.kanade.tachiyomi.extension.en.astrascans
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.interceptor.rateLimit
class AstraScans : MangaThemesia(
"Astra Scans",
"https://astrascans.org",
"en",
"/series",
) {
override val client = super.client.newBuilder()
.rateLimit(3)
.build()
}

View File

@ -1,7 +1,7 @@
ext {
extName = 'Asura Scans'
extClass = '.AsuraScans'
extVersionCode = 36
extVersionCode = 39
}
apply from: "$rootDir/common.gradle"

View File

@ -205,7 +205,12 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
description = document.selectFirst("span.font-medium.text-sm")?.text()
author = document.selectFirst("div.grid > div:has(h3:eq(0):containsOwn(Author)) > h3:eq(1)")?.ownText()
artist = document.selectFirst("div.grid > div:has(h3:eq(0):containsOwn(Artist)) > h3:eq(1)")?.ownText()
genre = document.select("div[class^=space] > div.flex > button.text-white").joinToString { it.ownText() }
genre = buildList {
document.selectFirst("div.flex:has(h3:eq(0):containsOwn(type)) > h3:eq(1)")
?.ownText()?.let(::add)
document.select("div[class^=space] > div.flex > button.text-white")
.forEach { add(it.ownText()) }
}.joinToString()
status = parseStatus(document.selectFirst("div.flex:has(h3:eq(0):containsOwn(Status)) > h3:eq(1)")?.ownText())
}
@ -229,10 +234,10 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
override fun chapterListSelector() = "div.scrollbar-thumb-themecolor > a.block"
override fun chapterListSelector() = "div.scrollbar-thumb-themecolor > div.group"
override fun chapterFromElement(element: Element) = SChapter.create().apply {
setUrlWithoutDomain(element.attr("abs:href").toPermSlugIfNeeded())
setUrlWithoutDomain(element.selectFirst("a")!!.attr("abs:href").toPermSlugIfNeeded())
name = element.selectFirst("h3:eq(0)")!!.text()
date_upload = try {
val text = element.selectFirst("h3:eq(1)")!!.ownText()
@ -253,7 +258,7 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
}
override fun pageListParse(document: Document): List<Page> {
return document.select("div > img[alt=chapter]").mapIndexed { i, element ->
return document.select("div > img[alt*=chapter]").mapIndexed { i, element ->
Page(i, imageUrl = element.attr("abs:src"))
}
}

View File

@ -1,6 +1,6 @@
ext {
extName = 'AgiToon'
extClass = '.AgiToon'
extName = 'Atsumaru'
extClass = '.Atsumaru'
extVersionCode = 1
isNsfw = true
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,156 @@
package eu.kanade.tachiyomi.extension.en.atsumaru
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import uy.kohesive.injekt.injectLazy
class Atsumaru : HttpSource() {
override val name = "Atsumaru"
override val baseUrl = "https://atsu.moe"
private val apiUrl = "$baseUrl/api/v1"
override val lang = "en"
override val supportsLatest = true
override val client = network.cloudflareClient.newBuilder()
.rateLimit(2)
.build()
override fun headersBuilder() = super.headersBuilder()
.add("Referer", "$baseUrl/")
private fun apiHeadersBuilder() = headersBuilder().apply {
add("Accept", "*/*")
add("Host", apiUrl.toHttpUrl().host)
}
private val apiHeaders by lazy { apiHeadersBuilder().build() }
private val json: Json by injectLazy()
// ============================== Popular ===============================
override fun popularMangaRequest(page: Int): Request {
return GET("$apiUrl/layouts/s1/sliders/hotUpdates", apiHeaders)
}
override fun popularMangaParse(response: Response): MangasPage {
val data = response.parseAs<BrowseMangaDto>().items
return MangasPage(data.map { it.manga.toSManga() }, false)
}
// =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int): Request {
return GET("$apiUrl/layouts/s1/latest-updates", apiHeaders)
}
override fun latestUpdatesParse(response: Response): MangasPage {
return popularMangaParse(response)
}
// =============================== Search ===============================
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = "$apiUrl/search".toHttpUrl().newBuilder()
.addPathSegment(query)
.build()
return GET(url, apiHeaders)
}
override fun searchMangaParse(response: Response): MangasPage {
val data = response.parseAs<SearchResultsDto>().hits
return MangasPage(data.map { it.info.toSManga() }, false)
}
// =========================== Manga Details ============================
override fun getMangaUrl(manga: SManga): String {
return baseUrl + manga.url
}
override fun mangaDetailsRequest(manga: SManga): Request {
return GET(apiUrl + manga.url, apiHeaders)
}
override fun mangaDetailsParse(response: Response): SManga {
return response.parseAs<MangaObjectDto>().manga.toSManga()
}
// ============================== Chapters ==============================
override fun chapterListRequest(manga: SManga): Request {
return mangaDetailsRequest(manga)
}
override fun chapterListParse(response: Response): List<SChapter> {
val chapterList = response.parseAs<MangaObjectDto>().manga.chapters!!.map {
it.toSChapter(response.request.url.pathSegments.last())
}
return chapterList.sortedWith(
compareBy(
{ it.chapter_number },
{ it.scanlator },
),
).reversed()
}
override fun getChapterUrl(chapter: SChapter): String {
val (slug, name) = chapter.url.split("/")
return "$baseUrl/read/s1/$slug/$name/1"
}
// =============================== Pages ================================
override fun pageListRequest(chapter: SChapter): Request {
val (slug, name) = chapter.url.split("/")
return GET("$apiUrl/manga/s1/$slug#$name", apiHeaders)
}
override fun pageListParse(response: Response): List<Page> {
val chapter = response.parseAs<MangaObjectDto>().manga.chapters!!.first {
it.name == response.request.url.fragment
}
return chapter.pages.map { page ->
Page(page.name.toInt(), imageUrl = page.pageURLs.first())
}.sortedBy { it.index }
}
override fun imageRequest(page: Page): Request {
val imgHeaders = headersBuilder().apply {
add("Accept", "image/avif,image/webp,*/*")
add("Host", page.imageUrl!!.toHttpUrl().host)
}.build()
return GET(page.imageUrl!!, imgHeaders)
}
override fun imageUrlParse(response: Response): String {
throw UnsupportedOperationException()
}
// ============================= Utilities ==============================
private inline fun <reified T> Response.parseAs(): T {
return json.decodeFromString(body.string())
}
}

View File

@ -0,0 +1,115 @@
package eu.kanade.tachiyomi.extension.en.atsumaru
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.Serializable
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
@Serializable
class BrowseMangaDto(
val items: List<MangaObjectDto>,
)
@Serializable
class MangaObjectDto(
val manga: MangaDto,
)
@Serializable
class SearchResultsDto(
val hits: List<SearchMangaDto>,
) {
@Serializable
class SearchMangaDto(
val info: MangaDto,
)
}
@Serializable
class MangaDto(
// Common
private val title: String,
private val cover: String,
private val slug: String,
// Details
private val authors: List<String>? = null,
private val description: String? = null,
private val genres: List<String>? = null,
private val statuses: List<String>? = null,
// Chapters
val chapters: List<ChapterDto>? = null,
) {
fun toSManga(): SManga = SManga.create().apply {
title = this@MangaDto.title
thumbnail_url = cover
url = "/manga/s1/$slug"
authors?.let {
author = it.joinToString()
}
description = this@MangaDto.description
genres?.let {
genre = it.joinToString()
}
statuses?.let {
status = when (it.first().lowercase().substringBefore(" ")) {
"ongoing" -> SManga.ONGOING
"complete" -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
}
}
}
@Serializable
class ChapterDto(
val pages: List<PageDto>,
val name: String,
private val type: String,
private val title: String? = null,
private val date: String? = null,
) {
fun toSChapter(slug: String): SChapter = SChapter.create().apply {
val chapterNumber = this@ChapterDto.name.replace("_", ".")
.filter { it.isDigit() || it == '.' }
name = buildString {
append("Chapter ")
append(chapterNumber)
if (title != null) {
append(" - ")
append(title)
}
}
url = "$slug/${this@ChapterDto.name}"
chapter_number = chapterNumber.toFloat()
scanlator = type.takeUnless { it == "Chapter" }
date?.let {
date_upload = parseDate(it)
}
}
private fun parseDate(dateStr: String): Long {
return try {
DATE_FORMAT.parse(dateStr)!!.time
} catch (_: ParseException) {
0L
}
}
companion object {
private val DATE_FORMAT by lazy {
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH)
}
}
}
@Serializable
class PageDto(
val pageURLs: List<String>,
val name: String,
)

View File

@ -1,7 +1,7 @@
ext {
extName = 'ColoredManga'
extClass = '.ColoredManga'
extVersionCode = 3
extVersionCode = 35
isNsfw = true
}

View File

@ -1,9 +0,0 @@
ext {
extName = 'Comic Scans'
extClass = '.ComicScans'
themePkg = 'madara'
baseUrl = 'https://www.comicscans.org'
overrideVersionCode = 0
}
apply from: "$rootDir/common.gradle"

View File

@ -1,7 +0,0 @@
package eu.kanade.tachiyomi.extension.en.comicscans
import eu.kanade.tachiyomi.multisrc.madara.Madara
class ComicScans : Madara("Comic Scans", "https://www.comicscans.org", "en") {
override val useNewChapterEndpoint = true
}

View File

@ -2,8 +2,8 @@ ext {
extName = 'EnryuManga'
extClass = '.EnryuManga'
themePkg = 'mangathemesia'
baseUrl = 'https://enryumanga.com'
overrideVersionCode = 0
baseUrl = 'https://enryumanga.net'
overrideVersionCode = 1
}
apply from: "$rootDir/common.gradle"

View File

@ -2,4 +2,4 @@ package eu.kanade.tachiyomi.extension.en.enryumanga
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
class EnryuManga : MangaThemesia("EnryuManga", "https://enryumanga.com", "en")
class EnryuManga : MangaThemesia("EnryuManga", "https://enryumanga.net", "en")

View File

@ -0,0 +1,9 @@
ext {
extName = 'Eros Scans'
extClass = '.ErosScans'
themePkg = 'mangathemesia'
baseUrl = 'https://erosscans.xyz'
overrideVersionCode = 0
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -0,0 +1,14 @@
package eu.kanade.tachiyomi.extension.en.erosscans
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.interceptor.rateLimit
class ErosScans : MangaThemesia(
"Eros Scans",
"https://erosscans.xyz",
"en",
) {
override val client = super.client.newBuilder()
.rateLimit(3)
.build()
}

View File

@ -1,9 +1,9 @@
ext {
extName = 'Fire Scans'
extClass = '.FireScans'
extName = 'Firecomics'
extClass = '.Firecomics'
themePkg = 'madara'
baseUrl = 'https://firescans.xyz'
overrideVersionCode = 1
baseUrl = 'https://firecomics.org'
overrideVersionCode = 2
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -11,8 +11,9 @@ import kotlinx.serialization.json.jsonPrimitive
import okhttp3.OkHttpClient
import org.jsoup.nodes.Document
class FireScans : Madara("Fire Scans", "https://firescans.xyz", "en") {
class Firecomics : Madara("Firecomics", "https://firecomics.org", "en") {
override val id: Long = 5761461704760730187
override val client: OkHttpClient = super.client.newBuilder()
.rateLimit(20, 5)
.build()

View File

@ -1,7 +1,7 @@
ext {
extName = 'Hentai2Read'
extClass = '.Hentai2Read'
extVersionCode = 16
extVersionCode = 17
isNsfw = true
}

View File

@ -0,0 +1,10 @@
ext {
extName = 'HentaiDex'
extClass = '.HentaiDex'
themePkg = 'mangathemesia'
baseUrl = 'https://dexhentai.com'
overrideVersionCode = 0
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Some files were not shown because too many files have changed in this diff Show More