u$VguD~Y^!1-0W@dX7~pj?&Gqs|exY^>G&ezMeZVcu zb#hHZCCg=-4OO34)rd4rf2o*HE-UGIA!xu}>T)(PY+8h~n_ZIHzS3(RkI^dX1!Ok!ZvT(eZnw@n!HWI$2k|cwqcZ?gl)kIJOS8Mp zMh65R*Wt?}LV-CH8N*uY^Jb0-jhO#}M4QaVLQL#RV~AIzFnZ}R)6j|9_X4`bftKYO zF1jeE$!3@4VcXDnD?2fu-@>p0!P{Xt|H|dvaN;vT8Rv;UvUmfFB|!7;K{5&0s~EjZ zLYk5jNJC)2l{mX$M2z#MAvhzI*ETS#FjD7{G8j`gG|Vz1K;B)^jh>mddDM0mRg;P%f8;`rD+XxdNb7@m61; z__6GrV~MJGt4D7lDV5wgferHx=}uUCmWBT2u24eB6J4O+tf4kvU@Od(jXIWL4hq3N zOrXzR>$PO@iH}VDAxi3U>G(|_#3Sr^MBB6OP1c4^PLnvb>F&vJUnaZb0oboy;;-=E znAs;=^5~H$==#XM#=eHQoJ0F|E(H>myf$Jl8`d7lU)^Z|^c2NP1+KC7`vjihg6kuY z<0| s-?nn-?jKdG7XG?=yKOy2ne}3v1upY&r R=xeq+#i zkb%HZkZ)Thu6z>AsbY444292C&|u2&n+^I@;&e#cx8Szm*5rbSMQlMST1cfl ^<%=Uu*T+4JSN z=!CUw@dn!{4_V o0hwq)u2yI& 4ZP!($)s+)i1=l}>N8us(R3e(Wm$CC{ou)mE!Ug! zFoG`1cprJ-$Z 4%e~n-4%w>z-zfy2JDT1G+*ZMgRZ+ diff --git a/src/pt/tsukimangas/res/mipmap-xxxhdpi/ic_launcher.png b/src/pt/tsukimangas/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 82085d6546b5e3106b72638d960e6d6c39cffcad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9164 zcmb_?WmJ^k7w(y%J48A~q`P~7A0g79NOww02oeJ-prkl-4I(KaA>CclAf@Ec9ZGY@ z|NVMD-VgK6TJKr!S JG&!7KAUGrVtR%41n;&1=o^@uW()l@D>>!avqstE`0YvV<8U>zLWNxbP!+9$0hU zI&yxFtOE}sarrh6!eF7a1ku!ANWZ`+b;*-3@l=$CE{_wMu1_+X>QklvW=zP=H*aLT z&flIk$!~PXFKA88%0k7G`V@ YMz@YxjoRW7(n1Nl10Q~kzfbx;0nRF;7vny;-nD8~xAIj{ z(~ibi-2A45Rbv1Sr9_)s;sCPfs*UnEhSTRP_G{ie9^=L=h){Fp!XwRKsEOJ`I5%}-8jFiyxweAI_QEMYkw zE4}|p!`=O0j8!FiMnBj$>5i$_bt;MX0s|r~->F=1ezN`eNbf=!p*bbVpS|*QFVXwO z7X}_WTH1iXll339GI!S};&O*=7~HlkPz74*x<^Xm@37%+*YC$xUydr^XwC;;?TsY1 zGPMSrZI69@R!aWn%^T~9d`(3$nWBfPRuq~;*C~}n=Es87pHE`xCH49sx~G5tMjfs8 zM&aFi RzS!jhh}TL^oxvMB4rQ+K9J=_BHiCjTZcG17bNS`^ZI)e};W{Z=yle!oY( zg+hX{ecmfVn17tVj+5Fhtir~|=6l}Y?X-`p%_;mgRM)O+sKB<@J7fTx@u|fSAsYKV zo1SRN7wutKhD2`wz{L;K0r0OFM$T&oiL7^mJJY3&`}G^gRQmL*xC%=Bhy8z-&uDIn zLUZ!WsinU&@?%K&&e|oj;DxR3w_NRCRQ^d9VMdCY+&IKhKtX)Ybr3-M{n?#;{Ul`n zmhDMW{L|d%i0w75wca!c$FC#^82yp;dcWSdjP7n@OqD6<83rWUqLe^Qdhh`*1pa6> z87n4D-2L}i6eX`zTJilU1^U(XQ61DjE3P&p6Bq{DI5Q*4s1|aX|Ng$3dq+T(#X0!f z5e{2aLQc*m91wt@(}Q PhB{aD6Vg)4Q{pH&7SetcYhVDVRkBbbRnx6%fJ zyob_C6T$n~NfSlIZ=N68_L}k#3odyX_m2-FW;HG}idm`e^_Y7F=CMeN%UUkv0zTL+ zA>4xIb~~kgwkL)68xLA`!XfZf7|BQDxLeCZ2>iqK!(e%pkP8}Fhv5tp!; OQQ1O6!o{d|r3i<}5XsmJ41 5D_jCte@(X-f9qJy>SJY?SBQ@_O2y{CaSK@9qSa;LM~_! zO!x15nG;3;n9XVO{q1bYm+Px^;%@XdzI=JqbgKm__*!xikIIK(xAr5sH2wg2iu!cW z`DE*ds#y2@&!4sG`<#2?G8lzMuthp#4 =f^x>MkJgIm+Z|P&s8y(kwM9%YGWlbOCc7V&;$xf5JX?x8=j}JUT0X&!v z=)~}SKGIid>vw=ynmnv|pD}JUbp4=j8o+4)Q@L6^2^b !IMUDT>n{ML6Mco3iFv!@5V&5+pj!T`x=Kzdu52MjE%e9qGzPLZ7fUTZ zCq=bJzD@upDmBPl7s#?DQOQBel??^m7HiijKJx){w&^b{UV*+Sf)bASuY;X5F)sGF z#U~OdPg?{rn9IX14wAd5X-dQdd6;enYVt?@A7{1FWPr{Y@?`9I_Z9XJrp@L&gi1JH zBibB_F45cP-Uc^?fzE3rf}J`(k*SMrv+uClZ0iY{Oc~!THNX%n){SZz$4X=8(YF;4 z#qSlLE}ZPBC_!azLZ&4?Kq#8!Dmq&vu*&DKbX2%VX0XUbgmV=PT?lTQLxDze)RK30 zf?nj;qX_d;FBLOB&C{_EwQVT}=}+VJ+ASpfsv(J~5Dw*w@c$$S2#Lslip`chEfgxw z$eyYp9|H3o$YQddH@06UU_K=~mvB~b3Zkh#Qk0I+hl~T`+71lM^5#EYb2#5LCgJo9={ z{52tr8QQ0O&1Aop2i8YD9lc^gBn*`MkAD1RxCy!l+R5&<&;TyY6z)VoT~{twuHc?c zo$A@ R-AEL&Ty+r$~o&J)25E&k}DkJ&cQ>1ov? zo{qRf+juUxy597ECGD;!ORB*}O0gl9UlJDHb0euWM`RTSYDprZeb+WzJM>Y>&e%v= zrI@suYq3*$V`8EyY`!H4J6(~Mi%jg%=}U)BjElRAk&x3TN8OF&oUK1PUogQZ@RUvH z^_gcX+3xCu3Vt9wBjObjb>ChOV8Hb%cdW%j9=Zid&($y*F)#Jup|=X;@gNjA0EJH| zct*EQd7EvM-vb$!IwDW|`B{KaOH$B`bz$t0AWzxd9=XEj1;*h>+7IF5EQupUIBdCQ z7i^fYh9Vt&0;}_kSl-5?mvd@cbK>&845ycgi~v!2qVmkdoGyUQ*!gs0;PYnTHEB4N zBKFgf_=`L=JK;LmD5 Vg75v!_QRBeXp6?rVd>%3Wt}eoAydNIjhV>+)yGoq8v0iClL7F+Fy*4 z`9I43-BS3=1VG)YNQG0Jq}HY8HMK-z#&u!h!AizN3#rH++Bsybt(C$cuSAPCR T hi^*=3a)*} z-f|Q$2vrVnumK5t0w<4}k2G4dd~Vu(G-0_)%BwGb|IVlX2?tMA%!4`6xnOj9$rM$8 ztb4XPfEq=OKbO%RhNSxi*|NkdboUo}1s)TSz-9l;u=dG;0wpt5=7BaPo~9x#;;p|g zeUzu(4{RXNWx 9SgnCQ31swXcW6$g(F)M>13JQabHP3 z#14==Wh$m$44kY&rwK#{O_5R`uHaXX9kPU2)+lteB!N=|A)>;%`-Al&-g*f{C6@ki z&*vbb5XZ>NhW%2uXlg;lXhvD%)3dYpy16QBA#eOVJak+Z>I5(PKXwa(zGvR&W_cnP zh$a!E8ZQF|outcOPqF6`3fQY;1FohH(#2POKJ6L=03<}9hCgtbfc|RuOHTA^{YKV3 zDvLl*HyVLIhAqd5E4=RhQ7HmeVbtPo8Pw9gB|yUJ{Ke0*`{=UhN$~9|(;aE+)vtpt zeQjAbG1s}t2Zl7Gjla+MDmsa!BL!`GBKK T zr+$89Zk${Li&DSde*@= p_`Ka=<)Z!BD zplyBYA8DdRH~E)M-okLFlFhf-H@gnz0GW~ _ zqxSQIh8@16+SVJ*>p!)vn&9&sj?#I*c5ni`@6pYcb_jX))xriXPkim&?NwBHAc|Ye zntZNmM6S`Q>1w~R{QUA~s~hj?^~nfT;V1RtAT+)!ERdDB_F8r&^B~Y6A*Ow;ht9p4 zk1nXv3pL<{VL4arRBtt^1qH0j$t|aBEKCQL`}CPso#8|)llt2CM`TVkRu@?SGMX0? z*bk+!v>e5_Kd%)g0@4RfRp;nxAv^j{CV 1VkHDXL5A0d z^9}jC*}jg`+aK=1`h9 tv0v6p8H<2KifMSacb9TOD{k@6|2_Uzz6Wdo8~%H~y|3 zcsY@+wIJH}@r9u0@;j E1XAl`fW7 ei9{r%>@<`v#s _rp&cel~0MNmH)GxCh$kvCGO{A9k*wJ10`V-~JAtc93+0u+wnyCWWCaS(B#A zsdBfKUMN!;{&r{p 8iBx}v<4Q|gFo}`RN8VEw$|s4Pv)SMFG7E|-kw3>!SnOK zrzcf8HmF+9m7&k8AwG|v ;g4FalKbL6G~l zV;(`n*|dqtnz=_i)(X1*b}Lf-&GBBDeLL=5VOH>YC)0
$7ouPk*Yg+Zo9BziE;D7 QZgOB2NVG~HiCBfJRsxcu;dDQ>AxnB zU7+Wo{rC+z&MFegpY1*VSW||&8G`R$^RP < zQt@=@T^Ly~RcWeR3*P+30S#m*2zWuwr9f$lu9*vuzkT%UXG_Mt7z+CIye@H_IpLWb zEw!ryTn0vk&K$G=sc~Kv`J|xx%g4KlxF8Lg+w)b;DsnpmF8T5*Q;6lj5ER(63F9N| z5T<}x=nZaMDydVI(fRhZD5#tMGS;5m`#?k6!=%y_*+fRKFPXpp%Xgml`y&B~u3QN8 zzo>5tiHWB>;fNhFEHEea5d%E!l>tj?ION#4Z=Y3!=CQwZl|M-xiN~R?I<>+8>IG)P z7 0G~M8=6G8#p=pBY&_Ce-v{H+Mkj !Rh4edS2xuRX@=&|RyM=d_UnTP^Z<0fG+}VmF}7+UB%?^hOd*6gq++ zLVSs2J4Tua)7@$e+<=wIY$!bDiBTi0(@Mt#cu1-H@YrK5JnD=oHuIfjyH6+~6LBK& zoOy>e?{NkWaLa^6=p!ZYL#u8AI(}mh!#qvVG-);kptkN*?I*gA{S+f`vME}Yn&ms^ z6f=>Yamk(5M1#bJeR!|n`5bc<_gmJa9H0UjS_8+66>2?3f#=ujg64hQP%0|R<7j>Y zQ1`6=aq+Fd_1Ch7Vw5GV%FZIX)h_7{oU^JEL34lM&H3EVmgz~iYbIev@CFIb8qX4* z_Q}QqbqSN6j{4e(KA{>mXApSYvbax)Hy$ZfuP2^x`=N(ES2;T9ZH`nt&tY?|d{ol2 z633SNR)L3am^AqEJQ9e&H_ymM3<-O;N8l)&&W$ yZ8gdCUx(mRjewO&7&jr1p_=Ybx0gSz6 zOVfS8$Kv#Nx0#9Q%gK9Xm@9!A=87$N^rp>S6=5ZaX-Xag&r1Uw5c|?bpCreKIE4dz zNsQ|DFs2jSvCKsH#t3R^af2F0j-n=l|7h&Zdp$v0qB|6zI!gW5KC1Q=(PPfwO<5$s z>TwmUZFu-ux-QqnTkGFr5;#(q1)G|Xeff^_f{gx^uoALRdM@6Fvlo$y1AHhsN_n?E zGKl3S@9j{_Y*;6aV6;sqaNz+-GaO0cOe~<$x}f}RdsGB088fLIHNAC!eR~ Qe;9_inK$No^hihMgNN~9INdz+{UIIpl_o&}gC9kJrS)0Nw+;H7pm#~nj#;R6H4 zI6TwWd*5RSRErhrXd-Oba6hj9=n(~8z5VMN3p?)?qa~UGoHTST*Sa5&7l>5g=H`cV zN9=r5W%Rcl |RHn+J_vYXcE#K?~I{RnlVHR?io4GCooPiX5KG<;i$XcF? ztxo?wyzt1KXz^d(`o}JhjrDqPsroR1$to?&8q00=*^2QTM B1zxZeiXi6KHiZKitclT#!M0IAge73ZSjVF-vV zjRfK5_!E9tJkB{Nl;l-AZ|?7rx28i#=iK3Z`V!YkD_QC<{_^mIca0Qv!5>2V#g>;V zOKLcc5+QJ>FDxJ)6|s^*Vh=KI*JP#~eCf^Q-|S%dy}Ng&w)0A+>uTSxRa%haERf(Q z3`n>%S=nOY9@|SNZV-S?a;ivY@Z~Rg(k1Tt%AUK-ZDc{`q1$2#4^-(aJA|^ItW1 z+H7efQ4alW*1LB6uZ=2kz@53Q4KbBMkORb&`+W74Af)2YPI;^O5}x9`-$_-pfvj+B z0sd4K3cU3aM6xf8DqftU2^T^pe>oQC6-W4Gi!yocN0bcxFKe-8bVqVe?|iTBvBRft zNo{BPC)5P0*d0Aay=6~CF?4#e@(KSl=8&IQQ<6Lvaqn}qC{4-rp=JO`xfB}9wM##Y z&5`Va#2;G*$~N1WNd1HLPVHyGQUf?(%I}_Sb80G^;SE#6WKf7(Hd5wnxPX>gLOAxb zt_5G1nCGBD(_}v5CjJ4mKWana52P}B@L5p~st)1aDf|%fi}ta$JC>mvb%X1Mx5Tl8 zh!}>NlRf-7TE|0(w>fN27ukecSbsysJRV8>g(u~fDhhCk-Wq&~ PULm~gE?F;$gbhI@o@IA>;JwLyB&Zq=RZ*D^G&oGr23S_EiGb3xXLdIUg766 zseGmw 8hK=HyR3$6R>24AV+TQDUF=(SSl7||v=xDiJ zrE(&FhXW79E9JccVhpNIQ>sY><-FQF0d)0Z)rgj$<3>inBHf{y#9hv7@qgdS_54`g zlLB2jE#(?iw=*(g$2MbLgfq$cGGMf2c%o)ZjKP+5-mr|jl^~l)o6OPmvOS_k27GhO z)5I~3)KvQif4Rc}je;p^x<)&2lN$okV?CZeixdh(D>ie-Go!tqUH7xkt&ro8HkG5Y zp0abrL= RiN7u?kZeA^^G|(iVHjA+LsXyr2jVG-%v#UFtMMIq*4HvcudEAZF z_WVL(-&nB6myEuVRk8o?$JPIN+FfbKz0!(}f(mq&D{VkvhJm}0o=@1N_cgAlqX^tx z7^yC-G-tGpIl(9y+mruXX*xP{tP-^8O#NLitS2JIY@c(Y19Tl+TC C%xrSlzzqp$O#I{H&>$`$A7pku9|19d|uK)3{<}_2t#jSn{ z8=n6zg@H=3CXVpmA~FdmgZQSEp@TzsQk~n0<~wWWKQAY>OsKf(2m6EgiDF-0oxaLI z+xo+rsNNoc4t4Hi9tQjg`z4p8cdFd+Kb$UGK|Twdw`h5I0Kw@>^k$oZY#jHW%Nq~t z54{KAL4&0bQvV$Kjucb0*Xj>N4EoNb153r2Lw;hkeeGl|e`30`-m%efZ faZXB+{lmIifBU|F-H?m6o7Xp8#U5~m9D^; zig}nM%bLmp`2x6vv?b9eZS7j#)_p=j|8N}NpN%)$dG-qIR!?X#5WG<=N*Rr)c`HrH zV7=}kYH28ExXOiLK?D~Y=4-*;>^$f+!B$$I6m<2`!$5Xi0Tz3@SgXX;d`Hj*S=T)l zHV(c#LU)+Qo&Szi`N9)yVn5{AHV$~AqH;E%gQo0|Z>=SZ0T(p!*+j=xkAuZJPn0t{ zYxYy@Ov%p=x5mIIdk7P2oFY$rrsR}zVgCeiF7DItIC>^?y%DzxT|Jiw+$;o;u%!k9 zw~7F1mcHCL@$$m@{<&w|7QxAX3`13+ONw}K zZeala7P#`oLjlhhJn-p}W}2YaTHl2i1F6eu|MwF`I%8aa7Tdb*+@ZkH^lSQmGL>=~ zLG@S)q$GW_0UM^^OawOqQA<6FuU5L=C;$EPhtbL`9S{l<^1K})6@r$EeSQZ3M#R6n z0EGqB55(LSUY%@DeH~#G3;qtC0r-fT>~-dxuLUTiK{_!ASarPJ@@lw@xvo}Tu88J- zyFe;5_qhv7Rf+DkLW$_ah8U=+pBKm69^UzY=Z*5t6n?H!Z5W_Xhod8>UkYSb*z_{~ zT3oz)x hF2N3`ch1i4d zOrxOv{Ag7>v22u+#Xf8X`@VWGhvc-FQJGR^$$G!z=lHS_WwhqmEZ2Pw0bO@Tp2pw` z3Oh<4WByJFNH2S0==_EXb#sT4g%$Yy#2k~!-tn-1;Yso_NWpDD IIF1jX+hHC;6uBF?WJ zVwz&E5(BJjh4LKo;*VEbRW5Hv2 z_~eMLm!`nuxx1WkUa9A_cV!8_3D?mq-|xYht8>DWsF3gTC|LF^n d8ft|ra7hPo zj(q=};GW6@`bsDL@f+X!JqB{J0U*3g<@K5Lt$Wsu=ZD+384wCwgu+gaE_I7B^VeC3 z{8WQNCMOpq?wl>e%rsia7z-+zkPdWmn=kQJ4K0tnf)p{pF@pOG92xt#P}c$i%Z4}u zZ+?95RdEPlE*$$!f0no`%^&EK7~v~TfjgN7i#Z+GoLFGO3Zq8unxAm_4p!L%>hEb- zliFwUqQ|eVZUiC7Mx{%Y)P2US)}0 |H5wIGJ@8Vfyc+>Rj_{>^&_*tH#GF^i^AG 6#zP3AUqq(p2HkqmacbGfTCW}Up7~Jy2{h(tU)4Stvm*_6UZtAE=zXf}s zv_M4Qzk?$!z#Ndf4Rt2+K;Kh=e=SNYOQ0=;==8gl(sfV4h(KAsbA!4wy1`{@{O(3! zh`zm2msY&RRTN4K5_hK?bWMpS!IE=v{?{+q&cLA3WJksG|1nY99mes&+_&x%j$!mI P9q?FL>%THZ%dr0gznxd- diff --git a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangas.kt b/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangas.kt deleted file mode 100644 index 85891bfc0..000000000 --- a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangas.kt +++ /dev/null @@ -1,360 +0,0 @@ -package eu.kanade.tachiyomi.extension.pt.tsukimangas - -import android.annotation.SuppressLint -import android.app.Application -import android.os.Handler -import android.os.Looper -import android.webkit.WebView -import android.webkit.WebViewClient -import eu.kanade.tachiyomi.extension.pt.tsukimangas.dto.ChapterListDto -import eu.kanade.tachiyomi.extension.pt.tsukimangas.dto.CompleteMangaDto -import eu.kanade.tachiyomi.extension.pt.tsukimangas.dto.MangaListDto -import eu.kanade.tachiyomi.extension.pt.tsukimangas.dto.PageListDto -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.asObservableSuccess -import eu.kanade.tachiyomi.network.interceptor.rateLimitHost -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.json.Json -import kotlinx.serialization.json.decodeFromStream -import okhttp3.HttpUrl -import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.Interceptor -import okhttp3.Request -import okhttp3.Response -import rx.Observable -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import uy.kohesive.injekt.injectLazy -import java.text.SimpleDateFormat -import java.util.Locale -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit - -class TsukiMangas : HttpSource() { - - override val name = "Tsuki Mangás" - - override val baseUrl = "https://tsuki-mangas.com" - - private val apiUrl = baseUrl + API_PATH - - override val lang = "pt-BR" - - override val supportsLatest = true - - @delegate:SuppressLint("SetJavaScriptEnabled") - private val token: String by lazy { - val latch = CountDownLatch(1) - var token = "" - Handler(Looper.getMainLooper()).post { - val webView = WebView(Injekt.get ()) - with(webView.settings) { - javaScriptEnabled = true - domStorageEnabled = true - databaseEnabled = true - blockNetworkImage = true - } - webView.webViewClient = object : WebViewClient() { - override fun onPageFinished(view: WebView, url: String) { - val script = "javascript:localStorage['token']" - view.evaluateJavascript(script) { - view.apply { - stopLoading() - destroy() - } - if (it.isBlank() || it in listOf("null", "undefined")) { - return@evaluateJavascript - } - token = it.replace("[\"]+".toRegex(), "") - latch.countDown() - } - } - } - webView.loadUrl(baseUrl) - } - latch.await(10, TimeUnit.SECONDS) - - token - } - - override val client by lazy { - network.client.newBuilder() - .addInterceptor(::apiHeadersInterceptor) - .addInterceptor(::imageCdnSwapper) - .rateLimitHost(baseUrl.toHttpUrl(), 2) - .rateLimitHost(MAIN_CDN.toHttpUrl(), 1) - .rateLimitHost(SECONDARY_CDN.toHttpUrl(), 1) - .build() - } - - override fun headersBuilder() = super.headersBuilder() - .add("Referer", "$baseUrl/") - - private val json: Json by injectLazy() - - // ============================== Popular =============================== - override fun popularMangaRequest(page: Int) = GET("$apiUrl/mangas?page=$page&filter=0", headers) - - override fun popularMangaParse(response: Response): MangasPage { - val item = response.parseAs () - val mangas = item.data.map { - SManga.create().apply { - url = "/obra" + it.entryPath - thumbnail_url = baseUrl + it.imagePath - title = it.title - } - } - val hasNextPage = item.page < item.lastPage - return MangasPage(mangas, hasNextPage) - } - - // =============================== Latest =============================== - // Yes, "lastests". High IQ move. - // Also yeah, there's a "?format=0" glued to the page number. Without this, - // the request will blow up with a HTTP 500. - override fun latestUpdatesRequest(page: Int) = GET("$apiUrl/home/lastests?page=$page%3Fformat%3D0", headers) - - override fun latestUpdatesParse(response: Response) = popularMangaParse(response) - - // =============================== Search =============================== - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { - return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler - val id = query.removePrefix(PREFIX_SEARCH) - client.newCall(GET("$apiUrl/mangas/$id", headers)) - .asObservableSuccess() - .map(::searchMangaByIdParse) - } else { - super.fetchSearchManga(page, query, filters) - } - } - - private fun searchMangaByIdParse(response: Response): MangasPage { - val details = mangaDetailsParse(response) - return MangasPage(listOf(details), false) - } - - override fun getFilterList() = TsukiMangasFilters.FILTER_LIST - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val params = TsukiMangasFilters.getSearchParameters(filters) - val url = "$apiUrl/mangas".toHttpUrl().newBuilder() - .addQueryParameter("page", page.toString()) - .addQueryParameter("title", query.trim()) - .addIfNotBlank("filter", params.filter) - .addIfNotBlank("format", params.format) - .addIfNotBlank("status", params.status) - .addIfNotBlank("adult_content", params.adult) - .apply { - params.genres.forEach { addQueryParameter("genres[]", it) } - params.tags.forEach { addQueryParameter("tags[]", it) } - }.build() - - return GET(url, headers) - } - - override fun searchMangaParse(response: Response) = popularMangaParse(response) - - // =========================== Manga Details ============================ - override fun mangaDetailsRequest(manga: SManga): Request { - val id = manga.url.getMangaId() - return GET("$apiUrl/mangas/$id", headers) - } - - override fun getMangaUrl(manga: SManga) = baseUrl + manga.url - - override fun mangaDetailsParse(response: Response) = SManga.create().apply { - val mangaDto = response.parseAs () - url = "/obra" + mangaDto.entryPath - thumbnail_url = baseUrl + mangaDto.imagePath - title = mangaDto.title - artist = mangaDto.staff - genre = mangaDto.genres.joinToString { it.genre } - status = parseStatus(mangaDto.status.orEmpty()) - description = buildString { - mangaDto.synopsis?.also { append("$it\n\n") } - if (mangaDto.titles.isNotEmpty()) { - append("Títulos alternativos: ${mangaDto.titles.joinToString { it.title }}") - } - } - } - - private fun parseStatus(status: String) = when (status) { - "Ativo" -> SManga.ONGOING - "Completo" -> SManga.COMPLETED - "Hiato" -> SManga.ON_HIATUS - else -> SManga.UNKNOWN - } - - // ============================== Chapters ============================== - override fun chapterListRequest(manga: SManga): Request { - val split = manga.url.split("/").reversed() - val slug = split[0] - val id = split[1] - - return GET("$apiUrl/chapters/$id/all#$slug", headers) - } - - override fun chapterListParse(response: Response): List { - val parsed = response.parseAs () - val mangaSlug = response.request.url.fragment!! - val mangaId = response.request.url.pathSegments.reversed()[1] - - return parsed.chapters.reversed().map { - SChapter.create().apply { - name = "Capítulo ${it.number}" - // Sometimes the "number" attribute have letters or other characters, - // which could ruin the automatic chapter number recognition system. - chapter_number = it.number.trim { char -> !char.isDigit() }.toFloatOrNull() ?: 1F - - url = "/leitor/$mangaId/${it.versionId}/$mangaSlug/${it.number}" - - date_upload = it.created_at.orEmpty().toDate() - } - } - } - - // =============================== Pages ================================ - override fun getChapterUrl(chapter: SChapter) = baseUrl + chapter.url - - override fun pageListRequest(chapter: SChapter): Request { - val versionId = chapter.url.split("/")[3] - - return GET("$apiUrl/chapter/versions/$versionId", headers) - } - - override fun pageListParse(response: Response): List { - val data = response.parseAs () - val sortedPages = data.pages.sortedBy { it.url.extractPageNumber() } - val host = getImageHost(sortedPages.first().url) - - return sortedPages.mapIndexed { index, item -> - Page(index, imageUrl = host + item.url) - } - } - - /** - * The source normally uses only one CDN per chapter, so we'll try to get - * the correct CDN before loading all pages, leaving the [imageCdnSwapper] - * as the last choice. - */ - private fun getImageHost(path: String): String { - val pageCheck = super.client.newCall(GET(MAIN_CDN + path, headers)).execute() - pageCheck.close() - return when { - !pageCheck.isSuccessful -> SECONDARY_CDN - else -> MAIN_CDN - } - } - - override fun imageUrlParse(response: Response): String { - throw UnsupportedOperationException() - } - - // ============================= Utilities ============================== - private inline fun Response.parseAs(): T = use { - try { - json.decodeFromStream(it.body.byteStream()) - } catch (_: Exception) { - throw Exception( - """ - Contéudo protegido ou foi removido. - Faça o login na WebView e tente novamente - """.trimIndent(), - ) - } - } - - private fun HttpUrl.Builder.addIfNotBlank(query: String, value: String): HttpUrl.Builder { - if (value.isNotBlank()) addQueryParameter(query, value) - return this - } - - private fun String.getMangaId() = substringAfter("/obra/").substringBefore("/") - - private fun String.toDate(): Long { - return runCatching { DATE_FORMATTER.parse(trim())?.time } - .getOrNull() ?: 0L - } - - private val pageNumberRegex = Regex("""(\d+)\.(png|jpg|jpeg|gif|webp)$""") - - private fun String.extractPageNumber() = pageNumberRegex - .find(substringBefore("?")) - ?.groupValues - ?.get(1) - ?.toInt() ?: 0 - - /** - * This may sound stupid (because it is), but a similar approach exists - * in the source itself, because they somehow don't know to which server - * each page belongs to. I thought the `server` attribute returned by page - * objects would be enough, but it turns out that it isn't. Day ruined. - */ - private fun imageCdnSwapper(chain: Interceptor.Chain): Response { - val request = chain.request() - val response = chain.proceed(request) - - return if (response.code != 404) { - response - } else { - response.close() - val url = request.url.toString() - val newUrl = when { - url.startsWith(MAIN_CDN) -> url.replace("$MAIN_CDN/tsuki", SECONDARY_CDN) - url.startsWith(SECONDARY_CDN) -> url.replace(SECONDARY_CDN, "$MAIN_CDN/tsuki") - else -> url - } - - val newRequest = GET(newUrl, request.headers) - chain.proceed(newRequest) - } - } - - private val apiHeadersRegex = Regex("""headers\.common(?:\.([0-9A-Za-z_]+)|\[['"]([0-9A-Za-z-_]+)['"]])\s*=\s*['"]([a-zA-Z0-9_ :;.,\\/?!(){}\[\]@<>=\-+*#$&`|~^%]+)['"]""") - - private val apiHeaders by lazy { - val document = client.newCall(GET(baseUrl, headers)).execute().asJsoup() - val scriptUrl = document.selectFirst("script[src*=index-]")!!.absUrl("src") - val script = client.newCall(GET(scriptUrl, headers)).execute().body.string() - val matches = apiHeadersRegex.findAll(script) - - matches.associate { - (it.groups[1] ?: it.groups[2]!!).value to it.groups[3]!!.value - } - } - - private fun apiHeadersInterceptor(chain: Interceptor.Chain): Response { - val request = chain.request() - - if (!request.url.encodedPath.startsWith(API_PATH)) { - return chain.proceed(request) - } - - val newRequest = request.newBuilder().apply { - apiHeaders.entries.forEach { addHeader(it.key, it.value) } - if (token.isNotBlank()) { - addHeader("Authorization", "Bearer $token") - } - }.build() - - return chain.proceed(newRequest) - } - - companion object { - const val PREFIX_SEARCH = "id:" - - private val DATE_FORMATTER by lazy { - SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH) - } - - private const val MAIN_CDN = "https://cdn.tsuki-mangas.com/tsuki" - private const val SECONDARY_CDN = "https://cdn2.tsuki-mangas.com" - private const val API_PATH = "/api/v3" - } -} diff --git a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangasFilters.kt b/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangasFilters.kt deleted file mode 100644 index 77c5c6c5e..000000000 --- a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangasFilters.kt +++ /dev/null @@ -1,475 +0,0 @@ -package eu.kanade.tachiyomi.extension.pt.tsukimangas - -import eu.kanade.tachiyomi.source.model.Filter -import eu.kanade.tachiyomi.source.model.FilterList - -object TsukiMangasFilters { - open class CheckBoxFilterList(name: String, val pairs: Array >) : - Filter.Group (name, pairs.map { CheckBoxVal(it.first) }) - - private class CheckBoxVal(name: String) : Filter.CheckBox(name, false) - - private inline fun FilterList.parseCheckbox( - options: Array >, - ): Sequence { - return (first { it is R } as CheckBoxFilterList).state - .asSequence() - .filter { it.state } - .map { checkbox -> options.find { it.first == checkbox.name }!!.second } - } - - open class SelectFilter( - displayName: String, - val vals: Array >, - ) : Filter.Select ( - displayName, - vals.map { it.first }.toTypedArray(), - ) { - val selected get() = vals[state].second - } - - private inline fun FilterList.getSelected(): String { - return (first { it is R } as SelectFilter).selected - } - - internal class GenresFilter : CheckBoxFilterList("Gêneros", GENRES) - internal class TagsFilter : CheckBoxFilterList("Tags", TAGS) - - internal class FormatFilter : SelectFilter("Formato", FORMATS) - internal class AdultFilter : SelectFilter("Mostrar conteúdo adulto", ADULT_OPTIONS) - internal class ContentFilter : SelectFilter("Filtro", CONTENT_FILTER) - internal class StatusFilter : SelectFilter("Status", STATUS) - - internal val FILTER_LIST get() = FilterList( - GenresFilter(), - TagsFilter(), - - FormatFilter(), - AdultFilter(), - ContentFilter(), - StatusFilter(), - ) - - internal data class FilterSearchParams( - val genres: Sequence = emptySequence(), - val tags: Sequence = emptySequence(), - - val format: String = "", - val adult: String = "", - val filter: String = "", - val status: String = "", - ) - - internal fun getSearchParameters(filters: FilterList): FilterSearchParams { - if (filters.isEmpty()) return FilterSearchParams() - - return FilterSearchParams( - filters.parseCheckbox (GENRES), - filters.parseCheckbox (TAGS), - - filters.getSelected (), - filters.getSelected (), - filters.getSelected (), - filters.getSelected (), - ) - } - - private val GENRES = arrayOf( - "4-Koma", - "Adaptação", - "Aliens", - "Animais", - "Antologia", - "Artes Marciais", - "Aventura", - "Ação", - "Colorido por fã", - "Comédia", - "Criado pelo Usuário", - "Crime", - "Cross-dressing", - "Deliquentes", - "Demônios", - "Doujinshi", - "Drama", - "Ecchi", - "Esportes", - "Fantasia", - "Fantasmas", - "Filosófico", - "Gals", - "Ganhador de Prêmio", - "Garotas Monstro", - "Garotas Mágicas", - "Gastronomia", - "Gore", - "Harém", - "Harém Reverso", - "Hentai", - "Histórico", - "Horror", - "Incesto", - "Isekai", - "Jogos Tradicionais", - "Lolis", - "Long Strip", - "Mafia", - "Magia", - "Mecha", - "Medicina", - "Militar", - "Mistério", - "Monstros", - "Música", - "Ninjas", - "Obscenidade", - "Oficialmente Colorido", - "One-shot", - "Policial", - "Psicológico", - "Pós-apocalíptico", - "Realidade Virtual", - "Reencarnação", - "Romance", - "Samurais", - "Sci-Fi", - "Shotas", - "Shoujo Ai", - "Shounen Ai", - "Slice of Life", - "Sobrenatural", - "Sobrevivência", - "Super Herói", - "Thriller", - "Todo Colorido", - "Trabalho de Escritório", - "Tragédia", - "Troca de Gênero", - "Vampiros", - "Viagem no Tempo", - "Vida Escolar", - "Violência Sexual", - "Vídeo Games", - "Webcomic", - "Wuxia", - "Yaoi", - "Yuri", - "Zumbis", - ).map { Pair(it, it) }.toTypedArray() - - private val TAGS = arrayOf( - Pair("4-Koma", "4-Koma"), - Pair("Acromático", "Achromatic"), - Pair("Adoção", "Adoption"), - Pair("Agricultura", "Agriculture"), - Pair("Airsoft", "Airsoft"), - Pair("Alienígenas", "Aliens"), - Pair("Alquimia", "Alchemy"), - Pair("Amadurecimento", "Coming Of Age"), - Pair("Ambiental", "Environmental"), - Pair("Amnésia", "Amnesia"), - Pair("Amor entre Adolescentes", "Teens' Love"), - Pair("Amor entre Homens", "Boys' Love"), - Pair("Anacronismo", "Anachronism"), - Pair("Animais", "Animals"), - Pair("Anjos", "Angels"), - Pair("Anti-Herói", "Anti-Hero"), - Pair("Antologia", "Anthology"), - Pair("Antropomorfismo", "Anthropomorphism"), - Pair("Anúncio Publicitário", "Advertisement"), - Pair("Ao Ar Livre", "Outdoor"), - Pair("Arco e Flecha", "Archery"), - Pair("Armas", "Guns"), - Pair("Artes Marciais", "Martial Arts"), - Pair("Assassinos", "Assassins"), - Pair("Assexual", "Asexual"), - Pair("Astronomia", "Astronomy"), - Pair("Atletismo", "Athletics"), - Pair("Atuação", "Acting"), - Pair("Autobiográfico", "Autobiographical"), - Pair("Aviação", "Aviation"), - Pair("Badminton", "Badminton"), - Pair("Banda", "Band"), - Pair("Bar", "Bar"), - Pair("Barreira de Idioma Estrangeiro", "Foreign Language Barrier"), - Pair("Basquete", "Basketball"), - Pair("Batalha Real", "Battle Royale"), - Pair("Batalha de Cartas", "Card Battle"), - Pair("Beisebol", "Baseball"), - Pair("Biográfico", "Biographical"), - Pair("Bissexual", "Bisexual"), - Pair("Bombeiros", "Firefighters"), - Pair("Boxe", "Boxing"), - Pair("Bruxa", "Witch"), - Pair("Bullying", "Bullying"), - Pair("CGI Completo", "Full CGI"), - Pair("CGI", "CGI"), - Pair("Caligrafia", "Calligraphy"), - Pair("Canibalismo", "Cannibalism"), - Pair("Carros", "Cars"), - Pair("Casamento", "Marriage"), - Pair("Centauro", "Centaur"), - Pair("Chibi", "Chibi"), - Pair("Chuunibyou", "Chuunibyou"), - Pair("Ciborgue", "Cyborg"), - Pair("Ciclismo", "Cycling"), - Pair("Ciclomotores", "Mopeds"), - Pair("Circo", "Circus"), - Pair("Civilização Perdida", "Lost Civilization"), - Pair("Clone", "Clone"), - Pair("Clube Escolar", "School Club"), - Pair("Comida", "Food"), - Pair("Comédia Surrealista", "Surreal Comedy"), - Pair("Conspiração", "Conspiracy"), - Pair("Conto de Fadas", "Fairy Tale"), - Pair("Cor Completa", "Full Color"), - Pair("Cosplay", "Cosplay"), - Pair("Crime", "Crime"), - Pair("Crossover", "Crossover"), - Pair("Cultivo", "Cultivation"), - Pair("Culto", "Cult"), - Pair("Cultura Otaku", "Otaku Culture"), - Pair("Cyberpunk", "Cyberpunk"), - Pair("Dança", "Dancing"), - Pair("Deficiência", "Disability"), - Pair("Delinquentes", "Delinquents"), - Pair("Demônios", "Demons"), - Pair("Denpa", "Denpa"), - Pair("Desenho", "Drawing"), - Pair("Desenvolvimento de Software", "Software Development"), - Pair("Deserto", "Desert"), - Pair("Detetive", "Detective"), - Pair("Deuses", "Gods"), - Pair("Diferença de Idade", "Age Gap"), - Pair("Dinossauros", "Dinosaurs"), - Pair("Distópico", "Dystopian"), - Pair("Donzela do Santuário", "Shrine Maiden"), - Pair("Dragões", "Dragons"), - Pair("Drogas", "Drugs"), - Pair("Dullahan", "Dullahan"), - Pair("E-Sports", "E-Sports"), - Pair("Economia", "Economics"), - Pair("Educacional", "Educational"), - Pair("Elenco Conjunto", "Ensemble Cast"), - Pair("Elenco Principalmente Adolescente", "Primarily Teen Cast"), - Pair("Elenco Principalmente Adulto", "Primarily Adult Cast"), - Pair("Elenco Principalmente Feminino", "Primarily Female Cast"), - Pair("Elenco Principalmente Infantil", "Primarily Child Cast"), - Pair("Elenco Principalmente Masculino", "Primarily Male Cast"), - Pair("Elfo", "Elf"), - Pair("Empregadas", "Maids"), - Pair("Episódico", "Episodic"), - Pair("Ero Guro", "Ero Guro"), - Pair("Escola", "School"), - Pair("Escravidão", "Slavery"), - Pair("Escrita", "Writing"), - Pair("Esgrima", "Fencing"), - Pair("Espaço", "Space"), - Pair("Espionagem", "Espionage"), - Pair("Esqueleto", "Skeleton"), - Pair("Faculdade", "College"), - Pair("Fada", "Fairy"), - Pair("Família Encontrada", "Found Family"), - Pair("Fantasia Urbana", "Urban Fantasy"), - Pair("Fantasma", "Ghost"), - Pair("Filosofia", "Philosophy"), - Pair("Fitness", "Fitness"), - Pair("Flash", "Flash"), - Pair("Fotografia", "Photography"), - Pair("Freira", "Nun"), - Pair("Fugitivo", "Fugitive"), - Pair("Futebol Americano", "American Football"), - Pair("Futebol", "Football"), - Pair("Gangues", "Gangs"), - Pair("Garota Monstro", "Monster Girl"), - Pair("Garotas Bonitinhas Fazendo Coisas Bonitinhas", "Cute Girls Doing Cute Things"), - Pair("Garoto Feminino", "Femboy"), - Pair("Garoto Monstro", "Monster Boy"), - Pair("Garotos Bonitinhos Fazendo Coisas Bonitinhas", "Cute Boys Doing Cute Things"), - Pair("Go", "Go"), - Pair("Goblin", "Goblin"), - Pair("Golfe", "Golf"), - Pair("Gore", "Gore"), - Pair("Guerra", "War"), - Pair("Gyaru", "Gyaru"), - Pair("Gêmeos", "Twins"), - Pair("Handebol", "Handball"), - Pair("Harém Feminino", "Female Harem"), - Pair("Harém Masculino", "Male Harem"), - Pair("Harém com Gêneros Mistos", "Mixed Gender Harem"), - Pair("Henshin", "Henshin"), - Pair("Heterossexual", "Heterosexual"), - Pair("Hikikomori", "Hikikomori"), - Pair("Histórico", "Historical"), - Pair("Horror Corporal", "Body Horror"), - Pair("Horror Cósmico", "Cosmic Horror"), - Pair("Identidades Dissociativas", "Dissociative Identities"), - Pair("Inteligência Artificial", "Artificial Intelligence"), - Pair("Isekai", "Isekai"), - Pair("Iyashikei", "Iyashikei"), - Pair("Jogo da Morte", "Death Game"), - Pair("Jogos Eletrônicos", "Video Games"), - Pair("Jogos de Azar", "Gambling"), - Pair("Judô", "Judo"), - Pair("Kaiju", "Kaiju"), - Pair("Karuta", "Karuta"), - Pair("Kemonomimi", "Kemonomimi"), - Pair("Kuudere", "Kuudere"), - Pair("Lacrosse", "Lacrosse"), - Pair("Literatura Clássica", "Classic Literature"), - Pair("Lobisomem", "Werewolf"), - Pair("Luta Livre", "Wrestling"), - Pair("Luta com Espada", "Swordplay"), - Pair("Luta com Lança", "Spearplay"), - Pair("Líder de Torcida", "Cheerleading"), - Pair("Magia", "Magic"), - Pair("Mahjong", "Mahjong"), - Pair("Manipulação de Memória", "Memory Manipulation"), - Pair("Manipulação do Tempo", "Time Manipulation"), - Pair("Maquiagem", "Makeup"), - Pair("Maria-rapaz", "Tomboy"), - Pair("Masmorra", "Dungeon"), - Pair("Medicina", "Medicine"), - Pair("Mergulho", "Scuba Diving"), - Pair("Meta", "Meta"), - Pair("Militar", "Military"), - Pair("Mitologia", "Mythology"), - Pair("Moda", "Fashion"), - Pair("Mordomo", "Butler"), - Pair("Motocicletas", "Motorcycles"), - Pair("Mudança de Forma", "Shapeshifting"), - Pair("Mulher de Escritório", "Office Lady"), - Pair("Mundo Virtual", "Virtual World"), - Pair("Musical", "Musical"), - Pair("Máfia", "Mafia"), - Pair("Natação", "Swimming"), - Pair("Navios", "Ships"), - Pair("Necromancia", "Necromancy"), - Pair("Nekomimi", "Nekomimi"), - Pair("Ninja", "Ninja"), - Pair("Noir", "Noir"), - Pair("Nudez", "Nudity"), - Pair("Não Ficção", "Non-Fiction"), - Pair("Oiran", "Oiran"), - Pair("Ojou-Sama", "Ojou-Sama"), - Pair("Ordem Acrônica", "Achronological Order"), - Pair("Pandemia", "Pandemic"), - Pair("Parkour", "Parkour"), - Pair("Paródia", "Parody"), - Pair("Patinagem no Gelo", "Ice Skating"), - Pair("Pele Bronzeada", "Tanned Skin"), - Pair("Pesca", "Fishing"), - Pair("Piratas", "Pirates"), - Pair("Polícia", "Police"), - Pair("Política", "Politics"), - Pair("Ponto de Vista", "POV"), - Pair("Prisão", "Prison"), - Pair("Professor(a)", "Teacher"), - Pair("Protagonista Feminina", "Female Protagonist"), - Pair("Protagonista Masculino", "Male Protagonist"), - Pair("Pular no Tempo", "Time Skip"), - Pair("Puppetry", "Puppetry"), - Pair("Pós-Apocalíptico", "Post-Apocalyptic"), - Pair("Pós-Vida", "Afterlife"), - Pair("Pôquer", "Poker"), - Pair("Quimera", "Chimera"), - Pair("Rakugo", "Rakugo"), - Pair("Reabilitação", "Rehabilitation"), - Pair("Realidade Aumentada", "Augmented Reality"), - Pair("Reencarnação", "Reincarnation"), - Pair("Regressão de Idade", "Age Regression"), - Pair("Religião", "Religion"), - Pair("Robô Real", "Real Robot"), - Pair("Robôs", "Robots"), - Pair("Rotoscopia", "Rotoscoping"), - Pair("Rugby", "Rugby"), - Pair("Rural", "Rural"), - Pair("Samurai", "Samurai"), - Pair("Sem Diálogo", "No Dialogue"), - Pair("Sem Gênero", "Agender"), - Pair("Sem-teto", "Homeless"), - Pair("Sereia", "Mermaid"), - Pair("Shogi", "Shogi"), - Pair("Skateboarding", "Skateboarding"), - Pair("Slapstick", "Slapstick"), - Pair("Sobrevivência", "Survival"), - Pair("Steampunk", "Steampunk"), - Pair("Stop Motion", "Stop Motion"), - Pair("Suicídio", "Suicide"), - Pair("Sumô", "Sumo"), - Pair("Super Robô", "Super Robot"), - Pair("Super-herói", "Superhero"), - Pair("Superpoder", "Super Power"), - Pair("Surf", "Surfing"), - Pair("Sátira", "Satire"), - Pair("Súcubo", "Succubus"), - Pair("Tanques", "Tanks"), - Pair("Temas LGBTQ+", "LGBTQ+ Themes"), - Pair("Terrorismo", "Terrorism"), - Pair("Tokusatsu", "Tokusatsu"), - Pair("Tortura", "Torture"), - Pair("Trabalho", "Work"), - Pair("Tragédia", "Tragedy"), - Pair("Transgênero", "Transgender"), - Pair("Travestismo", "Crossdressing"), - Pair("Trens", "Trains"), - Pair("Triângulo Amoroso", "Love Triangle"), - Pair("Troca de Corpos", "Body Swapping"), - Pair("Troca de Gênero", "Gender Bending"), - Pair("Tríades", "Triads"), - Pair("Tsundere", "Tsundere"), - Pair("Tênis de Mesa", "Table Tennis"), - Pair("Tênis", "Tennis"), - Pair("Universo Alternativo", "Alternate Universe"), - Pair("Urbano", "Urban"), - Pair("VTuber", "VTuber"), - Pair("Vampiro", "Vampire"), - Pair("Viagem", "Travel"), - Pair("Vida Familiar", "Family Life"), - Pair("Vikings", "Vikings"), - Pair("Vilã", "Villainess"), - Pair("Vingança", "Revenge"), - Pair("Vôlei", "Volleyball"), - Pair("Wuxia", "Wuxia"), - Pair("Yakuza", "Yakuza"), - Pair("Yandere", "Yandere"), - Pair("Youkai", "Youkai"), - Pair("Yuri", "Yuri"), - Pair("Zumbi", "Zombie"), - Pair("Ídolo", "Idol"), - Pair("Ópera Espacial", "Space Opera"), - Pair("Órfão/Órfã", "Orphan"), - ) - - private val ANY = Pair("Qualquer um", "") - - private val FORMATS = arrayOf( - ANY, - Pair("Mangá", "1"), - Pair("Manhwa", "2"), - Pair("Manhua", "3"), - Pair("Novel", "4"), - ) - - private val ADULT_OPTIONS = arrayOf( - ANY, - Pair("Sim", "1"), - Pair("Não", "0"), - ) - - private val CONTENT_FILTER = arrayOf( - ANY, - Pair("Mais popular", "0"), - Pair("Menos popular", "1"), - Pair("Melhores notas", "2"), - Pair("Piores notas", "3"), - ) - - private val STATUS = arrayOf( - ANY, - Pair("Ativo", "0"), - Pair("Completo", "1"), - Pair("Cancelado", "2"), - Pair("Hiato", "3"), - ) -} diff --git a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangasUrlActivity.kt b/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangasUrlActivity.kt deleted file mode 100644 index 1722468b1..000000000 --- a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/TsukiMangasUrlActivity.kt +++ /dev/null @@ -1,41 +0,0 @@ -package eu.kanade.tachiyomi.extension.pt.tsukimangas - -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://tsuki-mangas.com/obra/ / - intents - * and redirects them to the main Tachiyomi process. - */ -class TsukiMangasUrlActivity : Activity() { - - private val tag = javaClass.simpleName - - 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", "${TsukiMangas.PREFIX_SEARCH}$id") - putExtra("filter", packageName) - } - - try { - startActivity(mainIntent) - } catch (e: ActivityNotFoundException) { - Log.e(tag, e.toString()) - } - } else { - Log.e(tag, "could not parse uri from intent $intent") - } - - finish() - exitProcess(0) - } -} diff --git a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/dto/TsukiMangasDto.kt b/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/dto/TsukiMangasDto.kt deleted file mode 100644 index 7207a0150..000000000 --- a/src/pt/tsukimangas/src/eu/kanade/tachiyomi/extension/pt/tsukimangas/dto/TsukiMangasDto.kt +++ /dev/null @@ -1,70 +0,0 @@ -package eu.kanade.tachiyomi.extension.pt.tsukimangas.dto - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable -data class MangaListDto( - val data: List
, - val page: Int, - val lastPage: Int, -) - -@Serializable -data class SimpleMangaDto( - val id: Int, - @SerialName("url") val slug: String, - val title: String, - val poster: String? = null, - val cover: String? = null, -) { - val imagePath = "/img/imgs/${poster ?: cover ?: "nobackground.jpg"}" - val entryPath = "/$id/$slug" -} - -@Serializable -data class CompleteMangaDto( - val id: Int, - @SerialName("url") val slug: String, - - val title: String, - val poster: String? = null, - val cover: String? = null, - val status: String? = null, - val synopsis: String? = null, - val staff: String? = null, - val genres: List = emptyList(), - val titles: List = emptyList(), -) { - val entryPath = "/$id/$slug" - - val imagePath = "/img/imgs/${poster ?: cover ?: "nobackground.jpg"}" - - @Serializable - data class Genre(val genre: String) - - @Serializable - data class Title(val title: String) -} - -@Serializable -data class ChapterListDto(val chapters: List ) - -@Serializable -data class ChapterDto( - val number: String, - val title: String? = null, - val created_at: String? = null, - private val versions: List , -) { - @Serializable - data class Version(val id: Int) - - val versionId = versions.first().id -} - -@Serializable -data class PageListDto(val pages: List ) - -@Serializable -data class PageDto(val url: String)