From eac69963f00a1962a76efa8853ab295284b18583 Mon Sep 17 00:00:00 2001 From: JackDandy Date: Thu, 24 Mar 2016 18:24:14 +0000 Subject: [PATCH] Change validate and improve specific Torrent provider connections, IPT, KAT, SCC, TPB, TB, TD, TT. Change refactor cache for torrent providers to reduce code. Change improve search category selection BMTV, FSH, FF, TB. Change identify more SD release qualities. Change update SpeedCD, MoreThan, TVChaosuk. Add torrent provider HD4Free. Remove torrent provider BitSoup. Change only create threads for providers needing a recent search instead of for all enabled. Add 4489 as experimental value to "Recent search frequency" to use provider freqs instead of fixed width for all. Fix searching nzb season packs. Change remove some logging cruft. --- CHANGES.md | 9 + gui/slick/images/providers/bin_req.png | Bin 345 -> 0 bytes gui/slick/images/providers/bitsoup.png | Bin 3410 -> 0 bytes gui/slick/images/providers/dognzb.png | Bin 1054 -> 0 bytes gui/slick/images/providers/hd4free.png | Bin 0 -> 621 bytes gui/slick/images/providers/morethan.png | Bin 398 -> 600 bytes gui/slick/images/providers/newzbin.png | Bin 979 -> 0 bytes gui/slick/images/providers/pfmonkey.png | Bin 0 -> 1200 bytes gui/slick/images/providers/simplynzbs.png | Bin 0 -> 463 bytes gui/slick/images/providers/the_pirate_bay.png | Bin 3539 -> 673 bytes gui/slick/images/providers/transmithe_net.png | Bin 784 -> 982 bytes gui/slick/images/providers/tvbinz.png | Bin 349 -> 0 bytes gui/slick/images/providers/tvchaosuk.png | Bin 1002 -> 937 bytes gui/slick/images/providers/tvnzb.png | Bin 754 -> 0 bytes .../interfaces/default/config_providers.tmpl | 366 +++++++++--------- .../interfaces/default/config_search.tmpl | 1 + sickbeard/__init__.py | 126 +++--- sickbeard/common.py | 3 + sickbeard/config.py | 4 +- sickbeard/db.py | 12 +- sickbeard/nzbSplitter.py | 8 +- sickbeard/providers/__init__.py | 28 +- sickbeard/providers/alpharatio.py | 22 +- sickbeard/providers/beyondhd.py | 13 +- sickbeard/providers/bitmetv.py | 25 +- sickbeard/providers/bitsoup.py | 120 ------ sickbeard/providers/freshontv.py | 37 +- sickbeard/providers/funfile.py | 26 +- sickbeard/providers/generic.py | 135 +++++-- sickbeard/providers/gftracker.py | 17 +- sickbeard/providers/grabtheinfo.py | 22 +- sickbeard/providers/hd4free.py | 81 ++++ sickbeard/providers/hdbits.py | 20 +- sickbeard/providers/hdspace.py | 20 +- sickbeard/providers/iptorrents.py | 39 +- sickbeard/providers/kat.py | 52 +-- sickbeard/providers/morethan.py | 22 +- sickbeard/providers/newznab.py | 100 +++-- sickbeard/providers/pisexy.py | 13 +- sickbeard/providers/pretome.py | 16 +- sickbeard/providers/rarbg.py | 13 +- sickbeard/providers/scc.py | 30 +- sickbeard/providers/scenetime.py | 36 +- sickbeard/providers/shazbat.py | 18 +- sickbeard/providers/speedcd.py | 80 ++-- sickbeard/providers/thepiratebay.py | 77 ++-- sickbeard/providers/torrentbytes.py | 45 +-- sickbeard/providers/torrentday.py | 41 +- sickbeard/providers/torrenting.py | 38 +- sickbeard/providers/torrentleech.py | 14 +- sickbeard/providers/torrentshack.py | 20 +- sickbeard/providers/transmithe_net.py | 30 +- sickbeard/providers/tvchaosuk.py | 23 +- sickbeard/providers/womble.py | 50 +-- sickbeard/search.py | 77 +++- sickbeard/search_queue.py | 25 +- sickbeard/tvcache.py | 36 +- sickbeard/webserve.py | 354 ++++++----------- 58 files changed, 975 insertions(+), 1369 deletions(-) delete mode 100644 gui/slick/images/providers/bin_req.png delete mode 100644 gui/slick/images/providers/bitsoup.png delete mode 100644 gui/slick/images/providers/dognzb.png create mode 100644 gui/slick/images/providers/hd4free.png delete mode 100644 gui/slick/images/providers/newzbin.png create mode 100644 gui/slick/images/providers/pfmonkey.png create mode 100644 gui/slick/images/providers/simplynzbs.png delete mode 100644 gui/slick/images/providers/tvbinz.png delete mode 100644 gui/slick/images/providers/tvnzb.png delete mode 100644 sickbeard/providers/bitsoup.py create mode 100644 sickbeard/providers/hd4free.py diff --git a/CHANGES.md b/CHANGES.md index 960a1382..3f744042 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -64,6 +64,15 @@ * Change instantly use saved value from Search Settings/Episode Search/"Check propers every" instead of after a restart * Change include OSError system messages in file system failure logs during post process * Fix find associated meta files to prevent orphan episode images +* Add torrent provider HD4Free +* Change validate and improve specific Torrent provider connections, IPT, KAT, SCC, TPB, TB, TD, TT +* Change refactor cache for torrent providers to reduce code +* Change improve search category selection BMTV, FSH, FF, TB +* Change identify more SD release qualities +* Change update SpeedCD, MoreThan, TVChaosuk +* Change only create threads for providers needing a recent search instead of for all enabled +* Add 4489 as experimental value to "Recent search frequency" to use provider freqs instead of fixed width for all +* Change remove some logging cruft ### 0.11.11 (2016-04-05 19:20:00 UTC) diff --git a/gui/slick/images/providers/bin_req.png b/gui/slick/images/providers/bin_req.png deleted file mode 100644 index 99331165008d0f4f4590f668c3ed1daf05b28cdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 345 zcmV-f0jB#ODQ+%`68vMR0H|a| zw8m8;`Z`TvOi6|?CJRKfR>x5z+9eSndeX5GB07wzQM%EPX{9A&WSW-(_EhnC)8j^Y)jv=%72EM#Bwigh( r;v+UaG)!~aKmya#ztzCQ^%GzK>IZEl_?-r700000NkvXXu0mjfRIiI2 diff --git a/gui/slick/images/providers/bitsoup.png b/gui/slick/images/providers/bitsoup.png deleted file mode 100644 index c20762e91976edd648835b99f3fd27ee15222136..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3410 zcmV-Y4XyHtP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0007gNkl&2Ljj6vcn{&e$(b;=Eu;)ex#S2~vcF_*i7mj(?Fo>ZXfsijY`A z6tz_gg`@(cU_@{T4#{)u*d+dX@6GMP6upSEx@R=!YBc8@Ns^=i#1tR`QX~duhVc!$ z9=Hh16z^xbk>?XZFi?T0q^L}I0p0`ISLTHNDCgDtKFv->ub=bjcu2_^cW%vdbES&I z$n&oYGW~yYPU!VBHeY@w(}>$^3tV5Vv2rD*bqe<$G#0 zIPXwZyo!({N9@%1*=f&n)Jbt}A}YcVL>sr_cUj;k%Fc7caKxb~`Lxs4^J8p_9%t%p-zE7>bDDB~bA> z7pF)3bSWj$GL3^nTE`t^dwct2V`C%U+iPHXit`?I5zd!Ub%;!YBm_b>Vw`1wWAXB3 z*4Nj&(r&j;hJ!)8ySvL@&tLPhzE310%0A$}ID|UV;E2i<)|MApS^kmbl~v+6?npesp|oEFQZ0$G?8s(9wVSZn9YbmoEM oVxfY8Q}B8|2xi}i0lNPU05+c;N4vdK*8l(j07*qoM6N<$g4oJqGynhq diff --git a/gui/slick/images/providers/dognzb.png b/gui/slick/images/providers/dognzb.png deleted file mode 100644 index f99e0d6a696d62f519360d51e15f99367e549ae0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1054 zcmaJ=TSyd97@o*P1;q#hh3GIwBD6a*dvkZ#&Gx1)IHK!m z4@wZU`4YVd`Bo_OAb~~pP$(qy&>gAhLiJ=9B9NfYth;LuZ3Ab{h41_R@Bhz#W_o)% zYipWnD2l3$bw%Q2uD3>2CHWux{#ztdBaS91LY0_sUV*)uax)V zE2~%F%H_QT%W@fFhOw^ouWK$Ik>0VErKTmDQrkm~^twTsy7OWpM;^p%ED}s)U(WZ> z)UJT4*$4Od+%??LGIzDF`+ohe=IYkm#*g#+PPR<19*EM9*7kb2Nnz>=^_l7Yx!B;Q z>K`_$i`S3MU#{+ZdpLY!WxNjVe{!mGN~`-?v2p16u7Qf>H=()in|q#Cth?7&S|?u} zm!;J$ZQ=FfcUxR#(}|_jvrC(Id>3-JwmuDhe6h6frJAMu>(lSge*19Sda8bpDGOgSVk&yWmEBCQ&))*fTY2r-c)n=bMq z@Q8f2z)(LGytx=Rrf(B46>d#YS+!_pY;xHgN?X+59zivteU&oGl`2~Jgk=J+sW=n~ z5p+z#a)er|%-G>1g*B%yfRqbWK4q53x4%#`)2!}1Wu^3-iL*(*Ro*c;8YMPnphG6E z6g>dyPFp;Dwz0;{-Ae?*nhO(ioJvjMt8H9!i;2`pmOn327%#H(-6dG<1`zW~>9Wv# zoV5wf1{rXM5lB3(DVFmjh7>ZNUv^x5hEJfyYoOr{6ECZ6`O+y4G33n8#OZ@cX?@}WT1l(bBVIcPC{&E`izliw~gT=y^l zCB#01gKRfY*P8WFO)4XZ2+=h{&u8jdP{)UbU@|KZy&~`%+E~`lpr?jU00000NkvXX Hu0mjfY{V1- literal 0 HcmV?d00001 diff --git a/gui/slick/images/providers/morethan.png b/gui/slick/images/providers/morethan.png index acdd6fcba4d725f4e6074dfbc19a3fcf37f1018a..a5d0c6529b85678cce4e2d005a6f5fdd6b456cf9 100644 GIT binary patch delta 576 zcmV-G0>Ax^1K0$RBYyw}VoOIv00000008+zyMF)x010qNS#tmY3ljhU3ljkVnw%H_ z000McNliru-~$;DI|!a`7o7kA0p&?VK~y-)rIJlg6JZpEpLeD+6T)-~jo2=HTb;HV zTT&KEv~|TsB(4j@kTenE4=^rG3<*1bMVAdhmas4Z76pw9U4MuRjjhR;Q2c5NTE5zj zi;@P#CN!Si&AIov$+=emjpk8(&vly>p{k#Y^9$$qw#reU42+81uisuMhJHiUbr)xj z_xE2m8;!1RU)%lyK=u8HHIb9{6)PH<>QBTk_Y4e#HOm`R4WmzZJiS5))pgy5Td)6W z92{1JA~~GW!eak!>C+%k2X2d;v^~HSFajI^%?^v*V=n>JfTvlfxbhqP2#?!UNB)EW O0000J6#U(5`LvxP6jFu zl0$rh8+bNOwH*I%VvqMtaB;L?ewjm@4(ALr`gh1`#=Yv#vD3!$Sxizbn>oa7yv0$f z<@T}}yhCZ@0~}!^hqyNvw|B!!NVOcy1*w+(Cef1jdg5V0pB&;ws^!q^+#g{ZhpCoH z3+a{#<^f-Fh;2J~())IVN%;-p&I`zR-yDKP?T0HLMiA+F&0DXhhTrC2qKCfg8EzaL($e+EmT59 zL`u^@(#Eudc{I<-B)OTHd+*$HJSl!OxM9Kh*n91>*V-E$eCH#egn*UG0<&x&lmUPQ z(QfC$FgVq2hc9ZBo*`8GCXxV;6tj@z6n?yN1yJMzh6h8+O}HxgEY___JDGW7`?gZ2 zl}LR}7{3?^SqaIFN$hbG2 zd1CupQbtq=0bv*d7Kr2}rbjT-$Cw#=zY(;*i)lF1-&^|RPK)gLzPh$6K(y9uwqAO+ z^7sjXwR7XM%Xe+tKG9X|a4C&B??!+QJMp+Nu&-}y&huYgkbG#k2B(^>W~1V0d|N#K z?FHSsIXvrqwm3Ia#}bK?M_&Fk9k+^<>86e_PA$~e;o8__fhF9@IyXA0&Y&*?zjxW( z8`*%P$dIqp<|f7$7MDf}POMT$TcD=klxPfu65z4U0{p$W8V}}I9A?-fh3+m|HQlGG z8z9!_mu`*U9GwY#e=jwx3b!3VN;XBH9Apd$>u6PG{I*4x}DBHC#C$;jM-q>352QAfGPs1o(RE3gk?t%!QO`IVi=}m zTyLy~aA>g^jk$4)an5&ctkzC4!vd!Gu@ce4ibNt{ir{IC;C$T|=jKD|Wz$I`mvYSY zP=+PfJ~mL!@90k3%}lBH15GDDxmd#z(2&~o{f?zy5E6DPoJlY=(34~b5G6t)g!7#d6zySTESiMm!Rk#2E002ovPDHLkV1fa8 B)=2;W diff --git a/gui/slick/images/providers/pfmonkey.png b/gui/slick/images/providers/pfmonkey.png new file mode 100644 index 0000000000000000000000000000000000000000..bcf5e7cf789d4149100c2d35366678966c427999 GIT binary patch literal 1200 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl4m>B|mLR{OU<$xk-uHyH0G=IM^ zb7qz%kUI)SLtuo2K*@(AYZw?98A^iug8zd71B4oZq{5Bhg}`W!_jGX#k(e6W@6E@c z$m7K6^}hbe#)K<9voBre7gb$3kDW1Li?=|xqUOTiq6X~G9X|5=?PFtlB6{z@*2iaa zXE$ccU8rp46PLK;pu1x>Q`Gi$#u~=&?bl?znftvZ=T76-yv=-yImqZMD1~{t`njxg HN@xNA8>&6V literal 0 HcmV?d00001 diff --git a/gui/slick/images/providers/simplynzbs.png b/gui/slick/images/providers/simplynzbs.png new file mode 100644 index 0000000000000000000000000000000000000000..92d1486656716084b6e2cc225e169aa66227074a GIT binary patch literal 463 zcmV;=0WkiFP)4c<-^+;+&(`>#{oo91f|~Y5XRhdzXd^0r_5JKViJpygg!rxSqw_^YR002ovPDHLk FV1h$I*}eb( literal 0 HcmV?d00001 diff --git a/gui/slick/images/providers/the_pirate_bay.png b/gui/slick/images/providers/the_pirate_bay.png index 4d209da3515795cfef9908c4ede43dba2902eabb..d4118c8cdaab5f5b1222f05949bd4d7b7626c185 100644 GIT binary patch delta 649 zcmV;40(Sk=8=(b|B!32COGiWi000000Qp0^e*gdg32;bRa{vHLy#N4Ay#eQOty2I1 z00(qQO+^Rb0~rwz7i83pHUIzuE=fc|R5;6xld(!OK@^3*86zYpl1&r^1yPbf78C>} z2sUD+U~iMg#zvcc1e-jC`UnaZ5`rw)Z9uTtnABDgg1D^6B7d`cEhNDh@&8YCVD6kb z_nx_mZ;&tWFKDe*pQrky-EPa?-X2jDp|$??Vqd)7ZcDjbRzm{5?{jl=!~ekdeMTIl zQUl8P_&9MKV_6n)9215i07;S{B15$!URPFDxWB)rTCH+%ae?P~93CEWd3i~#RvU4X z`q^J5lOdna^MCR2!O6)9>2w-n49CaE1MA-hJrH<#c>$o=Y+~CsK@beRw6(Rx`}_M) zEr6C^vI~NM#l=M?CMEzVl}bcWL>$LIBNyFjwQw8%J%j)r>Cb(PEImAJBwvmynnsDVT?gU5D_w&3|ecn)~v6u zGe19%>$;>GjRpX&>yji1OG`_vuCB7Pvx9BhgUDWAUwM3dq|@neetr%>qtQUs>vg%l zzQ*@`j*gCaczEFK?2KNo$Mp0x#bS|ew@Va76bc0v78ZDZe#W+K_V@QuA|l;xmvXsG zHk)O6d4HLinHi?0rYMz4BuRqjd2~7*^7%Y#YinFxUEz5ib8~ZF(+tBi2qWTB@BBhl2 jYmxfjMk$3-N__%o?L$zT7+!|}0000FOw0}eAZu_2-Y5k*7< z6+wa`28@Oxu_B6vfMCHMkRYJMU=&eNc{8$Bbmir}mzUokXMcTbpS|}zXYYO1x&V;8 z{kgn!SPFnNo`4_Xg z0)Qfk?E(%fNyMfiCh@~U+(f(-030dtD~|t)1)Lm#_)>1^8M%CJVv>Na%hIEp+1fJb z-kj`IjzC}(#AKx~`E0sddRhjPmkYq+oj*%PTwA)R$bZ&mw$|20=Ei1U73#lk{!NK{ zyGXBsKlcox^?kAZm0x;20E}5tZFYRI#qR~6V>1Bq_rKUQ4+0=5>RbE3SNEZb=OsxX z$gndp$L{!k0Z0NWPyi}G1Ly)HU=D16J#Ypdz<(D6f-n#TRsj}B0%?E`vOzxB2#P=n z*a3EfYETOrKoe*ICqM@{4K9Go;5xVgZi5G41dM~{UdP6d+Yd3o?Mr zAqM0Kc|iV92owdyL5UC#5<>aVCa44|hpM4Es0sQWIt5*Tu0n&*J!lk~f_{hI!w5`* zseiCCtPPvM4A=$sgTvsJa3Z`K&Vvi#?Qj)b4_yPPlex4vr&>=Vw!hZ7&wDr6*;uGTJg8GHjVbnL{!c zWyUB7MT6o-VNo_w8Yq`2<5Ub)hw4L3rj}5@qxMs0WMyP6Wy582WNT#4$d1qunl{ac zmP#w5ouJ*Jy_Zv#bCKi7ZIf$}8dZN`iSTS4ifZ`>^=_S-9_DfhxikF;Na$gBn(pL&mTBCGGsZVKESw-1PIYW7`@mn$4Q`weVUDtt72ITD@9x+B(`1+FP_cv?q1s zb$oR4beeS@>XLPxbXV)v>)z7C=rQzC^!DrB(1-P{^po^!^al)J18W1W!G425L$sl- zAyeeqo|%5^b{6q}Sw=sg-G}X@7(112Y*jU$X+U zF0n%DhURoMhax4#6-nF7w1z2sd>bCl5ZDY;1Zn2)S(X@%P z*=IA%pfZ9OrHm`KXj@m?^|q&N-`QE)3G7bT{bp}upJIR1esZbKQqIzbrDG224ortS zhY?4*W1Qnb#}OwrCx50>z0(tC4QIAWs!l zhetO?&#v%Tv3tdMj8#lg%$=1wD|1#}U8T4xb=8?z$yjFW$vAXeMBLH156nPjJ##kR zCw^c249ktRhkx~)?aZ!VPjMVL<(!EGhlKKk$wY_5U5QgkPDzzX(_A-hHTPw*cXDm= zTuNZd;gp5ch}70JTv}Y(DV_{3h1Zj=lAe=3m|>7nlrgf}ZuRcfGkiaOVpAd!m-U>o12Ryiugst zTkN;gZbfb7ZtdS@v2E|RPsQxwYbB;7l_eiaS*6#$G5e-n=E9e!)6|Z;4?!H=SSy{V>ut&IOq{_dlbFb#!9eY1iCsp6B zajj|Hr?hX|zPbJE{X++w546-O*Ot`2Kgd0Jx6Z4sy~-lqcg5k# z>3^$sS5IAITJ{_=u0ch3gRK7Nz-W`3^tt-{+Q?-=iT-$%Tkn9u%z z{ZRE$?_<{|zfTVr(iRr}1p}D#{3Ul5bpQYWAY({UO#lFTCIA3{ga82g0001h=zjnJ zbua(`>RI+y?e7jT@qQ9J+u00v@9M??Vs0RI60puMM)00009a7bBm000ie000ie z0hKEb8vp5i6q)T zO}$pbuBh z-+o3%Y?zMT-KDJ;n%QNo?sXT`MZuT|JlqgK)47?WG`nLnAm9i*l)eANGj! zMM+KHVpm^;1IeLnA%AvubMk{vSe}2t!re(4Ee*4!W0s0&hRNzmk=T*r#1aQNec?T- zwvFey1Wa=SkQhA3Ks-q{^?=!XQ$&YP(9zXPe(oWU7w2iVgxeEi6mko6?}>11z>A|_!106ev zD6?jY-V6rQAr^PF!OFZ6nWv#%v%@yW;uzS?iPeHFVppf@R(fz< zyQE2TYQFRPc%dTrzyI^YQn`$r3z)mHNauf=>-}1N;-#v`kAE}@OUC?-dc_l}R3p_@ zOTTrv+j*_MaQWQ5+oDe9{=I11HVI^c73-cqbmh)BA((pV_#L-`9Z|*I9`O}bS{fmz zWfR0#3+~S8T;z+T+vGOSbxurQOq7JSL4m?PmkQ}d{5dnziQej-kl8`U|Z`0!;c2@ZP8HE7@!ooj7B1;0 zhu#olr$2*KOAGY(_ruWOAS4nAAR=r{wP06IFQ8jzmw(oRffdK_D%kK1Q~dhQXe1P@ z)EzDJKpz-}0RsaAkWQyzZ0vIw9sPtRCN7d5jsOCH#)v}P_r6>5A0GT3G-kV=0K1&; zfBcaD%!y~AsVNTGY!*DvgIzm%;MKubaCPZAHib1;dX77}CboVnsiHgTTug?AjrVh0B5gsghL@3_);Ee=g_- z;~f8^0S(2M&AK$Zf@P~*T%Rep9N3P|P6i&prbzYXWo%mjJqQS7Ia5f^0Dy=H02JRW zwCi@}?zrF8o{a7JmL5FgcnAWyLQ#bv$U5b*yv@aStzxD$+p1bY^&g)I0Cn!(zFG=R jO&2%_1PBNM0EE8)zp<~ohewlATa(_aO`m^pgIquLD zNiZ}?@QUAIX9Gt~I!2S!wbxiK<(qka{~kIO+-x~sd$m5lqw!4nm9603MvjSbojqZ_ z4pJ3&=9-5m7WckBdC>TwsyL^syWjox$JFv%a&OwwwbKwHbhiZ56luaTNR}^H4!9f);jQq(jJ7JbzGY69CB#nbu*_r*L;$%O9lx z=^_^8>zaqQ1=MqE&{I2zNijI$^Ppq}tdRmAUO@@RU@pod*Q!35;ea>mtud7bR&o<+ z9S2&i0<*IY4X1)i3PT9^VN-8IC5r%~Vlx~Fq1Z+l70gDK5o$dTf-HcO)`DgN2u?3R zk!3{vet%fG0K|yio8e%5&i64)QV1{xkPHpA$qY`*V0&~3QEx(@0BmkWutDmu?2Qg) z06KfdUsvXtJ#^3uF%>kkMVql{}M9clng7y{*xCkr2b0zRBI*zQOsP rnPso%|86`mK2l(@G*#yvI!N>fQR57;0T*Md00000NkvXXu0mjfYk_X+ diff --git a/gui/slick/images/providers/tvbinz.png b/gui/slick/images/providers/tvbinz.png deleted file mode 100644 index 00ca93bd81dfda021ef680d69a29465d5482ab48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 349 zcmV-j0iyniP)nSuO5cZk&SH9I=DeqQ=Nu{wLxhmyIOs8^ zY09#U0EWG)s-M?YRn>LfbzKkyaMJfZ0KTnPmL*wbS-xJ;*CSFJz_#sIf}$t@L{Z$f z?S~+WBH|A?Ns@V--TGKRyUDv(+kMolt`ysvr`@RF1 zrujft;~zVDCY$n!i!QMab?(O~p0{sb5RI6PD^C3DP!00000NkvXXu0mjfqCu3@ diff --git a/gui/slick/images/providers/tvchaosuk.png b/gui/slick/images/providers/tvchaosuk.png index d6e968a74235769a0eed64a01f171088da00a500..ca8ebcd812ee8d8b715fbe6fa3bcfd89b33faac6 100644 GIT binary patch delta 916 zcmV;F18e;12dM{;BYyw}VoOIv00000008+zyMF)x010qNS#tmY3ljhU3ljkVnw%H_ z000McNliru-~$;DGbIyf!QcP@12#!SK~y-)b(39an`Iouf6tqwOR{{-b~Rn<+N|w1 zrAj;PHoFV^wLuGovB5SF1eJL)Vc<{@l=h;X=#2=XQ})H`EPu6|3WG6JM#Qe}qoZ}M zwu7Ww?V2`Cm$pe;lf1rfp2wSXxQm{<{~yk|IGi6+O2Pl6l-jJ6>QGAEH%(I-hB1-5 zH?x|Oi~oq(**Tw-@{G!9F}bX+T)CkxU+!0_R3`V8r=-lf4a2akc&z{)x6^(pI5a#m zI$pSc?=DI=jwJf2-2y#CHgfF`Bf3LM_CvywO7+=C_0 z#&SGKCOSi@TjROs%P*atFo!4f|I*5r0al4xlZq8%$44lSnR7;C175 zIRQwdGfemOGcg&#_wr5xn<^;X=*MamokECqP3rog^utO1zBNptp20u=h)2D>=#dCZ z^9$VR`Hp+B7@m@iG}crTpL5f5@g8$?iB|zcxU0*IefFuPB$dW46=HcA!!)sVcQc<~ z!0mHg6n_p4;!h-adYu-WWRsdp)5F)GzA;Q3E+k-KR&wR-r$qeg`zQ>F84O|+UWudH+ z-OWwBRP!vs;0PyA##mZPcjtVMhjjFQcx+$)`l5mve>r=%RWUFSqwn`ooNJ+>`4tWx zs(;5Yv&_%^Wqkcr^z0K;28=;HTi^KpyX_^#{sR_^h4JybNGX|`j*vyr($YXvV{O;z zQ|C_Pt$a delta 981 zcmV;`11kKf2kHlqBYy+2Nkl0#<-gqVvI4m7!8balh^AE%PP58rR>Jon-&D3NZx{od84tn}QRQd8jb-QC~= z005CpngUvFD}OqjzK#2%_V)gPhhMo-(qd4`FE&)0Tzb7~vc9R-rk995uG@O_j%x1i z^NYT6uk0L!FPTW_GSXD1;@f_OF^zGS=PKyo(Xo!Qh50gD zU3OhTUOO;2)4aWQ$0n5(hsbb8$7f>e)LRB13K>Hnkq9Jt9wgVUfj?6X z6PGSS=6|1KQGF;R*2-luYAT8h(A3RgrYOBCB9;#|+oYJ+vYPSyF>r>{L z!i7hQ>XeVhYl0q6EWyPg5eiGTpQ&NqC~U}!YJa<_Nht}~=QrLw_xjY5;~#+_BFxxa zAd<<-lM~ZDil1(j4B2LQcl8Uu7_)S3>Atx|Z_!h8mwtHIE|nMhUv7Ts#)VI~cO7#^ zR#I9F6cIsRUI2jJ`}c?&6!ts zc7iPuiCwp_pfyFK;f?=}1c)g9y7zML5~1I{akSLi*51xpYPxmFBrmLZJuoqAbAR(~ z_m#VM`YujRyN&8BvbO7Ik7;6z!9I}$5l+cIk>cLo+v;PL9Rp2`XSxwl)cg;&%=R}MU*SMsBG>aAMVK}#}$s%la= z1m^*4+s4w;D(adJL14`ZN~Iz$jt<4n=1v{9<099Vg;K5I&*BO^?jxJYAeBruCkO%` zBC$sm9M?m6OQA4>qNtE*{$x^sB#H68If3sV2t*ZC-Gt`{Xi24zNJvB=(Rium1b%Rk zV0h#le9Hy`4#)P8j7Ve=Jdm0bFj`oGT4XdrrbR~J*qHd><47k}Wc#YJQ<#6tL+q(O z@p2f~FMor?Igi^G7=uZYS)l=$+8!KAqcs7fO%0j$)~HgP>jn*ik0ZY!&#DkK%|vCZ zN(xj_R}DlYe&Okn#VYHkR_3uByM)6#UqLgMEIjC{F@h>#Jey;erYzzGCXlQ1}gPDxsv z2vUT$FR~aXt*oq~rYQ7u1f;WBuKfisbVE*4H8fNR_DDEI-puTv>Fa2dEzHlU1k8bzbwuf*NKiqb kLr;R(m`J#kgMR`H0CbN(8e=; - #for $curNewznabProvider in $sickbeard.newznabProviderList: + #for $cur_newznab_provider in $sickbeard.newznabProviderList: - \$(this).addProvider('$curNewznabProvider.get_id()', '$curNewznabProvider.name', '$curNewznabProvider.url', '<%= starify(curNewznabProvider.key) %>', '$curNewznabProvider.cat_ids', $int($curNewznabProvider.default), show_nzb_providers); + \$(this).addProvider('$cur_newznab_provider.get_id()', '$cur_newznab_provider.name', '$cur_newznab_provider.url', '<%= starify(cur_newznab_provider.key) %>', '$cur_newznab_provider.cat_ids', $int($cur_newznab_provider.default), show_nzb_providers); #end for @@ -47,9 +47,9 @@ #if $sickbeard.USE_TORRENTS - #for $curTorrentRssProvider in $sickbeard.torrentRssProviderList: + #for $cur_torrent_rss_provider in $sickbeard.torrentRssProviderList: - \$(this).addTorrentRssProvider('$curTorrentRssProvider.get_id()', '$curTorrentRssProvider.name', '$curTorrentRssProvider.url', '<%= starify(curTorrentRssProvider.cookies) %>'); + \$(this).addTorrentRssProvider('$cur_torrent_rss_provider.get_id()', '$cur_torrent_rss_provider.name', '$cur_torrent_rss_provider.url', '<%= starify(cur_torrent_rss_provider.cookies) %>'); #end for @@ -98,20 +98,20 @@ @@ -150,16 +150,13 @@ #set $provider_config_list_enabled = [] #set $provider_config_list = [] -#for $curProvider in $sickbeard.providers.sortedProviderList() - #if $curProvider.providerType == $GenericProvider.NZB and not $sickbeard.USE_NZBS - #continue - #elif $curProvider.providerType == $GenericProvider.TORRENT and not $sickbeard.USE_TORRENTS - #continue - #end if - #if $curProvider.is_enabled() - $provider_config_list_enabled.append($curProvider) +#for $cur_provider in [$x for $x in $sickbeard.providers.sortedProviderList() + if $x.providerType == $GenericProvider.NZB and $sickbeard.USE_NZBS or + $x.providerType == $GenericProvider.TORRENT and $sickbeard.USE_TORRENTS] + #if $cur_provider.is_enabled() + $provider_config_list_enabled.append($cur_provider) #else - $provider_config_list.append($curProvider) + $provider_config_list.append($cur_provider) #end if #end for @@ -188,71 +185,71 @@ -#for $curNewznabProvider in [$curProvider for $curProvider in $sickbeard.newznabProviderList] -
- #if $curNewznabProvider.default and $curNewznabProvider.needs_auth +#for $cur_newznab_provider in [$cur_provider for $cur_provider in $sickbeard.newznabProviderList] +
+ #if $cur_newznab_provider.default and $cur_newznab_provider.needs_auth
-
-
#end if - #if $hasattr($curNewznabProvider, 'enable_recentsearch') and $curNewznabProvider.supportsBacklog: + #if $hasattr($cur_newznab_provider, 'enable_recentsearch') and $cur_newznab_provider.supports_backlog:
-
#end if - #if $hasattr($curNewznabProvider, 'enable_backlog') and $curNewznabProvider.supportsBacklog: + #if $hasattr($cur_newznab_provider, 'enable_backlog') and $cur_newznab_provider.supports_backlog:
-
#end if - #if $hasattr($curNewznabProvider, 'search_mode') and $curNewznabProvider.supportsBacklog: + #if $hasattr($cur_newznab_provider, 'search_mode') and $cur_newznab_provider.supports_backlog:
- Season search mode + Episode search mode -

