^rF93iNc
z8445p7T$9I4#R{-(v7L?Lw`b2Pjd?Z`UN`qx&zftru!3tG!B51+#s|_e`^8!QwWYE
zS#rXTvnT%yhQU+wLa*23$j|u87UXA~6NSs(na}mv`3DR++|^*JnrZ3qOkuvDqoU!_;j?PK{O&R=D3NID4fw@e8|x
zm0&r`9Y@6T0S=|V^y}|9LXfA|&O=j*jLHvw0%LvS{2u&C#iD-TO7Fp0mwyPR^jc~O
zeu1qc5WP2DIcQSe8b~@4adqsDOvJ=?%lg#U5e;elr;ilyYO^xS_7gC({gaN21@qL}
zlZ~zmx`Oj}S0gEZ&l7cvwLny|ge$h@<@5dd;8$t&PUhJZr(Y$lMg;vQJestd%gFgI
z_C*d>IU4b6=g^|XyctjwuhB-Sc&l)*Pl%P+8Os-3AFfg=vPTHKdz@JvoKKD$g^5JgxZSZ
zw@gjgVCrN|UFBdZ*rOF}SS6sjWQIZo1oN$?c+TfWHGhhI#vx`G!}gNN)VqgtcQ(r;
zLxDO`(yNN}F(cu8OmV9;0=glY#l`wl96bK_Ws?8Cj)ccY>Z>&gm?bP#z%c37{u^Pd
zuu*{2ej^q+qQW8sT;oJM86vLp+82*k#e7=Y_xH0CXIOjVtC#=vFK0(Lt6~Fc!?rxP
z=BMOCSy#_lb{CsU^XnD8BlV;Xs>Nug2KX19D6{%H?T&v-U*fT5(ahf6@2_VSH
zrO`QEU{rmA9y#cs^t;u)3uzK(?7O?XRvKpleYCr?;&&ldm;;rwV=e`W@}`A!*6QDp
z=3?bXR`g+v{L|+G28&HsqKU-rTm<|{^qpss3UfART5mQCNjzvdJ)h@&SGL{8G*-kG
z4Sq2h?PC%!+>D%P_S~`)B>D#VR`wh{EAvlfeF$HP5>LyR$fY1I#NBj%NMOydOojO#
z`d*&^cKIYW4&4uc@P7HISj-Fn+iF-6j@P&_1f1x`KCW4Jm4B&N#QmiR09FrK
zwJDu>FUq#c-Xz}K$o0U8pleQq{!sEaWXKA@AUGSFb3#UPBh5oIAFnQgyMgs
z@$HNhd2cYe7Wj8{S1;Nqm|9~G@3{uIy#OBzVPyH=O6^Q?6x9*0Nka{(Mb;E!3FDjo
z>7BiqlzmRF(W%QuRo|))atDpL-PDfmE@3l`i4AFgW+>9EaOpRB*QVfHT+~HrX>(OJ%A*qc8>T^kQ5h>`W@kY`39TmzwntG
z3)r|}-&4-Nm0<}2-?i0HiJpJVqm#!#?61kk==xr`bp4W(T{BOB=F9BG*J&-adJ6H=E^HQB2oN7)-nHmV7GEZCrO2_tJR#9Pr1$C-=5>9YBTj@I
zzJ@ksYCydiD~cFzmb5DvXNze~H6#&xtRHO7Cv*PF=eVDT*WDKNog9hb^gfADrY?E1
zex`rUI4LanRxFjE6`bS9-H$|{f4vq~6AoZ~LXFIW)bo*@vD5jc1K0NAAp%2+%rsd$
zn)5uL<0|&n0B-Fh(IQ9Wkt!=;SJ+q4c;{YPqM)gili0hP?nMBnA}`6js3JMRBK#>{
z?RaxKfC*d4&b^~XXn!ZF4E2^x1M@=C_V5!Rm5v-UWMWJ@KjSYMtUC#~zS5%UuC&)1
z7r+1tCa|DV9yh8CEi$Tp+24vxO_2Vg>Z-~99n}nbqSD@$d9pjRb><8STBKoRGQ(%l
z$Fsk2-S%a(XTiBbb{R{*$|o{nN
zrFCh+qN&IT;JR~eu8d1_EuckD=_jBF%pFt`d9u}$=06r8N#&XhVZaTy#aY;eJW|Xl
z&Zvk$o*VT96q$eK1}Y}FAl
zGT3U#=8G$8(UKvT1jDM+=9)R6nW;2B1PDy%A~W*!vPXXvuA*PvxXj#Eq|JN-064n^
zY%)>jK%vpn;r>cButX>IF}HJ(B+6~c@IQVVu&n96_{*F|`rwKfnkPL*$Wp;;I>Fk8
zk_gt8dH~N=S$DB}{dvxPkfrP_`-;=G)JC;LoaESfnh~7fka9q>*s1S{@u)y9IiLx*
zg<4g~kf#ZX3Dw_SGY2NI3XrbiKUQ-FF9R&w!~%7eO24QnJcm*I#4f)z;Z
zOY^)&4uw7l^`ZA?lku87A1^hmNtxqc?^S>aKLTOHN{l|Y}QS`
zP5u?AMnNX6XPkikse;5uX#Z_pY*yc90jG~tifa%Sn18Fj!WY=NN|
znO=*0*w-k!;|qA(&gMFVeY3mA&?hPk|4vRTU=i9;m%2uDMRHEcL(qzVKb-{
zh(|97TLv002s#OJqO_xV5Q>HFGmz*H0V8CdLlHMz*01LmwI)Ee!+e%VFH4z`fR%!W
zGIj1XCDY}9vj4FNKzsHhRRWL=W&Z1kHiAg*lfa0O;sLvW*b5*cUZRvkTceAbaCQiF
zKtqo#hP)r$u<_%jZ;Fb{E&t0D5F8j23D7W*tv6)nabotm0W1{ybG=y`#`MG2k9`iU
z)ZRb(udmLL`cqxFW5=6y3c0s*pV~S693YDnkcCe>xxfG-FCqSfD>zaL7ixgw;qhE3
ztX>4?BB2c%Mdt2e=(RKI?(>}=O?5%L`uF4TGm@S$q?GWk$sfQvF19h5p7%&gRZ(_lL|ECD;DGm}>>e#I&)od{kr<4?`N3GjQ#bHbbTt@EHer!rWmqjjRFLV3
z64}glr^Nv&Lcm0kSLZS(cRbn2PPh^UKnoIGVsHVY{Jx{weG+jpSMD$VDvgu&^CdV%
z(eV;{b@B^6vta!r8%FG?Mr0-B+et3Bd}q(#ahKn-9vy
z_oH!&&(n~K1SH0`FkG2G)e#*s5qVNA-qxm-ES+#@fKai)xU%&R5O~7^jC(*f>^S!CL
z;D(1_+z)}|@ES}hxIEL9k%p&F#=n7g_Eg97bO5QLvFA5E0qZ!7-x*)wK7@M9Yd${)@w&a~L`Sfg1~Yg}DP(%wUSV&z(q2;j5d5mw
zE3HU&$pXibDyWOl=bJV+If?Fb=eEtgQe-cMQ#n){E*Y$SVvXF1qs)h+bwf|OB(0(N
z*Pnjd2IuFkaEGGzAKJx*Km9i?-NRc|+nDuSe&ee*$
zpmK`h0HeCY1fq_s-Skul7@Qz>=D*!6S4Uz}_qIm1_u6F=djeQj=IsdX!SFNZ!
z%WyWszmjtn9A?8eIHUNuKYAmhKnpZHJ_J9$A$KD{O70bRW⪼VkR~-)Wip*9$5vf
zfK&M0#AK}ly?c*{1vP`X^moR*iUkbHf|yRjw^rU=fAU$k(9p`V{bi-N@w~!Qz=3E_t!0q@Uh+Ilu
zBUrBCJYATHt>=Xde>5TO$9Ixm10mbqhkG;0^Ud4C_D`>KF%Whp-K;hxv=P0EBH?`2
zef~<;(a(>?Pxn~uzpBus{d)EO(e}b%*GqQEPD;8fsL~G*svVGU(yJo4ciPwF8ClzV
zq#pD&UT`Lhj2UaA$k>eJXBDRKC6=CW%!_;(e}X2w@M&E;LSQ1W?90eahIFYwCH`^~
zIx?O^?#{XTSn{9yP+6qS%07H`PSFsIKcOd*78lJbX7^7-8vLVXkm0_|yi;%HbD-Z}
z#-EX!b>ahtB!XRXI6MHUakRfYQx5UoqcDmjz}6a-M1Vzyrp7e0|6cpsZUltUo54s7
zv+l$~t+v8tgR=XFdie58+*S@d4>00LVJ6?WzN*q`e9XjqO`Z+%W~4Y#(sD|te_dGmaVJ@#HtWu-KQzXGK@gvJb+&rcEislyldB-!er_-Y
zU~c~1?3aQk-$E)0$#zHii?;?*KVMC{bUtqYD{qc1RMdiRT
z8vyrQ=(V#f?y+jdkuM3!o>BRO2wo!XDqkXkGBB!v*WBJvb4R3c#TMyPPI
z^Dth?sHD|fNdkgbA8M|^;5;(XkkJL>KC8fcElE5^_x$d;nAPZp-ir#qmlTO~J*-8S^ddR4tJSnU3{z{EXi
zS+Fuz%>av(07?_J_J`l{iln7}o;iIq7ufmwKEz7J*Y+f>!FD{bw|=tnif}Sp@oX?h
z=>^1XM%OMU11s^57ymJYX5Usss&PSif1%lDf2q2WU1kmsV72ttxi2IFz(kEv3jx5C
z{)M>~ipEl=T4X|meQJ7HkT&Qr1B%#4SaG@)a$;*P{-)dF>fNT^tu=XfTwVS^k}p)z
z@tJvE4pKASKUgp!K_|q!q>mb`?XD0oqjvpf&ATbajULtpKRqPFHxq~uQ&s-*Il}K$
z0Y+;6N^@T>sf}qQHR{(s&Kl<+y%DFoWQ%*m{`4OmKM(`i8T}tVTPJObFlpc871@Se7>2?P
zIT17V*R7o><&aT0l!iALRi>A=6@c;!9Xn%qt01Ts57Q7CQ_jAXX~c=y{VWL}ru5Wg
z-4dOADwaB_lGlnUO?^g*CgFS#&}`yTH}dZXM_YPKfZl{te_kx0tUN)KMActkEY}MBrbq#Im^E3f#Bmh
zH2D?~sS4y>8_pSTqViTCMR8-h=A2q+Sjjg=>?=&cNA-g80669>9dVMZOOa!V00GR0
zXh}HNF**xx#q1>S~oC8Qt4
zg-MDDT0jO;L1}^dkOEGBS5(;K0ncz>1*;YQn@HF0uhCuYorQ;b_FhO%?Q_6)>Ys=_
z(^nFkvp>N*u&%c7w4j1ck3O|~S$h$`Hj!?l1LO?eQw6_E@o%m6ue9$$&ERJn@dn-f
z$MVlE>s(NdDS^cAsWqb>0W-G55=!A9Y~jB6IxR=79nSJNW~A7$q?k(?c4vH$sr&>n
zJl0>IhcoxwZTWQaAr>?k<%Fz!Ph3EMcr|Q|RNWRJ&-jCTU(VYoMV1lM
zNNz@DX{01~Fi^R;~+;TKy2?5@->#<+7v=?gGst@
z>)V4JCZ@DfYEek#Aj+HF&w7dX%gWtzdCitRv+VSr~|lZrSAwNNZt&5G-tv-)gMBL-0jZWO~$#F_14%k
zHl5n~?Qbuk1(jLE9p1Q8U}nR(jQPC#H=H+TH3OJQIIjSywqVMomB#aqGR0-^2uQ;H
zm`)kKR1nb28C+f>O#MMDuX0Legh%lOvn=OF6wxz7<>i{cC&E%O`pWiRj5YBBMyHC2
zrH)2N5%$Uy&maAD=d}FDVmN4^eu48Mf5430Z9ZM;bpwK=geuQs=G09j4zlBAv<`7j
zqSPgKUU9`qJbf&6mm#+E-SzUVxxV)DS}eNeeuYyVaAUti(o3`;%J|TOl0?MktOjSW
zuidNOld%#{*Q3@IHT~pup`bcG3GP7U0U$Bo8-LEqO{N2U$Jssry4npW9uL249gftk
zT-LaBw5<1go>MN62@QeFVfk+Xns7DJrmL3Z2y+nfAuCmhjYllf0(68@ncPtU1CSJX
z=&Do_dKdA;C8r?LA5bkSIDbSPh7`0^}}BUA>r!vQ$P`%8M?%<0VRnf()-E>!q6QqZe{<2EqKlDg8ffpjHu~8xp828yp5_|ajjks>mAwOkmZV`a2bKT~s
zACbcu73c_3k_%M`m$J~C6+W0s^mcvl%na1&m&UwSvO*ctnt4>>E)77T0ekU*1uFd=
zRP=|cQ$bxB7D9X>ucCDkq%BntV~AqbnIO8AA$gpLe&_ksTCUBVIqcizyz7Ek^e#PX
zu3?>vEjvR@PM|W}AqyxCQh1a^Qhm(R$v?P%7ooZ*|TVlr#6u!OcWWs(j
z#->myQer(6q1OP9FgXt>3k1ObY(!wai^z?ax4@A^T~
zR;U=sUIpX;RvrHbfTsAv-`DbW3t4yYWNjJDCBP9TixE;`GkoU&?F+G;3EphW=u?D*
zNs>4>;lTfGKVd(;Gh>fZr}(b^b|$1Dr7-YHX);A(Y+E=J
z>49YbsphG#@gsd2(ug?pZ@D}Viq~>`^&<^wg%Uj>ZSdy8U?edw&-ppu!t;etz>YY5
zy_XVCAb-xsb-b8K58}q2H=Xi?SPLvw2vvHB&f(VP*G-6i8NmB}O)t!(e=lFJSiReQ
z6XvxISJtZ?<(Nly;U3>EyR@$a3Fm+`7UF}~is;f^9%f}ojhgQv$y<3ly_RFa{vqJ_
zeV-#JyxJg&gA^e-*{Cv`I%N>bUSp-s&2wOof(hO=1<*2<(=t{{66yn
zvzjsjVjbKTE9A93&v+ce{-o8c27cK3vX`~*;W%Osx#agZLg!jP%Ezpams>|R?l0Gm
ziOGa>$fXq$V$20dI2AN;*+A&|I(;R4G^w4Sp60FK*EFMNXu|smI5{5Ke*7aF)>IP0
zTpdif|L!|FioyzkyIW$+SZ4V-4o1DTEBEy41}~d7HDuSs@;;w3SDK$0oYAa(Y~=-L
z-Vs8v>>j(_RYJ%y+fbi)Jm>g=zkYOn#Crw-HTnR2eNYi)
z1f`q%dVIkBZ#G?0=FbT1mo7M^9kCgk@FiLDW;73-@;}vNLwg~VP}sBb*|x7ASG%-G
zCLj^01|`qac_XyY@Ji0semMVXU!6(eZ|YNdOqk9ie^PccA3-@K?eR=1=hUw?S5S27
z;EodVPSK1)u|ph+LWp!`Dan1T6m&=);+(_kMRs$2W<2;q7sZ?p4Q6R_(o5*5SFiUn
zTTZ5BMhmw9cKM9@#FaPpAlmRiJM#{m>4OaVMW7rPgPBZL?a@hb=Oo|ouJQ{2VRZdS
z((aCSNw~Vs)zx2?k#xIs6oj@y-2mu;aR?Phz4nc0emwncj`z`0M&yY4AV|
zOhLG7N|iOPR|3`Y7e2VT?4R#A85Fdxb_J2s!=umCOF$C!=PVh`FHI(sOm$laRf>^cisos{{00c+vvU3Mp>SNx_2gicvmW!f;5(e0&O*YbOgy{
z4(FB2!58UMvDu>4d?S^Q_)q&S*;OLELCTj(D~;v{_~BbU4~Col{Jy@vK>6f=j-oH{
z8#u#Ibf_5k$dznq_JAP0PW#MhP%cV*KVwZK`qf0>A)-`5w0?j^693)ZUvAh?XS?B&
zW6h@>%9J;6ivNYEH=(%g`RY9QkKk$*C{LU(y7yUPtA+m#X+{Jl
zArxT@VEjV8ViR$zPKM@b%~NvH#lDA_G}RBFF7Pf6DpSUt-c{#hVCh4RRN9BYc8K<<
z5pzlqwZ;b2_TpJfdZ30Uh`nig6CrCFvCa@D5Y4XFa_!6_(3)$dAM?IRj?Wp$nz*~=
zWj1dO7!?BH0X)~$X5Vft8picp>!UBP&iS&^^eY`TtAUTUUqmGQh`z}5V&*$LeulFK?^gx9+kSI4nw_sAI-y(Vmc`j8Y56ZfcDffM;}gmJHym@H6$__mfwG{k
z^tF8_KqEUVLV$bcDyKWu_?evJn)AeKjhRPD#A&LNrhJ{3a@=kUQdwPN*v(y57dDIWdA5Jt_`;qDtRI83P2KhVyHtVe9zvO((bx){|oKP)ZikS@uR4D
zMV|F6YXdPA#3JTKG9RjiPX);8bl4X-12I$xB-^pKmXxu0zb+VL$KXP}28{1;Mx>M-
zQc(gxgZUkTiBTF->ZdbDS-b#Eu_fxm7b=@6XG9)ATVmSm+jL2h*e#9utC!Tzq|_l=
z@blH6G4`xazrpIF_ysQ|*K?C}0ze9QEmqHtg~N~#&W6mpRl|D~Pcij%I&|5vWNf+dqRw*l@q$exC6BINkUqCo(rmMoN{DsMF?IHlSMY2EtQ!l
zh*qxDD>z3fIc=CC3{7TPLHJg)h3qUt{Tapi!{=5O11KtXi8od<@X<#Rl*Lm~JF9C#;poIr+?HsY9DxPjUppv4y{w
zMlRj=qekIC;SGNEAaMoS16Bg3(`3lfennLU+gV-vRD0$-UHAsi68%JxXRHUPH1KlUdW>h4G#^tBR~~r*DXcwsP~ZowO$?IG*i-c&8)J=#3;C|WrloJ$*{-tJiq
zHZwG#^Vkh6c%9@B;Q{(n=Sn+
z4NQFozl5sZ@*oQO6DDNk$kNEPfw6Z4p|kd(CF)O?ieTd>F%&$ND*WJ^4M6xRX#P0)
z?Fwqm8o)7gj3|7GuhTtT(|g^XkX%4uO}IyoMy*vrN@yZ~n4J5OCf$y(3<%tbW#?Bej|a$7$n
z3IhgzvJ#0VqXy-B6_kwhf%5j4rIm{>04eD2akf15F32~Hy_PDa%r5yI9?Zn*zFHXX
zY4+Oc*Bgn|Gns31tou8?aZp|ay=cwJ`0Wv=ge`cV0MJ|&2qQ~Mb9S?uKs4#Ln9pUX
zg^q=ofF1!cEQBQ;02`8);ZYj}5W)s|U*pl?zF)NGASCZPNA5p6k!~dW;fh?E%G`Uk
zW!7iI8TlUoLVBFR86Cx^!^h!GAO6vIQ|b^B!$nAZiFl}FY=)|xQlK!Bj7O0@%B#*V
zs_WF4N7~;YFMS%d47nTinHxU?dx6K0e3GM{Zk9^F3>^hX{nBKvC?y-}7|DkS2JYhT
z0D)a%05D#PmAp}teEKD+YHzNzl2!pntH}(qTTrCO#B<6CxqZ;XKq$!1p6h=&P+%b9
zwekI`&l8&~gg%__Zn$>BN0!jaSB;=J(49&WzJfvvK(26W^7JVR*=8CRK`Rws+#Gkn
zNfOSrUzPUpm5w6=EB`!%xEMxxA0(|8*G{u))GlO7BJ~yF3@qDn&KY(0zeu?d2!!3r
z+f@!j4T(xDFYZtu;v{+Y9|3VefV?X~)b=%_pvk-V^KzQZn>sGpcb~lClK;Kvcd*u8
z1)SD-$w_Vo{IF|qu6ulu(AJ@r_$?A{t#8?LjoF?F8@b@>(#={vRbww!QTQ+nb3U<2XJe&Y`
zuoZW!|N4ckE$m@KMTk7
zmug!)pv~}E93_=Z%sSA@L(qZK_~seYCArBF;eq#RY!F+L@vzW_nm^CONMSZlIh^woceT2dex%Fq`=iRgTw1WFT3
z*PUznH$rSQvZo1XXjyd~nxIqet6T~^kFrd*5&ezEK5%Utd2U+xG_Y?{&T5I-fQ27bExn3QEXX6!*?&_r9
zr4da-*4G1MHo_@+TSxd6Kd-67te>}YgX_R?id+9U{Qzf);^L4b0(bR~50%Er|4=Ta
zYSD4Du772xKbUYbuuM?+{(Mz;N-S=tYsWhGIu&dA!LWVt(`{^wGzq8OyOKC!TUF=G
z%Of&8_cFbv_;m7i36kM@44*v{O5)-
z5I|syiP=Ge1qL5Gpks~JcsAJ{kJ}oku)V85obe_u%%U7b$(2HU^L>{+BYNIDaln@<
zZAkV&;x>UVA|hb0*D9_i`Q$R&-72*^K?stlgz8o3&
zMryZb_6F#mJ)AM$9!L#@>OH^^
zoG}lYQ2wi}G*qRfRM1GpeGqKzl2%kMLXNY;Zlj6{%k1+_mU!yDRb;s9l2r*Zt>f>6I$cEI`ql!9`u5qD
zRA(Kiar(@7LD|{IKfKOx6Hkl?DZX?>a~HyGk=j2^kNw~%x`MP;=DP#eHc#kPQJmD|
zgM5p8>$bg@8KC1|oT0Dpfu?8OO($Z;2XWafkyZ6bue02J0&RK>5N)4HGS0Jn&)@!e
zbGhbYvMUxnXb1WEUVD9-y)ZNZ;d?v?x9x$xZyy>+#R1*@jmqKl-Tg
z%fh*!l(5TsVwWpH{1FFHi-3{Bld&0kIG8Rky6=M$KA?ID1Z=o$hUPMb8%uh5+8uWfAmy^c&>&x<
zVBrJ-@FD%6x
z63>9l5CmczdIUnR{|t^c5i~1oNFDC}-3B&jUyc{rw`8b5UPx#9Ej?8x^@Rz7s@m7{
zTq9lULHvc4MvAp!(3sLHt9f26punWDE&|l(5$t_?NRyA>tyWpaaVP|>87zOJ3jM9^
z2SCF6^d``UOK{oO$bE?XU{71*)vy$;h|)$N@a>8^CgMdC9&`iyTs({$w!AR}(r}=l
z?QuHiJpGLYn3!;Cc8Oomsw|gEEn+*8f!p%hoHa-K;*sJLWWjIRX~4+uT$^X;zA*?p
zI0W>n4~azURoj(K@I3SRZr0!5PT_HUv(Vdl+Ef>&AY=0a+Y8OqPTK)x!1?0HV^U9h
z+M>Gzs()Jme%P2&hc?ljzNU*e31EvkHM{$Sq%w3XlthM>SD(bx>V
z!#AP*@IMyZl+*4FX$I2d$02kN1c@9X;Vd;CcBZlWP?@fPuI3R?7fH@?+;9oK>4U7|
zej0_#5{o|cSo?r#p-BP6xWmwyu>7W&rF*3rl4e9i=`@%K7)1bhi>imC^BYXs*3h7h
z#)c|x5N)rFJ0Tcz>35h2|t0OAcn6jBEI|cHk7H!_Dk0GfofTF)iR`DKLiud|+re!>k+J2dvp*7y~vsrhlEV~QH9%e750rUBg!R}|yq}IZ_?UAEs(RP_^SNv7n3ba3&
zn+9cal;6!(hf0GxXgE?*{%vi5+G#lO0Ib*+m?#9&AN9Od&iH5kRDj%4{a+~mobgKA7
Uf=cA*FtTe(^6IyX,
- val authors: List,
- val genres: List,
- val chapters: List? = null,
- val title: String,
- val series_id: String,
- val description: String,
- val status: String,
- val cover_art: CatSeriesCover,
- val all_covers: List? = null
-) {
- fun toSManga() = this.let { series ->
- SManga.create().apply {
- url = "/series/${series.series_id}"
- title = series.title
- thumbnail_url = series.cover_art.source
- author = series.authors.joinToString(", ")
- description = series.description
- genre = series.genres.joinToString(", ")
- status = when (series.status) {
- "ongoing" -> SManga.ONGOING
- "completed" -> SManga.COMPLETED
- else -> SManga.UNKNOWN
- }
-
- if (alt_titles.isNotEmpty()) {
- description += "\n\nAlternative titles:\n"
- alt_titles.forEach {
- description += "• $it\n"
- }
- }
- }
- }
-}
-
-@Serializable
-data class CatSeriesChapter(
- val title: String? = null,
- val groups: List,
- val number: Float,
- val display_number: String? = null,
- val volume: Int? = null
-)
-
-@Serializable
-data class CatSeriesCover(
- val source: String,
- val width: Int,
- val height: Int
-)
diff --git a/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatManga.kt b/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatManga.kt
deleted file mode 100644
index abae4e7c4..000000000
--- a/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatManga.kt
+++ /dev/null
@@ -1,179 +0,0 @@
-package eu.kanade.tachiyomi.extension.en.catmanga
-
-import android.app.Application
-import eu.kanade.tachiyomi.network.GET
-import eu.kanade.tachiyomi.network.asObservableSuccess
-import eu.kanade.tachiyomi.source.model.FilterList
-import eu.kanade.tachiyomi.source.model.MangasPage
-import eu.kanade.tachiyomi.source.model.Page
-import eu.kanade.tachiyomi.source.model.SChapter
-import eu.kanade.tachiyomi.source.model.SManga
-import eu.kanade.tachiyomi.source.online.HttpSource
-import eu.kanade.tachiyomi.util.asJsoup
-import kotlinx.serialization.ExperimentalSerializationApi
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.boolean
-import kotlinx.serialization.json.decodeFromJsonElement
-import kotlinx.serialization.json.jsonObject
-import kotlinx.serialization.json.jsonPrimitive
-import okhttp3.Request
-import okhttp3.Response
-import org.jsoup.nodes.Document
-import rx.Observable
-import uy.kohesive.injekt.injectLazy
-
-@ExperimentalSerializationApi
-class CatManga : HttpSource() {
-
- private val application: Application by injectLazy()
-
- override val name = "CatManga"
- override val baseUrl = "https://catmanga.org"
- override val supportsLatest = false
- override val lang = "en"
- private val json: Json by injectLazy()
-
- private val allSeriesRequest = GET("$baseUrl/api/series/allSeries")
-
- override fun popularMangaRequest(page: Int) = allSeriesRequest
-
- override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = allSeriesRequest
-
- override fun chapterListRequest(manga: SManga): Request {
- val seriesId = manga.url.substringAfter("/series/")
- return GET("$baseUrl/api/series/$seriesId")
- }
-
- override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable {
- return client.newCall(searchMangaRequest(page, query, filters))
- .asObservableSuccess()
- .map { response ->
- val manga = json.decodeFromString>(response.body!!.string())
- .filter {
- if (query.startsWith(SERIES_ID_SEARCH_PREFIX)) {
- return@filter it.series_id.contains(query.removePrefix(SERIES_ID_SEARCH_PREFIX), true)
- }
- sequence { yieldAll(it.alt_titles); yield(it.title) }
- .any { title -> title.contains(query, true) }
- }
- .map { it.toSManga() }
- .toList()
- MangasPage(manga, false)
- }
- }
-
- override fun fetchMangaDetails(manga: SManga): Observable {
- val seriesId = manga.url.substringAfter("/series/")
- return client.newCall(allSeriesRequest)
- .asObservableSuccess()
- .map { response ->
- json.decodeFromString>(response.body!!.string())
- .find { it.series_id == seriesId }
- ?.toSManga() ?: manga
- }
- }
-
- override fun chapterListParse(response: Response): List {
- val series = json.decodeFromString(response.body!!.string())
- val seriesPrefs = application.getSharedPreferences("source_${id}_time_found:${series.series_id}", 0)
- val seriesPrefsEditor = seriesPrefs.edit()
- val chapters = series.chapters!!
- .asReversed()
- .map { chapter ->
- val title = chapter.title ?: ""
- val groups = chapter.groups.joinToString(", ")
- val numberUrl = chapter.number.chapterNumberToUrlPath()
- val displayNumber = chapter.display_number ?: numberUrl
- SChapter.create().apply {
- url = "/series/${series.series_id}/$numberUrl"
- chapter_number = chapter.number
- scanlator = groups
-
- name = if (chapter.volume != null) {
- "Vol.${chapter.volume} "
- } else {
- ""
- }
- name += "Ch.$displayNumber"
- if (title.isNotBlank()) {
- name += " - $title"
- }
-
- // Save current time when a chapter is found for the first time, and reuse it on future
- // checks to prevent manga entry without any new chapter bumped to the top of
- // "Latest chapter" list when the library is updated.
- val currentTimeMillis = System.currentTimeMillis()
- if (!seriesPrefs.contains(numberUrl)) {
- seriesPrefsEditor.putLong(numberUrl, currentTimeMillis)
- }
- date_upload = seriesPrefs.getLong(numberUrl, currentTimeMillis)
- }
- }
- seriesPrefsEditor.apply()
- return chapters
- }
-
- override fun popularMangaParse(response: Response): MangasPage {
- val mangas = json.decodeFromString>(response.body!!.string()).map { it.toSManga() }
- return MangasPage(mangas, false)
- }
-
- override fun fetchPageList(chapter: SChapter): Observable> {
- return client.newCall(pageListRequest(chapter))
- .asObservableSuccess()
- .map {
- val doc = it.asJsoup().getDataJsonObject()
- val pages = if (doc["isFallback"]!!.jsonPrimitive.boolean) {
- val buildId = doc["buildId"]!!.jsonPrimitive.content
- val directRequest = GET("$baseUrl/_next/data/$buildId/${chapter.url}.json")
- val directResponse = client.newCall(directRequest).execute()
- json.parseToJsonElement(directResponse.body!!.string())
- } else {
- doc["props"]!!
- }.jsonObject["pageProps"]!!.jsonObject["pages"]!!
- json.decodeFromJsonElement>(pages)
- .mapIndexed { index, s -> Page(index, "", s) }
- }
- }
-
- /**
- * Returns json object of site data
- */
- private fun Document.getDataJsonObject() = json.parseToJsonElement(getElementById("__NEXT_DATA__").html()).jsonObject
-
- /**
- * Returns string without decimal when it is not relevant
- */
- private fun Float.chapterNumberToUrlPath(): String {
- return if (toInt().toFloat() == this) toInt().toString() else toString()
- }
-
- override fun pageListParse(response: Response): List {
- throw UnsupportedOperationException("Not used.")
- }
-
- override fun latestUpdatesRequest(page: Int): Request {
- throw UnsupportedOperationException("Not used.")
- }
-
- override fun latestUpdatesParse(response: Response): MangasPage {
- throw UnsupportedOperationException("Not used.")
- }
-
- override fun mangaDetailsParse(response: Response): SManga {
- throw UnsupportedOperationException("Not used.")
- }
-
- override fun searchMangaParse(response: Response): MangasPage {
- throw UnsupportedOperationException("Not used.")
- }
-
- override fun imageUrlParse(response: Response): String {
- throw UnsupportedOperationException("Not used.")
- }
-
- companion object {
- const val SERIES_ID_SEARCH_PREFIX = "series_id:"
- }
-}
diff --git a/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatMangaUrlActivity.kt b/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatMangaUrlActivity.kt
deleted file mode 100644
index fc2a09fe1..000000000
--- a/src/en/catmanga/src/eu/kanade/tachiyomi/extension/en/catmanga/CatMangaUrlActivity.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package eu.kanade.tachiyomi.extension.en.catmanga
-
-import android.app.Activity
-import android.content.ActivityNotFoundException
-import android.content.Intent
-import android.os.Bundle
-import android.util.Log
-import kotlin.system.exitProcess
-
-/**
- * Springboard that accepts https://catmanga.org/series/xxxxxx intents and redirects them to
- * the main Tachiyomi process.
- */
-class CatMangaUrlActivity : Activity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- val pathSegments = intent?.data?.pathSegments
- if (pathSegments != null && pathSegments.size > 1) {
- val id = pathSegments[1]
- val mainIntent = Intent().apply {
- action = "eu.kanade.tachiyomi.SEARCH"
- putExtra("query", "${CatManga.SERIES_ID_SEARCH_PREFIX}$id")
- putExtra("filter", packageName)
- }
-
- try {
- startActivity(mainIntent)
- } catch (e: ActivityNotFoundException) {
- Log.e("CatMangaUrlActivity", e.toString())
- }
- } else {
- Log.e("CatMangaUrlActivity", "could not parse uri from intent $intent")
- }
-
- finish()
- exitProcess(0)
- }
-}