@RUn1Ka50n#7k65Vg@*YN@0nOqF3!wZ~0BtCSo-nHgAlH^$=mprRIvu+*sGaHouG0#v<^pc!J94hC+g344`7Q2PDPfP#%sk8= wKi^D~rMJjhhEujH?**nOBjFy(kl{>YDX2F`S^P!(EQ$u~ zEiyYTc^i8EYfyKMql%{55mv`=dZz%$97gCh&;*E)sZg>U5D)rtE7bJAK<5_$=~n{# zXyTmhybI01hL|WwDj&~LieWr^%W;mb04ky9%zMBJ9epAoo~yqtfxh8h>v{{uD^Eg= zWT#k~0os2Mdd4%rMVy&3Q=9G~3VQET;2%X)&ux~9tSMb4jrTvNT81-}xK>*82{1at zGJWK)=dxi3mHIIB@(+MvmveCT+1}?_i3bi)UZHK$-l@Bp1IbWQMnlendVxN~7}w+J zBi~oRwT*9<#6(+O;-38+url8YA6G8b5^AqW+(S5B(_d6B|IS%Sk6|)bmK7%sf_Rar zg|nGjl>;?6nW`wH0dvJ&AnKQ+#YULb!}!xWOI>nYlRCtJ!~rewX05)W9D4QXK&e zC#-;akTg#I3m{W+tA!?e1{>Hd5?VU5$0KElb *z!{j;Y%%)jT(~qpe8O~bZ zaS-$oc^jo=QPBhv?NP57vUpS|uQ^h0g|evAg40OPk+qfll+UD1^3z&(v0hJ`0;Zrg zsC4>|4In>5XaE^N&Z68X$SBAt$Qc2nAZPrH2N?w!1vw*N6y%Jb@gSohqabGljDno; zbL>If2{Zkd2j|Y(5_DH{zZke-=l|ZT5mi!B@-TPfJ<1)2p8Rgm_0ds-WJ4WyRW3+Q zPUb`KliLm@@18^z6cmh2OG{f678cgsQA>jKVs7lMD=aL0kh`DXV-qD$-XgE=YfEO= z^z`(kWy_YmN)-(Y(mpzB)~;Q aF?t`Apw}56oL8)qQR1mF?f%GBY##=j7xp z>D#yO5N-`;4i~?Av&m5#Px;04Q+Go{!%=SL-JX?|HDmSa)lA1)d&T(Fzh&{cEu5z_ zg@EXkl$3-iQ>I))C7l-%5)#hX^|#;tly|&6HzXYSVu532Wo0ERR;<{_Qt5#s>S^^0 z2K;qY%vqEqDNcbUzsq(_f7i9Ay}!jdlJF6qkuBf?MGjF8^F*ze_H CAAv67fQ6*B6|$M?t?uC 5VE`FG&Z6~yusGF) T*ZV7}00000NkvXXu0mjf(O_2^ literal 0 HcmV?d00001 diff --git a/src/zh/dm5/res/mipmap-mdpi/ic_launcher.png b/src/zh/dm5/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c05b218a201ee5ba735d8ec8758ed78d7288b4c4 GIT binary patch literal 1244 zcmV<21S9*2P) +9 sEXfGu^!E1d^mshanF)OOvm=qn2VSrDdH(*=<=2uC@bvfh zpS0WU`PoDu9*>6|4#$m*NnDV$(%WzX@_8ED)}2k@6JUvM;PZd3M!?1wr!#>wSxR6A z;}UUYP$zZ3B9KYvct*4w$fUrd# *C}sLpPvH$DdC *__8*2i_ychCCt!pz9pyzQs^~odx-~fQop%#IB$_3>A%m#4SEziU)|tfjmAA z6mDZBpgpx6`1ABom23p6ejLc3237m6Q4umAYN*!FRbV$%@SqNgYBoT%909)i2AER_ z-0lOdx*M1~3lLI8oI=F$?pg@7_W %R`?b-oay&US;aenu~FF(AKIjuN# zX3x~Y(-RLveclW>b3hx{j+4O3jX>z6VYTse{f}y^bj1{tv9$*QhXdM*r-7abY)3w2 zf-Y$DnSi8FI0E(BZooIs2q6le>I60K;^}pg{u>-RX3S8MLNah?73edR+OuDOCRMB+ z9|83*2WN|iG#PX}L#Rvr!1;@ysa~C+;&Zu|L`iw `ZMflofjU24F%r oBzooV73RA1C|46Dqy8hngXW%bIXCWB}_9w z$_{9nc19}4Y-;?*oGT1lO7BMVqtR%)%jKGyO$7S-`g+`M_sxt+_6J6My)LrnwY9aq z>GSzEWD|i AF5l+QCk`x0>>4u~vHA z?G(+%)yQ}4Gy{%xvOsGZTDk1M_6(+GqX@^*JPDR`6|(g8qC6X!;bYI*cYeM<{4y>+ zkU&WBUoxFt`j8y`pnY;Dc6Q9fqZ941$Ekij%s3m>aS?SGA_w-d?wDD+w(I}N9}N7* z9s(=|#_?53*~zGGegd*f>@7L|dqS33UI9%gm6ht);vZ}OX(8TvxMR3t;DLF2vWtsL zl#h>(T`p2hLGzI&^fOx#e<~zpeWW=As;8$XtK-eQY}?@5`XRDbDO|$vyB{3! btH*$YiSU;G9ps*?6ab646o}#`K&HHSHAN&mJ%;@JEu?q_89`?~%;Acl zxna7%x14+mkVQg3dJzb4&{w)Y45o1(_4FbP20V>8a|Dtp`5rNH6p{(T8$Ol;zse1S zh024mAnh`DG2p9}UM5ovK#^oVXl9Wjs^qcWf1NO*1Zhi*;YYDbZA%QS;wmE#rBW7@ z#VSFmKv=K5x)BJRzGYC~e}6ZPbsb3F{VV49k033YQtsC-;{oRWY*NS=JT=q1WWHBD zGx^pa%TXd5Z 2*~XgzT@JeV_jRwwjP5a&iQ7>XWvXAF9HNC? z2O`H@ }oZVi-W=qL)sI*M}-rxdJ) zp>-WTrMe8&Jll%qcB(HKo;RuevUZi72oQvxQ>8RZGH^sW%}%3X3ZZrP0++kx8Y9J_ zbQYq2Q~R}885(?A#=`3QTDJteK;iRV;%ft5TL7GO&4OkghvK3G*l{G62F)mslp47u z&OjFRJE9alx*JAI&YEOqzi6-A!t4Hq{aU_6lcZMa24WwrXZyY*y!;t`J>k%g(l{qY z{EF0FDDjsY?O FeO9U;;Pn!j0UD+&jP1ic+a~=yU_|V$XtCxHZ&fC *#K>QcO;E z%f|gr;VCb2-dJ2P(Ug2N!LFB$D7KM2kTSSA%qoXkNM4w6#FQ#A^&cDQe*BkxBKh>J zPX?M*@CC9!*xA1rnra7iU`*+0v;lpF1Xr!SLsY?oD Bo(efblEbi?lwL?VAY z6mioRd5=II4%^i`2Wi$; ^`P7ZPq0Szxicmt=56H^`=*gM$UDTgjzmJ0B=&vfj8Vs{9^H1wFha| zjJs;o^fI&vt*hFGPmxwt`&=12F;z^x(}30W?A6oOx1aRQ%&UqsTScVwNYL)P56gIu zT2d$f*~6lkaZ=2y(}n|oi{1X=R~Q$r43
#z&59-q#>iy zzIhCt7g&1>ABzfsc~1QTg IQ zQhE79AQf^$WguXyj2KhxFH!s@p`CImOR${n+{9RDKyfCs{_QFpSmO;{7Vqd@Zn2gV zc3@-}*@tQi%f F z+E?sa6Z!z}cpRaFalw>c^E&!zV#qPBqBVH;SUkh}Q^~ySq+i!-xQN-eO!-irdH(LV zCrPB25#oX;9?`f==bZaT<~JFounGg1r@@bc?|gmTV!WfNwH4aP5$t2i zJ``^!vvogHG9WQ2NcnOg#Y$XmLX@aFB=M#tA?de}r}BrV9(~4%2+q@+EY<22(N>SL zH89*M49T72BcH4n?W50bSi|!Ci#wd$uT{9tglsJs+Gs(z oT1B14BoZEKXp<(;o-RjF!VeK(Yu(~4hBs#f4+5$~k-*we^OpjvC`3VX1i zFIrAV*&os26#WXrYt>I UR22#m(l}YM*nM-zD7gKFUE6KJPM#;$BI}+%`!+o N27S`(yqDH5YeuPWUQ1!v6aud-no}Z_l@}rjB_G4&YtN(bkpp8 z`=aZow_F<~5pwHqb g?xk6h{$?qN&(cKD|CpF9C~#L23LBm8P}g4bd?g-vmPj)v z3z=!ATdOmDNp`n2yTwb@g|XcE&yQzw-2+NQ`x>Zyw# U(f(nAxmSBZKhM zz20ZTSr>@9V)?e6y!6sSHEeODImIMy!La9UWygMI =_m=vk{qgpNW2c(zf5p$Ii~~ zHHX8whpu!!E#|0rKSmK4N!e$XY#8va_+ZBD`_gA`w6>ZOnWvr|u!Z_(O{=RJ8F?@- zv8&y)B^2*-s!rzXtgNgw&n?a{avTaI7&<;J5ht{@L+7S@i|)9tIwp1ADb*AC$HEpP zN&(uAHm!M(N^(x++}NoCuln>Cr Q!r6 YLpLj!kZ8~Z$Y5)M}9^8i;|EsD02`Y+z zd0lIz835Qc9>CR2f>As9*Romr8U_sHdK7zZQg0AM6R~I*i@G|C>@9UG!Dg%!HD>n# z5CJiQXJE)^vEpJ(BaezyP3Ff%p6&^Ni|)bUvC!qg_MT4K+Qm;-OA%qEE%V g?9)?jP-qa`zxd^ z%DzL#LZr^V# wt8kzB9?=p*Tgviy27(`qCXS#659kf0P!Bo}6id$#mjCih(4 zBm1v^MHrq=_vKAJ>6-=xR;>YB({y!pby21*zCR^19p(C`2|WG?8!suQc=yi6{pGG$ ze$Uz3pGU8tW>vhZ;U~ZH^74d?u;J<%k}y=T7%Y{#67kOUGv2%|42r-9#~W85Y~(Cb z$Uj@`-VHz5OK)(SQJt I@o7l*_1K$K#Xbk$z9!Gp>2>HEcU|MeY#%L<;)v71; z-*;}vVm)qoPoBkcqoN>)gao7dLmHe3D1pWxkxjyB(wZC T%x2! z+duz3d>G?|=aV4Jz_^EF5| #cCRb5j zv~z@*U1eM3#hEsjtn=;L-%W? GyL=*1})G*zs9wn`s9$NehsvkZDo3H zu2QvDGMAc8Fl(KLja+JB;Z* d~F)+ z$#lx2g|t()VVfm%3+5~kc_>s0z0qD_Q~B(D_p_%=IlLs*ps5`$*x-c`lqGk%(D2ek z98Bsge<=Wa4LDmb|68G34gz}5@@d8e!u1vDA5ud4)l7@nHl9D7eElCa(96XK!f`|8 z(9Y4mB-Ok^HuvZN?B|+Ckt{eS%0YT;k>vLIf6p?&JR#ON$zgyc__{IkIFOOkKD;Q! zbsONk{y%*2|Nig)&lER;_kyxP-u**3_6Whrrm}J+ukOE%d3Mss5r74MDUzzSq;Rj; z-qMIy>Kd_hM^J57+*k dt1Hb%ZFqe*uJxiFXihtDzj1c*+A9$hD zuY}rIsVW{lVu@0#i}w>imlQ@kn#$xAJiZF@(b?V#r+_>rCi;2vmFh s0fvD&Tj~X!T zA`X^4PKeyJp7@(YZx*nHS!-_qhp)TWN@TqMvyS8AH?3DDAf&gd1 8zi>PG zAdT=l>5Cg|CZsH?r9J36+c2#x3Jdil$sEWDt-jBOADUv o# sLw@2- zt?`@3@mAli87QtmeyKfAJnNgMDF~J0&2*S$$Blxv=NP$nV&{gc*2(5)12iSKmmQuY zUXnLaP=)ZmmtQof>&I1?F<+cE36?!c fW@kuR`W zhpox`thNr}nlp9uuq2ISQRY3X=;tMD(yi3Zry+xX8r_3F0XvrQXSQ{NPg~)tD3>f& z6Edv((hmCJg%zcnA3dH$Jip*luwrQrJ`yg%s5Z>C&>&4xJEcwwOGt3od+p4#p?wmf zoFCdV-JR>XcpsmY`Z15 ac^sW{Ck~58 zm<@S0g(bmG6SKhBS3MQ^O^dhEs;6&Kl$$=PLGkP={~T+R%*iJUa*I8@w!)93CWmT6 zi$`H+23v5EGojy#Mlc;iZ39;Gx{r d@KWd}PSK+I9%t%PU+9nQ#R4=ui>cUMXGSq zml6q26FigH#DWUT6UXAX-3m{>zfn$dIRQfgCyPoGT`AoT$Q>+VT@?T$|F>qx;0tMS zt|6e+Hx2tev>rxy=*#_(F4wkZF&pYCzJh;5#6U8}^|%GSDXj)sRvVT{{Xsw|lh3sT zw`+5#>~NrX>0Da?Ru3DNqyj% LpX>3{QJ7xdbqoALMQw!HN< zy6Z^B3*(AG5_`tdSUN+Qt6ouE?zWqfnHQ*taO+9BH-qgz!mQR?j|8)V0uD9HHzl8p z^jviD%CFbj3^dh}gY`}^+L|5AJI)qZ2jHI1E#E#!XPl8&qpPXZ)NS}wK=8p=)e{rJ zSib&ocoiw<3g1>qyrA{ByB++b;1y0KiUf*@MGmTbEmi+1>;4@^FWBf90Ye;Ph<~5w zHkWC$+K^s;-un>jjt(}!52{`>Gb%&a?Sz1E_uSEZqW-p;=8ytT^0q;a;t5*U3Fm_^ z8DZPvT1)b#huf#*(H~+o4Q2R6OoBnMW~XQxQkb`PAoxOG7IRZInV6`^UDNLqiz~p( zJh!(YaCpXiZHN_Fq?D<^ajj-LibO+lAC+~TL5k|%-C=$zM-b=GsjI7D)60vt>JQeX zX#eQ*i8uKEHZp!d%Ibv5(?gz*!wKUdP_5+2?sox@Je9rtUPhyoD4A5FH3 aEsw*3SFTjGjRupazSr0ne?t0hb_lmFt?nv-820L2+Z03CV3izy_vyt zB{<$pDHlliEGjHU` !O#jiHND5ku5>MD=TS&|S+xMTBDZN$hoD7erGxQmR_e4NVKFbXpI;kR&Le!Kn z-BsQPrU`(i7DVy^1r}dnClNXtAN_S1aajCBQ%$awU_8&;-k|}VU}l8Qc0(jLLl`HC zt!Y|es9*07@6Z mpd2Gjq7ro+X zW>;%S(e0sN13uV|@NF+mhS*AvIg;5~5AP2I8^5ehoIc|bpYat>ZyYHf*lln`Fvv>y zK;<%`YXtY~qJPmj`fvxmy9R}aKIS_925Nxuq21Xt9l*&6ZVq5PY2~c@zIbYGoD}8{ zN$*A41EV*AHOXwTPPz8?jhgzGU+$Ho?!Wu+P6VCp$QYyCOmD$MQB_Y8PoZ(m@O%*` zUo@_L*Eu?Y1akv~yni}tj^k_VNlU1H{ud+uB6HKVH;{oo;1kH5avyuhBSQSc?LJfW zTp!%< ~~YqYX)onNtz9UrkNy_nK%v zI{llW*O(+T$uiG0+nh7{w76W#= zf5vqOpVr(U@%QzpDa8`55e&YH449kQo{&gU&BX)vo|S}= ZL@2ow4JI97<|K7lO0KYd4i zAo~pi`Ek)D!xxjxjh7${^=0G-_ 4o#8Vd@d1`iG<@v|9`LGBBk2v!^P^p9Q` zWe%VtO8wbrZu0lsg(Ot_+kj23c*#|oY|Fbt-M-amh?5^zfUi17c+hQ8TKIcl=ewot zHXTgdoU}B)VO|4tK2&6V8Vh0Bzr1?ZNck}gs-%uTx zBlA-K<}(NN^MK+}TKHxj@}aAXqVgBF{fz)auM7d3XyhFTCb(!a(DtNIVBccdDmyYf z^WwndTXGLec*ol4 SZtTD@X;OMYzLK9_dy>)PM)DYf!F zXc6tYg?|6M8ur-LlP3zlEax2k{_ZAicbgf{f1sL8SxEWfUERa{`^KGio!;{obW@@| zMo*R-ms!~@zG`r2{HPRiSHAU*+s$N(ckJVF;>oTcYK?&h_JBCE%?769K$A=|+OqZl zEYk%vn0X2;+8>VWyA8xOtdj^ffkYs@j0h=OnC(srde8%)zOVh%l$O*G872ww<^F#v zT@@zX7)%pdG83^o`%4h3Yx@|%;wR(e;E+KKwarUSWu|lbwa^+Aazy-6Q<~~x`vn#m zd6|O8i&vd?e!Q;Z*wsRUzT^INFEB9hPAQ3;1fJ__qsLrM=n>Ip#ho28JSdviC%YI^ zJFwt{Yw7qv>22qrdn9TFnrVdTWJyLe+Yh85i@WLxt~PxMtaXb18|c$i4|H>mPdvzB zO#VeO8^-SwB3C)Yw+uu|(PmiZG$Ob*N>^zy^n5-fB!tpwtU#qW>gqCk-|BV;feu`D ze2bCh2g%d; u5k`_ZC@qFrfiz*SQX>{pYZQfm8ZN0XYqu zcbWw|M6yu}ot{Il^h$rd-QS)JgTR0t^>bw3ZZ*uHl-iAow6gW)>Iu%k{#NM>D$HZ* z-__Xp6}&sSufW*sqjw4Il_tQ7d7DqFN8HAzQoY>3kZRP2U)7I0BHxLbR+zx71;j(e z&3t`dQ*`?J4`oV(vE4!`fB4r%>h?A&&o=|&tNh)}*3^)iP~#n!YHmM!0d8E4{Q&Cg zhp=O}fA}gKWQQXH@kepJOxY?Atw{aNC~IKeo}RxJ|Dm%NY?4+AVTT(N{90YM#9tI+ zqAj _vW*cTdMF6OCG+eXmp$T^`k%~tdTh1;#aL0K&-E}YB_kD87If1cP=XD z&4PGxUS-{?YT4*M8|Jq*d`j!F{zl{ZeD?Fq=eaZnlfR(W=wO~V%WM4_!=L7p4fn%5 z$&ypw&l$WOJP7oVr@9HAr=pU7FX~zKWxsp%eN{2ZhCkr@!iUtAU2ukrkuUP5^52mL z#3rh;Eg;lq>6ZGk*6n6SNa-dSCaR^yrX^F@CHNmlbTgXAexpgJVd(Hv|Lyl~1>qW^ zSV)t~%@HQxYn^HN+viyCf!f=C*y77D>zC};tAFmlCuESxD6uC}v;i$u!{pC^{o{J^ z7tnlublb0Cw=}y|zGJR`*ixKJLR;9!I*rCiT(@SatR!b;V+sjt%Y3UaS~#8jIyPkj z&CYhY9AGBer(6>%F-o7Jl6Ab)7sA`4<;#Vke0Hq#c$p=OM&}n|80Cl{?U&A&t&+&+ z{s&f43Wl~#X3yZaVAzw6Kz*b?GoxQp49f-zHn6NDVhPT82@5fQeIUqrd02+I_pf W!j*CsRR5?l@IX@^UUknV=Dz^-y`zx; literal 0 HcmV?d00001 diff --git a/src/zh/dm5/res/mipmap-xxxhdpi/ic_launcher.png b/src/zh/dm5/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..733d5853f7361a8aed680e148b64c00e689f7cb5 GIT binary patch literal 7931 zcmds+=TlQ()bEoJB%wo8q)9?o5s)GQq#7hhFDktw(tB^A2c)CY31Fm&^d_RA3(|`U zA`n_IbOh<;@_TXrfjf8RnR#BEeb&tP%&awQ@4aTu_Y #c{L^^rc=n&!K@~b1&S(WTi25n4&H_e5;L3~+;3z=qY^YHyqoOT*3<3die?F`A zM__st@l1>$RN#r-jxr!M9L)m I!!vh7mqCE%K5D zgr!BXg;z7dop 1;%4 z@Gn9Rp-o3kr=i1#sQ7q5XvF4uVpuj|w kRsfU0eA;Nk5CZ}ONvo0RJVI)RXldiy&JSXvOgqp`v1=f2}eLHpVj zs77K6lb0Y2ybU|o6FN0iY-;gYOKLB(5Ehdapc&)^Q8hYGc@8tFa@@PE1$xGAs{zBS zV}hf@W?FpY)+WltuXb2Sr(=8TilPA$?fZ%BQnQpsfoyjah@)4EEmD|8v)~xk`T2B$ zH%>mJJb_E$oabJU-Y?k4zDNMN+Gz~0R`PFS+D|hVpaE7`K{~9DAutDfeo $(F%9&ykDIt(|?AY z5vk2}0P}0*PI4Gqs^kJHrEN*{X*b1SVD}<9q0`{ICXMTlqN+C41Nl88;W`k|ooAJ; zO}cL%y&ZM2Fok6z#$Gwbj`3mGH@!8uOzq~Y6RM2rNPM+95sJl37>6^p%Zg-(AA{)h zd)e7E9VZQ-#BBM~@rJYhg#*uC(xAfWc4xA- MY?33?Z)oblX9-wC9Ha@_G zM$0>O!1$>Z=#_#yv5ol^asvH->k!PC)NAo37ytJu{I0m58E6Sf2tF1EGS(Uk$liin zy#|6*PIT5C5UuIjSYVi{S4B#f&2_rSNQPl-8pgok+)4m&DVG4i3BZrZfr-|2LX-38 zfu>ZGap%?BU!mI}9dFfDmEdY%Ma&g>u;^d`K0i|!s6jQ!*XE}-s3=1NQiB6P5(%(2 z$;g4fSp37nEPh4GL%{oV!({Jk;520b7|ABJ-qX#`Xi*3U$hHMTfoZ?A$hkrw570Jw z%Ml=)DEJiCtA=5f$GpJU`aL-oNB}_GHB2cWK;}o9GB?E_QF#Do&<7dYkvGv%^gx8- zpGFk_RbG%X20r?xMmhHKK6{&R!>E}rrIZ)_hJ_C=uY1egR48TKrG&1xs~ADR!H}6Z zy-^XUONsZF*wa6ZjG!o2bz5a6?n{Z;h4qg2 ~{;ol7!&p&t8@Wun9=Qh}i^~%hco5qpw){I~EHC zg3cYvm=4C<4!Esp?Urf9F|IH*FtE{_Q^ng6R#f#AmUzN2`Y(g&tj22Lz44dqbz!O0 za-&FtPvY2Y4)uuzZ4}`>+MvZ?VHoP5jZj2O@h>~nj0Y}T*0KaIJm@$cev7h~;t3(o zp+!tJR>$t+AI(4o?nCF#b_B*mK5OpHuAuJxWIAifn~= +jnPWFM`Zu}$Pad6Oye?0)=bG~k1TbT!SO%+lbGtuz=?f!qnURtetWl?h+| z)+6i|6b79#YD)jNRft;2XA^^` n}rCU3uP9pj6B?H`_!xYMHzefAG(gC01w~kmw ze^{uQ0R?>byll5-*CuyXSGDk3NVceU&o-7{jd^=T!)k7mU}hp~qh^aUtDdR>pJV~m zDCtXY;jG0HP^{}`r7VKIY%(<@_;YtO{GaE-zapvK1V+HhNx1VWO5ECjZX>7DG zN-Omomy5amv|pcN_smn^xZ+x2?qe%h?=~w_j^03WOoQ58|7=K9uLFBi%FMn@?YR%j zsL`M@ou*Yf40JU{N9`n6`-t+T8X mJYXB%aC~GNxB0TtT9>1IyB*e zi+LeO)xI*l4xbrn491=GhK4Ye{XGm@w84IvQ)J`U&F^VE-+IsZ1fyLYBvn=ipD+pK z3$hxBBR!XN(vaBW9~&pZ1xBtAlDk(fylUH56JTne#bhL}PT7ZlyrwT%-96SPycK<+ zcf~k9q<}Y@5e}_Zp79|+!&eb-r6eYNQiay>HZ|V9L+IE=s+dk`*P;BuY52)GwK!=Q zMOf#JU{Jyd^8{K`PfdsQe~xURfD}m+bjYIID|M6N-yH-}7j&Gs6St@WO5Oap4{z`F zF5NgfbTDa3mAUXP+Rf&P1#UF>+6*YfouyCLDrNGAVF#z2KW`#d!=y)X$=bI3(jkxK zfj^w#fm|g_IQWs|#n~`Hmiu (v^Jp2OcQi7tLwhQl217 z1ve&7SdH-egy%^`bcJ?%d7%lS854_ 4SHqJ0TmatRGnHwD{(rmN|V z{CLJjsY}wQW)Csz=Dleo^_Jg9rJmSQjR0&ZA2T|x-t9+<>ratqBh*G2(WUfq58zEd z*S6AUVD#nVf2Gf)jrV2^#*#G=Pu{YP?$D_nurEOB0*S?w&<&U1WBK!hMJ_?!aS2$x zSg#pp$>A{e{>JZz)Jru@Ti#$@IqV8Yoc$*kDs-*$wNc$(9q~e$`CTt~HL`V2)gr}O z;jMP1<=RQX-KW9H!yb?}yngWN90rx& DEqZCGf#-AO`EY=$A%PSAT-(aK zS(PK7MlwD18)%KZn4o1|DB)(eFtjfNGB$M3o<3fiEY-us5q1FEJkbr1rWf#t7;da2 zD|dB}8h_66eUj3M2#%WDD1Kyf&ZQKz8SXxlh-GrBW0^yZIfW*irpR_1r@-uU1uO|g zpn4#UyfVI??)kWQ9rlZfc2}r!$ QuU zX#$b;uY>PXhD@HE-F+L`TwLOc >;k2;qV z9%@%rKxR*b(jbUWMnG_L=8Y6S%))rf{Wh)1bE=Wv+_3|Nu3R~7eU?UENe}cn*mC|W zxujT`9l=%@^jjqm7S;A*)f8oj3^Gm;Y2)wN{>^Bcpjk?0{l$g&<`ow>tGUlS`SsB* zpQ1?aW{d^i-MT!r`d`?LQs9z-0IJ+-Oc0f1@ScRvD13^gOzi6xkdp2CFbw~`myBOg z6wL_LTx~SJ!9{vnlzQDZ|DPgpXUHBu4>Po}dc*lr27l`!`bT>o;Rd}F?(|d^mU^(h zZ;t<}puOtPyP6*u{U?77{g9{p EzI2gwi4MpN~UTRo6gqp+Ic$e@~Dg7 z&noB66kVhn8@FE!FjbElZ=s8zI2;H)_o %un gIiF_xT7v$K~oMya>vbdZ#)O}4-r~Mf(xI-x~CIJyN zHt-;f)Emj>lzB}9^WIEVeD+#Nx+InIFc=9C%L~0mP7KgwT^kPL%|42%x;~ODrx}P0 zrV}r)v;V3!B Sc zz|~R=_-}VfJeDXxeD^WaB~tB@Nva&Uhl!nEnwd(TtfBol(R)&@ZR4DoS**^uI2z!o zZ~9xoBv{sT8b4r8<|ga+6M-(R?;M&yub9CC8u!0hbRExe6hO?w6^W*>*SBp$kd*A4 z$=~pgF`FB?9g-(*o%5>1C=nrxu0`?i!`sj3heZF cnIBgz^0CtMKFFJ*@o-~7cKTrDPi_}OkwDV@ z{DXK&6i>cVJ}?~kLxxfUf#E`;yC#3qtKk6e!{DFB=^#w5!zUH{_Nm#Jl^oyIr3_24 z_IBGo?`ST8d`af#H1-xVBy~V0%ruR7e+kgaruYQa%p6g5gc7MZQW=|+BK~gIXCQvY zNT78lCxwq_zO8MW{vAx_6;pJ@J _iuNckPiZ{TSfmOF1mSbkCPFUD9=B+n+<;InvfVh%rmN;mZ*-MVqs2 zrU&DTO0nhaJb(Sns$)h P*C;*izx8lH)}p}8?uy(NINlfOMo(K5mdfh{VdF-{A;4r2J7E4ulq zR~)WhVM&^T&D&2@Cbfd-Upwk<1I07|iCgWXpSLvg0oXDVS{c>wfyQ-{LlC2mIH9e? zbNFRVs(o6B^z7_6n_cDJ82Eeg2fulH-_~$vVMFm>N^BSf8 6%z z|A~#6KHj*`4 @A->VQbLQvO#{< z_hlD1V$ds|Yvg|Ry-*!9ol4bwEBXOI@q6jc=uPp?pWqhicXZDeA7HqE&BMhX(4I {2DyCo-1*Tkii@ z6OsWi;zTFj-v?!p*4vZy%h0d_t~9=NQ9fhp_GnAfg$LfP`dNRjU5#%39QX}sH@ko` zWCjx{_PCJUJsKj0kkpZyS=BO-08WputzVGw^bW}}#z _a8Tulj zD{GXQ8<3$Sp<-v>M59JW=ng{-1> b8V(H*?ps^Q4^1?M2`nvNVo5TwkU1{NIh;vb$f`h<+}8 zpa7mLJK$5s1lN!}UsS=?*%#FJCU?oP=_3o{1hf7 G%@# zHRazXZ&7iK_^)y)ve~Cx_wpFlvbl=~q^|SA(DhLMVM++6h(&UZdHicj?3G?s%)H@E z6h^{UZur9v^A(?+k2;IUv!i8(rg_fak&fY(=7wInG+mNwM-5x|;hy2;kL!qcXMf%z zexm!LuJobPqVL=}z?Ff1doQX?YQP^6BmRY@Fwm16-^z<7S#Iy!iG?%%$Q!Zbu-?Bf z?A6xNyq;|yx%iDPjOW#ZKUKOvBlTzp5tB!_h5m*wvE#>z>y(J#&Zwc5&Nzv(%3gmj zGAIK%V1{1h+NL?S@7DN8Wo 28Hw{9JuO{}w4IFoaN+0Q8W9U>DLG~fvm?@5*F);=1d}x)M zL>XbL=kGz5uT2caPE`lnRjB@Mt!vivLZ&@`9=TZlF_(h3Hy}?`Hz62n{iG}If{`8= zT$k&H{3mb-UHPZ<(Tk#pB_TW5U~;U~e&@4_pi2+C)v9yruIvromD(529?pkYDnsk@ zlQK5vCuQdB1MieuOGlC4JRs(fCCv9csONtF)cM$)G#BYQ`sx*{L}u)R-l&VVqn?wY zXx`4tKivCg8hhPRHRbKzIrAdOpw9XGt%3{eNhrbObV*y*t)m6J-YK8n=??=Xx;Vu7 z`At8s`43$^FXBAsI;{WYQXEpI-u{^|FGe@??KoskKsE9QPgEbjO8n%Kq55ee?5om? zT_;oNc%cd}8845Vspf(Wfftb!e>&sj2yQux=MO9l2zq=ks6&%~ozUK|IXnY4-P1jq zUN?N0IlQ!koNEiAX|L;o!Mj6VPlJI}Km-P&{Qt%qE A*$+HY$vzF2yBEyNIAS!x}0x`R9925}W z#b1$5T$N|dwH{N=-nHAMwr<#il@lS;ckVUy880oaHM-56d;Et&N)AmwYBKh+gmcRJ zo*I1gTqb$UGh73Hv({Ta`c-Y!`P;a`kyGGA5Ms*~jte_KT3h}8zUklvhQewDpaJ*+ zy7uL8;iZRWwuD0txx0TC9RB*wv(Twh-M2|M>2xZ z?P CIhjxw;w 034WS0G!vBMnQ*RM-Jn~X46F~FM-=srNIG7X^&xG z=7*NU`EvCR $pYYs^V}@Z$_pQ^Zc0%t5Jryx;^>@5%oCP*Vj?}m1cP!v?ZW{qOrRB%4(@Sz% z{}d3Ex?~*1m%yd9)T%RP!*QZC+}7Og_OnWkl7_b}!?msyKw*!`CO59ac+4ebs&%={ zQYB(s|Kj@kIiH9ASM9^WaUAYC5~v~G%L`O*cn>utV8Y(?ef#D(dATc%y;pJc>7`Gn zYVDk`ybw?+*L2Gz5F1oDKU|EZxh~`%v_4tWkD*reKlI!P`AL@KQE>eu&Nr|9j3V>k z6WG$CZGa9Lk^C~O Fdn`f=hUQNvD7{+-hAQbzqFL*!SDgl}@`%}(d4HhTAt|c#CoAthKo&TF3+KLj@ z4n3c_8k&wG52 bpp!+@ZCSh>sAft1iFLWJ zd7Fh2*g7nPp441vDkU+;&%9AP b;wdlZ zUQL^DWXykop|3JYSLl-7#8djRO8gge)WXD)t(AxuEWEg)xFsILOQ;P{Q_(_IDqBYU EA7^8iF8}}l literal 0 HcmV?d00001 diff --git a/src/zh/dm5/src/eu/kanade/tachiyomi/extension/zh/dm5/CommentsInterceptor.kt b/src/zh/dm5/src/eu/kanade/tachiyomi/extension/zh/dm5/CommentsInterceptor.kt new file mode 100644 index 000000000..dc8190866 --- /dev/null +++ b/src/zh/dm5/src/eu/kanade/tachiyomi/extension/zh/dm5/CommentsInterceptor.kt @@ -0,0 +1,91 @@ +package eu.kanade.tachiyomi.extension.zh.dm5 + +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Color +import android.text.Layout +import android.text.StaticLayout +import android.text.TextPaint +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import okhttp3.Interceptor +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.Response +import okhttp3.ResponseBody.Companion.toResponseBody +import org.jsoup.parser.Parser +import uy.kohesive.injekt.injectLazy +import java.io.ByteArrayOutputStream + +// This file is modified from DMZJ extension + +val json: Json by injectLazy() + +@Serializable +class ChapterCommentDto( + val PostContent: String, + val Poster: String, +) { + override fun toString() = "$Poster: $PostContent" +} + +fun parseChapterComments(response: Response): List { + val result: List = json.decodeFromString(response.body.string()) + if (result.isEmpty()) return listOf("没有吐槽") + return result.map { + Parser.unescapeEntities(it.toString(), false) + } +} + +object CommentsInterceptor : Interceptor { + private const val MAX_HEIGHT = 1920 + private const val WIDTH = 1080 + private const val UNIT = 32 + private const val UNIT_F = UNIT.toFloat() + + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val response = chain.proceed(request) + if (!response.request.url.toString().contains("pagerdata.ashx")) return response + + val comments = parseChapterComments(response) + + val paint = TextPaint().apply { + color = Color.BLACK + textSize = UNIT_F + isAntiAlias = true + } + + var height = UNIT + val layouts = comments.map { + @Suppress("DEPRECATION") + StaticLayout(it, paint, WIDTH - 2 * UNIT, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false) + }.takeWhile { + val lineHeight = it.height + UNIT + if (height + lineHeight <= MAX_HEIGHT) { + height += lineHeight + true + } else { + false + } + } + + val bitmap = Bitmap.createBitmap(WIDTH, height, Bitmap.Config.ARGB_8888) + bitmap.eraseColor(Color.WHITE) + val canvas = Canvas(bitmap) + + var y = UNIT + for (layout in layouts) { + canvas.save() + canvas.translate(UNIT_F, y.toFloat()) + layout.draw(canvas) + canvas.restore() + y += layout.height + UNIT + } + + val output = ByteArrayOutputStream() + bitmap.compress(Bitmap.CompressFormat.PNG, 0, output) + val body = output.toByteArray().toResponseBody("image/png".toMediaType()) + return response.newBuilder().body(body).build() + } +} diff --git a/src/zh/dm5/src/eu/kanade/tachiyomi/extension/zh/dm5/Dm5.kt b/src/zh/dm5/src/eu/kanade/tachiyomi/extension/zh/dm5/Dm5.kt new file mode 100644 index 000000000..bb24d775d --- /dev/null +++ b/src/zh/dm5/src/eu/kanade/tachiyomi/extension/zh/dm5/Dm5.kt @@ -0,0 +1,218 @@ +package eu.kanade.tachiyomi.extension.zh.dm5 + +import android.app.Application +import android.content.SharedPreferences +import androidx.preference.PreferenceScreen +import androidx.preference.SwitchPreferenceCompat +import eu.kanade.tachiyomi.lib.unpacker.Unpacker +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.ConfigurableSource +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 okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +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 + +class Dm5 : ParsedHttpSource(), ConfigurableSource { + override val lang = "zh" + override val supportsLatest = true + override val name = "动漫屋" + override val baseUrl = "https://www.dm5.cn" + override val client: OkHttpClient = network.client.newBuilder() + .addInterceptor(CommentsInterceptor) + .build() + + private val preferences: SharedPreferences = + Injekt.get ().getSharedPreferences("source_$id", 0x0000) + + // Some mangas are blocked without this + override fun headersBuilder() = super.headersBuilder().set("Accept-Language", "zh-TW") + + override fun popularMangaRequest(page: Int) = GET("$baseUrl/manhua-list-p$page/", headers) + override fun popularMangaNextPageSelector(): String = "div.page-pagination a:contains(>)" + override fun popularMangaSelector(): String = "ul.mh-list > li > div.mh-item" + override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply { + title = element.selectFirst("h2.title > a")!!.text() + thumbnail_url = element.selectFirst("p.mh-cover")!!.attr("style") + .substringAfter("url(").substringBefore(")") + url = element.selectFirst("h2.title > a")!!.attr("href") + } + + override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/manhua-list-s2-p$page/", headers) + override fun latestUpdatesNextPageSelector(): String = popularMangaNextPageSelector() + override fun latestUpdatesSelector() = popularMangaSelector() + override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element) + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + return GET("$baseUrl/search?title=$query&language=1&page=$page", headers) + } + override fun searchMangaNextPageSelector(): String = popularMangaNextPageSelector() + override fun searchMangaSelector(): String = "ul.mh-list > li, div.banner_detail_form" + override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply { + title = element.selectFirst(".title > a")!!.text() + thumbnail_url = element.selectFirst("img")?.attr("src") + ?: element.selectFirst("p.mh-cover")!!.attr("style") + .substringAfter("url(").substringBefore(")") + url = element.selectFirst(".title > a")!!.attr("href") + } + + override fun mangaDetailsParse(document: Document) = SManga.create().apply { + title = document.selectFirst("div.banner_detail_form p.title")!!.ownText() + thumbnail_url = document.selectFirst("div.banner_detail_form img")!!.attr("abs:src") + author = document.selectFirst("div.banner_detail_form p.subtitle > a")!!.text() + artist = author + genre = document.select("div.banner_detail_form p.tip a").eachText().joinToString(", ") + val el = document.selectFirst("div.banner_detail_form p.content")!! + description = el.ownText() + el.selectFirst("span")?.ownText().orEmpty() + status = when (document.selectFirst("div.banner_detail_form p.tip > span > span")!!.text()) { + "连载中" -> SManga.ONGOING + "已完结" -> SManga.COMPLETED + else -> SManga.UNKNOWN + } + } + + override fun chapterListParse(response: Response): List { + val document = response.asJsoup() + // May need to click button on website to read + document.selectFirst("ul#detail-list-select-1")?.attr("class") + ?: throw Exception("請到webview確認") + val li = document.select("div#chapterlistload li > a").map { + SChapter.create().apply { + url = it.attr("href") + name = if (it.selectFirst("span.detail-lock, span.view-lock") != null) { + "\uD83D\uDD12" + } else { + "" + } + (it.selectFirst("p.title")?.text() ?: it.text()) + + val dateStr = it.selectFirst("p.tip") + if (dateStr != null) { + date_upload = dateFormat.parse(dateStr.text())?.time ?: 0L + } + } + } + + // Sort chapter by url (related to upload time) + if (preferences.getBoolean(SORT_CHAPTER_PREF, false)) { + return li.sortedByDescending { it.url.drop(2).dropLast(1).toInt() } + } + + // Sometimes list is in ascending order, probably unread paid manga + return if (document.selectFirst("div.detail-list-title a.order")!!.text() == "正序") { + li.reversed() + } else { + li + } + } + override fun chapterListSelector(): String = throw UnsupportedOperationException() + override fun chapterFromElement(element: Element): SChapter = throw UnsupportedOperationException() + + override fun pageListParse(document: Document): List { + val images = document.select("div#barChapter > img.load-src") + val result: ArrayList + val script = document.selectFirst("script:containsData(DM5_MID)")!!.data() + if (!script.contains("DM5_VIEWSIGN_DT")) { + throw Exception(document.selectFirst("div.view-pay-form p.subtitle")!!.text()) + } + val cid = script.substringAfter("var DM5_CID=").substringBefore(";") + if (!images.isEmpty()) { + result = images.mapIndexed { index, it -> + Page(index, "", it.attr("data-src")) + } as ArrayList + } else { + val mid = script.substringAfter("var DM5_MID=").substringBefore(";") + val dt = script.substringAfter("var DM5_VIEWSIGN_DT=\"").substringBefore("\";") + val sign = script.substringAfter("var DM5_VIEWSIGN=\"").substringBefore("\";") + val requestUrl = document.location() + val imageCount = script.substringAfter("var DM5_IMAGE_COUNT=").substringBefore(";").toInt() + result = (1..imageCount).map { + val url = requestUrl.toHttpUrl().newBuilder() + .addPathSegment("chapterfun.ashx") + .addQueryParameter("cid", cid) + .addQueryParameter("page", it.toString()) + .addQueryParameter("key", "") + .addQueryParameter("language", "1") + .addQueryParameter("gtk", "6") + .addQueryParameter("_cid", cid) + .addQueryParameter("_mid", mid) + .addQueryParameter("_dt", dt) + .addQueryParameter("_sign", sign) + .build() + Page(it, url.toString()) + } as ArrayList + } + + if (preferences.getBoolean(CHAPTER_COMMENTS_PREF, false)) { + val pageSize = script.substringAfter("var DM5_PAGEPCOUNT = ").substringBefore(";") + val tid = script.substringAfter("var DM5_TIEBATOPICID='").substringBefore("'") + for (i in 1..pageSize.toInt()) { + result.add( + Page( + result.size, + "", + "$baseUrl/m$cid/pagerdata.ashx?pageindex=$i&pagesize=$pageSize&tid=$tid&cid=$cid&t=9", + ), + ) + } + } + return result + } + + override fun imageUrlRequest(page: Page): Request { + val referer = page.url.substringBefore("chapterfun.ashx") + val header = headers.newBuilder().add("Referer", referer).build() + return GET(page.url, header) + } + + override fun imageUrlParse(response: Response): String { + val script = Unpacker.unpack(response.body.string()) + val pix = script.substringAfter("var pix=\"").substringBefore("\"") + val pvalue = script.substringAfter("var pvalue=[\"").substringBefore("\"") + val query = script.substringAfter("pix+pvalue[i]+\"").substringBefore("\"") + return pix + pvalue + query + } + override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException() + + override fun imageRequest(page: Page): Request { + if (!page.imageUrl!!.contains("pagerdata.ashx")) { + return GET(page.imageUrl!!, headers) + } + + val referer = page.imageUrl!!.substringBefore("pagerdata.ashx") + val header = headers.newBuilder().add("Referer", referer).build() + return GET(page.imageUrl!!, header) + } + + override fun setupPreferenceScreen(screen: PreferenceScreen) { + val chapterCommentsPreference = SwitchPreferenceCompat(screen.context).apply { + key = CHAPTER_COMMENTS_PREF + title = "章末吐槽页" + summary = "修改后,已加载的章节需要清除章节缓存才能生效。" + setDefaultValue(false) + } + val sortChapterPreference = SwitchPreferenceCompat(screen.context).apply { + key = SORT_CHAPTER_PREF + title = "依照上傳時間排序章節" + setDefaultValue(false) + } + screen.addPreference(chapterCommentsPreference) + screen.addPreference(sortChapterPreference) + } + + companion object { + private const val CHAPTER_COMMENTS_PREF = "chapterComments" + private const val SORT_CHAPTER_PREF = "sortChapter" + private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT) + } +}