1902 Commits

Author SHA1 Message Date
dragonx943
7f98a7fb5c chore (site/vi): Update sources domain 2025-10-17 15:09:51 +07:00
Draken
a39721eaf7 DoujinDesu.tv: Fix search query, add author search support (#2326) 2025-10-17 14:40:54 +07:00
Draken
65c61c0c01 Mangafire: Get/generate vrf for ajax + Add referer, fix access denied (#2310)
Co-authored-by: Vicente <vicente@per>
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
Co-authored-by: Koitharu <nvasya95@gmail.com>
Co-authored-by: epikaigle444 <epikaigle444@gmail.com>
Co-authored-by: Max Bethmann <bethibande@gmail.com>
Co-authored-by: vtorres-t <73935362+vtorres-t@users.noreply.github.com>
Co-authored-by: epikaigle444 <epikaigle444@gmail.com>
Co-authored-by: Naga <94557604+NagaYZ@users.noreply.github.com>
2025-10-14 10:20:01 +07:00
dragonx943
ac977a6cbb HentaiVN.su: Small fixes, remove broken annotation 2025-10-13 08:55:43 +07:00
Draken
8908031eee Rawkuma: Update domain + Add broken annotation 2025-10-10 12:37:53 +07:00
Draken
4141a8f429 MimiHentai: Update API suffix, fix content not found or removed 2025-10-10 12:21:36 +07:00
Draken
ad7f1eddca Rawkuma: Use old domain, temporary fix nothing found 2025-10-10 01:04:43 +07:00
Draken
472ddab27c GocTruyenTranhVui: Update token, fix chapters list 2025-10-10 00:57:09 +07:00
Draken
560cf63a5e CManga: Fix missing content in getPages 2025-10-10 00:48:58 +07:00
dragonx943
d4e1acd515 Cứu Truyện: Allow to choose cover quality in source setting 2025-10-09 20:23:53 +07:00
Draken
f66b97edc1 HentaiVN.su: Add source (#2295) 2025-10-09 19:52:22 +07:00
epikaigle444
a084909507 MangaMoins: Add source (#2284)
Co-authored-by: epikaigle444 <epikaigle444@gmail.com>
Co-authored-by: Koitharu <nvasya95@gmail.com>
Co-authored-by: dragonx943 <premieregirl26@gmail.com>
2025-10-09 19:30:54 +07:00
vtorres-t
58357a3745 chore: Add broken annotation for some sources (#2275)
Co-authored-by: Vicente <vicente@per>
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
Co-authored-by: Koitharu <nvasya95@gmail.com>
2025-10-09 19:09:18 +07:00
Max Bethmann
8a6a529023 Mangakakalot fix getListPage (#2231) (#2285) 2025-10-09 09:54:17 +03:00
UC-01-Zer0-ID
1b9ff47ab3 ScanHentai.Menu: Update domain (#2277) 2025-10-08 09:19:06 +07:00
Draken
229f321299 Cứu Truyện: Remove broken 2025-10-06 22:44:35 +07:00
Draken
a5233ede48 MangaGeko: Fix missing images in getPages (#2267) 2025-10-03 08:38:31 +07:00
dragonx943
d9025dbf81 AtsuMoe: Delete source that were never usable 2025-10-02 14:25:56 +07:00
vtorres-t
2cc0af17d5 chore: Update domains (#2264)
Co-authored-by: Vicente <vicente@per>
2025-10-02 07:29:30 +07:00
Hoàng Phi Hùng
a3f384e3b3 Ổ Truyện: Fix no value for _id in getListPage (#2259)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-09-30 19:27:46 +07:00
nakrovati
5882a5d54d chore: update domains (#2255)
Close #2249, #2234, #2228, #2127
2025-09-30 08:05:40 +07:00
f62809407b [Madaradex] Fixes 2025-09-28 11:34:47 +03:00
Draken
14c0eaf273 Truyện Tranh Full: Add source (#2252) 2025-09-28 06:48:07 +07:00
Draken
0817a82f36 MadaraDex: Fix access denied errors in getPages
Co-authored-by: Koitharu <nvasya95@gmail.com>
2025-09-27 21:14:31 +07:00
Draken
727e326379 Cứu Truyện: Add broken 2025-09-27 17:43:32 +07:00
Harsh Dev Jha
ccaf52b74e AtsuMoe: Add source (close #2187)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-09-27 17:36:24 +07:00
Harsh Dev Jha
fc988cdd1e ReadManhua: Change source name to Resetscans + Update domain
Close #2201
2025-09-27 17:07:58 +07:00
Harsh Dev Jha
cb2e9841ae YuriLab: Update domain (close #2233) 2025-09-27 17:05:28 +07:00
Draken
775063d36f MimiHentai: Fix intercept, scrambled images in getPages (#2237) 2025-09-26 08:42:54 +07:00
Naga
86b8642456 XoxoComics: Fixes (#2229) 2025-09-23 06:27:10 +07:00
Draken
185d9b6e6e MyReadingManga: Fix order when query is empty 2025-09-23 04:50:39 +07:00
dragonx943
e3495fc41f MadaraDex: Add referer 2025-09-22 11:50:31 +07:00
dragonx943
d8e47b2b52 HiveComic: Remove broken 2025-09-22 11:21:13 +07:00
dragonx943
be64bf2328 MyReadingManga: Fix locale query + tags in getDetails 2025-09-22 11:19:26 +07:00
dragonx943
d85bb64b1c HiveComic: Use API to fix content not found in getListPage 2025-09-21 17:27:06 +07:00
dragonx943
de2289eb75 FreeMangaTop: Fix access denied in getPages 2025-09-21 16:59:14 +07:00
dragonx943
7cb069d108 MyReadingManga: Improve search query with more filters 2025-09-21 15:24:05 +07:00
dragonx943
8a18df148d ComicK: Add exception + Fix build for ci 2025-09-21 14:16:58 +07:00
dragonx943
9007852d31 MyReadingManga: Add broken 2025-09-21 14:10:57 +07:00
dragonx943
60e451303e MadaraParser: Add some values + Fix warn 2025-09-21 13:58:01 +07:00
dragonx943
170a11ae26 ci: Update dependencies for actions 2025-09-21 13:40:47 +07:00
dragonx943
642ac08338 MadaraDex: Fix access denied in getPages 2025-09-21 13:21:11 +07:00
Draken
ff256cb3ec CBHentai: Add state to manga details 2025-09-20 23:44:25 +07:00
Hoàng Phi Hùng
08d46988a3 LXManga: Add referer, fix not found error in getPages (#2220) 2025-09-20 21:29:26 +07:00
Draken
a3abc81dfc Dâm Cô Nương: Fix chapter list not found (#2210) 2025-09-19 05:33:12 +07:00
dragonx943
41a4c90e75 ComicK: Add broken 2025-09-19 04:56:03 +07:00
dragonx943
23fdfbbef9 Madtheme: Fix warns 2025-09-14 08:52:37 +07:00
dragonx943
a4f41e41f8 MTLParser: Fix warns 2025-09-14 08:51:44 +07:00
dragonx943
db586045d7 VioletScans: Fix warns 2025-09-14 08:43:12 +07:00
dragonx943
e636eda840 Remove unused import + Fix warns 2025-09-14 03:57:20 +07:00
dragonx943
406992a6c9 DragonTranslation.org: Add source + Fix warns 2025-09-14 03:50:26 +07:00
30f97c5c82 Improve OkHttp coroutines integration 2025-09-13 10:06:42 +03:00
b9ecdb2db6 [Desu] Fixes 2025-09-13 09:41:49 +03:00
e044463f91 [Grouple] Fixes 2025-09-13 09:35:48 +03:00
a93c760133 Fix tests running 2025-09-13 09:23:36 +03:00
dragonx943
f2b6cab251 site/vi: Update sources domain 2025-09-11 21:13:20 +07:00
dragonx943
07225568ee BatCave: Add referer, close #2176 2025-09-11 20:57:15 +07:00
dragonx943
860dd32a53 Góc Truyện Tranh Vui: Fix warns 2025-09-11 20:35:26 +07:00
dragonx943
74f5891ffe Góc Truyện Tranh Vui: Update token, fix chapters list 2025-09-11 20:20:13 +07:00
Draken
7bae2602c7 Merge pull request #2174 from nakrovati/build/improve-buildsrc-gradle-config
Use libs.toml.versions and `kotlin-dsl` in buildSrc build.gradle.kts
2025-09-09 16:04:53 +07:00
Draken
4c697b6406 Jitpack: Add configuration file to use JVM 17 2025-09-09 15:26:12 +07:00
Daniil Zhuravlev
b61698d405 chore: use libs.toml.versions in buildSrc 2025-09-09 04:37:19 +04:00
Draken
260e5acd5c Cứu Truyện: Change pageSize to 24, remove unused state 2025-09-09 04:43:19 +07:00
e599f431c5 Merge pull request #2172 from nakrovati/build/remove-gradle-from-buildsrc 2025-09-08 09:50:29 +03:00
Daniil Zhuravlev
0ec4fe42c1 build: migrate to gradle 9 2025-09-08 03:12:26 +04:00
Daniil Zhuravlev
c9e4c7273e build: remove gradle from buildSrc dir 2025-09-08 03:10:20 +04:00
Draken
3e2515ac6a Cứu Truyện: Improve search query with multiple tags (#2171) 2025-09-08 05:46:18 +07:00
fe5534b006 Remove DUMMY parser 2025-09-07 09:48:55 +03:00
Sergey Shumov
6ca07aeff7 ZenManga: update site domain (#2168) 2025-09-06 10:11:46 +03:00
19567f9642 Update dependencies 2025-09-06 08:38:25 +03:00
4a854c7a23 Update docs 2025-09-06 08:38:24 +03:00
Draken
312b617b95 Cứu Truyện: Use another publicUrl for better redirection 2025-09-05 17:24:38 +07:00
0a0a869e88 Merge pull request #2166 from nakrovati/refactor/migrate-gradle-scripts-to-kotlin-dsl 2025-09-05 13:06:39 +03:00
Hoàng Phi Hùng
8573921243 GocTruyenTranhVui + KuroNeko: Fixes (#2165)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-09-05 15:16:43 +07:00
Draken
b8d3124227 Update Gradle 8.7 to 8.13 (#2133) 2025-09-04 13:33:25 +03:00
Sergey Shumov
14e23694fd FIx ZenManga manga page url (#2164) 2025-09-04 13:28:55 +03:00
Daniil Zhuravlev
7e25002dba refactor(build): migrate to Kotlin DSL and version catalog 2025-09-03 16:27:21 +04:00
Daniil Zhuravlev
a94d9bf8b8 chore: update .editorconfig 2025-09-03 15:15:54 +04:00
nakrovati
7430c7386e Mark broken parsers and update several domains (#2163)
* chore: update outdated domains

* chore: mark broken parsers
2025-09-03 05:56:53 +07:00
Naga
5f99e694c8 MediocreToons: Fix chapter order (#2162) 2025-09-02 22:21:43 +07:00
dragonx943
25b23854d8 Góc Truyện Tranh Vui: Add source 2025-09-02 21:57:54 +07:00
dragonx943
45d39fe94d KuroNeko: Add delay to avoid rate limit 2025-09-02 21:38:15 +07:00
dragonx943
21b63c1d77 TruyenQQ: Add delay to avoid rate limit 2025-09-02 21:27:10 +07:00
Draken
f64ce0f4a2 Dâm Cô Nương: Remove redundant escape character (#2160) 2025-09-02 16:39:55 +07:00
Naga
b3e7d8e8d5 SussyScan: Fix CDN url in getPages (#2156) 2025-09-01 13:33:58 +07:00
Hoàng Phi Hùng
8a147dbdd3 Update getpage for DamCoNuong parser (#2149)
* Update DamCoNuong.kt

* Update DamCoNuong.kt to fix "Can't find fallbackUrls"

* Update DamCoNuong.kt
2025-08-30 09:10:04 +03:00
Hoàng Phi Hùng
5a039acf82 Dâm Cô Nương: Fix unsupported format in getPages (#2148) 2025-08-30 02:37:14 +07:00
Draken
e9469ae0e0 Dâm Cô Nương: Update domain 2025-08-29 14:43:40 +07:00
Naga
48cfc3347b TraduccionesAmistosas: Update domain (#2145) 2025-08-29 14:37:26 +07:00
nakrovati
1566b807b7 Update domains and correct the source language (#2132) 2025-08-27 00:50:24 +07:00
Naga
8bed45dd2f Komikcast: Fix SortOrder (#2124) 2025-08-24 19:36:09 +07:00
Waranim
36c3a88d63 ZenManga: Add source (#2123) 2025-08-24 11:01:38 +03:00
16f5129b69 [LibSocial] Fix Not found error 2025-08-24 10:47:21 +03:00
dragonx943
674290d029 MimiHentai: Add Broken, need to open WebView to read 2025-08-23 14:53:47 +07:00
bivaly
6cb6873fcb GhostScan: Update site domain (#2118) 2025-08-22 20:31:11 +07:00
fuckpdf
705a684cc2 UzayManga: Fix getPages (#2086) 2025-08-18 22:05:44 +07:00
Naga
de76ccf753 Weeb Central: Update tags selector (#2087) 2025-08-18 08:53:16 +07:00
Naga
cbd74dd7df AnimeSama: Add source (#2080)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-08-17 13:29:46 +07:00
dragonx943
7f39798a8c Yuri Garden: Add intercept, apply unscrambleImage for getPages 2025-08-17 04:23:41 +07:00
Naga
31999d97a0 Hentaman: Add source (#2078) 2025-08-17 02:01:45 +07:00
dragonx943
fd0df2414e MimiHentai: Use another UserAgent key, fix query in getListPage 2025-08-16 10:58:29 +07:00
Naga
a93140fc36 MediocreToons: Add source (#2077) 2025-08-16 09:59:03 +07:00
Naga
7c264b6af7 SussyScan: Fixes (#2076) 2025-08-16 09:57:37 +07:00
Naga
134656b835 InManga: Add source (#2073) 2025-08-16 03:30:50 +07:00
Naga
8964bb1584 Manhwalist.org: Update domain (#2072) 2025-08-16 03:25:53 +07:00
Naga
8bee71342b PhenixScans: Fixes (#2071) 2025-08-15 03:08:02 +07:00
Naga
a4824a3582 RaijinScans: Fixes (#2070) 2025-08-15 03:07:15 +07:00
Draken
6fb4cc608c ci: Update dependencies for actions (#2065) 2025-08-14 00:15:59 +07:00
dragonx943
12aa4479cd ci: Update dependencies for actions 2025-08-14 00:15:08 +07:00
Draken
bfdb10d002 Dâm Cô Nương: Fix exclude tags, CSS selectors for parseMangaList (#2064) 2025-08-13 23:50:53 +07:00
Naga
f61f5329e3 ArabsHentai: Add source (#2063) 2025-08-13 23:43:43 +07:00
dragonx943
0477fe0659 site/vi: Update sources domain + Favicons 2025-08-13 16:52:32 +07:00
dragonx943
6b3329436f Làng Geek: Set CHROME_DESKTOP as default UserAgent key 2025-08-13 16:08:42 +07:00
Draken
35fd5042a7 Làng Geek: Fix CSS selector for getPages, attempt 1 2025-08-13 02:46:23 +07:00
Naga
d366628a20 HeyToon: Add source (#2060) 2025-08-13 01:42:21 +07:00
Naga
5483453f35 RocksManga: Update site structure (#2059) 2025-08-13 01:30:23 +07:00
Naga
02ac1cb896 Ikiru: Update site structure (#2058) 2025-08-12 12:27:59 +07:00
dragonx943
1563783afe ci: Use another module for Gradle, try to improve build times 2025-08-11 11:38:55 +07:00
Naga
f5436977a9 MangaGg: Fix chapter list (#2056) 2025-08-11 11:07:24 +07:00
dragonx943
b58cf32b7a ci: Upgrade actions version and split steps 2025-08-11 00:46:15 +07:00
dragonx943
38025a6b35 ci: Change Java version, use compileKotlin instead of assemble 2025-08-11 00:36:10 +07:00
Draken
96a2d9e0ac ci: Add workflow to automatically test and compile parsers 2025-08-11 00:23:03 +07:00
Draken
c9ebbfa1bf LxManga: Throw Exception for restricted content 2025-08-11 00:05:57 +07:00
Naga
91ec95448c MyReadingManga: Update site structure (#2054) 2025-08-11 00:00:06 +07:00
Naga
b5512e7574 [KdtScan] Update domain + Fixes (#2050)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
Co-authored-by: dragonx943 <premieregirl26@gmail.com>
2025-08-08 01:39:15 +07:00
Naga
8bc7480d84 [PerfScan] Update domain + Fixes (#2047) 2025-08-07 13:36:34 +07:00
Naga
db9a7161f4 [PoseidonScans] Add source (#2042)
Close #1641
2025-08-05 04:52:36 +07:00
74d0951d3d [Remanga] Fix chapters parsing 2025-08-04 15:57:25 +03:00
91d5eff20a [Remanga] Migrate to api v2 2025-08-04 15:35:39 +03:00
Draken
54d6b2a2bb [Làng Geek] Add source (#2041) 2025-08-04 03:20:38 +07:00
Naga
66cd27a673 [Manhastro] Fix chapter list (#2040)
Close #1376 #1362
2025-08-04 00:55:51 +07:00
Naga
137490001a [HuntersScan] Update domain and fixes (#2039)
Close #2038
2025-08-04 00:55:03 +07:00
Naga
c85dac5e0e [ManhuaScan] Fixes (#2037)
Close #1418 #1730 #1922
2025-08-03 11:36:20 +07:00
dragonx943
9a9102fa33 [LXManga] Small fix for scanlator 2025-08-03 02:06:24 +07:00
Naga
0d31adb20b [HentaiRead] Fix search, tags, rating (#2036)
Close #1945
2025-08-03 01:22:42 +07:00
Draken
df7f2d1a89 [LXManga] Fix state + scanlator 2025-08-02 23:35:53 +07:00
dragonx943
eaca421132 [GocTruyenTranh] Use API instead of fixed tags function 2025-08-02 13:33:58 +07:00
Naga
5f1f2df7f0 [ManhwaBreakup] Add source (#2034)
Close #1967
2025-08-02 03:37:28 +07:00
Naga
ed21a5b397 [DoujinHentai] Fixes (#2030)
Close #1983
2025-08-01 03:22:29 +07:00
Draken
39703e3ebb [Ổ Truyện] Small fixes (#2027) 2025-07-31 15:16:38 +07:00
Naga
14cff0d651 [RokariComics] Add source (#2023)
Close #2008
2025-07-31 11:27:10 +07:00
Naga
af89f42251 [Komiku] Fixes (#2022)
Close #1986
2025-07-31 02:59:05 +07:00
Naga
036ce155ae [FlameComics] Fix image loading (#2020)
Close #2014
2025-07-31 00:22:52 +07:00
Naga
177d014b13 [Kiryuu] Update domain (#2021) 2025-07-31 00:22:26 +07:00
dragonx943
7c74ff6177 [EleceedTurkiye] Fix warn 2025-07-30 04:02:59 +07:00
Naga
b139586df5 [KomikIndo] Update domain and structure (#2017)
Close #723 #1466
2025-07-30 03:06:50 +07:00
dragonx943
15c7f97432 [HentaiVN.plus] Add author search 2025-07-30 00:35:21 +07:00
Naga
f22c8f9e7c [TemakiMangas] Small fixes
Close #1997
2025-07-29 23:52:59 +07:00
dragonx943
b24baf7d93 [site/vi] Update domain 2025-07-29 23:45:19 +07:00
Draken
98e0f6cd6c [Ổ Truyện] Add source (#2012) 2025-07-29 23:25:50 +07:00
Naga
e7316b5cd0 [InovaScanManga] Remake parser (Close #1988) 2025-07-29 23:05:44 +07:00
Naga
33a0a68ac7 [Klz9] Fixes (close #1949, #1433, #1455) 2025-07-29 20:27:06 +07:00
a83baf4c12 [Grouple] Handle restricted state 2025-07-29 15:29:06 +03:00
307f2090f6 [LibSocial] Improvements 2025-07-29 15:20:46 +03:00
Naga
e73d636979 [KomikCast] Fixes (Close #1995) 2025-07-29 12:23:01 +07:00
Naga
77fb7270ce [RimuScans] Update domain (Close #2005) 2025-07-29 12:19:15 +07:00
9d35f26252 Fix warnings (refactor) 2025-07-27 19:14:04 +03:00
4eeb879451 Fix build 2025-07-27 19:04:18 +03:00
06aa701ab1 Update MangaState enum 2025-07-27 18:03:38 +03:00
Draken
3c55b68beb [EleceedTurkiye] Add source (#2006) 2025-07-27 15:00:08 +07:00
dragonx943
63f37d159a [MimiHentai] Fix sort orders 2025-07-26 22:45:43 +07:00
dragonx943
cb74c43f71 [MimiHentai] Temporarily remove "POPULARITY_MONTH" 2025-07-26 22:21:53 +07:00
dragonx943
798b7570fe [MimiHentai] Update favicon 2025-07-26 22:13:04 +07:00
Draken
9197b82e0d [KuroNeko] Rename source 2025-07-23 11:31:20 +07:00
Draken
ad45480439 [BatCave] Small fix for getDetails (#1994) 2025-07-22 16:35:13 +07:00
Draken
9493ff1630 [MyReadingManga] Fix tags + search 2025-07-22 14:24:08 +07:00
Draken
8ee46ad2d1 [TruyenHentai18] Small tweak + Refactor (#1992) 2025-07-22 12:15:22 +07:00
dragonx943
ba1b35522c [TruyenHentai18] Fix attempt 1 2025-07-22 11:54:47 +07:00
dragonx943
41c37c025a [site/vi] Update domain 2025-07-22 00:36:16 +07:00
Draken
9995657da5 [TruyenHentai18] Fix getPages 2025-07-21 23:30:33 +07:00
dragonx943
1569275cd4 [TruyenHentai18] Remove unused import + Broken 2025-07-21 23:27:08 +07:00
dragonx943
352d998680 [TruyenHentai18] Fix attempt 1 2025-07-21 23:12:24 +07:00
Draken
d0b2002a1b [KuroNeko + CuuTruyen] Small fixes (#1989) 2025-07-21 22:52:43 +07:00
5962efb7df Update parsers structure (again) 2025-07-18 13:50:02 +03:00
Draken
8b18d1f0f8 [Com-X] Update domain 2025-07-17 16:38:16 +07:00
Draken
97ca214815 [DoujinDesu.click] Update domain 2025-07-15 11:00:42 +07:00
Draken
5d9b56296b [HentaiVn.buzz + YuriGarden] Fixes (#1968)
* [HentaiVn.buzz] Fix "Nothing found" errors

* [YuriGarden] Add author search support + Small fixes
2025-07-14 20:52:51 +07:00
Batu
66f25c30fc [Gafeland] Add source (#1963)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-07-14 01:55:58 +07:00
dragonx943
fd197de86a [LXManga] Fix CSS selector in altTitles 2025-07-14 00:33:13 +07:00
dragonx943
5f7478b33c [LXManga] Store altTitles + Revert CSS selector 2025-07-13 23:53:26 +07:00
dragonx943
b058477b67 [LXManga] Small fix for altTitles 2025-07-13 23:12:57 +07:00
dragonx943
149d9e5a81 [LXManga] Remove not null constraint for altTitles 2025-07-13 19:37:05 +07:00
Batu
6420def95a [site/tr] Update domain + Add Broken (#1956)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-07-13 18:33:51 +07:00
fuckpdf
5dae26ce0b [MangaTilkisi] Add source (#1940)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-07-13 00:45:30 +07:00
Draken
b5fddadb18 [LXManga] Small fixes for getDetails (#1955) 2025-07-13 00:44:29 +07:00
Draken
613d1cd1a1 [PhenixScans] Fix API path 2025-07-10 16:54:31 +07:00
fuckpdf
a6a72064bb [TenshiManga] Add source (#1933)
* [UzayManga + ElderManga] Update order

* [TenshiManga] Add source

---------

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-07-10 14:26:49 +07:00
dragonx943
73c0a4f606 [YuriGarden] Revert scanlator for getDetails 2025-07-10 14:23:03 +07:00
Draken
1d2ee20d17 [YuriGarden] Fixes (#1934) 2025-07-10 14:09:09 +07:00
dragonx943
67b556c2eb [YuriGarden] Small fixes 2025-07-08 18:05:31 +00:00
Draken
3962c87e1d [YuriGarden] Fix line 2025-07-09 00:51:41 +07:00
dragonx943
e6ca455254 [YuriGarden] Fix order / path + Remove rating 2025-07-08 17:49:08 +00:00
Naga
d481ff416f [Flamecomics] Fix search and genre fitlering (#1923) 2025-07-08 02:22:16 +07:00
Draken
b0236e492d [YuriGarden] Add source (#1924) 2025-07-08 02:01:53 +07:00
dragonx943
497321bfa8 [KuroNeko] Add author search support 2025-07-07 12:29:02 +07:00
Draken
eff26f6303 [CBHentai] Add author search + Fix duplicate tags (#1918) 2025-07-06 17:53:26 +07:00
Crono
b5bd5b8cdf [Manhastro + LuraToon] Update domain (#1915) 2025-07-05 22:46:49 +07:00
Draken
4cc15daba3 [Koharu] Add Broken 2025-07-05 22:43:56 +07:00
248d51321a [Koharu] Refactor UserAgent 2025-07-05 08:41:29 +03:00
7cb9a264de [LibSocial] Allow to change domain 2025-07-05 08:39:47 +03:00
Draken
b58e9ff328 [TopTruyen] Update domain 2025-07-05 01:24:02 +07:00
dragonx943
958e0bed5c [site/vi] Update domain 2025-07-05 00:47:40 +07:00
ViAnh
e8d4143d72 [Koharu] Fix getPages (#1914)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-07-05 00:19:00 +07:00
Naga
079b2346f1 [Webtoon] Fixes (#1912) 2025-07-03 20:56:20 +07:00
Iwakurra
553615b3ff [HentaiLib] Update domain + allow user to set custom (#1908) 2025-07-02 23:47:50 +07:00
f8992457dc Update domains 2025-06-29 16:26:27 +03:00
Draken
06a9209b9e [DexHentai] Fix getListPage (close #1901) 2025-06-26 12:43:42 +07:00
Draken
4c0b873013 [Hentalk] Update domain 2025-06-23 22:08:19 +07:00
dba7f46f73 [Remanga] Update domain (#1891) 2025-06-21 19:23:01 +03:00
8665186426 [LibSocial] Fix chapters branches 2025-06-21 19:18:59 +03:00
b5c6a94311 [ExHentai] Fix pagination 2025-06-21 19:08:27 +03:00
1540021f6f [Remanga] Fix parsing manga without covers 2025-06-21 19:03:06 +03:00
0e1247476e [LibSocial] Fix tags in details 2025-06-21 18:55:57 +03:00
SrCrono
bf83909349 [FlowerManga] Update domain (#1890) 2025-06-19 12:20:38 +07:00
Draken
e398a01f14 [AgsComics] Fix cover images
Close #1886
2025-06-19 03:34:26 +07:00
Draken
0e77938ade [NewTruyen] Fix getPages
Solved #1604
2025-06-19 02:17:34 +07:00
dragonx943
a4a9a1cf67 [NewTruyen] Fix getPages 2025-06-19 02:10:37 +07:00
Draken
3f9544fdb8 [MimiHentai] Small fix for exclude tags 2025-06-18 23:03:36 +07:00
dragonx943
bd30fc35a1 [WestManga] Add broken 2025-06-16 22:38:43 +00:00
Draken
b6f82cc282 Merge pull request #1884 from dragonx943/dev
[1stKissManga] Update domain + Small fix
2025-06-17 05:36:43 +07:00
dragonx943
9222079e98 [1stKissManga] Update domain + Small fix 2025-06-16 22:31:14 +00:00
Draken
49158b99d5 [CManga] Fix logic 2025-06-16 05:14:28 +07:00
Draken
3fe61a09b7 [CManga] Improvement getPages 2025-06-16 04:27:34 +07:00
Draken
b82ad1356e [CManga] Fix chap number (#1880) 2025-06-15 18:46:05 +07:00
dragonx943
b825d06b22 [CManga] Fix chap number 2025-06-15 11:27:38 +00:00
Draken
28f5856f9e [Desu] Update domain 2025-06-15 03:22:19 +07:00
Draken
19751674ee [TruyenHentai18] Add broken 2025-06-15 03:15:46 +07:00
Draken
a78afba15e [KuroNeko + TruyenHentai18] Fixes (#1879)
Solved #1683 #1604
2025-06-15 00:00:17 +07:00
Draken
0e946cf84c [site/vi] Update sources domain (#1874) 2025-06-14 23:59:18 +07:00
Draken
6cd29603ac [CBHentai] Fix duplicated tags (#1873) 2025-06-09 20:49:33 +07:00
Draken
d94cf53624 [MimiHentai] Add exclude tags support (#1872) 2025-06-09 20:18:42 +07:00
Draken
c81628c027 [YuriGarden] Removal (#1866, close #1863) 2025-06-07 15:50:52 +07:00
bcde8ef2a2 Fix build 2025-06-07 11:15:29 +03:00
66df6caa67 [ExHentai] Improvements 2025-06-07 10:53:28 +03:00
Draken
08e53b2f5f [MimiHentai] Small fix 2025-06-05 17:33:56 +07:00
Draken
7c83730ad0 [MimiHentai] Fix getListPage 2025-06-05 16:23:56 +07:00
dragonx943
d2a026c054 [MimiHentai] Remove state 2025-06-05 08:41:55 +00:00
dragonx943
faf8f6ffd7 [MimiHentai] Fix getListPage 2025-06-05 08:35:23 +00:00
Draken
6c372548db [site/vi] Update sources domain (#1861) 2025-06-05 09:23:37 +07:00
Draken
0029697350 Fix line 2025-06-05 09:21:22 +07:00
dragonx943
bdcf27b955 [site/vi] Update sources domain 2025-06-05 02:20:12 +00:00
Draken
bb7ac26c0c [MimiHentai] Small fixes (#1860) 2025-06-05 09:03:45 +07:00
Draken
7b42317996 [MimiHentai] Add Broken 2025-06-05 05:14:06 +07:00
Draken
103b0e7eb6 [ZinChanManga] Update domain
Solved https://github.com/KotatsuApp/kotatsu-parsers/issues/1835
2025-06-05 03:33:13 +07:00
Draken
fa80598e7c [DamCoNuong] Update domain
Solved a task in #1604
2025-06-03 02:58:28 +07:00
Draken
3cb5367028 [madtheme/en + wpcomics/vi] Small fixes (#1830)
* [WpComics] Split NetTruyenX + Small improvements

* [MangaBuddy] Add subdomain

* [MangaPuma] Add subdomain

* [MangaForest] Add subdomain

* [MangaCute] Add subdomain

* [Manhuagui] Change UA to `CHROME_DESKTOP`

* [Mangaxyz] Add subdomain
2025-06-03 01:11:42 +07:00
Zhifan Ye
9417d1f973 [Manhuagui] Fix UA and parse errors (#1834) 2025-06-03 01:08:26 +07:00
mozzaru
173d30737b [MgKomik] Update domain (#1828) 2025-06-01 00:53:59 +07:00
Draken
0db45877b7 [SolarMTL] Add source (#1826) 2025-05-31 18:12:40 +07:00
Draken
e7fac812a7 [SnowMTL] Add source (#1823)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-31 12:29:13 +07:00
Draken
ab26e6b3d0 [TrueManga] Update domain 2025-05-30 15:19:21 +07:00
Draken
baafc29967 [MimiHentai] Small fix 2025-05-28 15:12:03 +07:00
Draken
b0bd3e99a4 [MimiHentai] Small changes (#1818)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-28 03:34:22 +07:00
Draken
6bf377a654 [NhatTruyenVN] Fix list chaps (#1816)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-27 14:46:48 +07:00
Zhifan Ye
3d78b9003d [Manhuagui] Add source (#1812)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-27 02:48:57 +07:00
Draken
f57722ec54 [Com-X] Small changes (#1814)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-26 16:18:40 +07:00
9558a34b00 [Koharu] Fixes 2025-05-25 19:29:37 +03:00
Draken
522e3af41d [Koharu] Fixes (#1811)
* [Koharu] Debug attempt 1

* [Koharu] Debug attempt 2

* [Koharu] Debug attempt 3

* [Koharu] Fix chapter url

---------

Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-25 10:06:52 +03:00
7b1a0b8d0d [LibSocial] Authorization support 2025-05-24 16:50:23 +03:00
5856681753 [LibSocial] Fixes 2025-05-24 14:04:01 +03:00
Draken
f066be47fe [site/vi] Update domain + Small fixes (#1804)
* [VioletScans] Move to "en"

* [site/vi] Update sources domain

* [Madara] Split and allow overwrite for "postData"

--------------------------

Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-24 16:35:14 +07:00
Draken
884142a15e [UlasComic] Update domain + Fix getPages (#1803) 2025-05-24 15:22:37 +07:00
Tronik568
d7267b20fd [MaidScan] Update domain (#1802) 2025-05-23 14:46:45 +07:00
Talkc0n
0537cdd533 [SayHentai] Update domain (#1801) 2025-05-23 01:07:06 +07:00
Draken
c5f939df70 [Com-X] Small fixes: Bypass age verification (#1800) 2025-05-22 15:11:55 +07:00
Darwin
6854164e5a [VioletScans] Add source (#1798)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-21 20:39:14 +07:00
Draken
1e942c650b [HiperDex] Update domain + Remove Broken
Solved #1766
2025-05-21 15:21:30 +07:00
Naga
30a06b67d8 [Hitomi.La] Fix cover images (#1795) 2025-05-21 03:28:52 +07:00
Naga
34a1dabae4 [MagusToon] Move to iken (#1794)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-21 01:15:05 +07:00
Draken
23227a0427 [HoloEarth] Fix getDetails + Add locale (#1792)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-20 13:19:58 +07:00
Draken
02d1aef77c [Multporn] Add source (#1791)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-20 11:43:53 +07:00
Darwin
39ebdacef9 [HoloEarth] Add source (#1788)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-20 10:14:36 +07:00
Draken
276349e23c [YuriGarden] Replace SAFE with SUGGESTIVE 2025-05-18 00:38:17 +07:00
kerimmkirac
0507ed8d59 [DemonicScans] Add source (#1785)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-17 19:36:49 +07:00
Nam Huynh
2f8a0fe775 [HentaiNexus + HentaiRead] Small fixes (#1784)
* [HentaiNexus]
+ Fix package (due to moving)
+ Fix getPages() getPageUrl() (add flag for data reloading)
+ Fix getDetails (tag with quotes)
+ Cleaning

* [HentaiRead]
+ Fix package (due to moving)
+ Fix getListPage() (author searching)
+ Re-write getDetails() (update source)
+ Cleaning
2025-05-17 14:28:59 +07:00
Draken
aab7e9360a [site/vi] Update sources domain (#1780)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-15 21:23:49 +07:00
Draken
9db443f7f7 [HangTruyen + GocTruyenTranh] Fix getPages (#1778) 2025-05-15 19:46:39 +07:00
Nam Huynh
70ce9eb008 [HentaiNexus + HentaiRead] Small fixes (#1776)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-14 13:36:32 +07:00
Draken
a58947376c [Misskon] Add source (#1772) 2025-05-10 20:20:13 +07:00
Draken
cbb70f94dd [Manhwa210] Add source (#1771) 2025-05-10 19:05:46 +07:00
9408b9ba1b Update MangaLoaderContext 2025-05-10 13:33:11 +03:00
409828d22f Update MangaLoaderContext 2025-05-10 12:06:20 +03:00
Nam Huynh
c9d32a804c [Nhentai World + MeHentaiVN] Fixes (#1769)
* [HentaiRead] Fix lines

* [MeHentaiVN] Soft re-write due to source changed (#1604)

* [NHentaiWorld] Fixes fetchTags (due to source changed) and pass MangaParserTest:link (#1604)

* [MeHentaiVN] Small changes

* [MeHentaiVN] Update domain

---------

Solve task #1604

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-10 14:28:18 +07:00
Draken
a65cbf4981 [ReaperComics] Add Broken 2025-05-10 13:44:49 +07:00
mozzaru
e325063260 [Apkomik] Add Source (#1765) 2025-05-09 17:19:25 +07:00
cf0177364c Add requestDataFromBrowser function to MangaLoaderContext 2025-05-08 14:06:52 +03:00
Draken
8eaad2270b [Hitomi.La] Small fix for red covers 2025-05-08 12:54:15 +07:00
Nam Huynh
362f9c6786 [HentaiRead] Add Source! (KotatsuApp#1745) (#1762)
Solved https://github.com/KotatsuApp/kotatsu-parsers/issues/1745

---------

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-08 00:33:35 +07:00
Draken
3047949b22 [ru/grouple] Small fixes (#1761)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-07 14:08:31 +07:00
Draken
8d7c81c8ef Merge branch 'master' into master 2025-05-07 13:19:33 +07:00
Nam Huynh
7d6e12d1fc [HentaiNexus] Add source (#1757)
Solved #1690

---------

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-06 23:05:55 +07:00
spozer
7a0f1af06a [ReadOnePiece] Add source (#1758)
Solved https://github.com/KotatsuApp/kotatsu-parsers/issues/1040

---------

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-06 22:51:19 +07:00
Draken
21aaa23586 [MimiHentai] Remove deprecated value 2025-05-06 22:00:34 +07:00
Draken
95fcbd44fd [Kiutaku] Debug attempt 1 2025-05-05 14:22:59 +00:00
Draken
cc98931147 [Kiutaku + Xiutaku] Add sources (#1755)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-05 13:11:12 +07:00
Draken
8f61beadb2 [Hitomi.la] Small fixes (#1754)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-05 13:03:45 +07:00
Draken
6d404c6997 [RoliaScan + ElderManga] Add sources (#1753) 2025-05-05 13:02:57 +07:00
kerimmkirac
27060cfef0 [RoliaScan + ElderManga] Add sources (#1753)
* [RoliaScan] Add source

* [ElderManga] Add source

* [UzayManga] Fix search

---------

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-05-05 13:02:20 +07:00
Draken
ca3d8f555a [BatCave] Remove referer 2025-05-04 16:16:58 +07:00
Draken
7ea59a7bf1 [HeanCms] Small improvements (#1751)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-04 16:01:34 +07:00
Draken
cea4db9619 [BatCave] Small fixes (#1750)
Solved #1749
2025-05-04 16:01:14 +07:00
Draken
e7c3168099 [Readmanga] Add referer (#1748) 2025-05-04 16:00:38 +07:00
Draken
b165a0d611 Merge pull request #1744 from dragonx943/debug
[TeamXNovel] Small fixes
2025-05-03 11:20:41 +07:00
Draken
43e6c7c86f [TeamXNovel] Small fixes 2025-05-03 04:17:01 +00:00
Draken
346828402b [TeamXNovel] Revert: Fix getPages 2025-05-03 11:07:33 +07:00
Draken
01d67eca2e [site/vi] Update sources domain (#1741)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-05-03 00:16:56 +07:00
Draken
4445b666aa [site/iken] Small fixes (#1740)
* Vortexscans (Broken): Need to fix list chaps + getPages function

* Temporary fix for #1737, reference: keiyoushi/extensions-source#8645
2025-05-01 17:08:32 +07:00
Draken
adf0b4e397 [DayComics] Fix list chaps 2025-05-01 09:57:39 +07:00
Draken
e797cabd88 [HotComics] Fix list chaps (#1739)
Solved https://github.com/KotatsuApp/kotatsu-parsers/issues/1717, reference: https://github.com/keiyoushi/extensions-source/pull/5405
2025-05-01 09:53:20 +07:00
Draken
0c32b56378 [NetTruyen1975] Add source (#1736)
* [UzayManga] Fix tags (Attempt 1)

* [NetTruyen1975] Add source

* [NetTruyen*] Fix getPages

---------

Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-04-30 00:12:23 +07:00
kerimmkirac
5c9c2c3a7a [BookManga] Add Source (#1731) 2025-04-28 01:46:34 +07:00
kerimmkirac
7cd7180adb [ArmoniScans] Add Source (#1729)
Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-04-27 20:02:44 +07:00
kerimmkirac
4b6b585801 [MajorScans] Rename + Update domain (#1725) 2025-04-27 00:34:09 +07:00
Draken
1cf2153df0 [UzayManga] Fixes (#1726) 2025-04-27 00:33:13 +07:00
Draken
6ed104aeca [AlucardScans] Add source (#1722) 2025-04-27 00:00:47 +07:00
kerimmkirac
9ba1629065 [AlucardScans] Add source (#1722) 2025-04-26 23:59:48 +07:00
kerimmkirac
669709dfbb [site/tr + en] Add new sources (#1721)
* Add UzayManga, Mangacix, AsuraScansTR, TrMangaOku, MangaKoleji, HiveComic

* [Mangacix] Clean url

* [HiveComic] Add Broken

* [UzayManga] Clean up

* Update summary.yaml

---------

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-04-26 21:54:53 +07:00
kerimmkirac
b5cb310aab [RagnarScans] Add source (#1715)
* Add files via upload

* Update summary.yaml

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Update Ragnarscans.kt

* Remove old parser

* [Ragnarscans] Add source

---------

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-04-26 09:38:18 +07:00
Draken
50771771a8 [TeamXNovel] Fix getPages
Reference: https://github.com/keiyoushi/extensions-source/pull/8624
2025-04-25 21:35:59 +07:00
Draken
dce24e2005 [MimiHentai] Small change 2025-04-25 15:43:11 +07:00
Draken
d3a61f6556 [MimiHentai] Fix chaps order (#1711)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-04-25 15:19:58 +07:00
Dika Ardianta
8cdd7effe5 [site/id] Update sources domain + Rename (#1705)
- Update sources domain
- Remove dead sources
- Remove duplicate site
- Rename title ManhwaList.in to ManhwaList
- Rename title KomikMirror to KomikLokal

* restore removed files with @Broken marker

Related to commit 60a085843d
2025-04-25 14:17:47 +07:00
kerimmkirac
e389b01d35 [MangaGezgini] Update domain (#1710) 2025-04-25 01:55:31 +07:00
Draken
2c9632e3e5 [site/vi] Update sources domain (#1709) 2025-04-24 23:25:14 +07:00
Draken
2fff92b023 [HangTruyen] Add source (#1708)
Solved task #1694
2025-04-24 23:05:44 +07:00
Draken
c949b95dab [YuriGarden] Add source (#1707)
Solved task #1704
2025-04-24 17:13:14 +07:00
Draken
da145c7f41 [MangaDistrict] Small change 2025-04-23 14:13:44 +07:00
bivaly
16b8bf9328 [FlameComics] Fixing coverurl (#1697) 2025-04-22 03:10:05 +07:00
f076c8095a Misc parsers fixes 2025-04-21 12:22:08 +03:00
d2b2578a3a [Shinigami] Fixes 2025-04-21 12:09:09 +03:00
b24741678c [Koharu] Fixes 2025-04-21 11:18:49 +03:00
dragonx943
fecb1db3be [Shinigami] Fix search with tags + Refactor 2025-04-20 14:21:04 +07:00
Draken
6418422157 [site/vi] Update sources domain 2025-04-20 00:56:11 +07:00
Draken
7718ff28e7 [Shinigami] Remake parser
* Solved task #1676

* Solved #1654 #1638 #1563 #1535 #1402 #1380 #1306 #1289 #1089
2025-04-20 00:16:29 +07:00
devi
3771b8d26b Fix PhenixScans close #1599
close #1675
Fix KeyoappParser close #1640
2025-04-18 20:20:42 +02:00
Draken
c1357b46fb [NetTruyen] Fix list chaps (#1678) 2025-04-18 00:39:08 +07:00
Draken
6c9f6eaae5 [Shinigami] Add Broken 2025-04-17 12:26:16 +07:00
Draken
309b6405f9 [Koharu] Add source (#1667)
[Koharu] Add source (Broken)
2025-04-16 03:52:20 +07:00
Draken
9058ead462 [Com-X] Add source (#1673) 2025-04-16 03:46:09 +07:00
Draken
162436c913 [BatCave] Fix search (#1672) 2025-04-16 00:59:25 +07:00
Draken
876f3a3d3a [BatCave] Move to Comic sources 2025-04-15 23:40:20 +07:00
Draken
02acc7e9d4 [CuuTruyen] Add new SortOrder (#1669) 2025-04-14 15:46:45 +07:00
e874837efb Improve some parsers 2025-04-13 09:43:31 +03:00
Draken
c294f5bb61 [Hentalk] Small fixes 2025-04-13 03:33:20 +07:00
Draken
826c948260 [Hentalk] Add source (#1665) 2025-04-13 02:53:19 +07:00
Draken
a5c70f0b51 [WaManga] Set reverse for list chaps 2025-04-13 01:25:24 +07:00
Draken
c2f9c18e29 [YuriNeko] Add Broken 2025-04-12 03:24:18 +07:00
Draken
91cd239c97 [BatCave] Add source (#1658) 2025-04-12 03:06:24 +07:00
Draken
4d255d0d53 [MimiHentai] Add source (#1651)
* [MimiHentai] Add source

* [MimiHentai] Fixes

* [MimiHentai] Clean code

---------

Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-04-11 23:34:58 +07:00
Draken
d5a1e1a52f [site/vi] Update sources domain (#1653)
Co-authored-by: Draken <dragonx943@users.noreply.github.com>
2025-04-11 23:34:32 +07:00
9abc80880f [Desu] Update domain 2025-04-10 09:29:51 +03:00
Draken
8d91adbd6e [Vcomycs] Update domain - #1644 2025-04-09 01:45:36 +07:00
kerimmkirac
20a24db949 Fixing url of turkish extensions (#1642)
* Update MangaGezgini.kt

* Update MangaTr.kt

* Update Timenaight.kt

* Update Mangacim.kt

* Update MilaSub.kt

* Update Grimelek.kt

* Update Grimelek.kt

---------

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-04-08 08:03:26 +07:00
b837659408 [Desu] Fix domains order 2025-04-06 16:30:49 +03:00
MakaMonstir
696e0bc8f6 [Desu] Update domain (#1637)
* Update domain list

* [Desu] Update domain

---------

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
2025-04-05 23:20:54 +07:00
palaks-1
2ec2484982 [NHentai.xxx] Fix source (#1628) 2025-04-01 22:31:10 +07:00
Draken
738e2649d6 [DocTruyen5s] Small fixes 2025-04-01 18:20:50 +07:00
Draken
8e9da4e39f [Hitomi.La] Change cdn domain & fix image url logic (#1624)
* [Hitomi.La] Change cdn domain & fix image url logic

* [Hitomi.La] Set null for preview in getPages

* [Hitomi.La] Remove unused function

* [Hitomi.La] Use webp for preview images

* [Hitomi.La] Fix build
2025-03-31 15:30:38 +07:00
Draken
da3a9a7d9b [Phenixscans] Mark as Broken 2025-03-31 13:27:37 +07:00
Draken
8f9c0d93f6 [DocTruyen3Q] Fix chapter images + Improvements (#1621) 2025-03-30 16:41:12 +07:00
Draken
8bb0c4f4f1 [site/vi] Update sources domain 2025-03-30 00:27:50 +07:00
dbb04d2051 Fix link resolver 2025-03-28 09:03:36 +02:00
Draken
84562d7b36 [DoujinDesu.click] Update domain
Solved #1590
2025-03-25 13:10:14 +07:00
Draken
29327dafd0 [DamCoNuong] Update domain + Fix images
* [DamCoNuong] Update domain + Fix images
* [DamCoNuong] Fix domain
2025-03-24 18:43:48 +07:00
Draken
c0d12b0c83 [CuuTruyen] Fixes + Tweaks
* [Cứu Truyện] Fix chap scanlator

* [Cứu Truyện] Fix search with state + Tags
2025-03-24 17:57:50 +07:00
a0041f3c93 Fix build 2025-03-21 19:06:26 +02:00
2175e91db7 [DamCoNuong] Fixes 2025-03-21 18:44:59 +02:00
Draken
5fa7590550 [TopTruyen] Update domain 2025-03-21 18:25:34 +07:00
Draken
f3ae64ed1f [HentaiZ] Update domain 2025-03-21 18:24:52 +07:00
cc437b8cd4 [ExHentai] Pages preview support 2025-03-21 13:16:09 +02:00
Draken
db0782c61a Merge pull request #1591 - dragonx943/damconuong/fixes
[DamCoNuong] Fixes
2025-03-21 18:11:28 +07:00
Draken
bbf059ff35 [DamCoNuong] Fixes 2025-03-21 18:07:18 +07:00
Draken
bebc615376 Merge pull request #1589 - dragonx943/sources/damconuong
[DamCoNuong] Add source
2025-03-21 02:58:40 +07:00
Draken
77616a5404 [DamCoNuong] Add source 2025-03-20 19:55:05 +00:00
Draken
45584f2eea Merge pull request #1588 - dragonx943/fixes
[TopTruyen] Fix chapter images
2025-03-20 22:15:27 +07:00
dragonx943
1c3e59f9f0 [TopTruyen] Fix chapter images 2025-03-20 21:16:09 +07:00
Draken
a88de5b1b6 [TopTruyen] Small changes 2025-03-20 21:02:43 +07:00
Draken
91977ba025 [MyReadingManga] Small changes 2025-03-20 21:01:31 +07:00
Draken
5420290564 [CuuTruyen] Add some tags 2025-03-17 23:32:12 +07:00
Draken
98c21db8da Merge pull request #1577 - dragonx943/sources/domain
[vi/site] Update sources domain
2025-03-17 20:11:01 +07:00
dragonx943
23953cae11 [vi/site] Update domain 2025-03-17 20:06:41 +07:00
Draken
9cd310ba51 Merge pull request #1576 - dragonx943/sources/doctruyen3q
[TopTruyen + DocTruyen3Q] Fix chapter images
2025-03-17 19:50:42 +07:00
dragonx943
51311a17fb [TopTruyen] Fix chapter images 2025-03-17 19:46:40 +07:00
dragonx943
6799d79754 [DocTruyen3Q] Fix chapter images 2025-03-17 19:24:42 +07:00
Draken
e429cdd811 [WeebCentral] Fix title not found 2025-03-17 18:07:36 +07:00
Draken
2e5ce98bac Merge pull request #1575 - dragonx943/sources/myreadingmanga
[MyReadingManga] Add source
2025-03-17 17:24:48 +07:00
Draken
68c3a7148f [MyReadingManga] Add source 2025-03-17 10:08:10 +00:00
Draken
2a1c5bc6da [Manga18] Fix title not found 2025-03-17 00:14:18 +07:00
Draken
6fd18543ef [Manga18] Fix title not found 2025-03-17 00:11:38 +07:00
ae76631aaf [HeanCms] Fix manga ids 2025-03-16 13:04:34 +02:00
Draken
ca59e8e577 Merge pull request #1571 - dragonx943/sources/cmanga
[CManga] Small fixes
2025-03-15 15:27:18 +07:00
Draken
3648b36d16 [CManga] Small fixes 2025-03-15 15:13:33 +07:00
Draken
439b7862a3 Merge pull request #1570 - dragonx943/sources/doctruyen5s
[DocTruyen5s] Fixes
2025-03-15 14:41:03 +07:00
dragonx943
f4b975c865 [DocTruyen5s] Fixes 2025-03-15 14:38:34 +07:00
dragonx943
da02a82d74 [DocTruyen5s] Fixes 2025-03-15 14:24:01 +07:00
bivaly
0d5498e60d Update FlameComics.kt 2025-03-15 08:13:36 +02:00
0847baf17b Fix http request processing 2025-03-14 20:55:36 +02:00
adf5794ad3 Expose authorization provider 2025-03-14 19:18:25 +02:00
Draken
cfeea09a05 Merge pull request #1567 - dragonx943/sources/domain
[site/vi] Update domain + Tweak
2025-03-14 18:17:11 +07:00
dragonx943
e9bcb1abed [site/vi] Update domain + Tweak 2025-03-14 18:13:30 +07:00
Draken
35cf827c90 Merge pull request #1566 - dragonx943/sources/nhentaiworld
[Nhentai World] Fix tags
2025-03-14 12:47:29 +07:00
dragonx943
a10c34115b [Nhentai World] Fix tags 2025-03-14 12:37:29 +07:00
Draken
2f4e93e391 Merge pull request #1565 - dragonx943/sources/nhentaiworld
[Nhentai World] Fix chapters list
2025-03-14 01:00:28 +07:00
dragonx943
6ed42bc28b [Nhentai World] Fix chapters list 2025-03-14 00:58:02 +07:00
dragonx943
dc7c859344 [Nhentai World] Fix chapters list 2025-03-14 00:56:19 +07:00
a82e41aabb Deprecate Manga.isNsfw 2025-03-12 13:01:43 +02:00
Draken
3c62f4280f Merge pull request #1557 from dragonx943/kuma/tweak
[Kumapage] Fixes + Tweak
2025-03-11 10:23:34 +07:00
Draken
f806cdd118 [Kumapage] Fixes + Tweak 2025-03-11 02:48:22 +00:00
Draken
224c8a6c53 [Kumapage] Fixes + Tweak 2025-03-11 02:43:17 +00:00
Draken
408be7fa3c Merge pull request #1555 - dragonx943/sources/kuma
[Kumapage] Add source
2025-03-10 21:46:27 +07:00
Draken
a02b001768 [Kumapage] Add source + TODO 2025-03-10 14:43:03 +00:00
Draken
5edbdf801a [Kumapage] Fixes 2025-03-10 14:41:21 +00:00
Draken
cc3701250a [Kumapage] Fixes 2025-03-10 14:27:07 +00:00
Draken
e94d434f92 [Kumapage] Fixes 2025-03-10 14:19:31 +00:00
Draken
4d3adaa143 [Kumapage] Add source 2025-03-10 13:51:22 +00:00
Draken
36eecf781f Merge pull request #1552 - palaks-1/source/fixes
[NHentai.xxx] Fixes
2025-03-10 01:11:38 +07:00
palaks-1
76f44c98be [NHentai.xxx] Fix source 2025-03-09 20:06:08 +02:00
Draken
d660d9a30f Merge pull request #1551 - dragonx943/sources/domain
[site/vi] Update sources domain
2025-03-10 00:38:48 +07:00
Draken
8326ee8c29 [site/vi] Update domain 2025-03-09 17:36:07 +00:00
Draken
690a004de6 Merge pull request #1550 - dragonx943/sources/dragon
[Dragon Translation] Remake parser
2025-03-10 00:22:50 +07:00
Draken
98c6454eba [Dragon Translation] Fix pages img 2025-03-09 17:14:48 +00:00
Draken
8e42ef1229 [Dragon Translation] Remake attempt 1 2025-03-09 16:58:25 +00:00
Draken
02359a2630 Fix build 2025-03-09 22:53:11 +07:00
Draken
158f6f4232 [Dragon Translation] Fix build 2025-03-09 21:52:14 +07:00
Draken
77de194b83 [Dragon Translation] Small changes 2025-03-09 17:16:29 +07:00
Draken
85cd13c8b2 Merge pull request #1549 - dragonx943/fixes
[MeHentaiVN] Fix "403 Access Denied" errors
2025-03-09 16:33:34 +07:00
Draken
bfbd01b1c2 [MeHentaiVN] Fixes 2025-03-09 16:30:13 +07:00
e83636edc0 [NhentaiWorld] Fixes 2025-03-09 10:20:39 +02:00
63dc67b6fd [NhentaiWorld] Draft 2025-03-09 09:55:19 +02:00
b0de4c3b66 [ComicK] Improvements 2025-03-09 09:42:02 +02:00
Draken
d5a4cf68c6 [NewTruyen] Fix dateText + parse function 2025-03-07 00:03:43 +07:00
Draken
288d6e0b8f Merge pull request #1543 - dragonx943/fixes
[NewTruyen] Small fixes
2025-03-05 23:37:47 +07:00
Draken
aa98db9ac6 [NewTruyen] Fixes 2025-03-05 16:34:06 +00:00
Draken
c19e1fd5e5 [Manganato] Update domain 2025-03-05 21:33:13 +07:00
Draken
ef10e3cafc [MangaNelo.com] Update domain 2025-03-05 21:31:12 +07:00
Draken
400c423dde [Mangakakalot.gg] Update domain 2025-03-05 21:30:03 +07:00
Draken
85ba4fa0de [Mangakakalot.gg] Update domain 2025-03-05 21:23:11 +07:00
Draken
8cb913d538 [TruyenHentai18] Update domain 2025-03-04 19:47:45 +07:00
Draken
2128bbe1b6 [TruyenHentai18] Fixes 2025-03-04 19:25:01 +07:00
Draken
4df07a50fb Merge pull request #1538 - dragonx943/sources/truyenhentai18
[TruyenHentai18] Add source
2025-03-04 18:05:00 +07:00
Draken
8fa63bca64 [TruyenHentai18] Add source 2025-03-04 10:58:49 +00:00
Draken
e191e0c9c1 Merge pull request #1529 - dragonx943/fixes
[Madara] Fixes + Update sources domain [vi]
2025-03-03 23:49:04 +07:00
Draken
5970509886 [site/vi] Update sources domain 2025-03-03 16:41:50 +00:00
Draken
b2c7d1028c [Madara] Fixes 2025-03-03 16:29:58 +00:00
Draken
377606d1aa [CBHentai + HentaiZ] Fixes 2025-03-03 16:21:13 +00:00
Draken
688bfdaa82 Merge pull request #1528 - dragonx943/sources/mangapill
[MangaPill] Add source
2025-03-03 22:36:03 +07:00
Draken
bc60629e66 [MangaPill] Add source 2025-03-03 22:29:58 +07:00
Draken
f3372751d1 [MangaPill] Add source 2025-03-03 22:29:35 +07:00
Draken
77a5216ebf Merge pull request #1524 - shub39/mangakakalot_fix
[Mangakakalot.com] -> [Mangakakalot.gg] Fixes
2025-03-03 20:26:30 +07:00
shub39
7ced91beea 🔧 no description 2025-03-03 12:24:34 +05:30
shub39
41f5cee6c6 ⚡ New way to get tags 2025-03-03 11:02:26 +05:30
shub39
ba5086c409 🔨 Mangakakalot fix
* issue #1522
* passing 5 out of 11 tests
2025-03-03 09:21:55 +05:30
531145c7f9 Change chapter name to title 2025-03-02 18:15:06 +02:00
f26fecb714 Small fixes 2025-03-02 18:15:06 +02:00
Draken
dd7568659f Fix warn 2025-03-02 19:34:23 +07:00
843d1f1bea Fixes 2025-03-01 16:38:25 +02:00
29263ff59b Add missing changes from #1496 2025-03-01 16:27:56 +02:00
3b91a3883e [Grouple] Fixes 2025-03-01 16:12:19 +02:00
ddb9b13df7 Some refactor and fix warnings 2025-02-28 14:50:36 +02:00
ed578e5bff Migrate altTitle to Set<String> 2025-02-27 19:08:38 +02:00
cdbb004ca1 Merge branch 'feature/search_query' 2025-02-27 17:46:14 +02:00
palaks-1
f6145bc412 Remove deprecated Manga constructor and introduce authors field 2025-02-27 17:17:53 +02:00
Draken
86e7c21e4d Merge pull request #1514 - VietAnh14/source/buondua
[BuonDua] Some fixes
2025-02-27 00:15:13 +07:00
ViAnh
76638c6aab [BuonDua] Some fixes 2025-02-26 23:40:09 +07:00
Draken
3a950f401b [BuonDua] Update domain 2025-02-26 22:45:12 +07:00
Draken
eeba47ea03 Merge pull request #1513 - VietAnh14/source/buondua
[BuonDua] New source
2025-02-26 22:41:47 +07:00
ViAnh
762f5cbec2 [BuonDua] New source 2025-02-26 22:35:41 +07:00
Draken
5b6c9be6d6 [CBHentai] Small fixes 2025-02-26 22:16:49 +07:00
f681ed270b Update parsers structure 2025-02-26 16:31:20 +02:00
a0168a7d49 Improvements 2025-02-26 15:25:26 +02:00
Draken
47263e641e Update Mangaoku.kt 2025-02-26 19:00:45 +07:00
Draken
70c78f1cab Update MangaKazani.kt 2025-02-26 19:00:45 +07:00
Draken
e7cb83f7b1 Update MangaSiginagi.kt 2025-02-26 19:00:45 +07:00
Draken
0212e1e18f Update PrunusScans.kt 2025-02-26 19:00:45 +07:00
Draken
265c411df2 Update RobinManga.kt 2025-02-26 19:00:45 +07:00
Draken
69a14b6fc5 Update YaoiTr.kt 2025-02-26 19:00:45 +07:00
Draken
168446e6d5 Update YaoiTr.kt 2025-02-26 19:00:45 +07:00
Draken
23af28f4dd Update NabiScans.kt 2025-02-26 19:00:45 +07:00
Draken
ac80384ba1 Update Mangaoku.kt 2025-02-26 19:00:45 +07:00
Draken
c4be0b58ca Update ImparatorManga.kt 2025-02-26 19:00:45 +07:00
Draken
023d13e44b Update EpikMan.kt 2025-02-26 19:00:45 +07:00
bai
f4909ade09 readded 2025-02-26 19:00:45 +07:00
bai
26fb2b9dcb new domain 2025-02-26 19:00:45 +07:00
bai
44c2ebd4a5 closed 2025-02-26 19:00:45 +07:00
bai
47874032a3 new domain 2025-02-26 19:00:45 +07:00
bai
6dfa5ad1c2 vlosed 2025-02-26 19:00:45 +07:00
bai
111ad58b57 closed 2025-02-26 19:00:45 +07:00
bai
f1086c93f7 change 2025-02-26 19:00:45 +07:00
bai
5e27a59414 change domain 2025-02-26 19:00:45 +07:00
bai
cece556669 change domain 2025-02-26 19:00:45 +07:00
bai
9252da8004 closed 2025-02-26 19:00:45 +07:00
bai
a9fdfee7ad mangagezgini new domain 2025-02-26 19:00:45 +07:00
bai
6904aecea3 they are closed 2025-02-26 19:00:45 +07:00
bai
b516632731 milasub new domain 2025-02-26 19:00:45 +07:00
bai
87ad5d0c3a nabiscans closed 2025-02-26 19:00:45 +07:00
bai
b95bb46d00 nyx mange closed 2025-02-26 19:00:45 +07:00
bai
60c91f9cc4 prunuscans closed 2025-02-26 19:00:45 +07:00
bai
20ce9cb8d9 robinmanga closed 2025-02-26 19:00:45 +07:00
bai
a2625410f9 rüyamange new domain 2025-02-26 19:00:45 +07:00
bai
e2697012ea viyafansub is closed 2025-02-26 19:00:45 +07:00
bai
f28cd3aad9 webtoonhatti new domain 2025-02-26 19:00:45 +07:00
bai
fd82a54d63 change to new domain 2025-02-26 19:00:45 +07:00
bai
d95d26a280 change site name 2025-02-26 19:00:45 +07:00
bai
33310bdc42 yaoi tr closed 2025-02-26 19:00:45 +07:00
bai
6281d770c1 zamanmanga is closed 2025-02-26 19:00:45 +07:00
Batu
c37f3bdad7 Delete src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/tr/AlliedFansub.kt
allied fansub is closed
2025-02-26 19:00:45 +07:00
Draken
5630ca5982 Merge pull request #1507 - dragonx943/sources/pzt
[PointZero Toons] Add source
2025-02-26 00:03:07 +07:00
Draken
ceb75d98d0 [PointZero Toons] Add source
[PointZero Toons] Add source
2025-02-26 00:00:24 +07:00
Draken
75ad3b5657 [PointZero Toons] Add source
[PointZero Toons] Add source
2025-02-26 00:00:05 +07:00
Draken
5adf27eab1 Update SssScanlator.kt 2025-02-25 23:58:04 +07:00
Draken
18fbbed723 Merge pull request #1501 - palaks-1/source/nhentai_xxx_fix
[NHentai.xxx] Fix source
2025-02-25 09:40:30 +07:00
Draken
201bbf755d Merge pull request #1502 - AwkwardPeak7/weeb2
weebcentral: fix manga list & link resolving
2025-02-25 09:39:45 +07:00
AwkwardPeak7
b9fe35b8c3 weebcentral: fix manga list & link resolving 2025-02-25 07:10:02 +05:00
palaks-1
fd0787152e [NHentai.xxx] Fix source 2025-02-25 01:40:26 +02:00
29cf04c804 MangaParser interface 2025-02-24 17:59:40 +02:00
a4827d1b7d Merge branch 'palaks-1-new-search-query-proposal' into feature/search_query 2025-02-24 17:18:11 +02:00
f107e11528 Refactoring 2025-02-24 17:14:27 +02:00
Draken
52b6f75dd0 Merge pull request #1495 - dragonx943/sources/HentaiZ
[HentaiZ] Add source
2025-02-24 19:27:30 +07:00
Draken
fd719221ed [HentaiZ] Add source 2025-02-24 19:24:30 +07:00
Draken
a2c04fa954 [HentaiZ] Add source 2025-02-24 19:23:59 +07:00
Draken
6db5ac5f26 [HentaiVn.buzz] Small fixes 2025-02-24 19:07:01 +07:00
Draken
cedce23cf5 Merge pull request #1494 - sources/domain
- [TruyenQQ] Refactor
- [TruyenGG] Refactor
- Update some sources domain [site/vi]
2025-02-24 18:30:06 +07:00
Draken
645816f614 [site/vi] Update sources domain 2025-02-24 11:25:35 +00:00
Draken
00a769bfd5 Merge pull request #1492 - dragonx943/sources/HentaiVn
[HentaiVn.buzz] Add source
2025-02-24 17:45:49 +07:00
Draken
0fe5133992 Merge pull request #1493 - dragonx943/sources/SssScanlator
[sources/SssScanlator] Small fixes
2025-02-24 17:45:17 +07:00
Draken
2994f5936e Merge pull request #1491 - dragonx943/sources/cbhentai
[CBHentai] Fix tags
2025-02-24 17:42:47 +07:00
Draken
e8a96fa0ad [SssScanlator] Small fixes
Fix chapters > numChap [SssScanlator]
2025-02-24 17:30:38 +07:00
Draken
8c8cf5dcd9 [SssScanlator] Fix attempt 1 2025-02-24 10:11:20 +00:00
Draken
19ff5db70d [HentaiVn.buzz] Add source 2025-02-24 16:40:38 +07:00
Draken
c7b689842e [HentaiVn.buzz] Add source 2025-02-24 16:39:26 +07:00
Draken
df03c65d5a [CBHentai] Small fixes 2025-02-24 15:44:08 +07:00
Draken
4a88a93e8d [CBHentai] Fix tags
Fix "Root not found" / "Content not found or removed" error [CBHentai]
2025-02-24 13:29:34 +07:00
Draken
950b9e5510 [Vcomycs] Update source domain
Solved #1489
2025-02-24 00:10:25 +07:00
Draken
70230de8e1 [vi/KuroNeko] Fix source name
.../site/vi/viHentai.kt -> KuroNeko.kt [Việt Hentai]
2025-02-21 16:14:39 +07:00
palaks-1
c0ea9cadd7 New MangaSearchQuery implementation proposal 2025-02-19 00:19:21 +02:00
Draken
8c966c3e23 Merge pull request #1478 - VietAnh14/fixes
[Cmanga] Fixes
2025-02-19 00:56:52 +07:00
ViAnh
9f87e77ede [Cmanga] Fixes 2025-02-19 00:04:50 +07:00
ViAnh
6165c9b7cf [Cmanga] Update api 2025-02-19 00:02:18 +07:00
88ea5215c0 [MangaDex] Search by author 2025-02-18 18:12:13 +02:00
522b3d53cc Artist filter support 2025-02-18 17:48:20 +02:00
Draken
9a1d37166a [CManga] Small fixes
[CManga] Fix "Nothing found" bug #1477
2025-02-18 13:04:23 +07:00
Draken
07ae87f72b [Kiryuu] Update domain
[Kiryuu] Fix looping captcha
2025-02-17 21:40:33 +07:00
Draken
a16a202800 Merge PR #1475 - dragonx943/sources/viHentai
[viHentai] Add source
2025-02-17 19:42:40 +07:00
Draken
09ff9c0a7d [viHentai] Fix attempt 2 2025-02-17 12:16:47 +00:00
Draken
8c4a93d1dc [viHentai] Fix attempt 1 2025-02-17 11:57:03 +00:00
Draken
2da8a4af84 [viHentai] Add source 2025-02-17 11:19:23 +00:00
Draken
7d5f0d3187 Merge pull request #1464 - scryptan/wamanga-fix
[WaManga] Fixes
2025-02-16 11:28:10 +07:00
Draken
a65c1810a2 Merge pull request #1465 - palaks-1/sources/nhentai_xxx
[NHentai.xxx] Fix source
2025-02-16 11:25:18 +07:00
palaks-1
09b7d27b40 [NHentai.xxx] Fix source 2025-02-16 04:16:01 +02:00
scryptan
e1175d01cc use api, instead of html parse 2025-02-16 06:41:45 +05:00
Draken
51fe77ff33 Merge pull request #1461 - dragonx943/site/vi/newtruyen
[NewTruyen] Add source + Update sources domain [vi]
2025-02-16 01:18:19 +07:00
Draken
c540266e48 [NewTruyen] Add source 2025-02-15 18:10:45 +00:00
Draken
198e859850 [HamTruyen] Small fixes
[HamTruyen] Fix chapters order + Number
2025-02-14 22:42:01 +07:00
Draken
87944719a5 Merge pull request #1457 - palaks-1/sources/nhentai_xxx
[NHentai.xxx] Add source
2025-02-13 23:42:22 +07:00
palaks-1
6b44656819 [NHentai.xxx] Add source 2025-02-13 17:50:10 +02:00
Draken
35334e82ae Merge pull request #1456 - palaks-1/sources/nhentai_to
[NHentai.to] Add source
2025-02-13 19:55:28 +07:00
palaks-1
32e7b7184f [NHentai.to] Add source 2025-02-13 14:50:08 +02:00
Draken
4098183be7 Merge pull request #1453 - dragonx943/sources/muitohentai
[MuitoHentai] Fix "Content not found or removed" errors
2025-02-13 01:14:52 +07:00
Draken
e25b03b68f [MuitoHentai] Fix attempt 3 2025-02-12 17:49:27 +00:00
Draken
7076b2d443 [MuitoHentai] Fix attempt 2 2025-02-12 17:26:45 +00:00
Draken
1933200372 [MuitoHentai] Fixes 2025-02-12 17:04:45 +00:00
Draken
0359afe574 Merge pull request #1452 - dragonx943/sources/hamtruyen
[HamTruyen] Add source
2025-02-12 13:19:52 +07:00
Draken
cd8282bbe0 [HamTruyen] Add source 2025-02-12 06:14:06 +00:00
Draken
8350b3c70e Merge branch 'sources/hamtruyen' of https://github.com/dragonx943/Kotatsu-parsers into sources/hamtruyen 2025-02-12 05:57:12 +00:00
Draken
8488d80c6f Merge branch 'KotatsuApp:master' into sources/hamtruyen 2025-02-12 12:56:52 +07:00
Draken
affd4646af Merge pull request #1451 - dragonx943/fixes
[Hentai18VN, TruyenHentaiVN] Refactor + Fixes
2025-02-12 12:54:10 +07:00
Draken
9853638c6b [Hentai18VN] Refactor 2025-02-12 05:49:08 +00:00
Draken
faf2f2a312 [HentaiVN18] Refactor + Fixes 2025-02-12 05:24:22 +00:00
Draken
4adf485208 Merge branch 'fixes' of https://github.com/dragonx943/Kotatsu-parsers into fixes 2025-02-12 04:24:38 +00:00
Draken
eaab76aa9e [HamTruyen] Add source 2025-02-11 18:38:42 +00:00
Draken
2ca740a85d Merge pull request #1450 - dragonx943/sources/hentai18vn
[Hentai18VN] Add source
2025-02-12 01:10:18 +07:00
Draken
569aa73cd4 [Hentai18VN] Fix attempt 3 2025-02-11 18:00:14 +00:00
Draken
d3858ff5ff [Hentai18VN] Fix attempt 2 2025-02-11 17:41:18 +00:00
Draken
2760dc8a76 [Hentai18VN] Fix attempt 1 2025-02-11 17:23:30 +00:00
Draken
c1990dde75 Merge branch 'sources/hentai18vn' of https://github.com/dragonx943/Kotatsu-parsers into sources/hentai18vn 2025-02-11 16:50:41 +00:00
Draken
af5b62b8fd Merge branch 'KotatsuApp:master' into sources/hentai18vn 2025-02-11 23:09:13 +07:00
Draken
fcd6e92dba [Hentai18VN] Add source 2025-02-11 16:08:46 +00:00
Draken
dad098ff34 Merge pull request #1449 from dragonx943/fixes
[TruyenHentaiVN] Fix tags
2025-02-11 20:57:27 +07:00
Draken
aa9a499a09 [TruyenHentaiVN] Fix tags 2025-02-11 13:30:27 +00:00
Draken
f10e6f021c Add base code for Hentai18VN 2025-02-11 13:25:33 +00:00
Draken
09596331fd [TruyenHentaiVN] Fix tags 2025-02-11 20:21:47 +07:00
Draken
c8f9962def [TruyenHentaiVN] Fix tags 2025-02-11 20:16:39 +07:00
Draken
e91e8fcccb Merge branch 'sources/hentai18vn' of https://github.com/dragonx943/Kotatsu-parsers into sources/hentai18vn 2025-02-11 12:58:34 +00:00
Draken
a702f1f7ef Merge pull request #1439 from scryptan/wamanga-fix
[WaManga] Fix NoSuchMethodError
2025-02-11 19:20:18 +07:00
Draken
9654a68dad Merge pull request #1443 - VietAnh14/fixes
[CManga] Fixes
2025-02-10 21:13:48 +07:00
ViAnh
a2f18e2284 [Cmanga] Remove escape chars in description 2025-02-10 21:11:23 +07:00
ViAnh
fceb927bce [Cmanga] Small fixes 2025-02-10 20:44:29 +07:00
ViAnh
f192c1716d [Cmanga] Filter unknown manga item 2025-02-10 20:31:29 +07:00
Draken
f2960c2229 Merge pull request #1442 - dragonx943/sources/manhwaindo
[ManhwaIndo] Fix "Content not found or removed"
2025-02-10 15:29:20 +07:00
Draken
552a68c1d4 [ManhwaIndo] Fix attempt 1 2025-02-10 08:14:29 +00:00
Draken
e5f277c957 Merge pull request #1441 from AwkwardPeak7/weeb
WeebCentral: some fixes
2025-02-10 12:08:03 +07:00
AwkwardPeak7
ff05dd7694 [WeebCentral] fix chapter number not correct in some cases 2025-02-10 08:24:23 +05:00
AwkwardPeak7
7c604647bf [WeebCentral] fix tags not loading 2025-02-10 08:23:39 +05:00
Draken
0fd0c38971 Merge pull request #1440 - dragonx943/sources/truyenhentaivn
Add new source: TruyenHentaiVN
2025-02-10 03:26:12 +07:00
Draken
a454613ce8 [TruyenHentaiVN] Add source 2025-02-09 20:22:35 +00:00
Draken
73dd8c4688 [TruyenHentaiVN] Add source 2025-02-09 20:21:28 +00:00
scryptan
1a07cfc144 try fix not exist optJSONObject in kotatsu app 2025-02-09 19:41:27 +05:00
Draken
715fe9e645 [Weeb Central] Add source 2025-02-09 21:14:05 +07:00
Draken
6316ac055c Merge pull request #1438 from AwkwardPeak7/weeb
[Weeb Central] Add source
2025-02-09 21:13:22 +07:00
Draken
ff64db7a7c Merge pull request #1437 from VietAnh14/fixes
[NetTruyen] Fix fetch chapters
2025-02-09 21:11:37 +07:00
AwkwardPeak7
d5a299d7ff mark MangaSee and MangaLife as broken 2025-02-09 19:05:11 +05:00
AwkwardPeak7
0e3c3f89d0 add Weeb Central 2025-02-09 19:04:54 +05:00
ViAnh
234e23b7a5 [NetTruyenVie] Fix fetch chapters 2025-02-09 20:47:33 +07:00
ViAnh
69093b8214 [NetTruyen] Fix fetch chapters 2025-02-09 20:18:09 +07:00
Draken
708d7908aa [GocTruyenTranh] Fixes
Add NSFW detector by Tags [site/vi/GocTruyenTranh]
2025-02-09 19:30:44 +07:00
Draken
b08051789d [GocTruyenTranh] Fixes
Fix author + "null" in altTitle [GocTruyenTranh]
2025-02-09 16:22:59 +07:00
Draken
794a737b6d Merge pull request #1435 - dragonx943/vi/goctruyentranh
Add new source: GocTruyenTranh
2025-02-09 04:04:41 +07:00
Draken
b1ef29fadf [GocTruyenTranh] Add source 2025-02-08 20:58:10 +00:00
Draken
0475fc81ed [GocTruyenTranh] Add source 2025-02-08 20:57:04 +00:00
6aefb603ae [NetTruyen] Fix chapters order 2025-02-08 16:40:46 +02:00
Draken
92bdefcf9d Merge pull request #1432 - dragonx943/sources/wpcomics
[site/wpcomics/vi] Fixes
2025-02-07 19:58:27 +07:00
Draken
576de54ef8 [wpcomics/vi/nettruyen*] Fix fetch invaild format 2025-02-07 12:15:09 +00:00
Draken
319225d645 [wpcomics/vi/nettruyen*] Fixes 2025-02-07 04:53:33 +00:00
Draken
9addea65d6 [wpcomics/vi/nettruyen*] Fixes 2025-02-07 04:51:41 +00:00
Draken
95c43a06d5 [wpcomics/vi/nettruyen*] Fixes 2025-02-07 04:23:38 +00:00
Draken
72c7317672 Merge pull request #1429 - dragonx943:sources/nsfw
Mark some sites as NSFW sources
2025-02-05 22:38:22 +07:00
Draken
1cec3e5436 Mark some sites as NSFW sources 2025-02-05 15:31:47 +00:00
Draken
6c18056cef [NetTruyenVie] Fix attempt 1 2025-02-04 02:19:35 +07:00
Draken
f4b678083d Merge pull request #1422 from VietAnh14/source/vivicomi
[Vcomycs] New source
2025-02-03 16:11:36 +07:00
ViAnh
50eb6f7b7e [Vcomycs] Update content type 2025-02-03 15:59:46 +07:00
ViAnh
0b6af2549f [Vcomycs] New source 2025-02-03 15:53:47 +07:00
Draken
f229d95469 Merge pull request #1421 - dragonx943:site/domain
Update some sources domain
2025-02-02 23:59:18 +07:00
hoanphonglinh
7ba725de6d [vi] Update sources domain 2025-02-02 16:52:24 +00:00
Draken
677fd51e91 Update ManhuaScan.kt 2025-02-02 15:32:09 +07:00
45b843fadc Replace try-catch with use{} in parse functions 2025-02-02 10:14:48 +02:00
9ec62f0be0 Refactor 2025-02-02 10:07:31 +02:00
Draken
9baba17692 Merge pull request #1413 from dragonx943/sources/manhwaindo
[Manhwaindo] Fix missing images
2025-01-31 23:54:07 +07:00
hoanphonglinh
d86d0a5d5b [Manhwaindo] Fix attempt 2 2025-01-31 16:27:41 +00:00
hoanphonglinh
543e8e3267 [Manhwaindo] Fix attempt 1 2025-01-31 16:06:56 +00:00
Draken
267dcf8fa7 [TruyenTranh3Q] Fixes 2025-01-30 23:09:10 +07:00
Draken
fec4594480 Merge pull request #1410 from dragonx943:site/vi/final
[TruyenTranh3Q] Add source
2025-01-30 22:55:50 +07:00
hoanphonglinh
f669df2ff5 [TruyenTranh3Q] Add source 2025-01-30 15:47:40 +00:00
hoanphonglinh
9dfa652125 [TruyenTranh3Q] Add source 2025-01-30 15:47:04 +00:00
Draken
87f1cd8cdc Update Komiku.kt 2025-01-29 22:29:15 +07:00
Draken
f30f8ee563 Merge pull request #1408 from dragonx943:site/vi/yurineko
[YuriNeko] Fix 403 errors + Missing images
2025-01-29 18:15:15 +07:00
Draken
64eceba9fa [YuriNeko] Fix domain 2025-01-29 18:09:00 +07:00
Draken
58e09bdaba Merge pull request #1397 from sources/nettruyenvie
[NetTruyenVie] Add source
2025-01-24 22:08:51 +07:00
Koitharu
d4e9040ccf Fixes 2025-01-24 14:17:47 +00:00
Koitharu
653894cb82 First commit from local/Kotatsu-parsers 2025-01-24 14:08:57 +00:00
Draken
581cb0c1fe First commit from local/Kotatsu-parsers 2025-01-24 14:07:27 +00:00
4e545ca7af [WaManga] Refactor #1390 2025-01-23 20:54:26 +02:00
scryptan
b4050e0335 refactor 2025-01-23 20:44:12 +02:00
scryptan
1cecd1fe94 add wamanga parser 2025-01-23 20:44:12 +02:00
51ed1b2db8 Update json utils 2025-01-22 09:34:27 +02:00
Draken
3e4d712dca Merge pull request #1385 from dragonx943/sources/domain
Update sources domain
2025-01-19 21:37:12 +07:00
Draken
d284b647ab Merge branch 'KotatsuApp:master' into sources/domain 2025-01-19 21:29:13 +07:00
Draken
3bcd05fc5f Update sources domain 2025-01-19 14:27:03 +00:00
b0a1cc48a6 Update utils 2025-01-19 11:07:48 +02:00
Draken
2eba38b289 Update domains 2025-01-18 03:24:03 +00:00
8481fadbd0 Fix absolute url resolving 2025-01-16 08:51:55 +02:00
6abcdd8d4b Fix nullable strings usage 2025-01-12 19:16:46 +02:00
5df1445e29 Migrate models to data class and update Manga class 2025-01-12 18:16:30 +02:00
Draken
a94adf4d90 [CuuTruyen] Fixes
Fix timer + Add manga status for CuuTruyen
2025-01-03 17:49:38 +07:00
dragonx943
f21aa282dd [CuuTruyen] Fix attempt 1 2025-01-03 08:44:13 +00:00
Draken
8ce6694232 Merge pull request #1336 from dragonx943/sources/vi
[sources/vi] Fix sources domain
2024-12-31 20:47:16 +07:00
Draken
d8bd51e17e [site/vi] Change sources domain 2024-12-31 13:40:01 +00:00
Draken
b1b04d2953 Merge pull request #1331 from dragonx943/final
Update domain + Fixes
2024-12-28 16:01:49 +07:00
dragonx943
8852020ca8 [MeHentaiVN] Add source 2024-12-28 08:55:16 +00:00
Draken
deb4f763d0 Merge pull request #2 from dragonx943/test
[NetTruyen] Fixes
2024-12-28 11:13:21 +07:00
dragonx943
58593de53d [NetTruyen] Fix attempt 2 2024-12-28 03:44:29 +00:00
dragonx943
040be87a54 [NetTruyen] Fix attempt 1 2024-12-28 02:27:22 +00:00
Draken
1703ac39d5 Rename + Change domain sources from dragonx943/test
Rename + Change domain sources
2024-12-27 18:16:53 +07:00
dragonx943
839869061e Rename some sources 2024-12-27 11:14:33 +00:00
764c65563b [Grouple] Fixes 2024-12-23 11:02:41 +02:00
2550b9cac1 [KomikTap] Fix http pages 2024-12-19 17:00:16 +02:00
04225170d3 [Grouple] Fix pages parsing 2024-12-19 16:57:19 +02:00
326a3f78b2 Fix Response.mimeType extension 2024-12-19 14:58:40 +02:00
f86d31f811 Update utils 2024-12-18 14:00:43 +02:00
vianh
10dac6c0d4 [CManga] New source 2024-12-15 10:07:46 +02:00
devi
fece09b781 Merge remote-tracking branch 'origin/master' 2024-12-13 23:57:51 +01:00
devi
6b1fb90584 Update source
[AnimeH] Broken source close #1301
 [SussyScan] fix close #1298
 close #1287
 close #1282
 close #1273
 close #1267
 close #1268
 close #1260
 close #1234
 [Manhwa18] fix src close #1297
 close #1290
 close #1288
[KomikCast] close #1284
close #1283
close #1272
close #1270
close #1265
[Birdtoon] close #1276
[Komiktap] close #1275
[SadScans] close #1274
[Flamecomics] reverse chapter fix close #1266
[Kiryuu] fix url close #1258
[MangaTime] Broken close #1228
[Dexhentai] fix close #1226
2024-12-13 23:57:09 +01:00
5055cfddbd Merge pull request #1294 from dragonx943/patch-1 2024-12-10 18:19:38 +02:00
Draken
878d20e612 [ComicExtra] Remake #1 2024-12-10 23:02:36 +07:00
336f64712d Merge pull request #1292 from dragonx943/patch-1 2024-12-09 17:08:40 +02:00
Draken
56989c6b2f Update Fecomicc.kt 2024-12-09 20:59:27 +07:00
Draken
7b1d3dcd46 Fixes 2024-12-09 20:32:12 +07:00
f1e66daf06 Merge pull request #1291 from dragonx943/test 2024-12-09 12:35:00 +02:00
dragonx943
ca087290b9 [YuriNeko] Fix attempt 1 2024-12-09 09:49:31 +00:00
883886bc32 Merge pull request #1281 from dragonx943/test 2024-12-05 19:12:18 +02:00
Draken
9e60253eb1 Merge branch 'KotatsuApp:master' into test 2024-12-05 23:53:54 +07:00
dragonx943
dba85f2bff Fixes 2024-12-05 16:52:14 +00:00
e5b852793e Merge pull request #1280 from dragonx943/test 2024-12-05 18:43:38 +02:00
Draken
d4cbd86b96 Update summary.yaml 2024-12-05 23:37:23 +07:00
Draken
8d82bacaa3 Merge branch 'KotatsuApp:master' into test 2024-12-05 23:35:33 +07:00
dragonx943
4af760c172 Fixes 2024-12-05 16:35:02 +00:00
dragonx943
7747bc53b1 Update domain + Refactor 2024-12-05 16:29:22 +00:00
0456a92f15 [WpComics] Fix covers 2024-12-05 18:23:03 +02:00
Draken
677afa9a41 Update TopTruyen.kt (#1279) 2024-12-05 17:00:40 +02:00
ebcce4f2ec [DocTruyen3Q] Fix covers 2024-12-05 15:34:39 +02:00
91e53e4872 [AsuraScans] Fix pages parsing 2024-11-27 11:56:42 +02:00
8bc51b3b79 [FlameComics] Rewrite #1237 2024-11-23 15:02:27 +02:00
733d3ca69f [ResetScans] Migrate to the new website (close #1252) 2024-11-23 15:01:51 +02:00
4a2e465e5d [NineManga] Fixes #1253 2024-11-23 15:01:51 +02:00
Draken
7ed3c5a175 Update sources domain (#1254)
* Update Mangarbic.kt

* Update BlogTruyenParser.kt

* Update CuuTruyenParser.kt

* Update HentaiVNParser.kt

* Update LxManga.kt

* Update DocTruyen3Q.kt

* Update NetTruyenHE.kt

* Update NetTruyenLL.kt

* Update NetTruyenSSR.kt

* Update NetTruyenUU.kt

* Update NhatTruyenVN.kt

* Update TopTruyen.kt

* Update OtakusanVi.kt

* Update OtakusanEn.kt

* Update HentaiVnPlus.kt

* Update TruyenTranhDamMyy.kt

* Update TruyenVn.kt

* Update DocTruyen5s.kt
2024-11-23 13:59:25 +02:00
bivaly
8567cedf0a Updating FlameComics ListUrl (#1255)
* Update FlameComics.kt

* Update FlameComics.kt

* Update FlameComics's listUrl

Ther are no longer a listUrl but maybe they are  going to revert the changes so leaving there the overide for easy changing

* removing FlameComics ListUrl

Ther are no longer a listUrl but maybe they are  going to revert the changes so leaving there the overide for easy changing
2024-11-23 13:58:48 +02:00
e02b563bf4 [AsuraComic] Fix pages parsing 2024-11-21 09:15:12 +02:00
Draken
27d2814ef9 [LectorManga] Update domain (#1233)
* Update LectorManga.kt

* Update LikeManga.kt
2024-11-21 07:57:13 +02:00
Draken
de95fa2e3e Update domain + Add sources (#1221)
* Update HariManga.kt

* Update Mgkomik.kt

* Update XoxoComics.kt

* Create DuaLeoTruyen.kt

* Create MyComicList.kt

* Update DuaLeoTruyen.kt

* Update summary.yaml

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Add suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Fixes

---------

Co-authored-by: Koitharu <nvasya95@gmail.com>
2024-11-16 20:31:18 +02:00
5a4f9d8914 [MangaFire] Fix search 2024-11-16 16:42:31 +02:00
23271c4623 [LibSocial] Use site domains 2024-11-16 10:25:23 +02:00
f3d14e101c [MintManga] Update domain 2024-11-10 14:02:34 +02:00
275d7f5419 [ImHentai] Fix pages parsing 2024-11-10 12:52:48 +02:00
ac163085e1 [ImHentai] Fix pages parsing 2024-11-10 12:07:58 +02:00
Draken
8b4bac3cc2 [TruyenGG] Refactor (#1215)
* Update TruyenGG.kt

* Update TruyenGG.kt
2024-11-09 20:19:10 +02:00
35f4db7905 Rollback kotlin to fix build 2024-11-09 20:12:05 +02:00
08b1241a68 Remove redundant trim and mapNotNullToSet usage 2024-11-09 19:43:23 +02:00
3ffcefaa1b Get rid of redundant boxing 2024-11-09 19:11:41 +02:00
3b173dc6fc Improve utils 2024-11-09 19:04:22 +02:00
Draken
60f1fb1f70 Update + Add source (#1213)
* Update YurinekoParser.kt

* Create TruyenGG.kt

* Update and rename Truyenqq.kt to TruyenQQ.kt

* Update TruyenGG.kt

* Update summary.yaml

* Update suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Update suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Update suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Update suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Update suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Update suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Fix tags

---------

Co-authored-by: Koitharu <nvasya95@gmail.com>
2024-11-09 11:53:26 +02:00
devi
f610ae6412 [ManhwaLatino] fix the order of the chapters and some manga don't display all the chapters.
close #1211
2024-11-05 20:19:30 +01:00
f80b586081 [Iken] Fixes 2024-11-04 10:45:55 +02:00
7999064dd4 [MangaFire] Fix search (close #1196) 2024-11-04 10:41:54 +02:00
8c387e7983 [Desu] Cleanup 2024-11-04 10:33:48 +02:00
1d29cacf04 [LxManga] Refactor 2024-11-04 10:27:22 +02:00
Draken
ce4b4d06d0 Update domain + Fixes (#1206)
* Update MaidScan.kt

* Update NetTruyenLL.kt

* Update Quaanhdaocuteo.kt

* Fixes
2024-11-04 10:09:24 +02:00
79e1d59482 Fixes 2024-11-01 12:44:09 +02:00
devi
47e1c0fa89 Minor changes 2024-10-31 21:45:09 +01:00
devi
3ec23a56ab Minor changes 2024-10-31 21:44:27 +01:00
devi
a01493e071 [EpsilonScan] fix close #1038
[Keyoapp] fix pages close #1192
[Yaoiflix] Fix close #1201
[Teamxnovel] fix Searching close #1176
close #1185
[ManhwaLatino] close #1181
[MiHentai] fix close #1180
[GenzToon] close #1169
[MangaGalaxy] close #1168 ( redirect to VortexScans )
[CatharsisFantasy] close #1158
[CatharsisWorld] close #1157
Update soures
2024-10-31 21:41:11 +01:00
Draken
16052210c1 [NhatTruyenVN] Fixes (#1199)
* Update NhatTruyenVN.kt

* Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NhatTruyenVN.kt

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Update suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

* Update suggestions

Co-authored-by: Koitharu <nvasya95@gmail.com>

---------

Co-authored-by: Koitharu <nvasya95@gmail.com>
2024-10-31 13:34:56 +02:00
7dd9658864 [Ahen] Fix chapters parsing 2024-10-30 14:02:13 +02:00
f794f411b7 [DesuMe] Fix covers 2024-10-29 12:44:23 +02:00
Draken
94fbbad6f3 [DocTruyen3Q + TopTruyen] Fixes (#1187)
* Update DocTruyen3Q.kt

* Update CuuTruyenParser.kt

* Update NetTruyen.kt

* Update DocTruyen3Q.kt

* TopTruyen sus :p

* Update TopTruyen.kt

* Remove unavailable tags

* Update TopTruyen.kt

* Remove redundant trim() calls

* Update DocTruyen3Q.kt

* Update TopTruyen.kt

* Remove some unavailable tags

* Update TopTruyen.kt

* Update DocTruyen3Q.kt

* Update TopTruyen.kt

---------

Co-authored-by: Koitharu <nvasya95@gmail.com>
2024-10-27 12:03:23 +02:00
4c5ed57958 Fix json iterator 2024-10-26 08:34:49 +03:00
Draken
3d5cc5ceff Update TruyenVn.kt 2024-10-21 10:04:13 +03:00
Draken
c506153737 Update OtakusanEn.kt 2024-10-21 10:04:13 +03:00
Draken
95ee8a4a16 Update OtakusanVi.kt 2024-10-21 10:04:13 +03:00
Draken
3f7b0695f4 Update LxManga.kt 2024-10-21 10:04:13 +03:00
Draken
b3bb0939de Update HentaiVnPlus.kt 2024-10-21 10:04:13 +03:00
08fe54c36d Refactor json utilities 2024-10-18 08:58:16 +03:00
166c5be5d6 Refactoring 2024-10-17 18:24:11 +03:00
7ce2a97c1f [DocTruyen5s] Refactoring 2024-10-17 17:42:17 +03:00
Draken
b23e241973 Update DocTruyen5s.kt 2024-10-17 17:12:39 +03:00
Draken
b8b54b7139 Update DocTruyen5s.kt 2024-10-17 17:12:39 +03:00
Draken
5853e54684 Update SayHentai.kt 2024-10-17 17:12:39 +03:00
Draken
32e3b07e5d Update HentaiCube.kt 2024-10-17 17:12:39 +03:00
Draken
3b99676e7a Update HentaiCube.kt 2024-10-17 17:12:39 +03:00
Draken
3c829302c7 Update TopTruyenViet.kt 2024-10-17 17:12:39 +03:00
Draken
b579b01db5 Update DocTruyen3Q.kt 2024-10-17 17:12:39 +03:00
Draken
7db798c420 Update CuuTruyenParser.kt 2024-10-17 17:12:39 +03:00
Draken
77ed11b58e Update summary.yaml 2024-10-17 17:12:39 +03:00
Draken
3ae6ffb8d0 Tweak :p 2024-10-17 17:12:39 +03:00
Draken
0e5e4d57c5 Create SayHentai.kt 2024-10-17 17:12:39 +03:00
d8cb38a9be Improve links resolving 2024-10-16 12:36:31 +03:00
07b0a2da9e Fix loading manga by link 2024-10-16 12:36:31 +03:00
1d040e8291 Link resolver implementation 2024-10-16 12:36:27 +03:00
davvarrr
797a91a037 Merge pull request #1167 from dragonx943/patch-1
Daily update
2024-10-14 21:39:32 +02:00
devi
9c0b57835f [WebtoonEmpire] fix close #1134 2024-10-14 21:38:25 +02:00
devi
72564f5449 [MadaraParser] auto fix url manga on
fix query ( withoutAjax
[MangaPark] fix close #1152
close #1145
[AdultWebtoon] fix close #1139
[ComicExtra] change type close #1130
[liliana] fix and add ManhuaPlusorg, Raw1001, MangaSect, MangaKoma01, ManhuaGold
2024-10-14 21:09:35 +02:00
Draken
cc18692538 Update ComickFunParser.kt 2024-10-15 00:10:19 +07:00
Draken
3e102e9d69 Update BlogTruyenParser.kt 2024-10-14 20:04:33 +03:00
Draken
b9b53bcc91 Add some tags 2024-10-14 20:04:33 +03:00
Draken
00ef8e5cdf Remove broken tag 2024-10-14 20:04:33 +03:00
Draken
a738591dd0 Update DocTruyen5s.kt 2024-10-14 20:04:33 +03:00
Draken
85771bcd89 Fix BlogTruyen 2024-10-14 20:04:33 +03:00
0150ede4cb [Liliana] Fix chapters order 2024-10-13 15:26:58 +03:00
Draken
1406165789 Update LxManga.kt 2024-10-13 15:11:40 +03:00
Draken
a62eadb581 Fix filters 2024-10-13 15:11:40 +03:00
Draken
197b148fca Update Hijala.kt 2024-10-11 09:51:18 +03:00
Draken
fd4a1cda2d Update HentaiCube.kt 2024-10-11 09:51:18 +03:00
Draken
108920c4fd Update DocTruyen5s.kt 2024-10-11 09:51:18 +03:00
Draken
49c7702707 Update LilianaParser.kt 2024-10-11 09:51:18 +03:00
Draken
15361654b7 Create LilianaParser.kt 2024-10-11 09:51:18 +03:00
Draken
c2b64d40d1 Create DocTruyen5s.kt 2024-10-11 09:51:18 +03:00
ce9404da84 [Madara] Fix multiple pages handling 2024-10-09 17:18:48 +03:00
5c55d65eb3 Refactor and fixes 2024-10-09 08:18:29 +03:00
Draken
6f9180545b Update and rename HentaiVnParser.kt to HentaiVnPlus.kt 2024-10-09 08:07:05 +03:00
Draken
e966aa07cd Create BlogTruyenParser.kt 2024-10-09 08:07:05 +03:00
Draken
102993cb10 Remove BlogTruyen - Closed site 2024-10-09 08:07:05 +03:00
Draken
d0627b83d0 Update BlogTruyenVN.kt 2024-10-09 08:07:05 +03:00
Draken
a6602a0f5a Update BlogTruyenVN.kt 2024-10-09 08:07:05 +03:00
Draken
55b9a72795 Create BlogTruyenVN.kt 2024-10-09 08:07:05 +03:00
Draken
d4f0c9d116 Update LxManga.kt 2024-10-09 08:07:05 +03:00
Draken
bbb3184454 Update CuuTruyenParser.kt 2024-10-09 08:07:05 +03:00
Draken
7d81e68757 Update CuuTruyenParser.kt 2024-10-09 08:07:05 +03:00
Draken
487388c950 Update DocTruyen3Q.kt 2024-10-09 08:07:05 +03:00
Draken
9d507eb10c Update TopTruyenViet.kt 2024-10-09 08:07:05 +03:00
Draken
cf9b19ffa7 This source will no longer work!
This site has been sold and it has changed name + source structure :p

Changed to: https://github.com/KotatsuApp/kotatsu-parsers/issues/1135
2024-10-09 08:07:05 +03:00
Draken
9591269a68 Update TopTruyenViet.kt 2024-10-09 08:07:05 +03:00
Draken
27fe426213 Update DocTruyen3Q.kt 2024-10-09 08:07:05 +03:00
Draken
b23d899f5e Update CuuTruyenParser.kt 2024-10-09 08:07:05 +03:00
Draken
8bf0c03fe2 Tags ? 2024-10-09 08:07:05 +03:00
Draken
1ebb298cd7 Update CuuTruyenParser.kt 2024-10-07 15:16:49 +03:00
Draken
9f588ab9fd Rename HentaiVn.kt to HentaiVnParser.kt 2024-10-07 15:16:49 +03:00
Draken
91a1198900 Update HentaiVn.kt 2024-10-07 15:16:49 +03:00
Draken
321ac087dc Update TruyenVn.kt 2024-10-07 15:16:49 +03:00
Draken
5d81c030b5 Rename HentaiVnFit.kt to HentaiVn.kt 2024-10-07 15:16:49 +03:00
Draken
e798bc7787 Update HentaiVnFit.kt 2024-10-07 15:16:49 +03:00
Draken
057b053d58 Update TopTruyenViet.kt 2024-10-07 15:16:49 +03:00
Draken
e9a9ef6b95 Update DocTruyen3Q.kt 2024-10-07 15:16:49 +03:00
Draken
bd7062a479 Update LxManga.kt 2024-10-07 15:16:49 +03:00
a659068ef3 Fixes batch 2024-10-07 15:15:52 +03:00
6f7e1fcfb2 [Grouple] Fix closing response on error 2024-10-05 15:23:22 +03:00
Draken
eff26c8889 Create NetTruyenFE.kt 2024-10-05 13:40:59 +03:00
Draken
037059d0e6 Update NetTruyenHE.kt 2024-10-05 13:40:59 +03:00
Draken
9b78a3ecf2 Update PinkTeaComic.kt 2024-10-05 13:40:59 +03:00
Draken
4df8311e18 Update Truyenqq.kt 2024-10-05 13:40:59 +03:00
645006fde8 Fix closing response in interceptors 2024-10-04 08:28:48 +03:00
95bbfefe90 Merge pull request #1128 from dragonx943/patch-1
Daily update sources
2024-10-03 09:17:28 +03:00
Draken
3181a5860b Update Truyenqq.kt 2024-10-03 10:48:22 +07:00
Draken
39c83444b7 Broken:( 2024-10-03 10:43:17 +07:00
Draken
7356d2036d Update BlogTruyenVNParser.kt 2024-10-03 10:40:30 +07:00
a8df8665ae [CuuTruyen] Fix tags 2024-10-02 11:02:46 +03:00
6355252699 Merge pull request #1117 from dragonx943/het-cuu-truyen
[CuuTruyen] Fix tags
2024-10-02 10:49:53 +03:00
Draken
6ec65e4aa4 Update TopTruyenViet.kt 2024-10-01 13:08:23 +07:00
Draken
f58bb421e5 Update DocTruyen3Q.kt 2024-10-01 13:08:05 +07:00
Draken
38ecde185a Update CuuTruyenParser.kt 2024-09-30 02:17:42 +07:00
Draken
e3924d5b06 Remove something
Remove some Tags (not found manga with it)
2024-09-30 02:10:08 +07:00
Draken
c1a7fc2624 Update CuuTruyenParser.kt 2024-09-30 01:29:46 +07:00
818d14fdbb Merge pull request #1109 from dragonx943/patch-2
Update domain
2024-09-29 19:25:01 +03:00
Draken
e93a6865e7 Update HentaiVNParser.kt 2024-09-28 20:07:57 +07:00
Draken
c6325eef50 Update DocTruyen3Q.kt 2024-09-28 18:59:16 +07:00
Draken
06d6653c78 Create DocTruyen3Q.kt 2024-09-28 18:54:05 +07:00
Draken
aac722909b Update HentaiVNParser.kt 2024-09-28 18:42:20 +07:00
Draken
78d64713a2 Create NetTruyenUU.kt 2024-09-28 18:36:10 +07:00
devi
7d71421c30 Update sources
Close #1105
Close #1104
2024-09-27 17:31:07 +02:00
7a571e596d [NHentai] Fix duplicated preferences 2024-09-27 08:00:01 +03:00
davvarrr
1718a034ee Merge pull request #1101 from dragonx943/patch-1
Update domain (Fetch data error)
2024-09-26 23:51:30 +02:00
devi
5443daabb6 [PornComix] fix close #1100 2024-09-26 23:50:53 +02:00
devi
de4f8ef2f9 [madtheme] add SearchWithFilters
[manga18] add SearchWithFilters
[mangadventure] add SearchWithFilters
[mangaworld] add POPULARITY_ASC, NEWEST_ASC, SearchWithFilters, Year, ContentTypes, Multiple states
Remove type on fetch tags
[mmrcms] add SearchWithFilters
[TrWebtoon] add SearchWithFilters
[Truyenqq] add TagsExclusion, ContentTypes, NEWEST_ASC, UPDATED_ASC, POPULARITY_ASC
[Baozimh] add ContentTypes
[zmanga] add SearchWithFilters, Year, ContentTypes
2024-09-26 23:26:07 +02:00
Draken
b9fb4a5e93 Update HentaiVNParser.kt 2024-09-26 22:35:01 +07:00
3cdd391410 [ExHentai] Use ContentType filter 2024-09-26 13:53:10 +03:00
ad77e8afa4 [CuuTruyen] Fix UserAgent 2024-09-26 13:41:04 +03:00
c85d17d60d [CuuTruyen] Fix 2024-09-26 13:31:37 +03:00
955c75a99f [CuuTruyen] Fix attempt 1 2024-09-25 18:47:20 +03:00
devi
d32d1f5044 [ImHentai] add ContentTypes
add new ContentTypes
[iken] add SearchWithFilters, ContentTypes
[keyoapp] add SearchWithFilters
[likemanga] add POPULARITY_TODAY, POPULARITY_WEEK, POPULARITY_MONTH, SearchWithFilters
2024-09-25 16:10:29 +02:00
091c5247d5 Merge pull request #1093 from dragonx943/het-cuu-truyen
Fix decryptor + Add image reconstructor ?
2024-09-25 16:33:09 +03:00
Draken
c593798d83 Update NetTruyenSSR.kt 2024-09-25 19:32:55 +07:00
Draken
edac81f51a Update NetTruyenLL.kt 2024-09-25 19:32:26 +07:00
Draken
8da3b4b7ac Update NetTruyen.kt 2024-09-25 19:31:49 +07:00
Draken
844e5fdb50 Update Truyenqq.kt 2024-09-25 19:30:34 +07:00
Draken
3f502de1f7 Update Truyenqq.kt 2024-09-25 19:30:05 +07:00
Draken
6532f392b5 Update Truyenqq.kt 2024-09-25 19:29:39 +07:00
Draken
9f340b2dfb Update LxManga.kt 2024-09-25 19:28:50 +07:00
Draken
30d34de653 Update CuuTruyenParser.kt 2024-09-25 19:21:10 +07:00
devi
52329e658f [SoManga] close #1091
[AsuraComic] fix close #1088
[HeanCms] add SearchWithFilters
[fuzzydoodle] add ContentTypes, SearchWithFilters
[DoujinDesu.tv] add SearchWithFilters, ContentTypes
2024-09-25 14:18:43 +02:00
devi
1c0df02c56 [HiveToon] fix close #1086 2024-09-24 19:39:58 +02:00
devi
2061a971b8 [fmreader] add SearchWithFilters
[LegacyScans] add ContentTypes, SortOrder.UPDATED
[MangaMana] add SortOrder.RATING_ASC , SortOrder.NEWEST_ASC
[Manhwa18.com] move to /en
Add new option on .toAbsoluteUrl()
2024-09-24 19:35:22 +02:00
cc62981f12 [ComicK] Fix chapter numbers in names 2024-09-24 16:32:55 +03:00
613623fa53 Update information pages 2024-09-24 08:45:21 +03:00
devi
fffdbfdbee [MangaDex] fix close #1084 2024-09-23 19:05:31 +02:00
devi
a55a4720fe [TuMangaOnline] add SearchWithFilters, TagsExclusion, Demographics, ContentTypes
[TempleScanEsp] fix
Add KODOMO on Demographic
Add ONE_SHOT on ContentType
2024-09-23 18:57:08 +02:00
42f2813e44 Update readme 2024-09-23 16:01:26 +03:00
c58d35288b Added some codegen features 2024-09-23 15:45:02 +03:00
f410df40f1 Improve utilities 2024-09-22 10:52:45 +03:00
7e95949ab7 [Grouple] Improve filter 2024-09-22 08:37:55 +03:00
7c4c3a3c97 [ExHentai] Improve filtering and tags 2024-09-22 08:37:55 +03:00
devi
7f25c5f82d [Manga-Starz] Fix close #1073 2024-09-21 18:43:17 +02:00
devi
f1939391e8 [AsuraComic] Fix close #1077
add ContentTypes , SearchWithFilters
[CloneManga] isSearchSupported false
[MangaGeko] fix tags,  add MultipleTags, TagsExclusion
[Manhwa18.net] add isSearchSupported
[ManhwasMen] add Exception
[Pururin] add SearchWithFilters, MultipleTags , TagsExclusion
[VyManga] add SearchWithFilters, MultipleTags, TagsExclusion
2024-09-21 18:33:45 +02:00
devi
d1f9b0d829 [mangaDex] Fix SortOrder and remove YearRange
[Bato] add OriginalLocale
[MangaPark] add OriginalLocale, SearchWithFilters
[Comick] add SearchWithFilters
[NineMangaParser] add SearchWithFilters
[AnimeBootstrap] add SearchWithFilters , ContentTypes
[madara] add Year, SearchWithFilters, SortOrder.RELEVANCE
[TeamXNovel] add ContentTypes , SearchWithFilters
2024-09-21 11:27:04 +02:00
f2354957e6 [MangaDex] Fix filter capabilities 2024-09-21 11:29:32 +03:00
devi
600eab20a1 remove unessery code
Remove old chapter manga and change last source for new manga chapter
Simplify parseChapterDate
Fix fetchAvailableTags on some source need to override
2024-09-20 20:37:36 +02:00
336c4a4d49 Add year constants 2024-09-20 12:15:49 +03:00
a1e47edfb2 Fix getPageUrl visibility 2024-09-20 08:55:51 +03:00
5269659c73 Merge pull request #1063 from KotatsuApp/feature/advanced_filter
Advanced filter
2024-09-19 20:14:23 +03:00
ab1b549a64 Merge branch 'master' of github.com:KotatsuApp/kotatsu-parsers into feature/advanced_filter 2024-09-19 19:37:52 +03:00
devi
2867dffc5a Capabilities simplified on madara to avoid redundant code 2024-09-19 18:00:26 +02:00
6d972a13fe Fix filter capabilities/options default values 2024-09-19 11:12:55 +03:00
3918bfafdf Specify visibility modifiers explicitly 2024-09-19 10:45:47 +03:00
1c15e569bf Migration to MangaListFilterCapabilities 2024-09-19 10:20:53 +03:00
5030548500 Global refactoring: partial migrate to ListFilterOptions/ListFilterCapabilities 2024-09-18 16:52:35 +03:00
c5d3a7b0c1 Global refactoring: migrate getList to new filter 2024-09-18 15:22:19 +03:00
Draken
75c46130ed Update NetTruyenSSR.kt 2024-09-18 10:05:48 +03:00
Draken
62c17155ca Update NetTruyen.kt 2024-09-18 10:05:48 +03:00
Draken
3a52062ce4 Update NetTruyenLL.kt 2024-09-18 10:05:48 +03:00
Draken
74ccbdcaee Update HentaiCube.kt 2024-09-18 10:05:48 +03:00
Draken
fbd610349a Update PinkTeaComic.kt 2024-09-18 10:05:48 +03:00
Draken
8af75d8c6a Update TruyenVn.kt 2024-09-18 10:05:48 +03:00
Draken
0bafd117ff Update and rename HentaiVnCafe.kt to HentaiVnFit.kt 2024-09-18 10:05:48 +03:00
ae9a7c6090 Introduce MangaListFilterCapabilities class 2024-09-17 10:16:18 +03:00
481ad02e01 Partial migration to MangaListFilterV2 2024-09-17 10:10:22 +03:00
9042074c50 Merge remote-tracking branch 'origin/SortOrderPopularitytime' into feature/advanced_filter 2024-09-17 09:46:03 +03:00
821e51ff7d Merge branch 'filter-type-and-demographic' into feature/advanced_filter 2024-09-17 09:40:51 +03:00
0f4808f5b5 Use ContentType instead of Type 2024-09-17 09:35:54 +03:00
aba8a80d8f [MangaDex] Fix settings 2024-09-15 15:48:35 +03:00
2b0edfde60 [MangaDex] Data-saver server support (close #1062) 2024-09-14 14:27:31 +03:00
01a496768a MangaListFilter v2 2024-09-14 12:41:24 +03:00
Draken
82a57cb3c8 Update HentaiVN Domain 2024-09-14 12:30:37 +03:00
Naga
27c07d86bc fix tags 2024-09-14 12:29:28 +03:00
Naga
e916f2a66e Closes #1057 2024-09-14 12:29:28 +03:00
devi
494ecdfec8 Add year range. 2024-09-14 12:28:38 +03:00
devi
8a3c0e02f6 Add relevance sort order for good filters with text searches
Adding the added filter
2024-09-14 12:28:38 +03:00
devi
37428bf9c0 Add year, localeMangas filter on MangaListFilter.Advanced
Add year, localeMangas and localeMangas on MangaDexParser
2024-09-14 12:28:38 +03:00
devi
62b4a21cef Add query filter on MangaListFilter.Advanced
Add query.filer Advanced on MangaDexParser
2024-09-14 12:28:38 +03:00
davvarrr
b566e4e7e4 Update src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2024-09-14 11:25:23 +02:00
davvarrr
4ff2061bb7 Update src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2024-09-14 11:25:16 +02:00
devi
03d7e138e9 Add support type and Demographic on MangaListFilter 2024-09-14 10:55:56 +02:00
devi
0540da57e6 Update Sources
Close #1060
2024-09-13 20:15:46 +02:00
devi
e0e9d25a4f Improve madara 2024-09-13 18:43:35 +02:00
devi
fd7684866e Refonte madara :
Add tagsExclude
Add support multiple tags
Add RATING_ASC ( and prepare RELEVANCE )
simplify postrequest
Preparation for query, year, author and artist filters
Change withoutAjax for some sources
2024-09-12 18:49:38 +02:00
devi
7c8b427d2a Miss add SortOrder in availableSortOrders for NHentaiParser 2024-09-10 14:31:19 +02:00
devi
4fcc68d149 add POPULARITY time sortOrder 2024-09-10 14:25:24 +02:00
ad726a3fd7 [CuuTruyen] Fixes 2024-09-05 12:30:27 +03:00
f167a8c8f6 [CuuTruyen] Fixes 2024-09-05 12:29:33 +03:00
Draken
b404b44008 insert something :p 2024-09-02 12:37:46 +03:00
Draken
c6dc51bb5d Some suggestions 2024-09-02 12:37:46 +03:00
Draken
69ee6be246 Create NetTruyenHE.kt 2024-09-02 12:37:46 +03:00
Draken
e08fab2938 Final Source commit:(
i cried:(
2024-09-02 12:37:46 +03:00
5db275bce2 [Grouple] Handle Usagi redirects 2024-08-31 16:03:32 +03:00
9c05e3f8e8 Usagi parser 2024-08-31 15:58:37 +03:00
devi
ac2c9b8621 Add InfamousScans 2024-08-31 11:28:59 +02:00
devi
02852ac4e7 Add Exclude Genres and new sort order on ComickFunParser
close #1032
2024-08-31 11:12:55 +02:00
devi
1163541ac5 Update sources and add sources
Fix MagusManga close #1021
2024-08-30 18:32:19 +02:00
devi
2da0c17fe2 Merge remote-tracking branch 'origin/master' 2024-08-29 17:46:36 +02:00
devi
7528480f54 add asc 2024-08-28 09:20:16 +03:00
devi
a45a270479 Add Asc on some SortOrder 2024-08-28 09:20:16 +03:00
devi
380804361b Add Asc on some SortOrder 2024-08-28 09:20:16 +03:00
devi
e072ee8b44 add asc 2024-08-23 18:41:56 +02:00
devi
d812644e61 Add Asc on some SortOrder 2024-08-23 18:41:38 +02:00
devi
71deb11e1f Add Asc on some SortOrder 2024-08-23 17:54:12 +02:00
devi
2e138da3d5 add source and fix 2024-08-23 17:32:53 +02:00
939b6b1e46 Improve TooManyRequestExceptions 2024-08-22 09:12:34 +03:00
d937c7e6ab [ExHentai] Fix IP ban detection 2024-08-20 17:17:46 +03:00
f91ff0b9d0 [ExHentai] Detect IP ban 2024-08-20 14:28:07 +03:00
98cbee11b9 Unify user agent header processing 2024-08-17 11:05:13 +03:00
Draken
7f0431d493 Update NetTruyenLL.kt 2024-08-17 09:46:39 +03:00
Draken
3227c53699 Create NetTruyenLL.kt 2024-08-17 09:46:39 +03:00
Draken
2ee8784d7d Update NetTruyen.kt 2024-08-17 09:46:39 +03:00
Draken
0fac0f450c Create BlogTruyenVNParser.kt 2024-08-17 09:46:39 +03:00
Draken
b4fb202db4 Update BlogTruyenParser.kt 2024-08-17 09:46:39 +03:00
Draken
93ba163ea2 Update NetTruyen.kt 2024-08-17 09:46:39 +03:00
Draken
bd3ff20146 Hotfix Source 2024-08-17 09:46:39 +03:00
devi
b3a0b97f0e add HastaTeamReader close #1004
Update Sources ( fix , url and broken )
Add sources
2024-08-16 12:58:51 +02:00
devi
ca212ca692 add auth on some sources
add Config Header on many sources
close #974
2024-08-11 18:06:07 +02:00
devi
3b809202b3 Merge pull request #994 from dragonx943/patch-1
Update HentaiVN Domain
2024-08-11 18:05:25 +02:00
Draken
9858419586 Update HentaiVN Domain 2024-08-11 21:57:15 +07:00
devi
1f7fe2aed3 Fix Sources
Add sources
Correct detect login on MadaraParser
close #988
fix oocini.biz close #987
Changing the latest DEPRECATION
( Technically we can raise the old support for getList() and MangaChapter() )
2024-08-11 16:15:16 +02:00
devi
71affd155c Some Fix 2024-08-06 18:20:35 +02:00
devi
a54f030c4e Fix, change url and add broken
Fix HeamCms Chapter close #970
add Template FuzzyDoodleParser
Fix LelScanVf
Add hentaislayer , ScyllaComics
Close #609
Close #901
Close #440
Add template IkenParser
Fix MangaGalaxyParser
Add VortexScans
Fix HniScantrad
Add HastaTeam close #939
Add HotComicsParser close #962
Add HentaiCrot close #913
2024-08-04 17:44:38 +02:00
devi
3b5a018f8c Fix, change url and add broken 2024-08-02 22:01:18 +02:00
devi
8d5fc945d4 Move ReaperComics to HeanCms
Rework heancms based on @NagaYZ's code
2024-08-02 19:27:23 +02:00
devi
50194df24d Rm duniakomik close #952
Fix DoujinKu close #951
Fix DoujinDesu.tv close
Add, fix some sources  #963
change url close #965 ( the copy was added anyway )
2024-08-02 17:38:04 +02:00
devi
5f771973a8 Merge pull request #967 from NagaYZ/fix-reaper
Fix reaperscan site structure changed
2024-08-02 17:31:06 +02:00
devi
4fcfbb374f Merge pull request #959 from dragonx943/patch-1
Broken source + Update domain
2024-08-02 17:30:51 +02:00
853c21e49f [ExHentai] Fix tags parsing 2024-08-01 21:18:55 +03:00
Naga
3efb5d8520 fixed page duplicated 2024-08-01 18:40:08 +02:00
Naga
e74985d870 Merge branch 'refs/heads/master' into fix-reaper
# Conflicts:
#	src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/ReaperComics.kt
2024-08-01 18:14:02 +02:00
Naga
32eab42c26 Merge pull request #31 from KotatsuApp/master
[pull] master from KotatsuApp:master
2024-08-01 18:11:10 +02:00
Naga
0d3d8232f9 reaper changed site structure 2024-08-01 18:09:55 +02:00
Draken
fd3dc389df Update Saytruyenhay.kt 2024-08-01 00:48:54 +07:00
Draken
2d274f37ee Update TruyenTranhDamMyy.kt 2024-08-01 00:48:49 +07:00
Draken
d1a12df18f Create Saytruyenhay.kt 2024-08-01 00:42:27 +07:00
Draken
017a9a58a3 Update TruyenTranhDamMyy.kt 2024-08-01 00:36:19 +07:00
Draken
e33c57f51b Update Quaanhdaocuteo.kt 2024-07-31 02:06:55 +07:00
Draken
da041df054 Delete src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/Saytruyenhay.kt 2024-07-31 02:05:13 +07:00
Draken
99b57e1297 Update TruyenTranhDamMyy.kt 2024-07-31 01:54:57 +07:00
Draken
6ce8a22514 Update BlogTruyenParser.kt 2024-07-31 01:48:51 +07:00
Draken
a9fc534ea7 Remove dead sources + Change domain (#955)
* Delete src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyentranhLHParser.kt

* Update NetTruyen.kt

* Delete src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenAA.kt

* Delete src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenX.kt

* Delete src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/Nettruyenmax.kt

* Update NetTruyen.kt

* Update NhatTruyenVN

* Delete src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NhatTruyenSS.kt
2024-07-30 09:27:41 +03:00
devi
6e04fa1251 Add CupFoxParser and sources
Add OneMangaParser and sources
2024-07-28 18:36:21 +02:00
devi
8f851282b4 Add XManhwa, MangaMana, MangaFr
Fix XoxoComics close #928
2024-07-28 01:08:01 +02:00
devi
d774935a6a Merge remote-tracking branch 'origin/master' 2024-07-27 11:28:31 +02:00
devi
712d42b328 Some Fix 2024-07-27 11:28:15 +02:00
SBS123
f66aab03f2 Updata MangaNoon (#924)
* Update Manjanoon.kt

* Update Manjanoon.kt

* Update Manjanoon.kt
2024-07-27 10:28:22 +03:00
devi
53ca9c9677 Rework WpComicsParser
Adds sources
2024-07-25 20:20:34 +02:00
devi
7bcc624a74 Add some sources
Fix some sources
close #929
2024-07-24 19:17:06 +02:00
devi
fa2d73348e rm @Broken 2024-07-23 18:38:12 +02:00
devi
26c3edbc17 Fix some sources
add @Broken on sources
Close #927
2024-07-23 18:36:21 +02:00
b9d89edfc2 [DynastyScans] Fixes 2024-07-23 10:04:46 +03:00
7ccc6438d5 [Grouple] Fix public url 2024-07-23 09:29:51 +03:00
devi
cd9f65596b Add some sources
Fix some sources
Add @Broken on some sources
close #909 #912 #920 #910 #914 #916
2024-07-20 19:57:45 +02:00
5404743f17 Update dependencies 2024-07-20 11:44:27 +03:00
c0296d0882 Fix build 2024-07-20 11:00:22 +03:00
Inkesk
dec07bd27d Update MangaGalaxy.kt
parser issue for mangagalaxy not loading chapter solved
2024-07-20 10:36:42 +03:00
Inkesk
1be1e9843d Update MangaGalaxy.kt
Updated the domain
2024-07-20 10:36:42 +03:00
Inkesk
5b5afcfe4c Update LuaScans.kt
Luascans.com changed domain to Luacomic.com , committing the change so future bugs and issues don't arise.
2024-07-20 10:36:42 +03:00
Inkesk
4f5dc9ffad Update ManhuaScan.kt
manhuascan.io was changed to kaliscan.io hence the change committed in here .
2024-07-20 10:36:42 +03:00
Inkesk
9c5b00ecf0 Update DarkScans.kt
Updated the domain name from darkscans.com to darkscans.net
2024-07-20 10:36:42 +03:00
Inkesk
048ba99323 Update ResetScans.kt
Changed the domain from reset-scans.xyz to reset-scans.co.
As previous domain for source was closed due to DMCA. Figure out the rest of details yourself , but resetscans is still on mates. Enjoy
2024-07-20 10:36:42 +03:00
devi
35bdc15aa9 Fix url grimelek 2024-07-15 18:49:19 +02:00
b06288e7eb Merge branch 'master' into experimental/abstract_sources 2024-07-15 14:58:19 +03:00
SBS123
426c7ad708 Update Normoyun.kt 2024-07-15 13:31:40 +03:00
devi
fadf8861e7 Rm BrMangas close #454
rm PowerManga close #462
Add MangaNinja close #897
Add Grimelek close #375
Add OpiaToon close#374
Add login on madara
Fix ManhwaFreak
2024-07-14 14:17:17 +02:00
devi
dceedf019a Fix HentaiVN
Remove some warning
2024-07-13 21:49:31 +02:00
devi
f49ddf7437 Fix HentaiVN
Remove some warning
2024-07-13 21:49:05 +02:00
devi
33a3c8350d Merge pull request #885 from dragonx943/patch-1
domain change hentaivn
2024-07-13 21:47:20 +02:00
devi
052fa146d2 Merge pull request #889 from NagaYZ/fix-manhuaplus
domain change manhuaplus
2024-07-13 21:33:34 +02:00
devi
1c85782690 Fix CafecomYaoi close #715
Fix Topmanhua close #710
Add Some sources
Add new Parser
fix EpsilonScan close #602
Add MangaHub.link close #892
Fix SussyScan close #893
Fix MaidScan close #585
fix HuntersScan close #584
Fix TeamXNovel close #575
close #574
Fix MangaTown close #569
Add LeitorDeManga close #864
add Search on ScanParser
Add mangabr close #862
Add Manga Italia close #841
Add Mangá Terra close #856
Fix MilaSub close #559
Fix KomikTapParser close #554
Fix YugenApp close #586
Fix TuMangaOnline close #566
Fix bato close #516
Fix Mangakakalot close #490
2024-07-13 21:30:59 +02:00
Draken
cf5abdf7d3 Update HentaiVNParser.kt 2024-07-12 16:22:44 +07:00
Naga
df562bedbb Closes #886 2024-07-12 00:38:19 +02:00
devi
11c1eafa0d Fix ReaperComics close #816
close #699
Fix GuildaTierDraw close #786
Fix Truyenqq close #793
Fix JiangzaiToon close #783
Fix MangaPark close #734
Fix ScanIta close #670
Add MangaPeak close #888
Fix ArvenComics close #660
2024-07-11 21:30:04 +02:00
Draken
cc8369e02a Update HentaiVNParser.kt 2024-07-11 23:49:45 +07:00
devi
cd468df9ad Add : MangaTx.to - AlterkaiScans - StoneScape
Kalango - SolooScan - ErosScans - SolooScan
RaysScan - TemakiMangas - ZinChanManga
Urls Changes
Add volume on some parser
Fix ThunderScans close #818
NinjaScan close #753
Add Ngomik close #761
Remove dulicate source paragonscans
Fix LuminousScans close #578
Fix YugenApp close #854
Fix KaiScans close #614
Add PeachBl Close #884
Fix GalinhaSamurai close #835
Fix RocksManga close #827
Fix CrystalComics close #792
2024-07-10 20:17:06 +02:00
Draken
64666e42e8 Update HentaiVNParser.kt
not sure, i hope it will works...
2024-07-09 01:31:14 +07:00
ad7c953d29 Merge pull request #883 from NagaYZ/fix-mangaworld 2024-07-08 09:03:07 +03:00
Naga
b345efe2d1 fixed source mangaworld pages 2024-07-07 20:53:16 +02:00
Naga
74b8aaa94e fixed source mangaworldadult 2024-07-07 12:06:48 +03:00
Naga
1ace1ba3ec added source mangaworldadult, refactor mangaworld 2024-07-07 12:06:48 +03:00
Naga
b822574b70 moved mangaworld in package 2024-07-07 12:06:48 +03:00
devi
466ca0f0e9 Merge remote-tracking branch 'origin/master' 2024-07-06 17:43:09 +02:00
devi
0bcac0c639 Add @Broken on some Dead Sources
Urls Changes
repair sources
Remove Duplicate Source
Add volume on some parser
2024-07-06 17:37:32 +02:00
7433fb8fa0 [LibSoc] Fix image server option 2024-07-06 12:23:37 +03:00
b1ac1cf238 [LibSoc] Fix image server option 2024-07-06 11:53:40 +03:00
Naga
a88a861d82 added main page sortby updated 2024-07-05 13:51:59 +03:00
Naga
41ced8edee added states , fixed title, added types 2024-07-05 13:51:59 +03:00
0f73f74539 [LibSoc] Default image server config option 2024-07-05 13:24:44 +03:00
bb9902e3b2 [LibSoc] Add split by translations config option 2024-07-05 13:24:41 +03:00
devi
c03b0fc981 Fix search on MangaDexParser
Fix State on ScansMangasMe
2024-07-03 21:50:18 +02:00
e8733f15e4 Merge pull request #853 from NagaYZ/fix-mangaworld 2024-06-30 15:52:27 +03:00
Naga
26519c71a6 fix #852 2024-06-25 21:44:40 +02:00
f923acc5a7 Extract MangaSource interface 2024-06-24 15:35:41 +03:00
Naga
55b9b6aac4 Merge pull request #26 from KotatsuApp/master
[pull] master from KotatsuApp:master
2024-06-23 17:33:07 +02:00
devi
52db07a33b MiHentai Closes #829
MrBenne Closes #627
Closes #555
Norterose Closes #625
Closes #564
Closes #483
MaidSecret Closes #623
Closes #550
HentaiOrigines
Fix SortOrder On MmrcmsParser
2024-06-22 18:18:19 +02:00
7ed8c9f787 [AllHen] Update domain 2024-06-22 12:08:05 +03:00
cc12b193d3 [MangaWorld] Refactor 2024-06-22 12:04:14 +03:00
4d9c51bcd9 [MangaWtf] Parser 2024-06-22 11:55:10 +03:00
Naga
7de48393b6 added source MangaWorld 2024-06-22 11:55:02 +03:00
Naga
283aa92fd5 fixed url and chapters 2024-06-22 11:52:08 +03:00
Naga
9d0393ca72 update domain 2024-06-22 11:30:21 +03:00
c5fc7f76d3 Merge pull request #845 from NagaYZ/fix-aquamanga 2024-06-19 11:14:50 +03:00
Naga
6b6325895b update aquamanga domain 2024-06-19 01:39:12 +02:00
39e9f5a2ff Added UNKNOWN manga source constant 2024-06-17 21:24:34 +03:00
204223e2a8 Merge pull request #837 from NagaYZ/fix-baozimh 2024-06-17 08:48:18 +03:00
Naga
b39abcc4a0 fix select chapter 2024-06-15 14:17:19 +02:00
SBS123
f49e9fa66b Update MangaPro.kt 2024-06-15 10:43:00 +03:00
scaledzdn
56fd22b43f src: id: shinigami: Change url to shinigamitoon.id
* Previously not working.
2024-06-07 08:27:51 +03:00
0b2bf607f7 Make locale non-nullable 2024-06-04 10:02:38 +03:00
3ff9e69585 [MangaOVH] Removal (closes #824) 2024-06-04 00:14:39 +03:00
9ceb90204c Merge pull request #801 from OtakuArab/patch-3 2024-06-03 17:28:17 +03:00
SBS123
ab3c4b2b2d Update and rename PewPiece.kt to Gmanga.kt 2024-06-01 12:49:11 +03:00
SBS123
060ca4b7ef Update MangaLinkNet.kt 2024-06-01 12:36:48 +03:00
SBS123
a7a29ef029 Rename LinkManga.kt to MangaLinkNet.kt 2024-06-01 12:34:08 +03:00
SBS123
e7826c2570 Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/ar/LinkManga.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2024-06-01 12:26:43 +03:00
SBS123
77a733a062 Update and rename EnAresManga.kt to FlAres.kt 2024-06-01 11:06:07 +03:00
SBS123
96bd99650f Update and rename RocksManga.kt to YuriMoonSub.kt 2024-06-01 11:06:07 +03:00
SBS123
2d1899f1f2 Update TeamXNovel.kt 2024-06-01 11:05:45 +03:00
SBS123
42b1740b0f Update FlixScans.kt 2024-06-01 11:05:45 +03:00
SBS123
fbf613c4e6 Update and rename MangalinkParser.kt to LekMangaOrg.kt 2024-06-01 11:05:45 +03:00
SBS123
bf18070bc1 Update and rename MangaLekNet.kt to MangaLeko.kt 2024-06-01 11:05:45 +03:00
SBS123
c9c41fdd33 Create StellarSaber.kt 2024-06-01 11:05:45 +03:00
SBS123
949d822385 Delete src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/ar/StellarSaber.kt 2024-06-01 11:05:45 +03:00
SBS123
83b8f28055 Create MangaPro.kt 2024-06-01 11:05:45 +03:00
SBS123
c602d817d9 Create CrowScans.kt 2024-06-01 11:05:45 +03:00
SBS123
a50b217b6f Update and rename MangaLekCom.kt to LekMangaCom.kt 2024-06-01 11:05:45 +03:00
SBS123
23c031780f Update and rename Mangaatrend.kt to ManhaTok.kt 2024-06-01 11:05:45 +03:00
SBS123
e3b50d5dfa Update and rename KingOfShojo.kt to Hijalacom.kt 2024-06-01 11:05:45 +03:00
SBS123
9b1bee567f Update and rename KingOfManga.kt to MangaAtrend.kt 2024-06-01 11:05:45 +03:00
SBS123
3534973357 Create RocksManga.kt 2024-06-01 11:05:45 +03:00
SBS123
c4c4bdd547 Update Source 2024-06-01 11:04:43 +03:00
SBS123
528fadceb8 Update UmiManga.kt 2024-06-01 11:04:18 +03:00
SBS123
e15aecaa52 Update and rename BeastScans.kt to UmiManga.kt 2024-06-01 11:04:18 +03:00
SBS123
62e635ebe5 Update MangaTime.kt 2024-06-01 11:03:58 +03:00
SBS123
be846b43ae Update Mangaspark.kt 2024-06-01 11:03:58 +03:00
SBS123
7bfe168eee Update MangaLionz.kt 2024-06-01 11:03:58 +03:00
SBS123
e8d4a91ad7 Update MangaStarz.kt 2024-06-01 11:03:58 +03:00
SBS123
bc1804c030 Update and rename LikeManga.kt to LikeMangaNet.kt 2024-06-01 11:03:20 +03:00
SBS123
d18c9fe0da Update LikeManga.kt 2024-06-01 11:03:20 +03:00
SBS123
a7ea87dd8c Update AzoraMoon.kt 2024-06-01 11:03:20 +03:00
SBS123
e3a0ab8513 Update LikeManga.kt 2024-06-01 11:03:20 +03:00
SBS123
3a77144a5e Update LikeManga.kt 2024-06-01 11:03:20 +03:00
SBS123
69e311829b Update and rename MangaLike.kt to LikeManga.kt 2024-06-01 11:03:20 +03:00
SBS123
b1effdb7c7 Update and rename Azoranov.kt to AzoraMoon.kt 2024-06-01 11:03:20 +03:00
SBS123
124537eb18 Create ArAreaScans.kt 2024-06-01 11:02:06 +03:00
SBS123
b81924b144 Update Manjanoon.kt 2024-06-01 10:59:27 +03:00
Naga
dd18605678 cleanup 2024-06-01 10:59:06 +03:00
Naga
6bce31d43f fix title selector 2024-06-01 10:59:06 +03:00
Naga
0da5b47ce5 fetching code using suspendlazy 2024-06-01 10:55:15 +03:00
Naga
d0d891b112 Apply suggestions from code review
Co-authored-by: Koitharu <nvasya95@gmail.com>
2024-06-01 10:55:15 +03:00
Naga
2292c392e9 fix filters, added search support (#775) 2024-06-01 10:55:15 +03:00
cc35aa6bc3 Broken parser annotation 2024-06-01 10:53:59 +03:00
SBS123
9e4a124a58 Update ScarManga.kt 2024-05-28 21:35:30 +03:00
SBS123
d63afb0917 Rename LikManga.kt to LinkManga.kt 2024-05-28 19:15:03 +03:00
SBS123
80a3f61a1f Create ArAreaScans.kt 2024-05-28 15:05:02 +03:00
SBS123
303c817d2d Update and rename MangalinkNet.kt to LikManga.kt 2024-05-28 14:24:14 +03:00
SBS123
d9cf94c6b5 Update LekManga.kt 2024-05-27 20:18:46 +03:00
SBS123
d72414d531 Update and rename AresManga.kt to ScarManga.kt 2024-05-27 20:13:56 +03:00
26be293f24 [ComicK] Fix volume & chapter numbers 2024-05-27 13:18:15 +03:00
SBS123
36b8633c1e Update and rename MangaLek.kt to LekManga.kt 2024-05-27 13:05:55 +03:00
Naga
6bdbf2c65e closes #795 2024-05-27 13:05:34 +03:00
80ec615548 [Comick] Fix "No value for hentai" 2024-05-26 14:19:32 +03:00
ffc45ff79b Merge pull request #777 from AwkwardPeak7/patch-1 2024-05-25 18:48:16 +03:00
AwkwardPeak7
48cb28d9f8 Update MangaFireParser.kt 2024-05-25 18:33:38 +05:00
51da0b62c1 Apply suggestions from code review 2024-05-25 16:23:31 +03:00
AwkwardPeak7
e391ed52f3 MangaFire: related manga author language filter 2024-05-25 16:23:31 +03:00
AwkwardPeak7
a5e6e4255d MangaFire: tag exclusion 2024-05-25 16:23:31 +03:00
AwkwardPeak7
590e7e3ba3 add MangaFire 2024-05-25 16:23:31 +03:00
d218ad5a67 [MangaReaderTo] Syncronize descrambling 2024-05-23 16:58:10 +03:00
350bc0ad58 Small refactor 2024-05-23 16:26:49 +03:00
AwkwardPeak7
a0f9bc032d cleanup and test impl 2024-05-23 16:05:14 +03:00
AwkwardPeak7
4edcd70871 simplify api 2024-05-23 16:05:14 +03:00
AwkwardPeak7
90c0bf46f4 image redrawing api 2024-05-23 16:05:14 +03:00
AwkwardPeak7
9d4fc1980f MangaReader.To 2024-05-23 16:05:14 +03:00
Naga
332524f1f3 new source added modescanlator, closes #759 2024-05-23 16:03:43 +03:00
078b59b1e2 [Madara] Migrate to ScatterSet and add UserAgent config option 2024-05-15 19:46:48 +03:00
0551ed5f0b [MangaDex] Chapters fixes 2024-05-15 17:25:09 +03:00
915d4093b9 Fixes 2024-05-14 12:51:48 +03:00
952e9c39ac [LibSocial] Rewrite parsers 2024-05-14 12:33:24 +03:00
3e32a6280a [LuratoonScan] Rewrite parser 2024-05-12 13:12:51 +03:00
288b67e250 Close #741 2024-05-09 11:43:32 +03:00
7d2f5696f5 Close #719 2024-05-09 01:16:18 +03:00
8c3fec0933 Close #677 2024-05-09 01:15:48 +03:00
33b00fe65f Fixes #728 #725 2024-05-08 12:35:38 +03:00
f0f50a37b5 Fixes batch #733 #730 #731 #727 2024-05-08 10:26:29 +03:00
c2b2148190 Upgrade gradle 2024-05-06 18:03:20 +03:00
f22362dc53 [Grouple] Fix alt titles parsing 2024-05-06 17:55:21 +03:00
68cc1d4c4f [DesuMe] Improvements 2024-05-06 17:46:54 +03:00
0f84ef1e58 [Desu] Fix list loading 2024-05-04 21:26:59 +03:00
Naga
a245574dee fix #702 2024-04-21 16:32:51 +03:00
fd90970173 [MadTheme] Improve pages parsing 2024-04-21 16:31:22 +03:00
75a55e4748 [SinensisScans] Update domain #674 2024-04-20 17:57:38 +03:00
bbd4867830 [FbSquads] Update domain #681 2024-04-20 17:55:15 +03:00
3463c8a49e [HeanCms] Fixes 2024-04-20 17:52:17 +03:00
7829a2ad3b [MadTheme] Fix pages parsing #701 2024-04-20 16:53:23 +03:00
AwkwardPeak7
fb387dbcd9 FreakComic: update selectors 2024-04-14 08:47:06 +03:00
cd0b3cd1dc Update gitignore 2024-04-14 08:46:46 +03:00
fe500a27c0 Update dependencies 2024-04-14 08:43:24 +03:00
da860bc250 Fix imports 2024-04-14 08:32:42 +03:00
e3a8eeb647 Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/en/OmegaScans.kt
Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
2024-04-13 15:15:03 +03:00
Naga
6dbc709f98 fix #687 2024-04-13 15:15:03 +03:00
AwkwardPeak7
49ca54d68a MangaGalaxy: move to MangaReader 2024-04-13 15:13:31 +03:00
AwkwardPeak7
e81b8127af DrakeScans: move to MangaReader 2024-04-13 15:13:31 +03:00
AwkwardPeak7
d1b490ed98 add german to MangaPlus 2024-04-13 15:13:31 +03:00
AwkwardPeak7
893ed6afd2 999Hentai: fix api url 2024-04-13 15:13:31 +03:00
9df2cf5bd7 [AstrumScans] Source removal on request (closes #682) 2024-04-07 12:38:21 +03:00
b5ceaf4e65 Add OtakuWorld to README 2024-04-04 21:34:21 +03:00
Naga
44ea9fe709 fix #667 2024-03-30 09:06:15 +02:00
8174229d28 Merge pull request #658 from NagaYZ/fix-xoxocomics
fix chapter order
2024-03-30 09:05:54 +02:00
f628ed2e1b Add kotatsu-dl to README 2024-03-26 14:26:51 +03:00
c90a0a77bc Update README 2024-03-26 14:24:07 +03:00
Naga
10b3f2e65b fix chapter order 2024-03-23 16:11:08 +01:00
9821e93d25 Merge pull request #655 from NagaYZ/fix-xoxocomics
fix #652
2024-03-23 16:24:15 +02:00
Naga
6c16c9c55f fix #652 2024-03-22 18:57:49 +01:00
ab679bccc6 Merge pull request #647 from NagaYZ/fix-issue
Fix Omegscans
2024-03-22 06:58:40 +02:00
Naga
6fcf3785ef fix #591 2024-03-20 10:10:54 +01:00
Naga
e605b325c7 fixrating 2024-03-19 21:27:28 +01:00
Naga
a714d0927e fix OmegaScans tags 2024-03-19 20:46:15 +01:00
Naga
fe1ef89d30 fix OmegaScans site structure changed 2024-03-19 19:56:25 +01:00
639895f511 MangaOVH: Parsing related manga 2024-03-19 12:30:35 +02:00
4fdc02de35 MangaOVH: Fix handling unexisting branches 2024-03-19 11:37:34 +02:00
103ef11f3d Dynamic UserAgent support 2024-03-18 12:23:09 +02:00
69e7efe6d1 NHentai: configurable User-Agent 2024-03-18 11:05:47 +02:00
83e971d85b Update UserAgents 2024-03-18 09:49:40 +02:00
fec60955ed Merge pull request #631 from NagaYZ/fix-issue
Fix source domain and issue
2024-03-15 10:44:45 +02:00
c5b980a406 Update issue templates 2024-03-15 10:40:15 +02:00
99483268d6 Remove Bakai parser #629 2024-03-15 10:29:23 +02:00
Naga
67fef2cc1c fix mangatown select and pagination 2024-03-14 19:08:47 +01:00
Naga
f450111c1c fix Baozimh webview and 50+ page chapter 2024-03-14 19:08:18 +01:00
Naga
718e7eab82 fix source domain 2024-03-14 19:07:50 +01:00
eb031b00ab ComicK: Update domain 2024-03-14 17:16:00 +02:00
a10c1101ab New source: MangaOVH 2024-03-14 17:12:18 +02:00
Naga
9c0c20f86b Merge remote-tracking branch 'upstream/master' 2024-03-14 09:38:56 +01:00
c6d1f1b525 [NepNep] Refactor #628 2024-03-13 12:56:14 +02:00
9a84791f5c Merge pull request #628 from NagaYZ/feature-manga4life-sort
Feature manga4life sort
2024-03-13 12:53:47 +02:00
14fc02cb23 [ReaperComics] Refactor #620 2024-03-13 12:53:34 +02:00
39ae6a406c [Grouple] Added Seimanga support 2024-03-13 12:45:54 +02:00
ba8682f79e Merge pull request #620 from NagaYZ/feature-search-reaper
Feature search reaper
2024-03-13 12:43:19 +02:00
Naga
986e4d8fcc Merge pull request #1 from KotatsuApp/master
[pull] master from KotatsuApp:master
2024-03-13 00:51:39 +01:00
Naga
016ced24e0 added pagination 2024-03-13 00:13:02 +01:00
Naga
b60b2d8355 added sort by popularity/updated 2024-03-12 23:11:18 +01:00
Naga
f733b85878 fix webtoon sort newest 2024-03-12 23:10:31 +01:00
Naga
1926a73dee without serialization, and added cache 2024-03-11 20:01:07 +01:00
071f4f0911 Trigger rebuild 2024-03-11 11:41:32 +02:00
813c5236b3 [Grouple] Back to the old chapters parsing behavior with option 2024-03-11 09:27:04 +02:00
Naga
f39a9f191a cleanup 2024-03-10 23:39:31 +01:00
Naga
6d8d757798 fix manga chapters list 2024-03-10 23:38:28 +01:00
Naga
81975977ad added search support for reaperscans 2024-03-09 23:44:01 +01:00
b7613606c0 [TuMangaOnline] Fix regexp 2024-03-09 14:03:09 +02:00
0aa4ea01f7 [Grouple] Multiple translations support 2024-03-09 12:10:04 +02:00
20685598e3 [TuMangaOnline] Fix pages parsing 2024-03-09 11:22:30 +02:00
b1fb1bdc6b Merge pull request #615 from NagaYZ/feature-search-by-number
Feature search by number
2024-03-09 11:04:13 +02:00
Naga
a80bdcc611 full title name 2024-03-08 21:18:52 +01:00
Naga
4571e3e001 gitignore 2024-03-08 02:31:59 +01:00
Naga
38d7d97167 added search by id 2024-03-08 02:29:59 +01:00
3913e95b53 Merge pull request #608 from nghduc97/fix-mangabox-parser-white-spaces
fix mangaboxparser white space coding in search query
2024-03-04 11:56:07 +02:00
954c926a9f Merge pull request #588 from NagaYZ/feature-webtoon-original
Feature webtoon original
2024-03-04 11:55:52 +02:00
nghduc97
0973444c47 fix mangaboxparser white space coding in search query 2024-03-03 11:45:10 +07:00
Naga
368b61c21a fixed suggestions 2024-02-28 18:13:51 +01:00
Naga
efc9b3502c fixed suggestions 2024-02-28 18:03:12 +01:00
Naga
2e86c480ec Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/WebtoonsParser.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2024-02-28 16:01:36 +01:00
Naga
39eeaacdcb fixup! trying to improve speed 2024-02-25 16:32:31 +01:00
Naga
ea45e91aa7 trying to improve speed 2024-02-25 14:47:06 +01:00
Naga
a65e41e796 fix 2024-02-25 14:24:14 +01:00
Naga
91648756c9 added more language 2024-02-25 14:16:24 +01:00
Naga
a225234800 fixed chapter date 2024-02-25 14:11:30 +01:00
Naga
de58333dc4 fixup! fixup! fixed offset 2024-02-25 13:12:09 +01:00
Naga
24a25e3dbf fixup! fixed offset 2024-02-25 13:00:31 +01:00
Naga
8e5ae51067 fixed offset 2024-02-25 12:50:49 +01:00
Naga
86c981ae8e fixup! trying to speed up loading 2024-02-25 12:33:11 +01:00
Naga
b716c35438 trying to speed up loading 2024-02-25 12:30:11 +01:00
Naga
9e984510d4 added caching for title list to speed up loading 2024-02-25 03:30:00 +01:00
Naga
3c08119ccc added caching for title list to speed up loading 2024-02-25 03:12:12 +01:00
Naga
ada1b7b54c fixed sort descending 2024-02-25 00:38:17 +01:00
Naga
a7ed4fbcc3 fix import 2024-02-24 23:33:10 +01:00
Naga
1330feaea5 added webtoon original english support 2024-02-24 23:32:37 +01:00
103f578c61 Merge pull request #579 from NagaYZ/master
Update domains name
2024-02-24 12:19:58 +02:00
deee80ae71 Merge pull request #581 from NagaYZ/fix-popular-page-url
Fix popular page url
2024-02-24 12:19:37 +02:00
Naga
54350040ad fixed popular page url 2024-02-22 20:32:21 +01:00
Naga
3472b8ba00 Update ZinManga.kt 2024-02-22 17:09:36 +01:00
Naga
f2dd9af66c Update MagusManga.kt
fixed domain name and listurl acces
2024-02-22 16:56:55 +01:00
Naga
da46f7967a fixed bunch of domain name 2024-02-22 16:56:25 +01:00
Naga
ed3d6c5f98 Replaced GloryScans/GloryScansX with LunarScans/LunarHentai
domain changed
2024-02-22 16:55:28 +01:00
Naga
c4ea825df9 Replaced LightScans with Luascans , domain name changed 2024-02-22 16:54:49 +01:00
Naga
4120e3946c Update RagnarokScanlation.kt
new domain: ragnarokscanlation.net
2024-02-22 16:54:09 +01:00
Naga
c84b6acff2 Update EmperorScan.kt
new domain : emperorscan.com
2024-02-22 16:53:58 +01:00
Naga
159110c032 Update ResetScans.kt
new domain: reset-scans.xyz
2024-02-22 16:53:46 +01:00
Naga
93e1b38da2 Update MangaEsp.kt
new domain : mangaesp.net
2024-02-22 16:53:28 +01:00
3ff028c4e9 Merge pull request #572 from geexuan/baozimh_details_fix
Baozimh: Fix for not getting all chapter details
2024-02-18 08:25:57 +02:00
geexuans
9b46963015 Baozimh: Fix for not getting all chapter details 2024-02-17 16:04:24 +08:00
09e1c14f37 Merge pull request #565 from sandeepjak2007/Issue##561
Issue #561 Leading to non existing page
2024-02-14 12:03:01 +02:00
Sandeep Karanam
58af01b90a Issue #561 Leading to non existing page
Issue #561 fixed
2024-02-14 09:23:38 +05:30
e338237e2a [NudeMoon] Fix pages loading 2024-02-12 16:02:27 +02:00
014ea5ef49 [Manganato] Update domain 2024-02-10 14:30:10 +02:00
4a8c7fa36a Fix urlDecode usage 2024-02-07 09:33:33 +02:00
1251a6cd75 Merge pull request #548 from Ah3ron/patch-1
Fix tag filtering for Russian characters
2024-02-07 09:11:57 +02:00
Ah3ron
0ce8eae969 Fix tag filtering for Russian characters 2024-02-05 19:45:35 +03:00
devi
8b9c76fca5 LerYaoi #512
StellarSaber #533
Update Url ( #530 )
Remove dead sources
2024-02-03 11:00:02 +01:00
52e4e6b802 Update collections library 2024-01-31 15:04:00 +02:00
57c9d26916 Fix android compatibility 2024-01-31 14:45:39 +02:00
19d7003a9e [BatoTo] Fix pages parsing #521 #522 2024-01-31 14:31:06 +02:00
b11e50ab22 Fixes batch 2024-01-30 13:09:27 +02:00
a03ab0e0c0 Update tests 2024-01-30 11:16:28 +02:00
05d4db00b3 [ResetScans] Fix chapters names #518 2024-01-30 11:05:41 +02:00
f4aaa14fc5 Simplify workflow 2024-01-30 10:36:25 +02:00
a8f9423307 Migrate chapter number to float 2024-01-22 13:45:36 +02:00
7c871edbca Merge pull request #503 from mangadventure/master
Add MangAdventure sources (Arc-Relight, Assorted Scans)
2024-01-22 13:14:35 +02:00
ObserverOfTime
f7d9579cee Relax pagination test 2024-01-20 19:27:16 +02:00
ObserverOfTime
b7e6ca8a26 Add MangAdventure sources
- Arc-Relight
- Assorted Scans
2024-01-20 19:27:16 +02:00
8852d1e22e [Remanga] Attempt to fix No value for page id 2024-01-19 23:31:21 +03:00
fcaa0ea442 Add volume field to chapter 2024-01-17 15:03:33 +02:00
8e7d7e0bde Add some sources 2024-01-15 01:58:21 +03:00
scaledzdn
50c6c9f842 src: id/shinigami.kt: Change url source (#481)
* Previous url got banned on Indonesia
2024-01-13 13:40:06 +03:00
a2979753a9 [Grouple] Fix pages parsing 2024-01-12 18:10:58 +02:00
789e39b6cb Fixes batch 2024-01-11 17:36:07 +02:00
2f5441ef20 [Remanga] Use home url as authUrl 2024-01-09 20:15:56 +03:00
devi
6ad08f13d4 Add Comic1000, ThunderScans, WhaleManga, SussyScan, EDoujin, 3XYaoi, SussyScan #444
Url TeamXNovel, WestManga
Remove AzureManga, BabelToon, FranxxMangas, LsHistoria, MangaGenki, Wowomik, MiraiScans, Nonbiri, PeaceScans, ReaperScansTr, TurkToon
2024-01-09 17:51:16 +01:00
devi
656f621711 Remove bad import 2024-01-07 14:51:15 +01:00
devi
6dc0e12fb0 add filter on sources
Remove Komikgo redirect to ManhwaLand
Add Template PizzaReaderParser and move FmTeam
Add PhoenixScans, TuttoAnimeManga, LupiTeam, LadyEstelarScan, GtoTheGreatSite
2024-01-07 14:50:16 +01:00
0e8579017b [BatoTo] Fix pages parsing 2024-01-07 12:02:13 +02:00
devi
e03d0efe71 Fix FlixScansOrg and add filter 2024-01-05 19:24:36 +01:00
0b497c4e0b [ComicK] Fix branches names 2024-01-05 16:22:32 +02:00
devi
704f589b6d Add new filter on sources
Url GekkouScans, SssScanlator
Add LunarScan #435
2024-01-04 19:10:22 +01:00
3feb84ac9e Update some domains 2024-01-04 13:12:14 +02:00
e375654009 [ComickFun] Fix branches and titles 2024-01-04 13:06:37 +02:00
ce7ac5d8f4 [ExHentai] Fix tags and branch 2024-01-04 13:02:56 +02:00
devi
a172fa5a5b Add new filter on sources
Add BurningScans
2024-01-03 19:33:45 +01:00
7c89f53988 [ExHentai] Improve tags loading 2024-01-03 11:54:56 +02:00
4e2d739840 [Shinigami] Add user-agent changing option 2024-01-02 20:34:37 +03:00
devi
5cdbda700b Urls : DomalFansub, HentaiVN, PheTruyen, TruyentranhLH
Add : KomikSay, MangaLesen
Remove : 1stManhwa, ConsejoDeMatones, OzulScans, SugarLab, HyoManga, Mi2Manga
2024-01-02 17:53:45 +01:00
b274b51699 Improve filtering 2024-01-02 14:17:20 +02:00
efb5d34279 Merge pull request #431 from KotatsuApp/ExcludeTags 2024-01-02 12:51:43 +02:00
devi
9ecb75b51c Add ZScanlation, KomikGesn , Kenhuav2Scan
Fix MangaMate
2023-12-31 11:41:45 +01:00
69332a85da Add isTagsExclusionSupported flag 2023-12-31 09:51:09 +02:00
ea095084cc Fix some parsers 2023-12-31 09:27:17 +02:00
1f176ebab2 Update dependencies 2023-12-31 08:32:20 +02:00
devi
327c05d03e Fix Chapters madtheme
Url NettruyenBing
Remove Dead Sources :
AkuManga , CmReader, FalconManga, JaiminisBox, Manga3s, MangaCv, MangaLeks, UniToonOficial , 1stKissManga.tv, Manhwa2read, ManhuaMix, ManhuaDex, Hwago, ImmortalUpdates, KomikSay, MangaTx, Scan-Fr.org, QueenScans, PhantomScans, OpScanlations, NeuManga.net, ManhwaFreak.fr, Lady Estelar Scan, KomikManhwa, KomikManga, KaratcamScans, Boosei, LyraScans, MangaDiyari, MangaPro, NHentai.uk, Oxapk, SpiderScans, MangaNelo.biz, MangaOnline.team, SpartanManga
2023-12-30 11:09:56 +01:00
devi
2d7c120d19 Add Feature Content Rating Filter 2023-12-29 14:59:50 +01:00
devi
a2e9f19814 Fix Build 2023-12-29 14:16:56 +01:00
devi
c602355e65 Feature Add Exclude Tags 2023-12-29 13:57:01 +01:00
devi
a390e0de49 Fix ALPHABETICAL Sort on BentomangaParser
Remove Toonily.net
Add MonzeeKomik, Tresdaos
2023-12-29 13:55:04 +01:00
a228d71d57 Merge pull request #429 from KotatsuApp/Alpha-zaAndStateUpcoming
Add a new filter and a new state
2023-12-28 16:43:35 +02:00
devi
b2f0eaccc4 Remove Import Local 2023-12-28 10:55:20 +01:00
devi
07aaec7d3c Add template Scan and move ScanVfOrg in
Add ScanIta

Remove Mangastic -> redirect to toon69
Remove MangaGoYaoi -> redirect to asurascans.us
Remove Cizgiromanarsivi -> redirect to mangaoku.info
Remove WebtoonEvreni -> redirect to merlinscans.com
Remove GalaxyAction -> redirect to flixscans.com
Remove GalaxyAction -> redirect to kingofshojo.com
Remove aquamanga.live -> redirect to kingofshojo.com
Remove MangaReaderPro -> redirect to hadesnofansub.com

Urls : S2Manga.io, KomikzoId, Toon69, ReaperComics, ShadowXManga, TeamXNovel, YaoiFlix, MangaEmpress, MangaMukai.com, komikRemaja.cfd, MangaKyo, KomikMirror, ManhwaDesu, ManhwaIndo.sbs, ManhwaLand, Wowomik, LireScanVf.com, NhattruyenPlus
2023-12-28 10:54:52 +01:00
devi
392e9af944 New SortOrder.ALPHABETICAL_DESC
New MangaState.UPCOMING
2023-12-26 15:17:40 +01:00
904e0719eb [HitomiLa] Fix tag names 2023-12-25 19:48:33 +02:00
52ac3d2e6c Merge pull request #428 from AwkwardPeak7/hitomi
HitomiLa: fix thumbnails
2023-12-25 19:21:54 +02:00
devi
859b07e454 Add Ler999, ShadowCeviri 2023-12-25 17:02:06 +01:00
AwkwardPeak7
d4b252fd71 HitomiLa: fix thumbnails
I dismissed this in their scripts as the thumbnails worked fine but now they broke
2023-12-25 19:28:41 +05:00
4a0e7221b0 [HitomiLa] Refactor 2023-12-25 13:08:19 +02:00
43bdbe5a01 Merge pull request #426 from AwkwardPeak7/hitomi
Hitomi.la
2023-12-25 12:51:17 +02:00
3d10456a87 Apply suggestions from code review 2023-12-25 12:50:56 +02:00
d5a6c95ffb [MangaInUa] Fix chapters loading 2023-12-25 12:40:31 +02:00
devi
edc07b5dbd New Template GuyaParser
Add DankeFursLesen, GuyaCubari, Hachirumi, MahouShoujobu, Olaoe
Add local on sources GattsuParser
2023-12-24 12:00:06 +01:00
devi
a5219ceb6c New Template GattsuParser
Add Baozimh, MuitoHentai, TopReadManhwa, HentaiSeason, HentaiTokyo, MundoHentaiOficial, UniversoHentai
2023-12-23 18:59:48 +01:00
AwkwardPeak7
039075086e hitomi: better locale in tag search 2023-12-23 22:57:12 +05:00
AwkwardPeak7
495c9fad33 hitomi: formatting 2023-12-23 22:23:43 +05:00
AwkwardPeak7
b61c5e8f12 hitomi: locales 2023-12-23 20:29:16 +05:00
AwkwardPeak7
a40a8d329a simplify search a bit 2023-12-23 19:55:21 +05:00
AwkwardPeak7
3f3ab5a7be Hitomi.la 2023-12-23 19:14:51 +05:00
devi
d8c32047d0 Fix MangaATrend
Add LerManga
Remove ReaperScansPt.kt
2023-12-22 17:23:52 +01:00
devi
f5f2854f36 Add OnePieceEx 2023-12-20 20:02:31 +01:00
devi
86a2b95141 Add Comicaso, LectorManga, Mangaoku, MangaSehri.net, MangaTr, TempestFansub.net
Fix KomikCast
Url ElarcPage , InfraFandub
2023-12-19 20:42:49 +01:00
4db7ccc853 Tiny refactoring 2023-12-19 08:11:19 +02:00
b1da5c2924 [Mangaowl] Fix chapters parsing 2023-12-19 07:45:56 +02:00
devi
0fe6fed838 Merge pull request #418 from PhantomShift/patch-1
Fix MangaDex nsfw check
2023-12-17 18:09:23 +01:00
PhantomShift
a3f8c0a236 Fix MangaDex nsfw check
Additionally check for pornographic content rating when labeling a work as NSFW.
2023-12-17 10:49:12 -05:00
devi
c88d7de138 Add AComics, ReaperComics ( en ) 2023-12-17 14:48:54 +01:00
devi
eeafb3c6fd Fix JiangzaiToon #417 2023-12-17 11:58:29 +01:00
devi
0208f5be97 Add DatgarScanlation, HyoManga, HeckScans, MerlinScans, TraduccionesMoonlight, NinjaScan, Mi2MangaEs, ScanVfOrg
Url InariManga
Fix chapters MangaGeko
2023-12-16 17:24:54 +01:00
42ecf8a958 Merge pull request #413 from KotatsuApp/ZeistMangaParser
Add ZeistMangaParser
2023-12-16 08:06:03 +02:00
d780623b98 Merge pull request #406 from AwkwardPeak7/mplus
MangaPlus
2023-12-16 07:49:17 +02:00
devi
1b1a167580 Add EpikMan 2023-12-15 23:06:29 +01:00
devi
49d0c80070 Add MaxgsScan, WolfScanBr 2023-12-15 22:51:27 +01:00
devi
a35c2f3394 Add ZeistMangaParser and sources
add urldecode
ul VfScan
2023-12-15 22:04:47 +01:00
AwkwardPeak7
3034a87929 MangaPlus: divide different languages to avoid too many calls during chapter fetching & prevent some non-english titles to be filtered out 2023-12-15 18:34:27 +05:00
AwkwardPeak7
33b96043c9 Merge remote-tracking branch 'upstream/master' into mplus 2023-12-15 18:07:24 +05:00
devi
4d02dc0d12 Move FlixScansOrg to En
add MangasOnline , WorldManhwas
Url Shinigami
2023-12-14 18:18:18 +01:00
AwkwardPeak7
79fd2a58c1 MangaPlus: improvements 2023-12-14 19:19:32 +05:00
AwkwardPeak7
ab82d0eba0 MangaPlus 2023-12-13 21:18:57 +05:00
75cc0716fd Merge pull request #404 from AwkwardPeak7/999 2023-12-13 17:59:59 +02:00
87f99addbb Update SuspendLazy 2023-12-13 12:59:26 +02:00
AwkwardPeak7
3e1b15a23c review changes 2023-12-12 23:35:07 +05:00
devi
5758e9f68f Add BentoScan, Manga18.xyz, NewManhua
Url MangaScan, Anime-Sama.me
Fix DoujinDesu.tv
2023-12-12 18:29:01 +01:00
AwkwardPeak7
0964c02a44 largeCover and better chapter branch name 2023-12-12 18:55:15 +05:00
AwkwardPeak7
bf06ab7492 use SuspendLazy for fetching cdn host 2023-12-12 17:27:38 +05:00
AwkwardPeak7
e992566899 999Hentai 2023-12-12 14:01:36 +05:00
devi
97338f31c5 Add IrisScanlator #403
Add RagnaScan
Fix VexManga
2023-12-11 17:21:44 +01:00
devi
0ff4f976e1 Fix FlixScans
Add FlixScansOrg
Add DoujinKu
2023-12-10 20:28:35 +01:00
devi
496b3388ee Add source : MangaPark , GekkouScans, YuriLab 2023-12-09 17:19:43 +01:00
devi
d6b578acb0 Add, fix sources
Manual addition of lang on Bato.To
Add multi tag , lang and rework tags on exhentai
Add lang on imhentai
2023-12-08 17:18:23 +01:00
b3be87f541 Update readme 2023-12-08 07:27:35 +02:00
devi
786cd12dba Add, fix sources
Add language on Bato.To
2023-12-06 19:24:15 +01:00
devi
a1a17c02d7 Add, fix sources
Add language on Bato.To
2023-12-06 19:23:46 +01:00
devi
b8caf8e572 Minor update. 2023-12-05 17:37:07 +01:00
44c2c074a8 [MangaDex] Language filter support 2023-12-05 13:39:07 +02:00
3ed960254d [GalleryAdults] Language filter support #357 2023-12-05 13:05:11 +02:00
f1e8fbec5d Merge pull request #401 from KotatsuApp/filter
Rework getList
2023-12-05 11:26:17 +02:00
c5ed9cf54b Merge pull request #400 from deividgabrielpeira/master
Neoxscan change url
2023-12-05 11:25:03 +02:00
devi
65c567dbcb Fix NHentaiParser 2023-12-04 18:16:56 +01:00
devi
b312823afd Merge remote-tracking branch 'origin/master' 2023-12-03 12:57:14 +01:00
devi
56eb059bcd fix getlist VmpParser, LineWebtoonsParser, BlogTruyenParser, HentaiVNParser, YurinekoParser
add filter on WpComicsParser, ZMangaParser, LxManga, Truyenqq, TruyentranhLHParser

Move NetTruyen to template WpComicsParser and add multitags on WpComicsParser
2023-12-03 12:56:52 +01:00
devi
6ad78f1cba fix getlist OtakuSanctuaryParser, bakai , brmangas, LerMangaOnline, MangaOnline, YugenMangas, MangaAy, SadScans, YaoiFlix
add filter on SinmhParser, TrWebtoon
2023-12-02 16:41:37 +01:00
devi
26b758ae50 fix getlist some source mangaeader, MmrcmsParser
add filter on NepnepParser
2023-12-01 18:50:34 +01:00
devi
019b8cc087 fix getlist some source mangaeader, MmrcmsParser
add filter on NepnepParser
2023-12-01 18:49:30 +01:00
Deivid Gabriel Pereira de Oliveira
c95845083a Neoxscan change url 2023-12-01 16:48:41 +00:00
9c7f314f65 [HentaiUkr] Add usage of objects69.json 2023-12-01 02:48:00 +03:00
devi
743a92a3e8 remove import 2023-11-30 18:46:52 +01:00
devi
37e9b33c24 add filter : LikeMangaParser, FmTeam, MadthemeParser , MangaReaderParser
Fix GetList : NicovideoSeigaParser, Manga18Parser

add filter & multitags on MangaboxParser
2023-11-30 18:46:10 +01:00
devi
7c2ac033d7 add filter on HeanCms , DoujinDesu.tv
Fix GetList GalleryAdultsParser
2023-11-29 18:31:26 +01:00
0efd5437f9 [HentaiUkr] Fix objects loading 2023-11-29 17:18:01 +02:00
devi
db770351f3 add filter on FmreaderParser, LugnicaScans
Fix GetList on FoolSlideParser , FuryoSociety , LegacyScans, LireScan, ScansMangas.me, ScantradUnion
2023-11-28 21:07:54 +01:00
devi
14b2457627 fix getlist TempleScanEsp
fix getlist and add tag on Details mangas TuMangaOnline
2023-11-27 18:57:47 +01:00
devi
f62ea43de8 fix getlist on AnimeBootstrapParser, ImHentai, beetoon, CloneManga, MangaGeko, Po2Scans, Pururin
add filter FlixScans, TeamXNovel, ComicExtra, MangaOwl.to, MangaTown, Manhwa18.net, ManhwasMen

fix getlist and add tag list on DynastyScans
fix getlist and add SortOrder.UPDATED on MangaStorm
2023-11-26 18:44:34 +01:00
devi
ab2aad6bd0 add filter on bentomanga
add filter on ninemanga
2023-11-25 20:52:02 +01:00
devi
1293233ad9 fix getListPage Some sources madara 2023-11-25 20:04:47 +01:00
devi
5fff2adbfb MadaraParser add filter.states
- Some sources madara, need to be changed too
2023-11-25 17:57:38 +01:00
devi
7d67b718a5 Mangadex add filter.states and info states 2023-11-25 17:45:31 +01:00
devi
b8ca21d588 unwanted change 2023-11-25 17:37:04 +01:00
devi
44d91e43ad Add altName on ComicK
Change oneOrThrowIfMany on Bato.To
2023-11-25 17:34:52 +01:00
3bb10ee948 [HentaiUkr] Url hotfix 2023-11-25 19:22:42 +03:00
devi
81caa59a36 Add status filter support
Add oneOrThrowIfMany() on MangaState
2023-11-25 17:06:21 +01:00
46e863ef79 [ComicK] Fix manga state 2023-11-25 17:12:44 +02:00
cecba7623e [ComicK] Fixes and status filter support 2023-11-25 14:44:04 +02:00
7dee865c8a Merge pull request #397 from deividgabrielpeira/master
Daily Update (extensions portuguese)
2023-11-25 13:06:57 +02:00
Deivid Gabriel Pereira de Oliveira
5ac3cdb03c Arkham Scan -> HuntersScan (Fusion) 2023-11-24 12:28:54 +00:00
c3613f3ba4 [Grouple] Migrate to the new getList 2023-11-23 12:20:30 +02:00
e7ac1c1feb Fix PagedMangaParsers 2023-11-23 12:13:32 +02:00
24573d12f5 Fix compiling 2023-11-23 11:32:14 +02:00
9d2f633e14 Merge branch 'feature/filter-ex' 2023-11-23 11:20:26 +02:00
570b0c19c5 Merge pull request #388 from deividgabrielpeira/master
Daily Update (extensions portuguese)
2023-11-23 11:15:34 +02:00
Deivid Gabriel Pereira de Oliveira
a11e42a4d6 Merge branch 'KotatsuApp:master' into master 2023-11-19 14:50:31 -03:00
devi
410c73a74f Add multi tag some sources
Add SortOrder.POPULARITY some sources
Add all language on GalleryAdultsParser
fix YugenMangas (pt)
2023-11-19 17:58:10 +01:00
devi
3ea088371b Minor daily update 2023-11-18 20:44:35 +01:00
Deivid Gabriel Pereira de Oliveira
09a0bb364a HentaiSSSSSS (is closed) 2023-11-18 17:30:45 +00:00
Deivid Gabriel Pereira de Oliveira
d91947ae15 NocturneSummer fix? 2023-11-18 17:21:44 +00:00
Deivid Gabriel Pereira de Oliveira
0a8a9e5935 NocturneSummer fix 2023-11-18 17:18:31 +00:00
Deivid Gabriel Pereira de Oliveira
59226b298f apenasmaisumyaoi fix 2023-11-18 17:16:24 +00:00
Deivid Gabriel Pereira de Oliveira
dc41bf3e83 ArthurScan Fix 2023-11-18 16:06:30 +00:00
Deivid Gabriel Pereira de Oliveira
a790a18f7f test 2023-11-18 16:04:21 +00:00
Deivid Gabriel Pereira de Oliveira
1fcc1096f5 ArthurScan add Catalog (pt) and (test) 2023-11-18 15:59:47 +00:00
Deivid Gabriel Pereira de Oliveira
86aaca271f Merge branch 'KotatsuApp:master' into master 2023-11-18 12:41:55 -03:00
Deivid Gabriel Pereira de Oliveira
b8cc2d6953 Animaregia (Down) 2023-11-18 14:48:56 +00:00
11f110b0bb Merge pull request #385 from KotatsuApp/add-hiatus
add hiatus
2023-11-18 16:09:02 +02:00
Deivid Gabriel Pereira de Oliveira
31459ea6e7 yaoitoshokan (closed the site) 2023-11-18 12:58:48 +00:00
Deivid Gabriel Pereira de Oliveira
7ab84688c2 LerYaoi (down), posting in telegram 2023-11-18 12:56:12 +00:00
Deivid Gabriel Pereira de Oliveira
d18f287804 NocturneSummer fix 2023-11-18 12:44:41 +00:00
Deivid Gabriel Pereira de Oliveira
1c3b41acba Nocsummer, yaoi site, necessary (ContentType.HENTAI) 2023-11-18 12:42:15 +00:00
Deivid Gabriel Pereira de Oliveira
ecfc7e40c9 HiperCool, change url 2023-11-18 12:29:55 +00:00
41eea1c420 Set jvmTarget to 8 2023-11-18 14:28:13 +02:00
Deivid Gabriel Pereira de Oliveira
594524afc3 apenasmaisumyaoi change name, possibly the url will be changed 2023-11-18 12:16:12 +00:00
Deivid Gabriel Pereira de Oliveira
70a5337604 AkumanoTenshi -> tatakaeScant (fusion) 2023-11-18 12:12:02 +00:00
Deivid Gabriel Pereira de Oliveira
924fde8790 CeriseScans, change url 2023-11-18 11:58:45 +00:00
dea70974bf Revert unwanted changes 2023-11-18 13:03:09 +02:00
43fd7b8d47 [HoneyManga] Fix images urls 2023-11-18 12:55:02 +02:00
devi
6c2a526aeb rename 2023-11-18 11:27:38 +01:00
43a8caa687 Advanced filtering support 2023-11-18 10:22:35 +02:00
devi
f3fc848b6c Minor daily update 2023-11-17 17:54:57 +01:00
devi
98f5d115b3 Minor daily update 2023-11-16 17:55:13 +01:00
devi
885d98cebd Minor daily update 2023-11-15 18:37:47 +01:00
devi
6f73ff23e8 Minor update 2023-11-14 20:48:06 +01:00
2cd2d7dbc4 Merge pull request #368 from deividgabrielpeira/master
Update Daily
2023-11-14 07:31:22 +02:00
devi
d3afdad95b Minor update 2023-11-12 12:35:41 +01:00
Deivid Gabriel Pereira de Oliveira
48ac46eb5c chance url VexManga : Source url changed #370 2023-11-11 14:52:13 +00:00
Deivid Gabriel Pereira de Oliveira
2d6e6b359b they'll shut down leitorizakaya, they'll switch to blackoutcomics, it makes more sense to put it on madara, because they've made their own website. 2023-11-11 14:00:31 +00:00
Deivid Gabriel Pereira de Oliveira
7462743be8 se não funciona, so na proxima 2023-11-10 15:01:07 +00:00
Deivid Gabriel Pereira de Oliveira
db2acb752a fix 2023-11-10 14:55:37 +00:00
Deivid Gabriel Pereira de Oliveira
335229e61b fix error thanks @ztimms73 2023-11-10 14:48:25 +00:00
Deivid Gabriel Pereira de Oliveira
2acdd66f70 fix again 2023-11-10 14:42:42 +00:00
Deivid Gabriel Pereira de Oliveira
d3bec9006e Fix uppercase in parser 2023-11-10 14:40:23 +00:00
Deivid Gabriel Pereira de Oliveira
44f70c1388 Merge branch 'KotatsuApp:master' into master 2023-11-10 11:08:33 -03:00
02463e5833 [MangaReader] Fix NetShield bypass 2023-11-10 13:06:13 +02:00
Deivid Gabriel Pereira de Oliveira
778d14a1a2 change mangaSource 2023-11-09 22:27:19 +00:00
Deivid Gabriel Pereira de Oliveira
8b3814c485 , 2023-11-09 20:21:28 +00:00
Deivid Gabriel Pereira de Oliveira
6bcd9dd65c mudou de nome 2023-11-09 20:18:26 +00:00
154ae09c6e [MangaReader] Add NetShield bypass (testing) #198 2023-11-07 18:33:22 +02:00
devi
58c9d14d42 Minor daily update 2023-11-06 20:24:12 +01:00
3e69b88518 Update dependencies 2023-11-06 10:42:04 +02:00
devi
9d3671e117 Minor daily update 2023-11-05 18:07:37 +01:00
devi
0731d2487a Minor daily update 2023-11-05 18:07:12 +01:00
devi
5e4dd82b8d Minor daily update 2023-11-04 18:56:46 +01:00
devi
9d33d1a560 Minor daily update 2023-11-03 18:28:00 +01:00
devi
e788cff04a Minor daily update 2023-11-02 19:36:26 +01:00
face1d5b26 Merge pull request #355 from KotatsuApp/GalleryAdultsParser
Add GalleryAdultsParser
2023-11-02 08:52:39 +02:00
devi
18f8472baa Add GalleryAdultsParser
reworking some sources
add sources
2023-11-01 21:28:36 +01:00
devi
f14edd871f Minor daily update 2023-11-01 17:22:52 +01:00
c892a38c52 Trigger rebuild 2023-11-01 16:25:49 +02:00
devi
e9d473711d Minor daily update
- Fix tag ninemanga
- Fix search neonep parsser
2023-10-31 19:03:28 +01:00
devi
97a8bb1ca7 Minor daily update 2023-10-30 18:57:42 +01:00
devi
66d47bf579 Minor daily update 2023-10-29 18:31:35 +01:00
devi
508647eb5a Minor daily update ( and remove warning for name ) 2023-10-28 22:22:01 +02:00
4ca3a492b0 [ComicK] Fix genres 2023-10-28 12:40:00 +03:00
devi
fffe104cbe Minor daily update 2023-10-27 18:48:33 +02:00
devi
6258476a58 Minor daily update 2023-10-26 18:11:42 +02:00
devi
af1aca8725 Merge remote-tracking branch 'origin/master' 2023-10-25 17:51:04 +02:00
devi
bdb7fbc039 Minor daily update 2023-10-25 17:50:58 +02:00
6bf0ae92e4 [*chan] Fix sort orders 2023-10-25 13:36:42 +03:00
17b8fd51b7 [ComicK] Fix chapters numbers 2023-10-25 12:53:48 +03:00
d089fad6ce [MangaLib] Add branching support 2023-10-25 12:48:44 +03:00
ec11b79b18 [MangaLib] Fix search result covers 2023-10-25 12:22:10 +03:00
0f216c6de9 [Remanga] Fix loading large amount of chapters 2023-10-25 12:09:41 +03:00
devi
0606ace83a Merge pull request #328 from deividgabrielpeira/master
HentaiGekkout(pt)
2023-10-24 17:04:56 +02:00
Deivid Gabriel Pereira de Oliveira
746d857550 I forgot about Hentai Gekkou, which is part of Gekkou, which was taken down together by the DMCA. 2023-10-24 12:04:43 +00:00
devi
cf1d0b8d7e Merge pull request #327 from deividgabrielpeira/master
GekkouScan(pt) and FinalScans(pt), is down
2023-10-24 08:20:42 +02:00
Deivid Gabriel Pereira de Oliveira
d94145c6e5 GekkouScan(pt), has been taken down by the DMCA
FinalScans(pt), just closed
2023-10-24 00:42:56 +00:00
devi
b71a0ac3cf Minor daily update 2023-10-23 18:24:51 +02:00
devi
32afa26be5 Minor daily update 2023-10-22 20:15:17 +02:00
devi
23cc86e429 Minor daily update 2023-10-21 21:20:48 +02:00
devi
87032a6835 Minor daily update 2023-10-20 15:28:14 +02:00
devi
a4d9c6e36c Minor daily update 2023-10-19 18:46:07 +02:00
devi
76af0b0edb Minor daily update 2023-10-17 18:49:33 +02:00
0054d06e6e Fix sources titles 2023-10-17 09:49:38 +03:00
devi
e2e027df81 Minor daily update 2023-10-16 19:54:49 +02:00
a61e441e79 Merge pull request #283 from KotatsuApp/devi4
add sources and fix
2023-10-16 12:39:36 +03:00
devi
9b4153aacc fix 2023-10-15 10:12:20 +02:00
devi
b1d2d0a475 add Fakku 2023-10-14 16:43:42 +02:00
devi
aeec98db2a Rework tag hentaivn 2023-10-14 10:58:47 +02:00
devi
00f21de9eb quick fix 2023-10-14 10:28:30 +02:00
devi
2d595bb6ee Add small sources, fix , rename sources , remove code not used, remove dead sources, typo. 2023-10-14 10:10:21 +02:00
devi
e43c9f6489 Add small sources, fix , rename sources , remove code not used, remove dead sources, typo. 2023-10-14 10:08:00 +02:00
devi
81004b53a9 add Yaoi Flix 2023-10-13 18:38:36 +02:00
devi
85a0918da5 add Manga Ay 2023-10-13 17:38:02 +02:00
devi
b10fa0fd10 add change requested and fix url 2023-10-13 16:15:19 +02:00
a2f4bb35cd [*chan] Fix title parsing 2023-10-13 13:34:07 +03:00
devi
4120514256 add search on manga online 2023-10-12 19:39:15 +02:00
devi
29ef717ece add sources and fix 2023-10-12 18:56:49 +02:00
devi
d34cfbf405 add sources and fix 2023-10-12 18:56:20 +02:00
devi
94c2326153 Rework Yugen Mangas 2023-10-11 19:49:59 +02:00
devi
06c2287b71 fix 2023-10-11 17:47:14 +02:00
devi
8cb0d3d6fe Tag reduction on Pururin 2023-10-10 17:24:22 +02:00
devi
76860f82b9 add sources and fix 2023-10-10 17:17:06 +02:00
devi
f134137a05 add sources and fix 2023-10-09 17:58:43 +02:00
devi
fc231ec330 fix Asura Scans 2023-10-08 21:28:13 +02:00
devi
d3c32faf01 Tag reduction on hentaifox 2023-10-08 18:38:32 +02:00
devi
d16f4cd892 add ImHentai 2023-10-08 17:31:01 +02:00
devi
9a8de28a1d add Pururin 2023-10-08 15:29:25 +02:00
devi
939f08b8a1 add Mirai Scans 2023-10-08 09:55:59 +02:00
devi
09500c0734 add sources and fix 2023-10-07 17:10:29 +02:00
400a90464e [LineWebtoons] Refactoring 2023-10-06 10:36:51 +03:00
9103f9d473 Merge pull request #273 from DCNick3/line-webtoons-source
Add Line Webtoons sources (webtoons.com)
2023-10-06 09:47:45 +03:00
devi
27c29f99d9 minor fixes and add small sources 2023-10-04 17:14:12 +02:00
Nikita Strygin
753c27a90c Clean up code after review
- Do not use ConfigKey.Domain for supplementary domains
- use IllegalArgumentException
- use "$var" instead of "${var}" where possible
- fix the language in `publicUrl`
- use `?` to handle `largeCoverUrl`
- use `requireNotNull` instead of `!!`
2023-10-04 15:19:27 +03:00
3d7e62d2fe [MintManga] Update domain 2023-10-04 14:02:09 +03:00
e8289277a7 Merge pull request #274 from KotatsuApp/devi3
Add sources
2023-10-04 13:21:54 +03:00
Nikita Strygin
887fc691d1 Add support for more languages in Line Webtoons parser
Also change the default sorting to POPULARITY & clean up
2023-10-04 12:03:21 +03:00
devi
543e3da194 Add sources 2023-10-03 18:25:43 +02:00
devi
908cc22619 Minor fix 2023-10-03 16:55:32 +02:00
Nikita Strygin
c09d484a14 Add Line Webtoons sources (webtoons.com)
It uses the API of mobile app
2023-10-03 09:15:39 +03:00
07c3f22f75 Merge pull request #268 from VietAnh14/source/yurineko 2023-10-02 20:08:08 +03:00
devi
d494bf19ee Small fix 2023-10-02 17:29:07 +02:00
vianh
eda4f75219 [Yurineko] Fix api domain and chapters order 2023-10-02 21:21:58 +07:00
931f126119 Merge pull request #269 from deividgabrielpeira/patch-1
prismascan chance Domain
2023-10-02 13:19:59 +03:00
bc171ce06e [Grouple] Fix pumpkins 2023-10-02 13:19:36 +03:00
Deivid Gabriel Pereira de Oliveira
191d1fcec8 prismascan chance Domain 2023-10-01 21:01:05 -03:00
vianh
eaea9e54d1 [Yurineko] New source 2023-10-01 20:27:51 +07:00
devi
c9b3912fd4 Quick small fix 2023-10-01 00:01:20 +02:00
1611dc3429 Remove duplicated classes 2023-09-30 17:24:47 +03:00
88dc2145e0 Merge branch 'AwkwardPeak7-ksk' 2023-09-30 17:09:27 +03:00
8979987344 Merge pull request #266 from KotatsuApp/devi2
Update focus on fix and remove dead sources
2023-09-30 17:05:04 +03:00
AwkwardPeak7
1cec2cc187 remove need for refreshing chapter list 2023-09-29 20:29:14 +05:00
devi
a1279b64a2 small fix and sources 2023-09-29 17:21:38 +02:00
AwkwardPeak7
2ce5f2563a KskMoe: get original quality images 2023-09-29 19:29:57 +05:00
devi
75a60ff738 fix Union Mangás 2023-09-28 20:04:46 +02:00
devi
74eb7f83d6 other fix 2023-09-28 17:24:02 +02:00
devi
5b2ac5f6fb typo 2023-09-27 18:51:10 +02:00
devi
fde4ba1d85 remove mangatone 2023-09-27 18:45:56 +02:00
devi
8278a8f5c3 multiples fix, remove dead source and add source 2023-09-27 18:44:09 +02:00
a39d644094 [Remanga] Ability to change user-agent 2023-09-27 17:11:00 +03:00
0004be15ba Merge branch 'source/devi' 2023-09-20 12:11:03 +03:00
8fef459346 Misc fixes 2023-09-20 12:09:54 +03:00
109603f124 [HentaiUkr] Fix ids 2023-09-20 10:04:15 +03:00
91879a8405 Merge pull request #261 from CakesTwix/master
[HentaiUkr] Tag ID is String now
2023-09-20 09:43:33 +03:00
devi
f471a3513e add mangashiro.me and fix 2023-09-19 18:48:26 +02:00
CakesTwix
7362111318 [HentaiUkr] Tag ID is String now 2023-09-19 11:29:52 +03:00
devi
609c7188c0 add sources tr 2023-09-18 19:48:24 +02:00
devi
a106b34379 add sources and fix 2023-09-18 18:39:05 +02:00
devi
853b95363e add missing content type 2023-09-17 19:49:21 +02:00
devi
45113e419e small fix 2023-09-17 17:18:09 +02:00
devi
519bb3053b add ksk 2023-09-17 16:57:50 +02:00
devi
366cc862ba remove 1stkissmanga.me and add likemanga 2023-09-17 13:12:35 +02:00
devi
611aaf0d38 remove mirrordesu 2023-09-17 10:52:27 +02:00
devi
712d829b54 add sources 2023-09-17 10:50:01 +02:00
devi
e25656c090 reformat 2023-09-17 09:35:58 +02:00
devi
7debe6d7e2 add sources 2023-09-16 17:07:59 +02:00
devi
55e14e4cb3 add sources 2023-09-16 17:07:22 +02:00
7fbeb2e266 Add gradle jvmargs 2023-09-12 19:22:36 +03:00
7be6d779da Reformat 2023-09-12 19:15:57 +03:00
96585fbdf7 [DesuMe] Add alternate domain 2023-09-12 18:27:04 +03:00
1a0d623c02 Merge pull request #252 from davvarrr/master
adds sources and fix
2023-09-12 18:25:55 +03:00
67cf2c2a6e Revert MangaSources changes 2023-09-12 18:24:13 +03:00
b6dd7fb5f6 [HentaiUkr] Fixes 2023-09-12 18:23:34 +03:00
e0c5562600 Merge pull request #251 from CakesTwix/master
New 18+ UA Source and update urls in `CONTRIBUTING.md`
2023-09-12 13:47:20 +03:00
devi
2447f66834 change domain 2023-09-10 09:33:10 +02:00
devi
11ed27e397 correction 2023-09-09 18:12:19 +02:00
devi
6158547571 correction 2023-09-09 18:10:16 +02:00
devi
a24dfde1ba correction 2023-09-09 18:09:58 +02:00
devi
d805b49a4d adds sources and fix 2023-09-09 17:12:20 +02:00
devi
f871bf77fa Merge remote-tracking branch 'origin/master' 2023-09-09 17:11:36 +02:00
devi
be610b825d adds sources and fix 2023-09-09 17:11:14 +02:00
f791cc6f9c Added SoftSuspendLazy class 2023-09-09 16:36:13 +03:00
CakesTwix
30b2e81b15 [CONTRIBUTING] Update example urls
380861f29e
2023-09-08 20:51:36 +03:00
CakesTwix
067c7f2d0d [HentaiUkr] New 18+ UA Source 2023-09-08 20:51:25 +03:00
aae3fa3b05 Add abandoned state 2023-09-08 13:19:26 +03:00
41cd8ac7d7 Merge pull request #250 from CakesTwix/master
[HoneyManga] Change search url
2023-09-08 13:09:34 +03:00
CakesTwix
61f2a499da [HoneyManga] Change search url 2023-09-08 12:46:18 +03:00
2f7e704e21 [MangaLib] Check page response size 2023-09-03 18:55:55 +03:00
4d22e7d1e8 Merge pull request #243 from davvarrr/master
Add sources and fix
2023-09-03 18:30:44 +03:00
devi
18125ea982 fix url Ozulscans 2023-09-03 09:52:55 +02:00
devi
1498541b45 fix url Nivera Fansub 2023-09-02 16:27:24 +02:00
devi
4faaa9fc13 fix url Manhwalist 2023-09-02 13:35:27 +02:00
devi
c6c4b7190a fix url Random Scans 2023-09-02 10:09:33 +02:00
devi
c0bf3ad56c add RackusReads 2023-09-01 12:28:10 +02:00
devi
ad51271c40 format code 2023-09-01 12:14:32 +02:00
devi
fce952d240 change request and change url Nettruyenmax & NetTruyen 2023-09-01 12:13:57 +02:00
devi
0dc5032a7a change url Shinigami 2023-08-31 19:22:51 +02:00
devi
0395f29503 small change 2023-08-31 12:31:28 +02:00
devi
03581add21 add Perf Scan and fix Legacy Scans 2023-08-31 12:26:13 +02:00
devi
e0249accf8 fix domain Mgkomik 2023-08-31 09:46:19 +02:00
devi
a3afbafdcc remove small code 2023-08-30 18:03:45 +02:00
devi
4d4c126327 remove dead source 2023-08-30 17:50:26 +02:00
devi
c4bf7b2ae0 add sources and fix 2023-08-30 13:45:40 +02:00
devi
5d5f804c76 add sources and fix 2023-08-30 13:44:25 +02:00
3a76504380 [NepNep] Fixes 2023-08-24 14:16:47 +03:00
5035c90c73 Merge pull request #238 from davvarrr/master
add source and move Manga4Life to tempalte parser
2023-08-24 13:55:16 +03:00
devi
7f1cd30ce8 change domaine for QueenScans 2023-08-21 20:49:36 +02:00
devi
155a91a13d add Mangarbic 2023-08-21 12:19:54 +02:00
devi
8c291e274d nothing 2023-08-21 10:36:38 +02:00
devi
10e1eb8aac add source and move Manga4Life to tempalte parser
and fix url Duniakomik
2023-08-21 10:33:47 +02:00
06a2aa6f97 [Manga4Life] Refactoring and fixes 2023-08-19 17:38:57 +03:00
f08a2e4551 Merge pull request #235 from davvarrr/master
add sources and fix
2023-08-19 17:18:05 +03:00
e6839b1270 [Grouple] Change getPageUrl exception 2023-08-19 16:53:42 +03:00
270890f841 [NudeMoon] Migrate to mobile website parsing 2023-08-19 16:51:03 +03:00
devi
02581c9e2d Change and add Manga4Life 2023-08-19 15:38:40 +02:00
devi
ea4e69df19 remove japscan 2023-08-19 08:40:03 +02:00
devi
cb0ebb31f7 add more source 2023-08-18 20:03:31 +02:00
devi
497cd0bd15 add more source 2023-08-18 19:58:01 +02:00
devi
b74c7841dd add sources and fix 2023-08-18 17:39:35 +02:00
407ef5b655 Merge pull request #232 from davvarrr/master
quick fix
2023-08-14 09:54:20 +03:00
devi
f034b1874b add Mangakakalot 2023-08-13 11:26:29 +02:00
devi
eac086b935 add jaiminisbox 2023-08-13 09:26:20 +02:00
devi
ea310b184e add MangaCrab and MantrazScan 2023-08-13 09:20:15 +02:00
devi
ea3386eda5 add MangaCrab and MantrazScan 2023-08-13 09:19:52 +02:00
devi
2efdb1940a fix Asura Scans 2023-08-13 09:00:57 +02:00
devi
896139a8ed Add exception for source don't support multi tags
and other fix
Add birdToon
2023-08-12 15:24:27 +02:00
devi
da344233f4 quick fix 2023-08-11 18:30:48 +02:00
9cf3551356 [HentaiVN] Fix async/await 2023-08-11 12:01:32 +03:00
10aaae1ca8 Merge pull request #229 from davvarrr/master
Add template FoolSlideParser ands sources
2023-08-11 11:44:19 +03:00
dcb5206272 Add minus operator to favicons 2023-08-11 11:20:27 +03:00
devi
ccdd2b6c19 fix TuMangaOnlineParser 2023-08-10 17:47:01 +02:00
devi
16f3e1c180 add Ninja Scan 2023-08-09 21:10:24 +02:00
devi
7283cde5ff add missing contenttype 2023-08-09 21:01:43 +02:00
devi
4c20384d39 add sources and small fix 2023-08-09 20:59:03 +02:00
devi
5e9bc4fcc7 fix async and remove .imageUrl() to add .src() 2023-08-09 19:49:19 +02:00
devi
e5448649c3 fix pagination HentaiVNParser 2023-08-07 22:27:18 +02:00
devi
951e89d429 add rating on MadaraParser 2023-08-07 19:24:56 +02:00
devi
f34dd7926a add skanlacje-feniksy and fix hentaivn 2023-08-07 17:44:25 +02:00
devi
b900c05d9b Merge remote-tracking branch 'origin/master' 2023-08-06 22:45:34 +02:00
devi
06948934ac and sources 2023-08-06 22:45:14 +02:00
devi
e82915ef17 Merge branch 'KotatsuApp:master' into master 2023-08-06 17:56:52 +02:00
devi
bb37da403f Add template FoolSlideParser ands sources 2023-08-06 17:56:17 +02:00
065263a9bd Merge pull request #227 from davvarrr/master 2023-08-06 10:35:45 +03:00
devi
f3359cc830 quick fix hentai20 move to tempalte mangareader 2023-08-06 09:22:00 +02:00
1b3b5d95c0 Merge pull request #226 from davvarrr/master
fix and add sources
2023-08-06 09:00:10 +03:00
c290ba5436 Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/DynastyScans.kt 2023-08-06 09:00:04 +03:00
devi
bb4ea05375 fix domaine peacescans 2023-08-05 18:18:25 +02:00
devi
47dde65f65 fix and add sources 2023-08-05 18:04:13 +02:00
08eb9552d6 Update gradle, kotlin and enum extensions 2023-08-04 15:58:57 +03:00
6058221fec Merge pull request #223 from davvarrr/master
add templates and sources and fix
2023-08-02 10:05:16 +03:00
devi
5bf4ecb394 min change 2023-07-31 20:28:01 +02:00
devi
41fa80e8b8 Change .src() in accord of commit 3c43590 2023-07-31 20:22:56 +02:00
devi
0dd3a26080 no pagination 2023-07-31 20:12:37 +02:00
devi
fb400d83e3 q fix 2023-07-31 19:54:21 +02:00
devi
37e5c43e5c Merge branch 'KotatsuApp:master' into master 2023-07-31 19:50:21 +02:00
341aa0e13d [JapScan] Migrate to desktop version 2023-07-31 15:08:46 +03:00
3c4359096d Add Jsoup extensions 2023-07-31 13:01:59 +03:00
devi
d56240086c Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/zmanga/ZMangaParser.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2023-07-31 11:58:33 +02:00
devi
bfea5b314e Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/ScansMangasMe.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2023-07-31 11:58:22 +02:00
03b4fc9f00 Add Result utils 2023-07-31 09:53:21 +03:00
devi
826563694e add MangaboxParser and sourcres 2023-07-30 21:53:10 +02:00
devi
880ff923bc add AnimeBootstrapParser and sources 2023-07-30 15:11:44 +02:00
devi
cd0d4b103a add zmanga and soruces 2023-07-30 12:31:28 +02:00
devi
fefec4985d add Wpcomics and sources 2023-07-29 16:18:58 +02:00
devi
ba655f3d64 add domain and fix search url 2023-07-29 09:30:44 +02:00
devi
be3812fa2f fix pagination komikcast 2023-07-29 09:04:25 +02:00
devi
87d4326411 add MadthemeParser and sources 2023-07-29 08:11:51 +02:00
devi
ef6ede6b12 add correct page for UPDATED 2023-07-28 17:07:29 +02:00
devi
eeccda24b0 Add 2 source more typo and add val on gettags on madara for site not let list /manga/ 2023-07-28 16:53:17 +02:00
devi
2bf29da2ea small fix and rename bad typo 2023-07-28 16:16:13 +02:00
devi
0b54029e26 Merge remote-tracking branch 'origin/master' 2023-07-28 15:58:14 +02:00
d24ab347cb Move CloudFlareProtectedException to test sources 2023-07-28 14:35:13 +03:00
74ffe9418b Fix html descriptions 2023-07-28 10:49:20 +03:00
c945434d71 Merge pull request #222 from davvarrr/master
add new template and source
2023-07-28 10:38:22 +03:00
devi
b28545c852 add sources 2023-07-27 20:50:53 +02:00
devi
c8d33d06a1 add fmreader 2023-07-27 20:27:56 +02:00
devi
2089c3cc7b fix import name 2023-07-27 17:16:27 +02:00
devi
5df1da2bfd fix nswf 2023-07-27 16:52:56 +02:00
devi
70fda48983 fix nswf 2023-07-27 16:52:31 +02:00
devi
36fe5cb625 Merge branch 'KotatsuApp:master' into master 2023-07-27 16:45:45 +02:00
devi
7e2a00520b fix and add updated on template Mmrcms 2023-07-27 16:42:28 +02:00
caeeb699d1 Add content type field to sources 2023-07-27 16:33:46 +03:00
devi
f6dc4f9a00 add source 2023-07-26 19:04:43 +02:00
devi
28135aed66 add 2 new template and new source 2023-07-25 21:30:07 +02:00
8e452f4271 [MangaLib] Fix Android compatibility 2023-07-24 20:09:27 +03:00
f4656efebd Update packages structure 2023-07-24 20:02:08 +03:00
42cc0430f8 Merge pull request #220 from davvarrr/master
fix some source and add source
2023-07-24 15:54:21 +03:00
81dd8b58c8 Merge pull request #219 from VietAnh14/source/hentaivn
Add new source HentaiVN
2023-07-24 15:53:38 +03:00
415da81b1a [Komikcast] Fix chatpers names #221 2023-07-24 11:07:38 +03:00
74a20455f2 [MangaLib] Fix pages url 2023-07-24 11:06:36 +03:00
devi
0bdce39def Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/LxManga.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2023-07-24 08:50:40 +02:00
devi
24f7d8b5bd Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LugnicaScans.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2023-07-24 08:50:33 +02:00
devi
18adc66f53 Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LugnicaScans.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2023-07-24 08:50:26 +02:00
devi
8c1c855531 Update src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LugnicaScans.kt
Co-authored-by: Koitharu <nvasya95@gmail.com>
2023-07-24 08:50:17 +02:00
devi
02ae76baf2 add new set order 2023-07-23 16:23:57 +02:00
devi
b5c44383e8 add lxmanga.net 2023-07-23 14:45:46 +02:00
devi
c48ebb937b add Lugnica Scans 2023-07-23 12:29:50 +02:00
devi
49c30d1d26 Merge remote-tracking branch 'origin/master' 2023-07-23 10:16:13 +02:00
devi
cb1a7ece8c fix some source and add 3 source 2023-07-23 10:15:45 +02:00
devi
4d60ae3cb6 fix some source and add 3 source 2023-07-23 10:15:18 +02:00
vianh
fe64620e9f [HentaiVN] Load pages using api 2023-07-23 15:00:36 +07:00
vianh
a42ca9e2da [HentaiVN] New source 2023-07-23 14:06:35 +07:00
506f6f7d30 Merge pull request #217 from davvarrr/master
add source and fix
2023-07-22 13:35:22 +03:00
devi
380861f29e Group sites by language 2023-07-22 12:13:49 +02:00
devi
9afc046d7b Change logic date on mangareader
Change logic domain on mangareader
2023-07-22 11:15:18 +02:00
devi
aec87a9a67 add source and fix japscan 2023-07-22 09:38:56 +02:00
69e0a531df [Madara] Refactoring 2023-07-19 11:49:55 +03:00
c85101991f Merge pull request #214 from davvarrr/master
Add source and create decode url image
2023-07-19 11:14:00 +03:00
devi
99e87fd97a Merge remote-tracking branch 'origin/master' 2023-07-18 20:00:48 +02:00
devi
665ec6b7ed fix japscan 2023-07-18 20:00:33 +02:00
devi
01fbd209c8 Merge branch 'KotatsuApp:master' into master 2023-07-18 19:13:02 +02:00
devi
f0fa8d59a1 add source and create decode url image 2023-07-18 19:12:25 +02:00
a1598fd712 [MangaInUa] Fix parsing chapters and pages 2023-07-18 09:50:55 +03:00
db96a1ff2e [Grouple] Fix tags parsing 2023-07-17 12:20:55 +03:00
833a42e798 Merge pull request #206 from bapeey/tmo
New parser: TuMangaOnline
2023-07-17 12:20:34 +03:00
922c665ef5 Merge pull request #210 from davvarrr/master
Add new source, fix and other
2023-07-17 11:13:13 +03:00
01842e9870 Merge pull request #212 from VietAnh14/master
[BlogTruyen] Update domain, user agent
2023-07-17 11:07:38 +03:00
vianh
a235f6281c [BlogTruyen] Update domain, user agent 2023-07-17 14:52:09 +07:00
devi
c9e7d4f483 add source requested 2023-07-16 20:02:36 +02:00
devi
94496ecc02 fix Asura Scans 2023-07-16 18:51:25 +02:00
devi
5104a8b542 add source request and remove source duplicate 2023-07-16 08:31:50 +02:00
devi
e67beae235 add source request 2023-07-15 21:20:23 +02:00
devi
7c4bffede2 minor fix and add quick source ar 2023-07-15 19:41:28 +02:00
devi
8df620b1cd fix 2023-07-15 19:08:03 +02:00
devi
cbbdd13c8e add new source ( lise below )
fix multiple source. ( lise below )
update madra parser :
-> new option on getListPage for take liste without Ajax
-> add format date
-> change defaut date parterne ( the news is most used by default on sites )
2023-07-15 15:52:07 +02:00
3874fe31d5 [TuMangaOnline] Fixes 2023-07-11 10:58:51 +03:00
a8c086b340 Merge branch 'tmo' of github.com:bapeey/kotatsu-parsers into bapeey-tmo 2023-07-11 10:49:12 +03:00
06a043d290 Refactor Madara parser 2023-07-11 10:36:21 +03:00
5a15014369 Add additional methods to WebClient 2023-07-11 10:08:02 +03:00
7fe1f4b3ff Merge pull request #208 from davvarrr/master
add source and other
2023-07-11 09:56:43 +03:00
devi
0055146264 fix and quick add source request 2023-07-10 17:12:46 +02:00
seew3l
cc26897fb9 Opps 2023-07-10 09:37:35 -05:00
seew3l
46535f82af Apply requested changes 2023-07-10 09:35:26 -05:00
seew3l
23a7b945af Add headers to getPages request 2023-07-09 13:34:15 -05:00
devi
4fb6ff63b9 Merge remote-tracking branch 'origin/master' 2023-07-09 19:56:04 +02:00
devi
c2e90a210c add new source and add other 2023-07-09 19:51:53 +02:00
seew3l
22d59e46c8 Get domain from ConfigKey 2023-07-09 10:18:20 -05:00
seew3l
e462b7df97 Remove unused val 2023-07-09 10:07:25 -05:00
seew3l
af8fb952df Remove comments 2023-07-08 23:28:31 -05:00
seew3l
a3fa04bcb7 Remove comments 2023-07-08 23:27:48 -05:00
seew3l
adf6fea4ac Add TMO 2023-07-08 23:07:25 -05:00
69af4fe586 Merge pull request #203 from davvarrr/master
80 new source
2023-07-06 06:57:00 +03:00
devi
31476a55f9 Fix small bug parse on desc 2023-07-04 21:20:42 +02:00
devi
c833563907 add 10 new source 2023-07-04 18:21:46 +02:00
devi
74a4a3a8b4 And official Manga Origines 2023-07-04 16:01:10 +02:00
devi
141bca517d Add Koitharu optimization, and rename Manga origines 2023-07-04 15:49:50 +02:00
devi
b9eb6363b7 Add 5 new source 2023-07-03 19:31:59 +02:00
devi
c3bed26739 Add 3 new source "fr" 2023-07-03 18:05:30 +02:00
devi
a15d54fe11 Add 10 new source 2023-07-03 17:26:46 +02:00
devi
1998ceac5a Add 3 new sources 2023-07-02 23:01:37 +02:00
devi
4192ffdbfe Add ScantradUnion 2023-07-02 15:31:24 +02:00
devi
5ec7227886 Add ScantradUnion 2023-07-02 15:30:52 +02:00
devi
a9ebc372f6 Add 10 new source 2023-07-02 12:03:07 +02:00
devi
1e98104eca Add new source and add new scrapper for Chapter on theme madara 2023-07-01 21:02:20 +02:00
devi
d05d5fa911 Add new source 2023-07-01 18:33:05 +02:00
07df5a81cf [Chan] Add related manga implementation 2023-07-01 12:27:27 +03:00
9861a9aa6b [Grouple] Add related manga implementation 2023-07-01 12:15:22 +03:00
b65e1c498e Simple related manga search implementation 2023-07-01 11:18:10 +03:00
240562037d Merge pull request #202 from davvarrr/master
rework madara theme and fix many parser
2023-07-01 11:12:55 +03:00
b3f79e77c3 [JapScan] Fix code style 2023-07-01 11:12:24 +03:00
db3c73156e [JapScan] Fix code style 2023-07-01 11:12:15 +03:00
devi
44b3b9b0c1 Merge remote-tracking branch 'origin/master' 2023-06-30 21:22:20 +02:00
devi
ea8c1de44d rework madara theme and fix som parser 2023-06-30 21:22:00 +02:00
devi
8195d0190a remove miss test in local 2023-06-30 09:59:19 +02:00
devi
8fd10eabd1 fix japscan and fix wrong date on 2 source 2023-06-29 20:16:07 +02:00
devi
7b28072ee5 delete table mode for automatic detect mode and chage defaut value for date and list url 2023-06-28 19:59:11 +02:00
devi
b37db4d680 delete table mode for automatic detect mode and chage defaut value for date and list url 2023-06-28 19:58:48 +02:00
92bfc7e9fa [Bentomanga] Fix UserAgent 2023-06-28 13:21:55 +03:00
b3e97760db [DesuMe] Update headers 2023-06-28 12:58:37 +03:00
3895312bfc Refactor MangaReaderParser 2023-06-28 12:31:31 +03:00
06d2976bb5 Batch sources fix 2023-06-28 12:05:41 +03:00
da4566f82f Fix GitHub workflow 2023-06-28 12:01:33 +03:00
b8f0ea4690 Merge pull request #195 from davvarrr/patch-16
Create AiyuMangaScanlation.kt
2023-06-27 12:32:29 +03:00
bb5e49758a Merge pull request #194 from davvarrr/patch-15
54 new source and rework
2023-06-27 12:31:22 +03:00
devi
e617904b62 Update MangaScantrad.kt 2023-06-26 23:25:49 +02:00
devi
b0e455e163 Update ScantradVf.kt 2023-06-26 23:24:09 +02:00
devi
6c31cea155 Update HhentaiFr.kt 2023-06-26 23:23:41 +02:00
devi
9c71d1b57c Update Hentaizone.kt 2023-06-26 23:23:09 +02:00
devi
e4f12149ed fix 2023-06-26 23:22:44 +02:00
devi
f6d264f37d Update MangaScantrad.kt 2023-06-26 23:22:00 +02:00
devi
aa734e5ad3 fix 2023-06-26 23:21:24 +02:00
devi
591291e9d6 fix status 2023-06-26 22:25:35 +02:00
devi
2311a56658 add new parse language for status 2023-06-26 22:00:36 +02:00
514e4473a1 Merge branch 'master' into patch-15 2023-06-26 13:53:57 +03:00
7ccacf4c27 Fix plugins versions 2023-06-26 13:52:49 +03:00
15f226fc73 Update gradle config 2023-06-26 13:29:13 +03:00
1388196288 Update gradle config 2023-06-26 13:27:31 +03:00
fe024cb306 Merge branch 'master' into patch-15 2023-06-26 12:15:48 +03:00
04e7edaa3e Fix GitHub worklflow Java version 2023-06-26 12:11:29 +03:00
devi
87abdf6346 Update MangaReaderParser.kt 2023-06-26 08:08:36 +02:00
devi
c4fad321db Update MangaReaderParser.kt 2023-06-26 07:08:25 +02:00
devi
c17c9d9ccc Update MangaReaderParser.kt
Add long for parse onging / finished
2023-06-26 07:07:01 +02:00
devi
d27c208ab7 Create AiyuMangaScanlation.kt
add aiyumangascanlation.com "es"
2023-06-24 23:15:21 +02:00
devi
90966aa7e4 Update MangaReaderParser.kt
add 54 new source 
rework parseInfoList
Source sorting part language
2023-06-24 23:12:38 +02:00
553a6c709a Reformat code 2023-06-24 16:29:42 +03:00
16698201f4 Merge pull request #191 from davvarrr/patch-12
Create ScantradVf.kt
2023-06-24 13:49:25 +03:00
33f27a8af7 Merge pull request #190 from davvarrr/patch-11
Create MangaScantrad.kt
2023-06-24 13:49:04 +03:00
48ec877ad5 Merge pull request #189 from davvarrr/patch-10
Create Hipercool.kt
2023-06-24 13:48:44 +03:00
54002ce27f Merge pull request #188 from davvarrr/patch-9
Create Hentaiteca.kt
2023-06-24 13:45:47 +03:00
de03d80e10 Merge pull request #186 from davvarrr/patch-7
Create Atlantisscan.kt
2023-06-24 13:45:30 +03:00
60954c38b6 Merge pull request #187 from davvarrr/patch-8
Create FrScan.kt
2023-06-24 13:44:24 +03:00
ba41d5f4ce Merge pull request #184 from davvarrr/patch-5
add french parse date and new source
2023-06-24 13:44:06 +03:00
9b76f42138 Merge pull request #185 from davvarrr/patch-6
Create AstralManga.kt
2023-06-24 13:43:40 +03:00
5a0306b4b5 Merge pull request #192 from davvarrr/patch-13
Create HhentaiFr.kt
2023-06-24 13:43:08 +03:00
b70ddf0a7c Merge pull request #193 from davvarrr/patch-14
Create Hentaizone.kt
2023-06-24 13:42:47 +03:00
devi
f53174258c add Stkissmanga "en"
add Stkissmanga "en"
2023-06-23 19:33:51 +02:00
devi
36706d998e Create Hentaizone.kt 2023-06-23 18:33:44 +02:00
devi
65ec3ca5c6 Update Hipercool.kt
Add parse description
2023-06-23 08:03:58 +02:00
devi
0b0068e113 Update HhentaiFr.kt
large covers are not always present
2023-06-22 22:30:56 +02:00
devi
553777ef08 Create HhentaiFr.kt 2023-06-22 20:59:36 +02:00
devi
3cda7ffc18 Create ScantradVf.kt 2023-06-22 20:52:54 +02:00
devi
48d98548cd Create MangaScantrad.kt 2023-06-22 20:51:49 +02:00
devi
b878824d15 Create Hipercool.kt 2023-06-22 20:50:51 +02:00
devi
16a99d7b8c Create Hentaiteca.kt 2023-06-22 20:49:07 +02:00
devi
c34f250ac9 Create FrScan.kt 2023-06-22 20:48:03 +02:00
devi
e74b276c98 Create Atlantisscan.kt 2023-06-22 20:43:21 +02:00
devi
f0e61daa63 Create AstralManga.kt 2023-06-22 20:42:19 +02:00
devi
34b6f4aa32 add french parse date 2023-06-22 18:49:19 +02:00
c2b79b55f8 Update dependencies 2023-06-22 14:28:47 +03:00
875b08b1fc Merge pull request #182 from davvarrr/patch-3
Create ReaperScansFr.kt
2023-06-22 14:02:50 +03:00
0e3788d943 Merge pull request #181 from davvarrr/patch-2
Add 2 source fr on MangaReaderParser
2023-06-22 14:02:02 +03:00
396508da6f Merge pull request #183 from davvarrr/patch-4
Fix uloaddate and force Enables list
2023-06-22 14:01:03 +03:00
devi
6fc6beb067 Force Enables list
Enables list mode to be forced to load images
2023-06-21 20:03:50 +02:00
devi
939cdf71ad Fix uloaddate
allows you to use the function in madaraparser to fix dates, e.g. "2 hours ago", otherwise the app wouldn't display the chapters.
2023-06-20 21:39:54 +02:00
devi
8d7eabdd71 Create ReaperScansFr.kt
add reaperscans.fr
2023-06-20 19:05:20 +02:00
devi
d28d6b17d8 Update MangaReaderParser.kt
add epsilonscan.fr ( +18 ) "fr"
add legacy-scans.com "fr"
2023-06-20 17:34:28 +02:00
f096ca2ad3 Merge pull request #180 from drsgdfnhtyjktyjt/patch-1
Add Phenixscans.fr
2023-06-20 12:42:39 +03:00
32914eb36d Small fixes 2023-06-20 12:40:15 +03:00
sddsg
b58190ed17 Add Phenixscans.fr
I was finally able to test it at home and it works perfectly.

Could you add it, thank you.
2023-06-19 20:04:32 +02:00
86a82970fc Empty-Commit 2023-06-16 09:54:57 +03:00
9976ea5dfc [Ninemanga] Fix covers issue 2023-06-14 16:12:09 +03:00
f732582d55 [Grouple] Fix chapters parsing 2023-06-13 10:13:54 +03:00
44e28b40d3 Update issue templates 2023-06-02 10:56:20 +03:00
f969e2a8d1 [Grouple] Fix multiple genres search 2023-06-02 10:37:34 +03:00
fa7ea5b16a Fix domain config key 2023-05-27 16:42:43 +03:00
3d7a39cf67 Fix pagination 2023-05-27 12:08:24 +03:00
46f8b8e700 [Ninemanga] Remove redirect check 2023-05-24 17:01:19 +03:00
ebcc6391d6 [Mangalib] Fix nsfw detection 2023-05-23 12:52:59 +03:00
12522ce8d8 [Anibel] Fix parser 2023-05-23 12:15:12 +03:00
cae7073f87 [MangaDex][ComicK] Fix branching again 2023-05-15 15:46:59 +03:00
0366ad0e57 Fix Android compatibility 2023-05-15 11:43:46 +03:00
6b95a8c55e [MangaDex] Fix branching ##172 2023-05-15 10:56:09 +03:00
6183f6edf3 [ComicK] Fix branching #163 #167 2023-05-15 10:21:32 +03:00
83cca4ef12 [KomikTap] fix page size 2023-05-13 15:06:23 +03:00
20ad9d0472 [ALlHentai] New parser 2023-05-13 14:40:15 +03:00
96b9ac36f3 [Bentomanga] Fixes 2023-05-06 17:28:34 +03:00
65170c0fe9 [Mangadex] Fix chapters numbers 2023-05-01 09:03:11 +03:00
3e349d3db3 [Ninemanga] Fix redirects 2023-04-28 17:21:19 +03:00
b2675c3cac Fix @MangaSources annotation 2023-04-28 16:17:47 +03:00
7414cf4a4e Add @JvmField on models fields 2023-04-28 15:43:13 +03:00
f43c482539 [Honeymanga] Refactoring 2023-04-28 15:31:03 +03:00
f0fbbf4333 Merge pull request #169 from CakesTwix/master
[New source] HoneyManga
2023-04-28 15:20:30 +03:00
0d03c68c8b [Manhwaland] Fix list url 2023-04-28 15:20:00 +03:00
CakesTwix
b4a4c86049 [HoneyManga] Impl. filter by genres
and fix cover url
2023-04-26 16:35:42 +03:00
306d46ea93 [Grouple] Fix pages url extraction 2023-04-26 09:24:39 +03:00
5b94badfc2 [MangaRead] Fix list parsing 2023-04-25 08:13:32 +03:00
9adc0c5358 [Bentomanga] New parser 2023-04-24 19:34:29 +03:00
66adc65a96 [JapScan] New parser 2023-04-24 16:51:53 +03:00
8def9b5446 Improve network error handling 2023-04-23 09:20:11 +03:00
e6511061a7 [Grouple] Fix server selecting 2023-04-20 18:07:20 +03:00
CakesTwix
647a694d91 [HoneyManga] throw IllegalArgumentException if search < 3 2023-04-19 20:20:37 +03:00
CakesTwix
e5ececa42d [HoneyManga] Update code, get(), CONTENT_ENCODING 2023-04-19 19:58:25 +03:00
c321faeaa9 Merge pull request #168 from VietAnh14/source/doujindesu
[DoujinDesu] New parser
2023-04-19 19:24:29 +03:00
vianh
3112b7937c [DoujinDesu] Apply suggesions from code review 2023-04-18 23:49:46 +07:00
CakesTwix
a3565abdc3 [HoneyManga] Improve code 2023-04-18 19:35:15 +03:00
CakesTwix
34d2e15302 [New source] HoneyManga 2023-04-18 18:55:43 +03:00
1b6d1456f3 Add support for POST with json body 2023-04-17 08:35:58 +03:00
vianh
b49aee3188 [DoujinDesu] New parser 2023-04-16 22:52:22 +07:00
749f682ef9 [Madara] Fix empty tags 2023-04-15 13:22:33 +03:00
1b269efaa4 Update readme 2023-04-15 13:02:26 +03:00
2db1a8d958 Remove broken parser 2023-04-15 12:59:29 +03:00
ece7d71e09 Update domains 2023-04-15 12:51:29 +03:00
129602ea70 [IsekaiScan] Fix chapters numbers #162 2023-04-15 12:44:17 +03:00
5e3fddb652 [Grouple] Fix relative page urls 2023-04-12 18:35:46 +03:00
2340100999 Fix false nsfw flags on some madara parsers #164 2023-04-06 18:49:19 +03:00
dc0151720e [IsekaiScanEu] Fix chapters order #162 2023-04-04 07:52:24 +03:00
36e88b2c0c [Remanga] Fix chapters numbers 2023-04-04 07:40:47 +03:00
35695904d1 [Remanga] Add Accept header to image requests 2023-03-30 18:52:11 +03:00
a3ffecc00f [IsekaiScan] Fix chapters parsing 2023-03-25 10:14:35 +02:00
cc418570d5 [Remanga] Fix mirror 2023-03-25 07:32:18 +02:00
481af22ae7 [Remanga] Add mirror 2023-03-24 18:02:31 +03:00
96b9dc8b5c [ComicK] Updated API 2023-03-24 16:05:24 +03:00
93f5f70d79 Remove referrer field from page model 2023-03-19 09:28:38 +02:00
fc53b19915 Add toString to models 2023-03-18 18:20:00 +02:00
413f4a2f10 Batch parsers fixes 2023-03-09 07:32:04 +02:00
e8d299782b [Tempestfansub] Update domain #159 2023-03-05 08:09:49 +02:00
489a4ab586 [NeatManga] Fix chapters loading 2023-03-05 08:09:49 +02:00
32fa3a89e2 Merge pull request #152 from OshekharO/patch-1 2023-03-02 09:58:35 +02:00
Saksham Shekher
f2614dd3d7 Fix 2023-02-26 23:03:43 +05:30
1093584202 [Grouple] Add UserAgent config 2023-02-25 18:36:05 +02:00
f62d024342 Fix Manga District & Hentai4free parsers #157 2023-02-25 17:10:41 +02:00
eea87d8607 Fix grouple pages parsing #156 2023-02-25 16:43:06 +02:00
f4c47b5b84 Merge pull request #155 from VietAnh14/source/truyentranhlh
[TruyentranhLH]: New source
2023-02-21 18:28:27 +02:00
vianh
fa78d5dd6f [TruyentranhLH]: New source 2023-02-21 00:47:53 +07:00
779c6664be Merge pull request #154 from OshekharO/patch-2
BatoTo: New Subdomain
2023-02-18 07:18:03 +02:00
Saksham Shekher
38efd7935a BatoTo: New Subdomain 2023-02-18 07:35:24 +05:30
Saksham Shekher
03f021377d Update README.md
some minor grammatical corrections
2023-02-16 23:17:31 +05:30
cf345d2d0c [Grouple] update UserAgent 2023-02-16 19:12:35 +02:00
fb3a3f49dd Merge pull request #150 from OshekharO/patch-1
Add: KumaPoi
2023-02-16 17:59:39 +02:00
f3b731114e [DesuMe] Genres in list 2023-02-16 17:52:27 +02:00
454b24ec88 [Grouple] Selecting the fastest pages server 2023-02-16 17:52:14 +02:00
Saksham Shekher
2c6c64fbe9 Add: ToonHunter 2023-02-14 12:46:10 +05:30
Saksham Shekher
a51d6d6485 Add: Hentai20 2023-02-14 12:37:01 +05:30
Saksham Shekher
0da57c041c Fix 2023-02-14 12:09:40 +05:30
Saksham Shekher
503573f388 Add: KomikLokal 2023-02-14 12:03:18 +05:30
Saksham Shekher
29cd1f1fdf Add: KumaPoi 2023-02-14 11:54:42 +05:30
Saksham Shekher
e51b33c74a Add: Toonily, Komiklab, KomikDewasa, KomiKav (#148)
* Add: Toonily

* Add: KOMIKLAB

* Update MangaReaderParser.kt

* Add: KomikDewasa

* Add: KomiKav
2023-02-09 20:56:04 +03:00
624a3dd991 Merge pull request #146 from KotatsuApp/feature/refactor2
Improve network requests processing
2023-02-08 19:55:51 +02:00
05d705ac03 Remove deprecated "getFavicon" method 2023-02-08 11:08:57 +02:00
1e1756aa17 Refactor web client 2023-02-08 11:01:20 +02:00
91109bf6dc Merge pull request #144 from OshekharO/patch-1
Add: KomikManga & Fixes
2023-02-08 10:50:18 +02:00
Saksham Shekher
7f852e793a Add: BakaMan
Thai Manga Provider
2023-02-08 14:16:15 +05:30
Saksham Shekher
aae3747925 Add: KomikIndo
Closes #145
2023-02-08 08:27:17 +05:30
Saksham Shekher
5e23d52e8a refactor: HachiManga 2023-02-07 10:40:03 +05:30
Saksham Shekher
3bc8013d2f Merge branch 'KotatsuApp:master' into patch-1 2023-02-07 10:20:55 +05:30
00abaea324 [Remanga] Fix headers 2023-02-06 18:57:00 +02:00
d14168e325 Make headers accessible 2023-02-06 18:54:50 +02:00
c3b1556816 Add headers to CloudFlareException 2023-02-06 17:50:44 +02:00
80a2a10e71 [Remanga] Fix headers 2023-02-06 17:30:17 +02:00
Saksham Shekher
029f554d6e Add: DragonTranslation 2023-02-06 14:37:30 +05:30
Saksham Shekher
841d8f05d9 Fix: MangaRosie, PianManga 2023-02-06 14:19:49 +05:30
Saksham Shekher
7253699529 Dead: ReadManwha 2023-02-06 14:18:04 +05:30
Saksham Shekher
5fe546c94d Dead: MangaTX OT
Removed as site is not being updated
2023-02-06 14:16:40 +05:30
Saksham Shekher
31c26f16ac Dead: IsekaiScan
Url changed to isekaiscan.to ( chapter not found in kotatsu )
2023-02-06 14:13:58 +05:30
Saksham Shekher
5eda6f96b4 Dead: ReadManhwa 2023-02-06 14:10:54 +05:30
Saksham Shekher
56a54d5eb4 Fix: NeatManga 2023-02-06 14:10:12 +05:30
Saksham Shekher
7a78a67740 Dead: MangaKik 2023-02-06 14:08:40 +05:30
Saksham Shekher
742533977f Dead: X2Manga 2023-02-06 14:06:39 +05:30
Saksham Shekher
2dedaea0ab Dead: KingManga 2023-02-06 14:05:36 +05:30
Saksham Shekher
cf7f55181f Dead: Manhwa 2023-02-06 14:03:26 +05:30
Saksham Shekher
f68f0009a2 Dead: ManhwaChill 2023-02-06 14:00:07 +05:30
Saksham Shekher
4799f54fd1 Dead: All Top Manga 2023-02-06 13:57:30 +05:30
Saksham Shekher
06ff8df2e4 Dead: Heroxia 2023-02-06 13:52:37 +05:30
Saksham Shekher
9b78944f9b Fix: ManhwaList 2023-02-06 13:49:31 +05:30
Saksham Shekher
fc2781c83a Add: KomikManga 2023-02-06 13:43:02 +05:30
Saksham Shekher
176437531d Add: CosmicScans (#142)
* Add: CosmicScans

* Fix info

* Rem: nsfw

* Mangasu url changed 

Cert issue needs to be fixed
2023-02-05 19:44:48 +03:00
c28e2a72d5 [Remanga] Bypass blocking 2023-02-05 10:09:53 +03:00
7f630184c0 [GroupLe] Fix pages loading 2023-01-29 20:54:52 +03:00
e5a6b82853 [Grouple] Fix chapter link extraction 2023-01-24 09:11:09 +02:00
e1d22b1110 [ExHentai] Option to hide suspicious content 2023-01-24 08:57:19 +02:00
918318252e Fix coroutine cancellation handling in runCatching 2023-01-24 08:03:51 +02:00
e153463c35 [Grouple] Fix authorization recognizing 2023-01-24 07:58:56 +02:00
cf00732023 Misc parsers fixes 2023-01-05 11:26:58 +02:00
ef838068ff [MangahaTachi] Change url (closes #128) 2023-01-01 20:37:04 +03:00
c4acb9725f [Lib] Fix auth part 2 2022-12-31 22:28:46 +03:00
04e219ff69 Remove accidentally duplicated parser 2022-12-31 19:41:36 +03:00
106a85aa80 [Lib] Authorization fixes 2022-12-31 19:03:06 +03:00
ad6e074cce [Asura Scans] New parser 2022-12-29 18:12:22 +03:00
e89f06a35b [KomikTap] New parser (closes #40) (?) 2022-12-29 11:09:25 +03:00
238cc7529a [Asura Scans (tr)] New parser (closes #55) 2022-12-28 23:26:26 +03:00
fb22eb5fac [Tempest Fan Sub] New parser (closes #56) 2022-12-28 23:10:17 +03:00
9ee1c21a67 [ExHentai] Fix pagination 2022-12-26 18:23:15 +02:00
c7c142f4a0 [Remanga] Show bought chapters 2022-12-26 17:46:15 +02:00
efd0394398 [MangaTale] New parser (closes #125) 2022-12-25 12:22:13 +03:00
0091a8280a Merge pull request #122 from VietAnh14/source/heroxia
[MangaReader] Fix chapters order
2022-12-14 08:27:47 +02:00
vianh
f9b0e82473 [MangaReader] Add new source 2022-12-11 00:59:53 +07:00
vianh
63676c21a8 [MangaReader] fix chapters order 2022-12-10 14:55:43 +07:00
add70b4790 [ExHentai] Fix pagination 2022-12-09 18:15:01 +02:00
d18f665556 Merge pull request #121 from VietAnh14/source/heroxia
[MangaReadTheme] Add some new sources using MangaReader theme
2022-12-09 08:18:46 +02:00
vianh
42253e43b3 Add more mangareader theme sources, fix cache tags 2022-12-07 00:25:22 +07:00
vianh
ad500a9db6 [MangaReadTheme] Add some new sources using MangaReader theme 2022-12-06 23:17:31 +07:00
ViAnh
2ab03cb668 [Manhwa18] Fix parse upload date (#115) 2022-11-26 19:37:11 +03:00
ViAnh
b78ddc6166 [NetTruyen] Update domain (#116) 2022-11-26 19:36:41 +03:00
1e49d4095b [Grouple] Fix pages parsing 2022-11-21 09:03:13 +02:00
bf8a1f3db2 [MangaInUa] Fix #104 2022-11-04 17:30:38 +03:00
321cc7529e Merge pull request #96 from VietAnh14/source/manhwa18
[Manhwa18] New source
2022-10-24 19:35:30 +03:00
ViAnh
7907b3126c Apply suggestions from code review
Co-authored-by: Koitharu <nvasya95@gmail.com>
2022-10-24 23:29:53 +07:00
vianh
ccf9af0e51 [Manhwa18] New source 2022-10-24 23:05:13 +07:00
b38b43edc0 Merge pull request #94 from VietAnh14/master
[BlogTruyen] Fix image src attr change
2022-10-24 11:59:42 +03:00
vianh
5d13c55dd5 [BlogTruyen] Fix image src attr change 2022-10-23 20:37:40 +07:00
a1441e7ed7 [MangaDex] Fix large chapters loading error 2022-10-20 09:56:00 +03:00
a62662d116 Fix some madara parsers 2022-10-19 13:37:49 +03:00
5cb953eb86 Small fixes 2022-10-10 16:27:34 +03:00
505ffcf405 Mangalink parser #66 2022-10-10 16:07:14 +03:00
a45f9bfc58 ReaperScansID parser #83 2022-10-10 15:16:40 +03:00
b1990c7918 Fixes 2022-10-01 13:43:09 +03:00
e8b801684f [MangaDex] Fix error on empty description 2022-09-29 14:25:41 +03:00
1430 changed files with 79228 additions and 6784 deletions

View File

@@ -3,12 +3,18 @@ root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = tab
indent_style = space
indent_size = 4
max_line_length = 120
tab_width = 4
insert_final_newline = false
disabled_rules=no-wildcard-imports,no-unused-imports
insert_final_newline = true
trim_trailing_whitespace = true
# noinspection EditorConfigKeyCorrectness
disabled_rules = no-wildcard-imports, no-unused-imports
[{*.kt,*.kts}]
[*.{kt,kts}]
ij_kotlin_allow_trailing_comma = true
ij_kotlin_allow_trailing_comma_on_call_site = true
[*.md]
indent_size = 2
trim_trailing_whitespace = false

View File

@@ -1,65 +1,66 @@
name: 🐞 Issue report
description: Report a source issue in Kotatsu
labels: [bug]
description: Report a source issue with a source
labels: [ bug ]
body:
- type: input
id: source
attributes:
label: Source information
description: |
You can find the source name in navigation drawer.
placeholder: |
Example: "MangaDex"
validations:
required: true
- type: input
id: source
attributes:
label: Source information
description: |
You can find the source name in navigation drawer.
placeholder: |
Example: "MangaDex"
validations:
required: true
- type: textarea
id: reproduce-steps
attributes:
label: Steps to reproduce
description: Provide an example of the issue.
placeholder: |
Example:
1. First step
2. Second step
3. Issue here
validations:
required: false
- type: textarea
id: reproduce-steps
attributes:
label: Steps to reproduce
description: Provide an example of the issue.
placeholder: |
Example:
1. First step
2. Second step
3. Issue here
Please use English language
validations:
required: false
- type: input
id: kotatsu-version
attributes:
label: Kotatsu version
description: |
You can find your Kotatsu version in **Settings → About**.
placeholder: |
Example: "3.3"
validations:
required: true
- type: input
id: kotatsu-version
attributes:
label: Kotatsu version
description: |
You can find your Kotatsu version in **Settings → About**.
placeholder: |
Example: "3.3"
validations:
required: true
- type: input
id: android-version
attributes:
label: Android version
description: |
You can find this somewhere in your Android settings.
placeholder: |
Example: "Android 12"
validations:
required: false
- type: input
id: android-version
attributes:
label: Android version
description: |
You can find this somewhere in your Android settings.
placeholder: |
Example: "Android 12"
validations:
required: false
- type: textarea
id: other-details
attributes:
label: Other details
placeholder: |
Additional details and attachments.
- type: textarea
id: other-details
attributes:
label: Other details
placeholder: |
Additional details and attachments.
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
options:
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
required: true
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
options:
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
required: true

View File

@@ -1,30 +1,31 @@
name: ⭐ Feature request
description: Suggest a feature to improve a source
labels: [feature request]
labels: [ feature request ]
body:
- type: textarea
id: feature-description
attributes:
label: Describe your suggested feature
description: How can an existing source be improved?
placeholder: |
Example:
"It should work like this..."
validations:
required: true
- type: textarea
id: feature-description
attributes:
label: Describe your suggested feature
description: How can an existing source be improved?
placeholder: |
Example:
"It should work like this..."
Please use English language
validations:
required: true
- type: textarea
id: other-details
attributes:
label: Other details
placeholder: |
Additional details and attachments.
- type: textarea
id: other-details
attributes:
label: Other details
placeholder: |
Additional details and attachments.
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
options:
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
required: true
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
options:
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
required: true

View File

@@ -1,33 +1,31 @@
name: 🗑 Source removal request
description: Scanlators can request their site to be removed
labels: [source removal]
labels: [ source removal ]
body:
- type: input
id: link
attributes:
label: Source link
placeholder: |
Example: "https://example.org"
validations:
required: true
- type: input
id: link
attributes:
label: Source link
placeholder: |
Example: "https://example.org"
validations:
required: true
- type: textarea
id: other-details
attributes:
label: Other details
placeholder: |
Additional details and attachments.
- type: textarea
id: other-details
attributes:
label: Other details (reason for removal, etc)
placeholder: |
Additional details and attachments.
- type: checkboxes
id: requirements
attributes:
label: Requirements
description: Your request will be denied if you don't meet these requirements.
options:
- label: Proof of ownership/intent to remove sent to a Kotatsu Discord server mod via DM
required: true
- label: Site only hosts content scanlated by the group and not stolen from other scanlators or official releases (i.e., not an aggregator site)
required: true
- label: Site is not infested with user-hostile features (e.g., invasive or malicious ads)
required: true
- type: checkboxes
id: requirements
attributes:
label: Requirements
description: Your request will be denied if you don't meet these requirements.
options:
- label: Proof of ownership of the website is sent to a Kotatsu [Discord server](https://discord.gg/NNJ5RgVBC5) or [Telegram community](https://t.me/kotatsuapp)
required: true
- label: Site only hosts content scanlated by the group and not stolen from other scanlators or official releases (i.e., not an aggregator site)
required: true

View File

@@ -1,50 +1,53 @@
name: 🌐 Source request
description: Suggest a new source for Kotatsu
labels: [source request]
labels: [ source request ]
body:
- type: input
id: name
attributes:
label: Source name
placeholder: |
Example: "Example Scans"
validations:
required: true
- type: markdown
attributes:
value: Please specify source **name** and **language** in the issue title
- type: input
id: name
attributes:
label: Source name
placeholder: |
Example: "Example Scans"
validations:
required: true
- type: input
id: link
attributes:
label: Source link
placeholder: |
Example: "https://example.org"
validations:
required: true
- type: input
id: link
attributes:
label: Source link
placeholder: |
Example: "https://example.org"
validations:
required: true
- type: input
id: language
attributes:
label: Language
placeholder: |
Example: "English"
validations:
required: true
- type: input
id: language
attributes:
label: Language
placeholder: |
Example: "English"
validations:
required: true
- type: textarea
id: other-details
attributes:
label: Other details
placeholder: |
Additional details and attachments.
- type: textarea
id: other-details
attributes:
label: Other details
placeholder: |
Additional details and attachments.
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
options:
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
required: true
- label: I have checked that the source does not already exist on the app.
required: true
- label: I have checked that the source does not already exist by searching the [GitHub repository](https://github.com/KotatsuApp/kotatsu-parsers) and verified it does not appear in the code base.
required: true
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
options:
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
required: true
- label: I have checked that the source does not already exist on the app.
required: true
- label: I have checked that the source does not already exist by searching the [GitHub repository](https://github.com/KotatsuApp/kotatsu-parsers) and verified it does not appear in the code base.
required: true

1
.github/summary.yaml vendored Normal file
View File

@@ -0,0 +1 @@
total: 1255

25
.github/workflows/test-branch.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: Check & Test latest parsers
on:
push:
branches:
- master
jobs:
check-and-build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository 🌏
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up enviroment 🔧
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: '21'
distribution: 'temurin'
- name: Set up Gradle 📦
uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3
- name: Compile parsers 🚀
run: ./gradlew compileKotlin

View File

@@ -1,27 +1,29 @@
name: Parsers test
name: Parsers test for PRs
on:
workflow_dispatch:
pull_request:
paths:
- 'src/main/kotlin/org/koitharu/kotatsu/parsers/site/*'
workflow_dispatch:
pull_request:
paths:
- 'src/main/kotlin/org/koitharu/kotatsu/parsers/**'
permissions:
contents: read
contents: read
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: 'gradle'
- run: ./gradlew :test --tests "org.koitharu.kotatsu.parsers.MangaParserTest" || true
- run: ./gradlew generateTestsReport
- uses: actions/upload-artifact@v3
with:
name: Report
path: build/test-results-html/TEST-org.koitharu.kotatsu.parsers.MangaParserTest.htm
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository 🌏
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up enviroment 🔧
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: '21'
distribution: 'temurin'
- name: Set up Gradle 📦
uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3
- name: Compile parsers 🚀
run: ./gradlew compileKotlin

21
.gitignore vendored
View File

@@ -4,6 +4,7 @@
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
.idea/**/copilot
# Generated files
.idea/**/contentModel.xml
@@ -16,6 +17,7 @@
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
.idea/**/Project_Default.xml
# Gradle
.idea/**/gradle.xml
@@ -25,10 +27,13 @@
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
.idea/deviceManager.xml
.idea/.name
.idea/artifacts
.idea/compiler.xml
.idea/jarRepositories.xml
.idea/modules.xml
.idea/ktlint-plugin.xml
.idea/*.iml
.idea/modules
*.iml
@@ -69,11 +74,25 @@ fabric.properties
.gradle/
build/
bin/
.idea/**/misc.xml
.idea/**/vcs.xml
.idea/**/ktlint.xml
.idea/codeStyles/
.idea/kotlinc.xml
src/test/resources/cookies.txt
local.properties
local.properties
.kotlin/
!/.idea/kotlin-statistics.xml
.idea/**/discord.xml
.idea/**/migrations.xml
.idea/**/runConfigurations.xml
.idea/**/AndroidProjectSystem.xml
.idea/caches/deviceStreaming.xml
/.idea/copilot.data.migration.agent.xml
/.idea/copilot.data.migration.ask.xml
/.idea/copilot.data.migration.ask2agent.xml
/.idea/copilot.data.migration.edit.xml

5
.idea/.gitignore generated vendored
View File

@@ -1,3 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# GitHub Copilot persisted chat sessions
/copilot/chatSessions
.name
deviceManager.xml

6
.idea/kotlinc.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.6.21" />
</component>
</project>

View File

@@ -1,10 +1,10 @@
# Contributing
The following is guide for creating a Kotatsu parsers. Thanks for taking the time to contribute!
The following is a guide for creating Kotatsu parsers. Thanks for taking the time to contribute!
## Prerequisites
Before you start, please note that the ability to use following technologies is **required**.
Before you start, please note that the ability to use the following technologies is **required**.
- Basic [Android development](https://developer.android.com/)
- [Kotlin](https://kotlinlang.org/)
@@ -16,69 +16,74 @@ Before you start, please note that the ability to use following technologies is
- [IntelliJ IDEA](https://www.jetbrains.com/idea/) (Community edition is enough)
- Android device (or emulator)
Kotatsu parsers is not a part of Android application, but you can easily develop and test it directly inside an Android
application project and relocate it to the library project when done.
Kotatsu parsers are not a part of the Android application, but you can easily develop and test it directly inside an
Android application project and relocate it to the library project when done.
### Before you start
First, take a look at `kotatsu-parsers` project structure. Each parser is a single class that
extends `MangaParser` class and have a `MangaSourceParser` annotation.
Also pay attention on extensions in `util` package. For example, extensions from `Jsoup` file
First, take a look at the `kotatsu-parsers` project structure. Each parser is a single class that
extends the `MangaParser` class and has a `MangaSourceParser` annotation.
Also, pay attention to extensions in the `util` package. For example, extensions from the `Jsoup` file
should be used instead of existing JSoup functions because they have better nullability support
and improved error messages.
## Writing your parser
So, you want to create a parser, that will provide access to manga from a website.
First, you should explore a website for API availability.
First, you should explore a website to learn about API availability.
If it does not contain any documentation about
API, [explore network requests](https://firefox-source-docs.mozilla.org/devtools-user/):
some websites use ajax.
some websites use AJAX.
- [Example](https://github.com/KotatsuApp/kotatsu-parsers/blob/master/src/main/kotlin/org/koitharu/kotatsu/parsers/site/DesuMeParser.kt)
- [Example](https://github.com/KotatsuApp/kotatsu-parsers/blob/master/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/DesuMeParser.kt)
of Json API usage.
- [Example](https://github.com/KotatsuApp/kotatsu-parsers/blob/master/src/main/kotlin/org/koitharu/kotatsu/parsers/site/AnibelParser.kt)
- [Example](https://github.com/KotatsuApp/kotatsu-parsers/blob/master/src/main/kotlin/org/koitharu/kotatsu/parsers/site/be/AnibelParser.kt)
of GraphQL API usage
- [Example](https://github.com/KotatsuApp/kotatsu-parsers/blob/master/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaTownParser.kt)
- [Example](https://github.com/KotatsuApp/kotatsu-parsers/blob/master/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaTownParser.kt)
of pure HTML parsing.
If website is based on some engine it is rationally to use common base class for this one (for example, Madara wordress
theme
and the `MadaraParser` class)
If the website is based on some engine it is rationally to use a common base class for this one (for example, Madara
Wordpress theme and the `MadaraParser` class)
### Parser class skeleton
Parser class must have exactly one primary constructor parameter of type `MangaLoaderContext` and have an
`MangaSourceParser` annotation that provides internal name, title and language of a manga source.
The parser class must have exactly one primary constructor parameter of type `MangaLoaderContext` and have an
`MangaSourceParser` annotation that provides the internal name, title, and language of a manga source.
All functions in `MangaParser` class are documented. Pay attention to some peculiarities:
All members of the `MangaParser` class are documented. Pay attention to some peculiarities:
- Never hardcode domain. Specify default domain in `configKeyDomain` field and obtain an actual one using `getDomain()`.
- All ids must be unique and domain-independent. Use `generateUid` functions with relative url or some internal id which
is unique across the manga source.
- `sortOrders` set should not be empty. If your source is not support sorting, specify one most relevance value.
- If you cannot obtain direct links to pages images inside `getPages` method, it is ok to use an intermediate url
as `Page.url` and fetch a direct link at `getPageUrl` function.
- `getFaviconUrl` function is deprecated, but Kotatsu application before v4 still use it, so it is recommended to
override it too.
- You can use _asserts_ to check some optional fields. For example. `Manga.author` field is not required, but if your
source provide such information, add `assert(it != null)`. This will not have any effect on production but help to
find issues during unit testing.
- If your source website (or it's api) uses pages for pagination instead of offset you should extend `PagedMangaParser`
- Never hardcode domain. Specify the default domain in the `configKeyDomain` field and obtain an actual one using
`domain`.
- All IDs must be unique and domain-independent. Use `generateUid` functions with a relative URL or some internal id
that is unique across the manga source.
- The `availableSortOrders` set should not be empty. If your source does not support sorting, specify one most relevant
value.
- If you cannot obtain direct links to page images inside the `getPages` method, it is ok to use an intermediate URL
as `Page.url` and fetch a direct link in the `getPageUrl` function.
- You can use _asserts_ to check some optional fields. For example, the `Manga.author` field is not required, but if
your source provides this information, add `assert(it != null)`. This will not have any effect on production but help
to find issues during unit testing.
- Your parser may also implement the `Interceptor` interface for additional manipulation of all network requests and
responses, including image loading.
- If your source website (or its API) uses pages for pagination instead of offset you should extend `PagedMangaParser`
instead of `MangaParser`.
- If your source website (or its API) does not provide pagination (has only one page of content) you should extend
`SinglePageMangaParser` instead of `MangaParser` or `PagedMangaParser`.
![parser_classes.png](docs/parser_classes.png)
## Development process
During the development it is recommended (but not necessary) to write it directly
in the Kotatsu android application project. You can use `core.parser.DummyParser` class as a sandbox. `Dummy` manga
source is available in debug Kotatsu build.
During the development, it is recommended (but not necessary) to write it directly
in the Kotatsu Android application project. You can use the `core.parser.DummyParser` class as a sandbox. The `Dummy`
manga source is available in the debug Kotatsu build.
Once parser is ready you can relocate your code into `kotatsu-parsers` library project in a `site` package and create a
Pull Request.
Once the parser is ready you can relocate your code into the `kotatsu-parsers` library project in a `site` package and
create a Pull Request.
### Testing
It is recommended to run unit tests before submitting a PR.
It is recommended that unit tests be run before submitting a PR.
- Temporary modify the `MangaSources` annotation class: specify your parser(s) name(s) and change mode
to `EnumSource.Mode.INCLUDE`
@@ -87,4 +92,5 @@ It is recommended to run unit tests before submitting a PR.
## Help
If you need a help or have some questions, ask a community in our [Discord server](https://discord.gg/NNJ5RgVBC5).
If you need help or have some questions, ask a community in our [Telegram chat](https://t.me/kotatsuapp)
or [Discord server](https://discord.gg/NNJ5RgVBC5).

View File

@@ -1,12 +1,13 @@
# Kotatsu parsers
Library that provides manga sources.
This library provides a collection of manga parsers for convenient access manga available on the web. It can be used in
JVM and Android applications.
[![](https://jitpack.io/v/KotatsuApp/kotatsu-parsers.svg)](https://jitpack.io/#KotatsuApp/kotatsu-parsers) ![Kotlin](https://img.shields.io/github/languages/top/KotatsuApp/kotatsu-parsers) ![License](https://img.shields.io/github/license/KotatsuApp/Kotatsu) [![Discord](https://img.shields.io/discord/898363402467045416?color=5865f2&label=discord)](https://discord.gg/NNJ5RgVBC5)
![Sources count](https://img.shields.io/badge/dynamic/yaml?url=https%3A%2F%2Fraw.githubusercontent.com%2FKotatsuApp%2Fkotatsu-parsers%2Frefs%2Fheads%2Fmaster%2F.github%2Fsummary.yaml&query=total&label=manga%20sources&color=%23E9321C) [![](https://jitpack.io/v/KotatsuApp/kotatsu-parsers.svg)](https://jitpack.io/#KotatsuApp/kotatsu-parsers) ![License](https://img.shields.io/github/license/KotatsuApp/Kotatsu) [![Telegram](https://img.shields.io/badge/chat-telegram-60ACFF)](https://t.me/kotatsuapp) [![Discord](https://img.shields.io/discord/898363402467045416?color=5865f2&label=discord)](https://discord.gg/NNJ5RgVBC5)
## Usage
1. Add it in your root build.gradle at the end of repositories:
1. Add it to your root build.gradle at the end of repositories:
```groovy
allprojects {
@@ -35,20 +36,33 @@ Library that provides manga sources.
}
```
See for versions at [JitPack](https://jitpack.io/#KotatsuApp/kotatsu-parsers)
Versions are available on [JitPack](https://jitpack.io/#KotatsuApp/kotatsu-parsers)
When used in Android
projects, [core library desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) with
the [NIO specification](https://developer.android.com/studio/write/java11-nio-support-table) should be enabled to
support Java 8+ features.
3. Usage in code
```kotlin
val parser = MangaSource.MANGADEX.newParser(mangaLoaderContext)
val parser = mangaLoaderContext.newParserInstance(MangaParserSource.MANGADEX)
```
`mangaLoaderContext` is an implementation of the `MangaLoaderContext` class.
See [Android](https://github.com/KotatsuApp/Kotatsu/blob/devel/app/src/main/java/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt)
and [Non-Android](https://github.com/KotatsuApp/kotatsu-dl/blob/master/src/main/kotlin/org/koitharu/kotatsu_dl/env/MangaLoaderContextImpl.kt)
implementation examples.
See examples
of [Android](https://github.com/KotatsuApp/Kotatsu/blob/devel/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt)
and [Non-Android](https://github.com/KotatsuApp/kotatsu-dl/blob/master/src/main/kotlin/org/koitharu/kotatsu/dl/parsers/MangaLoaderContextImpl.kt)
implementation.
Note that the `MangaSource.LOCAL` and `MangaSource.DUMMY` parsers cannot be instantiated.
## Projects that use the library
- [Kotatsu](https://github.com/KotatsuApp/Kotatsu)
- [Doki](https://github.com/DokiTeam/Doki)
- [kotatsu-dl](https://github.com/KotatsuApp/kotatsu-dl)
- [Shirizu (WIP)](https://github.com/ztimms73/shirizu)
- [OtakuWorld](https://github.com/jakepurple13/OtakuWorld)
## Contribution
@@ -56,5 +70,5 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for the guidelines.
## DMCA disclaimer
The developers of this application does not have any affiliation with the content available in the app. It is collecting
from the sources freely available through any web browser.
The developers of this application have no affiliation with the content available in the app. It is collected from
sources freely available through any web browser.

View File

@@ -1,73 +0,0 @@
import tasks.ReportGenerateTask
plugins {
id 'java-library'
id 'org.jetbrains.kotlin.jvm'
id 'com.google.devtools.ksp'
id 'maven-publish'
}
group = 'org.koitharu'
version = '1.0'
test {
useJUnitPlatform()
}
compileKotlin {
kotlinOptions {
jvmTarget = '1.8'
freeCompilerArgs += [
'-opt-in=kotlin.RequiresOptIn',
'-opt-in=kotlin.contracts.ExperimentalContracts',
'-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi',
'-opt-in=org.koitharu.kotatsu.parsers.InternalParsersApi',
]
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = '1.8'
freeCompilerArgs += [
'-opt-in=kotlin.RequiresOptIn',
'-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi',
'-opt-in=org.koitharu.kotatsu.parsers.InternalParsersApi',
]
}
}
kotlin {
sourceSets {
main.kotlin.srcDirs += 'build/generated/ksp/main/kotlin'
}
}
afterEvaluate {
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
}
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'com.squareup.okio:okio:3.2.0'
api 'org.jsoup:jsoup:1.15.2'
implementation 'org.json:json:20220320'
implementation 'androidx.collection:collection-ktx:1.2.0'
ksp project(':kotatsu-parsers-ksp')
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.0'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4'
testImplementation 'io.webfolder:quickjs:1.1.0'
}
task generateTestsReport(type: ReportGenerateTask)

64
build.gradle.kts Normal file
View File

@@ -0,0 +1,64 @@
import tasks.ReportGenerateTask
plugins {
`java-library`
`maven-publish`
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.ksp)
}
group = "org.koitharu"
version = "1.0"
tasks.test {
useJUnitPlatform()
}
ksp {
arg("summaryOutputDir", "${projectDir}/.github")
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
compilerOptions {
freeCompilerArgs.addAll(
"-opt-in=kotlin.RequiresOptIn",
"-opt-in=kotlin.contracts.ExperimentalContracts",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=org.koitharu.kotatsu.parsers.InternalParsersApi",
)
}
}
kotlin {
jvmToolchain(8)
explicitApiWarning()
sourceSets["main"].kotlin.srcDirs("build/generated/ksp/main/kotlin")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
}
}
}
dependencies {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.okhttp)
implementation(libs.okio)
implementation(libs.json)
implementation(libs.androidx.collection)
api(libs.jsoup)
ksp(project(":kotatsu-parsers-ksp"))
testImplementation(libs.junit.api)
testImplementation(libs.junit.engine)
testImplementation(libs.junit.params)
testRuntimeOnly(libs.junit.launcher)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.quickjs)
}
tasks.register<ReportGenerateTask>("generateTestsReport")

View File

@@ -1,13 +0,0 @@
plugins {
id('org.jetbrains.kotlin.jvm') version '1.6.21'
}
repositories {
mavenCentral()
}
dependencies {
implementation gradleApi()
implementation 'org.simpleframework:simple-xml:2.7.1'
implementation 'com.soywiz.korlibs.korte:korte-jvm:3.0.0-Beta5'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3'
}

17
buildSrc/build.gradle.kts Normal file
View File

@@ -0,0 +1,17 @@
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
}
kotlin {
jvmToolchain(8)
}
dependencies {
implementation(libs.korte)
implementation(libs.simplexml)
implementation(libs.kotlinx.coroutines.core)
}

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

47
buildSrc/gradlew vendored
View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +82,11 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -114,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -133,22 +133,29 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -193,18 +200,28 @@ if "$cygwin" || "$msys" ; then
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.

41
buildSrc/gradlew.bat vendored
View File

@@ -13,8 +13,10 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +27,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -56,32 +59,34 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View File

@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

View File

@@ -1,6 +1,6 @@
package tasks
import com.soywiz.korte.Template
import korlibs.template.Template
import kotlinx.coroutines.runBlocking
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
@@ -42,10 +42,13 @@ open class ReportGenerateTask : DefaultTask() {
val results = LinkedHashMap<String, LinkedHashMap<String, TestCase>>()
val tests = LinkedHashSet<String>()
for (case in testSuite.testCases) {
if (!case.isValid()) {
continue
}
tests.add(case.testName)
val map = results.getOrPut(case.source) { LinkedHashMap() }
val oldValue = map.put(case.testName, case)
check(oldValue == null)
check(oldValue == null) { "Check failed: $oldValue" }
}
val failPercent = (testSuite.failures.toDouble() / testSuite.tests * 100.0).roundToInt()

View File

@@ -19,14 +19,16 @@ class TestCase {
var failure: Failure? = null
val index by lazy {
name.split('|')[0].toInt()
name.split('|').getOrNull(0)?.toIntOrNull() ?: 0
}
val testName by lazy {
name.split('|')[1]
name.split('|').getOrNull(1).orEmpty()
}
val source by lazy {
name.split('|')[2]
name.split('|').getOrNull(2).orEmpty()
}
}
fun isValid() = name.count { it == '|' } == 2
}

View File

@@ -2,13 +2,15 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta content="width=device-width, initial-scale=1" name="viewport">
<title>{{ testSuite.name }}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2"
crossorigin="anonymous"></script>
<!-- CSS only -->
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css"
integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" rel="stylesheet">
<!-- JavaScript Bundle with Popper -->
<script crossorigin="anonymous"
integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3"
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
</head>
<body class="py-4">
@@ -25,67 +27,80 @@
{{ testSuite.errors }} ({{ error_percent }}%)
</div>
</div>
<div class="table-responsive mt-4">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Source</th>
{% for test in tests %}
<th scope="col" style="min-width: 5em;">{{ test }}</th>
{% endfor %}
</tr>
</thead>
{% for name, cases in results %}
<tr>
<th scope="row">{{ name }}</th>
{% for test in tests %}
{% set case = cases[test] %}
{% if case.failure == null %}
<td class="table-success text-center">
<i data-feather="check"></i>
</td>
{% else %}
{% if case.failure.type == 'java.lang.AssertionError' %}
<td class="table-warning text-center" style="cursor: pointer;"
data-bs-toggle="modal" data-bs-target="#failure_{{ case.hashCode }}">
<i data-feather="alert-triangle"></i>
</td>
{% else %}
<td class="table-danger text-center" style="cursor: pointer;"
data-bs-toggle="modal" data-bs-target="#failure_{{ case.hashCode }}">
<i data-feather="x"></i>
</td>
{% endif %}
<!--suppress HtmlUnknownTag -->
<div class="modal fade" id="failure_{{ case.hashCode }}" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ case.testName }} failed</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body font-monospace lh-sm bg-light" style="font-size: 0.7em;">
{{ case.failure.textHtml()|raw }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
<table class="table table-hover">
<thead class="sticky-top bg-body">
<tr>
<th scope="col">Source</th>
{% for test in tests %}
<th class="text-center" scope="col" style="min-width: 5em;">{{ test }}</th>
{% endfor %}
</tr>
</thead>
{% for name, cases in results %}
<tr>
<th scope="row">{{ name }}</th>
{% for test in tests %}
{% set case = cases[test] %}
{% if case.failure == null %}
<td class="table-success text-center">
<i data-feather="check"></i>
</td>
{% else %}
{% if case.failure.type == 'java.lang.AssertionError' %}
<td class="table-warning text-center" data-bs-target="#failure_{{ case.hashCode }}"
data-bs-toggle="modal" style="cursor: pointer;">
<i data-feather="alert-triangle"></i>
</td>
{% elseif case.failure.type == 'java.net.SocketTimeoutException' or case.failure.type ==
'java.net.UnknownHostException' %}
<td class="table-secondary text-center" data-bs-target="#failure_{{ case.hashCode }}"
data-bs-toggle="modal" style="cursor: pointer;">
<i data-feather="power"></i>
</td>
{% elseif case.failure.type == 'org.koitharu.kotatsu.parsers.CloudFlareProtectedException' %}
<td class="table-secondary text-center" data-bs-target="#failure_{{ case.hashCode }}"
data-bs-toggle="modal" style="cursor: pointer;">
<i data-feather="shield"></i>
</td>
{% elseif case.failure.type == 'org.koitharu.kotatsu.parsers.exception.AuthRequiredException' %}
<td class="table-secondary text-center" data-bs-target="#failure_{{ case.hashCode }}"
data-bs-toggle="modal" style="cursor: pointer;">
<i data-feather="user-x"></i>
</td>
{% else %}
<td class="table-danger text-center" data-bs-target="#failure_{{ case.hashCode }}"
data-bs-toggle="modal" style="cursor: pointer;">
<i data-feather="x"></i>
</td>
{% endif %}
<!--suppress HtmlUnknownTag -->
<div class="modal fade" id="failure_{{ case.hashCode }}" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ case.testName }} failed</h5>
<button aria-label="Close" class="btn-close" data-bs-dismiss="modal"
type="button"></button>
</div>
<div class="modal-body font-monospace lh-sm bg-light" style="font-size: 0.7em;">
{{ case.failure.textHtml()|raw }}
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal" type="button">Close</button>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</tr>
</div>
{% endif %}
{% endfor %}
</table>
</div>
</tr>
{% endfor %}
</table>
</div>
<script>
feather.replace()
</script>
</body>
</html>
</html>

804
docs/parser_classes.gaphor Normal file
View File

@@ -0,0 +1,804 @@
<?xml version="1.0" encoding="utf-8"?>
<gaphor xmlns="https://gaphor.org/model" xmlns:Core="https://gaphor.org/modelinglanguage/Core" xmlns:UML="https://gaphor.org/modelinglanguage/UML" xmlns:general="https://gaphor.org/modelinglanguage/general" version="4" gaphor-version="3.1.0">
<model>
<Core:StyleSheet id="58d6989a-66f8-11ec-b4c8-0456e5e540ed"/>
<UML:Package id="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed">
<name>
<val>Новая модель</val>
</name>
<ownedDiagram>
<reflist>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</reflist>
</ownedDiagram>
<ownedType>
<reflist>
<ref refid="0b54a350-f59d-11ef-bfb1-4cbb5880a0b8"/>
<ref refid="a300f58a-f5bd-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="ad4c68d0-f5bd-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="198a3108-f5be-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="32081654-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</ownedType>
<packagedElement>
<reflist>
<ref refid="0b54a350-f59d-11ef-bfb1-4cbb5880a0b8"/>
<ref refid="a300f58a-f5bd-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="ad4c68d0-f5bd-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="198a3108-f5be-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="32081654-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="25a17c58-f5be-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="41318a02-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</packagedElement>
</UML:Package>
<UML:Diagram id="58d6c536-66f8-11ec-b4c8-0456e5e540ed">
<element>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</element>
<name>
<val>Новая диаграмма</val>
</name>
<ownedPresentation>
<reflist>
<ref refid="0b54edc4-f59d-11ef-bfb1-4cbb5880a0b8"/>
<ref refid="a3018fc2-f5bd-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="ad4d2aae-f5bd-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="198aace6-f5be-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="320868c0-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="b760bcd4-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="bff32eae-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="d5113ca4-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="e8042ad8-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="531831f2-f5c0-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="5ccae8d4-f5c0-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="b6e0240e-f5bd-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="254e40f6-f5be-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="2bb6e87a-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="40e36d2c-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="bcc07c64-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="f6b48e4c-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="f89ba010-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="fabe0540-f5bf-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="6f993af6-f5c0-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</ownedPresentation>
</UML:Diagram>
<UML:Class id="0b54a350-f59d-11ef-bfb1-4cbb5880a0b8">
<clientDependency>
<reflist>
<ref refid="25a17c58-f5be-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</clientDependency>
<comment>
<reflist>
<ref refid="bff31afe-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</comment>
<isAbstract>
<val>1</val>
</isAbstract>
<name>
<val>AbstractMangaParser</val>
</name>
<owningPackage>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</owningPackage>
<package>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</package>
<presentation>
<reflist>
<ref refid="0b54edc4-f59d-11ef-bfb1-4cbb5880a0b8"/>
</reflist>
</presentation>
<specialization>
<reflist>
<ref refid="b969dac6-f5bd-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="2c236356-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</specialization>
</UML:Class>
<UML:ClassItem id="0b54edc4-f59d-11ef-bfb1-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 405.16796875, 388.8671875)</val>
</matrix>
<top-left>
<val>(0.0, 0.0)</val>
</top-left>
<width>
<val>158.0</val>
</width>
<height>
<val>60.0</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<show_attributes>
<val>0</val>
</show_attributes>
<show_operations>
<val>0</val>
</show_operations>
<subject>
<ref refid="0b54a350-f59d-11ef-bfb1-4cbb5880a0b8"/>
</subject>
</UML:ClassItem>
<UML:Class id="a300f58a-f5bd-11ef-9ec2-4cbb5880a0b8">
<comment>
<reflist>
<ref refid="d5112a70-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</comment>
<generalization>
<reflist>
<ref refid="b969dac6-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</generalization>
<isAbstract>
<val>1</val>
</isAbstract>
<name>
<val>PagedMangaParser</val>
</name>
<owningPackage>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</owningPackage>
<package>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</package>
<presentation>
<reflist>
<ref refid="a3018fc2-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
</UML:Class>
<UML:ClassItem id="a3018fc2-f5bd-11ef-9ec2-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 476.3368367667698, 525.76953125)</val>
</matrix>
<top-left>
<val>(0.0, 0.0)</val>
</top-left>
<width>
<val>142.0</val>
</width>
<height>
<val>60.0</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<show_attributes>
<val>0</val>
</show_attributes>
<show_operations>
<val>0</val>
</show_operations>
<subject>
<ref refid="a300f58a-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</subject>
</UML:ClassItem>
<UML:Class id="ad4c68d0-f5bd-11ef-9ec2-4cbb5880a0b8">
<comment>
<reflist>
<ref refid="e80418f4-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</comment>
<generalization>
<reflist>
<ref refid="2c236356-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</generalization>
<isAbstract>
<val>1</val>
</isAbstract>
<name>
<val>SinglePageMangaParser</val>
</name>
<owningPackage>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</owningPackage>
<package>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</package>
<presentation>
<reflist>
<ref refid="ad4d2aae-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
</UML:Class>
<UML:ClassItem id="ad4d2aae-f5bd-11ef-9ec2-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 405.16796875, 627.46875)</val>
</matrix>
<top-left>
<val>(0.0, 0.0)</val>
</top-left>
<width>
<val>175.0</val>
</width>
<height>
<val>60.0</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<show_attributes>
<val>0</val>
</show_attributes>
<show_operations>
<val>0</val>
</show_operations>
<subject>
<ref refid="ad4c68d0-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</subject>
</UML:ClassItem>
<UML:GeneralizationItem id="b6e0240e-f5bd-11ef-9ec2-4cbb5880a0b8">
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<horizontal>
<val>False</val>
</horizontal>
<orthogonal>
<val>False</val>
</orthogonal>
<subject>
<ref refid="b969dac6-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</subject>
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 499.2109069824219, 463.45703125)</val>
</matrix>
<points>
<val>[(28.486861756586336, 62.3125), (25.111328125, -14.58984375)]</val>
</points>
<head-connection>
<ref refid="a3018fc2-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</head-connection>
<tail-connection>
<ref refid="0b54edc4-f59d-11ef-bfb1-4cbb5880a0b8"/>
</tail-connection>
</UML:GeneralizationItem>
<UML:Generalization id="b969dac6-f5bd-11ef-9ec2-4cbb5880a0b8">
<general>
<ref refid="0b54a350-f59d-11ef-bfb1-4cbb5880a0b8"/>
</general>
<presentation>
<reflist>
<ref refid="b6e0240e-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
<specific>
<ref refid="a300f58a-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</specific>
</UML:Generalization>
<UML:Interface id="198a3108-f5be-11ef-9ec2-4cbb5880a0b8">
<name>
<val>MangaParser</val>
</name>
<owningPackage>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</owningPackage>
<package>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</package>
<presentation>
<reflist>
<ref refid="198aace6-f5be-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
<supplierDependency>
<reflist>
<ref refid="25a17c58-f5be-11ef-9ec2-4cbb5880a0b8"/>
<ref refid="41318a02-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</supplierDependency>
</UML:Interface>
<UML:InterfaceItem id="198aace6-f5be-11ef-9ec2-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 278.00391387939453, 232.92578125)</val>
</matrix>
<top-left>
<val>(0.0, 0.0)</val>
</top-left>
<width>
<val>105.0</val>
</width>
<height>
<val>80.0</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<show_attributes>
<val>0</val>
</show_attributes>
<show_operations>
<val>0</val>
</show_operations>
<subject>
<ref refid="198a3108-f5be-11ef-9ec2-4cbb5880a0b8"/>
</subject>
<folded>
<val>0</val>
</folded>
</UML:InterfaceItem>
<UML:InterfaceRealizationItem id="254e40f6-f5be-11ef-9ec2-4cbb5880a0b8">
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<horizontal>
<val>False</val>
</horizontal>
<orthogonal>
<val>False</val>
</orthogonal>
<subject>
<ref refid="25a17c58-f5be-11ef-9ec2-4cbb5880a0b8"/>
</subject>
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 306.1445007324219, 270.0625)</val>
</matrix>
<points>
<val>[(55.866059373910275, 42.86328125), (164.5765002560883, 118.8046875)]</val>
</points>
<head-connection>
<ref refid="198aace6-f5be-11ef-9ec2-4cbb5880a0b8"/>
</head-connection>
<tail-connection>
<ref refid="0b54edc4-f59d-11ef-bfb1-4cbb5880a0b8"/>
</tail-connection>
</UML:InterfaceRealizationItem>
<UML:InterfaceRealization id="25a17c58-f5be-11ef-9ec2-4cbb5880a0b8">
<client>
<reflist>
<ref refid="0b54a350-f59d-11ef-bfb1-4cbb5880a0b8"/>
</reflist>
</client>
<owningPackage>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</owningPackage>
<presentation>
<reflist>
<ref refid="254e40f6-f5be-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
<supplier>
<reflist>
<ref refid="198a3108-f5be-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</supplier>
</UML:InterfaceRealization>
<UML:GeneralizationItem id="2bb6e87a-f5bf-11ef-9ec2-4cbb5880a0b8">
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<horizontal>
<val>False</val>
</horizontal>
<orthogonal>
<val>False</val>
</orthogonal>
<subject>
<ref refid="2c236356-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</subject>
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 436.2929382324219, 439.1913757324219)</val>
</matrix>
<points>
<val>[(20.37646032737257, 188.27737426757812), (18.488327026367188, 9.675811767578125)]</val>
</points>
<head-connection>
<ref refid="ad4d2aae-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</head-connection>
<tail-connection>
<ref refid="0b54edc4-f59d-11ef-bfb1-4cbb5880a0b8"/>
</tail-connection>
</UML:GeneralizationItem>
<UML:Generalization id="2c236356-f5bf-11ef-9ec2-4cbb5880a0b8">
<general>
<ref refid="0b54a350-f59d-11ef-bfb1-4cbb5880a0b8"/>
</general>
<presentation>
<reflist>
<ref refid="2bb6e87a-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
<specific>
<ref refid="ad4c68d0-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</specific>
</UML:Generalization>
<UML:Class id="32081654-f5bf-11ef-9ec2-4cbb5880a0b8">
<clientDependency>
<reflist>
<ref refid="41318a02-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</clientDependency>
<name>
<val>MangaParserWrapper</val>
</name>
<note>
<val></val>
</note>
<owningPackage>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</owningPackage>
<package>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</package>
<presentation>
<reflist>
<ref refid="320868c0-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
</UML:Class>
<UML:ClassItem id="320868c0-f5bf-11ef-9ec2-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 128.5008992667698, 410.48990205860804)</val>
</matrix>
<top-left>
<val>(0.0, 0.0)</val>
</top-left>
<width>
<val>158.0</val>
</width>
<height>
<val>60.0</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<show_attributes>
<val>0</val>
</show_attributes>
<show_operations>
<val>0</val>
</show_operations>
<subject>
<ref refid="32081654-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</subject>
</UML:ClassItem>
<UML:InterfaceRealizationItem id="40e36d2c-f5bf-11ef-9ec2-4cbb5880a0b8">
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<horizontal>
<val>False</val>
</horizontal>
<orthogonal>
<val>False</val>
</orthogonal>
<subject>
<ref refid="41318a02-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</subject>
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 306.0585632324219, 249.69920349121094)</val>
</matrix>
<points>
<val>[(11.759223915218172, 63.22657775878906), (-98.55766396565207, 160.7906985673971)]</val>
</points>
<head-connection>
<ref refid="198aace6-f5be-11ef-9ec2-4cbb5880a0b8"/>
</head-connection>
<tail-connection>
<ref refid="320868c0-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</tail-connection>
</UML:InterfaceRealizationItem>
<UML:InterfaceRealization id="41318a02-f5bf-11ef-9ec2-4cbb5880a0b8">
<client>
<reflist>
<ref refid="32081654-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</client>
<owningPackage>
<ref refid="58d6c2e8-66f8-11ec-b4c8-0456e5e540ed"/>
</owningPackage>
<presentation>
<reflist>
<ref refid="40e36d2c-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
<supplier>
<reflist>
<ref refid="198a3108-f5be-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</supplier>
</UML:InterfaceRealization>
<UML:Comment id="b760ac44-f5bf-11ef-9ec2-4cbb5880a0b8">
<body>
<val>Used for providing external api. Do not use this class directly</val>
</body>
<presentation>
<reflist>
<ref refid="b760bcd4-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
</UML:Comment>
<UML:CommentItem id="b760bcd4-f5bf-11ef-9ec2-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 108.0561294327963, 550.1347579956054)</val>
</matrix>
<top-left>
<val>(0.0, 0.0)</val>
</top-left>
<width>
<val>183.21868896484375</val>
</width>
<height>
<val>91.23829650878906</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<subject>
<ref refid="b760ac44-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</subject>
</UML:CommentItem>
<UML:CommentLineItem id="bcc07c64-f5bf-11ef-9ec2-4cbb5880a0b8">
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<horizontal>
<val>False</val>
</horizontal>
<orthogonal>
<val>False</val>
</orthogonal>
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 549.205520203852, 278.05499559311954)</val>
</matrix>
<points>
<val>[(-349.5400462886338, 192.4349064654885), (-349.5400462886338, 272.0797624024858)]</val>
</points>
<tail-connection>
<ref refid="b760bcd4-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</tail-connection>
</UML:CommentLineItem>
<UML:Comment id="bff31afe-f5bf-11ef-9ec2-4cbb5880a0b8">
<annotatedElement>
<reflist>
<ref refid="0b54a350-f59d-11ef-bfb1-4cbb5880a0b8"/>
</reflist>
</annotatedElement>
<body>
<val>Extend this class if your manga source provides standard limit-offset based lists (get manga list by offset)</val>
</body>
<presentation>
<reflist>
<ref refid="bff32eae-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
</UML:Comment>
<UML:CommentItem id="bff32eae-f5bf-11ef-9ec2-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 673.0610499890082, 367.0515553989646)</val>
</matrix>
<top-left>
<val>(0.0, 0.0)</val>
</top-left>
<width>
<val>228.8028016098773</val>
</width>
<height>
<val>88.0</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<subject>
<ref refid="bff31afe-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</subject>
</UML:CommentItem>
<UML:Comment id="d5112a70-f5bf-11ef-9ec2-4cbb5880a0b8">
<annotatedElement>
<reflist>
<ref refid="a300f58a-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</annotatedElement>
<body>
<val>Extend this class if your manga source provides paged-based lists (get manga list by page number)</val>
</body>
<presentation>
<reflist>
<ref refid="d5113ca4-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
</UML:Comment>
<UML:CommentItem id="d5113ca4-f5bf-11ef-9ec2-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 666.7924311664914, 507.7539062499999)</val>
</matrix>
<top-left>
<val>(0.0, 0.0)</val>
</top-left>
<width>
<val>214.34368896484375</val>
</width>
<height>
<val>88.0</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<subject>
<ref refid="d5112a70-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</subject>
</UML:CommentItem>
<UML:Comment id="e80418f4-f5bf-11ef-9ec2-4cbb5880a0b8">
<annotatedElement>
<reflist>
<ref refid="ad4c68d0-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</annotatedElement>
<body>
<val>Extend this class if your manga source does not provide pagination (all manga provided in one list)</val>
</body>
<presentation>
<reflist>
<ref refid="e8042ad8-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
</UML:Comment>
<UML:CommentItem id="e8042ad8-f5bf-11ef-9ec2-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 666.7924311664914, 560.9671898788581)</val>
</matrix>
<top-left>
<val>(0.0, 58.00435704705592)</val>
</top-left>
<width>
<val>263.9307954323941</val>
</width>
<height>
<val>78.01706672440287</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<subject>
<ref refid="e80418f4-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</subject>
</UML:CommentItem>
<UML:CommentLineItem id="f6b48e4c-f5bf-11ef-9ec2-4cbb5880a0b8">
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<horizontal>
<val>False</val>
</horizontal>
<orthogonal>
<val>False</val>
</orthogonal>
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 561.8951626340418, 549.6101338901756)</val>
</matrix>
<points>
<val>[(56.44167413272805, 7.038279316310902), (104.89726853244963, 8.304008355003589)]</val>
</points>
<head-connection>
<ref refid="a3018fc2-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</head-connection>
<tail-connection>
<ref refid="d5113ca4-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</tail-connection>
</UML:CommentLineItem>
<UML:CommentLineItem id="f89ba010-f5bf-11ef-9ec2-4cbb5880a0b8">
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<horizontal>
<val>False</val>
</horizontal>
<orthogonal>
<val>False</val>
</orthogonal>
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 559.3873501340418, 413.0007588901755)</val>
</matrix>
<points>
<val>[(3.7806186159582467, 0.0), (113.67369985496646, 1.6012844908540842)]</val>
</points>
<head-connection>
<ref refid="0b54edc4-f59d-11ef-bfb1-4cbb5880a0b8"/>
</head-connection>
<tail-connection>
<ref refid="bff32eae-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</tail-connection>
</UML:CommentLineItem>
<UML:CommentLineItem id="fabe0540-f5bf-11ef-9ec2-4cbb5880a0b8">
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<horizontal>
<val>False</val>
</horizontal>
<orthogonal>
<val>False</val>
</orthogonal>
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 522.3600063840418, 652.6882588901756)</val>
</matrix>
<points>
<val>[(57.80796236595825, 5.29182139794003), (144.43242478244963, 5.657840086725969)]</val>
</points>
<head-connection>
<ref refid="ad4d2aae-f5bd-11ef-9ec2-4cbb5880a0b8"/>
</head-connection>
<tail-connection>
<ref refid="e8042ad8-f5bf-11ef-9ec2-4cbb5880a0b8"/>
</tail-connection>
</UML:CommentLineItem>
<general:Box id="531831f2-f5c0-11ef-9ec2-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 375.05802564891326, 349.05453145170736)</val>
</matrix>
<top-left>
<val>(0.0, 3.15625)</val>
</top-left>
<width>
<val>590.6594026101285</val>
</width>
<height>
<val>368.44140625</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
</general:Box>
<UML:Comment id="5ccad4ca-f5c0-11ef-9ec2-4cbb5880a0b8">
<body>
<val>To create your own parser you have to extends one of these classes</val>
</body>
<presentation>
<reflist>
<ref refid="5ccae8d4-f5c0-11ef-9ec2-4cbb5880a0b8"/>
</reflist>
</presentation>
</UML:Comment>
<UML:CommentItem id="5ccae8d4-f5c0-11ef-9ec2-4cbb5880a0b8">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 756.725301794198, 225.57697659840966)</val>
</matrix>
<top-left>
<val>(0.0, 0.0)</val>
</top-left>
<width>
<val>208.99212646484375</val>
</width>
<height>
<val>73.47482464883183</val>
</height>
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<subject>
<ref refid="5ccad4ca-f5c0-11ef-9ec2-4cbb5880a0b8"/>
</subject>
</UML:CommentItem>
<UML:CommentLineItem id="6f993af6-f5c0-11ef-9ec2-4cbb5880a0b8">
<diagram>
<ref refid="58d6c536-66f8-11ec-b4c8-0456e5e540ed"/>
</diagram>
<horizontal>
<val>False</val>
</horizontal>
<orthogonal>
<val>False</val>
</orthogonal>
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 943.6141683885666, 419.2772168262177)</val>
</matrix>
<points>
<val>[(-27.404961772030788, -67.06643537451032), (-27.404961772030788, -120.2254155789762)]</val>
</points>
<head-connection>
<ref refid="531831f2-f5c0-11ef-9ec2-4cbb5880a0b8"/>
</head-connection>
<tail-connection>
<ref refid="5ccae8d4-f5c0-11ef-9ec2-4cbb5880a0b8"/>
</tail-connection>
</UML:CommentLineItem>
</model>
</gaphor>

BIN
docs/parser_classes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -1 +1,15 @@
## Following this blog:
# https://proandroiddev.com/how-we-reduced-our-gradle-build-times-by-over-80-51f2b6d6b05b
kotlin.code.style=official
systemProp.org.gradle.unsafe.configuration-cache=false
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=4096m -XX:+UseParallelGC
org.gradle.configureondemand=true
org.gradle.configuration-cache.problems=warn
## Use these flags on local machine for faster build time
# org.gradle.caching=true
# org.gradle.configuration-cache=true
# org.gradle.vfs.watch=true
# org.gradle.parallel=true
# org.gradle.workers.max=8
# org.gradle.configuration-cache.max-problems=8

34
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,34 @@
[versions]
kotlin = "2.2.10"
ksp = "2.2.10-2.0.2"
coroutines = "1.10.2"
junit = "5.10.1"
okhttp = "5.1.0"
okio = "3.16.0"
json = "20240303"
androidx-collection = "1.5.0"
jsoup = "1.21.2"
quickjs = "1.1.0"
korte = "4.0.10"
simplexml = "2.7.1"
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
[libraries]
ksp-symbol-processing-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" }
kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutines" }
kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutines" }
junit-launcher = { group = "org.junit.platform", name = "junit-platform-launcher" }
junit-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" }
junit-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit" }
junit-params = { group = "org.junit.jupiter", name = "junit-jupiter-params", version.ref = "junit" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
okio = { module = "com.squareup.okio:okio", version.ref = "okio" }
json = { module = "org.json:json", version.ref = "json" }
androidx-collection = { module = "androidx.collection:collection", version.ref = "androidx-collection" }
jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
quickjs = { module = "io.webfolder:quickjs", version.ref = "quickjs" }
korte = { module = "com.soywiz.korlibs.korte:korte-jvm", version.ref = "korte" }
simplexml = { module = "org.simpleframework:simple-xml", version.ref = "simplexml" }

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

49
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +82,11 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -114,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -133,22 +133,29 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -193,18 +200,28 @@ if "$cygwin" || "$msys" ; then
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.

41
gradlew.bat vendored
View File

@@ -13,8 +13,10 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +27,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -56,32 +59,34 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

2
jitpack.yml Normal file
View File

@@ -0,0 +1,2 @@
jdk:
- openjdk17

View File

@@ -1,7 +0,0 @@
plugins {
id 'org.jetbrains.kotlin.jvm'
}
dependencies {
implementation 'com.google.devtools.ksp:symbol-processing-api:1.6.21-1.0.5'
}

View File

@@ -0,0 +1,11 @@
plugins {
alias(libs.plugins.kotlin.jvm)
}
kotlin {
jvmToolchain(8)
}
dependencies {
implementation(libs.ksp.symbol.processing.api)
}

View File

@@ -7,152 +7,180 @@ import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSVisitorVoid
import com.google.devtools.ksp.validate
import java.io.File
import java.io.Writer
import java.util.*
class ParserProcessor(
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger,
private val options: Map<String, String>,
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger,
private val options: Map<String, String>,
) : SymbolProcessor {
private val availableLocales = Locale.getAvailableLocales().toSet()
private val sourceNamePattern = Regex("[A-Z_][A-Z0-9_]{3,}")
private val availableLocales = Locale.getAvailableLocales().toSet()
private val sourceNamePattern = Regex("[A-Z_][A-Z0-9_]{3,}")
override fun process(resolver: Resolver): List<KSAnnotated> {
val symbols = resolver.getSymbolsWithAnnotation("org.koitharu.kotatsu.parsers.MangaSourceParser")
val ret = symbols.filterNot { it.validate() }.toList()
if (!symbols.iterator().hasNext()) {
return ret
}
val dependencies = Dependencies.ALL_FILES
val factoryFile =
try {
codeGenerator.createNewFile(
dependencies = dependencies,
packageName = "org.koitharu.kotatsu.parsers",
fileName = "MangaParserFactory",
)
} catch (e: FileAlreadyExistsException) {
logger.warn(e.toString(), null)
null
}
val sourcesFile =
try {
codeGenerator.createNewFile(
dependencies = dependencies,
packageName = "org.koitharu.kotatsu.parsers.model",
fileName = "MangaSource",
)
} catch (e: FileAlreadyExistsException) {
logger.warn(e.toString(), null)
null
}
val totalCount = sourcesFile?.writer().use { sourcesWriter ->
factoryFile?.writer().use { factoryWriter ->
writeContent(sourcesWriter, factoryWriter, symbols)
}
}
writeSummary(totalCount)
return ret
}
override fun process(resolver: Resolver): List<KSAnnotated> {
val symbols = resolver
.getSymbolsWithAnnotation("org.koitharu.kotatsu.parsers.MangaSourceParser")
val ret = symbols.filterNot { it.validate() }.toList()
if (!symbols.iterator().hasNext()) {
return ret
}
val dependencies = Dependencies.ALL_FILES
val factoryFile = try {
codeGenerator.createNewFile(
dependencies = dependencies,
packageName = "org.koitharu.kotatsu.parsers",
fileName = "MangaParserFactory",
)
} catch (e: FileAlreadyExistsException) {
logger.warn(e.toString(), null)
null
}
val sourcesFile = try {
codeGenerator.createNewFile(
dependencies = dependencies,
packageName = "org.koitharu.kotatsu.parsers.model",
fileName = "MangaSource",
)
} catch (e: FileAlreadyExistsException) {
logger.warn(e.toString(), null)
null
}
sourcesFile?.writer().use { sourcesWriter ->
factoryFile?.writer().use { factoryWriter ->
writeContent(sourcesWriter, factoryWriter, symbols)
}
}
return ret
}
private fun writeContent(
sourcesWriter: Writer?,
factoryWriter: Writer?,
symbols: Sequence<KSAnnotated>,
): Int {
if (sourcesWriter == null && factoryWriter == null) {
return 0
}
factoryWriter?.write(
"""
package org.koitharu.kotatsu.parsers
private fun writeContent(
sourcesWriter: Writer?,
factoryWriter: Writer?,
symbols: Sequence<KSAnnotated>,
) {
if (sourcesWriter == null && factoryWriter == null) {
return
}
factoryWriter?.write(
"""
package org.koitharu.kotatsu.parsers
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.core.MangaParserWrapper
internal fun MangaParserSource.newParser(context: MangaLoaderContext): MangaParser = when (this) {
import org.koitharu.kotatsu.parsers.model.MangaSource
@Suppress("DEPRECATION")
fun MangaSource.newParser(context: MangaLoaderContext): MangaParser = when (this) {
""".trimIndent(),
)
sourcesWriter?.write(
"""
package org.koitharu.kotatsu.parsers.model
enum class MangaSource(
val title: String,
val locale: String?,
) {
LOCAL("Local", null),
)
sourcesWriter?.write(
"""
package org.koitharu.kotatsu.parsers.model
public enum class MangaParserSource(
public val title: String,
public val locale: String,
public val contentType: ContentType,
public val isBroken: Boolean,
): MangaSource {
""".trimIndent(),
)
)
val visitor = ParserVisitor(sourcesWriter, factoryWriter)
symbols
.filter { it is KSClassDeclaration && it.validate() }
.forEach { it.accept(visitor, Unit) }
val visitor = ParserVisitor(sourcesWriter, factoryWriter)
val totalCount = symbols
.filter { it is KSClassDeclaration && it.validate() }
.onEach { it.accept(visitor, Unit) }
.count()
factoryWriter?.write(
"""
MangaSource.LOCAL -> throw NotImplementedError("Local manga parser is not supported")
MangaSource.DUMMY -> throw NotImplementedError("Dummy manga parser cannot be instantiated")
}.also {
factoryWriter?.write(
"""
}.let {
require(it.source == this) {
"Cannot instantiate manga parser: ${'$'}name mapped to ${'$'}{it.source}"
}
MangaParserWrapper(it)
}
""".trimIndent(),
)
sourcesWriter?.write(
"""
DUMMY("Dummy", null),
)
sourcesWriter?.write(
"""
;
}
""".trimIndent(),
)
}
)
return totalCount
}
private inner class ParserVisitor(
private val sourcesWriter: Writer?,
private val factoryWriter: Writer?,
) : KSVisitorVoid() {
private fun writeSummary(totalCount: Int) {
val file = File(options["summaryOutputDir"] ?: return, "summary.yaml")
file.writeText("total: $totalCount")
}
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
if (classDeclaration.classKind != ClassKind.CLASS || classDeclaration.isAbstract()) {
logger.error("Only non-abstract can be annotated with @MangaSourceParser", classDeclaration)
}
val annotation = classDeclaration.annotations.single { it.shortName.asString() == "MangaSourceParser" }
val deprecation = classDeclaration.annotations.singleOrNull { it.shortName.asString() == "Deprecated" }
val name = annotation.arguments.single { it.name?.asString() == "name" }.value as String
val title = annotation.arguments.single { it.name?.asString() == "title" }.value as String
val locale = annotation.arguments.single { it.name?.asString() == "locale" }.value as String
val localeString = if (locale.isEmpty()) "null" else "\"$locale\""
val localeObj = if (locale.isEmpty()) null else Locale(locale)
val localeTitle = localeObj?.getDisplayLanguage(localeObj)
if (localeObj != null && localeObj !in availableLocales) {
logger.error("Manga source $name has wrong locale: $localeTitle")
}
private inner class ParserVisitor(
private val sourcesWriter: Writer?,
private val factoryWriter: Writer?,
) : KSVisitorVoid() {
private val titles = HashMap<String, String>()
if (!sourceNamePattern.matches(name)) {
logger.error("Manga source name must be uppercase: $name")
}
override fun visitClassDeclaration(
classDeclaration: KSClassDeclaration,
data: Unit,
) {
if (classDeclaration.classKind != ClassKind.CLASS || classDeclaration.isAbstract()) {
logger.error("Only non-abstract can be annotated with @MangaSourceParser", classDeclaration)
}
val annotation = classDeclaration.annotations.single { it.shortName.asString() == "MangaSourceParser" }
val deprecation = classDeclaration.annotations.singleOrNull { it.shortName.asString() == "Deprecated" }
val isBroken = classDeclaration.annotations.any { it.shortName.asString() == "Broken" }
val name = annotation.arguments.single { it.name?.asString() == "name" }.value as String
val title = annotation.arguments.single { it.name?.asString() == "title" }.value as String
val locale = annotation.arguments.single { it.name?.asString() == "locale" }.value as String
val type = annotation.arguments.single { it.name?.asString() == "type" }.value
val localeString = "\"$locale\""
val localeObj = if (locale.isEmpty()) null else Locale(locale)
val localeTitle = localeObj?.getDisplayLanguage(localeObj)
if (localeObj != null && localeObj !in availableLocales) {
logger.error("Manga source $name has wrong locale: $localeTitle")
}
val constructor = classDeclaration.primaryConstructor
if (constructor == null || constructor.parameters.count { !it.hasDefault } != 1) {
logger.error(
"Class with @MangaSourceParser must have a primary constructor with one parameter",
classDeclaration,
)
}
val className = classDeclaration.qualifiedName?.asString()
factoryWriter?.write("\tMangaSource.$name -> $className(context)\n")
val deprecationString = if (deprecation != null) {
val reason = deprecation.arguments
.find { it.name?.asString() == "message" }?.value?.toString() ?: "Unknown reason"
"@Deprecated(\"$reason\") "
} else ""
val localeComment = localeTitle?.toTitleCase(localeObj)?.let { " /* $it */" }.orEmpty()
sourcesWriter?.write("\t$deprecationString$name(\"$title\", $localeString$localeComment),\n")
}
}
}
if (!sourceNamePattern.matches(name)) {
logger.error("Manga source name must be uppercase: $name")
}
val constructor = classDeclaration.primaryConstructor
if (constructor == null || constructor.parameters.count { !it.hasDefault } != 1) {
logger.error(
"Class with @MangaSourceParser must have a primary constructor with one parameter",
classDeclaration,
)
}
val className = checkNotNull(classDeclaration.qualifiedName?.asString()) { "Class name is null" }
val prevTitleClass = titles.put(title, className)
if (prevTitleClass != null) {
logger.warn("Source title duplication: \"$title\" is assigned to both $prevTitleClass and $className")
}
factoryWriter?.write("\tMangaParserSource.$name -> $className(context)\n")
val deprecationString =
if (deprecation != null) {
val reason =
deprecation.arguments
.find { it.name?.asString() == "message" }
?.value
?.toString() ?: "Unknown reason"
"@Deprecated(\"$reason\") "
} else {
""
}
val localeComment = localeTitle?.toTitleCase(localeObj)?.let { " /* $it */" }.orEmpty()
sourcesWriter?.write(
"\t$deprecationString$name(\"$title\", $localeString$localeComment, $type, $isBroken),\n",
)
}
}
}

View File

@@ -1,22 +0,0 @@
pluginManagement {
plugins {
id 'com.google.devtools.ksp' version '1.6.21-1.0.5'
id 'org.jetbrains.kotlin.jvm' version '1.6.21'
}
repositories {
gradlePluginPortal()
google()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = 'kotatsu-parsers'
include 'kotatsu-parsers-ksp'

18
settings.gradle.kts Normal file
View File

@@ -0,0 +1,18 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
rootProject.name = "kotatsu-parsers"
include("kotatsu-parsers-ksp")

View File

@@ -0,0 +1,14 @@
package org.koitharu.kotatsu.parsers
/**
* Annotate [MangaParser] implementation to mark this parser as broken instead of removing it
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
internal annotation class Broken(
/**
* Reason why this parser is broken
*/
val message: String = "",
)

View File

@@ -0,0 +1,18 @@
package org.koitharu.kotatsu.parsers
public object ErrorMessages {
public const val FILTER_MULTIPLE_STATES_NOT_SUPPORTED: String = "Multiple states are not supported by this source"
public const val FILTER_MULTIPLE_GENRES_NOT_SUPPORTED: String = "Multiple genres are not supported by this source"
public const val FILTER_MULTIPLE_CONTENT_RATING_NOT_SUPPORTED: String =
"Multiple Content ratings are not supported by this source"
public const val FILTER_MULTIPLE_CONTENT_TYPES_NOT_SUPPORTED: String =
"Multiple Content types are not supported by this source"
public const val FILTER_MULTIPLE_DEMOGRAPHICS_NOT_SUPPORTED: String =
"Multiple Demographics are not supported by this source"
public const val FILTER_BOTH_LOCALE_GENRES_NOT_SUPPORTED: String =
"Filtering by both genres and locale is not supported by this source"
public const val FILTER_BOTH_STATES_GENRES_NOT_SUPPORTED: String =
"Filtering by both genres and states is not supported by this source"
public const val SEARCH_NOT_SUPPORTED: String = "Search is not supported by this source"
}

View File

@@ -11,4 +11,4 @@ package org.koitharu.kotatsu.parsers
@SinceKotlin("1.3")
@RequiresOptIn
@MustBeDocumented
annotation class InternalParsersApi()
public annotation class InternalParsersApi

View File

@@ -1,166 +1,78 @@
package org.koitharu.kotatsu.parsers
import okhttp3.*
import okhttp3.CookieJar
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import org.jsoup.HttpStatusException
import okhttp3.OkHttpClient
import okhttp3.Response
import org.koitharu.kotatsu.parsers.bitmap.Bitmap
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.exception.GraphQLException
import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.parseJson
import org.koitharu.kotatsu.parsers.util.LinkResolver
import java.util.*
abstract class MangaLoaderContext {
public abstract class MangaLoaderContext {
protected abstract val httpClient: OkHttpClient
public abstract val httpClient: OkHttpClient
abstract val cookieJar: CookieJar
public abstract val cookieJar: CookieJar
/**
* Do a GET http request to specific url
* @param url
* @param headers an additional headers for request, may be null
*/
suspend fun httpGet(url: HttpUrl, headers: Headers? = null): Response {
val request = Request.Builder()
.get()
.url(url)
if (headers != null) {
request.headers(headers)
}
return httpClient.newCall(request.build()).await().ensureSuccess()
}
public fun newParserInstance(source: MangaParserSource): MangaParser = source.newParser(this)
suspend fun httpGet(url: String, headers: Headers? = null): Response {
return httpGet(url.toHttpUrl(), headers)
}
public fun newLinkResolver(link: HttpUrl): LinkResolver = LinkResolver(this, link)
public fun newLinkResolver(link: String): LinkResolver = newLinkResolver(link.toHttpUrl())
/**
* Do a HEAD http request to specific url
* @param url
* @param headers an additional headers for request, may be null
*/
suspend fun httpHead(url: String, headers: Headers? = null): Response {
val request = Request.Builder()
.head()
.url(url)
if (headers != null) {
request.headers(headers)
}
return httpClient.newCall(request.build()).await().ensureSuccess()
}
public open fun encodeBase64(data: ByteArray): String = Base64.getEncoder().encodeToString(data)
/**
* Do a POST http request to specific url with `multipart/form-data` payload
* @param url
* @param form payload as key=>value map
* @param headers an additional headers for request, may be null
*/
suspend fun httpPost(
url: String,
form: Map<String, String>,
headers: Headers? = null,
): Response {
val body = FormBody.Builder()
form.forEach { (k, v) ->
body.addEncoded(k, v)
}
val request = Request.Builder()
.post(body.build())
.url(url)
if (headers != null) {
request.headers(headers)
}
return httpClient.newCall(request.build()).await().ensureSuccess()
}
public open fun decodeBase64(data: String): ByteArray = Base64.getDecoder().decode(data)
/**
* Do a POST http request to specific url with `multipart/form-data` payload
* @param url
* @param payload payload as `key=value` string with `&` separator
* @param headers an additional headers for request, may be null
*/
suspend fun httpPost(
url: String,
payload: String,
headers: Headers?,
): Response {
val body = FormBody.Builder()
payload.split('&').forEach {
val pos = it.indexOf('=')
if (pos != -1) {
val k = it.substring(0, pos)
val v = it.substring(pos + 1)
body.addEncoded(k, v)
}
}
val request = Request.Builder()
.post(body.build())
.url(url)
if (headers != null) {
request.headers(headers)
}
return httpClient.newCall(request.build()).await().ensureSuccess()
}
/**
* Do a GraphQL request to specific url
* @param endpoint an url
* @param query GraphQL request payload
*/
suspend fun graphQLQuery(endpoint: String, query: String): JSONObject {
val body = JSONObject()
body.put("operationName", null as Any?)
body.put("variables", JSONObject())
body.put("query", "{$query}")
val mediaType = "application/json; charset=utf-8".toMediaType()
val requestBody = body.toString().toRequestBody(mediaType)
val request = Request.Builder()
.post(requestBody)
.url(endpoint)
val json = httpClient.newCall(request.build()).await().ensureSuccess().parseJson()
json.optJSONArray("errors")?.let {
if (it.length() != 0) {
throw GraphQLException(it)
}
}
return json
}
open fun encodeBase64(data: ByteArray): String = Base64.getEncoder().encodeToString(data)
open fun decodeBase64(data: String): ByteArray = Base64.getDecoder().decode(data)
open fun getPreferredLocales(): List<Locale> = listOf(Locale.getDefault())
public open fun getPreferredLocales(): List<Locale> = listOf(Locale.getDefault())
/**
* Execute JavaScript code and return result
* @param script JavaScript source code
* @return execution result as string, may be null
*/
abstract suspend fun evaluateJs(script: String): String?
@Deprecated("Provide a base url")
public abstract suspend fun evaluateJs(script: String): String?
abstract fun getConfig(source: MangaSource): MangaSourceConfig
/**
* Execute JavaScript code and return result
* @param script JavaScript source code
* @param baseUrl url of page script will be executed in context of
* @return execution result as string, may be null
*/
public abstract suspend fun evaluateJs(baseUrl: String, script: String): String?
private fun Response.ensureSuccess(): Response {
val exception: Exception? = when (code) { // Catch some error codes, not all
404 -> NotFoundException(message, request.url.toString())
in 500..599 -> HttpStatusException(message, code, request.url.toString())
else -> null
}
if (exception != null) {
runCatching {
close()
}.onFailure {
exception.addSuppressed(it)
}
throw exception
}
return this
/**
* Open [url] in browser for some external action (e.g. captcha solving or non cookie-based authorization)
*/
public open fun requestBrowserAction(parser: MangaParser, url: String): Nothing {
throw UnsupportedOperationException("Browser is not available")
}
}
public abstract fun getConfig(source: MangaSource): MangaSourceConfig
public abstract fun getDefaultUserAgent(): String
/**
* Helper function to be used in an interceptor
* to descramble images
* @param response Image response
* @param redraw lambda function to implement descrambling logic
*/
public abstract fun redrawImageResponse(
response: Response,
redraw: (image: Bitmap) -> Bitmap,
): Response
/**
* create a new empty Bitmap with given dimensions
*/
public abstract fun createBitmap(
width: Int,
height: Int,
): Bitmap
}

View File

@@ -1,200 +1,88 @@
package org.koitharu.kotatsu.parsers
import androidx.annotation.CallSuper
import androidx.annotation.VisibleForTesting
import okhttp3.Headers
import okhttp3.HttpUrl
import org.jsoup.nodes.Element
import okhttp3.Interceptor
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.FaviconParser
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQuery
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQueryCapabilities
import org.koitharu.kotatsu.parsers.util.LinkResolver
import org.koitharu.kotatsu.parsers.util.convertToMangaSearchQuery
import org.koitharu.kotatsu.parsers.util.toMangaListFilterCapabilities
import java.util.*
abstract class MangaParser @InternalParsersApi constructor(val source: MangaSource) {
public interface MangaParser : Interceptor {
protected abstract val context: MangaLoaderContext
public val source: MangaParserSource
/**
* Supported [SortOrder] variants. Must not be empty.
*
* For better performance use [EnumSet] for more than one item.
*/
abstract val sortOrders: Set<SortOrder>
public val availableSortOrders: Set<SortOrder>
val config by lazy { context.getConfig(source) }
@Deprecated("Too complex. Use filterCapabilities instead")
public val searchQueryCapabilities: MangaSearchQueryCapabilities
val sourceLocale: Locale?
get() = source.locale?.let { Locale(it) }
public val filterCapabilities: MangaListFilterCapabilities
public val config: MangaSourceConfig
public val authorizationProvider: MangaParserAuthProvider?
get() = this as? MangaParserAuthProvider
/**
* Provide default domain and available alternatives, if any.
*
* Never hardcode domain in requests, use [getDomain] instead.
* Never hardcode domain in requests, use [domain] instead.
*/
protected abstract val configKeyDomain: ConfigKey.Domain
public val configKeyDomain: ConfigKey.Domain
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
internal open val headers: Headers? = null
public val domain: String
/**
* Used as fallback if value of `sortOrder` passed to [getList] is null
*/
protected open val defaultSortOrder: SortOrder
get() {
val supported = sortOrders
return SortOrder.values().first { it in supported }
}
@Deprecated("Too complex. Use getList with filter instead")
public suspend fun getList(query: MangaSearchQuery): List<Manga>
/**
* Parse list of manga by specified criteria
*
* @param offset starting from 0 and used for pagination.
* Note than passed value may not be divisible by internal page size, so you should adjust it manually.
* @param query search query, may be null or empty if no search needed
* @param tags genres for filtering, values from [getTags] and [Manga.tags]. May be null or empty
* @param sortOrder one of [sortOrders] or null for default value
*/
@JvmSynthetic
@InternalParsersApi
abstract suspend fun getList(
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga>
/**
* Parse list of manga with search by text query
*
* @param offset starting from 0 and used for pagination.
* @param query search query
*/
open suspend fun getList(offset: Int, query: String): List<Manga> {
return getList(offset, query, null, defaultSortOrder)
}
/**
* Parse list of manga by specified criteria
*
* @param offset starting from 0 and used for pagination.
* Note than passed value may not be divisible by internal page size, so you should adjust it manually.
* @param tags genres for filtering, values from [getTags] and [Manga.tags]. May be null or empty
* @param sortOrder one of [sortOrders] or null for default value
*/
open suspend fun getList(offset: Int, tags: Set<MangaTag>?, sortOrder: SortOrder?): List<Manga> {
return getList(offset, null, tags, sortOrder ?: defaultSortOrder)
}
public suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga>
/**
* Parse details for [Manga]: chapters list, description, large cover, etc.
* Must return the same manga, may change any fields excepts id, url and source
* @see Manga.copy
*/
abstract suspend fun getDetails(manga: Manga): Manga
public suspend fun getDetails(manga: Manga): Manga
/**
* Parse pages list for specified chapter.
* @see MangaPage for details
*/
abstract suspend fun getPages(chapter: MangaChapter): List<MangaPage>
public suspend fun getPages(chapter: MangaChapter): List<MangaPage>
/**
* Fetch direct link to the page image.
*/
open suspend fun getPageUrl(page: MangaPage): String = page.url.toAbsoluteUrl(getDomain())
public suspend fun getPageUrl(page: MangaPage): String
/**
* Fetch available tags (genres) for source
*/
abstract suspend fun getTags(): Set<MangaTag>
/**
* Returns direct link to the website favicon
*/
@Deprecated(
message = "Use parseFavicons() to get multiple favicons with different size",
replaceWith = ReplaceWith("parseFavicons()"),
)
open fun getFaviconUrl() = "https://${getDomain()}/favicon.ico"
public suspend fun getFilterOptions(): MangaListFilterOptions
/**
* Parse favicons from the main page of the source`s website
*/
open suspend fun getFavicons(): Favicons {
return FaviconParser(context, getDomain(), headers).parseFavicons()
}
public suspend fun getFavicons(): Favicons
@CallSuper
open fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
keys.add(configKeyDomain)
}
public fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>)
/* Utils */
public suspend fun getRelatedManga(seed: Manga): List<Manga>
fun getDomain(): String {
return config[configKeyDomain]
}
fun getDomain(subdomain: String): String {
val domain = getDomain()
return subdomain + "." + domain.removePrefix("www.")
}
fun urlBuilder(): HttpUrl.Builder {
return HttpUrl.Builder()
.scheme("https")
.host(getDomain())
}
public fun getRequestHeaders(): Headers
/**
* Create a unique id for [Manga]/[MangaChapter]/[MangaPage].
* @param url must be relative url, without a domain
* @see [Manga.id]
* @see [MangaChapter.id]
* @see [MangaPage.id]
* Return [Manga] object by web link to it
* @see [Manga.publicUrl]
*/
@InternalParsersApi
protected fun generateUid(url: String): Long {
var h = 1125899906842597L
source.name.forEach { c ->
h = 31 * h + c.code
}
url.forEach { c ->
h = 31 * h + c.code
}
return h
}
/**
* Create a unique id for [Manga]/[MangaChapter]/[MangaPage].
* @param id an internal identifier
* @see [Manga.id]
* @see [MangaChapter.id]
* @see [MangaPage.id]
*/
@InternalParsersApi
protected fun generateUid(id: Long): Long {
var h = 1125899906842597L
source.name.forEach { c ->
h = 31 * h + c.code
}
h = 31 * h + id
return h
}
@InternalParsersApi
protected fun Element.parseFailed(message: String? = null): Nothing {
throw ParseException(message, ownerDocument()?.location() ?: baseUri(), null)
}
@InternalParsersApi
protected fun Set<MangaTag>?.oneOrThrowIfMany(): MangaTag? {
return when {
isNullOrEmpty() -> null
size == 1 -> first()
else -> throw IllegalArgumentException("Multiple genres are not supported by this source")
}
}
}
public suspend fun resolveLink(resolver: LinkResolver, link: HttpUrl): Manga?
}

View File

@@ -6,19 +6,19 @@ import org.koitharu.kotatsu.parsers.exception.ParseException
/**
* Implement this in your parser for authorization support
*/
interface MangaParserAuthProvider {
public interface MangaParserAuthProvider {
/**
* Return link to the login page, which will be opened in browser.
* Must be an absolute url
*/
val authUrl: String
public val authUrl: String
/**
* Quick check if user is logged in.
* In most case you should check for cookies in [MangaLoaderContext.cookieJar].
*/
val isAuthorized: Boolean
public suspend fun isAuthorized(): Boolean
/**
* Fetch and return current user`s name or login.
@@ -26,5 +26,5 @@ interface MangaParserAuthProvider {
* @throws [AuthRequiredException] if user is not logged in or authorization is expired
* @throws [ParseException] on parsing error
*/
suspend fun getUsername(): String
}
public suspend fun getUsername(): String
}

View File

@@ -1,20 +1,28 @@
package org.koitharu.kotatsu.parsers
import org.koitharu.kotatsu.parsers.model.ContentType
/**
* Annotate each [MangaParser] implementation with this annotation, used by codegen
*/
@Target(AnnotationTarget.CLASS)
annotation class MangaSourceParser(
@Retention(AnnotationRetention.SOURCE)
internal annotation class MangaSourceParser(
/**
* Name of manga source. Used as an Enum value, must be UPPER_CASE and unique.
*/
val name: String,
/**
* User-friendly title of manga source. In most case equals the website name.
* Avoid extra whitespaces between the words if it is not required.
*/
val title: String,
/**
* Language code (for example "en" or "ru") or blank if parser provide manga on different languages.
*/
val locale: String = "",
)
/**
* Type of content provided by parser. See [ContentType] for more info
*/
val type: ContentType = ContentType.MANGA,
)

View File

@@ -1,50 +0,0 @@
package org.koitharu.kotatsu.parsers
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.Paginator
@InternalParsersApi
abstract class PagedMangaParser(
source: MangaSource,
pageSize: Int,
searchPageSize: Int = pageSize,
) : MangaParser(source) {
protected val paginator = Paginator(pageSize)
protected val searchPaginator = Paginator(searchPageSize)
override suspend fun getList(offset: Int, query: String): List<Manga> {
return getList(searchPaginator, offset, query, null, defaultSortOrder)
}
override suspend fun getList(offset: Int, tags: Set<MangaTag>?, sortOrder: SortOrder?): List<Manga> {
return getList(paginator, offset, null, tags, sortOrder ?: defaultSortOrder)
}
@InternalParsersApi
@Deprecated("You should use getListPage for PagedMangaParser", level = DeprecationLevel.HIDDEN)
final override suspend fun getList(
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> = throw UnsupportedOperationException("You should use getListPage for PagedMangaParser")
abstract suspend fun getListPage(page: Int, query: String?, tags: Set<MangaTag>?, sortOrder: SortOrder): List<Manga>
private suspend fun getList(
paginator: Paginator,
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val page = paginator.getPage(offset)
val list = getListPage(page, query, tags, sortOrder)
paginator.onListReceived(offset, page, list.size)
return list
}
}

View File

@@ -0,0 +1,9 @@
package org.koitharu.kotatsu.parsers.bitmap
public interface Bitmap {
public val width: Int
public val height: Int
public fun drawBitmap(sourceBitmap: Bitmap, src: Rect, dst: Rect)
}

View File

@@ -0,0 +1,15 @@
package org.koitharu.kotatsu.parsers.bitmap
public data class Rect(
val left: Int = 0,
val top: Int = 0,
val right: Int = 0,
val bottom: Int = 0,
) {
val width: Int
get() = right - left
val height: Int
get() = bottom - top
}

View File

@@ -1,13 +1,37 @@
package org.koitharu.kotatsu.parsers.config
sealed class ConfigKey<T>(
val key: String,
public sealed class ConfigKey<T>(
@JvmField public val key: String,
) {
abstract val defaultValue: T
public abstract val defaultValue: T
class Domain(
public class Domain(
@JvmField @JvmSuppressWildcards public vararg val presetValues: String,
) : ConfigKey<String>("domain") {
init {
require(presetValues.isNotEmpty()) { "You must provide at least one domain" }
}
override val defaultValue: String
get() = presetValues.first()
}
public class ShowSuspiciousContent(
override val defaultValue: Boolean,
) : ConfigKey<Boolean>("show_suspicious")
public class UserAgent(
override val defaultValue: String,
val presetValues: Array<String>?,
) : ConfigKey<String>("domain")
}
) : ConfigKey<String>("user_agent")
public class SplitByTranslations(
override val defaultValue: Boolean,
) : ConfigKey<Boolean>("split_translations")
public class PreferredImageServer(
public val presetValues: Map<String?, String?>,
override val defaultValue: String?,
) : ConfigKey<String?>("img_server")
}

View File

@@ -1,6 +1,6 @@
package org.koitharu.kotatsu.parsers.config
interface MangaSourceConfig {
public interface MangaSourceConfig {
operator fun <T> get(key: ConfigKey<T>): T
}
public operator fun <T> get(key: ConfigKey<T>): T
}

View File

@@ -0,0 +1,105 @@
package org.koitharu.kotatsu.parsers.core
import androidx.annotation.CallSuper
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.Response
import org.koitharu.kotatsu.parsers.InternalParsersApi
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQuery
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQueryCapabilities
import org.koitharu.kotatsu.parsers.network.OkHttpWebClient
import org.koitharu.kotatsu.parsers.network.WebClient
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@Suppress("OVERRIDE_DEPRECATION")
@InternalParsersApi
public abstract class AbstractMangaParser @InternalParsersApi constructor(
@property:InternalParsersApi public val context: MangaLoaderContext,
public final override val source: MangaParserSource,
) : MangaParser {
public final override val searchQueryCapabilities: MangaSearchQueryCapabilities
get() = filterCapabilities.toMangaSearchQueryCapabilities()
public override val config: MangaSourceConfig by lazy { context.getConfig(source) }
public open val sourceLocale: Locale
get() = if (source.locale.isEmpty()) Locale.ROOT else Locale(source.locale)
protected val sourceContentRating: ContentRating?
get() = if (source.contentType == ContentType.HENTAI) {
ContentRating.ADULT
} else {
null
}
protected val isNsfwSource: Boolean = source.contentType == ContentType.HENTAI
protected open val userAgentKey: ConfigKey.UserAgent = ConfigKey.UserAgent(context.getDefaultUserAgent())
override fun getRequestHeaders(): Headers = Headers.Builder()
.add("User-Agent", config[userAgentKey])
.build()
/**
* Used as fallback if value of `order` passed to [getList] is null
*/
public open val defaultSortOrder: SortOrder
get() {
val supported = availableSortOrders
return SortOrder.entries.first { it in supported }
}
final override val domain: String
get() = config[configKeyDomain]
@JvmField
protected val webClient: WebClient = OkHttpWebClient(context.httpClient, source)
/**
* Search list of manga by specified searchQuery
*
* @param query searchQuery
*/
public final override suspend fun getList(query: MangaSearchQuery): List<Manga> = getList(
offset = query.offset,
order = query.order ?: defaultSortOrder,
filter = convertToMangaListFilter(query),
)
/**
* Fetch direct link to the page image.
*/
public override suspend fun getPageUrl(page: MangaPage): String = page.url.toAbsoluteUrl(domain)
/**
* Parse favicons from the main page of the source`s website
*/
public override suspend fun getFavicons(): Favicons {
return FaviconParser(webClient, domain).parseFavicons()
}
@CallSuper
public override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
keys.add(configKeyDomain)
}
public override suspend fun getRelatedManga(seed: Manga): List<Manga> {
return RelatedMangaFinder(listOf(this)).invoke(seed)
}
/**
* Return [Manga] object by web link to it
* @see [Manga.publicUrl]
*/
override suspend fun resolveLink(resolver: LinkResolver, link: HttpUrl): Manga? = null
override fun intercept(chain: Interceptor.Chain): Response = chain.proceed(chain.request())
}

View File

@@ -0,0 +1,94 @@
package org.koitharu.kotatsu.parsers.core
import androidx.annotation.CallSuper
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.Interceptor
import okhttp3.Response
import org.koitharu.kotatsu.parsers.InternalParsersApi
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.network.OkHttpWebClient
import org.koitharu.kotatsu.parsers.network.WebClient
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@Deprecated("Too complex. Use AbstractMangaParser instead")
internal abstract class FlexibleMangaParser @InternalParsersApi constructor(
@property:InternalParsersApi val context: MangaLoaderContext,
final override val source: MangaParserSource,
) : MangaParser {
override val config: MangaSourceConfig by lazy { context.getConfig(source) }
open val sourceLocale: Locale
get() = if (source.locale.isEmpty()) Locale.ROOT else Locale(source.locale)
protected open val userAgentKey: ConfigKey.UserAgent = ConfigKey.UserAgent(context.getDefaultUserAgent())
final override val filterCapabilities: MangaListFilterCapabilities
get() = searchQueryCapabilities.toMangaListFilterCapabilities()
protected val sourceContentRating: ContentRating?
get() = if (source.contentType == ContentType.HENTAI) {
ContentRating.ADULT
} else {
null
}
final override val domain: String
get() = config[configKeyDomain]
@Deprecated("Override intercept() instead")
override fun getRequestHeaders(): Headers = Headers.Builder()
.add("User-Agent", config[userAgentKey])
.build()
/**
* Used as fallback if value of `order` passed to [getList] is null
*/
open val defaultSortOrder: SortOrder
get() {
val supported = availableSortOrders
return SortOrder.entries.first { it in supported }
}
@JvmField
protected val webClient: WebClient = OkHttpWebClient(context.httpClient, source)
/**
* Fetch direct link to the page image.
*/
override suspend fun getPageUrl(page: MangaPage): String = page.url.toAbsoluteUrl(domain)
final override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
return getList(convertToMangaSearchQuery(offset, order, filter))
}
/**
* Parse favicons from the main page of the source`s website
*/
override suspend fun getFavicons(): Favicons {
return FaviconParser(webClient, domain).parseFavicons()
}
@CallSuper
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
keys.add(configKeyDomain)
}
override suspend fun getRelatedManga(seed: Manga): List<Manga> {
return RelatedMangaFinder(listOf(this)).invoke(seed)
}
/**
* Return [Manga] object by web link to it
* @see [Manga.publicUrl]
*/
override suspend fun resolveLink(resolver: LinkResolver, link: HttpUrl): Manga? = null
override fun intercept(chain: Interceptor.Chain): Response = chain.proceed(chain.request())
}

View File

@@ -0,0 +1,60 @@
package org.koitharu.kotatsu.parsers.core
import androidx.annotation.VisibleForTesting
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQuery
import org.koitharu.kotatsu.parsers.model.search.SearchableField
import org.koitharu.kotatsu.parsers.util.Paginator
@Deprecated("Too complex. Use PagedMangaParser instead")
internal abstract class FlexiblePagedMangaParser(
context: MangaLoaderContext,
source: MangaParserSource,
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @JvmField public val pageSize: Int,
searchPageSize: Int = pageSize,
) : FlexibleMangaParser(context, source) {
@JvmField
protected val paginator: Paginator = Paginator(pageSize)
@JvmField
protected val searchPaginator: Paginator = Paginator(searchPageSize)
final override suspend fun getList(query: MangaSearchQuery): List<Manga> {
var containTitleNameCriteria = false
query.criteria.forEach {
if (it.field == SearchableField.TITLE_NAME) {
containTitleNameCriteria = true
}
}
return searchManga(
paginator = if (containTitleNameCriteria) {
paginator
} else {
searchPaginator
},
query = query,
)
}
public abstract suspend fun getListPage(query: MangaSearchQuery, page: Int): List<Manga>
protected fun setFirstPage(firstPage: Int, firstPageForSearch: Int = firstPage) {
paginator.firstPage = firstPage
searchPaginator.firstPage = firstPageForSearch
}
private suspend fun searchManga(
paginator: Paginator,
query: MangaSearchQuery,
): List<Manga> {
val offset: Int = query.offset
val page = paginator.getPage(offset)
val list = getListPage(query, page)
paginator.onListReceived(offset, page, list.size)
return list
}
}

View File

@@ -0,0 +1,77 @@
package org.koitharu.kotatsu.parsers.core
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQuery
import org.koitharu.kotatsu.parsers.util.mergeWith
internal class MangaParserWrapper(
private val delegate: MangaParser,
) : MangaParser by delegate {
override val authorizationProvider: MangaParserAuthProvider?
get() = delegate as? MangaParserAuthProvider
@Deprecated("Too complex. Use getList with filter instead")
override suspend fun getList(query: MangaSearchQuery): List<Manga> = withContext(Dispatchers.Default) {
if (!query.skipValidation) {
searchQueryCapabilities.validate(query)
}
delegate.getList(query)
}
override suspend fun getList(
offset: Int,
order: SortOrder,
filter: MangaListFilter,
): List<Manga> = withContext(Dispatchers.Default) {
delegate.getList(offset, order, filter)
}
override suspend fun getDetails(manga: Manga): Manga = withContext(Dispatchers.Default) {
delegate.getDetails(manga)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> = withContext(Dispatchers.Default) {
delegate.getPages(chapter)
}
override suspend fun getPageUrl(page: MangaPage): String = withContext(Dispatchers.Default) {
delegate.getPageUrl(page)
}
override suspend fun getFilterOptions(): MangaListFilterOptions = withContext(Dispatchers.Default) {
delegate.getFilterOptions()
}
override suspend fun getFavicons(): Favicons = withContext(Dispatchers.Default) {
delegate.getFavicons()
}
override suspend fun getRelatedManga(seed: Manga): List<Manga> = withContext(Dispatchers.Default) {
delegate.getRelatedManga(seed)
}
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val headers = request.headers.newBuilder()
.mergeWith(delegate.getRequestHeaders(), replaceExisting = false)
.build()
val newRequest = request.newBuilder().headers(headers).build()
return delegate.intercept(ProxyChain(chain, newRequest))
}
private class ProxyChain(
private val delegate: Interceptor.Chain,
private val request: Request,
) : Interceptor.Chain by delegate {
override fun request(): Request = request
}
}

View File

@@ -0,0 +1,57 @@
package org.koitharu.kotatsu.parsers.core
import androidx.annotation.VisibleForTesting
import org.koitharu.kotatsu.parsers.InternalParsersApi
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.Paginator
@InternalParsersApi
public abstract class PagedMangaParser(
context: MangaLoaderContext,
source: MangaParserSource,
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @JvmField public val pageSize: Int,
searchPageSize: Int = pageSize,
) : AbstractMangaParser(context, source) {
@JvmField
protected val paginator: Paginator = Paginator(pageSize)
@JvmField
protected val searchPaginator: Paginator = Paginator(searchPageSize)
final override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
return getList(
paginator = if (filter.query.isNullOrEmpty()) {
paginator
} else {
searchPaginator
},
offset = offset,
order = order,
filter = filter,
)
}
public abstract suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga>
protected fun setFirstPage(firstPage: Int, firstPageForSearch: Int = firstPage) {
paginator.firstPage = firstPage
searchPaginator.firstPage = firstPageForSearch
}
private suspend fun getList(
paginator: Paginator,
offset: Int,
order: SortOrder,
filter: MangaListFilter,
): List<Manga> {
val page = paginator.getPage(offset)
val list = getListPage(page, order, filter)
paginator.onListReceived(offset, page, list.size)
return list
}
}

View File

@@ -0,0 +1,24 @@
package org.koitharu.kotatsu.parsers.core
import org.koitharu.kotatsu.parsers.InternalParsersApi
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder
@InternalParsersApi
public abstract class SinglePageMangaParser(
context: MangaLoaderContext,
source: MangaParserSource,
) : AbstractMangaParser(context, source) {
final override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
if (offset > 0) {
return emptyList()
}
return getList(order, filter)
}
public abstract suspend fun getList(order: SortOrder, filter: MangaListFilter): List<Manga>
}

View File

@@ -1,11 +1,13 @@
package org.koitharu.kotatsu.parsers.exception
import okio.IOException
import org.koitharu.kotatsu.parsers.InternalParsersApi
import org.koitharu.kotatsu.parsers.model.MangaSource
/**
* Authorization is required for access to the requested content
*/
class AuthRequiredException @InternalParsersApi constructor(
val source: MangaSource,
) : RuntimeException("Authorization required")
public class AuthRequiredException @InternalParsersApi @JvmOverloads constructor(
public val source: MangaSource,
cause: Throwable? = null,
) : IOException("Authorization required", cause)

View File

@@ -1,7 +0,0 @@
package org.koitharu.kotatsu.parsers.exception
import okio.IOException
class CloudFlareProtectedException(
val url: String,
) : IOException("Protected by CloudFlare: $url")

View File

@@ -1,3 +1,3 @@
package org.koitharu.kotatsu.parsers.exception
class ContentUnavailableException(message: String) : RuntimeException(message)
public class ContentUnavailableException(message: String) : RuntimeException(message)

View File

@@ -2,14 +2,15 @@ package org.koitharu.kotatsu.parsers.exception
import okio.IOException
import org.json.JSONArray
import org.koitharu.kotatsu.parsers.util.json.mapJSON
import org.koitharu.kotatsu.parsers.InternalParsersApi
import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNull
class GraphQLException(private val errors: JSONArray) : IOException() {
public class GraphQLException @InternalParsersApi constructor(errors: JSONArray) : IOException() {
val messages = errors.mapJSON {
public val messages: List<String> = errors.mapJSONNotNull {
it.getString("message")
}
override val message: String
get() = messages.joinToString("\n")
}
}

View File

@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.parsers.exception
import org.jsoup.HttpStatusException
import java.net.HttpURLConnection
class NotFoundException(
public class NotFoundException(
message: String,
url: String,
) : HttpStatusException(message, HttpURLConnection.HTTP_NOT_FOUND, url)
) : HttpStatusException(message, HttpURLConnection.HTTP_NOT_FOUND, url)

View File

@@ -2,8 +2,8 @@ package org.koitharu.kotatsu.parsers.exception
import org.koitharu.kotatsu.parsers.InternalParsersApi
class ParseException @InternalParsersApi @JvmOverloads constructor(
val shortMessage: String?,
val url: String,
public class ParseException @InternalParsersApi @JvmOverloads constructor(
public val shortMessage: String?,
public val url: String,
cause: Throwable? = null,
) : RuntimeException("$shortMessage at $url", cause)
) : RuntimeException("$shortMessage at $url", cause)

View File

@@ -0,0 +1,31 @@
package org.koitharu.kotatsu.parsers.exception
import okio.IOException
import java.time.Instant
import java.time.temporal.ChronoUnit
public class TooManyRequestExceptions(
public val url: String,
retryAfter: Long,
) : IOException("Too man requests") {
public val retryAt: Instant? = if (retryAfter > 0 && retryAfter < Long.MAX_VALUE) {
Instant.now().plusMillis(retryAfter)
} else {
null
}
public fun getRetryDelay(): Long {
if (retryAt == null) {
return -1L
}
return Instant.now().until(retryAt, ChronoUnit.MILLIS).coerceAtLeast(0L)
}
override val message: String?
get() = if (retryAt != null) {
"${super.message}, retry at $retryAt"
} else {
super.message
}
}

View File

@@ -2,4 +2,10 @@
package org.koitharu.kotatsu.parsers.model
const val RATING_UNKNOWN = -1f
public const val RATING_UNKNOWN: Float = -1f
public const val YEAR_UNKNOWN: Int = 0
public const val YEAR_MIN: Int = 1900
public const val YEAR_MAX: Int = 2099

View File

@@ -0,0 +1,7 @@
package org.koitharu.kotatsu.parsers.model
public enum class ContentRating {
SAFE,
SUGGESTIVE,
ADULT
}

View File

@@ -0,0 +1,36 @@
package org.koitharu.kotatsu.parsers.model
public enum class ContentType {
/**
* Standard manga, manhua, webtoons, etc
*/
MANGA,
MANHWA,
MANHUA,
/**
* Use this if the source provides mostly nsfw content.
*/
HENTAI,
/**
* Western comics
*/
COMICS,
NOVEL,
/**
* Use this type if no other suits your needs. For example, for an indie manga
*/
ONE_SHOT,
DOUJINSHI,
IMAGE_SET,
ARTIST_CG,
GAME_CG,
OTHER,
}

View File

@@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.model
public enum class Demographic {
SHOUNEN,
SHOUJO,
SEINEN,
JOSEI,
KODOMO,
NONE,
}

View File

@@ -2,13 +2,14 @@ package org.koitharu.kotatsu.parsers.model
import okhttp3.HttpUrl.Companion.toHttpUrl
class Favicon internal constructor(
val url: String,
val size: Int,
internal val rel: String?,
public data class Favicon(
@JvmField public val url: String,
@JvmField public val size: Int,
@JvmField internal val rel: String?,
) : Comparable<Favicon> {
val type: String = url.toHttpUrl().pathSegments.last()
@JvmField
public val type: String = url.toHttpUrl().pathSegments.last()
.substringAfterLast('.', "").lowercase()
override fun compareTo(other: Favicon): Int {
@@ -19,33 +20,9 @@ class Favicon internal constructor(
return relWeightOf(rel).compareTo(relWeightOf(other.rel))
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Favicon
if (url != other.url) return false
if (size != other.size) return false
if (rel != other.rel) return false
return true
}
override fun hashCode(): Int {
var result = url.hashCode()
result = 31 * result + size
result = 31 * result + rel.hashCode()
return result
}
override fun toString(): String {
return "Favicon(size=$size, type='$type', rel='$rel', url='$url')"
}
private fun relWeightOf(rel: String?) = when (rel) {
"apple-touch-icon" -> 1 // Prefer apple-touch-icon because it has a better quality
"mask-icon" -> -1
else -> 0
}
}
}

View File

@@ -1,8 +1,8 @@
package org.koitharu.kotatsu.parsers.model
class Favicons internal constructor(
public class Favicons(
favicons: Collection<Favicon>,
val referer: String,
@JvmField public val referer: String?,
) : Collection<Favicon> {
private val icons = favicons.sortedDescending()
@@ -18,6 +18,11 @@ class Favicons internal constructor(
override fun iterator(): Iterator<Favicon> = icons.iterator()
public operator fun minus(victim: Favicon): Favicons = Favicons(
favicons = icons.filterNot { it == victim },
referer = referer,
)
/**
* Finds a favicon whose size in pixels is greater than or equal to the specified size.
* If such icon is not available returns the largest icon
@@ -25,7 +30,7 @@ class Favicons internal constructor(
* @param types supported file types, e.g. png, svg, ico. May be null but not empty
*/
@JvmOverloads
fun find(size: Int, types: Set<String>? = null): Favicon? {
public fun find(size: Int, types: Set<String>? = null): Favicon? {
if (icons.isEmpty()) {
return null
}
@@ -42,4 +47,13 @@ class Favicons internal constructor(
}
return result
}
}
public companion object {
@JvmStatic
public val EMPTY: Favicons = Favicons(emptySet(), null)
@JvmStatic
public fun single(url: String): Favicons = Favicons(setOf(Favicon(url, 0, null)), null)
}
}

View File

@@ -1,158 +1,203 @@
package org.koitharu.kotatsu.parsers.model
import org.koitharu.kotatsu.parsers.InternalParsersApi
import androidx.collection.ArrayMap
import org.koitharu.kotatsu.parsers.util.findById
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
class Manga(
public data class Manga(
/**
* Unique identifier for manga
*/
val id: Long,
@JvmField public val id: Long,
/**
* Manga title, human-readable
*/
val title: String,
@JvmField public val title: String,
/**
* Alternative title (for example on other language), may be null
* Alternative titles (for example on other language), may be empty
*/
val altTitle: String?,
@JvmField public val altTitles: Set<String>,
/**
* Relative url to manga (**without** a domain) or any other uri.
* Used principally in parsers
*/
val url: String,
@JvmField public val url: String,
/**
* Absolute url to manga, must be ready to open in browser
*/
val publicUrl: String,
@JvmField public val publicUrl: String,
/**
* Normalized manga rating, must be in range of 0..1 or [RATING_UNKNOWN] if rating s unknown
* @see hasRating
*/
val rating: Float,
@JvmField public val rating: Float,
/**
* Indicates that manga may contain sensitive information (18+, NSFW)
*/
val isNsfw: Boolean,
@JvmField public val contentRating: ContentRating?,
/**
* Absolute link to the cover
* @see largeCoverUrl
*/
val coverUrl: String,
@JvmField public val coverUrl: String?,
/**
* Tags (genres) of the manga
*/
val tags: Set<MangaTag>,
@JvmField public val tags: Set<MangaTag>,
/**
* Manga status (ongoing, finished) or null if unknown
*/
val state: MangaState?,
@JvmField public val state: MangaState?,
/**
* Author of the manga, may be null
* Authors of the manga
*/
val author: String?,
@JvmField public val authors: Set<String>,
/**
* Large cover url (absolute), null if is no large cover
* @see coverUrl
*/
val largeCoverUrl: String? = null,
@JvmField public val largeCoverUrl: String? = null,
/**
* Manga description, may be html or null
*/
val description: String? = null,
@JvmField public val description: String? = null,
/**
* List of chapters
*/
val chapters: List<MangaChapter>? = null,
@JvmField public val chapters: List<MangaChapter>? = null,
/**
* Manga source
*/
val source: MangaSource,
@JvmField public val source: MangaSource,
) {
@Deprecated("Use other constructor")
public constructor(
/**
* Unique identifier for manga
*/
id: Long,
/**
* Manga title, human-readable
*/
title: String,
/**
* Alternative title (for example on other language), may be null
*/
altTitle: String?,
/**
* Relative url to manga (**without** a domain) or any other uri.
* Used principally in parsers
*/
url: String,
/**
* Absolute url to manga, must be ready to open in browser
*/
publicUrl: String,
/**
* Normalized manga rating, must be in range of 0..1 or [RATING_UNKNOWN] if rating s unknown
* @see hasRating
*/
rating: Float,
/**
* Indicates that manga may contain sensitive information (18+, NSFW)
*/
isNsfw: Boolean,
/**
* Absolute link to the cover
* @see largeCoverUrl
*/
coverUrl: String?,
/**
* Tags (genres) of the manga
*/
tags: Set<MangaTag>,
/**
* Manga status (ongoing, finished) or null if unknown
*/
state: MangaState?,
/**
* Authors of the manga
*/
author: String?,
/**
* Large cover url (absolute), null if is no large cover
* @see coverUrl
*/
largeCoverUrl: String? = null,
/**
* Manga description, may be html or null
*/
description: String? = null,
/**
* List of chapters
*/
chapters: List<MangaChapter>? = null,
/**
* Manga source
*/
source: MangaSource,
) : this(
id = id,
title = title,
altTitles = setOfNotNull(altTitle?.nullIfEmpty()),
url = url,
publicUrl = publicUrl,
rating = rating,
contentRating = if (isNsfw) ContentRating.ADULT else null,
coverUrl = coverUrl?.nullIfEmpty(),
tags = tags,
state = state,
authors = setOfNotNull(author),
largeCoverUrl = largeCoverUrl?.nullIfEmpty(),
description = description?.nullIfEmpty(),
chapters = chapters,
source = source,
)
/**
* Author of the manga, may be null
*/
@Deprecated("Please use authors")
public val author: String?
get() = authors.firstOrNull()
/**
* Alternative title (for example on other language), may be null
*/
@Deprecated("Please use altTitles")
public val altTitle: String?
get() = altTitles.firstOrNull()
/**
* Return if manga has a specified rating
* @see rating
*/
val hasRating: Boolean
public val hasRating: Boolean
get() = rating > 0f && rating <= 1f
fun getChapters(branch: String?): List<MangaChapter>? {
return chapters?.filter { x -> x.branch == branch }
@Deprecated("Use contentRating instead", ReplaceWith("contentRating == ContentRating.ADULT"))
public val isNsfw: Boolean
get() = contentRating == ContentRating.ADULT
public fun getChapters(branch: String?): List<MangaChapter> {
return chapters?.filter { x -> x.branch == branch }.orEmpty()
}
@InternalParsersApi
fun copy(
title: String = this.title,
altTitle: String? = this.altTitle,
publicUrl: String = this.publicUrl,
rating: Float = this.rating,
isNsfw: Boolean = this.isNsfw,
coverUrl: String = this.coverUrl,
tags: Set<MangaTag> = this.tags,
state: MangaState? = this.state,
author: String? = this.author,
largeCoverUrl: String? = this.largeCoverUrl,
description: String? = this.description,
chapters: List<MangaChapter>? = this.chapters,
) = Manga(
id = id,
title = title,
altTitle = altTitle,
url = url,
publicUrl = publicUrl,
rating = rating,
isNsfw = isNsfw,
coverUrl = coverUrl,
tags = tags,
state = state,
author = author,
largeCoverUrl = largeCoverUrl,
description = description,
chapters = chapters,
source = source,
)
public fun findChapterById(id: Long): MangaChapter? = chapters?.findById(id)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
public fun requireChapterById(id: Long): MangaChapter = findChapterById(id)
?: throw NoSuchElementException("Chapter with id $id not found")
other as Manga
if (id != other.id) return false
if (title != other.title) return false
if (altTitle != other.altTitle) return false
if (url != other.url) return false
if (publicUrl != other.publicUrl) return false
if (rating != other.rating) return false
if (isNsfw != other.isNsfw) return false
if (coverUrl != other.coverUrl) return false
if (tags != other.tags) return false
if (state != other.state) return false
if (author != other.author) return false
if (largeCoverUrl != other.largeCoverUrl) return false
if (description != other.description) return false
if (chapters != other.chapters) return false
if (source != other.source) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + title.hashCode()
result = 31 * result + (altTitle?.hashCode() ?: 0)
result = 31 * result + url.hashCode()
result = 31 * result + publicUrl.hashCode()
result = 31 * result + rating.hashCode()
result = 31 * result + isNsfw.hashCode()
result = 31 * result + coverUrl.hashCode()
result = 31 * result + tags.hashCode()
result = 31 * result + (state?.hashCode() ?: 0)
result = 31 * result + (author?.hashCode() ?: 0)
result = 31 * result + (largeCoverUrl?.hashCode() ?: 0)
result = 31 * result + (description?.hashCode() ?: 0)
result = 31 * result + (chapters?.hashCode() ?: 0)
result = 31 * result + source.hashCode()
public fun getBranches(): Map<String?, Int> {
if (chapters.isNullOrEmpty()) {
return emptyMap()
}
val result = ArrayMap<String?, Int>()
chapters.forEach {
val key = it.branch
result[key] = result.getOrDefault(key, 0) + 1
}
return result
}
}
}

View File

@@ -1,70 +1,65 @@
package org.koitharu.kotatsu.parsers.model
class MangaChapter(
import org.koitharu.kotatsu.parsers.util.formatSimple
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
public data class MangaChapter(
/**
* An unique id of chapter
*/
val id: Long,
@JvmField public val id: Long,
/**
* User-readable name of chapter
* User-readable name of chapter if provided by parser or null instead
* Do not pass manga title or chapter number here
*/
val name: String,
@JvmField public val title: String?,
/**
* Chapter number starting from 1
* Chapter number starting from 1, 0 if unknown
*/
val number: Int,
@JvmField public val number: Float,
/**
* Volume number starting from 1, 0 if unknown
*/
@JvmField public val volume: Int,
/**
* Relative url to chapter (**without** a domain) or any other uri.
* Used principally in parsers
*/
val url: String,
@JvmField public val url: String,
/**
* User-readable name of scanlator (releaser) or null if unknown
*/
val scanlator: String?,
@JvmField public val scanlator: String?,
/**
* Chapter upload date in milliseconds
*/
val uploadDate: Long,
@JvmField public val uploadDate: Long,
/**
* User-readable name of branch.
* A branch is a group of chapters that overlap (e.g. different languages)
*/
val branch: String?,
val source: MangaSource,
) : Comparable<MangaChapter> {
@JvmField public val branch: String?,
@JvmField public val source: MangaSource,
) {
override fun compareTo(other: MangaChapter): Int {
return number.compareTo(other.number)
@Deprecated("Use title instead", ReplaceWith("title"))
val name: String
get() = title.ifNullOrEmpty {
buildString {
if (volume > 0) append("Vol ").append(volume).append(' ')
if (number > 0) append("Chapter ").append(number.formatSimple()) else append("Unnamed")
}
}
public fun numberString(): String? = if (number > 0f) {
number.formatSimple()
} else {
null
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as MangaChapter
if (id != other.id) return false
if (name != other.name) return false
if (number != other.number) return false
if (url != other.url) return false
if (scanlator != other.scanlator) return false
if (uploadDate != other.uploadDate) return false
if (branch != other.branch) return false
if (source != other.source) return false
return true
public fun volumeString(): String? = if (volume > 0) {
volume.toString()
} else {
null
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + number
result = 31 * result + url.hashCode()
result = 31 * result + (scanlator?.hashCode() ?: 0)
result = 31 * result + uploadDate.hashCode()
result = 31 * result + (branch?.hashCode() ?: 0)
result = 31 * result + source.hashCode()
return result
}
}
}

View File

@@ -0,0 +1,88 @@
package org.koitharu.kotatsu.parsers.model
import java.util.*
public data class MangaListFilter(
@JvmField val query: String? = null,
@JvmField val tags: Set<MangaTag> = emptySet(),
@JvmField val tagsExclude: Set<MangaTag> = emptySet(),
@JvmField val locale: Locale? = null,
@JvmField val originalLocale: Locale? = null,
@JvmField val states: Set<MangaState> = emptySet(),
@JvmField val contentRating: Set<ContentRating> = emptySet(),
@JvmField val types: Set<ContentType> = emptySet(),
@JvmField val demographics: Set<Demographic> = emptySet(),
@JvmField val year: Int = YEAR_UNKNOWN,
@JvmField val yearFrom: Int = YEAR_UNKNOWN,
@JvmField val yearTo: Int = YEAR_UNKNOWN,
@JvmField val author: String? = null,
) {
private fun isNonSearchOptionsEmpty(): Boolean = tags.isEmpty() &&
tagsExclude.isEmpty() &&
locale == null &&
originalLocale == null &&
states.isEmpty() &&
contentRating.isEmpty() &&
year == YEAR_UNKNOWN &&
yearFrom == YEAR_UNKNOWN &&
yearTo == YEAR_UNKNOWN &&
types.isEmpty() &&
demographics.isEmpty() &&
author.isNullOrEmpty()
public fun isEmpty(): Boolean = isNonSearchOptionsEmpty() && query.isNullOrEmpty()
public fun isNotEmpty(): Boolean = !isEmpty()
public fun hasNonSearchOptions(): Boolean = !isNonSearchOptionsEmpty()
public companion object {
@JvmStatic
public val EMPTY: MangaListFilter = MangaListFilter()
}
internal class Builder {
private var query: String? = null
private val tags: MutableSet<MangaTag> = mutableSetOf()
private val tagsExclude: MutableSet<MangaTag> = mutableSetOf()
private var locale: Locale? = null
private var originalLocale: Locale? = null
private val states: MutableSet<MangaState> = mutableSetOf()
private val contentRating: MutableSet<ContentRating> = mutableSetOf()
private val types: MutableSet<ContentType> = mutableSetOf()
private val demographics: MutableSet<Demographic> = mutableSetOf()
private var year: Int = YEAR_UNKNOWN
private var yearFrom: Int = YEAR_UNKNOWN
private var yearTo: Int = YEAR_UNKNOWN
fun query(query: String?): Builder = apply { this.query = query }
fun addTag(tag: MangaTag): Builder = apply { tags.add(tag) }
fun addTags(tags: Collection<MangaTag>): Builder = apply { this.tags.addAll(tags) }
fun excludeTag(tag: MangaTag): Builder = apply { tagsExclude.add(tag) }
fun excludeTags(tags: Collection<MangaTag>): Builder = apply { this.tagsExclude.addAll(tags) }
fun locale(locale: Locale?): Builder = apply { this.locale = locale }
fun originalLocale(locale: Locale?): Builder = apply { this.originalLocale = locale }
fun addState(state: MangaState): Builder = apply { states.add(state) }
fun addStates(states: Collection<MangaState>): Builder = apply { this.states.addAll(states) }
fun addContentRating(rating: ContentRating): Builder = apply { contentRating.add(rating) }
fun addContentRatings(ratings: Collection<ContentRating>): Builder =
apply { this.contentRating.addAll(ratings) }
fun addType(type: ContentType): Builder = apply { types.add(type) }
fun addTypes(types: Collection<ContentType>): Builder = apply { this.types.addAll(types) }
fun addDemographic(demographic: Demographic): Builder = apply { demographics.add(demographic) }
fun addDemographics(demographics: Collection<Demographic>): Builder =
apply { this.demographics.addAll(demographics) }
fun year(year: Int): Builder = apply { this.year = year }
fun yearFrom(year: Int): Builder = apply { this.yearFrom = year }
fun yearTo(year: Int): Builder = apply { this.yearTo = year }
fun build(): MangaListFilter = MangaListFilter(
query, tags, tagsExclude, locale, originalLocale, states,
contentRating, types, demographics, year, yearFrom, yearTo,
)
}
}

View File

@@ -0,0 +1,56 @@
package org.koitharu.kotatsu.parsers.model
import org.koitharu.kotatsu.parsers.InternalParsersApi
public data class MangaListFilterCapabilities @InternalParsersApi constructor(
/**
* Whether parser supports filtering by more than one tag
* @see [MangaListFilter.tags]
* @see [MangaListFilterOptions.availableTags]
*/
val isMultipleTagsSupported: Boolean = false,
/**
* Whether parser supports tagsExclude field in filter
* @see [MangaListFilter.tagsExclude]
* @see [MangaListFilterOptions.availableTags]
*/
val isTagsExclusionSupported: Boolean = false,
/**
* Whether parser supports searching by string query
* @see [MangaListFilter.query]
*/
val isSearchSupported: Boolean = false,
/**
* Whether parser supports searching by string query combined within other filters
*/
val isSearchWithFiltersSupported: Boolean = false,
/**
* Whether parser supports searching/filtering by year
* @see [MangaListFilter.year]
*/
val isYearSupported: Boolean = false,
/**
* Whether parser supports searching by year range
* @see [MangaListFilter.yearFrom] and [MangaListFilter.yearTo]
*/
val isYearRangeSupported: Boolean = false,
/**
* Whether parser supports searching Original Languages
* @see [MangaListFilter.originalLocale]
* @see [MangaListFilterOptions.availableLocales]
*/
val isOriginalLocaleSupported: Boolean = false,
/**
* Whether parser supports searching by author name
* @see [MangaListFilter.author]
*/
val isAuthorSearchSupported: Boolean = false,
)

View File

@@ -0,0 +1,45 @@
package org.koitharu.kotatsu.parsers.model
import org.koitharu.kotatsu.parsers.InternalParsersApi
import java.util.*
public data class MangaListFilterOptions @InternalParsersApi constructor(
/**
* Available tags (genres)
*/
public val availableTags: Set<MangaTag> = emptySet(),
/**
* Supported [MangaState] variants for filtering. May be empty.
*
* For better performance use [EnumSet] for more than one item.
*/
public val availableStates: Set<MangaState> = emptySet(),
/**
* Supported [ContentRating] variants for filtering. May be empty.
*
* For better performance use [EnumSet] for more than one item.
*/
public val availableContentRating: Set<ContentRating> = emptySet(),
/**
* Supported [ContentType] variants for filtering. May be empty.
*
* For better performance use [EnumSet] for more than one item.
*/
public val availableContentTypes: Set<ContentType> = emptySet(),
/**
* Supported [Demographic] variants for filtering. May be empty.
*
* For better performance use [EnumSet] for more than one item.
*/
public val availableDemographics: Set<Demographic> = emptySet(),
/**
* Supported content locales for multilingual sources
*/
public val availableLocales: Set<Locale> = emptySet(),
)

View File

@@ -2,51 +2,21 @@ package org.koitharu.kotatsu.parsers.model
import org.koitharu.kotatsu.parsers.MangaParser
class MangaPage(
public data class MangaPage(
/**
* Unique identifier for manga
* Unique identifier for page
*/
val id: Long,
@JvmField public val id: Long,
/**
* Relative url to page (**without** a domain) or any other uri.
* Used principally in parsers.
* May contain link to image or html page.
* @see MangaParser.getPageUrl
*/
val url: String,
/**
* Absolute link to the chapter or website home page.
* Used in Referer header
*/
val referer: String,
@JvmField public val url: String,
/**
* Absolute url of the small page image if exists, null otherwise
*/
val preview: String?,
val source: MangaSource,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as MangaPage
if (id != other.id) return false
if (url != other.url) return false
if (referer != other.referer) return false
if (preview != other.preview) return false
if (source != other.source) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + url.hashCode()
result = 31 * result + referer.hashCode()
result = 31 * result + (preview?.hashCode() ?: 0)
result = 31 * result + source.hashCode()
return result
}
}
@JvmField public val preview: String?,
@JvmField public val source: MangaSource,
)

View File

@@ -0,0 +1,6 @@
package org.koitharu.kotatsu.parsers.model
public interface MangaSource {
public val name: String
}

View File

@@ -1,5 +1,5 @@
package org.koitharu.kotatsu.parsers.model
enum class MangaState {
ONGOING, FINISHED
}
public enum class MangaState {
ONGOING, FINISHED, ABANDONED, PAUSED, UPCOMING, RESTRICTED
}

View File

@@ -2,36 +2,15 @@ package org.koitharu.kotatsu.parsers.model
import org.koitharu.kotatsu.parsers.MangaParser
class MangaTag(
public data class MangaTag(
/**
* User-readable tag title, should be in Title case
*/
val title: String,
@JvmField public val title: String,
/**
* Identifier of a tag, must be unique among the source.
* @see MangaParser.getList
*/
val key: String,
val source: MangaSource,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as MangaTag
if (title != other.title) return false
if (key != other.key) return false
if (source != other.source) return false
return true
}
override fun hashCode(): Int {
var result = title.hashCode()
result = 31 * result + key.hashCode()
result = 31 * result + source.hashCode()
return result
}
}
@JvmField public val key: String,
@JvmField public val source: MangaSource,
)

View File

@@ -1,9 +1,22 @@
package org.koitharu.kotatsu.parsers.model
enum class SortOrder {
public enum class SortOrder {
UPDATED,
UPDATED_ASC,
POPULARITY,
POPULARITY_ASC,
RATING,
RATING_ASC,
NEWEST,
ALPHABETICAL
}
NEWEST_ASC,
ALPHABETICAL,
ALPHABETICAL_DESC,
ADDED,
ADDED_ASC,
RELEVANCE,
POPULARITY_HOUR,
POPULARITY_TODAY,
POPULARITY_WEEK,
POPULARITY_MONTH,
POPULARITY_YEAR,
}

View File

@@ -3,9 +3,9 @@ package org.koitharu.kotatsu.parsers.model
import org.koitharu.kotatsu.parsers.InternalParsersApi
@InternalParsersApi
class WordSet(private vararg val words: String) {
public class WordSet(private vararg val words: String) {
fun anyWordIn(dateString: String): Boolean = words.any {
dateString.contains(it, ignoreCase = true)
}
}
public fun anyWordIn(dateString: String): Boolean = words.any { dateString.contains(it, ignoreCase = true) }
public fun startsWith(dateString: String): Boolean = words.any { dateString.startsWith(it, ignoreCase = true) }
public fun endsWith(dateString: String): Boolean = words.any { dateString.endsWith(it, ignoreCase = true) }
}

View File

@@ -0,0 +1,90 @@
package org.koitharu.kotatsu.parsers.model.search
import androidx.collection.ArrayMap
import androidx.collection.ArraySet
import org.koitharu.kotatsu.parsers.model.SortOrder
/**
* Represents a search query for filtering and sorting manga search results.
* This class is immutable and must be constructed using the [Builder].
*
* @property criteria The set of search criteria applied to the query.
* @property order The sorting order for the results (optional).
* @property offset The offset number for paginated search results (optional).
*/
@Deprecated("Too complex. Use MangaListFilter instead")
@ConsistentCopyVisibility
public data class MangaSearchQuery private constructor(
@JvmField public val criteria: Set<QueryCriteria<*>>,
@JvmField public val order: SortOrder?,
@JvmField public val offset: Int,
@JvmField public val skipValidation: Boolean,
) {
public fun newBuilder(): Builder = Builder(this)
public class Builder {
private val criteria = ArraySet<QueryCriteria<*>>()
private var order: SortOrder? = null
private var offset: Int = 0
private var skipValidation: Boolean = false
public constructor()
public constructor(query: MangaSearchQuery) : this() {
criteria.addAll(query.criteria)
order = query.order
offset = query.offset
}
public fun criterion(criterion: QueryCriteria<*>): Builder = apply { criteria.add(criterion) }
public fun order(order: SortOrder?): Builder = apply { this.order = order }
public fun offset(offset: Int): Builder = apply { this.offset = offset }
public fun skipValidation(skip: Boolean): Builder = apply { this.skipValidation = skip }
@Throws(IllegalArgumentException::class)
public fun build(): MangaSearchQuery {
return MangaSearchQuery(deduplicateCriteria(criteria), order, offset, skipValidation)
}
private fun deduplicateCriteria(criteria: Set<QueryCriteria<*>>): Set<QueryCriteria<*>> {
val uniqueCriteria =
ArrayMap<Pair<SearchableField, Class<out QueryCriteria<*>>>, QueryCriteria<*>>(criteria.size)
for (criterion in criteria) {
val key = criterion.field to criterion::class.java
val existing = uniqueCriteria[key]
when {
existing == null -> uniqueCriteria[key] = criterion
existing is QueryCriteria.Include<*> && criterion is QueryCriteria.Include<*> -> {
uniqueCriteria[key] =
QueryCriteria.Include(criterion.field, existing.values union criterion.values)
}
existing is QueryCriteria.Exclude<*> && criterion is QueryCriteria.Exclude<*> -> {
uniqueCriteria[key] =
QueryCriteria.Exclude(criterion.field, existing.values union criterion.values)
}
else -> throw IllegalArgumentException(
"Match and Range have only one criterion per type, but found duplicates for: ${criterion.field} in ${criterion::class.simpleName}",
)
}
}
return uniqueCriteria.values.toSet()
}
}
public companion object {
public val EMPTY: MangaSearchQuery = MangaSearchQuery(emptySet(), null, 0, false)
}
}

View File

@@ -0,0 +1,48 @@
package org.koitharu.kotatsu.parsers.model.search
import androidx.collection.ArraySet
import org.koitharu.kotatsu.parsers.model.search.QueryCriteria.*
import org.koitharu.kotatsu.parsers.util.mapToSet
@Deprecated("Too complex. Use MangaListFilterCapabilities instead")
@ExposedCopyVisibility
public data class MangaSearchQueryCapabilities internal constructor(
public val capabilities: Set<SearchCapability>,
) {
public constructor(vararg capabilities: SearchCapability) : this(ArraySet(capabilities))
internal fun validate(query: MangaSearchQuery) {
val strictFields = capabilities.filter { it.isExclusive }.mapToSet { it.field }
val usedStrictFields = query.criteria.mapToSet { it.field }.intersect(strictFields)
require(usedStrictFields.isEmpty() || query.criteria.size <= 1) {
"Query contains multiple criteria, but at least one field (${usedStrictFields.joinToString()}) does not support multiple criteria."
}
for (criterion in query.criteria) {
val capability = requireNotNull(capabilities.find { it.field == criterion.field }) {
"Unsupported search field: ${criterion.field}"
}
require(criterion::class in capability.criteriaTypes) {
"Unsupported search criterion: ${criterion::class.simpleName} for field ${criterion.field}"
}
// Ensure single value per criterion if supportMultiValue is false
if (!capability.isMultiple) {
when (criterion) {
is Include<*> -> require(criterion.values.size <= 1) {
"Multiple values are not allowed for field ${criterion.field}"
}
is Exclude<*> -> require(criterion.values.size <= 1) {
"Multiple values are not allowed for field ${criterion.field}"
}
is Range<*> -> Unit // Range is always valid (from, to)
is Match<*> -> Unit // Match always has a single value
}
}
}
}
}

View File

@@ -0,0 +1,106 @@
package org.koitharu.kotatsu.parsers.model.search
/**
* Represents a generic search criterion used for filtering manga search results.
* Each criterion applies a specific condition to a [SearchableField] and operates on values of type [T].
*
* @param T The type of value associated with the search criterion.
* @property field The field to which this search criterion applies.
*/
@Deprecated("Too complex")
public sealed interface QueryCriteria<T> {
public val field: SearchableField
override fun equals(other: Any?): Boolean
override fun hashCode(): Int
/**
* Represents an inclusion criterion that allows search results based on a set of allowed values.
*
* @param T The type of value being included in the search.
* @property values The set of values that should be included in the search results.
*
* ### Example Usage:
* ```kotlin
* val genreFilter = QueryCriteria.Include(SearchableField.STATE, setOf(MangaState.ONGOING, MangaState.FINISHED))
* ```
*/
public data class Include<T : Any>(
public override val field: SearchableField,
@JvmField public val values: Set<T>,
) : QueryCriteria<T> {
init {
check(values.all { x -> field.type.isInstance(x) })
}
}
/**
* Represents an exclusion criterion that exclude results containing certain values.
*
* @param T The type of value being excluded from the search.
* @property values The set of values that should be excluded from the search results.
*
* ### Example Usage:
* ```kotlin
* val excludeTag = QueryCriteria.Exclude(SearchableField.TAG, setOf(MangaTag(key, title, source)))
* ```
*/
public data class Exclude<T : Any>(
public override val field: SearchableField,
@JvmField public val values: Set<T>,
) : QueryCriteria<T> {
init {
check(values.all { x -> field.type.isInstance(x) })
}
}
/**
* Represents a range criterion that allows search based on a range of values.
*
* @param T The type of value used in the range (must be comparable).
* @property from The starting value of the range (inclusive).
* @property to The ending value of the range (inclusive).
*
* ### Example Usage:
* ```kotlin
* val yearRange = QueryCriteria.Range(SearchableField.PUBLICATION_YEAR, 2000, 2020)
* ```
*/
public data class Range<T : Comparable<T>>(
public override val field: SearchableField,
@JvmField public val from: T,
@JvmField public val to: T,
) : QueryCriteria<T> {
init {
check(field.type.isInstance(from))
check(field.type.isInstance(to))
}
}
/**
* Represents a match criterion that search results based on an exact match of a value.
*
* @param T The type of value being matched.
* @property value The exact value that must be matched.
*
* ### Example Usage:
* ```kotlin
* val titleMatch = QueryCriteria.Match(SearchableField.TITLE, "manga title")
* ```
*/
public data class Match<T : Any>(
public override val field: SearchableField,
@JvmField public val value: T,
) : QueryCriteria<T> {
init {
check(field.type.isInstance(value))
}
}
}

View File

@@ -0,0 +1,34 @@
package org.koitharu.kotatsu.parsers.model.search
import kotlin.reflect.KClass
/**
* Defines the search capabilities of a given field in the manga search query.
*
* @property field The searchable field that this capability applies to.
* Example values:
* - `SearchableField.TITLE_NAME` for searching by title.
* - `SearchableField.AUTHOR` for searching by author names.
* - `SearchableField.TAG` for filtering by tags.
* @property criteriaTypes The set of supported criteria types for the field.
* Example values:
* - `setOf(Include::class, Exclude::class)` selected field supports inclusion/exclusion criteria.
* - `setOf(Range::class)` selected field support numerical range criteria.
* @property isMultiValue Indicates whether the field supports multiple values.
* - `true` if multiple values can be provided (e.g., multiple tags or authors).
* - `false` if only a single value is allowed (e.g., only one tag or author).
* @property isExclusive Specifies whether the field can be used alongside other criteria.
* - `true` if this field can be used with other search criteria.
* - `false` if using this field requires it to be the only criterion in query.
*/
@Deprecated("Too complex")
public data class SearchCapability(
/** The searchable field that this capability applies to. */
@JvmField public val field: SearchableField,
/** The set of supported criteria types for this field. */
@JvmField public val criteriaTypes: Set<KClass<out QueryCriteria<*>>>,
/** Indicates whether the field supports multiple values. */
@JvmField public val isMultiple: Boolean,
/** Specifies whether the field can be used alongside other criteria. */
@JvmField public val isExclusive: Boolean = false,
)

View File

@@ -0,0 +1,24 @@
package org.koitharu.kotatsu.parsers.model.search
import org.koitharu.kotatsu.parsers.model.*
import java.util.*
/**
* Represents the various fields that can be used for searching manga.
* Each field is associated with a specific data type that defines its expected values.
*
* @property type The Java class representing the expected type of values for this field.
*/
@Deprecated("Too complex")
public enum class SearchableField(public val type: Class<*>) {
TITLE_NAME(String::class.java),
TAG(MangaTag::class.java),
AUTHOR(MangaTag::class.java),
LANGUAGE(Locale::class.java),
ORIGINAL_LANGUAGE(Locale::class.java),
STATE(MangaState::class.java),
CONTENT_TYPE(ContentType::class.java),
CONTENT_RATING(ContentRating::class.java),
DEMOGRAPHIC(Demographic::class.java),
PUBLICATION_YEAR(Int::class.javaObjectType);
}

View File

@@ -0,0 +1,47 @@
package org.koitharu.kotatsu.parsers.network
import okhttp3.CookieJar
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Response
import org.jsoup.Jsoup
import java.net.HttpURLConnection.HTTP_FORBIDDEN
import java.net.HttpURLConnection.HTTP_UNAVAILABLE
public object CloudFlareHelper {
public const val PROTECTION_NOT_DETECTED: Int = 0
public const val PROTECTION_CAPTCHA: Int = 1
public const val PROTECTION_BLOCKED: Int = 2
private const val CF_CLEARANCE = "cf_clearance"
public fun checkResponseForProtection(response: Response): Int {
if (response.code != HTTP_FORBIDDEN && response.code != HTTP_UNAVAILABLE) {
return PROTECTION_NOT_DETECTED
}
val content = try {
response.peekBody(Long.MAX_VALUE).use {
Jsoup.parse(it.byteStream(), Charsets.UTF_8.name(), response.request.url.toString())
}
} catch (_: IllegalStateException) {
return PROTECTION_NOT_DETECTED
}
return when {
content.selectFirst("h2[data-translate=\"blocked_why_headline\"]") != null -> PROTECTION_BLOCKED
content.getElementById("challenge-error-title") != null || content.getElementById("challenge-error-text") != null -> PROTECTION_CAPTCHA
else -> PROTECTION_NOT_DETECTED
}
}
public fun getClearanceCookie(cookieJar: CookieJar, url: String): String? {
return cookieJar.loadForRequest(url.toHttpUrl()).find { it.name == CF_CLEARANCE }?.value
}
public fun isCloudFlareCookie(name: String): Boolean {
return name.startsWith("cf_")
|| name.startsWith("_cf")
|| name.startsWith("__cf")
|| name == "csrftoken"
}
}

View File

@@ -0,0 +1,133 @@
package org.koitharu.kotatsu.parsers.network
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import org.jsoup.HttpStatusException
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import org.koitharu.kotatsu.parsers.exception.GraphQLException
import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.parseJson
import java.net.HttpURLConnection
public class OkHttpWebClient(
private val httpClient: OkHttpClient,
private val mangaSource: MangaSource,
) : WebClient {
override suspend fun httpGet(url: HttpUrl, extraHeaders: Headers?): Response {
val request = Request.Builder()
.get()
.url(url)
.addTags()
.addExtraHeaders(extraHeaders)
return httpClient.newCall(request.build()).await().ensureSuccess()
}
override suspend fun httpHead(url: HttpUrl): Response {
val request = Request.Builder()
.head()
.url(url)
.addTags()
return httpClient.newCall(request.build()).await().ensureSuccess()
}
override suspend fun httpPost(url: HttpUrl, form: Map<String, String>, extraHeaders: Headers?): Response {
val body = FormBody.Builder()
form.forEach { (k, v) ->
body.addEncoded(k, v)
}
val request = Request.Builder()
.post(body.build())
.url(url)
.addTags()
.addExtraHeaders(extraHeaders)
return httpClient.newCall(request.build()).await().ensureSuccess()
}
override suspend fun httpPost(url: HttpUrl, payload: String, extraHeaders: Headers?): Response {
val body = FormBody.Builder()
payload.split('&').forEach {
val pos = it.indexOf('=')
if (pos != -1) {
val k = it.substring(0, pos)
val v = it.substring(pos + 1)
body.addEncoded(k, v)
}
}
val request = Request.Builder()
.post(body.build())
.url(url)
.addTags()
.addExtraHeaders(extraHeaders)
return httpClient.newCall(request.build()).await().ensureSuccess()
}
override suspend fun httpPost(url: HttpUrl, body: JSONObject, extraHeaders: Headers?): Response {
val mediaType = "application/json; charset=utf-8".toMediaType()
val requestBody = body.toString().toRequestBody(mediaType)
val request = Request.Builder()
.post(requestBody)
.url(url)
.addTags()
.addExtraHeaders(extraHeaders)
return httpClient.newCall(request.build()).await().ensureSuccess()
}
override suspend fun graphQLQuery(endpoint: String, query: String): JSONObject {
val body = JSONObject()
body.put("operationName", null as Any?)
body.put("variables", JSONObject())
body.put("query", "{$query}")
val mediaType = "application/json; charset=utf-8".toMediaType()
val requestBody = body.toString().toRequestBody(mediaType)
val request = Request.Builder()
.post(requestBody)
.url(endpoint)
.addTags()
val json = httpClient.newCall(request.build()).await().parseJson()
json.optJSONArray("errors")?.let {
if (it.length() != 0) {
throw GraphQLException(it)
}
}
return json
}
private fun Request.Builder.addTags(): Request.Builder {
tag(MangaSource::class.java, mangaSource)
return this
}
private fun Request.Builder.addExtraHeaders(headers: Headers?): Request.Builder {
if (headers != null) {
headers(headers)
}
return this
}
private fun Response.ensureSuccess(): Response {
val exception: Exception? = when (code) { // Catch some error codes, not all
HttpURLConnection.HTTP_NOT_FOUND -> NotFoundException(message, request.url.toString())
HttpURLConnection.HTTP_UNAUTHORIZED -> request.tag(MangaSource::class.java)?.let {
AuthRequiredException(it)
} ?: HttpStatusException(message, code, request.url.toString())
in 400..599 -> HttpStatusException(message, code, request.url.toString())
else -> null
}
if (exception != null) {
runCatching {
close()
}.onFailure {
exception.addSuppressed(it)
}
throw exception
}
return this
}
}

View File

@@ -0,0 +1,17 @@
package org.koitharu.kotatsu.parsers.network
public object UserAgents {
public const val CHROME_MOBILE: String =
"Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.196 Mobile Safari/537.36"
public const val FIREFOX_MOBILE: String =
"Mozilla/5.0 (Android 14; Mobile; LG-M255; rv:123.0) Gecko/123.0 Firefox/123.0"
public const val CHROME_DESKTOP: String =
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
public const val FIREFOX_DESKTOP: String = "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/116.0"
public const val KOTATSU: String = "Kotatsu/6.8 (Android 13;;; en)"
}

View File

@@ -0,0 +1,117 @@
package org.koitharu.kotatsu.parsers.network
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Response
import org.json.JSONObject
public interface WebClient {
/**
* Do a GET http request to specific url
* @param url
*/
public suspend fun httpGet(url: String): Response = httpGet(url.toHttpUrl())
public suspend fun httpGet(url: String, extraHeaders: Headers?): Response = httpGet(url.toHttpUrl(), extraHeaders)
/**
* Do a GET http request to specific url
* @param url
*/
public suspend fun httpGet(url: HttpUrl): Response = httpGet(url, null)
/**
* Do a GET http request to specific url
* @param url
* @param extraHeaders additional HTTP headers for request
*/
public suspend fun httpGet(url: HttpUrl, extraHeaders: Headers?): Response
/**
* Do a HEAD http request to specific url
* @param url
*/
public suspend fun httpHead(url: String): Response = httpHead(url.toHttpUrl())
/**
* Do a HEAD http request to specific url
* @param url
*/
public suspend fun httpHead(url: HttpUrl): Response
/**
* Do a POST http request to specific url with `multipart/form-data` payload
* @param url
* @param form payload as key=>value map
*/
public suspend fun httpPost(url: String, form: Map<String, String>): Response =
httpPost(url.toHttpUrl(), form, null)
/**
* Do a POST http request to specific url with `multipart/form-data` payload
* @param url
* @param form payload as key=>value map
*/
public suspend fun httpPost(url: HttpUrl, form: Map<String, String>): Response = httpPost(url, form, null)
/**
* Do a POST http request to specific url with `multipart/form-data` payload
* @param url
* @param form payload as key=>value map
* @param extraHeaders additional HTTP headers for request
*/
public suspend fun httpPost(url: HttpUrl, form: Map<String, String>, extraHeaders: Headers?): Response
/**
* Do a POST http request to specific url with `multipart/form-data` payload
* @param url
* @param payload payload as `key=value` string with `&` separator
*/
public suspend fun httpPost(url: String, payload: String): Response = httpPost(url.toHttpUrl(), payload, null)
/**
* Do a POST http request to specific url with `multipart/form-data` payload
* @param url
* @param payload payload as `key=value` string with `&` separator
*/
public suspend fun httpPost(url: HttpUrl, payload: String): Response = httpPost(url, payload, null)
/**
* Do a POST http request to specific url with `multipart/form-data` payload
* @param url
* @param payload payload as `key=value` string with `&` separator
* @param extraHeaders additional HTTP headers for request
*/
public suspend fun httpPost(url: HttpUrl, payload: String, extraHeaders: Headers?): Response
/**
* Do a POST http request to specific url with json payload
* @param url
* @param body
*/
public suspend fun httpPost(url: String, body: JSONObject): Response = httpPost(url.toHttpUrl(), body, null)
/**
* Do a POST http request to specific url with json payload
* @param url
* @param body
*/
public suspend fun httpPost(url: HttpUrl, body: JSONObject): Response = httpPost(url, body, null)
/**
* Do a POST http request to specific url with json payload
* @param url
* @param body
* @param extraHeaders additional HTTP headers for request
*/
public suspend fun httpPost(url: HttpUrl, body: JSONObject, extraHeaders: Headers?): Response
/**
* Do a GraphQL request to specific url
* @param endpoint an url
* @param query GraphQL request payload
*/
public suspend fun graphQLQuery(endpoint: String, query: String): JSONObject
}

View File

@@ -1,248 +0,0 @@
package org.koitharu.kotatsu.parsers.site
import androidx.collection.ArrayMap
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.json.JSONArray
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.HashSet
@MangaSourceParser("BLOGTRUYEN", "BlogTruyen", "vi")
class BlogTruyenParser(override val context: MangaLoaderContext) :
PagedMangaParser(MangaSource.BLOGTRUYEN, pageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("blogtruyen.vn", null)
override val sortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED)
private val mutex = Mutex()
private val dateFormat = SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.US)
private var cacheTags: ArrayMap<String, MangaTag>? = null
override suspend fun getDetails(manga: Manga): Manga {
val doc = context.httpGet(manga.url.toAbsoluteUrl(getDomain())).parseHtml()
val descriptionElement = doc.selectFirstOrThrow("div.description")
val statusText = descriptionElement
.selectFirst("p:contains(Trạng thái) > span.color-red")
?.text()
val state = when (statusText) {
"Đang tiến hành" -> MangaState.ONGOING
"Đã hoàn thành" -> MangaState.FINISHED
else -> null
}
val rating = doc.selectFirst("span.total-vote")?.attr("ng-init")?.let { text ->
val like = text.substringAfter("TotalLike=")
.substringBefore(';')
.toIntOrNull() ?: return@let RATING_UNKNOWN
val dislike = text.substringAfter("TotalDisLike=")
.toIntOrNull() ?: return@let RATING_UNKNOWN
when {
like == 0 && dislike == 0 -> RATING_UNKNOWN
else -> like.toFloat() / (like + dislike)
}
}
val tagMap = getOrCreateTagMap()
val tags = descriptionElement.select("p > span.category").mapNotNullToSet {
val tagName = it.selectFirst("a")?.text()?.trim() ?: return@mapNotNullToSet null
tagMap[tagName]
}
return manga.copy(
tags = tags,
author = descriptionElement.selectFirst("p:contains(Tác giả) > a")?.text(),
description = doc.selectFirst(".detail .content")?.html(),
chapters = parseChapterList(doc),
largeCoverUrl = doc.selectLast("div.thumbnail > img")?.attrAsAbsoluteUrlOrNull("src"),
state = state,
rating = rating ?: RATING_UNKNOWN,
isNsfw = doc.getElementById("warningCategory") != null
)
}
private fun parseChapterList(doc: Document): List<MangaChapter> {
val chapterList = doc.select("#list-chapters > p")
return chapterList.asReversed().mapChapters { index, element ->
val titleElement = element.selectFirst("span.title > a") ?: return@mapChapters null
val name = titleElement.text()
val relativeUrl = titleElement.attrAsRelativeUrl("href")
val id = relativeUrl.substringAfter('/').substringBefore('/')
val uploadDate = dateFormat.tryParse(element.select("span.publishedDate").text())
MangaChapter(
id = generateUid(id),
name = name,
number = index + 1,
url = relativeUrl,
scanlator = null,
uploadDate = uploadDate,
branch = null,
source = source
)
}
}
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
return when {
!query.isNullOrEmpty() -> {
val searchUrl = "https://${getDomain()}/timkiem/nangcao/1/0/-1/-1?txt=${query.urlEncoded()}&p=$page"
val searchContent = context.httpGet(searchUrl).parseHtml()
.selectFirst("section.list-manga-bycate > div.list")
parseMangaList(searchContent)
}
!tags.isNullOrEmpty() -> {
val tag = tags.oneOrThrowIfMany()!!
val categoryAjax = "https://${getDomain()}/ajax/Category/AjaxLoadMangaByCategory?id=${tag.key}&orderBy=5&p=$page"
val listContent = context.httpGet(categoryAjax).parseHtml().selectFirst("div.list")
parseMangaList(listContent)
}
else -> getNormalList(page)
}
}
private suspend fun getNormalList(page: Int): List<Manga> {
val pageLink = "https://${getDomain()}/page-$page"
val doc = context.httpGet(pageLink).parseHtml()
val listElements = doc.selectFirstOrThrow("section.list-mainpage.listview")
.select("div.bg-white.storyitem")
return listElements.mapNotNull {
val linkTag = it.selectFirst("div.fl-l > a") ?: return@mapNotNull null
val relativeUrl = linkTag.attrAsRelativeUrl("href")
val tagMap = getOrCreateTagMap()
val tags = it.select("footer > div.category > a").mapNotNullToSet { a ->
tagMap[a.text()]
}
Manga(
id = generateUid(relativeUrl),
title = linkTag.attr("title"),
altTitle = null,
description = it.selectFirst("p.al-j.break.line-height-15")?.text(),
url = relativeUrl,
publicUrl = relativeUrl.toAbsoluteUrl(getDomain()),
coverUrl = linkTag.selectLast("img")?.attr("src").orEmpty(),
source = source,
tags = tags,
isNsfw = false,
rating = RATING_UNKNOWN,
author = null,
state = null,
)
}
}
private fun parseMangaList(listElement: Element?): List<Manga> {
listElement ?: return emptyList()
return listElement.select("span.tiptip[data-tiptip]").mapNotNull {
val mangaInfo = listElement.getElementById(it.attr("data-tiptip")) ?: return@mapNotNull null
val a = it.selectFirst("a") ?: return@mapNotNull null
val relativeUrl = a.attrAsRelativeUrl("href")
Manga(
id = generateUid(relativeUrl),
title = a.text(),
altTitle = null,
description = mangaInfo.select("div.al-j.fs-12").text(),
url = relativeUrl,
publicUrl = relativeUrl.toAbsoluteUrl(getDomain()),
coverUrl = mangaInfo.selectFirst("div > img.img")?.absUrl("src").orEmpty(),
isNsfw = false,
rating = RATING_UNKNOWN,
tags = emptySet(),
author = null,
state = null,
source = source,
)
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
fun generateImageId(index: Int) = generateUid("${chapter.url}/$index")
val doc = context.httpGet(chapter.url.toAbsoluteUrl(getDomain())).parseHtml()
val pages = ArrayList<MangaPage>()
val referer = chapter.url.toAbsoluteUrl(getDomain())
doc.select("#content > img").forEach { img ->
val url = img.attrAsRelativeUrl("src")
pages.add(
MangaPage(
id = generateImageId(pages.lastIndex),
url = url,
referer = referer,
preview = null,
source = source,
)
)
}
// Some chapters use js script to render images
val script = doc.selectLast("#content > script")
if (script != null && script.data().contains("listImageCaption")) {
val imagesStr = script.data().substringBefore(';').substringAfterLast('=').trim()
val imageArr = JSONArray(imagesStr)
for (i in 0 until imageArr.length()) {
val imageUrl = imageArr.getJSONObject(i).getString("url")
pages.add(
MangaPage(
id = generateImageId(pages.lastIndex),
url = imageUrl,
referer = referer,
preview = null,
source = source
)
)
}
}
return pages
}
override suspend fun getTags(): Set<MangaTag> {
val map = getOrCreateTagMap()
val tags = HashSet<MangaTag>(map.size)
for (entry in map) {
tags.add(entry.value)
}
return tags
}
private suspend fun getOrCreateTagMap(): ArrayMap<String, MangaTag> = mutex.withLock {
cacheTags?.let { return@withLock it }
val doc = context.httpGet("/timkiem/nangcao".toAbsoluteUrl(getDomain())).parseHtml()
val tagItems = doc.select("li[data-id]")
val tagMap = ArrayMap<String, MangaTag>(tagItems.size)
for (tag in tagItems) {
val title = tag.text().trim()
tagMap[tag.text().trim()] = MangaTag(
title = title,
key = tag.attr("data-id"),
source = source
)
}
cacheTags = tagMap
tagMap
}
}

View File

@@ -1,216 +0,0 @@
package org.koitharu.kotatsu.parsers.site
import androidx.collection.ArraySet
import androidx.collection.SparseArrayCompat
import org.json.JSONArray
import org.json.JSONObject
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.*
import java.text.SimpleDateFormat
import java.util.*
/**
* https://api.comick.fun/docs/static/index.html
*/
private const val PAGE_SIZE = 20
private const val CHAPTERS_LIMIT = 99999
@MangaSourceParser("COMICK_FUN", "ComicK")
internal class ComickFunParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.COMICK_FUN) {
override val configKeyDomain = ConfigKey.Domain("comick.fun", null)
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY,
SortOrder.UPDATED,
SortOrder.RATING,
)
@Volatile
private var cachedTags: SparseArrayCompat<MangaTag>? = null
override suspend fun getList(
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val domain = getDomain()
val url = buildString {
append("https://api.")
append(domain)
append("/search?tachiyomi=true")
if (!query.isNullOrEmpty()) {
if (offset > 0) {
return emptyList()
}
append("&q=")
append(query.urlEncoded())
} else {
append("&limit=")
append(PAGE_SIZE)
append("&page=")
append((offset / PAGE_SIZE) + 1)
if (!tags.isNullOrEmpty()) {
append("&genres=")
appendAll(tags, "&genres=", MangaTag::key)
}
append("&sort=") // view, uploaded, rating, follow, user_follow_count
append(
when (sortOrder) {
SortOrder.POPULARITY -> "view"
SortOrder.RATING -> "rating"
else -> "uploaded"
},
)
}
}
val ja = context.httpGet(url).parseJsonArray()
val tagsMap = cachedTags ?: loadTags()
return ja.mapJSON { jo ->
val slug = jo.getString("slug")
Manga(
id = generateUid(slug),
title = jo.getString("title"),
altTitle = null,
url = slug,
publicUrl = "https://$domain/comic/$slug",
rating = jo.getDoubleOrDefault("rating", -10.0).toFloat() / 10f,
isNsfw = false,
coverUrl = jo.getString("cover_url"),
largeCoverUrl = null,
description = jo.getStringOrNull("desc"),
tags = jo.selectGenres("genres", tagsMap),
state = runCatching {
if (jo.getBoolean("translation_completed")) {
MangaState.FINISHED
} else {
MangaState.ONGOING
}
}.getOrNull(),
author = null,
source = source,
)
}
}
override suspend fun getDetails(manga: Manga): Manga {
val domain = getDomain()
val url = "https://api.$domain/comic/${manga.url}?tachiyomi=true"
val jo = context.httpGet(url).parseJson()
val comic = jo.getJSONObject("comic")
return manga.copy(
title = comic.getString("title"),
altTitle = null, // TODO
isNsfw = jo.getBoolean("matureContent") || comic.getBoolean("hentai"),
description = comic.getStringOrNull("parsed") ?: comic.getString("desc"),
tags = manga.tags + jo.getJSONArray("genres").mapJSONToSet {
MangaTag(
title = it.getString("name"),
key = it.getString("slug"),
source = source,
)
},
author = jo.getJSONArray("artists").optJSONObject(0)?.getString("name"),
chapters = getChapters(comic.getLong("id")),
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val jo = context.httpGet(
"https://api.${getDomain()}/chapter/${chapter.url}?tachiyomi=true",
).parseJson().getJSONObject("chapter")
val referer = "https://${getDomain()}/"
return jo.getJSONArray("images").mapJSON {
val url = it.getString("url")
MangaPage(
id = generateUid(url),
url = url,
referer = referer,
preview = null,
source = source,
)
}
}
override suspend fun getTags(): Set<MangaTag> {
val sparseArray = cachedTags ?: loadTags()
val set = ArraySet<MangaTag>(sparseArray.size())
for (i in 0 until sparseArray.size()) {
set.add(sparseArray.valueAt(i))
}
return set
}
private suspend fun loadTags(): SparseArrayCompat<MangaTag> {
val ja = context.httpGet("https://api.${getDomain()}/genre").parseJsonArray()
val tags = SparseArrayCompat<MangaTag>(ja.length())
for (jo in ja.JSONIterator()) {
tags.append(
jo.getInt("id"),
MangaTag(
title = jo.getString("name"),
key = jo.getString("slug"),
source = source,
),
)
}
cachedTags = tags
return tags
}
private suspend fun getChapters(id: Long): List<MangaChapter> {
val ja = context.httpGet(
url = "https://api.${getDomain()}/comic/$id/chapter?tachiyomi=true&limit=$CHAPTERS_LIMIT",
).parseJson().getJSONArray("chapters")
val dateFormat = SimpleDateFormat("yyyy-MM-dd")
val counters = HashMap<Locale, Int>()
return ja.mapReversed { jo ->
val locale = Locale.forLanguageTag(jo.getString("lang"))
var number = counters[locale] ?: 0
number++
counters[locale] = number
MangaChapter(
id = generateUid(jo.getLong("id")),
name = buildString {
jo.getStringOrNull("vol")?.let { append("Vol ").append(it).append(' ') }
jo.getStringOrNull("chap")?.let { append("Chap ").append(it) }
jo.getStringOrNull("title")?.let { append(": ").append(it) }
},
number = number,
url = jo.getString("hid"),
scanlator = jo.optJSONArray("group_name")?.optString(0),
uploadDate = dateFormat.tryParse(jo.getString("created_at").substringBefore('T')),
branch = locale.getDisplayName(locale).toTitleCase(locale),
source = source,
)
}
}
private inline fun <R> JSONArray.mapReversed(block: (JSONObject) -> R): List<R> {
val len = length()
val destination = ArrayList<R>(len)
for (i in (0 until len).reversed()) {
val jo = getJSONObject(i)
destination.add(block(jo))
}
return destination
}
private fun JSONObject.selectGenres(name: String, tags: SparseArrayCompat<MangaTag>): Set<MangaTag> {
val array = optJSONArray(name) ?: return emptySet()
val res = ArraySet<MangaTag>(array.length())
for (i in 0 until array.length()) {
val id = array.getInt(i)
val tag = tags.get(id) ?: continue
res.add(tag)
}
return res
}
}

View File

@@ -1,161 +0,0 @@
package org.koitharu.kotatsu.parsers.site
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.mapJSON
import org.koitharu.kotatsu.parsers.util.json.mapJSONIndexed
import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet
import java.util.*
@MangaSourceParser("DESUME", "Desu.me", "ru")
internal class DesuMeParser(override val context: MangaLoaderContext) : PagedMangaParser(MangaSource.DESUME, 20) {
override val configKeyDomain = ConfigKey.Domain("desu.me", null)
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.POPULARITY,
SortOrder.NEWEST,
SortOrder.ALPHABETICAL,
)
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
if (query != null && page != searchPaginator.firstPage) {
return emptyList()
}
val domain = getDomain()
val url = buildString {
append("https://")
append(domain)
append("/manga/api/?limit=20&order=")
append(getSortKey(sortOrder))
append("&page=")
append(page)
if (!tags.isNullOrEmpty()) {
append("&genres=")
appendAll(tags, ",") { it.key }
}
if (query != null) {
append("&search=")
append(query)
}
}
val json = context.httpGet(url).parseJson().getJSONArray("response")
?: throw ParseException("Invalid response", url)
val total = json.length()
val list = ArrayList<Manga>(total)
for (i in 0 until total) {
val jo = json.getJSONObject(i)
val cover = jo.getJSONObject("image")
val id = jo.getLong("id")
list += Manga(
url = "/manga/api/$id",
publicUrl = jo.getString("url"),
source = MangaSource.DESUME,
title = jo.getString("russian"),
altTitle = jo.getString("name"),
coverUrl = cover.getString("preview"),
largeCoverUrl = cover.getString("original"),
state = when {
jo.getInt("ongoing") == 1 -> MangaState.ONGOING
else -> null
},
rating = jo.getDouble("score").toFloat().coerceIn(0f, 1f),
id = generateUid(id),
isNsfw = false,
tags = emptySet(),
author = null,
description = jo.getString("description"),
)
}
return list
}
override suspend fun getDetails(manga: Manga): Manga {
val url = manga.url.toAbsoluteUrl(getDomain())
val json = context.httpGet(url).parseJson().getJSONObject("response")
?: throw ParseException("Invalid response", url)
val baseChapterUrl = manga.url + "/chapter/"
val chaptersList = json.getJSONObject("chapters").getJSONArray("list")
val totalChapters = chaptersList.length()
return manga.copy(
tags = json.getJSONArray("genres").mapJSONToSet {
MangaTag(
key = it.getString("text"),
title = it.getString("russian").toTitleCase(),
source = manga.source,
)
},
publicUrl = json.getString("url"),
description = json.getString("description"),
chapters = chaptersList.mapJSONIndexed { i, it ->
val chid = it.getLong("id")
val volChap = "Том " + it.optString("vol", "0") + ". " + "Глава " + it.optString("ch", "0")
val title = it.optString("title", "null").takeUnless { it == "null" }
MangaChapter(
id = generateUid(chid),
source = manga.source,
url = "$baseChapterUrl$chid",
uploadDate = it.getLong("date") * 1000,
name = if (title.isNullOrEmpty()) volChap else "$volChap: $title",
number = totalChapters - i,
scanlator = null,
branch = null,
)
}.reversed(),
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(getDomain())
val json = context.httpGet(fullUrl)
.parseJson()
.getJSONObject("response") ?: throw ParseException("Invalid response", fullUrl)
return json.getJSONObject("pages").getJSONArray("list").mapJSON { jo ->
MangaPage(
id = generateUid(jo.getLong("id")),
referer = fullUrl,
preview = null,
source = chapter.source,
url = jo.getString("img"),
)
}
}
override suspend fun getTags(): Set<MangaTag> {
val doc = context.httpGet("https://${getDomain()}/manga/").parseHtml()
val root = doc.body().requireElementById("animeFilter")
.selectFirstOrThrow(".catalog-genres")
return root.select("li").mapToSet {
val input = it.selectFirstOrThrow("input")
MangaTag(
source = source,
key = input.attr("data-genre-slug").ifEmpty {
it.parseFailed("data-genre-slug is empty")
},
title = input.attr("data-genre-name").toTitleCase().ifEmpty {
it.parseFailed("data-genre-name is empty")
},
)
}
}
private fun getSortKey(sortOrder: SortOrder) =
when (sortOrder) {
SortOrder.ALPHABETICAL -> "name"
SortOrder.POPULARITY -> "popular"
SortOrder.UPDATED -> "updated"
SortOrder.NEWEST -> "id"
else -> "updated"
}
}

View File

@@ -1,279 +0,0 @@
package org.koitharu.kotatsu.parsers.site
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
import kotlin.math.pow
private const val DOMAIN_UNAUTHORIZED = "e-hentai.org"
private const val DOMAIN_AUTHORIZED = "exhentai.org"
@MangaSourceParser("EXHENTAI", "ExHentai")
internal class ExHentaiParser(
override val context: MangaLoaderContext,
) : PagedMangaParser(MangaSource.EXHENTAI, pageSize = 25), MangaParserAuthProvider {
override val sortOrders: Set<SortOrder> = Collections.singleton(
SortOrder.NEWEST,
)
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain(if (isAuthorized) DOMAIN_AUTHORIZED else DOMAIN_UNAUTHORIZED, null)
override val authUrl: String
get() = "https://${getDomain()}/bounce_login.php"
private val ratingPattern = Regex("-?[0-9]+px")
private val authCookies = arrayOf("ipb_member_id", "ipb_pass_hash")
private var updateDm = false
override val isAuthorized: Boolean
get() {
val authorized = isAuthorized(DOMAIN_UNAUTHORIZED)
if (authorized) {
if (!isAuthorized(DOMAIN_AUTHORIZED)) {
context.cookieJar.copyCookies(
DOMAIN_UNAUTHORIZED,
DOMAIN_AUTHORIZED,
authCookies,
)
context.cookieJar.insertCookies(DOMAIN_AUTHORIZED, "yay=louder")
}
return true
}
return false
}
init {
context.cookieJar.insertCookies(DOMAIN_AUTHORIZED, "nw=1", "sl=dm_2")
context.cookieJar.insertCookies(DOMAIN_UNAUTHORIZED, "nw=1", "sl=dm_2")
}
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
var search = query?.urlEncoded().orEmpty()
val url = buildString {
append("https://")
append(getDomain())
append("/?page=")
append(page)
if (!tags.isNullOrEmpty()) {
var fCats = 0
for (tag in tags) {
tag.key.toIntOrNull()?.let { fCats = fCats or it } ?: run {
search += tag.key + " "
}
}
if (fCats != 0) {
append("&f_cats=")
append(1023 - fCats)
}
}
if (search.isNotEmpty()) {
append("&f_search=")
append(search.trim().replace(' ', '+'))
}
// by unknown reason cookie "sl=dm_2" is ignored, so, we should request it again
if (updateDm) {
append("&inline_set=dm_e")
}
}
val body = context.httpGet(url).parseHtml().body()
val root = body.selectFirst("table.itg")
?.selectFirst("tbody")
?: if (updateDm) {
body.parseFailed("Cannot find root")
} else {
updateDm = true
return getListPage(page, query, tags, sortOrder)
}
updateDm = false
return root.children().mapNotNull { tr ->
if (tr.childrenSize() != 2) return@mapNotNull null
val (td1, td2) = tr.children()
val glink = td2.selectFirstOrThrow("div.glink")
val a = glink.parents().select("a").first() ?: glink.parseFailed("link not found")
val href = a.attrAsRelativeUrl("href")
val tagsDiv = glink.nextElementSibling() ?: glink.parseFailed("tags div not found")
val mainTag = td2.selectFirst("div.cn")?.let { div ->
MangaTag(
title = div.text().toTitleCase(),
key = tagIdByClass(div.classNames()) ?: return@let null,
source = source,
)
}
Manga(
id = generateUid(href),
title = glink.text().cleanupTitle(),
altTitle = null,
url = href,
publicUrl = a.absUrl("href"),
rating = td2.selectFirst("div.ir")?.parseRating() ?: RATING_UNKNOWN,
isNsfw = true,
coverUrl = td1.selectFirst("img")?.absUrl("src").orEmpty(),
tags = setOfNotNull(mainTag),
state = null,
author = tagsDiv.getElementsContainingOwnText("artist:").first()
?.nextElementSibling()?.text(),
source = source,
)
}
}
override suspend fun getDetails(manga: Manga): Manga {
val doc = context.httpGet(manga.url.toAbsoluteUrl(getDomain())).parseHtml()
val root = doc.body().selectFirstOrThrow("div.gm")
val cover = root.getElementById("gd1")?.children()?.first()
val title = root.getElementById("gd2")
val taglist = root.getElementById("taglist")
val tabs = doc.body().selectFirst("table.ptt")?.selectFirst("tr")
return manga.copy(
title = title?.getElementById("gn")?.text()?.cleanupTitle() ?: manga.title,
altTitle = title?.getElementById("gj")?.text()?.cleanupTitle() ?: manga.altTitle,
publicUrl = doc.baseUri().ifEmpty { manga.publicUrl },
rating = root.getElementById("rating_label")?.text()
?.substringAfterLast(' ')
?.toFloatOrNull()
?.div(5f) ?: manga.rating,
largeCoverUrl = cover?.styleValueOrNull("background")?.cssUrl(),
description = taglist?.select("tr")?.joinToString("<br>") { tr ->
val (tc, td) = tr.children()
val subtags = td.select("a").joinToString { it.html() }
"<b>${tc.html()}</b> $subtags"
},
chapters = tabs?.select("a")?.findLast { a ->
a.text().toIntOrNull() != null
}?.let { a ->
val count = a.text().toInt()
val chapters = ChaptersListBuilder(count)
for (i in 1..count) {
val url = "${manga.url}?p=${i - 1}"
chapters += MangaChapter(
id = generateUid(url),
name = "${manga.title} #$i",
number = i,
url = url,
uploadDate = 0L,
source = source,
scanlator = null,
branch = null,
)
}
chapters.toList()
},
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val doc = context.httpGet(chapter.url.toAbsoluteUrl(getDomain())).parseHtml()
val root = doc.body().requireElementById("gdt")
return root.select("a").map { a ->
val url = a.attrAsRelativeUrl("href")
MangaPage(
id = generateUid(url),
url = url,
referer = a.absUrl("href"),
preview = null,
source = source,
)
}
}
override suspend fun getPageUrl(page: MangaPage): String {
val doc = context.httpGet(page.url.toAbsoluteUrl(getDomain())).parseHtml()
return doc.body().requireElementById("img").attrAsAbsoluteUrl("src")
}
override suspend fun getTags(): Set<MangaTag> {
val doc = context.httpGet("https://${getDomain()}").parseHtml()
val root = doc.body().requireElementById("searchbox").selectFirstOrThrow("table")
return root.select("div.cs").mapNotNullToSet { div ->
val id = div.id().substringAfterLast('_').toIntOrNull()
?: return@mapNotNullToSet null
MangaTag(
title = div.text().toTitleCase(),
key = id.toString(),
source = source,
)
}
}
override suspend fun getUsername(): String {
val doc = context.httpGet("https://forums.$DOMAIN_UNAUTHORIZED/").parseHtml().body()
val username = doc.getElementById("userlinks")
?.getElementsByAttributeValueContaining("href", "showuser=")
?.firstOrNull()
?.ownText()
?: if (doc.getElementById("userlinksguest") != null) {
throw AuthRequiredException(source)
} else {
doc.parseFailed()
}
return username
}
private fun isAuthorized(domain: String): Boolean {
val cookies = context.cookieJar.getCookies(domain).mapToSet { x -> x.name }
return authCookies.all { it in cookies }
}
private fun Element.parseRating(): Float {
return runCatching {
val style = requireNotNull(attr("style"))
val (v1, v2) = ratingPattern.find(style)!!.destructured
var p1 = v1.dropLast(2).toInt()
val p2 = v2.dropLast(2).toInt()
if (p2 != -1) {
p1 += 8
}
(80 - p1) / 80f
}.getOrDefault(RATING_UNKNOWN)
}
private fun String.cleanupTitle(): String {
val result = StringBuilder(length)
var skip = false
for (c in this) {
when {
c == '[' -> skip = true
c == ']' -> skip = false
c.isWhitespace() && result.isEmpty() -> continue
!skip -> result.append(c)
}
}
while (result.lastOrNull()?.isWhitespace() == true) {
result.deleteCharAt(result.lastIndex)
}
return result.toString()
}
private fun String.cssUrl(): String? {
val fromIndex = indexOf("url(")
if (fromIndex == -1) {
return null
}
val toIndex = indexOf(')', startIndex = fromIndex)
return if (toIndex == -1) {
null
} else {
substring(fromIndex + 4, toIndex).trim()
}
}
private fun tagIdByClass(classNames: Collection<String>): String? {
val className = classNames.find { x -> x.startsWith("ct") } ?: return null
val num = className.drop(2).toIntOrNull(16) ?: return null
return 2.0.pow(num).toInt().toString()
}
}

View File

@@ -1,269 +0,0 @@
package org.koitharu.kotatsu.parsers.site
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import org.json.JSONObject
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.*
import java.text.SimpleDateFormat
import java.util.*
private const val PAGE_SIZE = 20
private const val CHAPTERS_FIRST_PAGE_SIZE = 120
private const val CHAPTERS_MAX_PAGE_SIZE = 500
private const val CHAPTERS_PARALLELISM = 3
private const val CONTENT_RATING =
"contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic"
private const val LOCALE_FALLBACK = "en"
@MangaSourceParser("MANGADEX", "MangaDex")
internal class MangaDexParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.MANGADEX) {
override val configKeyDomain = ConfigKey.Domain("mangadex.org", null)
override val sortOrders: EnumSet<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.ALPHABETICAL,
SortOrder.NEWEST,
SortOrder.POPULARITY,
)
override suspend fun getList(
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val domain = getDomain()
val url = buildString {
append("https://api.")
append(domain)
append("/manga?limit=")
append(PAGE_SIZE)
append("&offset=")
append(offset)
append("&includes[]=cover_art&includes[]=author&includes[]=artist&")
tags?.forEach { tag ->
append("includedTags[]=")
append(tag.key)
append('&')
}
if (!query.isNullOrEmpty()) {
append("title=")
append(query.urlEncoded())
append('&')
}
append(CONTENT_RATING)
append("&order")
append(
when (sortOrder) {
SortOrder.UPDATED,
-> "[latestUploadedChapter]=desc"
SortOrder.ALPHABETICAL -> "[title]=asc"
SortOrder.NEWEST -> "[createdAt]=desc"
SortOrder.POPULARITY -> "[followedCount]=desc"
else -> "[followedCount]=desc"
},
)
}
val json = context.httpGet(url).parseJson().getJSONArray("data")
return json.mapJSON { jo ->
val id = jo.getString("id")
val attrs = jo.getJSONObject("attributes")
val relations = jo.getJSONArray("relationships").associateByKey("type")
val cover = relations["cover_art"]
?.getJSONObject("attributes")
?.getString("fileName")
?.let {
"https://uploads.$domain/covers/$id/$it"
}
Manga(
id = generateUid(id),
title = requireNotNull(attrs.getJSONObject("title").selectByLocale()) {
"Title should not be null"
},
altTitle = attrs.optJSONObject("altTitles")?.selectByLocale(),
url = id,
publicUrl = "https://$domain/title/$id",
rating = RATING_UNKNOWN,
isNsfw = attrs.getStringOrNull("contentRating") == "erotica",
coverUrl = cover?.plus(".256.jpg").orEmpty(),
largeCoverUrl = cover,
description = attrs.optJSONObject("description")?.selectByLocale(),
tags = attrs.getJSONArray("tags").mapJSONToSet { tag ->
MangaTag(
title = tag.getJSONObject("attributes")
.getJSONObject("name")
.firstStringValue()
.toTitleCase(),
key = tag.getString("id"),
source = source,
)
},
state = when (jo.getStringOrNull("status")) {
"ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED
else -> null
},
author = (relations["author"] ?: relations["artist"])
?.getJSONObject("attributes")
?.getStringOrNull("name"),
source = source,
)
}
}
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val domain = getDomain()
val mangaId = manga.url.removePrefix("/")
val attrsDeferred = async {
context.httpGet(
"https://api.$domain/manga/${mangaId}?includes[]=artist&includes[]=author&includes[]=cover_art",
).parseJson().getJSONObject("data").getJSONObject("attributes")
}
val feedDeferred = async { loadChapters(mangaId) }
val mangaAttrs = attrsDeferred.await()
val feed = feedDeferred.await()
// 2022-01-02T00:27:11+00:00
val dateFormat = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss'+00:00'",
Locale.ROOT,
)
manga.copy(
description = mangaAttrs.getJSONObject("description").selectByLocale()
?: manga.description,
chapters = feed.mapChapters { _, jo ->
val id = jo.getString("id")
val attrs = jo.getJSONObject("attributes")
if (!attrs.isNull("externalUrl")) {
return@mapChapters null
}
val locale = attrs.getStringOrNull("translatedLanguage")?.let { Locale.forLanguageTag(it) }
val relations = jo.getJSONArray("relationships").associateByKey("type")
val number = attrs.getIntOrDefault("chapter", 0)
MangaChapter(
id = generateUid(id),
name = attrs.getStringOrNull("title")?.takeUnless(String::isEmpty)
?: "Chapter #$number",
number = number,
url = id,
scanlator = relations["scanlation_group"]?.getStringOrNull("name"),
uploadDate = dateFormat.tryParse(attrs.getString("publishAt")),
branch = locale?.getDisplayName(locale)?.toTitleCase(locale),
source = source,
)
},
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val domain = getDomain()
val chapterJson = context.httpGet("https://api.$domain/at-home/server/${chapter.url}?forcePort443=false")
.parseJson()
.getJSONObject("chapter")
val pages = chapterJson.getJSONArray("data")
val prefix = "https://uploads.$domain/data/${chapterJson.getString("hash")}/"
val referer = "https://$domain/"
return List(pages.length()) { i ->
val url = prefix + pages.getString(i)
MangaPage(
id = generateUid(url),
url = url,
referer = referer,
preview = null, // TODO prefix + dataSaver.getString(i),
source = source,
)
}
}
override suspend fun getTags(): Set<MangaTag> {
val tags = context.httpGet("https://api.${getDomain()}/manga/tag").parseJson()
.getJSONArray("data")
return tags.mapJSONToSet { jo ->
MangaTag(
title = jo.getJSONObject("attributes").getJSONObject("name").firstStringValue().toTitleCase(),
key = jo.getString("id"),
source = source,
)
}
}
private fun JSONObject.firstStringValue() = values().next() as String
private fun JSONObject.selectByLocale(): String? {
val preferredLocales = context.getPreferredLocales()
for (locale in preferredLocales) {
getStringOrNull(locale.language)?.let { return it }
getStringOrNull(locale.toLanguageTag())?.let { return it }
}
return getStringOrNull(LOCALE_FALLBACK) ?: values().nextOrNull() as? String
}
private suspend fun loadChapters(mangaId: String): List<JSONObject> {
val firstPage = loadChapters(mangaId, offset = 0, limit = CHAPTERS_FIRST_PAGE_SIZE)
if (firstPage.size >= firstPage.total) {
return firstPage.data
}
val tail = coroutineScope {
val leftCount = firstPage.total - firstPage.size
val pages = (leftCount / CHAPTERS_MAX_PAGE_SIZE.toFloat()).toIntUp()
val dispatcher = Dispatchers.Default.limitedParallelism(CHAPTERS_PARALLELISM)
List(pages) { page ->
val offset = page * CHAPTERS_MAX_PAGE_SIZE + firstPage.size
async(dispatcher) {
loadChapters(mangaId, offset, CHAPTERS_MAX_PAGE_SIZE)
}
}.awaitAll()
}
val result = ArrayList<JSONObject>(firstPage.total)
result += firstPage.data
tail.flatMapTo(result) { it.data }
return result
}
private suspend fun loadChapters(mangaId: String, offset: Int, limit: Int): Chapters {
val url = buildString {
append("https://api.")
append(getDomain())
append("/manga/")
append(mangaId)
append("/feed")
append("?limit=")
append(limit)
append("&includes[]=scanlation_group&order[volume]=asc&order[chapter]=asc&offset=")
append(offset)
append('&')
append(CONTENT_RATING)
}
val json = context.httpGet(url).parseJson()
if (json.getString("result") == "ok") {
return Chapters(
data = json.optJSONArray("data")?.toJSONList().orEmpty(),
total = json.getInt("total"),
)
} else {
val error = json.optJSONArray("errors").mapJSON { jo ->
jo.getString("detail")
}.joinToString("\n")
throw ParseException(error, url)
}
}
private class Chapters(
val data: List<JSONObject>,
val total: Int,
) {
val size: Int
get() = data.size
}
}

View File

@@ -1,152 +0,0 @@
package org.koitharu.kotatsu.parsers.site
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
private const val DEF_BRANCH_NAME = "Основний переклад"
@MangaSourceParser("MANGAINUA", "MANGA/in/UA", "uk")
class MangaInUaParser(override val context: MangaLoaderContext) : PagedMangaParser(
source = MangaSource.MANGAINUA,
pageSize = 24,
searchPageSize = 10,
) {
override val sortOrders: Set<SortOrder>
get() = Collections.singleton(SortOrder.UPDATED)
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manga.in.ua", null)
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val url = when {
!query.isNullOrEmpty() -> (
"/index.php?do=search" +
"&subaction=search" +
"&search_start=$page" +
"&full_search=1" +
"&story=$query" +
"&titleonly=3"
).toAbsoluteUrl(getDomain())
tags.isNullOrEmpty() -> "/mangas/page/$page".toAbsoluteUrl(getDomain())
tags.size == 1 -> "${tags.first().key}/page/$page"
tags.size > 1 -> throw IllegalArgumentException("This source supports only 1 genre")
else -> "/mangas/page/$page".toAbsoluteUrl(getDomain())
}
val doc = context.httpGet(url).parseHtml()
val container = doc.body().requireElementById("dle-content")
val items = container.select("div.col-6")
return items.mapNotNull { item ->
val href = item.selectFirst("a")?.attrAsRelativeUrl("href") ?: return@mapNotNull null
Manga(
id = generateUid(href),
title = item.selectFirst("h3.card__title")?.text() ?: return@mapNotNull null,
coverUrl = item.selectFirst("header.card__cover")?.selectFirst("img")?.run {
attrAsAbsoluteUrlOrNull("data-src") ?: attrAsAbsoluteUrlOrNull("src")
}.orEmpty(),
altTitle = null,
author = null,
rating = item.selectFirst("div.card__short-rate--num")
?.text()
?.toFloatOrNull()
?.div(10F) ?: RATING_UNKNOWN,
url = href,
isNsfw = item.selectFirst("ul.card__list")?.select("li")?.lastOrNull()?.text() == "18+",
tags = runCatching {
item.selectFirst("div.card__category")?.select("a")?.mapToSet {
MangaTag(
title = it.ownText(),
key = it.attr("href").removeSuffix("/"),
source = source,
)
}
}.getOrNull().orEmpty(),
state = null,
publicUrl = href.toAbsoluteUrl(container.host ?: getDomain()),
source = source,
)
}
}
override suspend fun getDetails(manga: Manga): Manga {
val doc = context.httpGet(manga.url.toAbsoluteUrl(getDomain())).parseHtml()
val root = doc.body().requireElementById("dle-content")
val dateFormat = SimpleDateFormat("dd.MM.yyyy", Locale.US)
val chapterNodes = root.selectFirstOrThrow(".linkstocomics").select(".ltcitems")
var prevChapterName: String? = null
var i = 0
return manga.copy(
description = root.selectFirst("div.item__full-description")?.text(),
largeCoverUrl = root.selectFirst("div.item__full-sidebar--poster")?.selectFirst("img")
?.attrAsAbsoluteUrlOrNull("src"),
chapters = chapterNodes.mapChapters { _, item ->
val href = item?.selectFirst("a")?.attrAsRelativeUrlOrNull("href")
?: return@mapChapters null
val isAlternative = item.styleValueOrNull("background") != null
val name = item.selectFirst("a")?.text().orEmpty()
if (!isAlternative) i++
MangaChapter(
id = generateUid(href),
name = if (isAlternative) {
prevChapterName ?: return@mapChapters null
} else {
prevChapterName = name
name
},
number = i,
url = href,
scanlator = null,
branch = if (isAlternative) {
name.substringAfterLast(':').trim()
} else {
DEF_BRANCH_NAME
},
uploadDate = dateFormat.tryParse(item.selectFirst("div.ltcright")?.text()),
source = source,
)
},
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(getDomain())
val doc = context.httpGet(fullUrl).parseHtml()
val root = doc.body().requireElementById("comics").selectFirstOrThrow("ul.xfieldimagegallery")
return root.select("li").map { ul ->
val img = ul.selectFirstOrThrow("img")
val url = img.attrAsAbsoluteUrl("data-src")
MangaPage(
id = generateUid(url),
url = url,
preview = null,
referer = fullUrl,
source = source,
)
}
}
override suspend fun getTags(): Set<MangaTag> {
val domain = getDomain()
val doc = context.httpGet("https://$domain/mangas").parseHtml()
val root = doc.body().requireElementById("menu_1").selectFirstOrThrow("div.menu__wrapper")
return root.select("li").mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null
MangaTag(
title = a.ownText(),
key = a.attr("href").removeSuffix("/"),
source = source,
)
}
}
}

View File

@@ -1,187 +0,0 @@
package org.koitharu.kotatsu.parsers.site
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
@Deprecated("Permanently shutdown")
@MangaSourceParser("MANGAOWL", "MangaOwl", "en")
internal class MangaOwlParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.MANGAOWL) {
override val configKeyDomain = ConfigKey.Domain("mangaowls.com", null)
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY,
SortOrder.NEWEST,
SortOrder.UPDATED,
)
private val regexNsfw = Regex("(yaoi)|(yuri)|(smut)|(mature)|(adult)", RegexOption.IGNORE_CASE)
override suspend fun getList(
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val page = (offset / 36f).toIntUp().inc()
val link = buildString {
append("https://")
append(getDomain())
when {
!query.isNullOrEmpty() -> {
append("/search/$page?search=")
append(query.urlEncoded())
}
!tags.isNullOrEmpty() -> {
for (tag in tags) {
append(tag.key)
}
append("/$page?type=${getAlternativeSortKey(sortOrder)}")
}
else -> {
append("/${getSortKey(sortOrder)}/$page")
}
}
}
val doc = context.httpGet(link).parseHtml()
val slides = doc.body().selectOrThrow("ul.slides")
val items = slides.select("div.col-md-2")
return items.mapNotNull { item ->
val href = item.selectFirst("h6 a")?.attrAsRelativeUrlOrNull("href") ?: return@mapNotNull null
Manga(
id = generateUid(href),
title = item.selectFirst("h6 a")?.text() ?: return@mapNotNull null,
coverUrl = item.select("div.img-responsive").attr("abs:data-background-image"),
altTitle = null,
author = null,
rating = runCatching {
item.selectFirst("div.block-stars")
?.text()
?.toFloatOrNull()
?.div(10f)
}.getOrNull() ?: RATING_UNKNOWN,
url = href,
isNsfw = false,
tags = emptySet(),
state = null,
publicUrl = href.toAbsoluteUrl(getDomain()),
source = source,
)
}
}
override suspend fun getDetails(manga: Manga): Manga {
val doc = context.httpGet(manga.publicUrl).parseHtml()
val info = doc.body().selectFirstOrThrow("div.single_detail")
val table = doc.body().selectFirstOrThrow("div.single-grid-right")
val dateFormat = SimpleDateFormat("MM/dd/yyyy", Locale.US)
val trRegex = "window\\['tr'] = '([^']*)';".toRegex(RegexOption.IGNORE_CASE)
val trElement = doc.getElementsByTag("script").find { trRegex.find(it.data()) != null }
?: doc.parseFailed("Oops, tr not found")
val tr = trRegex.find(trElement.data())!!.groups[1]!!.value
val s = context.encodeBase64(getDomain().toByteArray())
var isNsfw = manga.isNsfw
val parsedTags = info.select("div.col-xs-12.col-md-8.single-right-grid-right > p > a[href*=genres]")
.mapNotNullToSet {
val a = it.selectFirst("a") ?: return@mapNotNullToSet null
val name = a.text()
if (!isNsfw && isNsfwGenre(name)) {
isNsfw = true
}
MangaTag(
title = name.toTitleCase(),
key = a.attr("href"),
source = source,
)
}
return manga.copy(
description = info.selectFirst(".description")?.html(),
largeCoverUrl = info.select("img").first()?.let { img ->
if (img.hasAttr("data-src")) img.attr("abs:data-src") else img.attr("abs:src")
},
isNsfw = isNsfw,
author = info.selectFirst("p.fexi_header_para a.author_link")?.text(),
state = parseStatus(info.select("p.fexi_header_para:contains(status)").first()?.ownText()),
tags = manga.tags + parsedTags,
chapters = table.select("div.table.table-chapter-list").select("li.list-group-item.chapter_list")
.asReversed().mapChapters { i, li ->
val a = li.select("a")
val href = a.attr("data-href").ifEmpty {
li.parseFailed("Link is missing")
}
MangaChapter(
id = generateUid(href),
name = a.select("label").text(),
number = i + 1,
url = "$href?tr=$tr&s=$s",
scanlator = null,
branch = null,
uploadDate = dateFormat.tryParse(li.selectFirst("small:last-of-type")?.text()),
source = MangaSource.MANGAOWL,
)
},
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(getDomain())
val doc = context.httpGet(fullUrl).parseHtml()
val root = doc.body().selectOrThrow("div.item img.owl-lazy")
return root.map { div ->
val url = div?.attrAsRelativeUrlOrNull("data-src") ?: doc.parseFailed("Page image not found")
MangaPage(
id = generateUid(url),
url = url,
preview = null,
referer = url,
source = MangaSource.MANGAOWL,
)
}
}
private fun parseStatus(status: String?) = when {
status == null -> null
status.contains("Ongoing") -> MangaState.ONGOING
status.contains("Completed") -> MangaState.FINISHED
else -> null
}
override suspend fun getTags(): Set<MangaTag> {
val doc = context.httpGet("https://${getDomain()}/").parseHtml()
val root = doc.body().select("ul.dropdown-menu.multi-column.columns-3").select("li")
return root.mapToSet { p ->
val a = p.selectFirstOrThrow("a")
MangaTag(
title = a.text().toTitleCase(),
key = a.attr("href"),
source = source,
)
}
}
private fun getSortKey(sortOrder: SortOrder) =
when (sortOrder) {
SortOrder.POPULARITY -> "popular"
SortOrder.NEWEST -> "new_release"
SortOrder.UPDATED -> "lastest"
else -> "lastest"
}
private fun getAlternativeSortKey(sortOrder: SortOrder) =
when (sortOrder) {
SortOrder.POPULARITY -> "0"
SortOrder.NEWEST -> "2"
SortOrder.UPDATED -> "3"
else -> "3"
}
private fun isNsfwGenre(name: String): Boolean = regexNsfw.containsMatchIn(name)
}

View File

@@ -1,217 +0,0 @@
package org.koitharu.kotatsu.parsers.site
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("MANGATOWN", "MangaTown", "en")
internal class MangaTownParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.MANGATOWN) {
override val configKeyDomain = ConfigKey.Domain("www.mangatown.com", null)
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL,
SortOrder.RATING,
SortOrder.POPULARITY,
SortOrder.UPDATED,
)
private val regexTag = Regex("[^\\-]+-[^\\-]+-[^\\-]+-[^\\-]+-[^\\-]+-[^\\-]+")
override suspend fun getList(
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val sortKey = when (sortOrder) {
SortOrder.ALPHABETICAL -> "?name.az"
SortOrder.RATING -> "?rating.za"
SortOrder.UPDATED -> "?last_chapter_time.za"
else -> ""
}
val page = (offset / 30) + 1
val url = when {
!query.isNullOrEmpty() -> {
if (offset != 0) {
return emptyList()
}
"/search?name=${query.urlEncoded()}".toAbsoluteUrl(getDomain())
}
tags.isNullOrEmpty() -> "/directory/$page.htm$sortKey".toAbsoluteUrl(getDomain())
tags.size == 1 -> "/directory/${tags.first().key}/$page.htm$sortKey".toAbsoluteUrl(getDomain())
else -> tags.joinToString(
prefix = "/search?page=$page".toAbsoluteUrl(getDomain()),
) { tag ->
"&genres[${tag.key}]=1"
}
}
val doc = context.httpGet(url).parseHtml()
val root = doc.body().selectFirstOrThrow("ul.manga_pic_list")
return root.select("li").mapNotNull { li ->
val a = li.selectFirst("a.manga_cover")
val href = a?.attrAsRelativeUrlOrNull("href")
?: return@mapNotNull null
val views = li.select("p.view")
val status = views.firstNotNullOfOrNull { it.ownText().takeIf { x -> x.startsWith("Status:") } }
?.substringAfter(':')?.trim()?.lowercase(Locale.ROOT)
Manga(
id = generateUid(href),
title = a.attr("title"),
coverUrl = a.selectFirst("img")?.absUrl("src").orEmpty(),
source = MangaSource.MANGATOWN,
altTitle = null,
rating = li.selectFirst("p.score")?.selectFirst("b")
?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,
author = views.firstNotNullOfOrNull { it.text().takeIf { x -> x.startsWith("Author:") } }
?.substringAfter(':')
?.trim(),
state = when (status) {
"ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED
else -> null
},
tags = li.selectFirst("p.keyWord")?.select("a")?.mapNotNullToSet tags@{ x ->
MangaTag(
title = x.attr("title").toTitleCase(),
key = x.attr("href").parseTagKey() ?: return@tags null,
source = MangaSource.MANGATOWN,
)
}.orEmpty(),
url = href,
isNsfw = false,
publicUrl = href.toAbsoluteUrl(a.host ?: getDomain()),
)
}
}
override suspend fun getDetails(manga: Manga): Manga {
val doc = context.httpGet(manga.url.toAbsoluteUrl(getDomain())).parseHtml()
val root = doc.body().selectFirstOrThrow("section.main")
.selectFirstOrThrow("div.article_content")
val info = root.selectFirst("div.detail_info")?.selectFirst("ul")
val chaptersList = root.selectFirst("div.chapter_content")
?.selectFirst("ul.chapter_list")?.select("li")?.asReversed()
val dateFormat = SimpleDateFormat("MMM dd,yyyy", Locale.US)
return manga.copy(
tags = manga.tags + info?.select("li")?.find { x ->
x.selectFirst("b")?.ownText() == "Genre(s):"
}?.select("a")?.mapNotNull { a ->
MangaTag(
title = a.attr("title").toTitleCase(),
key = a.attr("href").parseTagKey() ?: return@mapNotNull null,
source = MangaSource.MANGATOWN,
)
}.orEmpty(),
description = info?.getElementById("show")?.ownText(),
chapters = chaptersList?.mapChapters { i, li ->
val href = li.selectFirst("a")?.attrAsRelativeUrlOrNull("href")
?: return@mapChapters null
val name = li.select("span")
.filter { x -> x.className().isEmpty() }
.joinToString(" - ") { it.text() }.trim()
MangaChapter(
id = generateUid(href),
url = href,
source = MangaSource.MANGATOWN,
number = i + 1,
uploadDate = parseChapterDate(
dateFormat,
li.selectFirst("span.time")?.text(),
),
name = name.ifEmpty { "${manga.title} - ${i + 1}" },
scanlator = null,
branch = null,
)
} ?: bypassLicensedChapters(manga),
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(getDomain())
val doc = context.httpGet(fullUrl).parseHtml()
val root = doc.body().selectFirstOrThrow("div.page_select")
return root.selectFirstOrThrow("select").selectOrThrow("option").mapNotNull {
val href = it.attrAsRelativeUrlOrNull("value")
if (href == null || href.endsWith("featured.html")) {
return@mapNotNull null
}
MangaPage(
id = generateUid(href),
url = href,
preview = null,
referer = fullUrl,
source = MangaSource.MANGATOWN,
)
}
}
override suspend fun getPageUrl(page: MangaPage): String {
val doc = context.httpGet(page.url.toAbsoluteUrl(getDomain())).parseHtml()
return doc.requireElementById("image").attrAsAbsoluteUrl("src")
}
override suspend fun getTags(): Set<MangaTag> {
val doc = context.httpGet("/directory/".toAbsoluteUrl(getDomain())).parseHtml()
val root = doc.body().selectFirst("aside.right")
?.getElementsContainingOwnText("Genres")
?.first()
?.nextElementSibling() ?: doc.parseFailed("Root not found")
return root.select("li").mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null
val key = a.attr("href").parseTagKey()
if (key.isNullOrEmpty()) {
return@mapNotNullToSet null
}
MangaTag(
source = MangaSource.MANGATOWN,
key = key,
title = a.text().toTitleCase(),
)
}
}
private fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
return when {
date.isNullOrEmpty() -> 0L
date.contains("Today") -> Calendar.getInstance().timeInMillis
date.contains("Yesterday") -> Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -1) }.timeInMillis
else -> dateFormat.tryParse(date)
}
}
private suspend fun bypassLicensedChapters(manga: Manga): List<MangaChapter> {
val doc = context.httpGet(manga.url.toAbsoluteUrl(getDomain("m"))).parseHtml()
val list = doc.body().selectFirst("ul.detail-ch-list") ?: return emptyList()
val dateFormat = SimpleDateFormat("MMM dd,yyyy", Locale.US)
return list.select("li").asReversed().mapIndexedNotNull { i, li ->
val a = li.selectFirst("a") ?: return@mapIndexedNotNull null
val href = a.attrAsRelativeUrl("href")
val name = a.selectFirst("span.vol")?.text().orEmpty().ifEmpty {
a.ownText()
}
MangaChapter(
id = generateUid(href),
url = href,
source = MangaSource.MANGATOWN,
number = i + 1,
uploadDate = parseChapterDate(
dateFormat,
li.selectFirst("span.time")?.text(),
),
name = name.ifEmpty { "${manga.title} - ${i + 1}" },
scanlator = null,
branch = null,
)
}
}
private fun String.parseTagKey() = split('/').findLast { regexTag matches it }
}

View File

@@ -1,188 +0,0 @@
package org.koitharu.kotatsu.parsers.site
import androidx.collection.ArraySet
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("NHENTAI", "N-Hentai")
class NHentaiParser(override val context: MangaLoaderContext) : PagedMangaParser(MangaSource.NHENTAI, pageSize = 25) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("nhentai.net", null)
override val sortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.NEWEST, SortOrder.POPULARITY)
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
if (query.isNullOrEmpty() && tags != null && tags.size > 1) {
return getListPage(page, buildQuery(tags), emptySet(), sortOrder)
}
val domain = getDomain()
val url = buildString {
append("https://")
append(domain)
if (!query.isNullOrEmpty()) {
append("/search/?q=")
append(query.urlEncoded())
append("&page=")
append(page)
if (sortOrder == SortOrder.POPULARITY) {
append("&sort=popular")
}
} else {
append('/')
if (!tags.isNullOrEmpty()) {
val tag = tags.single()
append("tag/")
append(tag.key)
append('/')
if (sortOrder == SortOrder.POPULARITY) {
append("popular")
}
append("?page=")
append(page)
} else {
if (sortOrder == SortOrder.POPULARITY) {
append("?sort=popular&page=")
} else {
append("?page=")
}
append(page)
}
}
}
val root = context.httpGet(url).parseHtml().body().requireElementById("content")
.selectLastOrThrow("div.index-container")
val regexBrackets = Regex("\\[[^]]+]|\\([^)]+\\)")
val regexSpaces = Regex("\\s+")
return root.select(".gallery").map { div ->
val a = div.selectFirstOrThrow("a.cover")
val href = a.attrAsRelativeUrl("href")
val img = div.selectFirstOrThrow("img")
val title = div.selectFirstOrThrow(".caption").text()
Manga(
id = generateUid(href),
title = title.replace(regexBrackets, "")
.replace(regexSpaces, " ")
.trim(),
altTitle = null,
url = href,
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = true,
coverUrl = img.attrAsAbsoluteUrlOrNull("data-src")
?: img.attrAsAbsoluteUrl("src"),
tags = setOf(),
state = null,
author = null,
largeCoverUrl = null,
description = null,
chapters = listOf(),
source = source,
)
}
}
override suspend fun getDetails(manga: Manga): Manga {
val root = context.httpGet(
url = manga.url.toAbsoluteUrl(getDomain()),
).parseHtml().body().requireElementById("bigcontainer")
val img = root.requireElementById("cover").selectFirstOrThrow("img")
val tagContainers = root.requireElementById("tags").select(".tag-container")
val dateFormat = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss.SSSSSS'+00:00'",
Locale.ROOT,
)
return manga.copy(
tags = tagContainers.find { x -> x.ownText() == "Tags:" }?.parseTags() ?: manga.tags,
author = tagContainers.find { x -> x.ownText() == "Artists:" }
?.selectFirst("span.name")?.text()?.toCamelCase(),
largeCoverUrl = img.attrAsAbsoluteUrlOrNull("data-src")
?: img.attrAsAbsoluteUrl("src"),
description = null,
chapters = listOf(
MangaChapter(
id = manga.id,
name = manga.title,
number = 1,
url = manga.url,
scanlator = null,
uploadDate = dateFormat.tryParse(
tagContainers.find { x -> x.ownText() == "Uploaded:" }
?.selectFirst("time")
?.attr("datetime"),
),
branch = null,
source = source,
),
),
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val url = chapter.url.toAbsoluteUrl(getDomain())
val root = context.httpGet(url).parseHtml().requireElementById("thumbnail-container")
return root.select(".thumb-container").map { div ->
val a = div.selectFirstOrThrow("a")
val img = div.selectFirstOrThrow("img")
val href = a.attrAsRelativeUrl("href")
MangaPage(
id = generateUid(href),
url = href,
referer = url,
preview = img.attrAsAbsoluteUrlOrNull("data-src")
?: img.attrAsAbsoluteUrl("src"),
source = source,
)
}
}
override suspend fun getPageUrl(page: MangaPage): String {
val root = context.httpGet(page.url.toAbsoluteUrl(getDomain())).parseHtml().body()
.requireElementById("image-container")
return root.selectFirstOrThrow("img").attrAsAbsoluteUrl("src")
}
override suspend fun getTags(): Set<MangaTag> {
return coroutineScope {
// parse first 3 pages of tags
(1..3).map { page ->
async { getTags(page) }
}
}.awaitAll().flattenTo(ArraySet(360))
}
private suspend fun getTags(page: Int): Set<MangaTag> {
val root = context.httpGet("https://${getDomain()}/tags/popular?page=$page").parseHtml().body()
.getElementById("tag-container")
return root?.parseTags().orEmpty()
}
private fun Element.parseTags() = select("a.tag").mapToSet { a ->
val href = a.attr("href").removeSuffix('/')
MangaTag(
title = a.selectFirstOrThrow(".name").text().toTitleCase(),
key = href.substringAfterLast('/'),
source = source,
)
}
private fun buildQuery(tags: Collection<MangaTag>) = tags.joinToString(separator = " ") { tag ->
"tag:\"${tag.key}\""
}
}

View File

@@ -1,221 +0,0 @@
package org.koitharu.kotatsu.parsers.site
import androidx.collection.ArrayMap
import androidx.collection.ArraySet
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.koitharu.kotatsu.parsers.*
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("NETTRUYEN", "NetTruyen", "vi")
class NetTruyenParser(override val context: MangaLoaderContext) :
PagedMangaParser(MangaSource.NETTRUYEN, pageSize = 36) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("www.nettruyenme.com", null)
override val sortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.RATING)
private val mutex = Mutex()
private val dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US)
private var tagCache: ArrayMap<String, MangaTag>? = null
override suspend fun getDetails(manga: Manga): Manga {
val doc = context.httpGet(manga.url.toAbsoluteUrl(getDomain())).parseHtml()
val rating = doc.selectFirst("span[itemprop=ratingValue]")
?.ownText()
?.toFloatOrNull() ?: 0f
val chapterElements = doc.getElementById("nt_listchapter")?.select("ul > li") ?: doc.parseFailed()
val chapters = chapterElements.asReversed().mapChapters { index, element ->
val a = element.selectFirst("div.chapter > a") ?: return@mapChapters null
val relativeUrl = a.attrAsRelativeUrlOrNull("href") ?: return@mapChapters null
val timeText = element.selectFirst("div.col-xs-4.text-center.no-wrap.small")?.text()
MangaChapter(
id = generateUid(relativeUrl),
name = a.text(),
number = index + 1,
url = relativeUrl,
scanlator = null,
uploadDate = parseChapterTime(timeText),
branch = null,
source = source,
)
}
return manga.copy(
rating = rating / 5,
chapters = chapters,
description = doc.selectFirst("div.detail-content > p")?.html(),
isNsfw = doc.selectFirst("div.alert.alert-danger > strong:contains(Cảnh báo độ tuổi)") != null,
)
}
// 20 giây trước
// 52 phút trước
// 6 giờ trước
// 2 ngày trước
// 19:09 30/07
// 23/12/21
private fun parseChapterTime(timeText: String?): Long {
if (timeText.isNullOrEmpty()) {
return 0L
}
val timeWords = arrayOf("giây", "phút", "giờ", "ngày")
val calendar = Calendar.getInstance()
val timeArr = timeText.split(' ')
if (WordSet(*timeWords).anyWordIn(timeText)) {
val timeSuffix = timeArr.getOrNull(1)
val timeDiff = timeArr.getOrNull(0)?.toIntOrNull() ?: return 0L
when (timeSuffix) {
timeWords[0] -> calendar.add(Calendar.SECOND, -timeDiff)
timeWords[1] -> calendar.add(Calendar.MINUTE, -timeDiff)
timeWords[2] -> calendar.add(Calendar.HOUR, -timeDiff)
timeWords[3] -> calendar.add(Calendar.DATE, -timeDiff)
else -> return 0L
}
} else {
val relativeDate = timeArr.lastOrNull() ?: return 0L
val dateString = when (relativeDate.split('/').size) {
2 -> {
val currentYear = calendar.get(Calendar.YEAR).toString().takeLast(2)
"$relativeDate/$currentYear"
}
3 -> relativeDate
else -> return 0L
}
calendar.timeInMillis = dateFormat.tryParse(dateString)
}
return calendar.time.time
}
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val isSearching = !query.isNullOrEmpty()
val url = buildString {
append("https://")
append(getDomain())
if (isSearching) {
append("/tim-truyen?keyword=")
append(query!!.urlEncoded())
append("&page=")
append(page)
} else {
val tagQuery = tags.orEmpty().joinToString(",") { it.key }
append("/tim-truyen-nang-cao?genres=$tagQuery")
append("&notgenres=&gender=-1&status=-1&minchapter=1&sort=${getSortOrderKey(sortOrder)}")
append("&page=$page")
}
}
val response = if (isSearching) {
val result = runCatching { context.httpGet(url) }
val exception = result.exceptionOrNull()
if (exception is NotFoundException) {
return emptyList()
}
result.getOrThrow()
} else {
context.httpGet(url)
}
val itemsElements = response.parseHtml()
.select("div.ModuleContent > div.items")
.select("div.item")
return itemsElements.mapNotNull { item ->
val tooltipElement = item.selectFirst("div.box_tootip") ?: return@mapNotNull null
val absUrl = item.selectFirst("div.image > a")?.attrAsAbsoluteUrlOrNull("href") ?: return@mapNotNull null
val slug = absUrl.substringAfterLast('/')
val mangaState = when (tooltipElement.selectFirst("div.message_main > p:contains(Tình trạng)")?.ownText()) {
"Đang tiến hành" -> MangaState.ONGOING
"Hoàn thành" -> MangaState.FINISHED
else -> null
}
val tagMap = getOrCreateTagMap()
val tagsElement = tooltipElement.selectFirst("div.message_main > p:contains(Thể loại)")?.ownText().orEmpty()
val mangaTags = tagsElement.split(',').mapNotNullToSet { tagMap[it.trim()] }
Manga(
id = generateUid(slug),
title = tooltipElement.selectFirst("div.title")?.text().orEmpty(),
altTitle = null,
url = absUrl.toRelativeUrl(getDomain()),
publicUrl = absUrl,
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = item.selectFirst("div.image a img")?.absUrl("data-original").orEmpty(),
largeCoverUrl = null,
tags = mangaTags,
state = mangaState,
author = tooltipElement.selectFirst("div.message_main > p:contains(Tác giả)")?.ownText(),
description = tooltipElement.selectFirst("div.box_text")?.text(),
chapters = null,
source = source,
)
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val pageElements = context.httpGet(chapter.url.toAbsoluteUrl(getDomain())).parseHtml()
.select("div.reading-detail.box_doc > div img")
return pageElements.map { element ->
val url = element.attrAsAbsoluteUrl("data-original")
MangaPage(
id = generateUid(url),
url = url,
referer = getDomain(),
preview = null,
source = source,
)
}
}
override suspend fun getTags(): Set<MangaTag> {
val map = getOrCreateTagMap()
val tagSet = ArraySet<MangaTag>(map.size)
for (entry in map) {
tagSet.add(entry.value)
}
return tagSet
}
private suspend fun getOrCreateTagMap(): ArrayMap<String, MangaTag> = mutex.withLock {
tagCache?.let { return@withLock it }
val doc = context.httpGet("/tim-truyen-nang-cao".toAbsoluteUrl(getDomain())).parseHtml()
val tagItems = doc.select("div.genre-item")
val result = ArrayMap<String, MangaTag>(tagItems.size)
for (item in tagItems) {
val title = item.text().trim()
val key = item.select("span[data-id]").attr("data-id")
result[title] = MangaTag(title = title, key = key, source = source)
}
tagCache = result
result
}
private fun getSortOrderKey(sortOrder: SortOrder) = when (sortOrder) {
SortOrder.UPDATED -> 0
SortOrder.POPULARITY -> 10
SortOrder.NEWEST -> 15
SortOrder.RATING -> 20
else -> throw IllegalArgumentException("Sort order ${sortOrder.name} not supported")
}
}

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