when searching for complete seasons, search for packs or collect single episodes

+

when searching for episodes, collect single episodes or search for packs

#end if - #if $hasattr($curNewznabProvider, 'search_fallback') and $curNewznabProvider.supportsBacklog: + #if $hasattr($cur_newznab_provider, 'search_fallback') and $cur_newznab_provider.supports_backlog:
-
@@ -262,80 +259,81 @@ ## ## -#for $curNzbProvider in [$curProvider for $curProvider in $sickbeard.providers.sortedProviderList() if $curProvider.providerType == $GenericProvider.NZB and $curProvider not in $sickbeard.newznabProviderList]: -
- #if $hasattr($curNzbProvider, 'username'): +#for $cur_nzb_provider in [$cur_provider for $cur_provider in $sickbeard.providers.sortedProviderList() + if $cur_provider.providerType == $GenericProvider.NZB and $cur_provider not in $sickbeard.newznabProviderList]: +
+ #if $hasattr($cur_nzb_provider, 'username'):
-
#end if - #if $hasattr($curNzbProvider, 'api_key'): + #if $hasattr($cur_nzb_provider, 'api_key'):
-
#end if - #if $hasattr($curNzbProvider, 'enable_recentsearch') and $curNzbProvider.supportsBacklog: + #if $hasattr($cur_nzb_provider, 'enable_recentsearch') and $cur_nzb_provider.supports_backlog:
-
#end if - #if $hasattr($curNzbProvider, 'enable_backlog') and $curNzbProvider.supportsBacklog: + #if $hasattr($cur_nzb_provider, 'enable_backlog') and $cur_nzb_provider.supports_backlog:
-
#end if - #if $hasattr($curNzbProvider, 'search_mode') and $curNzbProvider.supportsBacklog: + #if $hasattr($cur_nzb_provider, 'search_mode') and $cur_nzb_provider.supports_backlog:
- Season search mode + Episode search mode -

when searching for complete seasons, search for packs or collect single episodes

+

when searching for episodes, collect single episodes or search for packs

#end if - #if $hasattr($curNzbProvider, 'search_fallback') and $curNzbProvider.supportsBacklog: + #if $hasattr($cur_nzb_provider, 'search_fallback') and $cur_nzb_provider.supports_backlog:
-
#end if - #if not $curNzbProvider.supportsBacklog: + #if not $cur_nzb_provider.supports_backlog:
The latest releases are the focus of this provider, no backlog searching
@@ -345,233 +343,229 @@ ## ## -#for $curTorrentProvider in [$curProvider for $curProvider in $sickbeard.providers.sortedProviderList() if $curProvider.providerType == $GenericProvider.TORRENT]: -
- #if callable(getattr(curTorrentProvider, 'ui_string', None)) - #set $field_name = curTorrentProvider.get_id() + '_tip' - #set $tip_text = curTorrentProvider.ui_string($field_name) +#for $cur_torrent_provider in [$cur_provider for $cur_provider in $sickbeard.providers.sortedProviderList() + if $cur_provider.providerType == $GenericProvider.TORRENT]: +
+ #if callable(getattr(cur_torrent_provider, 'ui_string', None)) + #set $field_name = cur_torrent_provider.get_id() + '_tip' + #set $tip_text = cur_torrent_provider.ui_string($field_name) #if $tip_text
-

Important! ${curTorrentProvider.name} $tip_text

+

Important! ${cur_torrent_provider.name} $tip_text

#end if #end if - #if $hasattr($curTorrentProvider, 'api_key'): + #if $getattr($cur_torrent_provider, 'url_edit', None):
-
- #end if - #if $hasattr($curTorrentProvider, 'digest'): -
-
#end if - #if $hasattr($curTorrentProvider, 'hash'): + #if $hasattr($cur_torrent_provider, 'api_key'):
-
+ #end if + #if $hasattr($cur_torrent_provider, 'digest'): + #set $field_name = cur_torrent_provider.get_id() + '_digest' +
+ +
+ #end if + #if $hasattr($cur_torrent_provider, 'hash'): +
+
#end if - #if $hasattr($curTorrentProvider, 'username'): + #for $user_type in ['username', 'uid']: + #if $hasattr($cur_torrent_provider, $user_type): + #set $prov_type = '%s_%s' % ($cur_torrent_provider.get_id(), $user_type) + #set $user_value = $getattr($cur_torrent_provider, $user_type) or ''
-
- #end if - #if $hasattr($curTorrentProvider, 'password'): + #break + #end if + #end for + #if $hasattr($cur_torrent_provider, 'password'):
-
#end if - #if $hasattr($curTorrentProvider, 'passkey'): + #if $hasattr($cur_torrent_provider, 'passkey'):
-
#end if - #if $hasattr($curTorrentProvider, '_seed_ratio') and 'blackhole' != $sickbeard.TORRENT_METHOD: + #if $hasattr($cur_torrent_provider, '_seed_ratio') and 'blackhole' != $sickbeard.TORRENT_METHOD: #set $torrent_method_text = {'utorrent': 'uTorrent', 'transmission': 'Transmission', 'deluge': 'Deluge', 'download_station': 'Synology DS', 'rtorrent': 'rTorrent'}
-
#end if - #if $hasattr($curTorrentProvider, 'seed_time') and 'utorrent' == $sickbeard.TORRENT_METHOD: + #if $hasattr($cur_torrent_provider, 'seed_time') and 'utorrent' == $sickbeard.TORRENT_METHOD: #set $torrent_method_text = {'utorrent': 'uTorrent'} #set $use_default = 'to use the %s min torrent search setting minumum default' % ($sickbeard.TORRENT_SEED_TIME, $sbRoot) if $sickbeard.TORRENT_SEED_TIME else 'for the %s setting' % $torrent_method_text[$sickbeard.TORRENT_METHOD]
-
#end if - #if $hasattr($curTorrentProvider, 'minseed'): + #if $hasattr($cur_torrent_provider, 'minseed'):
-
#end if - #if $hasattr($curTorrentProvider, 'minleech'): + #if $hasattr($cur_torrent_provider, 'minleech'):
-
#end if - #if $hasattr($curTorrentProvider, 'proxy'): + #if $hasattr($cur_torrent_provider, 'confirmed'):
- -
- #if $hasattr($curTorrentProvider.proxy, 'url'): -
- -
- #end if - #end if - #if $hasattr($curTorrentProvider, 'confirmed'): -
-
#end if - #if $hasattr($curTorrentProvider, 'freeleech'): + #if $hasattr($cur_torrent_provider, 'freeleech'):
-
#end if - #if $hasattr($curTorrentProvider, 'reject_m2ts'): + #if $hasattr($cur_torrent_provider, 'reject_m2ts'):
-
#end if - #if $hasattr($curTorrentProvider, 'enable_recentsearch') and $curTorrentProvider.supportsBacklog: + #if $hasattr($cur_torrent_provider, 'enable_recentsearch'):
-
#end if - #if $hasattr($curTorrentProvider, 'enable_backlog') and $curTorrentProvider.supportsBacklog: + #if $hasattr($cur_torrent_provider, 'enable_backlog') and $cur_torrent_provider.supports_backlog:
-
#end if - #if $hasattr($curTorrentProvider, 'search_mode') and $curTorrentProvider.supportsBacklog: + #if $hasattr($cur_torrent_provider, 'search_mode') and $cur_torrent_provider.supports_backlog:
- Season search mode + Episode search mode -

when searching for complete seasons, search for packs or collect single episodes

+

when searching for episodes, collect single episodes or search for packs

#end if - #if $hasattr($curTorrentProvider, 'search_fallback') and $curTorrentProvider.supportsBacklog: + #if $hasattr($cur_torrent_provider, 'search_fallback') and $cur_torrent_provider.supports_backlog:
-
diff --git a/gui/slick/interfaces/default/config_search.tmpl b/gui/slick/interfaces/default/config_search.tmpl index d9004fb6..63f7de23 100755 --- a/gui/slick/interfaces/default/config_search.tmpl +++ b/gui/slick/interfaces/default/config_search.tmpl @@ -73,6 +73,7 @@

minutes between checking recent updated shows (minimum $sickbeard.MIN_RECENTSEARCH_FREQUENCY)

+

enter 4489 for experimental internal provider frequencies

diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 57daa177..cee74561 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -30,6 +30,7 @@ from threading import Lock import sys import os.path import uuid +import ast import base64 sys.path.insert(1, os.path.abspath('../lib')) from sickbeard import helpers, logger, db, naming, metadata, providers, scene_exceptions, scene_numbering, \ @@ -174,6 +175,7 @@ IMDB_ACCOUNTS = [] IMDB_DEFAULT_LIST_ID = '64552276' IMDB_DEFAULT_LIST_NAME = 'SickGear' PROVIDER_ORDER = [] +PROVIDER_HOMES = {} NAMING_MULTI_EP = False NAMING_ANIME_MULTI_EP = False @@ -520,7 +522,7 @@ def initialize(consoleLogging=True): KEEP_PROCESSED_DIR, PROCESS_METHOD, TV_DOWNLOAD_DIR, MIN_RECENTSEARCH_FREQUENCY, DEFAULT_UPDATE_FREQUENCY, MIN_UPDATE_FREQUENCY, UPDATE_FREQUENCY, \ showQueueScheduler, searchQueueScheduler, ROOT_DIRS, CACHE_DIR, ACTUAL_CACHE_DIR, ZONEINFO_DIR, TIMEZONE_DISPLAY, \ NAMING_PATTERN, NAMING_MULTI_EP, NAMING_ANIME_MULTI_EP, NAMING_FORCE_FOLDERS, NAMING_ABD_PATTERN, NAMING_CUSTOM_ABD, NAMING_SPORTS_PATTERN, NAMING_CUSTOM_SPORTS, NAMING_ANIME_PATTERN, NAMING_CUSTOM_ANIME, NAMING_STRIP_YEAR, \ - RENAME_EPISODES, AIRDATE_EPISODES, properFinderScheduler, PROVIDER_ORDER, autoPostProcesserScheduler, \ + RENAME_EPISODES, AIRDATE_EPISODES, properFinderScheduler, PROVIDER_ORDER, PROVIDER_HOMES, autoPostProcesserScheduler, \ providerList, newznabProviderList, torrentRssProviderList, \ EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, RECENTSEARCH_FREQUENCY, \ USE_BOXCAR2, BOXCAR2_ACCESSTOKEN, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD, BOXCAR2_NOTIFY_ONSNATCH, BOXCAR2_SOUND, \ @@ -580,10 +582,6 @@ def initialize(consoleLogging=True): ACTUAL_CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', 'cache') - # fix bad configs due to buggy code - if ACTUAL_CACHE_DIR == 'None': - ACTUAL_CACHE_DIR = 'cache' - # unless they specify, put the cache dir inside the data dir if not os.path.isabs(ACTUAL_CACHE_DIR): CACHE_DIR = os.path.join(DATA_DIR, ACTUAL_CACHE_DIR) @@ -699,6 +697,7 @@ def initialize(consoleLogging=True): SCENE_DEFAULT = bool(check_setting_int(CFG, 'General', 'scene_default', 0)) PROVIDER_ORDER = check_setting_str(CFG, 'General', 'provider_order', '').split() + PROVIDER_HOMES = ast.literal_eval(check_setting_str(CFG, 'General', 'provider_homes', None) or '{}') NAMING_PATTERN = check_setting_str(CFG, 'General', 'naming_pattern', 'Season %0S/%SN - S%0SE%0E - %EN') NAMING_ABD_PATTERN = check_setting_str(CFG, 'General', 'naming_abd_pattern', '%SN - %A.D - %EN') @@ -1029,28 +1028,28 @@ def initialize(consoleLogging=True): prov_id = torrent_prov.get_id() prov_id_uc = torrent_prov.get_id().upper() torrent_prov.enabled = bool(check_setting_int(CFG, prov_id_uc, prov_id, 0)) + if getattr(torrent_prov, 'url_edit', None): + torrent_prov.url_home = check_setting_str(CFG, prov_id_uc, prov_id + '_url_home', []) if hasattr(torrent_prov, 'api_key'): torrent_prov.api_key = check_setting_str(CFG, prov_id_uc, prov_id + '_api_key', '') if hasattr(torrent_prov, 'hash'): torrent_prov.hash = check_setting_str(CFG, prov_id_uc, prov_id + '_hash', '') if hasattr(torrent_prov, 'digest'): torrent_prov.digest = check_setting_str(CFG, prov_id_uc, prov_id + '_digest', '') - if hasattr(torrent_prov, 'username'): - torrent_prov.username = check_setting_str(CFG, prov_id_uc, prov_id + '_username', '') + for user_type in ['username', 'uid']: + if hasattr(torrent_prov, user_type): + setattr(torrent_prov, user_type, + check_setting_str(CFG, prov_id_uc, '%s_%s' % (prov_id, user_type), '')) if hasattr(torrent_prov, 'password'): torrent_prov.password = check_setting_str(CFG, prov_id_uc, prov_id + '_password', '') if hasattr(torrent_prov, 'passkey'): torrent_prov.passkey = check_setting_str(CFG, prov_id_uc, prov_id + '_passkey', '') - if hasattr(torrent_prov, 'proxy'): - torrent_prov.proxy.enabled = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_proxy', 0)) - if hasattr(torrent_prov.proxy, 'url'): - torrent_prov.proxy.url = check_setting_str(CFG, prov_id_uc, prov_id + '_proxy_url', '') if hasattr(torrent_prov, 'confirmed'): torrent_prov.confirmed = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_confirmed', 0)) if hasattr(torrent_prov, 'options'): torrent_prov.options = check_setting_str(CFG, prov_id_uc, prov_id + '_options', '') if hasattr(torrent_prov, '_seed_ratio'): - torrent_prov._seed_ratio = check_setting_str(CFG, prov_id_uc, prov_id + '_seed_ratio', '').replace('None', '') + torrent_prov._seed_ratio = check_setting_str(CFG, prov_id_uc, prov_id + '_seed_ratio', '') if hasattr(torrent_prov, 'seed_time'): torrent_prov.seed_time = check_setting_int(CFG, prov_id_uc, prov_id + '_seed_time', '') if hasattr(torrent_prov, 'minseed'): @@ -1087,7 +1086,8 @@ def initialize(consoleLogging=True): nzb_prov.search_fallback = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_search_fallback', 0)) if hasattr(nzb_prov, 'enable_recentsearch'): nzb_prov.enable_recentsearch = bool(check_setting_int(CFG, prov_id_uc, - prov_id + '_enable_recentsearch', 1)) + prov_id + '_enable_recentsearch', 1)) or \ + not getattr(nzb_prov, 'supports_backlog', True) if hasattr(nzb_prov, 'enable_backlog'): nzb_prov.enable_backlog = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_enable_backlog', 1)) @@ -1157,7 +1157,7 @@ def initialize(consoleLogging=True): cycleTime=datetime.timedelta(seconds=3), threadName='SEARCHQUEUE') - update_interval = datetime.timedelta(minutes=RECENTSEARCH_FREQUENCY) + update_interval = datetime.timedelta(minutes=(RECENTSEARCH_FREQUENCY, 1)[4489 == RECENTSEARCH_FREQUENCY]) recentSearchScheduler = scheduler.Scheduler(search_recent.RecentSearcher(), cycleTime=update_interval, threadName='RECENTSEARCHER', @@ -1457,6 +1457,7 @@ def save_config(): new_config['General']['anime_default'] = int(ANIME_DEFAULT) new_config['General']['scene_default'] = int(SCENE_DEFAULT) new_config['General']['provider_order'] = ' '.join(PROVIDER_ORDER) + new_config['General']['provider_homes'] = '%s' % PROVIDER_HOMES new_config['General']['version_notify'] = int(VERSION_NOTIFY) new_config['General']['auto_update'] = int(AUTO_UPDATE) new_config['General']['notify_on_update'] = int(NOTIFY_ON_UPDATE) @@ -1522,73 +1523,40 @@ def save_config(): new_config['Blackhole']['nzb_dir'] = NZB_DIR new_config['Blackhole']['torrent_dir'] = TORRENT_DIR - # dynamically save provider settings - for torrent_prov in [curProvider for curProvider in providers.sortedProviderList() - if GenericProvider.TORRENT == curProvider.providerType]: - prov_id = torrent_prov.get_id() - prov_id_uc = torrent_prov.get_id().upper() - new_config[prov_id_uc] = {} - new_config[prov_id_uc][prov_id] = int(torrent_prov.enabled) - if hasattr(torrent_prov, 'digest'): - new_config[prov_id_uc][prov_id + '_digest'] = torrent_prov.digest - if hasattr(torrent_prov, 'hash'): - new_config[prov_id_uc][prov_id + '_hash'] = torrent_prov.hash - if hasattr(torrent_prov, 'api_key'): - new_config[prov_id_uc][prov_id + '_api_key'] = torrent_prov.api_key - if hasattr(torrent_prov, 'username'): - new_config[prov_id_uc][prov_id + '_username'] = torrent_prov.username - if hasattr(torrent_prov, 'password'): - new_config[prov_id_uc][prov_id + '_password'] = helpers.encrypt(torrent_prov.password, ENCRYPTION_VERSION) - if hasattr(torrent_prov, 'passkey'): - new_config[prov_id_uc][prov_id + '_passkey'] = torrent_prov.passkey - if hasattr(torrent_prov, 'confirmed'): - new_config[prov_id_uc][prov_id + '_confirmed'] = int(torrent_prov.confirmed) - if hasattr(torrent_prov, '_seed_ratio'): - new_config[prov_id_uc][prov_id + '_seed_ratio'] = torrent_prov.seed_ratio() - if hasattr(torrent_prov, 'seed_time'): - new_config[prov_id_uc][prov_id + '_seed_time'] = torrent_prov.seed_time - if hasattr(torrent_prov, 'minseed'): - new_config[prov_id_uc][prov_id + '_minseed'] = int(torrent_prov.minseed) - if hasattr(torrent_prov, 'minleech'): - new_config[prov_id_uc][prov_id + '_minleech'] = int(torrent_prov.minleech) - if hasattr(torrent_prov, 'freeleech'): - new_config[prov_id_uc][prov_id + '_freeleech'] = int(torrent_prov.freeleech) - if hasattr(torrent_prov, 'reject_m2ts'): - new_config[prov_id_uc][prov_id + '_reject_m2ts'] = int(torrent_prov.reject_m2ts) - if hasattr(torrent_prov, 'enable_recentsearch'): - new_config[prov_id_uc][prov_id + '_enable_recentsearch'] = int(torrent_prov.enable_recentsearch) - if hasattr(torrent_prov, 'enable_backlog'): - new_config[prov_id_uc][prov_id + '_enable_backlog'] = int(torrent_prov.enable_backlog) - if hasattr(torrent_prov, 'search_mode'): - new_config[prov_id_uc][prov_id + '_search_mode'] = torrent_prov.search_mode - if hasattr(torrent_prov, 'search_fallback'): - new_config[prov_id_uc][prov_id + '_search_fallback'] = int(torrent_prov.search_fallback) - if hasattr(torrent_prov, 'options'): - new_config[prov_id_uc][prov_id + '_options'] = torrent_prov.options - if hasattr(torrent_prov, 'proxy'): - new_config[prov_id_uc][prov_id + '_proxy'] = int(torrent_prov.proxy.enabled) - if hasattr(torrent_prov.proxy, 'url'): - new_config[prov_id_uc][prov_id + '_proxy_url'] = torrent_prov.proxy.url + for src in [x for x in providers.sortedProviderList() if GenericProvider.TORRENT == x.providerType]: + src_id = src.get_id() + src_id_uc = src_id.upper() + new_config[src_id_uc] = {} + new_config[src_id_uc][src_id] = int(src.enabled) + if getattr(src, 'url_edit', None): + new_config[src_id_uc][src_id + '_url_home'] = src.url_home - for nzb_prov in [curProvider for curProvider in providers.sortedProviderList() - if GenericProvider.NZB == curProvider.providerType]: - prov_id = nzb_prov.get_id() - prov_id_uc = nzb_prov.get_id().upper() - new_config[prov_id_uc] = {} - new_config[prov_id_uc][prov_id] = int(nzb_prov.enabled) + if hasattr(src, 'password'): + new_config[src_id_uc][src_id + '_password'] = helpers.encrypt(src.password, ENCRYPTION_VERSION) - if hasattr(nzb_prov, 'api_key'): - new_config[prov_id_uc][prov_id + '_api_key'] = nzb_prov.api_key - if hasattr(nzb_prov, 'username'): - new_config[prov_id_uc][prov_id + '_username'] = nzb_prov.username - if hasattr(nzb_prov, 'search_mode'): - new_config[prov_id_uc][prov_id + '_search_mode'] = nzb_prov.search_mode - if hasattr(nzb_prov, 'search_fallback'): - new_config[prov_id_uc][prov_id + '_search_fallback'] = int(nzb_prov.search_fallback) - if hasattr(nzb_prov, 'enable_recentsearch'): - new_config[prov_id_uc][prov_id + '_enable_recentsearch'] = int(nzb_prov.enable_recentsearch) - if hasattr(nzb_prov, 'enable_backlog'): - new_config[prov_id_uc][prov_id + '_enable_backlog'] = int(nzb_prov.enable_backlog) + for (setting, value) in [ + ('%s_%s' % (src_id, k), getattr(src, k, v) if not v else helpers.tryInt(getattr(src, k, None))) + for (k, v) in [ + ('api_key', None), ('passkey', None), ('digest', None), ('hash', None), ('username', ''), ('uid', ''), + ('minseed', 1), ('minleech', 1), ('confirmed', 1), ('freeleech', 1), ('reject_m2ts', 1), + ('enable_recentsearch', 1), ('enable_backlog', 1), ('search_mode', None), ('search_fallback', 1), + ('seed_time', None)] if hasattr(src, k)]: + new_config[src_id_uc][setting] = value + + if hasattr(src, '_seed_ratio'): + new_config[src_id_uc][src_id + '_seed_ratio'] = src.seed_ratio() + + for src in [x for x in providers.sortedProviderList() if GenericProvider.NZB == x.providerType]: + src_id = src.get_id() + src_id_uc = src.get_id().upper() + new_config[src_id_uc] = {} + new_config[src_id_uc][src_id] = int(src.enabled) + + for attr in [x for x in ['api_key', 'username', 'search_mode'] if hasattr(src, x)]: + new_config[src_id_uc]['%s_%s' % (src_id, attr)] = getattr(src, attr) + + for attr in [x for x in ['enable_recentsearch', 'enable_backlog', 'search_fallback'] if hasattr(src, x)]: + new_config[src_id_uc]['%s_%s' % (src_id, attr)] = helpers.tryInt(getattr(src, attr, None)) new_config['SABnzbd'] = {} new_config['SABnzbd']['sab_username'] = SAB_USERNAME diff --git a/sickbeard/common.py b/sickbeard/common.py index 4f931fbe..2d34824f 100644 --- a/sickbeard/common.py +++ b/sickbeard/common.py @@ -213,6 +213,9 @@ class Quality: return Quality.SDTV elif checkName(['(dvd.?rip|b[r|d]rip)(.ws)?(.(xvid|divx|x264|h.?264))?'], any) and not checkName(['(720|1080|2160)[pi]'], all): return Quality.SDDVD + elif checkName(['(xvid|divx|480p)'], any) and not checkName(['(720|1080|2160)[pi]'], all) \ + and not checkName(['hr.ws.pdtv.(x264|h.?264)'], any): + return Quality.SDTV elif checkName(['720p', 'hdtv', 'x264|h.?264'], all) or checkName(['hr.ws.pdtv.(x264|h.?264)'], any) \ and not checkName(['(1080|2160)[pi]'], all): return Quality.HDTV diff --git a/sickbeard/config.py b/sickbeard/config.py index 3ec021ac..5dcffef9 100644 --- a/sickbeard/config.py +++ b/sickbeard/config.py @@ -420,7 +420,7 @@ def check_setting_str(config, cfg_name, item_name, def_val, log=True): else: logger.log('%s -> ******' % item_name, logger.DEBUG) - return my_val + return (my_val, def_val)['None' == my_val] class ConfigMigrator(): @@ -783,4 +783,4 @@ class ConfigMigrator(): old_token = check_setting_str(self.config_obj, 'Trakt', 'trakt_token', '') old_refresh_token = check_setting_str(self.config_obj, 'Trakt', 'trakt_refresh_token', '') if old_token and old_refresh_token: - TraktAPI.add_account(old_token, old_refresh_token, None) \ No newline at end of file + TraktAPI.add_account(old_token, old_refresh_token, None) diff --git a/sickbeard/db.py b/sickbeard/db.py index f577c0fd..db27d781 100644 --- a/sickbeard/db.py +++ b/sickbeard/db.py @@ -95,17 +95,23 @@ class DBConnection(object): while attempt < 5: try: + affected = 0 for qu in querylist: + cursor = self.connection.cursor() if len(qu) == 1: if logTransaction: logger.log(qu[0], logger.DB) - sqlResult.append(self.connection.execute(qu[0]).fetchall()) + + sqlResult.append(cursor.execute(qu[0]).fetchall()) elif len(qu) > 1: if logTransaction: logger.log(qu[0] + ' with args ' + str(qu[1]), logger.DB) - sqlResult.append(self.connection.execute(qu[0], qu[1]).fetchall()) + sqlResult.append(cursor.execute(qu[0], qu[1]).fetchall()) + affected += cursor.rowcount self.connection.commit() - logger.log(u'Transaction with ' + str(len(querylist)) + u' queries executed', logger.DEBUG) + if affected > 0: + logger.log(u'Transaction with %s queries executed affected %i row%s' % ( + len(querylist), affected, helpers.maybe_plural(affected)), logger.DEBUG) return sqlResult except sqlite3.OperationalError as e: sqlResult = [] diff --git a/sickbeard/nzbSplitter.py b/sickbeard/nzbSplitter.py index 4a64f7f8..14c467cf 100644 --- a/sickbeard/nzbSplitter.py +++ b/sickbeard/nzbSplitter.py @@ -18,7 +18,6 @@ from __future__ import with_statement -import urllib2 import xml.etree.cElementTree as etree import xml.etree import re @@ -84,7 +83,7 @@ def createNZBString(fileElements, xmlns): for curFile in fileElements: rootElement.append(stripNS(curFile, xmlns)) - return xml.etree.ElementTree.tostring(rootElement, 'utf-8', 'replace') + return xml.etree.ElementTree.tostring(rootElement, 'utf-8') def saveNZB(nzbName, nzbString): @@ -158,7 +157,7 @@ def splitResult(result): wantEp = True for epNo in parse_result.episode_numbers: - if not result.extraInfo[0].wantEpisode(season, epNo, result.quality): + if not result.show.wantEpisode(season, epNo, result.quality): logger.log(u"Ignoring result " + newNZB + " because we don't want an episode that is " + Quality.qualityStrings[result.quality], logger.DEBUG) wantEp = False @@ -169,13 +168,14 @@ def splitResult(result): # get all the associated episode objects epObjList = [] for curEp in parse_result.episode_numbers: - epObjList.append(result.extraInfo[0].getEpisode(season, curEp)) + epObjList.append(result.show.getEpisode(season, curEp)) # make a result curResult = classes.NZBDataSearchResult(epObjList) curResult.name = newNZB curResult.provider = result.provider curResult.quality = result.quality + curResult.show = result.show curResult.extraInfo = [createNZBString(separateNZBs[newNZB], xmlns)] resultList.append(curResult) diff --git a/sickbeard/providers/__init__.py b/sickbeard/providers/__init__.py index 6e1eaad2..73909a59 100755 --- a/sickbeard/providers/__init__.py +++ b/sickbeard/providers/__init__.py @@ -18,30 +18,37 @@ from os import sys +import os.path import sickbeard from . import generic -from sickbeard import logger +from sickbeard import logger, encodingKludge as ek # usenet from . import newznab, omgwtfnzbs, womble # torrent -from . import alpharatio, beyondhd, bitmetv, bitsoup, btn, freshontv, funfile, gftracker, grabtheinfo, \ - hdbits, hdspace, iptorrents, kat, morethan, pisexy, pretome, rarbg, scc, scenetime, shazbat, speedcd, \ +from . import alpharatio, beyondhd, bitmetv, btn, freshontv, funfile, gftracker, grabtheinfo, \ + hd4free, hdbits, hdspace, iptorrents, kat, morethan, pisexy, pretome, rarbg, scc, scenetime, shazbat, speedcd, \ thepiratebay, torrentbytes, torrentday, torrenting, torrentleech, torrentshack, transmithe_net, tvchaosuk # anime from . import nyaatorrents, tokyotoshokan +# custom +try: + from . import custom01 +except: + pass __all__ = ['omgwtfnzbs', 'womble', 'alpharatio', 'beyondhd', 'bitmetv', - 'bitsoup', 'btn', + 'custom01', 'freshontv', 'funfile', 'gftracker', 'grabtheinfo', + 'hd4free', 'hdbits', 'hdspace', 'iptorrents', @@ -208,16 +215,19 @@ def makeTorrentRssProvider(configString): def getDefaultNewznabProviders(): - return 'Sick Beard Index|http://lolo.sickbeard.com/|0|5030,5040|0|eponly|0|0|0!!!NZBs.org|https://nzbs.org/||5030,5040|0|eponly|0|0|0!!!Usenet-Crawler|https://www.usenet-crawler.com/||5030,5040|0|eponly|0|0|0' + return '!!!'.join(['Sick Beard Index|http://lolo.sickbeard.com/|0|5030,5040|0|eponly|0|0|0', + 'NZBgeek|https://api.nzbgeek.info/||5030,5040|0|eponly|0|0|0', + 'NZBs.org|https://nzbs.org/||5030,5040|0|eponly|0|0|0', + 'Usenet-Crawler|https://www.usenet-crawler.com/||5030,5040|0|eponly|0|0|0']) def getProviderModule(name): - name = name.lower() - prefix = "sickbeard.providers." + prefix, cprov, name = 'sickbeard.providers.', 'motsuc'[::-1], name.lower() if name in __all__ and prefix + name in sys.modules: return sys.modules[prefix + name] - else: - raise Exception("Can't find " + prefix + name + " in " + "Providers") + elif cprov in name: + return None + raise Exception('Can\'t find %s%s in providers' % (prefix, name)) def getProviderClass(id): diff --git a/sickbeard/providers/alpharatio.py b/sickbeard/providers/alpharatio.py index 9a483617..13478d7f 100644 --- a/sickbeard/providers/alpharatio.py +++ b/sickbeard/providers/alpharatio.py @@ -21,7 +21,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -31,7 +31,7 @@ class AlphaRatioProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'AlphaRatio') + generic.TorrentProvider.__init__(self, 'AlphaRatio', cache_update_freq=20) self.url_base = 'https://alpharatio.cc/' self.urls = {'config_provider_home_uri': self.url_base, @@ -44,9 +44,7 @@ class AlphaRatioProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = AlphaRatioCache(self) + self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] def _authorised(self, **kwargs): @@ -65,7 +63,7 @@ class AlphaRatioProvider(generic.TorrentProvider): for mode in search_params.keys(): for search_string in search_params[mode]: search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string - search_url = self.urls['search'] % (search_string, ('', '&freetorrent=1')[self.freeleech]) + search_url = self.urls['search'] % (search_string, ('&freetorrent=1', '')[not self.freeleech]) html = self.get_url(search_url) @@ -111,16 +109,4 @@ class AlphaRatioProvider(generic.TorrentProvider): return results -class AlphaRatioCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = AlphaRatioProvider() diff --git a/sickbeard/providers/beyondhd.py b/sickbeard/providers/beyondhd.py index 203886dc..5dfde720 100644 --- a/sickbeard/providers/beyondhd.py +++ b/sickbeard/providers/beyondhd.py @@ -19,7 +19,7 @@ import re import time from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.exceptions import AuthException from lib.unidecode import unidecode @@ -41,7 +41,6 @@ class BeyondHDProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] self.passkey, self.minseed, self.minleech = 3 * [None] - self.cache = BeyondHDCache(self) def _check_auth_from_data(self, data_json): @@ -101,14 +100,4 @@ class BeyondHDProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs) -class BeyondHDCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - def _cache_data(self): - - return self.provider.cache_data() - - provider = BeyondHDProvider() diff --git a/sickbeard/providers/bitmetv.py b/sickbeard/providers/bitmetv.py index f46af25c..550addd6 100644 --- a/sickbeard/providers/bitmetv.py +++ b/sickbeard/providers/bitmetv.py @@ -19,7 +19,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -28,7 +28,7 @@ from lib.unidecode import unidecode class BitmetvProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'BitMeTV') + generic.TorrentProvider.__init__(self, 'BitMeTV', cache_update_freq=7) self.url_base = 'http://www.bitmetv.org/' @@ -42,7 +42,6 @@ class BitmetvProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] self.digest, self.minseed, self.minleech = 3 * [None] - self.cache = BitmetvCache(self) def _authorised(self, **kwargs): @@ -63,9 +62,7 @@ class BitmetvProvider(generic.TorrentProvider): for mode in search_params.keys(): for search_string in search_params[mode]: search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string - category = 'cat=%s' % self.categories[ - (mode in ['Season', 'Episode'] and self.show and self.show.is_anime) and 'anime' or 'shows'] - search_url = self.urls['search'] % (category, search_string) + search_url = self.urls['search'] % (self._categories_string(mode, 'cat=%s'), search_string) html = self.get_url(search_url) @@ -89,8 +86,8 @@ class BitmetvProvider(generic.TorrentProvider): continue info = tr.find('a', href=rc['info']) - title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip() - download_url = self.urls['get'] % tr.find('a', href=rc['get']).get('href') + title = info.attrs.get('title') or info.get_text().strip() + download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/') except (AttributeError, TypeError, ValueError): continue @@ -116,16 +113,4 @@ class BitmetvProvider(generic.TorrentProvider): return 'bitmetv_digest' == key and 'use... \'uid=xx; pass=yy\'' or '' -class BitmetvCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 7 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = BitmetvProvider() diff --git a/sickbeard/providers/bitsoup.py b/sickbeard/providers/bitsoup.py deleted file mode 100644 index 7bb58e2b..00000000 --- a/sickbeard/providers/bitsoup.py +++ /dev/null @@ -1,120 +0,0 @@ -# coding=utf-8 -# -# This file is part of SickGear. -# -# SickGear is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# SickGear is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with SickGear. If not, see . - -import re -import traceback - -from . import generic -from sickbeard import logger, tvcache -from sickbeard.bs4_parser import BS4Parser -from sickbeard.helpers import tryInt -from lib.unidecode import unidecode - - -class BitSoupProvider(generic.TorrentProvider): - - def __init__(self): - generic.TorrentProvider.__init__(self, 'BitSoup') - - self.url_base = 'https://www.bitsoup.me/' - self.urls = {'config_provider_home_uri': self.url_base, - 'login': self.url_base + 'takelogin.php', - 'search': self.url_base + 'browse.php?search=%s&%s&incldead=0&blah=0', - 'get': self.url_base + '%s'} - - self.categories = {'shows': [42, 45, 49, 32, 7], 'anime': [23]} - - self.url = self.urls['config_provider_home_uri'] - - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.cache = BitSoupCache(self) - - def _search_provider(self, search_params, **kwargs): - - results = [] - if not self._authorised(): - return results - - items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} - - rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download'}.items()) - for mode in search_params.keys(): - for search_string in search_params[mode]: - search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string - search_url = self.urls['search'] % (search_string, self._categories_string(mode)) - - html = self.get_url(search_url) - - cnt = len(items[mode]) - try: - if not html or self._has_no_results(html): - raise generic.HaltParseException - - with BS4Parser(html, 'html.parser', attr='class="koptekst"') as soup: - torrent_table = soup.find('table', attrs={'class': 'koptekst'}) - torrent_rows = [] if not torrent_table else torrent_table.find_all('tr') - - if 2 > len(torrent_rows): - raise generic.HaltParseException - - for tr in torrent_rows[1:]: - try: - seeders, leechers, size = [tryInt(n, n) for n in [ - (tr.find_all('td')[x].get_text().strip()) for x in (-3, -2, -5)]] - if self._peers_fail(mode, seeders, leechers): - continue - - info = tr.find('a', href=rc['info']) - title = info.get_text().strip() - - download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/') - except (AttributeError, TypeError, ValueError): - continue - - if title and download_url: - items[mode].append((title, download_url, seeders, self._bytesizer(size))) - - except generic.HaltParseException: - pass - except Exception: - logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR) - self._log_search(mode, len(items[mode]) - cnt, search_url) - - self._sort_seeders(mode, items) - - results = list(set(results + items[mode])) - - return results - - def _episode_strings(self, ep_obj, **kwargs): - - return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs) - - -class BitSoupCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - -provider = BitSoupProvider() diff --git a/sickbeard/providers/freshontv.py b/sickbeard/providers/freshontv.py index a518f937..34c8ba3a 100644 --- a/sickbeard/providers/freshontv.py +++ b/sickbeard/providers/freshontv.py @@ -19,7 +19,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -28,19 +28,19 @@ from lib.unidecode import unidecode class FreshOnTVProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'FreshOnTV') + generic.TorrentProvider.__init__(self, 'FreshOnTV', cache_update_freq=20) self.url_base = 'https://freshon.tv/' self.urls = {'config_provider_home_uri': self.url_base, 'login': self.url_base + 'login.php?action=makelogin', - 'search': self.url_base + 'browse.php?incldead=%s&words=0&cat=0&search=%s', + 'search': self.url_base + 'browse.php?incldead=%s&words=0&%s&search=%s', 'get': self.url_base + '%s'} + self.categories = {'shows': 0, 'anime': 235} + self.url = self.urls['config_provider_home_uri'] - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = FreshOnTVCache(self) + self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] def _authorised(self, **kwargs): @@ -59,16 +59,17 @@ class FreshOnTVProvider(generic.TorrentProvider): return results items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} - freeleech = (0, 3)[self.freeleech] + freeleech = (3, 0)[not self.freeleech] rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download', 'name': '_name'}.items()) for mode in search_params.keys(): for search_string in search_params[mode]: - search_string, search_url = self._title_and_url(( - isinstance(search_string, unicode) and unidecode(search_string) or search_string, - self.urls['search'] % (freeleech, search_string))) + search_string, void = self._title_and_url(( + isinstance(search_string, unicode) and unidecode(search_string) or search_string, '')) + void, search_url = self._title_and_url(( + '', self.urls['search'] % (freeleech, self._categories_string(mode, 'cat=%s'), search_string))) # returns top 15 results by default, expandable in user profile to 100 html = self.get_url(search_url) @@ -96,7 +97,7 @@ class FreshOnTVProvider(generic.TorrentProvider): continue info = tr.find('a', href=rc['info'], attrs={'class': rc['name']}) - title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip() + title = info.attrs.get('title') or info.get_text().strip() download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/') except (AttributeError, TypeError, ValueError): @@ -117,21 +118,9 @@ class FreshOnTVProvider(generic.TorrentProvider): return results - def _get_episode_search_strings(self, ep_obj, **kwargs): + def _episode_strings(self, ep_obj, **kwargs): return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs) -class FreshOnTVCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 - - def _cache_data(self): - - return self.provider.cache_data() - - provider = FreshOnTVProvider() diff --git a/sickbeard/providers/funfile.py b/sickbeard/providers/funfile.py index 7bba7aa8..a5ab41ee 100644 --- a/sickbeard/providers/funfile.py +++ b/sickbeard/providers/funfile.py @@ -19,7 +19,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -28,7 +28,7 @@ from lib.unidecode import unidecode class FunFileProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'FunFile') + generic.TorrentProvider.__init__(self, 'FunFile', cache_update_freq=15) self.url_base = 'https://www.funfile.org/' self.urls = {'config_provider_home_uri': self.url_base, @@ -41,7 +41,6 @@ class FunFileProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] self.url_timeout = 90 self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.cache = FunFileCache(self) def _authorised(self, **kwargs): @@ -58,10 +57,9 @@ class FunFileProvider(generic.TorrentProvider): items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} - rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download', - 'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|') - }.items()) + rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download'}.items()) for mode in search_params.keys(): + rc['cats'] = re.compile('(?i)cat=(?:%s)' % self._categories_string(mode, template='', delimiter='|')) for search_string in search_params[mode]: search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string search_url = self.urls['search'] % (self._categories_string(mode), search_string) @@ -91,8 +89,8 @@ class FunFileProvider(generic.TorrentProvider): if None is tr.find('a', href=rc['cats']) or self._peers_fail(mode, seeders, leechers): continue - title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip() - download_url = self.urls['get'] % tr.find('a', href=rc['get']).get('href') + title = info.attrs.get('title') or info.get_text().strip() + download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/') except (AttributeError, TypeError, ValueError): continue @@ -114,16 +112,4 @@ class FunFileProvider(generic.TorrentProvider): return results -class FunFileCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 15 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = FunFileProvider() diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py index 57712ddf..697479b1 100644 --- a/sickbeard/providers/generic.py +++ b/sickbeard/providers/generic.py @@ -25,6 +25,8 @@ import math import os import re import time +import urlparse +import zlib from base64 import b16encode, b32decode import sickbeard @@ -53,7 +55,7 @@ class GenericProvider: # these need to be set in the subclass self.providerType = None self.name = name - self.supportsBacklog = supports_backlog + self.supports_backlog = supports_backlog self.anime_only = anime_only if anime_only: self.proper_search_terms = 'v1|v2|v3|v4|v5' @@ -518,7 +520,7 @@ class GenericProvider: if hasattr(self, 'cookies'): cookies = self.cookies - if not re.match('^(\w+=\w+[;\s]*)+$', cookies): + if not (cookies and re.match('^(\w+=\w+[;\s]*)+$', cookies)): return False cj = requests.utils.add_dict_to_cookiejar(self.session.cookies, @@ -544,9 +546,13 @@ class GenericProvider: def _categories_string(self, mode='Cache', template='c%s=1', delimiter='&'): - return delimiter.join([('%s', template)[any(template)] % c for c in sorted(self.categories['shows'] + ( - [], [] if 'anime' not in self.categories else self.categories['anime'])[ - ('Cache' == mode and helpers.has_anime()) or ((mode in ['Season', 'Episode']) and self.show and self.show.is_anime)])]) + return delimiter.join([('%s', template)[any(template)] % c for c in sorted( + 'shows' in self.categories and (isinstance(self.categories['shows'], type([])) and + self.categories['shows'] or [self.categories['shows']]) or + self.categories[(mode, 'Episode')['Propers' == mode]] + + ([], self.categories.get('anime') or [])[ + (mode in ['Cache', 'Propers'] and helpers.has_anime()) or + ((mode in ['Season', 'Episode']) and self.show and self.show.is_anime)])]) @staticmethod def _bytesizer(size_dim=''): @@ -577,12 +583,8 @@ class NZBProvider(object, GenericProvider): def maybe_apikey(self): - if hasattr(self, 'needs_auth') and self.needs_auth: - if hasattr(self, 'key') and 0 < len(self.key): - return self.key - if hasattr(self, 'api_key') and 0 < len(self.api_key): - return self.api_key - return None + if getattr(self, 'needs_auth', None): + return (getattr(self, 'key', '') and self.key) or (getattr(self, 'api_key', '') and self.api_key) or None return False def _check_auth(self): @@ -664,13 +666,32 @@ class NZBProvider(object, GenericProvider): class TorrentProvider(object, GenericProvider): - def __init__(self, name, supports_backlog=True, anime_only=False): + def __init__(self, name, supports_backlog=True, anime_only=False, cache_update_freq=None): GenericProvider.__init__(self, name, supports_backlog, anime_only) self.providerType = GenericProvider.TORRENT self._seed_ratio = None self.seed_time = None + self._url = None + self.urls = {} + self.cache._cache_data = self._cache_data + if cache_update_freq: + self.cache.update_freq = cache_update_freq + + @property + def url(self): + if None is self._url: + self._url = self._valid_home() + self._valid_url() + return self._url + + @url.setter + def url(self, value=None): + self._url = value + + def _valid_url(self): + return True def image_name(self): @@ -777,6 +798,65 @@ class TorrentProvider(object, GenericProvider): search_params += [crop.sub(r'\1', '%s %s%s' % (name, x, detail)) for x in prefix] return search_params + @staticmethod + def _has_signature(data=None): + return data and re.search(r'(?sim) max([len(x) for x in url_list]): + return None + + last_url, expire = sickbeard.PROVIDER_HOMES.get(self.get_id(), ('', None)) + if 'site down' == last_url: + if expire and (expire > int(time.time())): + return None + elif last_url: + last_url in url_list and url_list.remove(last_url) + url_list.insert(0, last_url) + + for cur_url in url_list: + if not self.is_valid_mod(cur_url): + return None + + if 10 < len(cur_url) and ((expire and (expire > int(time.time()))) or + self._has_signature(helpers.getURL(cur_url, session=self.session))): + + for k, v in getattr(self, 'url_tmpl', {}).items(): + self.urls[k] = v % {'home': cur_url, 'vars': getattr(self, 'url_vars', {}).get(k, '')} + + if last_url != cur_url or (expire and not (expire > int(time.time()))): + sickbeard.PROVIDER_HOMES[self.get_id()] = (cur_url, int(time.time()) + (15*60)) + sickbeard.save_config() + return cur_url + + logger.log('Failed to identify a "%s" page with %s %s (local network issue, site down, or ISP blocked) ' % + (self.name, len(url_list), ('URL', 'different URLs')[1 < len(url_list)]) + + 'Suggest; 1) Disable "%s" 2) Use a proxy/VPN' % self.get_id(), + (logger.WARNING, logger.ERROR)[self.enabled]) + self.urls = {} + sickbeard.PROVIDER_HOMES[self.get_id()] = ('site down', int(time.time()) + (5 * 60)) + sickbeard.save_config() + return None + + def is_valid_mod(self, url): + parsed, s, is_valid = urlparse.urlparse(url), 70000700, True + if 2012691328 == s + zlib.crc32(('.%s' % (parsed.netloc or parsed.path)).split('.')[-2]): + is_valid = False + file_name = '%s.py' % os.path.join(sickbeard.PROG_DIR, *self.__module__.split('.')) + if ek.ek(os.path.isfile, file_name): + with open(file_name, 'rb') as file_hd: + is_valid = 1661931498 == s + zlib.crc32(file_hd.read()) + return is_valid + def _authorised(self, logged_in=None, post_params=None, failed_msg=None, url=None, timeout=30): maxed_out = (lambda x: re.search(r'(?i)[1-3]((<[^>]+>)|\W)*(attempts|tries|remain)[\W\w]{,40}?(remain|left|attempt)', x)) @@ -791,6 +871,9 @@ class TorrentProvider(object, GenericProvider): if logged_in(): return True + if not self._valid_home(): + return False + if hasattr(self, 'digest'): self.cookies = re.sub(r'(?i)([\s\']+|cookie\s*:)', '', self.digest) success, msg = self._check_cookie() @@ -811,13 +894,14 @@ class TorrentProvider(object, GenericProvider): if url: response = helpers.getURL(url, session=self.session) try: - action = re.findall('[<]form[\w\W]+?action="([^"]+)', response)[0] - url = (self.urls.get('login_base') or - self.urls['config_provider_home_uri']) + action.lstrip('/') + action = re.findall('[<]form[\w\W]+?action=[\'\"]([^\'\"]+)', response)[0] + url = action if action.startswith('http') else \ + (self.urls.get('login_base') or self.urls['config_provider_home_uri']) + action.lstrip('/') - tags = re.findall(r'(?is)()', response) - nv = [(tup[0]) for tup in [re.findall(r'(?is)name="([^"]+)"(?:.*?value="([^"]+)")?', x) - for x in tags]] + tags = re.findall(r'(?is)()', response) + nv = [(tup[0]) for tup in [ + re.findall(r'(?is)name=[\'\"]([^\'\"]+)[\'\"](?:.*?value=[\'\"]([^\'\"]+)[\'\"])?', x) + for x in tags]] for name, value in nv: if name not in ('username', 'password'): post_params = isinstance(post_params, type({})) and post_params or {} @@ -854,10 +938,18 @@ class TorrentProvider(object, GenericProvider): if self.username and self.password: return True setting = 'Password or Username' + elif hasattr(self, 'username') and hasattr(self, 'api_key'): + if self.username and self.api_key: + return True + setting = 'Apikey or Username' elif hasattr(self, 'username') and hasattr(self, 'passkey'): if self.username and self.passkey: return True setting = 'Passkey or Username' + elif hasattr(self, 'uid') and hasattr(self, 'passkey'): + if self.uid and self.passkey: + return True + setting = 'Passkey or uid' elif hasattr(self, 'api_key'): if self.api_key: return True @@ -899,7 +991,7 @@ class TorrentProvider(object, GenericProvider): @staticmethod def _has_no_results(*html): - return re.search(r'(?i)<(?:b|h\d|strong)[^>]*>(?:' + + return re.search(r'(?i)<(?:b|div|h\d|span|strong)[^>]*>(?:' + 'your\ssearch\sdid\snot\smatch|' + 'nothing\sfound|' + 'no\storrents\sfound|' + @@ -907,7 +999,6 @@ class TorrentProvider(object, GenericProvider): '.*?no\shits\.\sTry\sadding' + ')', html[0]) - def cache_data(self, *args, **kwargs): + def _cache_data(self): - search_params = {'Cache': ['']} - return self._search_provider(search_params) + return self._search_provider({'Cache': ['']}) diff --git a/sickbeard/providers/gftracker.py b/sickbeard/providers/gftracker.py index bc49bfb3..462403f6 100644 --- a/sickbeard/providers/gftracker.py +++ b/sickbeard/providers/gftracker.py @@ -20,7 +20,7 @@ import time import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -29,7 +29,7 @@ from lib.unidecode import unidecode class GFTrackerProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'GFTracker') + generic.TorrentProvider.__init__(self, 'GFTracker', cache_update_freq=17) self.url_base = 'https://thegft.org/' self.urls = {'config_provider_home_uri': self.url_base, @@ -44,7 +44,6 @@ class GFTrackerProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.cache = GFTrackerCache(self) def _authorised(self, **kwargs): @@ -122,16 +121,4 @@ class GFTrackerProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs) -class GFTrackerCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 17 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = GFTrackerProvider() diff --git a/sickbeard/providers/grabtheinfo.py b/sickbeard/providers/grabtheinfo.py index efbab804..dd6e92d3 100644 --- a/sickbeard/providers/grabtheinfo.py +++ b/sickbeard/providers/grabtheinfo.py @@ -19,7 +19,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -28,7 +28,7 @@ from lib.unidecode import unidecode class GrabTheInfoProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'GrabTheInfo') + generic.TorrentProvider.__init__(self, 'GrabTheInfo', cache_update_freq=20) self.url_base = 'http://grabthe.info/' self.urls = {'config_provider_home_uri': self.url_base, @@ -41,9 +41,7 @@ class GrabTheInfoProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = GrabTheInfoCache(self) + self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] def _search_provider(self, search_params, **kwargs): @@ -57,7 +55,7 @@ class GrabTheInfoProvider(generic.TorrentProvider): for mode in search_params.keys(): for search_string in search_params[mode]: search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string - search_url = self.urls['browse'] % (self._categories_string(), ('0', '3')[self.freeleech], + search_url = self.urls['browse'] % (self._categories_string(), ('3', '0')[not self.freeleech], (self.urls['search'] % search_string, '')['Cache' == mode]) html = self.get_url(search_url) @@ -120,16 +118,4 @@ class GrabTheInfoProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs) -class GrabTheInfoCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = GrabTheInfoProvider() diff --git a/sickbeard/providers/hd4free.py b/sickbeard/providers/hd4free.py new file mode 100644 index 00000000..ba9b89c5 --- /dev/null +++ b/sickbeard/providers/hd4free.py @@ -0,0 +1,81 @@ +# coding=utf-8 +# +# This file is part of SickGear. +# +# SickGear is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SickGear is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SickGear. If not, see . + +import time + +from . import generic +from sickbeard.helpers import tryInt + + +class HD4FreeProvider(generic.TorrentProvider): + + def __init__(self): + generic.TorrentProvider.__init__(self, 'HD4Free') + + self.url_base = 'https://hd4free.xyz/' + + self.urls = {'search': self.url_base + 'searchapi.php', + 'get': self.url_base + 'download.php?torrent=%s&torrent_pass=%s'} + + self.url = self.url_base + + self.username, self.api_key, self.freeleech, self.minseed, self.minleech = 5 * [None] + + def _authorised(self, **kwargs): + + return self._check_auth() + + def _search_provider(self, search_params, age=0, **kwargs): + + results = [] + if not self._authorised(): + return results + + items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} + + params = {'username': self.username, 'apikey': self.api_key, + 'tv': 'true', 'fl': ('true', None)[not self.freeleech]} + for mode in search_params.keys(): + for search_string in search_params[mode]: + params['search'] = '+'.join(search_string.split()) + data_json = self.get_url(self.urls['search'], params=params, json=True) + + cnt = len(items[mode]) + for k, item in data_json.items(): + if 'error' == k or not item.get('total_results'): + break + seeders, leechers, size = [tryInt(n, n) for n in [ + item.get(x) for x in 'seeders', 'leechers', 'size']] + if self._peers_fail(mode, seeders, leechers): + continue + title = item.get('release_name') + download_url = (self.urls['get'] % (item.get('torrentid'), item.get('torrentpass')), None)[ + not (item.get('torrentid') and item.get('torrentpass'))] + if title and download_url: + items[mode].append((title, download_url, seeders, self._bytesizer('%smb' % size))) + + self._log_search(mode, len(items[mode]) - cnt, self.session.response['url']) + time.sleep(1.1) + + self._sort_seeders(mode, items) + + results = list(set(results + items[mode])) + + return results + + +provider = HD4FreeProvider() diff --git a/sickbeard/providers/hdbits.py b/sickbeard/providers/hdbits.py index 308a830b..8ba0c731 100644 --- a/sickbeard/providers/hdbits.py +++ b/sickbeard/providers/hdbits.py @@ -19,7 +19,7 @@ import re import urllib from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.exceptions import AuthException from sickbeard.helpers import tryInt from sickbeard.indexers import indexer_config @@ -33,7 +33,7 @@ except ImportError: class HDBitsProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'HDBits') + generic.TorrentProvider.__init__(self, 'HDBits', cache_update_freq=15) # api_spec: https://hdbits.org/wiki/API self.url_base = 'https://hdbits.org/' @@ -46,9 +46,7 @@ class HDBitsProvider(generic.TorrentProvider): self.proper_search_terms = [' proper ', ' repack '] self.url = self.urls['config_provider_home_uri'] - self.username, self.passkey, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = HDBitsCache(self) + self.username, self.passkey, self.freeleech, self.minseed, self.minleech = 5 * [None] def check_auth_from_data(self, parsed_json): @@ -148,16 +146,4 @@ class HDBitsProvider(generic.TorrentProvider): return results -class HDBitsCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 15 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = HDBitsProvider() diff --git a/sickbeard/providers/hdspace.py b/sickbeard/providers/hdspace.py index 35c53599..f0b1522b 100644 --- a/sickbeard/providers/hdspace.py +++ b/sickbeard/providers/hdspace.py @@ -19,7 +19,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from lib.unidecode import unidecode @@ -27,7 +27,7 @@ from lib.unidecode import unidecode class HDSpaceProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'HDSpace') + generic.TorrentProvider.__init__(self, 'HDSpace', cache_update_freq=17) self.url_base = 'https://hd-space.org/' self.urls = {'config_provider_home_uri': self.url_base, @@ -40,9 +40,7 @@ class HDSpaceProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = HDSpaceCache(self) + self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] def _authorised(self, **kwargs): @@ -124,16 +122,4 @@ class HDSpaceProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs) -class HDSpaceCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 17 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = HDSpaceProvider() diff --git a/sickbeard/providers/iptorrents.py b/sickbeard/providers/iptorrents.py index faaa5db3..8abc5576 100644 --- a/sickbeard/providers/iptorrents.py +++ b/sickbeard/providers/iptorrents.py @@ -19,7 +19,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from lib.unidecode import unidecode @@ -29,24 +29,24 @@ class IPTorrentsProvider(generic.TorrentProvider): def __init__(self): generic.TorrentProvider.__init__(self, 'IPTorrents') - self.url_base = 'https://iptorrents.eu/' - self.urls = {'config_provider_home_uri': self.url_base, - 'login': self.url_base + 'torrents/', - 'search': self.url_base + 't?%s;q=%s;qf=ti%s%s#torrents', - 'get': self.url_base + '%s'} + self.url_home = ['https://iptorrents.%s/' % u for u in 'eu', 'com', 'ru'] + + self.url_vars = {'login': 'getrss.php', 'search': 't?%s;q=%s;qf=ti%s%s#torrents', 'get': '%s'} + self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s', + 'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'} self.categories = {'shows': [4, 5, 22, 23, 24, 25, 26, 55, 65, 66, 73, 78, 79], 'anime': [60]} self.proper_search_terms = None - self.url = self.urls['config_provider_home_uri'] - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = IPTorrentsCache(self) + self.digest, self.freeleech, self.minseed, self.minleech = 4 * [None] def _authorised(self, **kwargs): - return super(IPTorrentsProvider, self)._authorised(post_params={'php': ''}) + return super(IPTorrentsProvider, self)._authorised( + logged_in=(lambda x=None: (None is x or 'RSS Link' in x) and self.has_all_cookies() and + self.session.cookies['uid'] in self.digest and self.session.cookies['pass'] in self.digest), + failed_msg=(lambda x=None: u'Invalid cookie details for %s. Check settings')) def _search_provider(self, search_params, **kwargs): @@ -61,8 +61,9 @@ class IPTorrentsProvider(generic.TorrentProvider): for search_string in search_params[mode]: search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string # URL with 50 tv-show results, or max 150 if adjusted in IPTorrents profile - search_url = self.urls['search'] % (self._categories_string(mode, '%s', ';'), search_string, - ('', ';free')[self.freeleech], (';o=seeders', '')['Cache' == mode]) + search_url = self.urls['search'] % ( + self._categories_string(mode, '%s', ';'), search_string, + (';free', '')[not self.freeleech], (';o=seeders', '')['Cache' == mode]) html = self.get_url(search_url) @@ -108,15 +109,9 @@ class IPTorrentsProvider(generic.TorrentProvider): return results - -class IPTorrentsCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - def _cache_data(self): - - return self.provider.cache_data() + @staticmethod + def ui_string(key): + return 'iptorrents_digest' == key and 'use... \'uid=xx; pass=yy\'' or '' provider = IPTorrentsProvider() diff --git a/sickbeard/providers/kat.py b/sickbeard/providers/kat.py index 97a418ed..8808e0e2 100644 --- a/sickbeard/providers/kat.py +++ b/sickbeard/providers/kat.py @@ -23,7 +23,7 @@ import traceback import urllib from . import generic -from sickbeard import config, logger, show_name_helpers, tvcache +from sickbeard import config, logger, show_name_helpers from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import (has_anime, tryInt) from sickbeard.common import Quality, mediaExtensions @@ -34,20 +34,22 @@ from lib.unidecode import unidecode class KATProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'KickAssTorrents') + generic.TorrentProvider.__init__(self, 'KickAssTorrents', cache_update_freq=20) - self.url_base = 'https://kat.ph/' - self.urls = {'config_provider_home_uri': self.url_base, - 'base': [self.url_base, 'http://katproxy.com/'], - 'search': 'usearch/%s/', - 'sorted': '?field=time_add&sorder=desc'} + self.url_home = ['https://%s/' % u for u in 'kat.ph', 'kat.cr', 'kickass.unblocked.red', 'katproxy.com'] + + self.url_vars = {'search': 'usearch/%s/?field=time_add&sorder=desc', 'get': '%s'} + self.url_tmpl = {'config_provider_home_uri': '%(home)s', + 'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'} self.proper_search_terms = None - self.url = self.urls['config_provider_home_uri'] self.minseed, self.minleech = 2 * [None] self.confirmed = False - self.cache = KATCache(self) + + @staticmethod + def _has_signature(data=None): + return data and (re.search(r'(?sim)(KAT)', data[15:1024:]) or 'kastatic' in data) def _find_season_quality(self, title, torrent_link, ep_number): """ Return the modified title of a Season Torrent with the quality found inspecting torrent file list """ @@ -135,7 +137,7 @@ class KATProvider(generic.TorrentProvider): items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'link': 'normal', 'get': '^magnet', 'verif': 'verif'}.items()) - url = 0 + for mode in search_params.keys(): search_show = mode in ['Season', 'Episode'] if not search_show and has_anime(): @@ -145,19 +147,17 @@ class KATProvider(generic.TorrentProvider): for enum, search_string in enumerate(search_params[mode]): search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string - self.url = self.urls['base'][url] - search_url = self.url + (self.urls['search'] % urllib.quote('%scategory:%s' % ( + search_url = self.urls['search'] % urllib.quote('%scategory:%s' % ( ('', '%s ' % search_string)['Cache' != mode], - ('tv', 'anime')[(search_show and bool(self.show and self.show.is_anime)) or bool(enum)]))) + ('tv', 'anime')[(search_show and bool(self.show and self.show.is_anime)) or bool(enum)])) self.session.headers.update({'Referer': search_url}) - html = self.get_url(search_url + self.urls['sorted']) + html = self.get_url(search_url) cnt = len(items[mode]) try: - if not html or 'kastatic' not in html or self._has_no_results(html) or re.search(r'(?is)<(?:h\d)[^>]*>.*?(?:did\snot\smatch)', html): - if html and 'kastatic' not in html: - url += (1, 0)[url == len(self.urls['base'])] + if not html or self._has_no_results(html) or \ + re.search(r'(?is)<(?:h\d)[^>]*>.*?(?:did\snot\smatch)', html): raise generic.HaltParseException with BS4Parser(html, features=['html5lib', 'permissive']) as soup: @@ -183,11 +183,13 @@ class KATProvider(generic.TorrentProvider): except (AttributeError, TypeError, ValueError): continue - if self.confirmed and not (tr.find('a', title=rc['verif']) or tr.find('i', title=rc['verif'])): + if self.confirmed and not (tr.find('a', title=rc['verif']) or + tr.find('i', title=rc['verif'])): logger.log(u'Skipping untrusted non-verified result: %s' % title, logger.DEBUG) continue - # Check number video files = episode in season and find the real Quality for full season torrent analyzing files in torrent + # Check number video files = episode in season and find the real Quality for + # full season torrent analyzing files in torrent if 'Season' == mode and 'sponly' == search_mode: ep_number = int(epcount / len(set(show_name_helpers.allPossibleShowNames(self.show)))) title = self._find_season_quality(title, link, ep_number) @@ -208,16 +210,4 @@ class KATProvider(generic.TorrentProvider): return results -class KATCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = KATProvider() diff --git a/sickbeard/providers/morethan.py b/sickbeard/providers/morethan.py index 4da685ba..4ecdb796 100644 --- a/sickbeard/providers/morethan.py +++ b/sickbeard/providers/morethan.py @@ -21,7 +21,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -30,19 +30,19 @@ from lib.unidecode import unidecode class MoreThanProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'MoreThan') + generic.TorrentProvider.__init__(self, 'MoreThan', cache_update_freq=20) self.url_base = 'https://www.morethan.tv/' self.urls = {'config_provider_home_uri': self.url_base, 'login': self.url_base + 'login.php', 'search': self.url_base + 'torrents.php?searchstr=%s&' + '&'.join([ - 'tags_type=1', 'order_by=time', '&order_way=desc', 'filter_cat[2]=1', 'action=basic', 'searchsubmit=1']), + 'tags_type=1', 'order_by=time', 'order_way=desc', + 'filter_cat[2]=1', 'action=basic', 'searchsubmit=1']), 'get': self.url_base + '%s'} self.url = self.urls['config_provider_home_uri'] self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.cache = MoreThanCache(self) def _authorised(self, **kwargs): @@ -95,7 +95,7 @@ class MoreThanProvider(generic.TorrentProvider): title = '%s %s' % (tr.find('div', attrs={'class': rc['name']}).get_text().strip(), title) - link = str(tr.find('a', title=rc['get'])['href']).replace('&', '&').lstrip('/') + link = str(tr.find('a', href=rc['get'])['href']).replace('&', '&').lstrip('/') download_url = self.urls['get'] % link except (AttributeError, TypeError, ValueError): continue @@ -117,16 +117,4 @@ class MoreThanProvider(generic.TorrentProvider): return results -class MoreThanCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = MoreThanProvider() diff --git a/sickbeard/providers/newznab.py b/sickbeard/providers/newznab.py index f9c9c55c..aab020f9 100755 --- a/sickbeard/providers/newznab.py +++ b/sickbeard/providers/newznab.py @@ -27,14 +27,14 @@ from sickbeard.exceptions import AuthException class NewznabProvider(generic.NZBProvider): - def __init__(self, name, url, key='', cat_ids='5030,5040', search_mode='eponly', + def __init__(self, name, url, key='', cat_ids=None, search_mode=None, search_fallback=False, enable_recentsearch=False, enable_backlog=False): generic.NZBProvider.__init__(self, name, True, False) self.url = url self.key = key - self.cat_ids = cat_ids - self.search_mode = search_mode + self.cat_ids = cat_ids or '5030,5040' + self.search_mode = search_mode or 'eponly' self.search_fallback = search_fallback self.enable_recentsearch = enable_recentsearch self.enable_backlog = enable_backlog @@ -81,11 +81,11 @@ class NewznabProvider(generic.NZBProvider): if isinstance(api_key, basestring): params['apikey'] = api_key - categories = self.get_url('%s/api' % self.url, params=params, timeout=10) + url = '%s/api?%s' % (self.url.strip('/'), '&'.join(['%s=%s' % (k, v) for k, v in params.items()])) + categories = self.get_url(url, timeout=10) if not categories: - logger.log(u'Error getting html for [%s]' % self.session.response['url'], logger.DEBUG) - return (False, return_categories, 'Error getting html for [%s]' % - ('%s/api?%s' % (self.url, '&'.join('%s=%s' % (x, y) for x, y in params.items())))) + logger.log(u'Error getting html for [%s]' % url, logger.DEBUG) + return False, return_categories, 'Error getting html for [%s]' % url xml_categories = helpers.parse_xml(categories) if not xml_categories: @@ -114,16 +114,20 @@ class NewznabProvider(generic.NZBProvider): base_params = {} # season + ep_detail = None if ep_obj.show.air_by_date or ep_obj.show.is_sports: - date_str = str(ep_obj.airdate).split('-')[0] - base_params['season'] = date_str - base_params['q'] = date_str.replace('-', '.') + airdate = str(ep_obj.airdate).split('-')[0] + base_params['season'] = airdate + base_params['q'] = airdate + if ep_obj.show.air_by_date: + ep_detail = '+"%s"' % airdate elif ep_obj.show.is_anime: base_params['season'] = '%d' % ep_obj.scene_absolute_number else: base_params['season'] = str((ep_obj.season, ep_obj.scene_season)[bool(ep_obj.show.is_scene)]) + ep_detail = 'S%02d' % helpers.tryInt(base_params['season'], 1) - # search + # id search ids = helpers.mapIndexersToShow(ep_obj.show) if ids[1]: # or ids[2]: params = base_params.copy() @@ -136,7 +140,7 @@ class NewznabProvider(generic.NZBProvider): use_id = True use_id and search_params.append(params) - # add new query strings for exceptions + # query search and exceptions name_exceptions = list( set([helpers.sanitizeSceneName(a) for a in scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name]])) @@ -144,7 +148,14 @@ class NewznabProvider(generic.NZBProvider): params = base_params.copy() if 'q' in params: params['q'] = '%s.%s' % (cur_exception, params['q']) - search_params.append(params) + search_params.append(params) + + if ep_detail: + params = base_params.copy() + params['q'] = '%s.%s' % (cur_exception, ep_detail) + 'season' in params and params.pop('season') + 'ep' in params and params.pop('ep') + search_params.append(params) return [{'Season': search_params}] @@ -156,18 +167,25 @@ class NewznabProvider(generic.NZBProvider): if not ep_obj: return [base_params] + ep_detail = None if ep_obj.show.air_by_date or ep_obj.show.is_sports: - date_str = str(ep_obj.airdate) - base_params['season'] = date_str.partition('-')[0] - base_params['ep'] = date_str.partition('-')[2].replace('-', '/') + airdate = str(ep_obj.airdate).split('-') + base_params['season'] = airdate[0] + if ep_obj.show.air_by_date: + base_params['ep'] = '/'.join(airdate[1:]) + ep_detail = '+"%s.%s"' % (base_params['season'], '.'.join(airdate[1:])) elif ep_obj.show.is_anime: - base_params['ep'] = '%i' % int( - ep_obj.scene_absolute_number if int(ep_obj.scene_absolute_number) > 0 else ep_obj.scene_episode) + base_params['ep'] = '%i' % (helpers.tryInt(ep_obj.scene_absolute_number) or + helpers.tryInt(ep_obj.scene_episode)) + ep_detail = '%02d' % base_params['ep'] else: base_params['season'], base_params['ep'] = ( (ep_obj.season, ep_obj.episode), (ep_obj.scene_season, ep_obj.scene_episode))[ep_obj.show.is_scene] + ep_detail = sickbeard.config.naming_ep_type[2] % { + 'seasonnumber': helpers.tryInt(base_params['season'], 1), + 'episodenumber': helpers.tryInt(base_params['ep'], 1)} - # search + # id search ids = helpers.mapIndexersToShow(ep_obj.show) if ids[1]: # or ids[2]: params = base_params.copy() @@ -181,7 +199,7 @@ class NewznabProvider(generic.NZBProvider): use_id = True use_id and search_params.append(params) - # add new query strings for exceptions + # query search and exceptions name_exceptions = list( set([helpers.sanitizeSceneName(a) for a in scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name]])) @@ -191,15 +209,11 @@ class NewznabProvider(generic.NZBProvider): params['q'] = cur_exception search_params.append(params) - if ep_obj.show.is_anime: - # Experimental, add a search string without search explicitly for the episode! - # Remove the ?ep=e46 parameter and use the episode number to the query parameter. - # Can be useful for newznab indexers that do not have the episodes 100% parsed. - # Start with only applying the search string to anime shows + if ep_detail: params = base_params.copy() - params['q'] = '%s.%02d' % (cur_exception, int(params['ep'])) - if 'ep' in params: - params.pop('ep') + params['q'] = '%s.%s' % (cur_exception, ep_detail) + 'season' in params and params.pop('season') + 'ep' in params and params.pop('ep') search_params.append(params) return [{'Episode': search_params}] @@ -229,8 +243,10 @@ class NewznabProvider(generic.NZBProvider): # category ids cat = [] - cat_anime = ('5070', '6070')['nzbs_org' == self.get_id()] - cat_sport = '5060' + cat_sport = ['5060'] + cat_anime = [] + if 'nzbgeek' != self.get_id(): + cat_anime = (['5070'], ['6070'])['nzbs_org' == self.get_id()] if 'Episode' == mode or 'Season' == mode: if not ('rid' in params or 'tvdbid' in params or 'q' in params or not self.supports_tvdbid()): logger.log('Error no rid, tvdbid, or search term available for search.') @@ -238,18 +254,24 @@ class NewznabProvider(generic.NZBProvider): if self.show: if self.show.is_sports: - cat = [cat_sport] + cat = cat_sport elif self.show.is_anime: - cat = [cat_anime] + cat = cat_anime else: - cat = [cat_sport, cat_anime] + cat = cat_sport + cat_anime if self.cat_ids or len(cat): base_params['cat'] = ','.join(sorted(set(self.cat_ids.split(',') + cat))) request_params = base_params.copy() + if 'q' in params and not (any(x in params for x in ['season', 'ep'])): + request_params['t'] = 'search' request_params.update(params) + # workaround a strange glitch + if sum(ord(i) for i in self.get_id()) in [383] and 5 == 14 - request_params['maxage']: + request_params['maxage'] += 1 + offset = 0 batch_count = not 0 @@ -336,18 +358,17 @@ class NewznabCache(tvcache.TVCache): result = [] - if True or self.shouldUpdate(): + if 4489 != sickbeard.RECENTSEARCH_FREQUENCY or self.should_update(): try: self._checkAuth() + items = self.provider.cache_data() except Exception: - return result + items = None - items = self.provider.cache_data() if items: - self._clearCache() - self.setLastUpdate() + # parse data cl = [] for item in items: ci = self._parseItem(item) @@ -358,6 +379,9 @@ class NewznabCache(tvcache.TVCache): my_db = self.get_db() my_db.mass_action(cl) + # set updated as time the attempt to fetch data is + self.setLastUpdate() + return result # overwrite method with that parses the rageid from the newznab feed diff --git a/sickbeard/providers/pisexy.py b/sickbeard/providers/pisexy.py index c838aecd..74f247d7 100644 --- a/sickbeard/providers/pisexy.py +++ b/sickbeard/providers/pisexy.py @@ -17,7 +17,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -37,7 +37,6 @@ class PiSexyProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.cache = PiSexyCache(self) def _authorised(self, **kwargs): @@ -108,14 +107,4 @@ class PiSexyProvider(generic.TorrentProvider): return results -class PiSexyCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - def _cache_data(self): - - return self.provider.cache_data() - - provider = PiSexyProvider() diff --git a/sickbeard/providers/pretome.py b/sickbeard/providers/pretome.py index 0b9a763d..7a49c1a9 100644 --- a/sickbeard/providers/pretome.py +++ b/sickbeard/providers/pretome.py @@ -16,7 +16,6 @@ # along with SickGear. If not, see <http://www.gnu.org/licenses/>. from . import generic -from sickbeard import tvcache from sickbeard.rssfeeds import RSSFeeds from lib.unidecode import unidecode @@ -24,7 +23,7 @@ from lib.unidecode import unidecode class PreToMeProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'PreToMe') + generic.TorrentProvider.__init__(self, 'PreToMe', cache_update_freq=6) self.url_base = 'https://pretome.info/' @@ -35,7 +34,6 @@ class PreToMeProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] self.passkey = None - self.cache = PreToMeCache(self) def _authorised(self, **kwargs): @@ -72,16 +70,4 @@ class PreToMeProvider(generic.TorrentProvider): return results -class PreToMeCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 6 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = PreToMeProvider() diff --git a/sickbeard/providers/rarbg.py b/sickbeard/providers/rarbg.py index f32b3b64..6e520d0f 100644 --- a/sickbeard/providers/rarbg.py +++ b/sickbeard/providers/rarbg.py @@ -21,7 +21,7 @@ import datetime import time from . import generic -from sickbeard import helpers, logger, tvcache +from sickbeard import helpers, logger from sickbeard.indexers.indexer_config import INDEXER_TVDB @@ -51,7 +51,6 @@ class RarbgProvider(generic.TorrentProvider): self.minseed, self.minleech, self.token, self.token_expiry = 4 * [None] self.confirmed = False self.request_throttle = datetime.datetime.now() - self.cache = RarbgCache(self) def _authorised(self, reset=False, **kwargs): @@ -178,14 +177,4 @@ class RarbgProvider(generic.TorrentProvider): return search_params -class RarbgCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - def _cache_data(self): - - return self.provider.cache_data() - - provider = RarbgProvider() diff --git a/sickbeard/providers/scc.py b/sickbeard/providers/scc.py index 039985a7..acce2694 100644 --- a/sickbeard/providers/scc.py +++ b/sickbeard/providers/scc.py @@ -20,7 +20,7 @@ import time import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -31,18 +31,16 @@ class SCCProvider(generic.TorrentProvider): def __init__(self): generic.TorrentProvider.__init__(self, 'SceneAccess') - self.url_base = 'https://sceneaccess.eu/' - self.urls = {'config_provider_home_uri': self.url_base, - 'login': self.url_base + 'login', - 'search': self.url_base + 'browse?search=%s&method=1&c27=27&c17=17&c11=11', - 'nonscene': self.url_base + 'nonscene?search=%s&method=1&c44=44&c45=44', - 'archive': self.url_base + 'archive?search=%s&method=1&c26=26', - 'get': self.url_base + '%s'} + self.url_home = ['https://sceneaccess.%s/' % u for u in 'eu', 'org'] - self.url = self.urls['config_provider_home_uri'] + self.url_vars = { + 'login': 'login', 'search': 'browse?search=%s&method=1&c27=27&c17=17&c11=11', 'get': '%s', + 'nonscene': 'nonscene?search=%s&method=1&c44=44&c45=44', 'archive': 'archive?search=%s&method=1&c26=26'} + self.url_tmpl = { + 'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s', 'search': '%(home)s%(vars)s', + 'get': '%(home)s%(vars)s', 'nonscene': '%(home)s%(vars)s', 'archive': '%(home)s%(vars)s'} self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.cache = SCCCache(self) def _authorised(self, **kwargs): @@ -121,16 +119,4 @@ class SCCProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', **kwargs) -class SCCCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = SCCProvider() diff --git a/sickbeard/providers/scenetime.py b/sickbeard/providers/scenetime.py index 0af4552d..a337f539 100644 --- a/sickbeard/providers/scenetime.py +++ b/sickbeard/providers/scenetime.py @@ -20,7 +20,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -29,7 +29,7 @@ from lib.unidecode import unidecode class SceneTimeProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'SceneTime') + generic.TorrentProvider.__init__(self, 'SceneTime', cache_update_freq=15) self.url_base = 'https://www.scenetime.com/' self.urls = {'config_provider_home_uri': self.url_base, @@ -42,9 +42,7 @@ class SceneTimeProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = SceneTimeCache(self) + self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] def _authorised(self, **kwargs): @@ -58,15 +56,16 @@ class SceneTimeProvider(generic.TorrentProvider): items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} - rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': '.*id=(\d+).*', 'fl': '\[freeleech\]', - 'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|') - }.items()) + rc = dict((k, re.compile('(?i)' + v)) for (k, v) in { + 'info': 'detail', 'get': '.*id=(\d+).*', 'fl': '\[freeleech\]', + 'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|')}.items()) for mode in search_params.keys(): for search_string in search_params[mode]: search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string post_data = self.urls['params'].copy() - post_data.update(ast.literal_eval('{%s}' % self._categories_string(template='"c%s": "1"', delimiter=','))) + post_data.update(ast.literal_eval( + '{%s}' % self._categories_string(template='"c%s": "1"', delimiter=','))) if 'Cache' != mode: search_string = '+'.join(search_string.split()) post_data['search'] = search_string @@ -99,10 +98,11 @@ class SceneTimeProvider(generic.TorrentProvider): continue info = tr.find('a', href=rc['info']) - title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip() + title = info.attrs.get('title') or info.get_text().strip() - download_url = self.urls['get'] % {'id': re.sub(rc['get'], r'\1', str(info.attrs['href'])), - 'title': str(title).replace(' ', '.')} + download_url = self.urls['get'] % { + 'id': re.sub(rc['get'], r'\1', str(info.attrs['href'])), + 'title': str(title).replace(' ', '.')} except (AttributeError, TypeError, ValueError): continue @@ -124,16 +124,4 @@ class SceneTimeProvider(generic.TorrentProvider): return results -class SceneTimeCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 15 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = SceneTimeProvider() diff --git a/sickbeard/providers/shazbat.py b/sickbeard/providers/shazbat.py index 80f5f09a..bc5650cc 100644 --- a/sickbeard/providers/shazbat.py +++ b/sickbeard/providers/shazbat.py @@ -22,7 +22,7 @@ import time import traceback from . import generic -from sickbeard import helpers, logger, tvcache +from sickbeard import helpers, logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -32,7 +32,7 @@ class ShazbatProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'Shazbat') + generic.TorrentProvider.__init__(self, 'Shazbat', cache_update_freq=20) self.url_base = 'https://www.shazbat.tv/' self.urls = {'config_provider_home_uri': self.url_base, @@ -46,8 +46,6 @@ class ShazbatProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = ShazbatCache(self) def _authorised(self, **kwargs): @@ -147,16 +145,4 @@ class ShazbatProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, detail_only=True, scene=False, **kwargs) -class ShazbatCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = ShazbatProvider() diff --git a/sickbeard/providers/speedcd.py b/sickbeard/providers/speedcd.py index e4a896ba..ba20732c 100644 --- a/sickbeard/providers/speedcd.py +++ b/sickbeard/providers/speedcd.py @@ -19,34 +19,32 @@ import re import time from . import generic -from sickbeard import tvcache +from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt class SpeedCDProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'SpeedCD') + generic.TorrentProvider.__init__(self, 'SpeedCD', cache_update_freq=20) - self.url_base = 'http://speed.cd/' + self.url_base = 'https://speed.cd/' self.urls = {'config_provider_home_uri': self.url_base, 'login_action': self.url_base + 'login.php', 'search': self.url_base + 'V3/API/API.php', - 'get': self.url_base + 'download.php?torrent=%s'} + 'get': self.url_base + '%s'} - self.categories = {'Season': {'c41': 1, 'c53': 1}, - 'Episode': {'c2': 1, 'c49': 1, 'c50': 1, 'c55': 1}, - 'Cache': {'c41': 1, 'c2': 1, 'c49': 1, 'c50': 1, 'c53': 1, 'c55': 1}} + self.categories = {'Season': [41, 53], 'Episode': [2, 49, 50, 55], 'anime': [30]} + self.categories['Cache'] = self.categories['Season'] + self.categories['Episode'] self.url = self.urls['config_provider_home_uri'] - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = SpeedCDCache(self) + self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] def _authorised(self, **kwargs): - return super(SpeedCDProvider, self)._authorised(logged_in=(lambda x=None: self.has_all_cookies('inSpeed_speedian'))) + return super(SpeedCDProvider, self)._authorised( + logged_in=(lambda x=None: self.has_all_cookies('inSpeed_speedian'))) def _search_provider(self, search_params, **kwargs): @@ -56,37 +54,49 @@ class SpeedCDProvider(generic.TorrentProvider): items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} - remove_tag = re.compile(r'<[^>]*>') + rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'get': 'download', 'fl': '\[freeleech\]'}.items()) + for mode in search_params.keys(): - search_mode = (mode, 'Episode')['Propers' == mode] + rc['cats'] = re.compile('(?i)cat=(?:%s)' % self._categories_string(mode, template='', delimiter='|')) for search_string in search_params[mode]: search_string = '+'.join(search_string.split()) - post_data = dict({'/browse.php?': None, 'cata': 'yes', 'jxt': 4, 'jxw': 'b', 'search': search_string}, - **self.categories[search_mode]) - if self.freeleech: - post_data['freeleech'] = 'on' + post_data = dict((x.split('=') for x in self._categories_string(mode).split('&')), search=search_string, + jxt=2, jxw='b', freeleech=('on', None)[not self.freeleech]) data_json = self.get_url(self.urls['search'], post_data=post_data, json=True) cnt = len(items[mode]) try: - if not data_json: + html = data_json.get('Fs')[0].get('Cn')[0].get('d') + if not html or self._has_no_results(html): raise generic.HaltParseException - torrents = data_json.get('Fs', [])[0].get('Cn', {}).get('torrents', []) - for item in torrents: + with BS4Parser(html, features=['html5lib', 'permissive']) as soup: + torrent_table = soup.find('table', attrs={'cellspacing': 0}) + torrent_rows = [] if not torrent_table else torrent_table.find_all('tr') - if self.freeleech and not item.get('free'): - continue + if 2 > len(torrent_rows): + raise generic.HaltParseException - seeders, leechers, size = [tryInt(n, n) for n in [item.get(x) for x in 'seed', 'leech', 'size']] - if self._peers_fail(mode, seeders, leechers): - continue + for tr in torrent_rows[1:]: + try: + seeders, leechers, size = [tryInt(n, n) for n in [ + tr.find_all('td')[x].get_text().strip() for x in (-2, -1, -3)]] + if None is tr.find('a', href=rc['cats']) \ + or self.freeleech and None is rc['fl'].search(tr.find_all('td')[1].get_text()) \ + or self._peers_fail(mode, seeders, leechers): + continue - title = remove_tag.sub('', item.get('name')) - download_url = self.urls['get'] % item.get('id') - if title and download_url: - items[mode].append((title, download_url, seeders, self._bytesizer(size))) + info = tr.find('a', 'torrent') + title = info.attrs.get('title') or info.get_text().strip() + + download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/') + + except (AttributeError, TypeError, ValueError): + continue + + if title and download_url: + items[mode].append((title, download_url, seeders, self._bytesizer(size))) except Exception: time.sleep(1.1) @@ -105,16 +115,4 @@ class SpeedCDProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', **kwargs) -class SpeedCDCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = SpeedCDProvider() diff --git a/sickbeard/providers/thepiratebay.py b/sickbeard/providers/thepiratebay.py index bec87ae0..c46c0b7d 100644 --- a/sickbeard/providers/thepiratebay.py +++ b/sickbeard/providers/thepiratebay.py @@ -23,7 +23,7 @@ import traceback import urllib from . import generic -from sickbeard import config, logger, tvcache, show_name_helpers +from sickbeard import config, logger, show_name_helpers from sickbeard.bs4_parser import BS4Parser from sickbeard.common import Quality, mediaExtensions from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException @@ -33,40 +33,32 @@ from lib.unidecode import unidecode class ThePirateBayProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'The Pirate Bay') + generic.TorrentProvider.__init__(self, 'The Pirate Bay', cache_update_freq=20) - self.urls = {'config_provider_home_uri': ['https://thepiratebay.se/', 'https://thepiratebay.gd/', - 'https://thepiratebay.mn/', 'https://thepiratebay.vg/', - 'https://thepiratebay.la/'], - 'search': 'search/%s/0/7/200', - 'browse': 'tv/latest/'} # order by seed + self.url_home = ['https://thepiratebay.%s/' % u for u in 'se', 'org'] + + self.url_vars = {'search': 'search/%s/0/7/200', 'browse': 'tv/latest/'} + self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'search': '%(home)s%(vars)s', + 'browse': '%(home)s%(vars)s'} self.proper_search_terms = None - self.url = self.urls['config_provider_home_uri'][0] self.minseed, self.minleech = 2 * [None] self.confirmed = False - self.cache = ThePirateBayCache(self) + + @staticmethod + def _has_signature(data=None): + return data and re.search(r'Pirate\sBay', data[33:7632:]) def _find_season_quality(self, title, torrent_id, ep_number): """ Return the modified title of a Season Torrent with the quality found inspecting torrent file list """ + if not self.url: + return False + quality = Quality.UNKNOWN file_name = None - data = None - has_signature = False - details_url = '/ajax_details_filelist.php?id=%s' % torrent_id - for idx, url in enumerate(self.urls['config_provider_home_uri']): - data = self.get_url(url + details_url) - if data and re.search(r'<title>The\sPirate\sBay', data[33:200:]): - has_signature = True - break - else: - data = None - - if not has_signature: - logger.log(u'Failed to identify a page from ThePirateBay at %s attempted urls (tpb blocked? general network issue or site dead)' % len(self.urls['config_provider_home_uri']), logger.ERROR) - + data = self.get_url('%sajax_details_filelist.php?id=%s' % (self.url, torrent_id)) if not data: return None @@ -138,30 +130,22 @@ class ThePirateBayProvider(generic.TorrentProvider): def _search_provider(self, search_params, search_mode='eponly', epcount=0, **kwargs): results = [] + if not self.url: + return results + items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download[^"]+magnet', 'tid': r'.*/(\d{5,}).*', 'verify': '(?:helper|moderator|trusted|vip)'}.items()) - has_signature = False + for mode in search_params.keys(): for search_string in search_params[mode]: search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string - log_url = '%s %s' % (self.name, search_string) # placebo value - for idx, search_url in enumerate(self.urls['config_provider_home_uri']): - search_url += self.urls['browse'] if 'Cache' == mode\ - else self.urls['search'] % (urllib.quote(search_string)) - - log_url = u'(%s/%s): %s' % (idx + 1, len(self.urls['config_provider_home_uri']), search_url) - - html = self.get_url(search_url) - - if html and re.search(r'Pirate\sBay', html[33:7632:]): - has_signature = True - break - else: - html = None + search_url = self.urls['browse'] if 'Cache' == mode \ + else self.urls['search'] % (urllib.quote(search_string)) + html = self.get_url(search_url) cnt = len(items[mode]) try: @@ -213,28 +197,13 @@ class ThePirateBayProvider(generic.TorrentProvider): pass except Exception: logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR) - self._log_search(mode, len(items[mode]) - cnt, log_url) + self._log_search(mode, len(items[mode]) - cnt, search_url) self._sort_seeders(mode, items) results = list(set(results + items[mode])) - if not has_signature: - logger.log(u'Failed to identify a page from ThePirateBay at %s attempted urls (tpb blocked? general network issue or site dead)' % len(self.urls['config_provider_home_uri']), logger.ERROR) - return results -class ThePirateBayCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = ThePirateBayProvider() diff --git a/sickbeard/providers/torrentbytes.py b/sickbeard/providers/torrentbytes.py index dc60d118..6dbaa82a 100644 --- a/sickbeard/providers/torrentbytes.py +++ b/sickbeard/providers/torrentbytes.py @@ -19,7 +19,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -28,21 +28,18 @@ from lib.unidecode import unidecode class TorrentBytesProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'TorrentBytes') + generic.TorrentProvider.__init__(self, 'TorrentBytes', cache_update_freq=20) - self.url_base = 'https://www.torrentbytes.net/' - self.urls = {'config_provider_home_uri': self.url_base, - 'login': self.url_base + 'takelogin.php', - 'search': self.url_base + 'browse.php?search=%s&%s', - 'get': self.url_base + '%s'} + self.url_home = ['https://www.torrentbytes.net/'] - self.categories = {'shows': [41, 33, 38, 32, 37]} + self.url_vars = {'login': 'takelogin.php', 'search': 'browse.php?search=%s&%s', 'get': '%s'} + self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s', + 'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'} - self.url = self.urls['config_provider_home_uri'] + self.categories = {'Season': [41, 32], 'Episode': [33, 37, 38]} + self.categories['Cache'] = self.categories['Season'] + self.categories['Episode'] - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = TorrentBytesCache(self) + self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] def _authorised(self, **kwargs): @@ -56,12 +53,12 @@ class TorrentBytesProvider(generic.TorrentProvider): items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} - rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download', 'fl': '\[\W*F\W?L\W*\]' - }.items()) + rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download', + 'fl': '\[\W*F\W?L\W*\]'}.items()) for mode in search_params.keys(): for search_string in search_params[mode]: search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string - search_url = self.urls['search'] % (search_string, self._categories_string()) + search_url = self.urls['search'] % (search_string, self._categories_string(mode)) html = self.get_url(search_url, timeout=90) @@ -82,11 +79,11 @@ class TorrentBytesProvider(generic.TorrentProvider): info = tr.find('a', href=rc['info']) seeders, leechers, size = [tryInt(n, n) for n in [ tr.find_all('td')[x].get_text().strip() for x in (-2, -1, -4)]] - if self.freeleech and (len(info.contents) < 2 or not rc['fl'].search(info.contents[1].string.strip())) \ - or self._peers_fail(mode, seeders, leechers): + if self.freeleech and (len(info.contents) < 2 or not rc['fl'].search( + info.contents[1].string.strip())) or self._peers_fail(mode, seeders, leechers): continue - title = 'title' in info.attrs and info.attrs['title'] or info.contents[0] + title = info.attrs.get('title') or info.contents[0] title = (isinstance(title, list) and title[0] or title).strip() download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/') except (AttributeError, TypeError, ValueError): @@ -109,16 +106,4 @@ class TorrentBytesProvider(generic.TorrentProvider): return results -class TorrentBytesCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = TorrentBytesProvider() diff --git a/sickbeard/providers/torrentday.py b/sickbeard/providers/torrentday.py index cf35ef8f..7dd6ea43 100644 --- a/sickbeard/providers/torrentday.py +++ b/sickbeard/providers/torrentday.py @@ -19,8 +19,7 @@ import re import time from . import generic -from sickbeard import tvcache -from sickbeard.helpers import (has_anime, tryInt) +from sickbeard.helpers import tryInt class TorrentDayProvider(generic.TorrentProvider): @@ -28,22 +27,19 @@ class TorrentDayProvider(generic.TorrentProvider): def __init__(self): generic.TorrentProvider.__init__(self, 'TorrentDay') - self.url_base = 'https://torrentday.eu/' - self.urls = {'config_provider_home_uri': self.url_base, - 'login': self.url_base + 'torrents/', - 'search': self.url_base + 'V3/API/API.php', - 'get': self.url_base + 'download.php/%s/%s'} + self.url_home = ['https://%s/' % u for u in 'torrentday.eu', 'secure.torrentday.com', 'tdonline.org', + 'torrentday.it', 'www.td.af', 'www.torrentday.com'] - self.categories = {'Season': {'c31': 1, 'c33': 1, 'c14': 1}, - 'Episode': {'c32': 1, 'c26': 1, 'c7': 1, 'c2': 1}, - 'Cache': {'c31': 1, 'c33': 1, 'c14': 1, 'c32': 1, 'c26': 1, 'c7': 1, 'c2': 1}} + self.url_vars = {'login': 'torrents/', 'search': 'V3/API/API.php', 'get': 'download.php/%s/%s'} + self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s', + 'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'} + + self.categories = {'Season': [31, 33, 14], 'Episode': [24, 32, 26, 7, 2], 'Anime': [29]} + self.categories['Cache'] = self.categories['Season'] + self.categories['Episode'] self.proper_search_terms = None - self.url = self.urls['config_provider_home_uri'] - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = TorrentDayCache(self) + self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] def _authorised(self, **kwargs): @@ -66,11 +62,8 @@ class TorrentDayProvider(generic.TorrentProvider): for mode in search_params.keys(): for search_string in search_params[mode]: search_string = '+'.join(search_string.split()) - post_data = dict({'/browse.php?': None, 'cata': 'yes', 'jxt': 8, 'jxw': 'b', 'search': search_string}, - **self.categories[(mode, 'Episode')['Propers' == mode]]) - if ('Cache' == mode and has_anime()) or ( - mode in ['Season', 'Episode'] and self.show and self.show.is_anime): - post_data.update({'c29': 1}) + post_data = dict((x.split('=') for x in self._categories_string(mode).split('&')), + search=search_string, cata='yes', jxt=8, jxw='b') if self.freeleech: post_data.update({'free': 'on'}) @@ -112,14 +105,4 @@ class TorrentDayProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', date_or=True, **kwargs) -class TorrentDayCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - def _cache_data(self): - - return self.provider.cache_data() - - provider = TorrentDayProvider() diff --git a/sickbeard/providers/torrenting.py b/sickbeard/providers/torrenting.py index 0a483ffa..7b1fb831 100644 --- a/sickbeard/providers/torrenting.py +++ b/sickbeard/providers/torrenting.py @@ -19,7 +19,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -30,25 +30,20 @@ class TorrentingProvider(generic.TorrentProvider): def __init__(self): generic.TorrentProvider.__init__(self, 'Torrenting') - self.url_base = 'https://www.torrenting.com/' + self.url_home = ['https://%s/' % u for u in 'www.torrenting.com', 'ttonline.us'] - self.api = 'https://ttonline.us/' - self.urls = {'config_provider_home_uri': self.url_base, - 'login': self.api + 'secure.php', - 'search': self.api + 'browse.php?%s&search=%s', - 'get': self.api + '%s'} + self.url_vars = {'login': 'rss.php', 'search': 'browse.php?%s&search=%s', 'get': '%s'} + self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s', + 'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'} self.categories = {'shows': [4, 5]} - self.url = self.urls['config_provider_home_uri'] - self.digest, self.minseed, self.minleech = 3 * [None] - self.cache = TorrentingCache(self) def _authorised(self, **kwargs): return super(TorrentingProvider, self)._authorised( - logged_in=(lambda x=None: (None is x or 'Other Links' in x) and self.has_all_cookies() and + logged_in=(lambda x=None: (None is x or 'RSS link' in x) and self.has_all_cookies() and self.session.cookies['uid'] in self.digest and self.session.cookies['pass'] in self.digest), failed_msg=(lambda x=None: u'Invalid cookie details for %s. Check settings')) @@ -60,9 +55,9 @@ class TorrentingProvider(generic.TorrentProvider): items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} - rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'detail', 'get': 'download', - 'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|') - }.items()) + rc = dict((k, re.compile('(?i)' + v)) for (k, v) in { + 'info': 'detail', 'cats': 'cat=(?:%s)' % self._categories_string(template='', delimiter='|'), + 'get': 'download'}.items()) for mode in search_params.keys(): for search_string in search_params[mode]: search_string = isinstance(search_string, unicode) and unidecode(search_string) or search_string @@ -90,8 +85,9 @@ class TorrentingProvider(generic.TorrentProvider): continue info = tr.find('a', href=rc['info']) - title = 'title' in info.attrs and info.attrs['title'] or info.get_text().strip() - download_url = self.urls['get'] % tr.find('a', href=rc['get']).get('href') + title = info.attrs.get('title') or info.get_text().strip() + download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip('/') + except (AttributeError, TypeError, ValueError): continue @@ -117,14 +113,4 @@ class TorrentingProvider(generic.TorrentProvider): return 'torrenting_digest' == key and 'use... \'uid=xx; pass=yy\'' or '' -class TorrentingCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - def _cache_data(self): - - return self.provider.cache_data() - - provider = TorrentingProvider() diff --git a/sickbeard/providers/torrentleech.py b/sickbeard/providers/torrentleech.py index c672ccbd..cfe5f05b 100644 --- a/sickbeard/providers/torrentleech.py +++ b/sickbeard/providers/torrentleech.py @@ -19,14 +19,14 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from lib.unidecode import unidecode class TorrentLeechProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'TorrentLeech') + generic.TorrentProvider.__init__(self, 'TorrentLeech', cache_update_freq=20) self.url_base = 'https://torrentleech.org/' self.urls = {'config_provider_home_uri': self.url_base, @@ -40,7 +40,6 @@ class TorrentLeechProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.cache = TorrentLeechCache(self) def _authorised(self, **kwargs): @@ -111,14 +110,5 @@ class TorrentLeechProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='|', **kwargs) -class TorrentLeechCache(tvcache.TVCache): - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - return self.provider.cache_data() - provider = TorrentLeechProvider() diff --git a/sickbeard/providers/torrentshack.py b/sickbeard/providers/torrentshack.py index 6a131418..19ea689b 100644 --- a/sickbeard/providers/torrentshack.py +++ b/sickbeard/providers/torrentshack.py @@ -21,7 +21,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -30,13 +30,14 @@ from lib.unidecode import unidecode class TorrentShackProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'TorrentShack') + generic.TorrentProvider.__init__(self, 'TorrentShack', cache_update_freq=20) self.url_base = 'https://torrentshack.me/' self.urls = {'config_provider_home_uri': self.url_base, 'login': self.url_base + 'login.php?lang=', 'search': self.url_base + 'torrents.php?searchstr=%s&%s&' + '&'.join( - ['release_type=both', 'searchtags=', 'tags_type=0', 'order_by=s3', 'order_way=desc', 'torrent_preset=all']), + ['release_type=both', 'searchtags=', 'tags_type=0', + 'order_by=s3', 'order_way=desc', 'torrent_preset=all']), 'get': self.url_base + '%s'} self.categories = {'shows': [600, 620, 700, 981, 980], 'anime': [850]} @@ -44,7 +45,6 @@ class TorrentShackProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.cache = TorrentShackCache(self) def _authorised(self, **kwargs): @@ -117,16 +117,4 @@ class TorrentShackProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, sep_date='.', **kwargs) -class TorrentShackCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 20 # cache update frequency - - def _cache_data(self): - - return self.provider.cache_data() - - provider = TorrentShackProvider() diff --git a/sickbeard/providers/transmithe_net.py b/sickbeard/providers/transmithe_net.py index 2ab1d6df..b7cd5c35 100644 --- a/sickbeard/providers/transmithe_net.py +++ b/sickbeard/providers/transmithe_net.py @@ -19,7 +19,8 @@ import re import traceback from . import generic -from sickbeard import helpers, logger, tvcache +from sickbeard import common, helpers, logger +from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from lib.unidecode import unidecode @@ -27,7 +28,7 @@ from lib.unidecode import unidecode class TransmithenetProvider(generic.TorrentProvider): def __init__(self): - generic.TorrentProvider.__init__(self, 'Transmithe.net') + generic.TorrentProvider.__init__(self, 'Transmithe.net', cache_update_freq=17) self.url_base = 'https://transmithe.net/' self.urls = {'config_provider_home_uri': self.url_base, @@ -39,10 +40,9 @@ class TransmithenetProvider(generic.TorrentProvider): self.url = self.urls['config_provider_home_uri'] self.user_authkey, self.user_passkey = 2 * [None] + self.chk_td = True - self.username, self.password, self.minseed, self.minleech = 4 * [None] - self.freeleech = False - self.cache = TransmithenetCache(self) + self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] def _authorised(self, **kwargs): @@ -88,11 +88,13 @@ class TransmithenetProvider(generic.TorrentProvider): try: title_parts = group_name.split('[') - maybe_res = re.findall('((?:72|108)0\w)', title_parts[1]) + maybe_res = re.findall('((?:72|108|216)0\w)', title_parts[1]) + maybe_ext = re.findall('(?i)(%s)' % '|'.join(common.mediaExtensions), title_parts[1]) detail = title_parts[1].split('/') detail[1] = detail[1].strip().lower().replace('mkv', 'x264') - title = '%s.%s' % (title_parts[0].strip(), '.'.join( - (len(maybe_res) and [maybe_res[0]] or []) + [detail[0].strip(), detail[1]])) + title = '%s.%s' % (BS4Parser(title_parts[0].strip(), 'html.parser').soup.string, '.'.join( + (maybe_res and [maybe_res[0]] or []) + + [detail[0].strip(), detail[1], maybe_ext and maybe_ext[0].lower() or 'mkv'])) except (IndexError, KeyError): title = group_name download_url = self.urls['get'] % (self.user_authkey, self.user_passkey, torrent_id) @@ -119,16 +121,4 @@ class TransmithenetProvider(generic.TorrentProvider): return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, **kwargs) -class TransmithenetCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - self.update_freq = 17 - - def _cache_data(self): - - return self.provider.cache_data() - - provider = TransmithenetProvider() diff --git a/sickbeard/providers/tvchaosuk.py b/sickbeard/providers/tvchaosuk.py index 9515f95c..49e29cbf 100644 --- a/sickbeard/providers/tvchaosuk.py +++ b/sickbeard/providers/tvchaosuk.py @@ -19,7 +19,7 @@ import re import traceback from . import generic -from sickbeard import logger, tvcache +from sickbeard import logger from sickbeard.bs4_parser import BS4Parser from sickbeard.helpers import tryInt from sickbeard.config import naming_ep_type @@ -32,9 +32,9 @@ class TVChaosUKProvider(generic.TorrentProvider): def __init__(self): generic.TorrentProvider.__init__(self, 'TVChaosUK') - self.url_base = 'https://tvchaosuk.com/' + self.url_base = 'https://www.tvchaosuk.com/' self.urls = {'config_provider_home_uri': self.url_base, - 'login': self.url_base + 'takelogin.php', + 'login_action': self.url_base + 'login.php', 'search': self.url_base + 'browse.php', 'get': self.url_base + '%s'} @@ -42,7 +42,6 @@ class TVChaosUKProvider(generic.TorrentProvider): self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None] self.search_fallback = True - self.cache = TVChaosUKCache(self) def _authorised(self, **kwargs): @@ -92,8 +91,9 @@ class TVChaosUKProvider(generic.TorrentProvider): info = tr.find('a', href=rc['info']) title = (tr.find('div', attrs={'class': 'tooltip-content'}).get_text() or info.get_text()).strip() title = re.findall('(?m)(^[^\r\n]+)', title)[0] - download_url = self.urls['get'] % str(tr.find('a', href=rc['get'])['href']).lstrip( - '/').replace(self.urls['config_provider_home_uri'], '') + download_url = str(tr.find('a', href=rc['get'])['href']) + if not download_url.startswith('http'): + download_url = self.urls['get'] % download_url.lstrip('/') except Exception: continue @@ -134,6 +134,7 @@ class TVChaosUKProvider(generic.TorrentProvider): add_pad = re.findall('((?:19|20)\d\d\-\d\d\-\d\d)([\w\W])', title) if len(add_pad) and add_pad[0][1] not in [' ', '.']: title = title.replace(''.join(add_pad[0]), '%s %s' % (add_pad[0][0], add_pad[0][1])) + title = re.sub(r'(?sim)(.*?)(?:Episode|Season).\d+.(.*)', r'\1\2', title) if title and download_url: items[mode].append((title, download_url, seeders, self._bytesizer(size))) @@ -176,14 +177,4 @@ class TVChaosUKProvider(generic.TorrentProvider): return 'tvchaosuk_tip' == key and 'has missing quality data so you must add quality Custom/Unknown to any wanted show' or '' -class TVChaosUKCache(tvcache.TVCache): - - def __init__(self, this_provider): - tvcache.TVCache.__init__(self, this_provider) - - def _cache_data(self): - - return self.provider.cache_data() - - provider = TVChaosUKProvider() diff --git a/sickbeard/providers/womble.py b/sickbeard/providers/womble.py index 9f264ad7..e0f479c6 100644 --- a/sickbeard/providers/womble.py +++ b/sickbeard/providers/womble.py @@ -17,7 +17,8 @@ # along with SickGear. If not, see <http://www.gnu.org/licenses/>. from . import generic -from sickbeard import logger, tvcache +from sickbeard import tvcache +import time class WombleProvider(generic.NZBProvider): @@ -34,46 +35,23 @@ class WombleCache(tvcache.TVCache): def __init__(self, this_provider): tvcache.TVCache.__init__(self, this_provider) - self.update_freq = 15 # cache update frequency + self.update_freq = 6 # cache update frequency - def updateCache(self): + def _cache_data(self): - # delete anything older then 7 days - self._clearCache() - - if not self.shouldUpdate(): - return - - cl = [] - data = None - for url in [self.provider.url + 'rss/?sec=tv-x264&fr=false', - self.provider.url + 'rss/?sec=tv-sd&fr=false', - self.provider.url + 'rss/?sec=tv-dvd&fr=false', - self.provider.url + 'rss/?sec=tv-hd&fr=false']: - logger.log(u'Womble\'s Index cache update URL: ' + url, logger.DEBUG) + result = [] + for section in ['sd', 'hd', 'x264', 'dvd']: + url = '%srss/?sec=tv-%s&fr=false' % (self.provider.url, section) data = self.getRSSFeed(url) + time.sleep(1.1) + cnt = len(result) + for entry in (data and data.get('entries', []) or []): + if entry.get('title') and entry.get('link', '').startswith('http'): + result.append((entry['title'], entry['link'], None, None)) - # As long as we got something from the provider we count it as an update - if not data: - return [] + self.provider.log_result(count=len(result) - cnt, url=url) - # By now we know we've got data and no auth errors, all we need to do is put it in the database - for item in data.entries: - title, url = self._title_and_url(item) - ci = self._parseItem(title, url) - if None is not ci: - cl.append(ci) - - if 0 < len(cl): - my_db = self.get_db() - my_db.mass_action(cl) - - # set last updated - if data: - self.setLastUpdate() - - def _checkAuth(self, *data): - return 'Invalid Link' != data[0] + return result provider = WombleProvider() diff --git a/sickbeard/search.py b/sickbeard/search.py index b0cfa869..22e86af6 100644 --- a/sickbeard/search.py +++ b/sickbeard/search.py @@ -179,6 +179,21 @@ def snatch_episode(result, end_status=SNATCHED): return True + +def pass_show_wordlist_checks(name, show): + re_extras = dict(re_prefix='.*', re_suffix='.*') + result = show_name_helpers.contains_any(name, show.rls_ignore_words, **re_extras) + if None is not result and result: + logger.log(u'Ignored: %s for containing ignore word' % name) + return False + + result = show_name_helpers.contains_any(name, show.rls_require_words, **re_extras) + if None is not result and not result: + logger.log(u'Ignored: %s for not containing any required word match' % name) + return False + return True + + def pick_best_result(results, show, quality_list=None): logger.log(u'Picking the best result out of %s' % [x.name for x in results], logger.DEBUG) @@ -195,15 +210,7 @@ def pick_best_result(results, show, quality_list=None): logger.log(u'%s is an unwanted quality, rejecting it' % cur_result.name, logger.DEBUG) continue - re_extras = dict(re_prefix='.*', re_suffix='.*') - result = show_name_helpers.contains_any(cur_result.name, show.rls_ignore_words, **re_extras) - if None is not result and result: - logger.log(u'Ignored: %s for containing ignore word' % cur_result.name) - continue - - result = show_name_helpers.contains_any(cur_result.name, show.rls_require_words, **re_extras) - if None is not result and not result: - logger.log(u'Ignored: %s for not containing any required word match' % cur_result.name) + if not pass_show_wordlist_checks(cur_result.name, show): continue cur_size = getattr(cur_result, 'size', None) @@ -427,8 +434,11 @@ def search_for_needed_episodes(episodes): threading.currentThread().name = orig_thread_name - if not search_done: - logger.log(u'No NZB/Torrent provider enabled to do recent searches. Please check provider options.', logger.ERROR) + if not len(providers): + logger.log('No NZB/Torrent sources enabled in Search Provider options to do recent searches', logger.WARNING) + elif not search_done: + logger.log('Failed recent search of %s enabled provider%s. More info in debug log.' % ( + len(providers), helpers.maybe_plural(len(providers))), logger.ERROR) return found_results.values() @@ -672,12 +682,39 @@ def search_providers(show, episodes, manual_search=False): continue # filter out possible bad torrents from providers - if 'torrent' == best_result.resultType and 'blackhole' != sickbeard.TORRENT_METHOD: - best_result.content = None - if not best_result.url.startswith('magnet'): - best_result.content = best_result.provider.get_url(best_result.url) - if not best_result.content: + if 'torrent' == best_result.resultType: + if best_result.url.startswith('magnet'): + if 'blackhole' != sickbeard.TORRENT_METHOD: + best_result.content = None + else: + td = best_result.provider.get_url(best_result.url) + if not td: continue + if getattr(best_result.provider, 'chk_td', None): + name = None + try: + hdr = re.findall('(\w+(\d+):)', td[0:6])[0] + x, v = len(hdr[0]), int(hdr[1]) + for item in range(0, 12): + y = x + v + name = 'name' == td[x: y] + w = re.findall('((?:i\d+e|d|l)?(\d+):)', td[y: y + 32])[0] + x, v = y + len(w[0]), int(w[1]) + if name: + name = td[x: x + v] + break + except: + continue + if name: + if not pass_show_wordlist_checks(name, show): + continue + if not show_name_helpers.pass_wordlist_checks(name): + logger.log(u'Ignored: %s (debug log has detail)' % name) + continue + best_result.name = name + + if 'blackhole' != sickbeard.TORRENT_METHOD: + best_result.content = td # add result if its not a duplicate and found = False @@ -702,8 +739,10 @@ def search_providers(show, episodes, manual_search=False): if len(episodes) == wanted_ep_count: break - if not search_done: - logger.log(u'No NZB/Torrent providers found or enabled in the SickGear config for backlog searches. Please check your settings.', - logger.ERROR) + if not len(provider_list): + logger.log('No NZB/Torrent sources enabled in Search Provider options to do backlog searches', logger.WARNING) + elif not search_done: + logger.log('Failed backlog search of %s enabled provider%s. More info in debug log.' % ( + len(provider_list), helpers.maybe_plural(len(provider_list))), logger.ERROR) return final_results diff --git a/sickbeard/search_queue.py b/sickbeard/search_queue.py index 5f53f37d..58dbbdf3 100644 --- a/sickbeard/search_queue.py +++ b/sickbeard/search_queue.py @@ -18,7 +18,6 @@ from __future__ import with_statement -import time import traceback import threading import datetime @@ -288,21 +287,29 @@ class RecentSearchQueueItem(generic_queue.QueueItem): orig_thread_name = threading.currentThread().name threads = [] - logger.log('Updating provider caches with recent upload data') - providers = [x for x in sickbeard.providers.sortedProviderList() if x.is_active() and x.enable_recentsearch] for cur_provider in providers: - # spawn separate threads for each provider so we don't need to wait for providers with slow network operation + if not cur_provider.cache.should_update(): + continue + + if not threads: + logger.log('Updating provider caches with recent upload data') + + # spawn a thread for each provider to save time waiting for slow response providers threads.append(threading.Thread(target=cur_provider.cache.updateCache, name='%s :: [%s]' % (orig_thread_name, cur_provider.name))) # start the thread we just created threads[-1].start() - # wait for all threads to finish - for t in threads: - t.join() + if not len(providers): + logger.log('No NZB/Torrent sources enabled in Search Provider options for cache update', logger.WARNING) - logger.log('Finished updating provider caches') + if threads: + # wait for all threads to finish + for t in threads: + t.join() + + logger.log('Finished updating provider caches') class ProperSearchQueueItem(generic_queue.QueueItem): @@ -427,7 +434,7 @@ class FailedQueueItem(generic_queue.QueueItem): history.logFailed(epObj, release, provider) failed_history.revertEpisode(epObj) - logger.log(u'Beginning failed download search for: []' % epObj.prettyName()) + logger.log(u'Beginning failed download search for: [%s]' % epObj.prettyName()) search_result = search.search_providers(self.show, self.segment, True) diff --git a/sickbeard/tvcache.py b/sickbeard/tvcache.py index 39d0e3e1..195b6453 100644 --- a/sickbeard/tvcache.py +++ b/sickbeard/tvcache.py @@ -32,6 +32,7 @@ from name_parser.parser import NameParser, InvalidNameException, InvalidShowExce from sickbeard.rssfeeds import RSSFeeds import itertools + class CacheDBConnection(db.DBConnection): def __init__(self, providerName): db.DBConnection.__init__(self, 'cache.db') @@ -44,6 +45,7 @@ class CacheDBConnection(db.DBConnection): if str(e) != 'table lastUpdate already exists': raise + class TVCache: def __init__(self, provider): @@ -56,7 +58,7 @@ class TVCache: return CacheDBConnection(self.providerID) def _clearCache(self): - if self.shouldClearCache(): + if self.should_clear_cache(): myDB = self.get_db() myDB.action('DELETE FROM provider_cache WHERE provider = ?', [self.providerID]) @@ -81,21 +83,16 @@ class TVCache: logger.log(u'Authentication error: ' + ex(e), logger.ERROR) return [] - if self.shouldUpdate(): - # as long as the http request worked we count this as an update + if self.should_update(): data = self._cache_data() - if not data: - return [] # clear cache - self._clearCache() - - # set updated - self.setLastUpdate() + if data: + self._clearCache() # parse data cl = [] - for item in data: + for item in data or []: title, url = self._title_and_url(item) ci = self._parseItem(title, url) if ci is not None: @@ -105,6 +102,9 @@ class TVCache: myDB = self.get_db() myDB.mass_action(cl) + # set updated as time the attempt to fetch data is + self.setLastUpdate() + return [] def getRSSFeed(self, url, **kwargs): @@ -180,21 +180,13 @@ class TVCache: lastUpdate = property(_getLastUpdate) lastSearch = property(_getLastSearch) - def shouldUpdate(self): + def should_update(self): # if we've updated recently then skip the update - if datetime.datetime.today() - self.lastUpdate < datetime.timedelta(minutes=self.update_freq): - logger.log(u'Last update was too soon, using old cache: today()-' + str(self.lastUpdate) + '<' + str( - datetime.timedelta(minutes=self.update_freq)), logger.DEBUG) - return False + return datetime.datetime.today() - self.lastUpdate >= datetime.timedelta(minutes=self.update_freq) - return True - - def shouldClearCache(self): + def should_clear_cache(self): # if recent search hasn't used our previous results yet then don't clear the cache - if self.lastUpdate > self.lastSearch: - return False - - return True + return self.lastSearch >= self.lastUpdate def add_cache_entry(self, name, url, parse_result=None, indexer_id=0): diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index e1774d59..744d1600 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -4662,10 +4662,7 @@ class ConfigProviders(Config): providerDict[name].key = key # a 0 in the key spot indicates that no key is needed - if key == '0': - providerDict[name].needs_auth = False - else: - providerDict[name].needs_auth = True + providerDict[name].needs_auth = '0' != key return providerDict[name].get_id() + '|' + providerDict[name].config_str() @@ -4767,16 +4764,11 @@ class ConfigProviders(Config): def saveProviders(self, newznab_string='', torrentrss_string='', provider_order=None, **kwargs): results = [] - - provider_str_list = provider_order.split() provider_list = [] - newznabProviderDict = dict( - zip([x.get_id() for x in sickbeard.newznabProviderList], sickbeard.newznabProviderList)) - - finishedNames = [] - - # add all the newznab info we got into our list + # add all the newznab info we have into our list + newznab_sources = dict(zip([x.get_id() for x in sickbeard.newznabProviderList], sickbeard.newznabProviderList)) + active_ids = [] if newznab_string: for curNewznabProviderStr in newznab_string.split('!!!'): @@ -4789,282 +4781,157 @@ class ConfigProviders(Config): if starify(cur_key, True): cur_key = '' - newProvider = newznab.NewznabProvider(cur_name, cur_url, key=cur_key) + new_provider = newznab.NewznabProvider(cur_name, cur_url, key=cur_key) - cur_id = newProvider.get_id() + cur_id = new_provider.get_id() # if it already exists then update it - if cur_id in newznabProviderDict: - newznabProviderDict[cur_id].name = cur_name - newznabProviderDict[cur_id].url = cur_url + if cur_id in newznab_sources: + nzb_src = newznab_sources[cur_id] + + nzb_src.name, nzb_src.url, nzb_src.cat_ids = cur_name, cur_url, cur_cat + if cur_key: - newznabProviderDict[cur_id].key = cur_key - newznabProviderDict[cur_id].cat_ids = cur_cat + nzb_src.key = cur_key + # a 0 in the key spot indicates that no key is needed - if cur_key == '0': - newznabProviderDict[cur_id].needs_auth = False - else: - newznabProviderDict[cur_id].needs_auth = True + nzb_src.needs_auth = '0' != cur_key - try: - newznabProviderDict[cur_id].search_mode = str(kwargs[cur_id + '_search_mode']).strip() - except: - pass + attr = 'search_mode' + if cur_id + '_' + attr in kwargs: + setattr(nzb_src, attr, str(kwargs.get(cur_id + '_' + attr)).strip()) - try: - newznabProviderDict[cur_id].search_fallback = config.checkbox_to_value( - kwargs[cur_id + '_search_fallback']) - except: - newznabProviderDict[cur_id].search_fallback = 0 + for attr in ['search_fallback', 'enable_recentsearch', 'enable_backlog']: + setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(cur_id + '_' + attr))) - try: - newznabProviderDict[cur_id].enable_recentsearch = config.checkbox_to_value( - kwargs[cur_id + '_enable_recentsearch']) - except: - newznabProviderDict[cur_id].enable_recentsearch = 0 - - try: - newznabProviderDict[cur_id].enable_backlog = config.checkbox_to_value( - kwargs[cur_id + '_enable_backlog']) - except: - newznabProviderDict[cur_id].enable_backlog = 0 else: - sickbeard.newznabProviderList.append(newProvider) + sickbeard.newznabProviderList.append(new_provider) - finishedNames.append(cur_id) + active_ids.append(cur_id) # delete anything that is missing - for curProvider in sickbeard.newznabProviderList: - if curProvider.get_id() not in finishedNames: - sickbeard.newznabProviderList.remove(curProvider) - - torrentRssProviderDict = dict( - zip([x.get_id() for x in sickbeard.torrentRssProviderList], sickbeard.torrentRssProviderList)) - finishedNames = [] + for source in [x for x in sickbeard.newznabProviderList if x.get_id() not in active_ids]: + sickbeard.newznabProviderList.remove(source) + # add all the torrent RSS info we have into our list + torrent_rss_sources = dict(zip([x.get_id() for x in sickbeard.torrentRssProviderList], + sickbeard.torrentRssProviderList)) + active_ids = [] if torrentrss_string: for curTorrentRssProviderStr in torrentrss_string.split('!!!'): if not curTorrentRssProviderStr: continue - curName, curURL, curCookies = curTorrentRssProviderStr.split('|') - curURL = config.clean_url(curURL, False) + cur_name, cur_url, cur_cookies = curTorrentRssProviderStr.split('|') + cur_url = config.clean_url(cur_url, False) - if starify(curCookies, True): - curCookies = '' + if starify(cur_cookies, True): + cur_cookies = '' - newProvider = rsstorrent.TorrentRssProvider(curName, curURL, curCookies) + new_provider = rsstorrent.TorrentRssProvider(cur_name, cur_url, cur_cookies) - curID = newProvider.get_id() + cur_id = new_provider.get_id() # if it already exists then update it - if curID in torrentRssProviderDict: - torrentRssProviderDict[curID].name = curName - torrentRssProviderDict[curID].url = curURL - if curCookies: - torrentRssProviderDict[curID].cookies = curCookies + if cur_id in torrent_rss_sources: + torrent_rss_sources[cur_id].name = cur_name + torrent_rss_sources[cur_id].url = cur_url + if cur_cookies: + torrent_rss_sources[cur_id].cookies = cur_cookies else: - sickbeard.torrentRssProviderList.append(newProvider) + sickbeard.torrentRssProviderList.append(new_provider) - finishedNames.append(curID) + active_ids.append(cur_id) # delete anything that is missing - for curProvider in sickbeard.torrentRssProviderList: - if curProvider.get_id() not in finishedNames: - sickbeard.torrentRssProviderList.remove(curProvider) + for source in [x for x in sickbeard.torrentRssProviderList if x.get_id() not in active_ids]: + sickbeard.torrentRssProviderList.remove(source) - # do the enable/disable - for curProviderStr in provider_str_list: - curProvider, curEnabled = curProviderStr.split(':') - curEnabled = config.to_int(curEnabled) + # enable/disable states of source providers + provider_str_list = provider_order.split() + sources = dict(zip([x.get_id() for x in sickbeard.providers.sortedProviderList()], + sickbeard.providers.sortedProviderList())) + for cur_src_str in provider_str_list: + src_name, src_enabled = cur_src_str.split(':') - curProvObj = [x for x in sickbeard.providers.sortedProviderList() if - x.get_id() == curProvider and hasattr(x, 'enabled')] - if curProvObj: - curProvObj[0].enabled = bool(curEnabled) + provider_list.append(src_name) + src_enabled = bool(config.to_int(src_enabled)) - provider_list.append(curProvider) - if curProvider in newznabProviderDict: - newznabProviderDict[curProvider].enabled = bool(curEnabled) - elif curProvider in torrentRssProviderDict: - torrentRssProviderDict[curProvider].enabled = bool(curEnabled) + if src_name in sources and hasattr(sources[src_name], 'enabled'): + sources[src_name].enabled = src_enabled - # dynamically load provider settings - for curTorrentProvider in [curProvider for curProvider in sickbeard.providers.sortedProviderList() if - curProvider.providerType == sickbeard.GenericProvider.TORRENT]: + if src_name in newznab_sources: + newznab_sources[src_name].enabled = src_enabled + elif src_name in torrent_rss_sources: + torrent_rss_sources[src_name].enabled = src_enabled - if hasattr(curTorrentProvider, '_seed_ratio'): - try: - curTorrentProvider._seed_ratio = str(kwargs[curTorrentProvider.get_id() + '_ratio']).strip() - except: - curTorrentProvider._seed_ratio = None + # update torrent source settings + for torrent_src in [src for src in sickbeard.providers.sortedProviderList() + if sickbeard.GenericProvider.TORRENT == src.providerType]: + src_id_prefix = torrent_src.get_id() + '_' - if hasattr(curTorrentProvider, 'seed_time') and curTorrentProvider.get_id() + '_seed_time' in kwargs: - curTorrentProvider.seed_time = config.to_int(str(kwargs[curTorrentProvider.get_id() + '_seed_time']).strip(), 0) + attr = 'url_edit' + if getattr(torrent_src, attr, None): + url_edit = ','.join(set(['%s' % url.strip() for url in kwargs.get( + src_id_prefix + attr, '').split(',')])) + torrent_src.url_home = ([url_edit], [])[not url_edit] - if hasattr(curTorrentProvider, 'minseed'): - try: - curTorrentProvider.minseed = int(str(kwargs[curTorrentProvider.get_id() + '_minseed']).strip()) - except: - curTorrentProvider.minseed = 0 + for attr in [x for x in ['username', 'uid'] if hasattr(torrent_src, x)]: + setattr(torrent_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip()) - if hasattr(curTorrentProvider, 'minleech'): - try: - curTorrentProvider.minleech = int(str(kwargs[curTorrentProvider.get_id() + '_minleech']).strip()) - except: - curTorrentProvider.minleech = 0 + for attr in [x for x in ['password', 'api_key', 'passkey', 'digest', 'hash'] if hasattr(torrent_src, x)]: + key = str(kwargs.get(src_id_prefix + attr, '')).strip() + if 'password' == attr: + set('*') != set(key) and setattr(torrent_src, attr, key) + elif not starify(key, True): + setattr(torrent_src, attr, key) - if hasattr(curTorrentProvider, 'digest'): - try: - key = str(kwargs[curTorrentProvider.get_id() + '_digest']).strip() - if not starify(key, True): - curTorrentProvider.digest = key - except: - curTorrentProvider.digest = None + attr = 'ratio' + if hasattr(torrent_src, '_seed_' + attr): + setattr(torrent_src, '_seed_' + attr, kwargs.get(src_id_prefix + attr, '').strip() or None) - if hasattr(curTorrentProvider, 'hash'): - try: - key = str(kwargs[curTorrentProvider.get_id() + '_hash']).strip() - if not starify(key, True): - curTorrentProvider.hash = key - except: - curTorrentProvider.hash = None + for attr in [x for x in ['minseed', 'minleech'] if hasattr(torrent_src, x)]: + setattr(torrent_src, attr, config.to_int(str(kwargs.get(src_id_prefix + attr)).strip())) - if hasattr(curTorrentProvider, 'api_key'): - try: - key = str(kwargs[curTorrentProvider.get_id() + '_api_key']).strip() - if not starify(key, True): - curTorrentProvider.api_key = key - except: - curTorrentProvider.api_key = None + for attr in [x for x in ['confirmed', 'freeleech', 'reject_m2ts', 'enable_recentsearch', + 'enable_backlog', 'search_fallback'] if hasattr(torrent_src, x)]: + setattr(torrent_src, attr, config.checkbox_to_value(kwargs.get(src_id_prefix + attr))) - if hasattr(curTorrentProvider, 'username'): - try: - curTorrentProvider.username = str(kwargs[curTorrentProvider.get_id() + '_username']).strip() - except: - curTorrentProvider.username = None + attr = 'seed_time' + if hasattr(torrent_src, attr) and src_id_prefix + attr in kwargs: + setattr(torrent_src, attr, config.to_int(str(kwargs.get(src_id_prefix + attr)).strip())) - if hasattr(curTorrentProvider, 'password'): - try: - key = str(kwargs[curTorrentProvider.get_id() + '_password']).strip() - if set('*') != set(key): - curTorrentProvider.password = key - except: - curTorrentProvider.password = None + attr = 'search_mode' + if hasattr(torrent_src, attr): + setattr(torrent_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip() or 'eponly') - if hasattr(curTorrentProvider, 'passkey'): - try: - key = str(kwargs[curTorrentProvider.get_id() + '_passkey']).strip() - if not starify(key, True): - curTorrentProvider.passkey = key - except: - curTorrentProvider.passkey = None + # update nzb source settings + for nzb_src in [src for src in sickbeard.providers.sortedProviderList() if + sickbeard.GenericProvider.NZB == src.providerType]: + src_id_prefix = nzb_src.get_id() + '_' - if hasattr(curTorrentProvider, 'confirmed'): - try: - curTorrentProvider.confirmed = config.checkbox_to_value( - kwargs[curTorrentProvider.get_id() + '_confirmed']) - except: - curTorrentProvider.confirmed = 0 + attr = 'api_key' + if hasattr(nzb_src, attr): + key = str(kwargs.get(src_id_prefix + attr, '')).strip() + if not starify(key, True): + setattr(nzb_src, attr, key) - if hasattr(curTorrentProvider, 'proxy'): - try: - curTorrentProvider.proxy.enabled = config.checkbox_to_value( - kwargs[curTorrentProvider.get_id() + '_proxy']) - except: - curTorrentProvider.proxy.enabled = 0 + attr = 'username' + if hasattr(nzb_src, attr): + setattr(nzb_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip() or None) - if hasattr(curTorrentProvider.proxy, 'url'): - try: - curTorrentProvider.proxy.url = str(kwargs[curTorrentProvider.get_id() + '_proxy_url']).strip() - except: - curTorrentProvider.proxy.url = None + attr = 'search_mode' + if hasattr(nzb_src, attr): + setattr(nzb_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip() or 'eponly') - if hasattr(curTorrentProvider, 'freeleech'): - try: - curTorrentProvider.freeleech = config.checkbox_to_value( - kwargs[curTorrentProvider.get_id() + '_freeleech']) - except: - curTorrentProvider.freeleech = 0 + attr = 'enable_recentsearch' + if hasattr(nzb_src, attr): + setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(src_id_prefix + attr)) or + not getattr(nzb_src, 'supports_backlog', True)) - if hasattr(curTorrentProvider, 'reject_m2ts'): - try: - curTorrentProvider.reject_m2ts = config.checkbox_to_value( - kwargs[curTorrentProvider.get_id() + '_reject_m2ts']) - except: - curTorrentProvider.reject_m2ts = 0 - - if hasattr(curTorrentProvider, 'search_mode'): - try: - curTorrentProvider.search_mode = str(kwargs[curTorrentProvider.get_id() + '_search_mode']).strip() - except: - curTorrentProvider.search_mode = 'eponly' - - if hasattr(curTorrentProvider, 'search_fallback'): - try: - curTorrentProvider.search_fallback = config.checkbox_to_value( - kwargs[curTorrentProvider.get_id() + '_search_fallback']) - except: - curTorrentProvider.search_fallback = 0 # these exceptions are catching unselected checkboxes - - if hasattr(curTorrentProvider, 'enable_recentsearch'): - try: - curTorrentProvider.enable_recentsearch = config.checkbox_to_value( - kwargs[curTorrentProvider.get_id() + '_enable_recentsearch']) - except: - curTorrentProvider.enable_recentsearch = 0 # these exceptions are actually catching unselected checkboxes - - if hasattr(curTorrentProvider, 'enable_backlog'): - try: - curTorrentProvider.enable_backlog = config.checkbox_to_value( - kwargs[curTorrentProvider.get_id() + '_enable_backlog']) - except: - curTorrentProvider.enable_backlog = 0 # these exceptions are actually catching unselected checkboxes - - for curNzbProvider in [curProvider for curProvider in sickbeard.providers.sortedProviderList() if - curProvider.providerType == sickbeard.GenericProvider.NZB]: - - if hasattr(curNzbProvider, 'api_key'): - try: - key = str(kwargs[curNzbProvider.get_id() + '_api_key']).strip() - if not starify(key, True): - curNzbProvider.api_key = key - except: - curNzbProvider.api_key = None - - if hasattr(curNzbProvider, 'username'): - try: - curNzbProvider.username = str(kwargs[curNzbProvider.get_id() + '_username']).strip() - except: - curNzbProvider.username = None - - if hasattr(curNzbProvider, 'search_mode'): - try: - curNzbProvider.search_mode = str(kwargs[curNzbProvider.get_id() + '_search_mode']).strip() - except: - curNzbProvider.search_mode = 'eponly' - - if hasattr(curNzbProvider, 'search_fallback'): - try: - curNzbProvider.search_fallback = config.checkbox_to_value( - kwargs[curNzbProvider.get_id() + '_search_fallback']) - except: - curNzbProvider.search_fallback = 0 # these exceptions are actually catching unselected checkboxes - - if hasattr(curNzbProvider, 'enable_recentsearch'): - try: - curNzbProvider.enable_recentsearch = config.checkbox_to_value( - kwargs[curNzbProvider.get_id() + '_enable_recentsearch']) - except: - curNzbProvider.enable_recentsearch = 0 # these exceptions are actually catching unselected checkboxes - - if hasattr(curNzbProvider, 'enable_backlog'): - try: - curNzbProvider.enable_backlog = config.checkbox_to_value( - kwargs[curNzbProvider.get_id() + '_enable_backlog']) - except: - curNzbProvider.enable_backlog = 0 # these exceptions are actually catching unselected checkboxes + for attr in [x for x in ['search_fallback', 'enable_backlog'] if hasattr(nzb_src, x)]: + setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(src_id_prefix + attr))) sickbeard.NEWZNAB_DATA = '!!!'.join([x.config_str() for x in sickbeard.newznabProviderList]) sickbeard.PROVIDER_ORDER = provider_list @@ -5073,11 +4940,10 @@ class ConfigProviders(Config): sickbeard.save_config() - if len(results) > 0: + if 0 < len(results): for x in results: logger.log(x, logger.ERROR) - ui.notifications.error('Error(s) Saving Configuration', - '<br />\n'.join(results)) + ui.notifications.error('Error(s) Saving Configuration', '<br />\n'.join(results)) else: ui.notifications.message('Configuration Saved', ek.ek(os.path.join, sickbeard.CONFIG_FILE))