From e95e7618335d0f3c4320856bb85a24d7bbb4b590 Mon Sep 17 00:00:00 2001 From: beerpsi <92439990+beerpiss@users.noreply.github.com> Date: Sat, 17 Feb 2024 15:57:33 +0700 Subject: [PATCH] Add Weekly Young Magazine (Yanmaga) (#1318) --- src/ja/yanmaga/build.gradle | 12 ++ .../yanmaga/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2973 bytes .../yanmaga/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1410 bytes .../yanmaga/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3375 bytes .../yanmaga/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6477 bytes .../res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 8231 bytes .../ja/yanmaga/ParseInsertAdjacentHTML.kt | 29 +++ .../tachiyomi/extension/ja/yanmaga/Yanmaga.kt | 169 ++++++++++++++++++ .../extension/ja/yanmaga/YanmagaComics.kt | 134 ++++++++++++++ .../extension/ja/yanmaga/YanmagaFactory.kt | 10 ++ .../extension/ja/yanmaga/YanmagaGravures.kt | 72 ++++++++ 11 files changed, 426 insertions(+) create mode 100644 src/ja/yanmaga/build.gradle create mode 100644 src/ja/yanmaga/res/mipmap-hdpi/ic_launcher.png create mode 100644 src/ja/yanmaga/res/mipmap-mdpi/ic_launcher.png create mode 100644 src/ja/yanmaga/res/mipmap-xhdpi/ic_launcher.png create mode 100644 src/ja/yanmaga/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 src/ja/yanmaga/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/ParseInsertAdjacentHTML.kt create mode 100644 src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/Yanmaga.kt create mode 100644 src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaComics.kt create mode 100644 src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaFactory.kt create mode 100644 src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaGravures.kt diff --git a/src/ja/yanmaga/build.gradle b/src/ja/yanmaga/build.gradle new file mode 100644 index 000000000..749c37e76 --- /dev/null +++ b/src/ja/yanmaga/build.gradle @@ -0,0 +1,12 @@ +ext { + extName = "Weekly Young Magazine" + extClass = ".YanmagaFactory" + extVersionCode = 1 + isNsfw = true +} + +apply from: "$rootDir/common.gradle" + +dependencies { + implementation(project(":lib:speedbinb")) +} diff --git a/src/ja/yanmaga/res/mipmap-hdpi/ic_launcher.png b/src/ja/yanmaga/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..09b61e3b4ccdb340610f6399747bb8caaa17d772 GIT binary patch literal 2973 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 Q;{X5v07*qoM6N<$f&;6${{R30 literal 0 HcmV?d00001 diff --git a/src/ja/yanmaga/res/mipmap-xhdpi/ic_launcher.png b/src/ja/yanmaga/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..74a1793b6b432f6e1d68b25a1c70193ef388e343 GIT binary patch literal 3375 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 FV1hb>ffN7$ literal 0 HcmV?d00001 diff --git a/src/ja/yanmaga/res/mipmap-xxhdpi/ic_launcher.png b/src/ja/yanmaga/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..3243795f584350edb167ed2469ac888a459b31f5 GIT binary patch literal 6477 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 literal 0 HcmV?d00001 diff --git a/src/ja/yanmaga/res/mipmap-xxxhdpi/ic_launcher.png b/src/ja/yanmaga/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..1b645fabe80a9ba097e1776e0218007fe58a8575 GIT binary patch literal 8231 zcmY*;byQSe)b<^69BOE!yO9zQkZvR-q#GoZ20=m?x;q4sl9rb4mK4FEJEf6^fdSt6 zed~Mwc+Wcb-gWP~YoD|Ce)c~5IVbA1h7ulx5&{4Ko{F-(HtN~^-v!1(-L;n-u>pYY zSVdk&_v6ChJbEmR7RA76gA-R3bkUKrJkr!SdcHYQP6bP;&lnn=A8A?xp~xW+zfV`xL|*#$3w*epQ9bu*&@UiczJO zmxY<1179U6{^_7IwQS8z>q+reQL=zai$)l48nc}aVdS1n=CNYbQ+W&U6;A3ZN!Q_U z3fs}<=H_5yW21I5!JenD8N=if{)_nY0Bh^b?Tw9%4^2$IxVGS@xr%L-H$};3Jv}|~ zX=!PLJ-z5M&idMAQ?&QC?9-;4^?n%Z+toJ@_jiQR3E31+pNdvVrJym@+z*?xmVM31 z=~O|S^8Wn!Q{&a=@62x-jyQ9=y(p9Xus;Rc ze1QWQ`hiVAOYJ58_l{(wX?@N3o4MwPf2&;%qy|v%<`~^7#o_q#f{gkJsUA zcJ`-o7wGiTVN}*>kDoR4FLb0TCw0f7q*flj$M-6`gPO@mI1lro1?e z_7i?-QtG?_j8Y}0P#;9-E?!L6C=_%sk>Ly*xs)n?^QQy`ZlQq_EE=h_@SvC8YoY__ zyG_=>U*2xgTRJ%Fp1$-2y1n`>3T*pC!T<~e1L5)k1~DK27q9>TbbtcbIFHEo0OAFs zLvEU1E=D>PH1e=CI4w4!I+fn%sm7us@5k|_i+5&8O@dTkYrEJwd_qLN3NoW46vw@v zT{|sM!iB|R1Mn-JEUij42R(F~mq5nxaz{-2dOpQOfnWFmIv+5%Vp#7qgRy^TSnF^v zh6SM0TRV)`J4~GXFa+g&fq}Y#A-+~$gaBiE2RqVoCC8B>6_n_9v2|*_6$7qId-zbU ziv`R)u?3LC-||@5SS^+!*K59tU3Msi=NT@GO`O#+Or-$br9B~~PdxWF6p$aR0KN`i z1W}XAvaEYA|Ha`UI24kmq}Ct488oM5r(ZYjiV3`1ro&sfoh*m+EHC?>418mMMmL zcYWBHlNft_c{neqmh~L8zG60YSVqkD^SIA<3wOI`Fi-B^cy=kBYvwc%hz?Zvc(6*) zSV!O~)UwBF{KX28G98k4K7!vjcZMz6F2HIfcxOU%jpe9@z^@m*&A2eFg4uqgfcPanHub zCQ_#mRs$7e$l}}ic%^c&%IB`Qk9{rp89ZPVOH(adO1^3|vN+E^9)8;(Ki8}tk?Ki| zUqk_2`Iq_obY|aOf3{wc6~bqws_bE-+jyulRLA9& zAP{4i#wGFBbn@~%W*?a8@MX>sFp_ieNFIm;J|EJ7)=miNu>kmFUj%gh0FzCWz%8wC zuJgCFsx#0fhR>^lB)SzjZt$Kic&L&;)Xp>s5`se(frO9Xy66=rk>gE^m_hJ|= zhT{E(lZ8PT*hC+8C-hXakG5mT1W>UV4?lUh&nG`?p&u!AIL`v*1xT-eX(2lsme&k4 z$?!Pk7Y@?-U;RJsJy#b0^yR-{V#jmEu?gZJlOS2j1yA|Cu74RIu9?zAdwzpHO|up~ zyp-o$PN6=CGZu6hXpI7If0|ga7D!<&r-26i;JJt*V~Q`NtdWvQU=K9H4vl+1L;uU2 zvdMX+kgyE<`rqaroUPt=2xJA=FiZH|lDvhGO2cA+#Vg7#24oi&tg=mLcluRybdkak z>Ccd+pk7VAx1&}<_ebA#>BrzS10Fl_eK#-EvR=^I{rN)y;KIxc#G9NM^j)FuVbQL9 z^B0qRcHahK3!mTKmGtGhjzqqpdLCIm7Ll$PAnAm*c3!Mi02zq3SS(h5Zn*{G|U}sIBia?3yM|onk zWH5ow`gi=%i6E6F^xOhE`F%VA88zVK*%G52ZK28H9?qe~oJ%>)H8S}zoJR`>~5bI8gt)-mJ0gcZao>x;-~pguCL$- zlNu9Ksc>|%s*mpFXDAZG5YInO2#DswolT#y+lSwCT0t<&u!ih}xpZM&4 zUTCIQEQ{Aiv>73^PAc=wU)TvhGi|n@aW5=T>8xQ0$C<@*Ty6%joNouED*9K|X z7P=c+`xw@^@y}WE8Ub1 z_7720kIql<7|8c_3%QQ)NZ)RL5vq`%sPPp#TkrF$!;yx-?z&z%1O{YO>&I{DGx0q8 zlB%qlS2g@-m_(PIPClLuuUvp6zv0lKw0XpG4bh+xzgkXzcX>FmqKfgU&5KYuMHNI5 zjy$&;&jS@z%k}TT=;DF26gr2W8a&2{C7Kui>K@aQt35{3_dnBhdts|%$YXxw&t}UJ zx29yd`rWS;vKaC?7YC@C%S>S#;{-T>n=_rkxDPke`h7=%55^2q50aMsuAfWZScjmI zoaqlK&oW=3u$Dx!{{unxOxhnpO26|v=fiQz+D!Kqr|f^T{{K;`RUo5hAfX z1T&K`SUajXTCPQR&}N0TKR#63AU48miC`qa4=O=c^{I=qMO$C2>tjrQjyr$Jz}rwV zw8ItesKA#Mf#$vG#&I;8y0%;l+!=(c3ARbm@b25Gs7?9u^?~1Ns#|E%`?K6=iD&?a zoqATZ#WcqTI%w*jK6X3acYPM~&f_f^g$C0)*7_aEs6u(AWX{Z@A^H7+K*U+*uET7V zi7lGFc6qoQP9xc`Y;~eOS?PdAi}wrtrxj}~?;@^_&=F5x+9S`A^Ew46{{ma)jjs9d zYDw$`j8ug;y3(bMXFLQ&$vn&xm65?PtFX+r=Z?}+%f{dz+)>Od0vnp}Qewrp?ihkI z!LG--bvb#>zJDNcnT!%_Te?_ofCDBW-k5TeNS`?GaI@I{0JlfNdWq$yTiyCxhJJ%` z?{@P;;=i)F0p5I=Y{J^aG1ZRx~q9-n&+202|9#;}#(qp>b zbO&Grd>JBOWLW(@oU5#Gv6&zhpw7|BpcND_pPXwgop3C#>35104WQ*tuNCU2wO{TY zP0015;?&T8<5Ut$RSwQu3%qAL<;+M(RaKpkBIU-U*T}fIq4>2$P{^!T@=_~*8*5cW zpnLWiBB;vAm{3uI>q7rR8Y0yrJj22woS1v{62Hrj)wS+D|Bm0$Aa93z3s|*cwN}Hz? zaeoo;QZe9_4aLydQm(d2)N>ebY5S1}wB72_92_C1-j5mqo-v$T z*e9Eee~I`wfSwi7_DI=&Y-y|dm#!f042dioyK`GLwpxZD$SFhQyHs5R2Yk3bAZ7Kb z^^g7a!?JjCTKYFAEuLRy*>IslhuGLars!J%TMUEh#{z5udgTbOrwkvvQsoM0mRO&` zWb4H$i2&Hu;Sws&x*wL?lrs`apokWr=2slf+DeC?mrlhTyvyfaY~Nf{!A}6`@_Ct1 zIWE5b`@7#+q9N)ZDob8f(}SCBU1Llfw*SCMKx;|B-ZX`Tqp~v?6$)HZBesRn&|LKU z>-~H(xme8Jrt!#x;b{#u62R><472+Y;bJp-duekNO?ns$hpk8qN6Mgg?Vy=)0L~}B zjfI@qH3FW&dND~rHmt^xgomgpRy=(s;xyljIdVX^ec+U;2j+n33?^8XDrDSHOMYL; z6(b!bW}?`L6ON-yUJ{s+<}2;PocLyD%Jkoa(&qnO?u*GkSnzri$p%&5X973=&wSV8 zEE*hgK25FlFgM{+F}gZnZT&uXd6dW4Tka1QJMbxT{N3~#Z0CJu75@PjDN&ztM zAa_EGfVsDFVw$v4y_7_ag^da!x6J&EQ;pvbT#Lx1Wh%($PKK zUZ>YU%V$@Q9v`tiNI!lYV@EA0^+c&$Ipa|-&FMQm>V&`HvS^md3()+(YiJSd$(kUF#?q@7oQfGPiHBP@Wjd6pt08mNjr9?M>C==wbw`Es1fq05|S{zSjr-<@2wWR0k z%iA4ry__rInl;_D!7rvbdvg5qtJjfq#9P0Mn`l?MG#g#!x z)*BmypRwg z8;?bG@oZKdqb38Y6KP&xCF zoEAf_q9{w>4HHc@b&g>CX;J60u{cboD;wE>q&o72spNqYbFY}>-V(s9dD2DAb4@thA|ZW>Q+#kg?K zEdr}K|G&zR!ytGf#7h6z;kjLvdfMLXI&wFxd^bG>NYzd+8@qn|Nb zXwcXY3u#~SRieci5D77S&aqdDW-_9 zA%fuYAkxs2e+Rmi6&UUGlDA3U(C=yRJ?|z+S(f;^%9SSka>CRWI6`TGmzctU&gnvf<#pU z06E1-r-?>T?;=`IM4GDenHj-DO@UD_Sx{AS+U7Y`iSM zAnzZKayX&0YwcHNDQu$=LQVP?jikVrqcLXG^qXAF4rBu?2EHk5NqnmGx%0#^vY-<2 zFNJSmzng3g9)W6tlj!;-D_b{$v%p3}1bN<1(y2)w;s8{xbNmknYXk8o=VXkMgD8Si z8)9DecRWj!M*K#Iw3#z?tcLTu0^$xOK{}V93A4`5fed)`{H`bbN<9E6!o4Mw1=z4O zTkR#w_V0W|QM2$&MavQ-s@q!-JLs?urs zW(3$D3R-i8l1P{6@hC+84kBS_ta8)dJWT%E7(P~SQ*J%W!u>>c3%k*2LAm*8?uQ{U z0~gX`$dZTWuoKqZ)|>^oloCx9U$fL&Zhi2G=eR^h1sN zD5pck#mRXyl$w`2K8-q@p~tBUl&fF7KEpNr$#>XyC!bFpKc@)=4*R>+804z-?xRmuUpk`(r&238YuSw z)$|U!rfK)cMBryg|SkiuJ0- z^%3V-)yOdwRoW#|U1M;*P50d29{dTJ5^)9B_($OypKV^NtUdou0@LE`HK1jY_iq>t zv7Wz?td$mCnti1sNM&X;hTk87g#$G={+`0bz#aOvr1PG@Gf8iAq2Z*=QXwEuRnMV0 z$@ahSbG$q&QjUNSn#bj2i*Hns{lsvSHqOgGx=W!m@B58d+Jigd+1!!+>hwW~)>ypi zE(Bt&3{)~GXushgK>o?~?^j65wEjvpy_fPPA!f!S&O1Xv!tll#Q4rsFs6@NImVFgn! z*WI0=Zz{#pD++J`r;BYvJvhXxWcDP+FR}VaAIVFm(07$_V$D#SqPVoy5OipWBkOYMriji6aPY zM83a4H{PRH4M)YVrSGrCku08{@f5{_wbC2_`Z1(esjF(MsiWOYm?_Sr!&AkrW5OJs zuWc-4g>57j5vLog9ZcN`5LHsQMdQjFjsQ zKx}5FhCR)$DfP-~griZqCAJ6_r{rXdP2{Jj5fSeyg-jqdQc$$9{?Fz&Ly#kime?$h zkWwu4aC-gSr(Wnvz&)Hs&*GH!iWpAFdS}2&Z>0_V6lsqh+CnKPx~5|{+>6+nPhopu zVJQSX&mrrNr2J zCBbHQ1moUnow$aw+c$9(M!a`4HmVXxV5fL{qbQP|FTCb{R&Gjrv1Vd0NXeW5&L@sjNs9P{u^fvd<0df!%6P z)n6mvKE(8XIAN0pm0Os;v0_?ihe%15YVvOVR9EzOJ7d}n!?FFCg64Yf_HJnq@5=LT zF;S{_mdcQ0IT%&Or!3N?f{leM`Y%LP2T`Yn1|SK9^ife(Dj2Y(~UX{@&FQ zNJgQ1^);-Q-@)Xo2n}NLAi<-$8Dwjpg2vZrX}$0#498WTDi`A!Yv&6DYD2?*`sM|H zDoVpuzOnfGtmTC!%wgQieWhC;>wdyP?zy4jJ#|R;&C&GkXpbQS?$BKuDWa-cQp`xM zV`+Y==lk1N4h75PR;noRf!(oh^_B2xnLUa%2e@KMBQwgU(~u{7#7wd(2S4$K$2d}4 z8!%&PGW={`q@X2U9si>8YPZ_IIkk7O<^3>Rh|%c$l8GOm*a+9*^x_}M%}#9S3+{;l zfBuD1!&euflT2=%VDuZ?;ni0l<+?|Qpa-UAO^V{j(?Pn&;Z7PV5L5<4a@b`BOa$-# zK3tIjnf>(ZPaYq#Gj|V|{pR;ihM)~aTLg4(Xn?~%(+IVs{`Js{IvR?dmQdG7X|g@Xx@IHl#!QQ2`QhMf1f4j{Cy1VHVj z{qPdae}c?JRPNg&X$5~7#M2>bSnV(=F!qx+?|(UOm6?TYP_4md=uZRCx`S`xN#0Em z8gx@!T>N9_cP;kwAW>LMY{5mDx$86`iRR_U z2~g7?8EVsW^qf|lHONaC0l3jDY-VOg&(d6wIe9hdV79s|Ti9u#3yB5A3x@HY+S`BWlaT_Q+L_z)w0rXdN|K>)R#)@UToD(u>-jo6JRiPv zf0r?rvYqj4zovluTLsrrz-FQhTqPwrb6d~^1f;v8>qoYG-O@m?R+p9^>n3As62SD-KwELEw z3}PiM@G6l&H6|uzvC(upo=(acoRZZSLC_^=%9lNdvVHpT@o`x(S03z) z4PM0e{`zrbuloL(MWrmLeT||~1br)57GEFqU0SFV)R3o<@qCJNY9b8Ms)gacrI3)QXa`K0Y!N4z57gWl za^b;zM9^dhh%^+ZA+7C416uyqZ`pX5|xH=a}K>7Cny zEa6hr8!!&9rS?YInk6DX+NE!}x&ut+9GthNYH~U2SIJrg{}0Qylw|+_ literal 0 HcmV?d00001 diff --git a/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/ParseInsertAdjacentHTML.kt b/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/ParseInsertAdjacentHTML.kt new file mode 100644 index 000000000..9000d5164 --- /dev/null +++ b/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/ParseInsertAdjacentHTML.kt @@ -0,0 +1,29 @@ +package eu.kanade.tachiyomi.extension.ja.yanmaga + +import app.cash.quickjs.QuickJs + +private val INSERT_ADJACENT_HTML_REGEX = Regex( + """\s*\.\s*insertAdjacentHTML\s*\(\s*['"](beforebegin|afterbegin|beforeend|afterend)['"]\s*,\s*""", +) + +/** + * Get the inserted content from a script containing a bunch of insertAdjacentHTML calls. + */ +internal fun parseInsertAdjacentHtmlScript(script: String, targetName: String = "target"): List = + QuickJs.create().use { qjs -> + val cleanedScript = script.split("\n") + .filterNot { + it.contains("var $targetName") || it.contains("$targetName.classList") + } + .joinToString("\n") + .replace(INSERT_ADJACENT_HTML_REGEX, ".push(") + val result = qjs.evaluate( + """ + const $targetName = []; + $cleanedScript + $targetName + """.trimIndent(), + ) + + (result as Array<*>).map { it as String } + } diff --git a/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/Yanmaga.kt b/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/Yanmaga.kt new file mode 100644 index 000000000..6c661fb47 --- /dev/null +++ b/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/Yanmaga.kt @@ -0,0 +1,169 @@ +package eu.kanade.tachiyomi.extension.ja.yanmaga + +import eu.kanade.tachiyomi.lib.speedbinb.SpeedBinbInterceptor +import eu.kanade.tachiyomi.lib.speedbinb.SpeedBinbReader +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.FilterList +import eu.kanade.tachiyomi.source.model.Page +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import eu.kanade.tachiyomi.util.asJsoup +import kotlinx.serialization.json.Json +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Request +import okhttp3.Response +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.text.SimpleDateFormat +import java.util.Locale + +abstract class Yanmaga( + private val searchCategoryClass: String, + private val highQualityImages: Boolean = false, + private val dateFormat: SimpleDateFormat = SimpleDateFormat("yyyy/MM/dd", Locale.ROOT), +) : ParsedHttpSource() { + + override val baseUrl = "https://yanmaga.jp" + + override val lang = "ja" + + protected val json = Injekt.get() + + override val client = network.client.newBuilder() + .addInterceptor(SpeedBinbInterceptor(json)) + .build() + + override fun headersBuilder() = super.headersBuilder() + .add("Referer", "$baseUrl/") + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val url = baseUrl.toHttpUrl().newBuilder().apply { + addPathSegment("search") + addQueryParameter("q", query) + addQueryParameter("kind", "human") + + if (page > 1) { + addQueryParameter("page", page.toString()) + } + + addQueryParameter("search-submit", "") + }.build() + + return GET(url, headers) + } + + override fun searchMangaSelector() = "ul.search-list > li.search-item:has(.$searchCategoryClass)" + + override fun searchMangaFromElement(element: Element) = SManga.create().apply { + setUrlWithoutDomain(element.selectFirst("a")!!.attr("href")) + title = element.selectFirst(".search-item-title")!!.text() + thumbnail_url = element.selectFirst(".search-item-thumbnail-image img")?.absUrl("src") + } + + override fun searchMangaNextPageSelector() = "ul.pagination > li.page-item > a.page-next" + + // Longer chapter lists are fetched through AJAX, the response being a JavaScript script + // that inserts raw HTML into the DOM. Horror. + override fun chapterListParse(response: Response): List { + val document = response.asJsoup() + + if (document.selectFirst(".js-episode") == null) { + return document.select(chapterListSelector()) + .map { chapterFromElement(it) } + .filter { it.url.isNotEmpty() } + } + + val chapterUrl = response.request.url.toString() + val firstChapterList = document + .select("ul.mod-episode-list:first-of-type > li.mod-episode-item") + .map { chapterFromElement(it) } + val lastChapterList = document + .select("ul.mod-episode-list:last-of-type > li.mod-episode-item") + .map { chapterFromElement(it) } + val totalChapterCount = document + .selectFirst("#contents") + ?.attr("data-count") + ?.toInt() + ?: return firstChapterList + lastChapterList + val chapterMoreButton = document.selectFirst(".mod-episode-more-button[data-offset][data-path]") + ?: return firstChapterList + lastChapterList + val chapterOffset = chapterMoreButton.attr("data-offset").toInt() + val chapterAjaxUrl = chapterMoreButton.attr("abs:data-path").toHttpUrl() + val chaptersPerPage = document + .selectFirst("script:containsData(gon.episode_more)") + ?.data() + ?.substringAfter("gon.episode_more=") + ?.substringBefore(";") + ?.toInt() + ?: 150 + val headers = headers.newBuilder() + .set("Referer", chapterUrl) + .set("X-CSRF-Token", document.selectFirst("meta[name=csrf-token]")!!.attr("content")) + .set("X-Requested-With", "XMLHttpRequest") + .build() + + return buildList(totalChapterCount) { + addAll(firstChapterList) + + for (i in chapterOffset until totalChapterCount - lastChapterList.size step chaptersPerPage) { + val limit = totalChapterCount - lastChapterList.size - i + val url = chapterAjaxUrl.newBuilder().apply { + addQueryParameter("offset", i.toString()) + + if (limit < 150) { + addQueryParameter("limit", limit.toString()) + } + + addQueryParameter("cb", System.currentTimeMillis().toString()) + }.build() + val script = client.newCall(GET(url, headers)).execute().body.string() + + parseInsertAdjacentHtmlScript(script) + .map { chapterFromElement(Jsoup.parseBodyFragment(it, chapterUrl)) } + .let { addAll(it) } + } + + addAll(lastChapterList) + } + .filter { it.url.isNotEmpty() } + } + + override fun chapterListSelector() = "ul.mod-episode-list > li.mod-episode-item" + + override fun chapterFromElement(element: Element) = SChapter.create().apply { + // The first chapter sometimes is a fake one. However, this still count towards the total + // chapter count, so we can't filter this out yet. + url = "" + element.selectFirst("a.mod-episode-link")?.attr("href")?.let { + setUrlWithoutDomain(it) + } + name = element.selectFirst(".mod-episode-title")!!.text() + date_upload = try { + dateFormat.parse(element.selectFirst(".mod-episode-date")!!.text())!!.time + } catch (_: Exception) { + 0L + } + } + + private val reader by lazy { SpeedBinbReader(client, headers, json, highQualityImages) } + + override fun pageListParse(document: Document): List { + if (document.selectFirst(".ga-rental-modal-sign-up") != null) { + // Please log in with WebView to read this story + throw Exception("このストーリーを読むには WebView でログイン") + } + + if (document.selectFirst(".ga-modal-open") != null) { + // Rent this story with points in WebView + throw Exception("WebView でポイントを使用してこのストーリーをレンタル") + } + + return reader.pageListParse(document) + } + + override fun imageUrlParse(document: Document) = throw UnsupportedOperationException() +} diff --git a/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaComics.kt b/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaComics.kt new file mode 100644 index 000000000..294e28cc9 --- /dev/null +++ b/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaComics.kt @@ -0,0 +1,134 @@ +package eu.kanade.tachiyomi.extension.ja.yanmaga + +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.source.model.MangasPage +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.util.asJsoup +import okhttp3.Request +import okhttp3.Response +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import org.jsoup.select.Elements +import rx.Observable + +class YanmagaComics : Yanmaga("search-item-category--comics") { + + override val name = "ヤンマガ(マンガ)" + + override val supportsLatest = true + + private lateinit var directory: Elements + + override fun fetchPopularManga(page: Int): Observable { + return if (page == 1) { + client.newCall(popularMangaRequest(page)) + .asObservableSuccess() + .map { popularMangaParse(it) } + } else { + Observable.just(parseDirectory(page)) + } + } + + override fun popularMangaRequest(page: Int) = GET("$baseUrl/comics", headers) + + override fun popularMangaParse(response: Response): MangasPage { + val document = response.asJsoup() + + directory = document.select(popularMangaSelector()) + return parseDirectory(1) + } + + private fun parseDirectory(page: Int): MangasPage { + val endRange = minOf(page * 24, directory.size) + val manga = directory.subList((page - 1) * 24, endRange).map { popularMangaFromElement(it) } + val hasNextPage = endRange < directory.lastIndex + + return MangasPage(manga, hasNextPage) + } + + override fun popularMangaSelector() = "a.ga-comics-book-item" + + override fun popularMangaFromElement(element: Element) = SManga.create().apply { + setUrlWithoutDomain(element.attr("href")) + title = element.selectFirst(".mod-book-title")!!.text() + thumbnail_url = element.selectFirst(".mod-book-image img")?.absUrl("data-src") + } + + override fun popularMangaNextPageSelector() = throw UnsupportedOperationException() + + private var latestUpdatesCsrfToken: String? = null + private var latestUpdatesMoreUrl: String? = null + private var latestUpdatesCount: Int = 0 + + override fun latestUpdatesRequest(page: Int): Request { + val pageUrl = "$baseUrl/comics/series/newer" + + if (page == 1) { + return GET(pageUrl, headers) + } + + val offset = (page - 1) * LATEST_UPDATES_PER_PAGE + val headers = headers.newBuilder() + .set("Referer", pageUrl) + .set("X-CSRF-Token", latestUpdatesCsrfToken!!) + .set("X-Requested-With", "XMLHttpRequest") + .build() + + return GET("${latestUpdatesMoreUrl!!}?offset=$offset", headers) + } + + override fun latestUpdatesParse(response: Response): MangasPage { + val pageUrl = "$baseUrl/comics/series/newer" + val url = response.request.url + + return if (url.pathSegments.last() == "newer") { + val document = response.asJsoup() + + latestUpdatesCsrfToken = document.selectFirst("meta[name=csrf-token]")!!.attr("content") + document.selectFirst(".newer-older-episode-more-button[data-count][data-path]")!!.let { + latestUpdatesMoreUrl = it.attr("abs:data-path") + latestUpdatesCount = it.attr("data-count").toInt() + } + + val manga = document.select(latestUpdatesSelector()) + .map { latestUpdatesFromElement(it) } + val hasNextPage = latestUpdatesCount > LATEST_UPDATES_PER_PAGE + + MangasPage(manga, hasNextPage) + } else { + val offset = url.queryParameter("offset")!!.toInt() + val manga = parseInsertAdjacentHtmlScript(response.body.string()) + .map { latestUpdatesFromElement(Jsoup.parseBodyFragment(it, pageUrl)) } + val hasNextPage = offset + LATEST_UPDATES_PER_PAGE < latestUpdatesCount + + MangasPage(manga, hasNextPage) + } + } + + override fun latestUpdatesSelector() = "#comic-episodes-newer > div" + + override fun latestUpdatesFromElement(element: Element) = SManga.create().apply { + setUrlWithoutDomain(element.selectFirst("a")!!.attr("href")) + title = element.selectFirst(".text-wrapper h2")!!.text() + thumbnail_url = element.selectFirst(".img-bg-wrapper")?.absUrl("data-bg") + } + + override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException() + + override fun mangaDetailsParse(document: Document) = SManga.create().apply { + title = document.selectFirst(".detailv2-outline-title")!!.text() + author = document.select(".detailv2-outline-author-item a").joinToString { it.text() } + description = document.selectFirst(".detailv2-description")?.text() + genre = document.select(".detailv2-tag .ga-tag").joinToString { it.text() } + thumbnail_url = document.selectFirst(".detailv2-thumbnail-image img")?.absUrl("src") + status = if (document.selectFirst(".detailv2-link-note") != null) { + SManga.ONGOING + } else { + SManga.COMPLETED + } + } +} + +private const val LATEST_UPDATES_PER_PAGE = 12 diff --git a/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaFactory.kt b/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaFactory.kt new file mode 100644 index 000000000..8704e7eb0 --- /dev/null +++ b/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaFactory.kt @@ -0,0 +1,10 @@ +package eu.kanade.tachiyomi.extension.ja.yanmaga + +import eu.kanade.tachiyomi.source.SourceFactory + +class YanmagaFactory : SourceFactory { + override fun createSources() = listOf( + YanmagaComics(), + YanmagaGravures(), + ) +} diff --git a/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaGravures.kt b/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaGravures.kt new file mode 100644 index 000000000..3cb5bdd64 --- /dev/null +++ b/src/ja/yanmaga/src/eu/kanade/tachiyomi/extension/ja/yanmaga/YanmagaGravures.kt @@ -0,0 +1,72 @@ +package eu.kanade.tachiyomi.extension.ja.yanmaga + +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.UpdateStrategy +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import rx.Observable + +class YanmagaGravures : Yanmaga("search-item-category--gravures", true) { + + override val name = "ヤンマガ(グラビア)" + + override val supportsLatest = false + + override fun popularMangaRequest(page: Int) = GET("$baseUrl/gravures/series?page=$page", headers) + + override fun popularMangaSelector() = "a.banner-link" + + override fun popularMangaFromElement(element: Element) = SManga.create().apply { + setUrlWithoutDomain(element.attr("href")) + title = element.selectFirst(".text-wrapper h2")!!.text() + thumbnail_url = element.selectFirst(".img-bg-wrapper")?.absUrl("data-bg") + } + + override fun popularMangaNextPageSelector() = "ul.pagination > li.page-item > a.page-next" + + override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException() + + override fun latestUpdatesSelector() = throw UnsupportedOperationException() + + override fun latestUpdatesFromElement(element: Element) = throw UnsupportedOperationException() + + override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException() + + // Search returns gravure books instead of series + override fun searchMangaFromElement(element: Element) = super.searchMangaFromElement(element) + .apply { + status = SManga.COMPLETED + update_strategy = UpdateStrategy.ONLY_FETCH_ONCE + } + + override fun fetchMangaDetails(manga: SManga): Observable { + return if (manga.url.contains("/series/")) { + super.fetchMangaDetails(manga) + } else { + Observable.just(manga) + } + } + + override fun mangaDetailsParse(document: Document) = SManga.create().apply { + title = document.selectFirst(".detail-header-title")!!.text() + genre = document.select(".ga-tag").joinToString { it.text() } + thumbnail_url = document.selectFirst(".detail-header-image img")?.absUrl("src") + } + + override fun fetchChapterList(manga: SManga): Observable> { + return if (manga.url.contains("/series/")) { + super.fetchChapterList(manga) + } else { + Observable.just( + listOf( + SChapter.create().apply { + url = manga.url + name = "作品" + }, + ), + ) + } + } +}