Compare commits

...

157 Commits

Author SHA1 Message Date
AwkwardPeak7 e0bb39f99a
swap injekt again
CI / Prepare job (push) Successful in 5s Details
CI / Build individual modules (push) Successful in 7m17s Details
CI / Publish repo (push) Successful in 53s Details
2024-09-15 20:42:59 +01:00
AwkwardPeak7 6032b0853f
swap injekt 2024-09-15 20:42:59 +01:00
Smol Ame 2802de7b62
Iken: Adjust DTO to handle 'isNovel' & 'mangaSlug' (#5071)
* Iken: Bump versionCode

* Iken: Adjust IkenDTO to handle isNovel, slug fields with ChapterPostDetails slug (courtesy of bapeey)

---------

Co-authored-by: bapeey <90949336+bapeey@users.noreply.github.com>
2024-09-15 20:42:59 +01:00
Chopper 8c426ce4fb
Add AnisaScans (#5068) 2024-09-15 20:42:59 +01:00
Chopper e74443b530
Remove AlliedFansub (#5067) 2024-09-15 20:42:59 +01:00
Chopper fdcadcd5a1
Remove HentaiKeyfi (#5066) 2024-09-15 20:42:59 +01:00
Chopper c1435f4c2f
Remove PrazeresViolentos (#5065) 2024-09-15 20:42:59 +01:00
Chopper 0b1efd70bd
YaoiFanClub: Fix webview (#5064)
Fix webview - age validation
2024-09-15 20:42:59 +01:00
Dexroneum 708f2cc55f
[RU] LibGroup: Update icons (#5059) 2024-09-15 20:42:57 +01:00
Vetle Ledaal c3e3a3d5c7
Luna Scans: update domain (#5055) 2024-09-15 20:42:57 +01:00
Vetle Ledaal 0f7c99bc52
Tecno Scans: update domain, add override URL setting (#5054) 2024-09-15 20:42:57 +01:00
Vetle Ledaal ea19c76636
Dua Leo Truyen: update domain (#5053) 2024-09-15 20:42:57 +01:00
Smol Ame abf3dca6fd
Vortex Scans: Update domain (#5026)
* Vortex Scans: Bump versionCode

* Vortex Scans: Update baseUrl
2024-09-15 20:42:57 +01:00
AwkwardPeak7 33e3638351
LuaScans: change theme (#5034) 2024-09-15 20:42:57 +01:00
Smol Ame d1c75db514
Add Bega Translation (#5027)
* Madara: Add "Publicándose" to Ongoing, bumped `baseVersionCode`

* Add Bega Translation

* Bega Translation: Use `newChapterEndpoint` (hopefully)

* Bega Translation: Override override to "series"

* Madara: Unbump versionCode

* Bega Translation: Use HD covers
2024-09-15 20:42:57 +01:00
Hasan b7a770367b
Fix for chapter dates on source Hayalistic (#4890)
* Add source: Nox Scans

* Add source: Manga Tilkisi

* Update src/tr/noxscans/build.gradle

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>

* Update src/tr/mangatilkisi/build.gradle

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>

* Update MangaTilkisi.kt

* Remove MajorScans

* Remove MajorScans

* Fix for chapter dates on source Hayalistic

* Update src/tr/hayalistic/src/eu/kanade/tachiyomi/extension/tr/hayalistic/Hayalistic.kt

---------

Co-authored-by: hasanturkylmz <hasanturkylmz@outlook.com>
Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>
Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-09-15 20:42:57 +01:00
Luqman 50dd55646c
Mangatale: update domain, change selector, tweak rate limit (#5016)
closes #4986

- update domain
- change title selector
- tweak rate limit
2024-09-15 20:42:57 +01:00
bapeey 78fb4d0fcf
MangasNoSekai: Fix popular and latest (#5011)
* fixes

* use their library path
2024-09-15 20:42:57 +01:00
mr-brune e13faaeff9
Add Mitaku (#4991)
* mitaku 1.0

* mitaku 1.1

* mitaku 1.2

* mitaku 1.3

* mitaku 1.4

* mitaku 1.5

* mitaku 1.6
2024-09-15 20:42:57 +01:00
bapeey 12fb2353ad
MHScans: Update domain (#5003)
dd
2024-09-15 20:42:57 +01:00
KirinRaikage 5cee63f5bb
Lunar Scans Hentai -> Pornhwa Scans (#5000) 2024-09-15 20:42:57 +01:00
bapeey af8a367cfa
LectorTmo: Fix images not loading (#4997)
* fix

* Use url.fragment

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>

* bruh

---------

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>
2024-09-15 20:42:57 +01:00
Smol Ame 96d97d7275
Mangahall: Convert into MangaGeek (#4994)
* Mangageek: Bump versionCode

* MangaHall --> MangaGeek (file & package/ext name, baseUrl)

* MangaGeek: Update logo
2024-09-15 20:42:57 +01:00
TheKingTermux 4559cdf121
Add IchiroManga (#4992) 2024-09-15 20:42:57 +01:00
AlphaBoom 1883e7a889
Sixmanhua: Fix page parsing (#4989) 2024-09-15 20:42:57 +01:00
Chopper c0e41cb54c
SlimeRead: Fix popularManga (#4973)
* Fix popularManga URL

* Fix lint

* Remove extra line

* Remove rateLimitHost

* Remove unused import

* Remove Pair statement
2024-09-15 20:42:57 +01:00
bapeey 606e70fc75
Mangago: Add random UA and mobile UA support (#4978)
* randomua

* Revert "randomua"

This reverts commit d7dab1d59099bb2a2ef32eab4249e2dd9c3b76c8.

* mmmmmmm

* reduce cache time

* extract function
2024-09-15 20:42:57 +01:00
Chopper 66244d5c2c
YugenMangas: Update domain and fix chapters (#4977)
* Fix YugenMangas

* Changes

* Add getSeriesCode
2024-09-15 20:42:57 +01:00
Vetle Ledaal 9a08636bda
Keyoapp: add support for new CDN (#4970)
* Kewn Scans: fix chapter pages

* Remove Rudra Scans

* Keyoapp: add support for new CDN

* Don't bump Kewn Scans twice
2024-09-15 20:42:57 +01:00
Vetle Ledaal a92b59fb3f
Remove Void Scans (#4969) 2024-09-15 20:42:56 +01:00
Vetle Ledaal 90eb12294c
Remove A Pair Of 2+, migrate Sadscans from old multisrc (#4955)
* Remove A Pair Of 2+

* move Sadscans from multisrc
2024-09-15 20:42:56 +01:00
bapeey f8ab0d3f2f
MANGA Plus: Add preference to remove the chapter number from the name and add the site name as scanlator (#4965)
* asasdsa

* more

* this is useless
2024-09-15 20:42:49 +01:00
bapeey 20b3c8ac86
Flame Comics: Fix page selector (#4960)
selector
2024-09-15 20:23:10 +01:00
Smol Ame 68f096e7c8
TruyenVN: Update domain (#4953)
* TruyenVN: Bump versionCode

* TruyenVN: Update baseUrl
2024-09-15 20:23:10 +01:00
Smol Ame a4aea82374
Cat300: Update domain (#4952)
* Cat300: Bump versionCode

* Cat300: Update baseUrl
2024-09-15 20:23:10 +01:00
Smol Ame 72585f0b78
MeituaTop: Remove extension (#4951) 2024-09-15 20:23:10 +01:00
AlphaBoom da86cb3ac1
colamanga: fix load image failed (#4950) 2024-09-15 20:23:10 +01:00
Smol Ame a8d36f9eca
MagusManga: Update image URL (#4949)
* Bump versionCode

* MagusManga: Update cdnUrl

* MagusManga: Remove fallbackCdnInterceptor
2024-09-15 20:23:10 +01:00
AwkwardPeak7 0af3536837
Mangadex: fix potential anr and remove ua pref (#4935)
* Mangadex: fix potential anr and remove ua pref

* remove unused stuff

* don't remove tachi ua
2024-09-15 20:23:10 +01:00
bapeey 3b826e0365
IkigaiMangas: Update domain (#4930)
update domain
2024-09-15 20:23:10 +01:00
dngonz 076ee3f5de
MangaEffect: remove source (#4922) 2024-09-15 20:23:10 +01:00
mr-brune 71e7c34dd7
hentaifantasy: Thumbnail support (#4919)
* thumnail support

* change version
2024-09-15 20:23:10 +01:00
AwkwardPeak7 7dd03b565b
fix build 2024-09-15 20:23:10 +01:00
mr-brune ba388ba801
Add HentaiArchive (#4807)
* Hentaiarchive beta

* Hentai Archive

* add page searchsupport

* remove debug

* better tag

* Update src/it/hentaiarchive/src/eu/kanade/tachiyomi/extension/it/hentaiarchive/HentaiArchive.kt

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

* Update src/it/hentaiarchive/src/eu/kanade/tachiyomi/extension/it/hentaiarchive/HentaiArchive.kt

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

* Update src/it/hentaiarchive/src/eu/kanade/tachiyomi/extension/it/hentaiarchive/HentaiArchive.kt

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

* Update src/it/hentaiarchive/src/eu/kanade/tachiyomi/extension/it/hentaiarchive/HentaiArchive.kt

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

* Update src/it/hentaiarchive/src/eu/kanade/tachiyomi/extension/it/hentaiarchive/HentaiArchive.kt

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

* fix

* fix most thing

* Update HentaiArchive.kt

* Update src/it/hentaiarchive/src/eu/kanade/tachiyomi/extension/it/hentaiarchive/HentaiArchive.kt

---------

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-09-15 20:23:10 +01:00
TheKingTermux 4addb7dad3
LianScans : Update BaseURL (#4914)
* LianScans : Update BaseURL

* Increase VersionCode
2024-09-15 20:23:09 +01:00
dngonz 47380ab91d
Dynasty scanlator (#4913)
* Dynasty: add scnalator

* Dynasty: bump
2024-09-15 20:23:09 +01:00
TheKingTermux 66c2007490
ManhwaList : Update BaseURL (#4912) 2024-09-15 20:23:09 +01:00
dngonz dc2fede86f
Rocksmanga: fix chapters (#4911)
Rocksmanga: fix chapter selector
2024-09-15 20:23:09 +01:00
Cuong-Tran dddecfbe05
Move ComicsValley to multi-language (#4904) 2024-09-15 20:23:09 +01:00
extmisc 7792ab3013
TeamLanhLung: Update domain (#4898)
* TeamLanhLung: Update Domain

* TeamLanhLung: Update Domain

---------

Co-authored-by: SCONE <scone.dns@gmail.com>
2024-09-15 20:23:09 +01:00
Deivid Gabriel Pereira de Oliveira 3ecfc66689
DemonSect(Seita Celestial): update icons and extension name (#4891)
* Rename "DemonSect" as "Seita Celestial", update logos

* Rename File name to: "SeitaCelestial"
2024-09-15 20:23:09 +01:00
dngonz 3f964e8b2c
Reset Scans: fix chapter names (#4883)
* Reset Scans: change chapter selector

* Reset Scans: bump
2024-09-15 20:23:09 +01:00
David Alysson cad87f7e78
TyrantScans: Enable latestUpdate (#4878)
Enable latestUpdate
2024-09-15 20:23:09 +01:00
David Alysson 7663887261
LunarScans: Add random User-Agent (#4877)
Add random User-Agent
2024-09-15 20:23:09 +01:00
ringosham a65e48cb1b
Nicovideo: Improve error handle on fetch page list (#4874)
* Improve error handle on fetch page list

* Text change for better clarity

* Clarify comments
2024-09-15 20:23:09 +01:00
dngonz c600831a70
Comics Valley: fix latest and popular (#4863)
* Comics Valley: change mangaSubString

* Comics Valley: bump

* ComicsValley: improve request performance
2024-09-15 20:23:09 +01:00
dngonz 7d7a127ae2
JManga: remove extension (#4866) 2024-09-15 20:23:03 +01:00
dngonz 07a8f8fe9e
Koharu: Show others (#4850)
* Koharu: add others to description

* Koharu: change others to genre
2024-09-15 20:23:03 +01:00
bapeey 5e5e60e8bd
MangaDemon: Fix bad url in some entries (#4861)
* smh

* change var name
2024-09-15 20:23:03 +01:00
bapeey 6b4dbb1d3d
MangaDemon: Update to new site structure (#4857)
* fix

* bruh
2024-09-15 20:23:03 +01:00
Hasan e11342f5df
Add source: Nox Scans & MangaTilkisi (#4854)
* Add source: Nox Scans

* Add source: Manga Tilkisi

* Update src/tr/noxscans/build.gradle

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>

* Update src/tr/mangatilkisi/build.gradle

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>

* Update MangaTilkisi.kt

* Remove MajorScans

* Remove MajorScans

---------

Co-authored-by: hasanturkylmz <hasanturkylmz@outlook.com>
Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>
2024-09-15 20:23:03 +01:00
Smol Ame 6ca8f886ed
Lua Scans (Unoriginal): Update domain (#4848)
* Bump versionCode

* Update baseURL
2024-09-15 20:23:03 +01:00
bapeey 4ce4b79054
ResetScans: Fix chapter list and filter out paywalled chapters (#4845)
fix
2024-09-15 20:23:03 +01:00
bapeey f6bf98b764
ArgosComics: Ignore ssl errors (#4844)
ignore ssl
2024-09-15 20:23:03 +01:00
bapeey 4e3f2d235f
Xoxocomics: Fix pages (#4843)
* fix

* bump
2024-09-15 20:23:03 +01:00
bapeey 57bbef431b
OppaiStream: Fix no chapters found and manga details (#4842)
fix
2024-09-15 20:23:03 +01:00
bapeey 925e50d120
Emperor Scan: Update domain (#4841)
update domain
2024-09-15 20:23:03 +01:00
bapeey a88503f4f4
Noblesse Translations: Update domain (#4840)
update domain
2024-09-15 20:23:03 +01:00
bapeey 87a1c4b5fe
MHScans: Update domain (#4832)
update domain
2024-09-15 20:23:03 +01:00
bapeey 6b9115a327
MangaHere: Fix http 500 (#4830)
idk
2024-09-15 20:23:03 +01:00
dngonz ff8b61ce59
MangaKimi (#4821)
added mangakimi
2024-09-15 20:23:03 +01:00
dngonz 57d69df4d9
Manhwabuddy (#4810)
* added manhwabuddy

* requested changes

* fix description

* remove invalid png
2024-09-15 20:23:03 +01:00
Vetle Ledaal 71ee8dc587
Upgrade some extensions from HTTP to HTTPS (#4816)
* Café com Yaoi: upgrade to https

* KomikIndo.info: upgrade to https

* LemonFont: upgrade to https

* NIFTeam: upgrade to https

* TuttoAnimeManga: upgrade to https

* Sodsaime: upgrade to https
2024-09-15 20:23:03 +01:00
Paco Chrispijn 27bf92cc04
Truyen tranh dam my domain change (#4801) 2024-09-15 20:23:03 +01:00
long21wt 81aa3a5d21
NhatTruyen: update search path (#4800)
Update search path for searching and migrating function
2024-09-15 20:23:03 +01:00
Vetle Ledaal 77aafd4076
Remove Mangakakalots (unoriginal) (#4793) 2024-09-15 20:23:03 +01:00
Creepler13 f75ed7f762
MangaHall domain change (#4791) 2024-09-15 20:23:03 +01:00
Creepler13 30c9647669
Atikrost domain change (#4790) 2024-09-15 20:23:03 +01:00
Wackery 3fe52c264d
ReaperScans: Fix date format (#4780) 2024-09-15 20:23:03 +01:00
Wackery b00c569c12
ReaperScans: Fix page listing (#4779)
* HeanCMS: Implement alternate chapter page format.

* HeanCMS: Up version code

* Revert "HeanCMS: Up version code"

This reverts commit 16b35d5e0fc9e287addfc19731ebd19b2e93b266.

* Revert "HeanCMS: Implement alternate chapter page format."

This reverts commit e81de53aec1aade5df17a6303239c70c7c6de808.

* ReaperScans: Fix chapter page list

* ReaperScans: Remove unused import

* ReaperScans: Up version number + whitespace

* ReaperScans: Actually put the Dto in the same package.

* ReaperScans: Formatting...
2024-09-15 20:23:03 +01:00
roolyz c162877800
Comicaso domain changed (#4778) 2024-09-15 20:23:03 +01:00
KirinRaikage 195b3771d3
VF Scan: Update domain (#4767) 2024-09-15 20:23:03 +01:00
AwkwardPeak7 5a6c302a6d
Magus Manga: domain & theme change (#4766) 2024-09-15 20:23:03 +01:00
mohamedotaku 2d16d1896b
update url ar.thunderscans "all" (#4765) 2024-09-15 20:23:03 +01:00
roolyz a973660aa0
Siyahmelek (grimelek) domain changed (#4760) 2024-09-15 20:23:02 +01:00
Tran M. Cuong 08c07a08dd
Move Kiutaku from en to all (#4755) 2024-09-15 20:23:02 +01:00
Chopper bbd983389a
YugenMangas: Update domains (#4743)
* Update domains

* Bump versionId
2024-09-15 20:23:02 +01:00
AwkwardPeak7 d655d6b23f
Luminousscans -> RadiantScans: update domain (#4748) 2024-09-15 20:23:02 +01:00
AwkwardPeak7 96113ce68e
SeiManga & Grouple sources domain prefs update (#4749)
* Added SeiManga extension (#4561)

* Added SeiManga extension

* Changed overrideVersionCode in build.gradle to 0

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

* Omitting id override from SeiManga.kt

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

* Removed a "needless blank line" because overpedantic Kotlin compiler said so

Seriously, what compiler in the world would even consider a blank line an error?

* Update SeiManga.kt

* Update GroupLe.kt

* Update build.gradle.kts

* Update AllHentai.kt

* Update MintManga.kt

* Update AllHentai.kt

* Update SeiManga.kt

* Update build.gradle

* Update build.gradle

---------

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

* readmanga(ru): domain pref

* rumix(ru): domain pref

* rselfmanga(ru): domain pref

* private preference...

---------

Co-authored-by: Teashrock <kajitsu22@gmail.com>
2024-09-15 20:23:02 +01:00
AwkwardPeak7 bc6ebbb394
Improve build times for local builds (#4655)
improve
2024-09-15 20:23:02 +01:00
Orion 2dcaabffb4
Nightscans domain changed (#4744)
Co-authored-by: apakekbebas <grayfieldrb@gmail.com>
2024-09-15 20:23:02 +01:00
Pedro Azevedo a6659a97dc
DemonSect: Updated Domain (#4742) 2024-09-15 20:23:02 +01:00
KirinRaikage edff39f57e
Sushiscan.fr: Fix search (#4740) 2024-09-15 20:22:49 +01:00
Chopper 589ebcd677
DiskusScan: Fix loading content (#4738)
* Fix loading content

* Bump version
2024-09-15 20:22:01 +01:00
Chopper 4c947f56b9
HuntersScans: Update domain (#4737)
Update domain
2024-09-15 20:22:01 +01:00
mohamedotaku 8a8eaf675e
add source Scans 4u "ar" (#4732)
* add source Scans 4u "ar"

* Update build.gradle
2024-09-15 20:22:01 +01:00
mohamedotaku d571f6b6d8
Update Url Manganoon "ar" (#4731) 2024-09-15 20:22:01 +01:00
mohamedotaku ee9df7d875
Update url mangaswat "ar" (#4730) 2024-09-15 20:22:01 +01:00
Creepler13 bd7aa80936
Add Comicskingdom (#4691)
* init

* adds comicskindom

* lint error

* Update fix search switch to api

* formatting

* Genre filter now Tristate

* Requested Changes

* Requested Changes
2024-09-15 20:22:00 +01:00
Creepler13 1671af188e
Add LeerComicsOnline (#4728)
* Add LeerComicsOnline

* Requested Changes
2024-09-15 20:22:00 +01:00
Creepler13 e11ebc5fd0
Lunascans domain change (#4720) 2024-09-15 20:22:00 +01:00
Creepler13 6457e349f5
Firescans domain + name change (#4719) 2024-09-15 20:22:00 +01:00
RePod f297323f42
LANraragi: Category fix + Summary (#4692)
* LRR: Drop last_used to fix categories

* LRR: Summary field

Maintain old behavior in case someone relied on it.
Tanks may encourage a standard in the future.
2024-09-15 20:22:00 +01:00
Vetle Ledaal 89a64d0b80
Manga1000: update theme (#4694) 2024-09-15 20:22:00 +01:00
TheKingTermux cfd6629d98
Add NgamenKomik (#4693)
* Add NgamenKomik

* Add some filter

* Add filter separator

* Remove NSFW

* Fix missing genres
2024-09-15 20:22:00 +01:00
Vetle Ledaal 67fcfb842f
Doujinku: update domain, add override URL setting (#4680) 2024-09-15 20:22:00 +01:00
Chopper 601f45baec
NoIndexScan: Fix manga details selector (#4686)
* Fix manga details selector

* Fix date format
2024-09-15 20:22:00 +01:00
KenjieDec 1302bf5e80
NHentai | Fixed "Pages" & "Uploaded" Filters (#4678)
Fixed "Pages" & "Uploaded" Filters

- Also removed "isOkayToSort" because I think it's useless... ( might be wrong? )
2024-09-15 20:22:00 +01:00
Chopper 042abd4e93
EmpireWebtoon: Update domain (#4669)
* Update domain

* Change baseurl pref implementation

* Remove BuildConfig.VERSION_CODE

* Add Suggested change

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

---------

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-09-15 20:22:00 +01:00
renovate[bot] c3fe4230fe
Update dependency gradle to v8.10 (#4674)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-15 20:22:00 +01:00
Chopper b0b1e0d5cd
Add KappaBeast (#4666)
* Add KappaBeast

* Fix Typo

* Add 'open' to parseGenre and filter properties

* Fix build
2024-09-15 20:22:00 +01:00
Vetle Ledaal f8de9ce1ea
RawINU: Handle DDoS protection (#4673) 2024-09-15 20:22:00 +01:00
Creepler13 cb17be204b
Readcomicsnet fix: add missing page index query in search (#4672)
* missing page index query in search

* version num

* Update src/en/readcomicnet/src/eu/kanade/tachiyomi/extension/en/readcomicnet/ReadcomicNet.kt

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>

---------

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>
2024-09-15 20:22:00 +01:00
Vetle Ledaal 7f456c6dc0
NHentai: fix sort by popular month/week/day for multi language (#4671) 2024-09-15 20:22:00 +01:00
Chopper 971007cde7
YuriMoonSub: Fix chapter url (#4670)
Fix url chapter
2024-09-15 20:22:00 +01:00
Chopper ac53bd65ff
YonaBar: Update domain (#4668)
Update domain
2024-09-15 20:22:00 +01:00
Chopper 41ef482be7
Add CultureSubs (#4664) 2024-09-15 20:22:00 +01:00
iloverabbit 4f58440542
Add ReaperTrans (#4661)
* Add ReaperTrans

* Use naked domain instead of www prefix

* Fix wrong date format from Thai to English

* Remove redundant default argument from constructor
2024-09-15 20:22:00 +01:00
KenjieDec 384146984b
SpyFakku | Update baseUrl (#4660)
Update baseUrl
2024-09-15 20:22:00 +01:00
子斗子 abf5f64873
[NHentai] fix several bugs about search (#4657)
* [NHentai] fix search

* 1. remove `+` before language since they have different semantics (add `+` before means this is not concern as a namespace, that time `+` will be encoded to `%2B`).
2. change fallback value of `fixedQuery` to empty string rather than a quote
3. change search url since there have a redirection.

* Update build.gradle

* Remove fixed query
2024-09-15 20:22:00 +01:00
bapeey dc6189f4c2
Re-add InariPikav (#4656)
Readd
2024-09-15 20:22:00 +01:00
AwkwardPeak7 0dc7a9817b
KDT Scans (#4648)
* new source: KDT Scans

* chnage lang of eromanhwa
2024-09-15 20:22:00 +01:00
AwkwardPeak7 0f09d40fde
add HastaTeam (#4647)
* new source: Hasta Team

* newline
2024-09-15 20:22:00 +01:00
AwkwardPeak7 e90f887d47
fix and remove some more sources (#4646)
* mangaweebs: update domain

* mangayaro: update domain

* furymanga: dead

* tecnospans: update domain

* truyenqq: update domain

* NvManga -> OneManhwa: update domain

* remove zinmanga.c

* rightdarkscan: update domain

* remove ancientcomics.com.br

* mangasehrinet: update domain

* remove inaripikav

* remove doujin69

* remove manga-moons

* new endpoint

* magusmanga: update domain
2024-09-15 20:22:00 +01:00
子斗子 9758bd897f
[NHentai] Fix search with exact tag (#4644)
* [NHentai] Fix language filter

* Update build.gradle

* Fix filter with exact search

* Fix code style

* Update build.gradle

* Update build.gradle
2024-09-15 20:22:00 +01:00
AwkwardPeak7 cb8cac580f
utoon: fix NPE on chapter list (#4643) 2024-09-15 20:22:00 +01:00
子斗子 231197b43c
[NHentai] Fix language filter (#4642)
* [NHentai] Fix language filter

* Update build.gradle
2024-09-15 20:22:00 +01:00
子斗子 779155707a
[Hitomi] Add Japanese Title for Manga Description (#4641) 2024-09-15 20:22:00 +01:00
bapeey 0321569d77
IkigaiMangas: Update domain and add override preference (#4640)
Update domain and add preference
2024-09-15 20:22:00 +01:00
Creepler13 08cb43435a
Add ReadComic.net (#4629)
* Added Extension for ReadComic.net

* Fix extVersion

* Requested Changes

* Requested Changes
2024-09-15 20:22:00 +01:00
AwkwardPeak7 99d1e125ff
more Domain changes (#4636)
* ruyamnaga: update domain

* umetruyen: update domain
2024-09-15 20:22:00 +01:00
AwkwardPeak7 c34db1d83e
remove more Dead sites (#4635)
* remove bakaman

* remove dessertscan

* remove housemanga/visormanga

* remove lectorunitoon.com

* remove mangaoku

* remove manhuako

* remove wiemanga
2024-09-15 20:22:00 +01:00
OncePunchedMan 4801226983
SamruaiScan: Change baseurl (#4633)
change baseurl
2024-09-15 20:22:00 +01:00
bapeey 94829063c1
LeerCapitulo: Fix script not found (#4627)
* hope is not a catandmouse game

* unused import

* no rebuild

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>

* cache url

* change to reorder

* lel i added the script to the last

---------

Co-authored-by: Vetle Ledaal <vetle.ledaal@gmail.com>
2024-09-15 20:22:00 +01:00
AwkwardPeak7 4fe3fbd9c3
update domains (#4625)
* dualeotryuen: domain change

* hentaivn.plus: domain change

* hiperdex: domain change

* bruh

* InmortalScan: domain change

* Lami-Manga: domain change

* Magus Manga: domain change

* mangabtt: domain change

* manhwaland: domain change

* pojok manga: domain change

* porncomix: domain change

* nartag: domain change

* jeazscans: update domain

* syosetu: update domain

* fix porncomix

* fix redirect(?)

* space

* Revert "manhwaland: domain change"

This reverts commit 74eac55207e03a87fb3fbd579da0e14201fccdf4.

* bruh
2024-09-15 20:22:00 +01:00
AwkwardPeak7 16e852a398
remove some websites (#4622)
* remove Hentai3z

redirects to hentai20

* remove ReadMangaToday

* remove Readmanhua

* remove mangakik

* remove mangapure

* remove mangashiro

* remove moonwithcinlove

* remove readkomik

* remove rio2manga
2024-09-15 20:22:00 +01:00
AwkwardPeak7 8e09de0654
yanpfansub: update domain (#4615) 2024-09-15 20:22:00 +01:00
KenjieDec 5d82449b0c
Colored Manga | Fix Latest, Pages Count, Fix Title Search (#4619)
* Fix Latest, Pages Count, Fix Title Search

- "Newest" is now a new Filter that sorts by manga first upload date
- Latest Updates fixed -> date parsed from latest manga chapter date, not manga upload date
2024-09-15 20:22:00 +01:00
子斗子 4060738822
[Akuma] fix language filter & add a preference for show short title (#4599)
* [Akuma] fix language filter

* dev

* fix typo

* fix order

* fix build bug

* fix build bug again

* fix build bug 3

* fix

* change default value

* fix property getter function

* fix manga detail title
2024-09-15 20:22:00 +01:00
AwkwardPeak7 b5df6c5788
MangaDistrict: fix date map (#4621) 2024-09-15 20:21:59 +01:00
AwkwardPeak7 7c8f692488
add Blacktoon (#4617)
* add BlackToon

* newline
2024-09-15 20:21:59 +01:00
AwkwardPeak7 9fd4ff010d
add EroManhwa (#4616) 2024-09-15 20:21:59 +01:00
KenjieDec 0735c39dad
Koharu | Fix Text Filters (#4614)
Fix Text Filters
2024-09-15 20:21:59 +01:00
AwkwardPeak7 81811577a6
add NabiScans (#4613) 2024-09-15 20:21:59 +01:00
AwkwardPeak7 9b17442c34
cizgiromanarsivi: remove dead source (#4612) 2024-09-15 20:21:59 +01:00
AwkwardPeak7 42037d400c
Atempral: use load more (#4611) 2024-09-15 20:21:59 +01:00
heagan01 4a1bdae3fa
Added source multimanga (#3631)
* Initial Commit

* Updated res

* Added isNsfw: true

* New line at end of file src/ru/multimanga/build.gradle

Add new line as requested

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

* extVersionCode change to 1 src/ru/multimanga/build.gradle

As requested

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

* Update MultiManga.kt

---------

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-09-15 20:21:59 +01:00
Chopper 5376efd5a7
Remove ShoujoHearts (#4591) 2024-09-15 20:21:59 +01:00
Chopper afe6556c25
Diskus - Fix - 510 Not Extend (#4586)
Fix - 510 Not Extend
2024-09-15 20:21:59 +01:00
Vetle Ledaal 84f3f8d2ff
Add Tempest Scans (#4584) 2024-09-15 20:21:59 +01:00
Vetle Ledaal 9938fb1750
Add Koreli Scans (#4583) 2024-09-15 20:21:59 +01:00
AwkwardPeak7 50e1900029
MangaSwat: fix order filter & preven 302 redirect (#4582) 2024-09-15 20:21:59 +01:00
子斗子 2bbdd0a351
[NHentai] Fix favorite count when login (#4581)
Fix favorite count when login
2024-09-15 20:21:59 +01:00
AwkwardPeak7 f7a92a1573
AdultWebtoons: fix chapter list & search (#4580) 2024-09-15 20:21:59 +01:00
iloverabbit a15350649f
Add PopsManga (#4578) 2024-09-15 20:21:59 +01:00
AwkwardPeak7 a7b59aecd4
AllAnime -> AllManga: update domain & small refactor (#4576)
* AllAnime -> AllManga: update domain & small refactor

* preserve id

* potential issue with img quality and cache?
2024-09-15 20:21:59 +01:00
Chopper 2f4249e842
BlackoutComics: Fix auth (#4571)
Fix auth
2024-09-15 20:21:59 +01:00
721 changed files with 5056 additions and 3475 deletions

View File

@ -1,12 +1,14 @@
# Editor configuration, see https://editorconfig.org # Editor configuration, see https://editorconfig.org
root = true root = true
[*]
insert_final_newline = true
end_of_line = lf
[*.kt] [*.kt]
charset = utf-8 charset = utf-8
end_of_line = lf
indent_size = 4 indent_size = 4
indent_style = space indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
ij_kotlin_allow_trailing_comma = true ij_kotlin_allow_trailing_comma = true
ij_kotlin_allow_trailing_comma_on_call_site = true ij_kotlin_allow_trailing_comma_on_call_site = true
@ -15,5 +17,3 @@ ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
[*.properties] [*.properties]
charset = utf-8 charset = utf-8
end_of_line = lf
insert_final_newline = true

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@ -9,6 +9,7 @@ assert !ext.has("libVersion")
assert extName.chars().max().asInt < 0x180 : "Extension name should be romanized" assert extName.chars().max().asInt < 0x180 : "Extension name should be romanized"
Project theme = ext.has("themePkg") ? project(":lib-multisrc:$themePkg") : null Project theme = ext.has("themePkg") ? project(":lib-multisrc:$themePkg") : null
if (theme != null) evaluationDependsOn(theme.path)
android { android {
compileSdk AndroidConfig.compileSdk compileSdk AndroidConfig.compileSdk

View File

@ -25,3 +25,5 @@ android.useAndroidX=true
android.enableBuildConfigAsBytecode=true android.enableBuildConfigAsBytecode=true
android.defaults.buildfeatures.resvalues=false android.defaults.buildfeatures.resvalues=false
android.defaults.buildfeatures.shaders=false android.defaults.buildfeatures.shaders=false
org.gradle.configureondemand=true

View File

@ -18,7 +18,7 @@ kotlin-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", ver
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines_version" } coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines_version" }
coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines_version" } coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines_version" }
injekt-core = { module = "com.github.inorichi.injekt:injekt-core", version = "65b0440" } injekt-core = { module = "com.github.null2264.injekt:injekt-core", version = "4135455a2a" }
rxjava = { module = "io.reactivex:rxjava", version = "1.3.8" } rxjava = { module = "io.reactivex:rxjava", version = "1.3.8" }
jsoup = { module = "org.jsoup:jsoup", version = "1.15.1" } jsoup = { module = "org.jsoup:jsoup", version = "1.15.1" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version = "5.0.0-alpha.11" } okhttp = { module = "com.squareup.okhttp3:okhttp", version = "5.0.0-alpha.11" }

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@ -2,7 +2,7 @@ plugins {
id("lib-multisrc") id("lib-multisrc")
} }
baseVersionCode = 3 baseVersionCode = 4
dependencies { dependencies {
api(project(":lib:synchrony")) api(project(":lib:synchrony"))

View File

@ -276,7 +276,7 @@ abstract class ColaManga(
}.also(screen::addPreference) }.also(screen::addPreference)
} }
private val keyMappingRegex = Regex("""[0-9A-Za-z_]+\s*==\s*['"](?<keyType>\d+)['"]\s*&&\s*\([0-9A-Za-z_]+\s*=\s*['"](?<key>[a-zA-Z0-9]+)['"]\)""") private val keyMappingRegex = Regex("""if\s*\(\s*([a-zA-Z0-9_]+)\s*==\s*(?<keyType>\d+)\s*\)\s*\{\s*return\s*'(?<key>[a-zA-Z0-9_]+)'\s*;""")
private val keyMapping by lazy { private val keyMapping by lazy {
val obfuscatedReadJs = client.newCall(GET("$baseUrl/js/manga.read.js")).execute().body.string() val obfuscatedReadJs = client.newCall(GET("$baseUrl/js/manga.read.js")).execute().body.string()

View File

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

View File

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

View File

@ -83,8 +83,8 @@ class Post<T>(val post: T)
@Serializable @Serializable
class ChapterListResponse( class ChapterListResponse(
val isNovel: Boolean, val isNovel: Boolean = false,
val slug: String, val slug: String? = null,
val chapters: List<Chapter>, val chapters: List<Chapter>,
) )
@ -96,11 +96,13 @@ class Chapter(
private val createdBy: Name, private val createdBy: Name,
private val createdAt: String, private val createdAt: String,
private val chapterStatus: String, private val chapterStatus: String,
private val mangaPost: ChapterPostDetails,
) { ) {
fun isPublic() = chapterStatus == "PUBLIC" fun isPublic() = chapterStatus == "PUBLIC"
fun toSChapter(mangaSlug: String) = SChapter.create().apply { fun toSChapter(mangaSlug: String?) = SChapter.create().apply {
url = "/series/$mangaSlug/$slug#$id" val seriesSlug = mangaSlug ?: mangaPost.slug
url = "/series/$seriesSlug/$slug#$id"
name = "Chapter $number" name = "Chapter $number"
scanlator = createdBy.name scanlator = createdBy.name
date_upload = try { date_upload = try {
@ -111,4 +113,9 @@ class Chapter(
} }
} }
@Serializable
class ChapterPostDetails(
val slug: String,
)
private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH) private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH)

View File

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

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.multisrc.keyoapp package eu.kanade.tachiyomi.multisrc.keyoapp
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
@ -31,9 +30,7 @@ abstract class Keyoapp(
) : ParsedHttpSource() { ) : ParsedHttpSource() {
override val supportsLatest = true override val supportsLatest = true
override val client = network.cloudflareClient.newBuilder() override val client = network.cloudflareClient
.rateLimit(2)
.build()
override fun headersBuilder() = super.headersBuilder() override fun headersBuilder() = super.headersBuilder()
.add("Referer", "$baseUrl/") .add("Referer", "$baseUrl/")
@ -197,7 +194,18 @@ abstract class Keyoapp(
status = document.selectFirst("div[alt=Status]").parseStatus() status = document.selectFirst("div[alt=Status]").parseStatus()
author = document.selectFirst("div[alt=Author]")?.text() author = document.selectFirst("div[alt=Author]")?.text()
artist = document.selectFirst("div[alt=Artist]")?.text() artist = document.selectFirst("div[alt=Artist]")?.text()
genre = document.select("div.grid:has(>h1) > div > a").joinToString { it.text() } genre = buildList {
document.selectFirst("div[alt='Series Type']")?.text()?.replaceFirstChar {
if (it.isLowerCase()) {
it.titlecase(
Locale.getDefault(),
)
} else {
it.toString()
}
}.let(::add)
document.select("div.grid:has(>h1) > div > a").forEach { add(it.text()) }
}.joinToString()
} }
private fun Element?.parseStatus(): Int = when (this?.text()?.lowercase()) { private fun Element?.parseStatus(): Int = when (this?.text()?.lowercase()) {
@ -223,15 +231,27 @@ abstract class Keyoapp(
// Image list // Image list
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
document.select("#pages > img")
.map { it.attr("uid") }
.filter { it.isNotEmpty() }
.mapIndexed { index, img ->
Page(index, document.location(), "$cdnUrl/uploads/$img")
}
.takeIf { it.isNotEmpty() }
?.also { return it }
// Fallback, old method
return document.select("#pages > img") return document.select("#pages > img")
.map { it.imgAttr() } .map { it.imgAttr() }
.filter { it.contains(imgCdnRegex) } .filter { it.contains(oldImgCdnRegex) }
.mapIndexed { index, img -> .mapIndexed { index, img ->
Page(index, document.location(), img) Page(index, document.location(), img)
} }
} }
private val imgCdnRegex = Regex("""^(https?:)?//cdn\d*\.keyoapp\.com""") protected val cdnUrl = "https://cdn.igniscans.com"
private val oldImgCdnRegex = Regex("""^(https?:)?//cdn\d*\.keyoapp\.com""")
override fun imageUrlParse(document: Document) = "" override fun imageUrlParse(document: Document) = ""
@ -247,7 +267,7 @@ abstract class Keyoapp(
return url return url
} }
private fun Element.getImageUrl(selector: String): String? { protected open fun Element.getImageUrl(selector: String): String? {
return this.selectFirst(selector)?.let { element -> return this.selectFirst(selector)?.let { element ->
element.attr("style") element.attr("style")
.substringAfter(":url(", "") .substringAfter(":url(", "")

View File

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

View File

@ -622,7 +622,7 @@ abstract class Madara(
"OnGoing", "Продолжается", "Updating", "Em Lançamento", "Em lançamento", "Em andamento", "OnGoing", "Продолжается", "Updating", "Em Lançamento", "Em lançamento", "Em andamento",
"Em Andamento", "En cours", "En Cours", "En cours de publication", "Ativo", "Lançando", "Đang Tiến Hành", "Devam Ediyor", "Em Andamento", "En cours", "En Cours", "En cours de publication", "Ativo", "Lançando", "Đang Tiến Hành", "Devam Ediyor",
"Devam ediyor", "In Corso", "In Arrivo", "مستمرة", "مستمر", "En Curso", "En curso", "Emision", "Devam ediyor", "In Corso", "In Arrivo", "مستمرة", "مستمر", "En Curso", "En curso", "Emision",
"Curso", "En marcha", "Publicandose", "En emision", "连载中", "Em Lançamento", "Devam Ediyo", "Curso", "En marcha", "Publicandose", "Publicándose", "En emision", "连载中", "Em Lançamento", "Devam Ediyo",
"Đang làm", "Em postagem", "Devam Eden", "Em progresso", "Em curso", "Đang làm", "Em postagem", "Devam Eden", "Em progresso", "Em curso",
) )

View File

@ -490,8 +490,8 @@ abstract class MangaThemesia(
Pair(intl["order_by_filter_popular"], "popular"), Pair(intl["order_by_filter_popular"], "popular"),
) )
protected val popularFilter by lazy { FilterList(OrderByFilter("", orderByFilterOptions, "popular")) } protected open val popularFilter by lazy { FilterList(OrderByFilter("", orderByFilterOptions, "popular")) }
protected val latestFilter by lazy { FilterList(OrderByFilter("", orderByFilterOptions, "update")) } protected open val latestFilter by lazy { FilterList(OrderByFilter("", orderByFilterOptions, "update")) }
protected class ProjectFilter( protected class ProjectFilter(
name: String, name: String,
@ -603,7 +603,7 @@ abstract class MangaThemesia(
(!strict && url.pathSegments.size == n + 1 && url.pathSegments[n].isEmpty()) (!strict && url.pathSegments.size == n + 1 && url.pathSegments[n].isEmpty())
} }
private fun parseGenres(document: Document): List<GenreData>? { protected open fun parseGenres(document: Document): List<GenreData>? {
return document.selectFirst("ul.genrez")?.select("li")?.map { li -> return document.selectFirst("ul.genrez")?.select("li")?.map { li ->
GenreData( GenreData(
li.selectFirst("label")!!.text(), li.selectFirst("label")!!.text(),

View File

@ -1,9 +0,0 @@
plugins {
id("lib-multisrc")
}
baseVersionCode = 1
dependencies {
api(project(":lib:dataimage"))
}

View File

@ -1,141 +0,0 @@
package eu.kanade.tachiyomi.multisrc.po2scans
import eu.kanade.tachiyomi.lib.dataimage.DataImageInterceptor
import eu.kanade.tachiyomi.lib.dataimage.dataImageAsUrl
import eu.kanade.tachiyomi.network.GET
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.ParsedHttpSource
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
abstract class PO2Scans(
override val name: String,
override val baseUrl: String,
override val lang: String,
private val dateFormat: SimpleDateFormat = SimpleDateFormat("dd MMMM, yy", Locale.ENGLISH),
) : ParsedHttpSource() {
override val supportsLatest = true
override val client = network.cloudflareClient.newBuilder()
.addInterceptor(DataImageInterceptor())
.build()
override fun headersBuilder() = super.headersBuilder()
.add("Referer", "$baseUrl/")
// popular
override fun popularMangaRequest(page: Int) = GET("$baseUrl/series", headers)
override fun popularMangaSelector() = "div.series-list"
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
setUrlWithoutDomain(element.selectFirst("div > a")!!.absUrl("href"))
title = element.selectFirst("div > h2")!!.text()
thumbnail_url = element.selectFirst("img")?.absUrl("data-src")
}
// TODO: add page selectors & url parameters when site have enough series for pagination
override fun popularMangaNextPageSelector() = null
// latest
override fun latestUpdatesRequest(page: Int) = GET(baseUrl, headers)
override fun latestUpdatesSelector() = "div.chap"
override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
element.selectFirst("div.chap-title a")!!.let {
setUrlWithoutDomain(it.absUrl("href"))
title = it.text()
}
thumbnail_url = element.selectFirst("img")?.absUrl("data-src")
}
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
// search
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
if (!query.startsWith(SLUG_SEARCH_PREFIX)) {
return super.fetchSearchManga(page, query, filters)
}
val url = "/series/${query.substringAfter(SLUG_SEARCH_PREFIX)}"
return fetchMangaDetails(SManga.create().apply { this.url = url })
.map {
it.url = url
MangasPage(listOf(it), false)
}
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
GET("$baseUrl/series?search=$query", headers)
override fun searchMangaSelector() = popularMangaSelector()
override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
// manga details
override fun mangaDetailsParse(document: Document): SManga {
return SManga.create().apply {
title = document.selectFirst(".title")!!.text()
author = document.select(".author > span:nth-child(2)").text()
artist = author
status = document.select(".status > span:nth-child(2)").text().parseStatus()
description = document.select(".summary p").text()
thumbnail_url = document.select("div.series-image img").attr("abs:src")
}
}
// chapter list
override fun chapterListSelector() = "div.chap"
override fun chapterFromElement(element: Element) = SChapter.create().apply {
element.selectFirst("a")!!.let {
setUrlWithoutDomain(it.absUrl("href"))
name = it.text()
}
date_upload = parseDate(element.select("div > div > span:nth-child(2)").text())
}
// page list
override fun pageListParse(document: Document) =
document.select(".swiper-slide img").mapIndexed { index, img ->
Page(index, imageUrl = img.imgAttr())
}
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException()
private val statusOngoing = listOf("ongoing", "devam ediyor")
private val statusCompleted = listOf("complete", "tamamlandı", "bitti")
private fun String.parseStatus(): Int {
return when (this.lowercase()) {
in statusOngoing -> SManga.ONGOING
in statusCompleted -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
}
private fun Element.imgAttr(): String = when {
hasAttr("data-pagespeed-high-res-src") -> dataImageAsUrl("data-pagespeed-high-res-src")
hasAttr("data-pagespeed-lazy-src") -> dataImageAsUrl("data-pagespeed-lazy-src")
else -> dataImageAsUrl("src")
}
private fun parseDate(dateStr: String) =
runCatching { dateFormat.parse(dateStr)!!.time }
.getOrDefault(0L)
companion object {
const val SLUG_SEARCH_PREFIX = "slug:"
}
}

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'Akuma' extName = 'Akuma'
extClass = '.AkumaFactory' extClass = '.AkumaFactory'
extVersionCode = 4 extVersionCode = 5
isNsfw = true isNsfw = true
} }

View File

@ -1,8 +1,13 @@
package eu.kanade.tachiyomi.extension.all.akuma package eu.kanade.tachiyomi.extension.all.akuma
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreferenceCompat
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.interceptor.rateLimit 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.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
@ -20,6 +25,8 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.IOException import java.io.IOException
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -29,7 +36,7 @@ import java.util.TimeZone
class Akuma( class Akuma(
override val lang: String, override val lang: String,
private val akumaLang: String, private val akumaLang: String,
) : ParsedHttpSource() { ) : ConfigurableSource, ParsedHttpSource() {
override val name = "Akuma" override val name = "Akuma"
@ -105,6 +112,23 @@ class Akuma(
return storedToken!! return storedToken!!
} }
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
private val displayFullTitle: Boolean get() = preferences.getBoolean(PREF_TITLE, false)
private val shortenTitleRegex = Regex("""(\[[^]]*]|[({][^)}]*[)}])""")
private fun String.shortenTitle() = this.replace(shortenTitleRegex, "").trim()
override fun setupPreferenceScreen(screen: PreferenceScreen) {
SwitchPreferenceCompat(screen.context).apply {
key = PREF_TITLE
title = "Display manga title as full title"
setDefaultValue(false)
}.also(screen::addPreference)
}
override fun popularMangaRequest(page: Int): Request { override fun popularMangaRequest(page: Int): Request {
val payload = FormBody.Builder() val payload = FormBody.Builder()
.add("view", "3") .add("view", "3")
@ -149,7 +173,9 @@ class Akuma(
override fun popularMangaFromElement(element: Element): SManga { override fun popularMangaFromElement(element: Element): SManga {
return SManga.create().apply { return SManga.create().apply {
setUrlWithoutDomain(element.select("a").attr("href")) setUrlWithoutDomain(element.select("a").attr("href"))
title = element.select(".overlay-title").text() title = element.select(".overlay-title").text().replace("\"", "").let {
if (displayFullTitle) it.trim() else it.shortenTitle()
}
thumbnail_url = element.select("img").attr("abs:src") thumbnail_url = element.select("img").attr("abs:src")
} }
} }
@ -176,7 +202,7 @@ class Akuma(
val finalQuery: MutableList<String> = mutableListOf(query) val finalQuery: MutableList<String> = mutableListOf(query)
if (lang != "all") { if (lang != "all") {
finalQuery.add("language: $akumaLang$") finalQuery.add("language:$akumaLang$")
} }
filters.forEach { filter -> filters.forEach { filter ->
when (filter) { when (filter) {
@ -220,7 +246,9 @@ class Akuma(
override fun mangaDetailsParse(document: Document) = with(document) { override fun mangaDetailsParse(document: Document) = with(document) {
SManga.create().apply { SManga.create().apply {
title = select(".entry-title").text() title = select(".entry-title").text().replace("\"", "").let {
if (displayFullTitle) it.trim() else it.shortenTitle()
}
thumbnail_url = select(".img-thumbnail").attr("abs:src") thumbnail_url = select(".img-thumbnail").attr("abs:src")
author = select(".group~.value").eachText().joinToString() author = select(".group~.value").eachText().joinToString()
@ -302,6 +330,7 @@ class Akuma(
companion object { companion object {
const val PREFIX_ID = "id:" const val PREFIX_ID = "id:"
private const val PREF_TITLE = "pref_title"
} }
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException() override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()

View File

@ -0,0 +1,7 @@
ext {
extName = 'ComicsKingdom'
extClass = '.ComicsKingdomFactory'
extVersionCode = 1
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -0,0 +1,44 @@
package eu.kanade.tachiyomi.extension.all.comicskingdom
import kotlinx.serialization.Serializable
@Serializable
class Chapter(
val id: Int,
val date: String,
val assets: Assets?,
val link: String,
)
@Serializable
class Assets(
val single: AssetData,
)
@Serializable
class AssetData(
val url: String,
)
@Serializable
class Manga(
val id: Int,
val link: String,
val title: Rendered,
val content: Rendered,
val meta: MangaMeta,
val yoast_head: String,
)
@Serializable
class MangaMeta(
val ck_byline_on_app: String,
)
@Serializable
class Rendered(
val rendered: String,
)
val ChapterFields = Chapter.javaClass.fields.joinToString(",") { it.name }
val MangaFields = Manga.javaClass.fields.joinToString(",") { it.name }

View File

@ -0,0 +1,311 @@
package eu.kanade.tachiyomi.extension.all.comicskingdom
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.Filter
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
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.Jsoup
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat
import java.util.Locale
import kotlin.math.ceil
import kotlin.math.roundToInt
class ComicsKingdom(override val lang: String) : ConfigurableSource, HttpSource() {
override val name = "Comics Kingdom"
override val baseUrl = "https://wp.comicskingdom.com"
override val supportsLatest = true
private val json: Json by injectLazy()
private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault())
private val compactChapterCountRegex = Regex("\"totalItems\":(\\d+)")
private val thumbnailUrlRegex = Regex("thumbnailUrl\":\"(\\S+)\",\"dateP")
private val mangaPerPage = 20
private val chapterPerPage = 100
private fun mangaApiUrl(): HttpUrl.Builder =
baseUrl.toHttpUrl().newBuilder().apply {
addPathSegments("wp-json/wp/v2")
addPathSegment("ck_feature")
addQueryParameter("per_page", mangaPerPage.toString())
addQueryParameter("_fields", MangaFields)
addQueryParameter("ck_language", if (lang == "es") "spanish" else "english")
}
private fun chapterApiUrl(): HttpUrl.Builder = baseUrl.toHttpUrl().newBuilder().apply {
addPathSegments("wp-json/wp/v2")
addPathSegment("ck_comic")
addQueryParameter("per_page", chapterPerPage.toString())
addQueryParameter("_fields", ChapterFields)
}
private fun getReq(orderBy: String, page: Int): Request = GET(
mangaApiUrl().apply {
addQueryParameter("orderBy", orderBy)
addQueryParameter("page", page.toString())
}.build(),
headers,
)
override fun popularMangaRequest(page: Int): Request = getReq("relevance", page)
override fun latestUpdatesRequest(page: Int): Request = getReq("modified", page)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request =
GET(
mangaApiUrl().apply {
addQueryParameter("search", query)
addQueryParameter("page", page.toString())
if (!filters.isEmpty()) {
for (filter in filters) {
when (filter) {
is OrderFilter -> {
addQueryParameter("orderby", filter.getValue())
}
is GenreList -> {
if (filter.included.isNotEmpty()) {
addQueryParameter(
"ck_genre",
filter.included.joinToString(","),
)
}
if (filter.excluded.isNotEmpty()) {
addQueryParameter(
"ck_genre_exclude",
filter.excluded.joinToString(","),
)
}
}
else -> {}
}
}
}
}.build(),
headers,
)
override fun searchMangaParse(response: Response): MangasPage {
val list = json.decodeFromString<List<Manga>>(response.body.string())
return MangasPage(
list.map {
SManga.create().apply {
thumbnail_url = thumbnailUrlRegex.find(it.yoast_head)?.groupValues?.get(1)
setUrlWithoutDomain(
mangaApiUrl().apply {
addPathSegment(it.id.toString())
addQueryParameter("slug", it.link.toHttpUrl().pathSegments.last())
}
.build().toString(),
)
title = it.title.rendered
}
},
list.count() == mangaPerPage,
)
}
override fun popularMangaParse(response: Response): MangasPage = searchMangaParse(response)
override fun latestUpdatesParse(response: Response): MangasPage = searchMangaParse(response)
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
val mangaData = json.decodeFromString<Manga>(response.body.string())
title = mangaData.title.rendered
author = mangaData.meta.ck_byline_on_app.substringAfter("By").trim()
description = Jsoup.parse(mangaData.content.rendered).text()
status = SManga.UNKNOWN
thumbnail_url = thumbnailUrlRegex.find(mangaData.yoast_head)?.groupValues?.get(1)
}
override fun getMangaUrl(manga: SManga): String =
"$baseUrl/${(baseUrl + manga.url).toHttpUrl().queryParameter("slug")}"
override fun chapterListParse(response: Response): List<SChapter> {
val mangaData = json.decodeFromString<Manga>(response.body.string())
val mangaName = mangaData.link.toHttpUrl().pathSegments.last()
if (shouldCompact()) {
val res = client.newCall(GET(mangaData.link)).execute()
val postCount = compactChapterCountRegex.findAll(res.body.string())
.find { result -> result.groupValues[1].toDouble() > 0 }!!.groupValues[1].toDouble()
res.close()
val maxPage = ceil(postCount / chapterPerPage)
return List(maxPage.roundToInt()) { idx ->
SChapter.create().apply {
chapter_number = idx * 0.01F
name =
"${idx * chapterPerPage + 1}-${if (postCount - (idx + 1) * chapterPerPage < 0) postCount.toInt() else (idx + 1) * chapterPerPage}"
setUrlWithoutDomain(
chapterApiUrl().apply {
addQueryParameter("orderBy", "date")
addQueryParameter("order", "asc")
addQueryParameter("ck_feature", mangaName)
addQueryParameter("page", (idx + 1).toString())
}.build().toString(),
)
}
}.reversed()
}
val chapters = mutableListOf<SChapter>()
var pageNum = 1
var chapterData = getChapterList(mangaName, pageNum)
var chapterNum = 0.0F
while (chapterData != null) {
val list = chapterData.map {
chapterNum += 0.01F
SChapter.create().apply {
chapter_number = chapterNum
setUrlWithoutDomain(
chapterApiUrl().apply {
addPathSegment(it.id.toString())
addQueryParameter("slug", it.link.substringAfter(baseUrl))
}
.toString(),
)
date_upload = dateFormat.parse(it.date).time
name = it.date.substringBefore("T")
}
}
chapters.addAll(list)
if (list.count() < 100) {
break
}
pageNum++
try {
chapterData = getChapterList(mangaName, pageNum)
} catch (exception: Exception) {
if (chapters.isNotEmpty()) {
return chapters
}
}
}
return chapters
}
private fun getChapterList(mangaName: String, page: Int): List<Chapter> {
val url = chapterApiUrl().apply {
addQueryParameter("order", "desc")
addQueryParameter("ck_feature", mangaName)
addQueryParameter("page", page.toString())
}.build()
val call = client.newCall(GET(url, headers)).execute()
val body = call.body.string()
call.close()
return json.decodeFromString<List<Chapter>>(body)
}
override fun getChapterUrl(chapter: SChapter): String {
if (shouldCompact()) {
return "$baseUrl/${(baseUrl + chapter.url).toHttpUrl().queryParameter("ck_feature")}"
}
return "$baseUrl/${(baseUrl + chapter.url).toHttpUrl().queryParameter("slug")}"
}
override fun pageListParse(response: Response): List<Page> {
if (shouldCompact()) {
return json.decodeFromString<List<Chapter>>(response.body.string())
.mapIndexed { idx, chapter ->
Page(idx, imageUrl = chapter.assets!!.single.url)
}
}
val chapter = json.decodeFromString<Chapter>(response.body.string())
return listOf(Page(0, imageUrl = chapter.assets!!.single.url))
}
private class OrderFilter :
Filter.Select<String>(
"Order by",
arrayOf(
"author",
"date",
"id",
"include",
"modified",
"parent",
"relevance",
"title",
"rand",
),
) {
fun getValue(): String = values[state]
}
private class Genre(name: String, val gid: String) : Filter.TriState(name)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) {
val included: List<String>
get() = state.filter { it.isIncluded() }.map { it.gid }
val excluded: List<String>
get() = state.filter { it.isExcluded() }.map { it.gid }
}
override fun getFilterList() = FilterList(
OrderFilter(),
GenreList(getGenreList()),
)
private fun getGenreList() = listOf(
Genre("Action", "action"),
Genre("Adventure", "adventure"),
Genre("Classic", "classic"),
Genre("Comedy", "comedy"),
Genre("Crime", "crime"),
Genre("Fantasy", "fantasy"),
Genre("Gag Cartoons", "gag-cartoons"),
Genre("Mystery", "mystery"),
Genre("New Arrivals", "new-arrivals"),
Genre("Non-Fiction", "non-fiction"),
Genre("OffBeat", "offbeat"),
Genre("Political Cartoons", "political-cartoons"),
Genre("Romance", "romance"),
Genre("Sci-Fi", "sci-fi"),
Genre("Slice Of Life", "slice-of-life"),
Genre("Superhero", "superhero"),
Genre("Vintage", "vintage"),
)
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val compactpref = androidx.preference.CheckBoxPreference(screen.context).apply {
key = "compactPref"
title = "Compact chapters"
summary =
"Unchecking this will make each daily/weekly upload into a chapter which can be very slow because some comics have 8000+ uploads"
isChecked = true
}
screen.addPreference(compactpref)
}
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
private fun shouldCompact() = preferences.getBoolean("compactPref", true)
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException()
}

View File

@ -0,0 +1,8 @@
package eu.kanade.tachiyomi.extension.all.comicskingdom
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory
class ComicsKingdomFactory : SourceFactory {
override fun createSources(): List<Source> = listOf(ComicsKingdom("en"), ComicsKingdom("es"))
}

View File

@ -3,7 +3,7 @@ ext {
extClass = '.ComicsValley' extClass = '.ComicsValley'
themePkg = 'madara' themePkg = 'madara'
baseUrl = 'https://comicsvalley.com' baseUrl = 'https://comicsvalley.com'
overrideVersionCode = 1 overrideVersionCode = 2
isNsfw = true isNsfw = true
} }

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,14 @@
package eu.kanade.tachiyomi.extension.all.comicsvalley
import eu.kanade.tachiyomi.multisrc.madara.Madara
class ComicsValley : Madara(
"Comics Valley",
"https://comicsvalley.com",
"all",
) {
override val mangaSubString = "comics-new"
override val useNewChapterEndpoint = true
override val useLoadMoreRequest = LoadMoreStrategy.Always
override val id = 1103204227230640533
}

View File

@ -1,8 +1,8 @@
ext { ext {
extName = 'Hentai Keyfi' extName = 'Eromanhwa'
extClass = '.HentaiKeyfi' extClass = '.Eromanhwa'
themePkg = 'madara' themePkg = 'madara'
baseUrl = 'https://hentaikeyfi.com' baseUrl = 'https://eromanhwa.org'
overrideVersionCode = 1 overrideVersionCode = 1
isNsfw = true isNsfw = true
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,12 @@
package eu.kanade.tachiyomi.extension.all.eromanhwa
import eu.kanade.tachiyomi.multisrc.madara.Madara
class Eromanhwa : Madara(
"Eromanhwa",
"https://eromanhwa.org",
"all",
) {
override val id = 3597355706480775153 // accidently set lang to en...
override val useNewChapterEndpoint = true
}

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'Hitomi' extName = 'Hitomi'
extClass = '.HitomiFactory' extClass = '.HitomiFactory'
extVersionCode = 32 extVersionCode = 33
isNsfw = true isNsfw = true
} }

View File

@ -517,6 +517,9 @@ class Hitomi(
"https://${subDomain}tn.$domain/webpbigtn/${thumbPathFromHash(hash)}/$hash.webp" "https://${subDomain}tn.$domain/webpbigtn/${thumbPathFromHash(hash)}/$hash.webp"
} }
description = buildString { description = buildString {
japaneseTitle?.let {
append("Japanese title: ", it, "\n")
}
parodys?.joinToString { it.formatted }?.let { parodys?.joinToString { it.formatted }?.let {
append("Series: ", it, "\n") append("Series: ", it, "\n")
} }

View File

@ -7,6 +7,7 @@ import kotlinx.serialization.json.JsonPrimitive
class Gallery( class Gallery(
val galleryurl: String, val galleryurl: String,
val title: String, val title: String,
val japaneseTitle: String?,
val date: String, val date: String,
val type: String?, val type: String?,
val language: String?, val language: String?,

View File

@ -1,8 +1,8 @@
ext { ext {
extName = 'Unitoon' extName = 'KDT Scans'
extClass = '.Unitoon' extClass = '.KdtScans'
themePkg = 'madara' themePkg = 'madara'
baseUrl = 'https://lectorunitoon.com' baseUrl = 'https://kdtscans.com'
overrideVersionCode = 0 overrideVersionCode = 0
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,41 @@
package eu.kanade.tachiyomi.extension.all.kdtscans
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.source.model.SManga
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class KdtScans : Madara(
"KDT Scans",
"https://kdtscans.com",
"all",
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("es")),
) {
override val useNewChapterEndpoint = true
override val fetchGenres = false
override fun popularMangaFromElement(element: Element): SManga {
return super.popularMangaFromElement(element).apply {
title = title.cleanupTitle()
}
}
override fun searchMangaFromElement(element: Element): SManga {
return super.searchMangaFromElement(element).apply {
title = title.cleanupTitle()
}
}
override fun mangaDetailsParse(document: Document): SManga {
return super.mangaDetailsParse(document).apply {
title = title.cleanupTitle()
}
}
private fun String.cleanupTitle() = replace(titleCleanupRegex, "").trim()
private val titleCleanupRegex =
Regex("""^\[(ESPAÑOL|English)\]\s+(\s+)?""", RegexOption.IGNORE_CASE)
}

View File

@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application> <application>
<activity <activity
android:name=".en.kiutaku.KiutakuUrlActivity" android:name=".all.kiutaku.KiutakuUrlActivity"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:exported="true" android:exported="true"
android:theme="@android:style/Theme.NoDisplay"> android:theme="@android:style/Theme.NoDisplay">

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.extension.en.kiutaku package eu.kanade.tachiyomi.extension.all.kiutaku
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.network.asObservableSuccess
@ -24,7 +24,9 @@ class Kiutaku : ParsedHttpSource() {
override val baseUrl = "https://kiutaku.com" override val baseUrl = "https://kiutaku.com"
override val lang = "en" override val lang = "all"
override val id = 3040035304874076216
override val supportsLatest = true override val supportsLatest = true

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.extension.en.kiutaku package eu.kanade.tachiyomi.extension.all.kiutaku
import android.app.Activity import android.app.Activity
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'LANraragi' extName = 'LANraragi'
extClass = '.LANraragiFactory' extClass = '.LANraragiFactory'
extVersionCode = 17 extVersionCode = 18
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -7,6 +7,7 @@ data class Archive(
val arcid: String, val arcid: String,
val isnew: String, val isnew: String,
val tags: String?, val tags: String?,
val summary: String?,
val title: String, val title: String,
) )
@ -25,7 +26,6 @@ data class ArchiveSearchResult(
@Serializable @Serializable
data class Category( data class Category(
val id: String, val id: String,
val last_used: String,
val name: String, val name: String,
val pinned: String, val pinned: String,
) )

View File

@ -242,7 +242,7 @@ open class LANraragi(private val suffix: String = "") : ConfigurableSource, Unme
private fun archiveToSManga(archive: Archive) = SManga.create().apply { private fun archiveToSManga(archive: Archive) = SManga.create().apply {
url = "/reader?id=${archive.arcid}" url = "/reader?id=${archive.arcid}"
title = archive.title title = archive.title
description = archive.title description = if (archive.summary.isNullOrBlank()) archive.title else archive.summary
thumbnail_url = getThumbnailUri(archive.arcid) thumbnail_url = getThumbnailUri(archive.arcid)
genre = archive.tags?.replace(",", ", ") genre = archive.tags?.replace(",", ", ")
artist = getArtist(archive.tags) artist = getArtist(archive.tags)
@ -406,12 +406,10 @@ open class LANraragi(private val suffix: String = "") : ConfigurableSource, Unme
private fun getCategoryPairs(categories: List<Category>): Array<Pair<String?, String>> { private fun getCategoryPairs(categories: List<Category>): Array<Pair<String?, String>> {
// Empty pair to disable. Sort by pinned status then name for convenience. // Empty pair to disable. Sort by pinned status then name for convenience.
// Web client sort is pinned > last_used but reflects between page changes.
val pin = "\uD83D\uDCCC " val pin = "\uD83D\uDCCC "
// Maintain categories sync for next FilterList reset. If there's demand for it, it's now // Maintain categories sync for next FilterList reset.
// possible to sort by last_used similar to the web client. Maybe an option toggle?
getCategories() getCategories()
return listOf(Pair("", "")) return listOf(Pair("", ""))

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'MangaDex' extName = 'MangaDex'
extClass = '.MangaDexFactory' extClass = '.MangaDexFactory'
extVersionCode = 193 extVersionCode = 194
isNsfw = true isNsfw = true
} }

View File

@ -138,13 +138,6 @@ object MDConstants {
return "${altTitlesInDescPref}_$dexLang" return "${altTitlesInDescPref}_$dexLang"
} }
private const val customUserAgentPref = "customUserAgent"
fun getCustomUserAgentPrefKey(dexLang: String): String {
return "${customUserAgentPref}_$dexLang"
}
val defaultUserAgent = "Tachiyomi " + System.getProperty("http.agent")
private const val tagGroupContent = "content" private const val tagGroupContent = "content"
private const val tagGroupFormat = "format" private const val tagGroupFormat = "format"
private const val tagGroupGenre = "genre" private const val tagGroupGenre = "genre"

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.all.mangadex
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build import android.os.Build
import android.widget.Toast
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.MultiSelectListPreference import androidx.preference.MultiSelectListPreference
@ -56,6 +55,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
private val preferences: SharedPreferences by lazy { private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
.sanitizeExistingUuidPrefs()
} }
private val helper = MangaDexHelper(lang) private val helper = MangaDexHelper(lang)
@ -67,6 +67,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
"Keiyoushi" "Keiyoushi"
val builder = super.headersBuilder().apply { val builder = super.headersBuilder().apply {
set("User-Agent", "Tachiyomi " + System.getProperty("http.agent"))
set("Referer", "$baseUrl/") set("Referer", "$baseUrl/")
set("Origin", baseUrl) set("Origin", baseUrl)
set("Extra", extraHeader) set("Extra", extraHeader)
@ -78,13 +79,8 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
override val client = network.client.newBuilder() override val client = network.client.newBuilder()
.rateLimit(3) .rateLimit(3)
.addInterceptor(MdAtHomeReportInterceptor(network.client, headers)) .addInterceptor(MdAtHomeReportInterceptor(network.client, headers))
.addInterceptor(MdUserAgentInterceptor(preferences, dexLang))
.build() .build()
init {
preferences.sanitizeExistingUuidPrefs()
}
// Popular manga section // Popular manga section
override fun popularMangaRequest(page: Int): Request { override fun popularMangaRequest(page: Int): Request {
@ -395,7 +391,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
// Manga Details section // Manga Details section
override fun getMangaUrl(manga: SManga): String { override fun getMangaUrl(manga: SManga): String {
return baseUrl + manga.url + "/" + helper.titleToSlug(manga.title) return baseUrl + manga.url.replace("/manga/", "/title/") + "/" + helper.titleToSlug(manga.title)
} }
/** /**
@ -761,30 +757,6 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
} }
} }
val userAgentPref = EditTextPreference(screen.context).apply {
key = MDConstants.getCustomUserAgentPrefKey(dexLang)
title = helper.intl["set_custom_useragent"]
summary = helper.intl["set_custom_useragent_summary"]
dialogMessage = helper.intl.format(
"set_custom_useragent_dialog",
MDConstants.defaultUserAgent,
)
setDefaultValue(MDConstants.defaultUserAgent)
setOnPreferenceChangeListener { _, newValue ->
try {
Headers.Builder().add("User-Agent", newValue as String)
summary = newValue
true
} catch (e: Throwable) {
val errorMessage = helper.intl.format("set_custom_useragent_error_invalid", e.message)
Toast.makeText(screen.context, errorMessage, Toast.LENGTH_LONG).show()
false
}
}
}
screen.addPreference(coverQualityPref) screen.addPreference(coverQualityPref)
screen.addPreference(tryUsingFirstVolumeCoverPref) screen.addPreference(tryUsingFirstVolumeCoverPref)
screen.addPreference(dataSaverPref) screen.addPreference(dataSaverPref)
@ -794,7 +766,6 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
screen.addPreference(originalLanguagePref) screen.addPreference(originalLanguagePref)
screen.addPreference(blockedGroupsPref) screen.addPreference(blockedGroupsPref)
screen.addPreference(blockedUploaderPref) screen.addPreference(blockedUploaderPref)
screen.addPreference(userAgentPref)
} }
override fun getFilterList(): FilterList = override fun getFilterList(): FilterList =
@ -869,20 +840,14 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
private val SharedPreferences.altTitlesInDesc private val SharedPreferences.altTitlesInDesc
get() = getBoolean(MDConstants.getAltTitlesInDescPrefKey(dexLang), false) get() = getBoolean(MDConstants.getAltTitlesInDescPrefKey(dexLang), false)
private val SharedPreferences.customUserAgent
get() = getString(
MDConstants.getCustomUserAgentPrefKey(dexLang),
MDConstants.defaultUserAgent,
)
/** /**
* Previous versions of the extension allowed invalid UUID values to be stored in the * Previous versions of the extension allowed invalid UUID values to be stored in the
* preferences. This method clear invalid UUIDs in case the user have updated from * preferences. This method clear invalid UUIDs in case the user have updated from
* a previous version with that behaviour. * a previous version with that behaviour.
*/ */
private fun SharedPreferences.sanitizeExistingUuidPrefs() { private fun SharedPreferences.sanitizeExistingUuidPrefs(): SharedPreferences {
if (getBoolean(MDConstants.getHasSanitizedUuidsPrefKey(dexLang), false)) { if (getBoolean(MDConstants.getHasSanitizedUuidsPrefKey(dexLang), false)) {
return return this
} }
val blockedGroups = getString(MDConstants.getBlockedGroupsPrefKey(dexLang), "")!! val blockedGroups = getString(MDConstants.getBlockedGroupsPrefKey(dexLang), "")!!
@ -902,5 +867,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
.putString(MDConstants.getBlockedUploaderPrefKey(dexLang), blockedUploaders) .putString(MDConstants.getBlockedUploaderPrefKey(dexLang), blockedUploaders)
.putBoolean(MDConstants.getHasSanitizedUuidsPrefKey(dexLang), true) .putBoolean(MDConstants.getHasSanitizedUuidsPrefKey(dexLang), true)
.apply() .apply()
return this
} }
} }

View File

@ -1,39 +0,0 @@
package eu.kanade.tachiyomi.extension.all.mangadex
import android.content.SharedPreferences
import okhttp3.Interceptor
import okhttp3.Response
/**
* Interceptor to set custom useragent for MangaDex
*/
class MdUserAgentInterceptor(
private val preferences: SharedPreferences,
private val dexLang: String,
) : Interceptor {
private val SharedPreferences.customUserAgent
get() = getString(
MDConstants.getCustomUserAgentPrefKey(dexLang),
MDConstants.defaultUserAgent,
)
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val newUserAgent = preferences.customUserAgent
?: return chain.proceed(originalRequest)
val originalHeaders = originalRequest.headers
val modifiedHeaders = originalHeaders.newBuilder()
.set("User-Agent", newUserAgent)
.build()
val modifiedRequest = originalRequest.newBuilder()
.headers(modifiedHeaders)
.build()
return chain.proceed(modifiedRequest)
}
}

View File

@ -17,6 +17,8 @@ schedule_monthly=Monthly
schedule_other=Other schedule_other=Other
schedule_trimonthly=Trimonthly schedule_trimonthly=Trimonthly
schedule_weekly=Weekly schedule_weekly=Weekly
subtitle_only=Show subtitle only
subtitle_only_summary=Removes the redundant chapter number from the chapter name.
serialization=Serialization: %s serialization=Serialization: %s
split_double_pages=Split double pages split_double_pages=Split double pages
split_double_pages_summary=Only a few titles supports disabling this setting. split_double_pages_summary=Only a few titles supports disabling this setting.

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'MANGA Plus by SHUEISHA' extName = 'MANGA Plus by SHUEISHA'
extClass = '.MangaPlusFactory' extClass = '.MangaPlusFactory'
extVersionCode = 52 extVersionCode = 53
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -289,9 +289,10 @@ class MangaPlus(
} }
val titleDetailView = result.success.titleDetailView!! val titleDetailView = result.success.titleDetailView!!
val subtitleOnly = preferences.subtitleOnly()
return titleDetailView.chapterList return titleDetailView.chapterList
.map(Chapter::toSChapter) .map { it.toSChapter(subtitleOnly) }
.reversed() .reversed()
} }
@ -307,8 +308,8 @@ class MangaPlus(
private fun pageListRequest(chapterId: String): Request { private fun pageListRequest(chapterId: String): Request {
val url = "$APP_API_URL/manga_viewer".toHttpUrl().newBuilder() val url = "$APP_API_URL/manga_viewer".toHttpUrl().newBuilder()
.addQueryParameter("chapter_id", chapterId) .addQueryParameter("chapter_id", chapterId)
.addQueryParameter("split", if (preferences.splitImages) "yes" else "no") .addQueryParameter("split", if (preferences.splitImages()) "yes" else "no")
.addQueryParameter("img_quality", preferences.imageQuality) .addQueryParameter("img_quality", preferences.imageQuality())
.addQueryParameter("ticket_reading", "no") .addQueryParameter("ticket_reading", "no")
.addQueryParameter("free_reading", "yes") .addQueryParameter("free_reading", "yes")
.addQueryParameter("subscription_reading", "no") .addQueryParameter("subscription_reading", "no")
@ -378,8 +379,16 @@ class MangaPlus(
key = "${VER_PREF_KEY}_$lang", key = "${VER_PREF_KEY}_$lang",
) )
val titlePref = SwitchPreferenceCompat(screen.context).apply {
key = "${SUBTITLE_ONLY_KEY}_$lang"
title = intl["subtitle_only"]
summary = intl["subtitle_only_summary"]
setDefaultValue(SUBTITLE_ONLY_DEFAULT_VALUE)
}
screen.addPreference(qualityPref) screen.addPreference(qualityPref)
screen.addPreference(splitPref) screen.addPreference(splitPref)
screen.addPreference(titlePref)
} }
private fun PreferenceScreen.addEditTextPreference( private fun PreferenceScreen.addEditTextPreference(
@ -494,11 +503,11 @@ class MangaPlus(
json.decodeFromString(body.string()) json.decodeFromString(body.string())
} }
private val SharedPreferences.imageQuality: String private fun SharedPreferences.imageQuality(): String = getString("${QUALITY_PREF_KEY}_$lang", QUALITY_PREF_DEFAULT_VALUE)!!
get() = getString("${QUALITY_PREF_KEY}_$lang", QUALITY_PREF_DEFAULT_VALUE)!!
private val SharedPreferences.splitImages: Boolean private fun SharedPreferences.splitImages(): Boolean = getBoolean("${SPLIT_PREF_KEY}_$lang", SPLIT_PREF_DEFAULT_VALUE)
get() = getBoolean("${SPLIT_PREF_KEY}_$lang", SPLIT_PREF_DEFAULT_VALUE)
private fun SharedPreferences.subtitleOnly(): Boolean = getBoolean("${SUBTITLE_ONLY_KEY}_$lang", SUBTITLE_ONLY_DEFAULT_VALUE)
private val SharedPreferences.appVersion: String? private val SharedPreferences.appVersion: String?
get() = getString("${VER_PREF_KEY}_$lang", VER_PREF_DEFAULT_VALUE) get() = getString("${VER_PREF_KEY}_$lang", VER_PREF_DEFAULT_VALUE)
@ -526,6 +535,9 @@ private val QUALITY_PREF_DEFAULT_VALUE = QUALITY_PREF_ENTRY_VALUES[2]
private const val SPLIT_PREF_KEY = "splitImage" private const val SPLIT_PREF_KEY = "splitImage"
private const val SPLIT_PREF_DEFAULT_VALUE = true private const val SPLIT_PREF_DEFAULT_VALUE = true
private const val SUBTITLE_ONLY_KEY = "subtitleOnly"
private const val SUBTITLE_ONLY_DEFAULT_VALUE = false
private const val VER_PREF_KEY = "appVer" private const val VER_PREF_KEY = "appVer"
private const val VER_PREF_DEFAULT_VALUE = "" private const val VER_PREF_DEFAULT_VALUE = ""
private const val SECRET_PREF_KEY = "accountSecret" private const val SECRET_PREF_KEY = "accountSecret"

View File

@ -322,11 +322,16 @@ class Chapter(
val isExpired: Boolean val isExpired: Boolean
get() = subTitle == null get() = subTitle == null
fun toSChapter(): SChapter = SChapter.create().apply { fun toSChapter(subtitlePref: Boolean): SChapter = SChapter.create().apply {
name = "${this@Chapter.name} - $subTitle" name = if (subtitlePref && subTitle != null) {
subTitle
} else {
"${this@Chapter.name} - $subTitle"
}
date_upload = 1000L * startTimeStamp date_upload = 1000L * startTimeStamp
url = "#/viewer/$chapterId" url = "#/viewer/$chapterId"
chapter_number = this@Chapter.name.substringAfter("#").toFloatOrNull() ?: -1f chapter_number = this@Chapter.name.substringAfter("#").toFloatOrNull() ?: -1f
scanlator = "MANGA Plus"
} }
} }

View File

@ -1,8 +0,0 @@
ext {
extName = 'Meitua.top'
extClass = '.MeituaTop'
extVersionCode = 6
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -1,111 +0,0 @@
package eu.kanade.tachiyomi.extension.all.meituatop
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.Filter
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 eu.kanade.tachiyomi.util.asJsoup
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.select.Evaluator
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
// Uses MACCMS http://www.maccms.la/
class MeituaTop : HttpSource() {
override val name = "Meitua.top"
override val lang = "all"
override val supportsLatest = false
override val baseUrl = "https://mt1.meitu1.sbs"
override fun popularMangaRequest(page: Int) = GET("$baseUrl/arttype/0b-$page.html", headers)
override fun popularMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = document.selectFirst(Evaluator.Class("thumbnail-group"))!!.children().map {
SManga.create().apply {
url = it.selectFirst(Evaluator.Tag("a"))!!.attr("href")
val image = it.selectFirst(Evaluator.Tag("img"))!!
title = image.attr("alt")
thumbnail_url = image.attr("src")
val info = it.selectFirst(Evaluator.Tag("p"))!!.ownText().split(" - ")
genre = info[0]
description = info[1]
status = SManga.COMPLETED
initialized = true
}
}
val pageLinks = document.select(Evaluator.Class("page_link"))
if (pageLinks.isEmpty()) return MangasPage(mangas, false)
val lastPage = pageLinks[3].attr("href")
val hasNextPage = document.location().pageNumber() != lastPage.pageNumber()
return MangasPage(mangas, hasNextPage)
}
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()
override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
if (query.isNotEmpty()) {
val url = "$baseUrl/artsearch/-------.html".toHttpUrl().newBuilder()
.addQueryParameter("wd", query)
.addQueryParameter("page", page.toString())
.toString()
return GET(url, headers)
}
val filter = filters.filterIsInstance<RegionFilter>().firstOrNull() ?: return popularMangaRequest(page)
return GET("$baseUrl/arttype/${21 + filter.state}b-$page.html", headers)
}
override fun searchMangaParse(response: Response) = popularMangaParse(response)
override fun fetchMangaDetails(manga: SManga): Observable<SManga> = Observable.just(manga)
override fun mangaDetailsParse(response: Response) = throw UnsupportedOperationException()
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
val chapter = SChapter.create().apply {
url = manga.url
name = "Gallery"
date_upload = dateFormat.parse(manga.description!!)!!.time
chapter_number = -2f
}
return Observable.just(listOf(chapter))
}
override fun chapterListParse(response: Response) = throw UnsupportedOperationException()
override fun pageListParse(response: Response): List<Page> {
val document = response.asJsoup()
val images = document.selectFirst(Evaluator.Class("ttnr"))!!.select(Evaluator.Tag("img"))
.map { it.attr("src") }.distinct()
return images.mapIndexed { index, imageUrl -> Page(index, imageUrl = imageUrl) }
}
override fun imageUrlParse(response: Response) = throw UnsupportedOperationException()
override fun getFilterList() = FilterList(
Filter.Header("Category (ignored for text search)"),
RegionFilter(),
)
private class RegionFilter : Filter.Select<String>(
"Region",
arrayOf("All", "国产美女", "韩国美女", "台湾美女", "日本美女", "欧美美女", "泰国美女"),
)
private fun String.pageNumber() = numberRegex.findAll(this).last().value.toInt()
private val numberRegex by lazy { Regex("""\d+""") }
private val dateFormat by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) }
}

View File

@ -0,0 +1,8 @@
ext {
extName = 'Mitaku'
extClass = '.Mitaku'
extVersionCode = 1
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -0,0 +1,171 @@
package eu.kanade.tachiyomi.extension.all.mitaku
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.Filter
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.model.UpdateStrategy
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
class Mitaku : ParsedHttpSource() {
override val name = "Mitaku"
override val baseUrl = "https://mitaku.net"
override val lang = "all"
override val supportsLatest = false
// ============================== Popular ===============================
override fun popularMangaRequest(page: Int) = GET("$baseUrl/category/ero-cosplay/page/$page", headers)
override fun popularMangaSelector() = "div.article-container article"
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href"))
title = element.selectFirst("a")!!.attr("title")
thumbnail_url = element.selectFirst("img")?.absUrl("src")
}
override fun popularMangaNextPageSelector() = "div.wp-pagenavi a.page.larger"
// =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int): Request {
throw UnsupportedOperationException()
}
override fun latestUpdatesSelector(): String {
throw UnsupportedOperationException()
}
override fun latestUpdatesFromElement(element: Element): SManga {
throw UnsupportedOperationException()
}
override fun latestUpdatesNextPageSelector(): String? {
throw UnsupportedOperationException()
}
// =============================== Search ===============================
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val filterList = if (filters.isEmpty()) getFilterList() else filters
val tagFilter = filterList.findInstance<TagFilter>()!!
val categoryFilter = filterList.findInstance<CategoryFilter>()!!
return when {
query.isEmpty() && categoryFilter.state != 0 -> {
val url = "$baseUrl/category/${categoryFilter.toUriPart()}/page/$page/"
GET(url, headers)
}
query.isEmpty() && tagFilter.state.isNotEmpty() -> {
val url = baseUrl.toHttpUrl().newBuilder()
.addPathSegment("tag")
.addPathSegment(tagFilter.toUriPart())
.addPathSegment("page")
.addPathSegment(page.toString())
.build()
GET(url, headers)
}
query.isNotEmpty() -> {
val url = "$baseUrl/page/$page/".toHttpUrl().newBuilder()
.addQueryParameter("s", query)
.build()
GET(url, headers)
}
else -> latestUpdatesRequest(page)
}
}
override fun searchMangaSelector() = popularMangaSelector()
override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
status = SManga.COMPLETED
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE
with(document.selectFirst("article")!!) {
title = selectFirst("h1")!!.text()
val catGenres = select("span.cat-links a").joinToString { it.text() }
val tagGenres = select("span.tag-links a").joinToString { it.text() }
genre = listOf(catGenres, tagGenres).filter { it.isNotEmpty() }.joinToString()
}
}
// ============================== Chapters ==============================
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
val chapter = SChapter.create().apply {
url = manga.url
chapter_number = 1F
name = "Chapter"
}
return Observable.just(listOf(chapter))
}
override fun chapterListSelector(): String {
throw UnsupportedOperationException()
}
override fun chapterFromElement(element: Element): SChapter {
throw UnsupportedOperationException()
}
// =============================== Pages ================================
override fun pageListParse(document: Document): List<Page> {
val imageElements = document.select("a.msacwl-img-link")
return imageElements.mapIndexed { index, element ->
val imageUrl = element.absUrl("data-mfp-src")
Page(index, imageUrl = imageUrl)
}
}
override fun imageUrlParse(document: Document): String {
throw UnsupportedOperationException()
}
open class UriPartFilter(
displayName: String,
private val valuePair: Array<Pair<String, String>>,
) : Filter.Select<String>(displayName, valuePair.map { it.first }.toTypedArray()) {
fun toUriPart() = valuePair[state].second
}
class CategoryFilter : UriPartFilter(
"Category",
arrayOf(
Pair("Any", ""),
Pair("Ero Cosplay", "/ero-cosplay"),
Pair("Nude", "/nude"),
Pair("Sexy Set", "/sexy-set"),
Pair("Online Video", "/online-video"),
),
)
override fun getFilterList(): FilterList = FilterList(
Filter.Header("NOTE: Only one tag search"),
Filter.Separator(),
CategoryFilter(),
TagFilter(),
)
class TagFilter : Filter.Text("Tag") {
fun toUriPart(): String {
return state.trim().lowercase().replace(" ", "-")
}
}
private inline fun <reified T> Iterable<*>.findInstance() = find { it is T } as? T
}

View File

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

View File

@ -136,57 +136,51 @@ open class NHentai(
} }
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val fixedQuery = query.ifEmpty { "\"\"" }
val filterList = if (filters.isEmpty()) getFilterList() else filters val filterList = if (filters.isEmpty()) getFilterList() else filters
val nhLangSearch = if (nhLang.isBlank()) "" else "+$nhLang " val nhLangSearch = if (nhLang.isBlank()) "" else "language:$nhLang "
val advQuery = combineQuery(filterList) val advQuery = combineQuery(filterList)
val favoriteFilter = filterList.findInstance<FavoriteFilter>() val favoriteFilter = filterList.findInstance<FavoriteFilter>()
val isOkayToSort = filterList.findInstance<UploadedFilter>()?.state?.isBlank() ?: true
val offsetPage = val offsetPage =
filterList.findInstance<OffsetPageFilter>()?.state?.toIntOrNull()?.plus(page) ?: page filterList.findInstance<OffsetPageFilter>()?.state?.toIntOrNull()?.plus(page) ?: page
if (favoriteFilter?.state == true) { if (favoriteFilter?.state == true) {
val url = "$baseUrl/favorites".toHttpUrl().newBuilder() val url = "$baseUrl/favorites/".toHttpUrl().newBuilder()
.addQueryParameter("q", "$fixedQuery $advQuery") .addQueryParameter("q", "$query $advQuery")
.addQueryParameter("page", offsetPage.toString()) .addQueryParameter("page", offsetPage.toString())
return GET(url.build(), headers) return GET(url.build(), headers)
} else { } else {
val url = "$baseUrl/search".toHttpUrl().newBuilder() val url = "$baseUrl/search/".toHttpUrl().newBuilder()
.addQueryParameter("q", "$fixedQuery $nhLangSearch$advQuery") // Blank query (Multi + sort by popular month/week/day) shows a 404 page
// Searching for `""` is a hacky way to return everything without any filtering
.addQueryParameter("q", "$query $nhLangSearch$advQuery".ifBlank { "\"\"" })
.addQueryParameter("page", offsetPage.toString()) .addQueryParameter("page", offsetPage.toString())
if (isOkayToSort) {
filterList.findInstance<SortFilter>()?.let { f -> filterList.findInstance<SortFilter>()?.let { f ->
url.addQueryParameter("sort", f.toUriPart()) url.addQueryParameter("sort", f.toUriPart())
} }
}
return GET(url.build(), headers) return GET(url.build(), headers)
} }
} }
private fun combineQuery(filters: FilterList): String { private fun combineQuery(filters: FilterList): String = buildString {
val stringBuilder = StringBuilder() filters.filterIsInstance<AdvSearchEntryFilter>().forEach { filter ->
val advSearch = filters.filterIsInstance<AdvSearchEntryFilter>().flatMap { filter -> filter.state.split(",")
val splitState = filter.state.split(",").map(String::trim).filterNot(String::isBlank) .map(String::trim)
splitState.map { .filterNot(String::isBlank)
AdvSearchEntry(filter.name, it.removePrefix("-"), it.startsWith("-")) .forEach { tag ->
val y = !(filter.name == "Pages" || filter.name == "Uploaded")
if (tag.startsWith("-")) append("-")
append(filter.name, ':')
if (y) append('"')
append(tag.removePrefix("-"))
if (y) append('"')
append(" ")
} }
} }
advSearch.forEach { entry ->
if (entry.exclude) stringBuilder.append("-")
stringBuilder.append("${entry.name}:")
stringBuilder.append(entry.text)
stringBuilder.append(" ")
} }
return stringBuilder.toString()
}
data class AdvSearchEntry(val name: String, val text: String, val exclude: Boolean)
private fun searchMangaByIdRequest(id: String) = GET("$baseUrl/g/$id", headers) private fun searchMangaByIdRequest(id: String) = GET("$baseUrl/g/$id", headers)
private fun searchMangaByIdParse(response: Response, id: String): MangasPage { private fun searchMangaByIdParse(response: Response, id: String): MangasPage {
@ -226,7 +220,7 @@ open class NHentai(
.plus("$fullTitle\n") .plus("$fullTitle\n")
.plus("${document.select("div#info h2").text()}\n\n") .plus("${document.select("div#info h2").text()}\n\n")
.plus("Pages: ${getNumPages(document)}\n") .plus("Pages: ${getNumPages(document)}\n")
.plus("Favorited by: ${document.select("div#info i.fa-heart + span span").text().removeSurrounding("(", ")")}\n") .plus("Favorited by: ${document.select("div#info i.fa-heart ~ span span").text().removeSurrounding("(", ")")}\n")
.plus(getTagDescription(document)) .plus(getTagDescription(document))
genre = getTags(document) genre = getTags(document)
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE update_strategy = UpdateStrategy.ONLY_FETCH_ONCE

View File

@ -3,7 +3,7 @@ ext {
extClass = '.ThunderScansFactory' extClass = '.ThunderScansFactory'
themePkg = 'mangathemesia' themePkg = 'mangathemesia'
baseUrl = 'https://en-thunderscans.com' baseUrl = 'https://en-thunderscans.com'
overrideVersionCode = 4 overrideVersionCode = 5
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

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

View File

@ -2,8 +2,8 @@ ext {
extName = 'Empire Webtoon' extName = 'Empire Webtoon'
extClass = '.EmpireWebtoon' extClass = '.EmpireWebtoon'
themePkg = 'madara' themePkg = 'madara'
baseUrl = 'https://webtoonsempireron.com' baseUrl = 'https://webtoonempire-ron.com'
overrideVersionCode = 3 overrideVersionCode = 4
isNsfw = true isNsfw = true
} }

View File

@ -4,7 +4,6 @@ import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.widget.Toast import android.widget.Toast
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.extension.BuildConfig
import eu.kanade.tachiyomi.multisrc.madara.Madara import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.ConfigurableSource
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -15,46 +14,56 @@ import java.util.Locale
class EmpireWebtoon : class EmpireWebtoon :
Madara( Madara(
"Empire Webtoon", "Empire Webtoon",
"https://webtoonsempireron.com", "https://webtoonempire-ron.com",
"ar", "ar",
SimpleDateFormat("d MMMM، yyyy", Locale("ar")), SimpleDateFormat("d MMMM، yyyy", Locale("ar")),
), ),
ConfigurableSource { ConfigurableSource {
private val defaultBaseUrl = "https://webtoonsempireron.com" private val preferences: SharedPreferences =
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
init {
preferences.getString(DEFAULT_BASE_URL_PREF, null).let { prefDefaultBaseUrl ->
if (prefDefaultBaseUrl != super.baseUrl) {
preferences.edit()
.putString(BASE_URL_PREF, super.baseUrl)
.putString(DEFAULT_BASE_URL_PREF, super.baseUrl)
.apply()
}
}
}
override val baseUrl by lazy { getPrefBaseUrl() } override val baseUrl by lazy { getPrefBaseUrl() }
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override val mangaSubString = "webtoon" override val mangaSubString = "webtoon"
override val useNewChapterEndpoint = false override val useNewChapterEndpoint = false
companion object {
private const val RESTART_TACHIYOMI = "Restart Tachiyomi to apply new setting."
private const val BASE_URL_PREF_TITLE = "Override BaseUrl"
private const val BASE_URL_PREF = "overrideBaseUrl_v${BuildConfig.VERSION_CODE}"
private const val BASE_URL_PREF_SUMMARY = "For temporary uses. Updating the extension will erase this setting."
}
override fun setupPreferenceScreen(screen: PreferenceScreen) { override fun setupPreferenceScreen(screen: PreferenceScreen) {
val baseUrlPref = androidx.preference.EditTextPreference(screen.context).apply { val baseUrlPref = androidx.preference.EditTextPreference(screen.context).apply {
key = BASE_URL_PREF key = BASE_URL_PREF
title = BASE_URL_PREF_TITLE title = BASE_URL_PREF_TITLE
summary = BASE_URL_PREF_SUMMARY summary = BASE_URL_PREF_SUMMARY
this.setDefaultValue(defaultBaseUrl) setDefaultValue(super.baseUrl)
dialogTitle = BASE_URL_PREF_TITLE dialogTitle = BASE_URL_PREF_TITLE
dialogMessage = "Default: ${super.baseUrl}"
setOnPreferenceChangeListener { _, _ -> setOnPreferenceChangeListener { _, _ ->
Toast.makeText(screen.context, RESTART_TACHIYOMI, Toast.LENGTH_LONG).show() Toast.makeText(screen.context, RESTART_APP, Toast.LENGTH_LONG).show()
true true
} }
} }
screen.addPreference(baseUrlPref) screen.addPreference(baseUrlPref)
} }
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!! private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, super.baseUrl)!!
companion object {
private const val DEFAULT_BASE_URL_PREF = "defaultBaseUrl"
private const val RESTART_APP = "Restart app to apply new setting."
private const val BASE_URL_PREF_TITLE = "Override BaseUrl"
private const val BASE_URL_PREF = "overrideBaseUrl"
private const val BASE_URL_PREF_SUMMARY = "For temporary uses. Updating the extension will erase this setting."
}
} }

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.extension.ar.mangaswat package eu.kanade.tachiyomi.extension.ar.mangaswat
import android.app.Application import android.app.Application
import android.content.SharedPreferences
import android.widget.Toast import android.widget.Toast
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
@ -12,7 +11,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
@ -24,7 +22,7 @@ import java.util.Locale
class MangaSwat : class MangaSwat :
MangaThemesia( MangaThemesia(
"MangaSwat", "MangaSwat",
"https://tatwt.com", "https://healteer.com",
"ar", "ar",
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")), dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
), ),
@ -32,29 +30,53 @@ class MangaSwat :
override val baseUrl by lazy { getPrefBaseUrl() } override val baseUrl by lazy { getPrefBaseUrl() }
private val preferences: SharedPreferences by lazy { private val preferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
} }
override val client: OkHttpClient = super.client.newBuilder() override val client = super.client.newBuilder()
.rateLimit(1) .rateLimit(1)
.build() .build()
override fun latestUpdatesRequest(page: Int): Request {
val filter = FilterList(OrderByFilter("", orderByFilterOptions, "added"))
return searchMangaRequest(page, "", filter)
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val request = super.searchMangaRequest(page, query, filters) val request = super.searchMangaRequest(page, query, filters)
if (query.isBlank()) return request val urlBuilder = request.url.newBuilder()
val url = request.url.newBuilder() // remove trailing slash
if (request.url.pathSegments.last().isBlank()) {
urlBuilder.removePathSegment(
request.url.pathSegments.lastIndex,
)
}
if (query.isNotBlank()) {
urlBuilder
.removePathSegment(0) .removePathSegment(0)
.removeAllQueryParameters("title") .removeAllQueryParameters("title")
.addQueryParameter("s", query) .addQueryParameter("s", query)
.build() .build()
}
return request.newBuilder() return request.newBuilder()
.url(url) .url(urlBuilder.build())
.build() .build()
} }
override val orderByFilterOptions = arrayOf(
Pair(intl["order_by_filter_default"], ""),
Pair(intl["order_by_filter_az"], "a-z"),
Pair(intl["order_by_filter_za"], "z-a"),
Pair(intl["order_by_filter_latest_update"], "update"),
Pair(intl["order_by_filter_latest_added"], "added"),
Pair(intl["order_by_filter_popular"], "popular"),
)
override fun searchMangaNextPageSelector() = "a[rel=next]" override fun searchMangaNextPageSelector() = "a[rel=next]"
override val seriesTitleSelector = "h1[itemprop=headline]" override val seriesTitleSelector = "h1[itemprop=headline]"
@ -82,13 +104,12 @@ class MangaSwat :
} }
@Serializable @Serializable
data class TSReader( class TSReader(
val sources: List<ReaderImageSource>, val sources: List<ReaderImageSource>,
) )
@Serializable @Serializable
data class ReaderImageSource( class ReaderImageSource(
val source: String,
val images: List<String>, val images: List<String>,
) )

View File

@ -3,7 +3,7 @@ ext {
extClass = '.RocksManga' extClass = '.RocksManga'
themePkg = 'madara' themePkg = 'madara'
baseUrl = 'https://rocksmanga.com' baseUrl = 'https://rocksmanga.com'
overrideVersionCode = 1 overrideVersionCode = 2
isNsfw = false isNsfw = false
} }

View File

@ -49,7 +49,7 @@ class RocksManga : Madara(
override val mangaDetailsSelectorThumbnail = ".manga-poster img" override val mangaDetailsSelectorThumbnail = ".manga-poster img"
override val mangaDetailsSelectorGenre = "div.meta span:contains(التصنيف:) + span a" override val mangaDetailsSelectorGenre = "div.meta span:contains(التصنيف:) + span a"
override val altNameSelector = "div.alternative" override val altNameSelector = "div.alternative"
override fun chapterListSelector() = ".chapters-list li.chapter-item" override fun chapterListSelector() = "li.chapter-item"
override fun chapterDateSelector() = ".chapter-release-date" override fun chapterDateSelector() = ".chapter-release-date"
override val pageListParseSelector = ".chapter-reading-page img" override val pageListParseSelector = ".chapter-reading-page img"

View File

@ -0,0 +1,10 @@
ext {
extName = 'Scans 4u'
extClass = '.Scans4u'
themePkg = 'keyoapp'
baseUrl = 'https://4uscans.com'
overrideVersionCode = 0
isNsfw = false
}
apply from: "$rootDir/common.gradle"

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