From 81393601e1a23552b821a9cd9476ac126d3daba7 Mon Sep 17 00:00:00 2001 From: cranci1 <100066266+cranci1@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:43:49 +0200 Subject: [PATCH] images reduction (-22kb) --- .../Discord Icon.imageset/Discord Icon.png | Bin 16214 -> 3722 bytes .../Github Icon.imageset/Github Icon.png | Bin 14726 -> 3545 bytes Sora/Models/EpisodeLink.swift | 7 - .../DownloadManager/DownloadManager.swift | 223 ------------------ 4 files changed, 230 deletions(-) delete mode 100644 Sora/Models/EpisodeLink.swift delete mode 100644 Sora/Utlis & Misc/DownloadManager/DownloadManager.swift diff --git a/Sora/Assets.xcassets/Discord Icon.imageset/Discord Icon.png b/Sora/Assets.xcassets/Discord Icon.imageset/Discord Icon.png index 3847685bc23cd7b9f12913f3634c27a2fd467fcd..72d3df415c9eaa2d90a3b140930475707136d856 100644 GIT binary patch literal 3722 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 ShKL~W_tDt#WA=|$X#NWYaj2^R diff --git a/Sora/Assets.xcassets/Github Icon.imageset/Github Icon.png b/Sora/Assets.xcassets/Github Icon.imageset/Github Icon.png index bb23c56ffca8e0bf380d09603693b05ab54c7003..13e93d7e8a19f9b5d505da59ede0d5aa6893bcb2 100644 GIT binary patch literal 3545 zcmb7H`9Bi?AD*O`c|PCo^YasDY;^YmkRJ#D050g?(=i1An6mycg_ZfA^ZEnf ze*wZ6X|9`;l=AF;V7mt!F%*?V3{RhV7zU#E_~&TaER zrcG+>`=3G}9g|2%0zlyS$-%1N{7{`nE52SQBOfSS;eHGVPcbuyuOJx56m)4%5Y^;T zM=KOqHT2?I#Ab!cETY-IJ(zk#%3pc?p7mSB_*Y!GehHghxu;?8a)M=9N}*&&w?eT> z-SoMFvg+Gw9p8yte%aBxPcWAQUt)5#=PE+Ks_-6D$C)^Z{mS#!KetMBi<7mZ5qBhF zF#=nzae|kgs4BlFH(IWQBG1zeO@=Wa5}rZ!&8=%h?<87>_PY;~6bF5R__5oP4{wN@ zsdn>D6Klhz`nqBw(XM73&fb2dG2zp&c^WVQj)0V7s;DT+(li&b4s#Z!dHeX$-*Zi$frjZ%L>_; zDVoU86#hxhrcV&`DGK_u`7Nlm2GnY6Ot7;e*vXAd;W2W-jjwy<7Hkl$hxEe5aN6I4 z;j`;ODR)UEp+PK}@j(4$_R-{%aupnU0H<~SUd1fSqtrQcZ8>{f90R5tcjtS(WG%NV zJc5bK8Qy&TC?+wf&IEWFULvOEtQ=>JP2B^$))?FxV`6pZRs-0}l4cXk;$h4wC0An2 zOU@Bwo}TM&s0sQ#`DO1U#`xnOn>9Zr6sa;BuZ(z2%75-3y^AILmkgW$)L-`Y z(2xOo?ylnkRW0t5mxlNi5zY?$g_LYWvx7~{=N+_d6Lq+q*8hEwd!O~E{lK7hno3{r zbBm;!0-I-B+eRU%+#eQQ3F@uA8edhe15x|(vmLdEe8MqFDsp||t#XB9`w+MO7t}*j za`QHCu>%|rbBSE4`m{Cq-l6DJ$^3U(Xp{||zjK-An?*9hr>&GM%fi5a2v%8Fr`-97Yf4~_r^$xv0pZ2O?JmYFGI6Sb&dWI;BfV?>%=N^%isf}+H$)IDzK)}_ zoG<;{=-Z`UA2!VE4lD^HMHa&VPQ6zl!066pP7wY!7viMT7;^SXxT7Q}>UnjxDTI~f z>K9YU*~^93N?=?-&5>Iut{7hl8Qmiv!Yl7XO=WB*_qeY_x-)Rs?3`wkGYfB|mcQk! zHp=@zRgyz~{=O>C>8r7jMSE`85`F%Dq#{89wtMv=TYg<(eKAt&Tb-Q+1%CQYn@Y>I zrsO&+g9i*|l8>xfo#F;FP(0V{y2NrI-93fi#Im@f8yC2{VQHU%E&wmMGMx`!U)W@Z zLciKPWYn2t#Xl5GTvmZHXU`6|45XEt92`JRMjFz+>QoQC)-}#8iKE?`C36^HM!?b2 zAJ7eW05hSm%36+YHj6k>IIzLy(z?tYt1oemIS>$Zb5>2W4KPycMRk&Wfg&_7KECuHt+N@8 z$Qe#$Aap~PohK=S)3z?+%ym#c9CG1@-iTB*cS@m84UVmsfK*cpnS(QEw@{nF`WbdK zq)*4Y$pB?+3~42q1JTA=o(NI$h!2M}NI?n-76X?m#JZV5@WMJKo8aD3SOH1sGq_hg zi6m4EJ1B;M2_)kz8S!FRrQ;hCoXaVn_=8Eb9sHL#V3@Lmu?02U) z6o}?IpC3&mM667BPm!Z8@U_vA^8dyK-pjWKgNv5pJ3S1Cj#=GH z<8DVdRN1*Y0d(@lk+6V65zn$)Y9$ccqN;m51O1=2Ys}AF{toLhJXr%~A&uw*n zbYOl|$)Z+M9ef?^Pwm2ZOIU<|-$zN4 z)%vT?Jy3@-f4clNq7yt&>bKew73J2X#sdtf8CbSp9=4P*fi~{rK8v^UC5$W@tf5_ z?eL2y6%$-6Vwsl7Y>atV1TYHh@?6E5vA;fQH_Z3V_Wz6Er6e;;7fA#o{&LB# z(YkRj@G`uWo()>qy%!$S%vU<)u=D5qba5x1{Tz^nnn!jO)|I`)!{zp3`TB|Bx`#Ix zyIF&n9KQFQ#53Z(qPdwyiY6bVmdgax(j$^vZX?Xz4fa&gKHcr($R3h`XHK-!VyUM> zw=jg4IE}!sV`Us*+mRZ90>Bd?rCjwTk5X5hvUh{cgI)*h6-%X=p~o}@OPP70GR5;D z>5(57SFWAFXKsHrU`bBAhwTvOp1E!Ire%NV$+?y=Pxo59#cyX$-e5%NYX(U)3(|-~#CD;8`HE0_<>nP#a|= zLw_S0OC*`|ei$`_^o5Cr-Xcm4W_$R}#AZVA`q)c8)!^@gj2lv6j#x>glEwb@e{!az z?Hvg3MtxM(W(@Hj;wb~+m# zgE%Sz(e+cQ0(gb80eSfzDWsoMtO06k-(W@H0&t8l^~yMlPdHx5)EsEmBUG+opJj(k zn{;94&9}mY)WKxq?1+a}sIM|a{hyYkP0Jzn0^8qW35_21TbmSKapz{{axEl8UPX9P zf^95+HkRkA=wJ@bC}9hPa!PGoEEGaQe6&pe2BV%fOPsXg-SmGMxX)il&eDcAxtrX$ zlN+DdZ8p0Q@o~DpD5D)lSvfR;zLVA%H=}ku_a-}fe$A$t;t8zB9KjC`Sx7O$^LGyd z_{3F@jPyR%!#?)08~EnHGH7`AbNFHzd0Uty2ot1G0Y%Lb@uNBdqy`a+$lt(dqrruh z$c&_F4v|LLPiia0O%>rQKjNC6QFa^&zmIK{Z{UkNT>N(ei5Fqo{L^1%{@k{PNFy2$QG+5nC{AD$qc1wBamCRlD4>SL zbreMdLB$2PC+@>c0;s6yBQh#R< z=?``ULEz#gM$zRnyyT8gY!)luUjAWi{0A)jT9Gn|$Rd-HPz(_H{5eBVbR~%xjvi>1 zQW;D9il%Pm+BoXQ&18y?{B`7{UCL9+e|w4aJ+{8n4`;^O1Hxb#SSPHJN%S)I;RKuE ze?9Q~xd5Zy*=_q%7UePN(R^etL&(&~vKcHEl$6G1@Zw!o*AX@Gjp*S7mtLa7BF6*w zhcxPRZOGo9aK&8|!@h`RCQqW6-|@JN5=Jw!^el$4)tjy`{c^N>f;lEWj^h^6Xf1_m z#oB^qhQ@1bFg5jQB)Lz)Bj0Ic&W2vyL`G|L@>M~L5&6kM=o*2+f4hSwYI_ptq|@oF z$Q`2)#V+Rq!;)}^n=$sK0o&ij$If(%n^;rC*oSu86xx?WQ}=e3jA`W0M7Ci8R7Ym0 zs$-4>Jxk^0qJZQVO`&^{WXH3y0h^6eFScO}d9B;Sid2CyG2P`0MBMh2c-ACKP-k6!^ZSaZvLa2rT!Z+^WU?>Y$PhY|Cs8)C zdhaKI$cxyp_M((P4dP}?@hWNyno&(f2uF%oYa7KBO3|sq`0e&^PCTlXTv#gCRHbW^ zf;hTvTM2Ze4hk7AoPXAJ#H*A^WT2GlSo(Ktz;@%*%keBOm-|(Z<#~c7IyB-?P-=yW zk;=GnpJK<`W0Hv#MSU!rd9GKvBikkmp4X@tOBoNRUN*J;70<8`sgdP}Ia0-|OEO<1 z5jZl>dxoMj>m+7vf_z^omExxf&;xh0;l;0INOG>$yI31N-<3Q#si%a$#hsbwF5YuJ z-`F0}WWD!%HhE~0MDK?uAWL>+YAXeS);rD*#cKdGo59eyTqe2;=ko=`0+4K^o7la~ zka$L;%Vqge&sp6FvdF1(BFl^teLTj{IPCYbwRUD!v>%x|ClZ8mJnOLN!zZKti+qH( zD~Jo$z-%g||3}UD2H@Umge~tIyh2fOU2LU$faEEqGIxB`Y@Ok(V*HFO4APl~QTpzT z_~ecmg6E$~fDzrP0XE^$OFuM;G3#Bh*tS$=sd35XB!bh3aSRV;NOC^qF|C!$>ZQxC z|Dz;x4M3@8xR>T%mgvcDfzRSOlfiYS>>D6~Tw^xYXKH*4`OelmGV!@;yA_HB5JSt< zESW8~&I2ZUp=9y|7|I^1;$B>vZYwda#P?+!Fr5_H_P6`<%Z6?lO3s($3;-*+A}LYk z`P9Z*&vLeGz;5HzOMqvdy`Sn}hz7H!EXR6E&M$+M+mYkVS&FsD0Be`2wwLYs<%*}r z6Az|F7LVNcU^4Z)e65=as@W2!XE13xsY1CkQET4S7)NrZ1q!yL6e$n$NJB^mOHkCv z{IJ8D$9|S}G=SwAgvV8HYBI&!?6P*EMz+RouCq#c&#ttfNrIm02E$NI+EZYV{3xo1 z0ukW z)*=>Shu>{By1j;Bb4sR|n(u54wZ-y`@1WPf47E9^gtyMATi~?i8AtwN21jJ$wPjmv ztrutKfXBL+@OaBPuWV{P_g+AbLaZJ-;DOzs!Dl=BL% zr*JV9(tJb~(ojkx37_l5$brE@si(ls2u?inb===S#dLFfF`2H|1)Wht4UZf+rJ^sFD+_Lx}`dEA#wZ(XGx>;+pONpf?xFE;UY4(Ckll)PT zd8G^f(k%$2=B`t0uLU$1zxfC*1Bn!z9;;oN3QO9}y1K1v9Poo>$xO?VFnsGH9=&8F z4Z!_~R~J1k>9U^%A}5Ys^s+$gERg=Pha2N8Y2bwgl7%D(<{q5tdB@^yS1iy2$Z^5^ zPOI2I=%Uh@#N(CStWp3>tyeSD9B(EX!e;4))z?jcqXt(HKS#JaEQ$L}MdE4ZhT zxhAW#gy)i|GYyz$mMI;|^gjIvV>8Y7nTtx_wLB9^KA7vjwZg$-jf*Z#hxa`-^VJ}B z;oNt(KUs7Lfx`XnAXk8N93myEo@@rT2L^@~-sjR}n)lGGrFbOv#DVW=Ev*5NHAlWc z7_qMtM_BAN3xKLVK_8V>p*LPVs$g0~NdU^t{`T8J(9v*aA7#a&hG<#~2`)|VjUzvr ziQ2Ma|EqZ?y+ePOL`-q>j+v;lY8vwFEVpRn3JXt;iwbMk8qG`n@TW4`|?(801;s4K(HpM?am7`qUQvk3Z7_We9BM=$IUd;pax@4eTb9I92i z;I}75fc)X^P6dfT`idOh^GU&Dr&T?Uifu!ZS^mM~J)+YR)dyUfN~f%k^VtG2i8Q_{ zg(<&59gf;4dVa4+d5~jpT+*O*2=)D`NSJE9jAOf&0s@OBRPpbZLrr6MnCr%c3TPs&^Fi#<182 zvK?G^rZ*#!x)RpBe^2dPo4x^3erEP_*J-pzCAuVjwEc#Yzhi&2h&(TMiOU(Rks-*u z*cl8vr#Bmw>q3(wPo~_lzYcN9^{Be#!k0L z#sv%9h2P^gwS|~LbtpX5sABjl`G$LwMt~ZCWhC}hW2wDSh71$4%`e!t* z%QLRYbe5vxiTxcE?ksN`$^GoMyOSoIqaDh`$?U@`8pLfL9u3LQ)5&Tk$z;Uf$0j@0 z^5jC=p#ff1>mPCKyi@-k3K28(vV)UK_3^D|sig$=@5M7{y)<%mr`zm2G}yUk55Yupi?POrbmJ)M_ZzTDy~)g0EtrytOxIcl`ulYS1YY$Wx9P4Nqj;3cxL z7q`Npq+(+)$t=uHOU=3~S#1f-YR>KzHlEGl$>;OJ#ItX>C%8QHQ@e}bW)@_;|40mb zl1?Ius?WOCB1@tytPk|auZv=Z*u>VJxr2E0e(G8IvhY^k2PA5*t4C?e{j&?ol~Fx& zszqLZ#y`2dPRnqWw3SB6>pZW8R}Hj?TnJS5Vo40EzM}6NBx2fQr06%jG?)4!!k6w*{yX^whxPTdnfKy7dgq~r z?O}t*?Dc^Wjey_h&y_Qn-h|S(BVBgV=M_sHb93z3VU7z^{ym~9VS1kdLDZXH3<2VY zqn@;{o0DC|x`8}D#yvme__|+u_Duey6y~Zsck$_60$RcAA*pcJQdji`9n-KfF=0x5 zXuZeEX75@;$3C1E;Y%rAZXY`C?*ixGxH_+DzNFKZV-l?}2nyR*&!BT%Ti%#9=uWlMT@hL`d5NJv`DKb(9T^}OU#%%V#zh|*Z02GPml zsoFP9Bgmco>@E9Qz}!Hz2vj=r;Rd|)<0IXcV3~tF0FhK(6_99aC zV&wTiANnw=oDL|Q&cK+eg}=d5ZW2+(PD171^?tr|5FPyh36O|kYHIeFPYD@AeR0*o zTHGSX1e%9RspreDucckR@_zx1uv%4t$*)?i`d>f`tyi(DS2Ra;<(o8GLkfD}HPg(;d!C1M#u+<$V*vd7pfl+_Nx=mO4kseUCPu24C9k2q zMXMCto-|U3gWek!!1)aIvZ>|P(C4+KEJ+Rl`MV$XbjYbhAI<;EV&W=g68?PNdhWx5 zEjiE;#>f=fRUzcJY$Z*kN-0PyON{u+B3q_adO1)Ljt>h2w47ZiaE#=K<3vQuFp>CI zZ(7T}Pbf#?<%fOTR6elyHSr~Giyoq{zUfH|0x(|gS^preH$K_~WHorI#>b*yqq;9B7BFYR+N<%BK^G3*u{6KXw&=!=SD_ z2QUP;PmT2;PRD0}BJe%3#%FIF>Rx*16rH{xN|E0)%DCe$h|zXbGriXvWM=vWTGm}k z!2svI_L3(@fzs4bxW|GDk$6CVx|Hk<5Q?hJktfA8ZgqRv@qbODT?ay+&l<YKImkg{t#iEB}?!X=Q^nhl?vF=;uuc!7v!2@uOyRB)H! z&&y!1SgkWf`aPoB2-*XCC+k(BruZTF=qBjtfo(FyHsmbT_HK^F>;PrVi}5TU)s-_a zR{Zn~li`h@nD2PdjgDDJXUDLFp~$iI!h(GdpqHWIxe7&Y7P(llwksqc7I06##OZHf z+B`Sam6CC+w(ESFSKUOtDsZfiXMfy7=mvHlPdR9oY|5fmoT3{Th|)2&5%ZMzIzl$% zWLno)k?y-V+QJay%CDttpJHASoby)cOw0PcLl*U={S@o>7!0du=Xps&9>M38)*u?Ocqnt7Yfc5uCK z=W4d5W*Z2Q{Ak?6$D2nTKdv6r9^92cfayy45?>UG@JaSS?(XCu4X~W7kOSr_S@aJ) zTYBqE1Sm!qg{CYr*wze|2OJRUH&T{~Vrc%*$GhRWGo$;?T+7`aL@Ue_jit<)}`sS-+SvS{XqQk z=LR(XM|ySLLd_#T9ZxbD`m8Dolv$+=nzb-(gd`G=N?HKtM?{2iEKWXiqBAX^>j)g6 z(|qh}97bo**)u~JHDarrC_DTG6ouCz^RldcuMkWN{|gdro7+%;q$7LBTX=f(hW3O& z@<;jr$PlJgCWhc?F<{xd^imNbdms7}wK}Re~?PBrYDZPq4TLG=jD9eRbwHgcp)3Lu4Tq@;%1O3l>0t-&0 z!qj$DFaLX0w_)>Fjet`3^RUR17TYl<5d8eYJT`_uKMS2;Jf;~y z2Wk~!?RMS{s^ey(f${c+zE*AoQWU1iNr!At$+YZP4(${f%A!q0j7ptp>Q|Z`da=me z;^;sk*8;OdW_xGLFVNsr#%9;%KENO_4Y~ra zg1P@|lze5ZHxV~s&f=>MioHeT<2Q6=2y+szy`U`5oOhk`j3Vw{iw!}oblPo>oJRy0jc>apOesQczF2=F9)*Nldjlc zwsiUkPDYzBn2}M9eNH@9YB@QfVBn(U78Dz^RTWPv<%(awr{fYXe@#@O;J)Bj$iM~% zR~0<*8@k~E2%ZIn^=v0w{3#0k))vv!->X6!_D!R;19^bT3l28xJyoH7Mq-7hS9Uo8 zIqLB4T6Eh-+oT8_j40!N8fjsJAlffM;Cdz)jz$mn60U(H^b2Way zL`pkj|6zMz&_dM~E|gg0c z0m8nT@xCC}69)ekZ~>*w^+$4kq$@;FbGy6$yj&2ZlPS_Z0RiTW2Y;});t^fF1 z$GM?bd&$CIVVrN&rMEBk-G|)TUrZwaI#clSf(j1kW&6TX&xH7Wcg3@)7eLdb(M}K0 z%p$RRN_;;+TFGizd&9JS=&d(4T?L=H+o+fFn>;=IVQff|Jmcyg_o0Sc_Ak6FB^QW3 z16y@41@8SWTD|VX@(@uq=zV%vn8CKCUh3+s8siUByjs0NAy@4~KKofzG*M6K^7T*l zcsV>S@o58o%d+XCn&YO9(EXW5kC0%O1qrDZ8iCB}XaY~WJaPddyjQnk1zib4c|37d z;5u*}L(L&&igga7k$Xdy(&++FS%ydbveQSVJu?(`t2*!$Vve)aHLH)@y=(IT$#J&9 zPb_HiyzLnbutw|UB8>yGAky}&jCLJ!TkE6oz-OlcU6XE7A|indCa09s!2~e8W(Cb~ zE@hGr>i&rffW3A#2Wb7xOirQO?-^Y+62MCbE@p7n`ENCjgte<5+fK7qF6R~gdnKJ{ zV5bd?JK)Q3NbRml3DmOHS6Fl1+Gq~|I75ij`*%J@LJ}7)SDefOCp4(l9}V*)m(9rQ zN{aw19dscYdyx4y0Mk*^q#*VT4vybh23l~S08sdNc_%o{K#j3NF>L1?s_Nb#%gNOH z7&{oW8lGarBhW1^a|qDXLgbr;Geb%Y{L()z&`|pMco2{%=s5k!(FjVVY`Gxs^`bF*!H5$1E(#DAq1khb@rq2 z`+?wG0Jq-hM~vrseMFzmZ=-z=(1UvA;?(F*VJhk866HF3*{Du?$yFVNNPk<^KB2*a z3&ud@1%gS^=+ob2I;+G6qU;Xay>#MZx<>=kq$R}C?>S`$mKH|7WvY?3T9k_+fKoYk*v3$-y8q= z6bBk2I|J*gY09O$=)*-m7Dqdw^vY?T;cVdAkij$RP5z*dY(TO$Jv9A(E{|Ut{p3nl zMGHuxxvTRcWfK2t&lYLyiy z?ML_`Wdmn{8>wvYM}R-s@VYh9m&2-8|)q8+C-IFc0EzJsKa;Iu;%RoJXvg? zFcVy>Y%7Vk%h6ts6%bU%t@Nl-IaOYVKyGM5pAEc5r%*8T2L{L)#FcO2*7!b7AN4^J zAh<=MGlK)L%|)kOP1nRYPuAycSsc0mnSH#B&N-ET_y}?FVvk3i$)9dDFAcs2iV#t}d&8bsuA~i( zI3J#R0o+?6&qFU-924As+~5}_gC~T4Ts;{UoO+>@)e9u>X}NrZBJ_0fGUrl`{JMb7 znBcyoo@mS&L?CCF>o?bKWg3dMYLMt~B2_TnCXmbt0@aM8y*#JM;=15=Cb{^Rg3Fgf z42I%5W5Dj0j2pXuPa*{;kzTKPwKL=f>1xnx|RLYV7^!$rfoR zGUulkzW5=YdhuaT=t<(VVu`}GfG6`S1`@QO?|J1G|CW z{DjlF#x={Fb%;E^Z24r%01DhdzD{?XT9eq{v`4>M>%ByoQ@uN{!j{Kf_ff8)jw2gc zrf+7^Ta)Sqp8(%V`DWdPfnRJ>^q3!jJAzuDkcvB`5zM)Su zfS8|dJGL{}Ag^xK*$U6$157NIDy7xiiMqHcS1^e7G+{O8vEFfq$wh6Hep_#gU&KB3 z3Bn0shc}GkVc-}PXzmap>f+PKifd8~81V|+ns9JbWISy%@~Am>@2 zu4(hexW!QmExR!RdTQSaKN~HWIErtN3EvJ1rMlU7^{b5aBjRju_qEluXA8k|1L+;( zL9!lmi&>R>pAZI~3Aeok+Q)$R_ju&XZ^Bb%(e?+(+R&GJsA{`X1ry`iu_L>2ivsf|;(Tu`Z1EPww>erZV;>V$j?)kGkI2oTNlSY`0| z96Oi$qhj8QHpbLYhmISn&Z`T2eMe9}_mWQ11%?Z27p=(71zy$0$eTYIC>KM_gEtir!oxpUZG5qO z%3VYowjta$pbV2Pvg6$g5atKtY5O9VA@Z{~?z$T--k^d^RtlXVlg6(!%NsVOrV5l|B)v z{JdpU%U0WCR~>~jG^?)PW%J{fB3vipr0Yl8vCNNz*d)4m1!6yY9$AMBOs2}!5vXvE zI{lj*lj9C_Yx+AhH9d`bp*cxJ6i0(W0L54u(z~D4!@gD*Zq~4z&*0h55%CJgnw9@h zj||_S@)7k&+Q;40h(FOjA2lu)+AvLRQ-uThZb{pr5hi#Nrb#*S_sX89<=|$U+Yq`V8;ha@V!Xryx{gR-&u^h2I9D_oe~|9 zY@Wr6ow%!l*+(qJAb6$*FgS}1(wiS*?iNEbdIKYN&Nxr2(d$LvPtPJ)hPGMe3BJA! zi=Fo$2!P18_CtHFmcwov+^svvW_)m%P4`2>XOPWW)jQ25IDXe4d_18j^MfV5@gV%K zF~uqHd{Z&9kdRyavdJRR+c&hg2m_%~{_y;ILmu0Md*s+{n*Tc zLvFg%7IA7j?W=RlGE^@IRqyGspwb6DLH>t%(+*gq0522^yizXoA^$!jxcw5kTO$@b zQ@%6AvXNpa#QKr$!yas984@xTjiAv|uEWSDYaRY=EzUuR#}3};bJ<26o2jXV9bkSm zGNFI${gi~GboDH}0);v-4OcI^u-&tK8*Ha6itvB4iB{0s+Ua+4)F-L{tNo_Q>PdoWXxpY`QFaeiJ93Y=qbsWW!Ueuwf{x z!>9>C{}jXw1RpvG)QcX#5ox&X8}F#Ms2v&L|KUi?t9785f&$vTz1>J_) z;=B6nsK6Xx<|HzVIKV&HM_|!pjm!~Q$a!sAV}2Qf_Crz@g5s{x;!-s-PzDWyW_2!Q zNZfXxv^;LCksZz(ZW<0BYy;?BhUWE&PHQN9F}+C)Kq`hiNaIgl$wH`Xt6_GHtSyge z=ylN)^w=E!-2V9OJEV<8IW;odJbO(*li3HP((s6*F@3C|;I(%`X1z4K6-q!oLqfMk zxBgI3CG3X7R@?LnFVjI9bMMxf5(WiX%NWmI1^O1n2Y9!2j~}Yyt=nK{Q7^o_)T{%4Loq{wEFu4;hrnIe#6+5O^ zcO#MCi<+*54^dS%V9ZkxWbH`#KKN`ScvsAo1Z=*CSbK4PC@I72rE3S6n4npb$Lu(=h{8DgEp5ZsPial}f{-%h%4CW}{|)zIQhzNOF$OerEru|ulXRZ?<7a1Ht6UuqxnMU71{FRv)uT2cv$Y3JFkyz;yAxb%!q zdQ+`?EF)1}=jf9)hk5EmPy{y=-hR=KndjJE3NVO?_;q(>u=&W zDDAjGbG0XeIE1weNzlM-bmmFy_;%-syIvxDGdS+gPjQDFMxJ)&OmR8O)+Y4LR-oto ebe3CD44H9!K+2fL155<`MvfRW{NON|^8Wx?*P7}8 diff --git a/Sora/Models/EpisodeLink.swift b/Sora/Models/EpisodeLink.swift deleted file mode 100644 index b0aae5f..0000000 --- a/Sora/Models/EpisodeLink.swift +++ /dev/null @@ -1,7 +0,0 @@ -struct EpisodeLink: Identifiable { - let id = UUID() - let number: Int - let title: String - let href: String - let duration: Int? -} \ No newline at end of file diff --git a/Sora/Utlis & Misc/DownloadManager/DownloadManager.swift b/Sora/Utlis & Misc/DownloadManager/DownloadManager.swift deleted file mode 100644 index b9f5b15..0000000 --- a/Sora/Utlis & Misc/DownloadManager/DownloadManager.swift +++ /dev/null @@ -1,223 +0,0 @@ -// -// DownloadManager.swift -// Sulfur -// -// Created by Francesco on 29/04/25. -// - -import SwiftUI -import AVKit -import Foundation -import AVFoundation - -struct DownloadedAsset: Identifiable, Codable { - let id: UUID - var name: String - let downloadDate: Date - let originalURL: URL - let localURL: URL - var fileSize: Int64? - let module: ScrapingModule - - init(id: UUID = UUID(), name: String, downloadDate: Date, originalURL: URL, localURL: URL, module: ScrapingModule) { - self.id = id - self.name = name - self.downloadDate = downloadDate - self.originalURL = originalURL - self.localURL = localURL - self.module = module - self.fileSize = getFileSize() - } - - func getFileSize() -> Int64? { - do { - let values = try localURL.resourceValues(forKeys: [.fileSizeKey]) - return Int64(values.fileSize ?? 0) - } catch { - return nil - } - } -} - -class DownloadManager: NSObject, ObservableObject { - @Published var activeDownloads: [ActiveDownload] = [] - @Published var savedAssets: [DownloadedAsset] = [] - - private var assetDownloadURLSession: AVAssetDownloadURLSession! - private var activeDownloadTasks: [URLSessionTask: (URL, ScrapingModule)] = [:] - - override init() { - super.init() - initializeDownloadSession() - loadSavedAssets() - reconcileFileSystemAssets() - } - - private func initializeDownloadSession() { - let configuration = URLSessionConfiguration.background(withIdentifier: "downloader-\(UUID().uuidString)") - assetDownloadURLSession = AVAssetDownloadURLSession( - configuration: configuration, - assetDownloadDelegate: self, - delegateQueue: .main - ) - } - - func downloadAsset(from url: URL, module: ScrapingModule, headers: [String: String]? = nil) { - var urlRequest = URLRequest(url: url) - - - if let headers = headers { - for (key, value) in headers { - urlRequest.addValue(value, forHTTPHeaderField: key) - } - } else { - urlRequest.addValue(module.metadata.baseUrl, forHTTPHeaderField: "Origin") - urlRequest.addValue(module.metadata.baseUrl, forHTTPHeaderField: "Referer") - } - - urlRequest.addValue("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36", forHTTPHeaderField: "User-Agent") - - let asset = AVURLAsset(url: urlRequest.url!, options: ["AVURLAssetHTTPHeaderFieldsKey": urlRequest.allHTTPHeaderFields ?? [:]]) - - let task = assetDownloadURLSession.makeAssetDownloadTask( - asset: asset, - assetTitle: url.lastPathComponent, - assetArtworkData: nil, - options: [AVAssetDownloadTaskMinimumRequiredMediaBitrateKey: 2_000_000] - ) - - let download = ActiveDownload( - id: UUID(), - originalURL: url, - progress: 0, - task: task! - ) - - activeDownloads.append(download) - activeDownloadTasks[task!] = (url, module) - task?.resume() - } - - func deleteAsset(_ asset: DownloadedAsset) { - do { - try FileManager.default.removeItem(at: asset.localURL) - savedAssets.removeAll { $0.id == asset.id } - saveAssets() - } catch { - Logger.shared.log("Error deleting asset: \(error)") - } - } - - func renameAsset(_ asset: DownloadedAsset, newName: String) { - guard let index = savedAssets.firstIndex(where: { $0.id == asset.id }) else { return } - savedAssets[index].name = newName - saveAssets() - } - - private func saveAssets() { - do { - let data = try JSONEncoder().encode(savedAssets) - UserDefaults.standard.set(data, forKey: "savedAssets") - } catch { - Logger.shared.log("Error saving assets: \(error)") - } - } - - private func loadSavedAssets() { - guard let data = UserDefaults.standard.data(forKey: "savedAssets") else { return } - do { - savedAssets = try JSONDecoder().decode([DownloadedAsset].self, from: data) - } catch { - Logger.shared.log("Error loading saved assets: \(error)") - } - } - - private func reconcileFileSystemAssets() { - guard let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return } - - do { - let fileURLs = try FileManager.default.contentsOfDirectory( - at: documents, - includingPropertiesForKeys: [.creationDateKey, .fileSizeKey], - options: .skipsHiddenFiles - ) - } catch { - Logger.shared.log("Error reconciling files: \(error)") - } - } -} - -extension DownloadManager: AVAssetDownloadDelegate { - func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) { - guard let (originalURL, module) = activeDownloadTasks[assetDownloadTask] else { return } - - let newAsset = DownloadedAsset( - name: originalURL.lastPathComponent, - downloadDate: Date(), - originalURL: originalURL, - localURL: location, - module: module - ) - - savedAssets.append(newAsset) - saveAssets() - cleanupDownloadTask(assetDownloadTask) - } - - func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { - guard let error = error else { return } - Logger.shared.log("Download error: \(error.localizedDescription)") - cleanupDownloadTask(task) - } - - func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didLoad timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges: [NSValue], timeRangeExpectedToLoad: CMTimeRange) { - guard let (originalURL, _) = activeDownloadTasks[assetDownloadTask], let downloadIndex = activeDownloads.firstIndex(where: { $0.originalURL == originalURL }) else { return } - - let progress = loadedTimeRanges - .map { $0.timeRangeValue.duration.seconds / timeRangeExpectedToLoad.duration.seconds } - .reduce(0, +) - - activeDownloads[downloadIndex].progress = progress - } - - private func cleanupDownloadTask(_ task: URLSessionTask) { - activeDownloadTasks.removeValue(forKey: task) - activeDownloads.removeAll { $0.task == task } - } -} - -struct DownloadProgressView: View { - let download: ActiveDownload - - var body: some View { - VStack(alignment: .leading) { - Text(download.originalURL.lastPathComponent) - .font(.subheadline) - ProgressView(value: download.progress) - .progressViewStyle(LinearProgressViewStyle()) - Text("\(Int(download.progress * 100))%") - .font(.caption) - } - } -} - -struct AssetRowView: View { - let asset: DownloadedAsset - - var body: some View { - VStack(alignment: .leading) { - Text(asset.name) - .font(.headline) - Text("\(asset.fileSize ?? 0) bytes • \(asset.downloadDate.formatted())") - .font(.caption) - .foregroundColor(.secondary) - } - } -} - -struct ActiveDownload: Identifiable { - let id: UUID - let originalURL: URL - var progress: Double - let task: URLSessionTask -}