mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-01 00:43:37 +00:00
Merge pull request #785 from JackDandy/feature/AddProvHDT
Add HD-Torrents provider.
This commit is contained in:
commit
17bf73e5ae
24 changed files with 393 additions and 187 deletions
|
@ -87,14 +87,16 @@
|
|||
* Add DigitalHive torrent provider
|
||||
* Add RevTT torrent provider
|
||||
* Add PTF torrent provider
|
||||
* Add ILT torrent provider
|
||||
* Add Fano torrent provider
|
||||
* Add BTScene torrent provider
|
||||
* Add Extratorrent provider
|
||||
* Add Limetorrents provider
|
||||
* Add HD-Torrents provider
|
||||
* Add nCore torrent provider
|
||||
* Add TorLock provider
|
||||
* Add Torrentz2 provider
|
||||
* Add freeleech options to fano, freshon, hdspace, phd, ptf providers
|
||||
* Change SceneTime to cookie auth
|
||||
* Remove Usenet-Crawler provider
|
||||
* Change CPU throttling on General Config/Advanced to "Disabled" by default for new installs
|
||||
* Change provider OMGWTFNZBS api url and auto reject nuked releases
|
||||
|
@ -180,6 +182,7 @@
|
|||
* Add handler for when rar files can not be opened during post processing
|
||||
* Fix join clean up
|
||||
* Fix add custom torrent RSS
|
||||
* Remove ILT torrent provider
|
||||
|
||||
|
||||
### 0.11.15 (2016-09-13 19:50:00 UTC)
|
||||
|
|
|
@ -2290,7 +2290,7 @@ config*.tmpl
|
|||
}
|
||||
|
||||
#config label.space-right{
|
||||
margin-right:20px
|
||||
margin-right:16px
|
||||
}
|
||||
|
||||
#config .metadataDiv{
|
||||
|
|
BIN
gui/slick/images/providers/hdtorrents.png
Normal file
BIN
gui/slick/images/providers/hdtorrents.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB |
|
@ -520,6 +520,23 @@ name = '' if not client else get_client_instance(sickbeard.TORRENT_METHOD)().nam
|
|||
</label>
|
||||
</div>
|
||||
#end if
|
||||
#if $hasattr($cur_torrent_provider, 'may_filter'):
|
||||
<div class="field-pair">
|
||||
<span class="component-title">Allow releases that are</span>
|
||||
<span class="component-desc">
|
||||
#for $cur_fval, $filter in $cur_torrent_provider.may_filter.iteritems()
|
||||
#set $cur_fname, $cur_is_default = $filter[0], $filter[1]
|
||||
#set $filter_id = '%s_filter_%s' % ($cur_torrent_provider.get_id(), $cur_fval)
|
||||
<label class="space-right">
|
||||
<input type="checkbox" name="$filter_id" id="$filter_id" #echo ('', $html_checked)[$cur_fval in $cur_torrent_provider.filter]#/>
|
||||
<span>$cur_fname</span>
|
||||
</label>
|
||||
#end for
|
||||
<span>(see site for meaning)</span>
|
||||
<p>nothing selected allows everything (no filter, default)</p>
|
||||
</span>
|
||||
</div>
|
||||
#end if
|
||||
#if $hasattr($cur_torrent_provider, 'reject_m2ts'):
|
||||
<div class="field-pair">
|
||||
<label for="${cur_torrent_provider.get_id()}_reject_m2ts">
|
||||
|
|
|
@ -1080,6 +1080,8 @@ def initialize(consoleLogging=True):
|
|||
torrent_prov.search_mode = check_setting_str(CFG, prov_id_uc, prov_id + '_search_mode', 'eponly')
|
||||
if hasattr(torrent_prov, 'search_fallback'):
|
||||
torrent_prov.search_fallback = bool(check_setting_int(CFG, prov_id_uc, prov_id + '_search_fallback', 0))
|
||||
if hasattr(torrent_prov, 'filter'):
|
||||
torrent_prov.filter = check_setting_str(CFG, prov_id_uc, prov_id + '_filter', [])
|
||||
|
||||
for nzb_prov in [curProvider for curProvider in providers.sortedProviderList()
|
||||
if GenericProvider.NZB == curProvider.providerType]:
|
||||
|
@ -1594,6 +1596,8 @@ def save_config():
|
|||
|
||||
if hasattr(src, '_seed_ratio'):
|
||||
new_config[src_id_uc][src_id + '_seed_ratio'] = src.seed_ratio()
|
||||
if hasattr(src, 'filter'):
|
||||
new_config[src_id_uc][src_id + '_filter'] = src.filter
|
||||
|
||||
for src in [x for x in providers.sortedProviderList() if GenericProvider.NZB == x.providerType]:
|
||||
src_id = src.get_id()
|
||||
|
|
|
@ -27,8 +27,8 @@ from sickbeard import logger, encodingKludge as ek
|
|||
from . import newznab, omgwtfnzbs, womble
|
||||
# torrent
|
||||
from . import alpharatio, beyondhd, bithdtv, bitmetv, btn, btscene, dh, extratorrent, \
|
||||
fano, filelist, freshontv, funfile, gftracker, grabtheinfo, hd4free, hdbits, hdspace, \
|
||||
ilt, iptorrents, limetorrents, morethan, ncore, pisexy, pretome, privatehd, ptf, \
|
||||
fano, filelist, freshontv, funfile, gftracker, grabtheinfo, hd4free, hdbits, hdspace, hdtorrents, \
|
||||
iptorrents, limetorrents, morethan, ncore, pisexy, pretome, privatehd, ptf, \
|
||||
rarbg, revtt, scc, scenetime, shazbat, speedcd, \
|
||||
thepiratebay, torlock, torrentbytes, torrentday, torrenting, torrentleech, \
|
||||
torrentshack, torrentz2, transmithe_net, tvchaosuk, zooqle
|
||||
|
@ -61,7 +61,7 @@ __all__ = ['omgwtfnzbs',
|
|||
'hd4free',
|
||||
'hdbits',
|
||||
'hdspace',
|
||||
'ilt',
|
||||
'hdtorrents',
|
||||
'iptorrents',
|
||||
'limetorrents',
|
||||
'morethan',
|
||||
|
|
|
@ -34,9 +34,8 @@ class BeyondHDProvider(generic.TorrentProvider):
|
|||
'browse': self.url_base + 'api_tv.php?passkey=%s&cats=%s',
|
||||
'search': '&search=%s'}
|
||||
|
||||
self.categories = {'Season': '89',
|
||||
'Episode': '40,44,48,43,45',
|
||||
'Cache': '40,44,48,89,43,45'}
|
||||
self.categories = {'Season': '89', 'Episode': '40,44,48,46,45'}
|
||||
self.categories['Cache'] = '%s,%s' % (self.categories['Episode'], self.categories['Season'])
|
||||
|
||||
self.url = self.urls['config_provider_home_uri']
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class BitHDTVProvider(generic.TorrentProvider):
|
|||
self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login_action': '%(home)s%(vars)s',
|
||||
'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'}
|
||||
|
||||
self.categories = {'Season': [12], 'Episode': [4, 5, 10], 'Anime': [1]}
|
||||
self.categories = {'Season': [12], 'Episode': [4, 5, 10], 'anime': [1]}
|
||||
self.categories['Cache'] = self.categories['Season'] + self.categories['Episode']
|
||||
|
||||
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from requests.compat import OrderedDict
|
||||
import re
|
||||
import traceback
|
||||
|
||||
|
@ -24,6 +28,8 @@ from sickbeard.bs4_parser import BS4Parser
|
|||
from sickbeard.helpers import tryInt
|
||||
from lib.unidecode import unidecode
|
||||
|
||||
FLTAG = '</a>\s+<img[^>]+%s[^<]+<br'
|
||||
|
||||
|
||||
class FanoProvider(generic.TorrentProvider):
|
||||
|
||||
|
@ -32,16 +38,19 @@ class FanoProvider(generic.TorrentProvider):
|
|||
|
||||
self.url_base = 'https://www.fano.in/'
|
||||
self.urls = {'config_provider_home_uri': self.url_base,
|
||||
'login_action': self.url_base + 'login.php',
|
||||
'search': self.url_base + 'browse_old.php?search=%s&%s&incldead=0%s',
|
||||
'get': self.url_base + '%s'}
|
||||
'login_action': self.url_base + 'login.php', 'get': self.url_base + '%s',
|
||||
'search': self.url_base + 'browse_old.php?search=%s&%s&incldead=0'}
|
||||
|
||||
self.categories = {'Season': [49], 'Episode': [6, 23, 32, 35], 'anime': [27]}
|
||||
self.categories['Cache'] = self.categories['Season'] + self.categories['Episode']
|
||||
|
||||
self.url = self.urls['config_provider_home_uri']
|
||||
|
||||
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
|
||||
self.filter = []
|
||||
self.may_filter = OrderedDict([
|
||||
('f0', ('not marked', False, '')), ('fx2', ('x2', True, FLTAG % 'x2_up')),
|
||||
('fgx2', ('gold/x2', True, FLTAG % 'free[^<]+<img[^>]+x2_up')), ('fg', ('gold', True, FLTAG % 'free'))])
|
||||
self.username, self.password, self.minseed, self.minleech = 4 * [None]
|
||||
|
||||
def _authorised(self, **kwargs):
|
||||
|
||||
|
@ -57,13 +66,21 @@ class FanoProvider(generic.TorrentProvider):
|
|||
|
||||
rc = dict((k, re.compile('(?i)' + v))
|
||||
for (k, v) in {'abd': '(\d{4}(?:[.]\d{2}){2})', 'info': 'details', 'get': 'download'}.items())
|
||||
log = ''
|
||||
if self.filter:
|
||||
non_marked = 'f0' in self.filter
|
||||
# if search_any, use unselected to exclude, else use selected to keep
|
||||
filters = ([f for f in self.may_filter if f in self.filter],
|
||||
[f for f in self.may_filter if f not in self.filter])[non_marked]
|
||||
rc['filter'] = re.compile('(?i)(%s)' % '|'.join(
|
||||
[self.may_filter[f][2] for f in filters if self.may_filter[f][1]]))
|
||||
log = '%sing (%s) ' % (('keep', 'skipp')[non_marked], ', '.join([self.may_filter[f][0] for f in filters]))
|
||||
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_string = '+'.join(rc['abd'].sub(r'%22\1%22', search_string).split())
|
||||
search_url = self.urls['search'] % (search_string, self._categories_string(mode),
|
||||
('&sgold=on', '')[not self.freeleech])
|
||||
search_url = self.urls['search'] % (search_string, self._categories_string(mode))
|
||||
|
||||
html = self.get_url(search_url)
|
||||
|
||||
|
@ -80,6 +97,10 @@ class FanoProvider(generic.TorrentProvider):
|
|||
raise generic.HaltParseException
|
||||
|
||||
for tr in torrent_rows[1:]:
|
||||
if (any(self.filter)
|
||||
and ((non_marked and rc['filter'].search(str(tr)))
|
||||
or (not non_marked and not rc['filter'].search(str(tr))))):
|
||||
continue
|
||||
try:
|
||||
seeders, leechers, size = [tryInt(n, n) for n in [
|
||||
tr.find_all('td')[x].get_text().strip() for x in -2, -1, -4]]
|
||||
|
@ -99,7 +120,7 @@ class FanoProvider(generic.TorrentProvider):
|
|||
except (StandardError, 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._log_search(mode, len(items[mode]) - cnt, log + search_url)
|
||||
|
||||
results = self._sort_seeding(mode, results + items[mode])
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from requests.compat import OrderedDict
|
||||
import re
|
||||
import traceback
|
||||
|
||||
|
@ -33,14 +37,17 @@ class FreshOnTVProvider(generic.TorrentProvider):
|
|||
self.url_base = 'https://freshon.tv/'
|
||||
self.urls = {'config_provider_home_uri': self.url_base,
|
||||
'login_action': self.url_base + 'login.php',
|
||||
'search': self.url_base + 'browse.php?incldead=%s&words=0&%s&search=%s',
|
||||
'search': self.url_base + 'browse.php?incldead=0&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.freeleech, self.minseed, self.minleech = 5 * [None]
|
||||
self.filter = []
|
||||
self.may_filter = OrderedDict([
|
||||
('f0', ('not marked', False, '')), ('f50', ('50%', True)), ('f100', ('100%', True))])
|
||||
self.username, self.password, self.minseed, self.minleech = 4 * [None]
|
||||
|
||||
def _authorised(self, **kwargs):
|
||||
|
||||
|
@ -59,17 +66,25 @@ class FreshOnTVProvider(generic.TorrentProvider):
|
|||
return results
|
||||
|
||||
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
|
||||
freeleech = (3, 0)[not self.freeleech]
|
||||
|
||||
rc = dict((k, re.compile('(?i)' + v))
|
||||
for (k, v) in {'info': 'detail', 'get': 'download', 'name': '_name'}.items())
|
||||
log = ''
|
||||
if self.filter:
|
||||
non_marked = 'f0' in self.filter
|
||||
# if search_any, use unselected to exclude, else use selected to keep
|
||||
filters = ([f for f in self.may_filter if f in self.filter],
|
||||
[f for f in self.may_filter if f not in self.filter])[non_marked]
|
||||
rc['filter'] = re.compile('(?i)(%s).png' % '|'.join(
|
||||
[f.replace('f', '') for f in filters if self.may_filter[f][1]]))
|
||||
log = '%sing (%s) ' % (('keep', 'skipp')[non_marked], ', '.join([self.may_filter[f][0] for f in filters]))
|
||||
for mode in search_params.keys():
|
||||
for search_string in search_params[mode]:
|
||||
|
||||
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)))
|
||||
'', self.urls['search'] % (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)
|
||||
|
@ -87,10 +102,12 @@ class FreshOnTVProvider(generic.TorrentProvider):
|
|||
raise generic.HaltParseException
|
||||
|
||||
for tr in torrent_rows[1:]:
|
||||
if (tr.find('img', alt='Nuked')
|
||||
or (any(self.filter)
|
||||
and ((non_marked and tr.find('img', src=rc['filter']))
|
||||
or (not non_marked and not tr.find('img', src=rc['filter']))))):
|
||||
continue
|
||||
try:
|
||||
if tr.find('img', alt='Nuked'):
|
||||
continue
|
||||
|
||||
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._peers_fail(mode, seeders, leechers):
|
||||
|
@ -109,7 +126,7 @@ class FreshOnTVProvider(generic.TorrentProvider):
|
|||
pass
|
||||
except (StandardError, 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._log_search(mode, len(items[mode]) - cnt, log + search_url)
|
||||
|
||||
results = self._sort_seeding(mode, results + items[mode])
|
||||
|
||||
|
|
|
@ -961,6 +961,7 @@ class TorrentProvider(object, GenericProvider):
|
|||
for i in range(0, len(url)):
|
||||
helpers.getURL(url.pop(), session=self.session)
|
||||
|
||||
passfield, userfield = None, None
|
||||
if not url:
|
||||
if hasattr(self, 'urls'):
|
||||
url = self.urls.get('login_action')
|
||||
|
@ -980,12 +981,13 @@ class TorrentProvider(object, GenericProvider):
|
|||
(url + action) if action.startswith('?') else \
|
||||
(self.urls.get('login_base') or self.urls['config_provider_home_uri']) + action.lstrip('/')
|
||||
|
||||
tags = re.findall(r'(?is)(<input.*?name=[\'"][^\'"]+[^>]*)', 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'):
|
||||
tags = re.findall(r'(?is)(<input[^>]*?name=[\'"][^\'"]+[^>]*)', response)
|
||||
attrs = [[(re.findall(r'(?is)%s=[\'"]([^\'"]+)' % attr, x) or [''])[0]
|
||||
for attr in ['type', 'name', 'value']] for x in tags]
|
||||
for itype, name, value in attrs:
|
||||
if 'password' in [itype, name]:
|
||||
passfield = name
|
||||
if name not in ('username', 'password') and 'password' != itype:
|
||||
post_params.setdefault(name, value)
|
||||
except KeyError:
|
||||
return super(TorrentProvider, self)._authorised()
|
||||
|
@ -1001,7 +1003,7 @@ class TorrentProvider(object, GenericProvider):
|
|||
if self.username not in post_params.values():
|
||||
post_params['username'] = self.username
|
||||
if self.password not in post_params.values():
|
||||
post_params['password'] = self.password
|
||||
post_params[(passfield, 'password')[not passfield]] = self.password
|
||||
|
||||
response = helpers.getURL(url, post_data=post_params, session=self.session, timeout=timeout)
|
||||
if response:
|
||||
|
@ -1074,10 +1076,10 @@ class TorrentProvider(object, GenericProvider):
|
|||
|
||||
@staticmethod
|
||||
def _has_no_results(*html):
|
||||
return re.search(r'(?i)<(?:b|div|h\d|p|span|strong)[^>]*>\s*(?:' +
|
||||
return re.search(r'(?i)<(?:b|div|h\d|p|span|strong|td)[^>]*>\s*(?:' +
|
||||
'your\ssearch.*?did\snot\smatch|' +
|
||||
'(?:nothing|0</b>\s+torrents)\sfound|' +
|
||||
'(sorry,\s)?no\s(?:results|torrents)\s(found|match)|' +
|
||||
'(sorry,\s)?no\s(?:results|torrents)\s(found|here|match)|' +
|
||||
'.*?there\sare\sno\sresults|' +
|
||||
'.*?no\shits\.\sTry\sadding' +
|
||||
')', html[0])
|
||||
|
|
|
@ -37,7 +37,7 @@ class GrabTheInfoProvider(generic.TorrentProvider):
|
|||
'search': '&search=%s',
|
||||
'get': self.url_base + '%s'}
|
||||
|
||||
self.categories = {'shows': [36, 32, 43, 56, 8, 10, 61]}
|
||||
self.categories = {'shows': [36, 32, 43, 56, 8, 65, 61, 10]}
|
||||
|
||||
self.url = self.urls['config_provider_home_uri']
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from requests.compat import OrderedDict
|
||||
import re
|
||||
import traceback
|
||||
|
||||
|
@ -42,12 +46,15 @@ class HDSpaceProvider(generic.TorrentProvider):
|
|||
|
||||
self.url = self.urls['config_provider_home_uri']
|
||||
|
||||
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
|
||||
self.filter = []
|
||||
self.may_filter = OrderedDict([
|
||||
('f0', ('not marked', False, '')), ('f25', ('FL', True, 'gold|sf')), ('f50', ('F/L', True, 'silver|sf'))])
|
||||
self.username, self.password, self.minseed, self.minleech = 4 * [None]
|
||||
|
||||
def _authorised(self, **kwargs):
|
||||
|
||||
return super(HDSpaceProvider, self)._authorised(
|
||||
post_params={'uid': self.username, 'pwd': self.password, 'form_tmpl': 'name=[\'"]login[\'"]'})
|
||||
post_params={'uid': self.username, 'form_tmpl': 'name=[\'"]login[\'"]'})
|
||||
|
||||
def _search_provider(self, search_params, **kwargs):
|
||||
|
||||
|
@ -57,8 +64,17 @@ class HDSpaceProvider(generic.TorrentProvider):
|
|||
|
||||
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
|
||||
|
||||
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'torrent-details', 'get': 'download', 'fl': 'free',
|
||||
'peers': 'page=peers', 'nodots': '[\.\s]+'}.items())
|
||||
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {
|
||||
'info': 'torrent-details', 'get': 'download', 'peers': 'page=peers', 'nodots': '[\.\s]+'}.items())
|
||||
log = ''
|
||||
if self.filter:
|
||||
non_marked = 'f0' in self.filter
|
||||
# if search_any, use unselected to exclude, else use selected to keep
|
||||
filters = ([f for f in self.may_filter if f in self.filter],
|
||||
[f for f in self.may_filter if f not in self.filter])[non_marked]
|
||||
rc['filter'] = re.compile('(?i)(%s).png' % '|'.join(
|
||||
[self.may_filter[f][2] for f in filters if self.may_filter[f][1]]))
|
||||
log = '%sing (%s) ' % (('keep', 'skipp')[non_marked], ', '.join([self.may_filter[f][0] for f in filters]))
|
||||
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
|
||||
|
@ -83,7 +99,10 @@ class HDSpaceProvider(generic.TorrentProvider):
|
|||
raise generic.HaltParseException
|
||||
|
||||
for tr in torrent_rows[1:]:
|
||||
if tr.find('td', class_='header'):
|
||||
if (tr.find('td', class_='header')
|
||||
or (any(self.filter)
|
||||
and ((non_marked and tr.find('img', src=rc['filter']))
|
||||
or (not non_marked and not tr.find('img', src=rc['filter']))))):
|
||||
continue
|
||||
downlink = tr.find('a', href=rc['get'])
|
||||
if None is downlink:
|
||||
|
@ -91,8 +110,7 @@ class HDSpaceProvider(generic.TorrentProvider):
|
|||
try:
|
||||
seeders, leechers = [tryInt(x.get_text().strip())
|
||||
for x in tr.find_all('a', href=rc['peers'])]
|
||||
if self._peers_fail(mode, seeders, leechers)\
|
||||
or self.freeleech and None is tr.find('img', title=rc['fl']):
|
||||
if self._peers_fail(mode, seeders, leechers):
|
||||
continue
|
||||
|
||||
info = tr.find('a', href=rc['info'])
|
||||
|
@ -109,7 +127,7 @@ class HDSpaceProvider(generic.TorrentProvider):
|
|||
pass
|
||||
except (StandardError, 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._log_search(mode, len(items[mode]) - cnt, log + search_url)
|
||||
|
||||
results = self._sort_seeding(mode, results + items[mode])
|
||||
|
||||
|
|
145
sickbeard/providers/hdtorrents.py
Normal file
145
sickbeard/providers/hdtorrents.py
Normal file
|
@ -0,0 +1,145 @@
|
|||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from requests.compat import OrderedDict
|
||||
import re
|
||||
import traceback
|
||||
|
||||
from . import generic
|
||||
from sickbeard import logger
|
||||
from sickbeard.bs4_parser import BS4Parser
|
||||
from sickbeard.helpers import tryInt
|
||||
from lib.unidecode import unidecode
|
||||
|
||||
|
||||
class HDTorrentsProvider(generic.TorrentProvider):
|
||||
|
||||
def __init__(self):
|
||||
generic.TorrentProvider.__init__(self, 'HDTorrents')
|
||||
|
||||
self.url_home = ['https://hd-torrents.%s/' % x for x in 'org', 'net', 'me'] + ['https://hdts.ru/']
|
||||
|
||||
self.url_vars = {'login_action': 'index.php',
|
||||
'search': 'torrents.php?search=%s&active=0&options=0&%s', 'get': '%s'}
|
||||
self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login_action': '%(home)s%(vars)s',
|
||||
'search': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'}
|
||||
|
||||
self.categories = {'Episode': [59, 60, 30, 38, 65], 'anime': ['Animation']}
|
||||
self.categories['Season'] = self.categories['Cache'] = self.categories['Episode']
|
||||
|
||||
self.filter = []
|
||||
self.may_filter = OrderedDict(
|
||||
[('f0', ('not marked', False)), ('f25', ('-25%', True)), ('f50', ('-50%', True)), ('f75', ('-75%', True))])
|
||||
self.username, self.password, self.minseed, self.minleech = 4 * [None]
|
||||
|
||||
def _authorised(self, **kwargs):
|
||||
|
||||
return super(HDTorrentsProvider, self)._authorised(post_params={'uid': self.username})
|
||||
|
||||
@staticmethod
|
||||
def _has_signature(data=None):
|
||||
return generic.TorrentProvider._has_signature(data) or \
|
||||
(data and re.search(r'(?i)<title[^<]+?(HD-Torrents)', data))
|
||||
|
||||
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': 'details', 'get': 'download'}.items())
|
||||
log = ''
|
||||
if self.filter:
|
||||
non_marked = 'f0' in self.filter
|
||||
# if search_any, use unselected to exclude, else use selected to keep
|
||||
filters = ([f for f in self.may_filter if f in self.filter],
|
||||
[f for f in self.may_filter if f not in self.filter])[non_marked]
|
||||
rc['filter'] = re.compile('(?i)(%s).png' % '|'.join(
|
||||
[f.replace('f', '') for f in filters if self.may_filter[f][1]]))
|
||||
log = '%sing (%s) ' % (('keep', 'skipp')[non_marked], ', '.join([self.may_filter[f][0] for f in filters]))
|
||||
|
||||
for mode in search_params.keys():
|
||||
rc['cats'] = re.compile('(?i)category=(?:%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'] % (
|
||||
search_string,
|
||||
self._categories_string(mode, template='category[]=%s')
|
||||
.replace('&category[]=Animation', ('&genre[]=Animation', '')[mode in ['Cache', 'Propers']]))
|
||||
html = self.get_url(search_url)
|
||||
|
||||
cnt = len(items[mode])
|
||||
try:
|
||||
if not html or self._has_no_results(html):
|
||||
raise generic.HaltParseException
|
||||
|
||||
html = re.sub('(?ims)<div[^>]+display:\s*none;.*?</div>', '', html)
|
||||
html = re.sub('(?im)href=([^\\"][^>]+)>', r'href="\1">', html)
|
||||
html = (html.replace('"/></td>', '" /></a></td>')
|
||||
.replace('"title="', '" title="')
|
||||
.replace('</u></span></a></td>', '</u></a></span></td>'))
|
||||
html = re.sub('(?im)<b([mtwfs][^>]+)', r'<b>\1</b', html)
|
||||
|
||||
with BS4Parser(html, features=['html5lib', 'permissive'], attr='width="100%"') as soup:
|
||||
torrent_rows = [tr for tr in ([] if not soup else soup.find_all('tr'))
|
||||
if tr.find('a', href=rc['info'])]
|
||||
|
||||
if not len(torrent_rows):
|
||||
raise generic.HaltParseException
|
||||
|
||||
for tr in torrent_rows:
|
||||
if (any(self.filter)
|
||||
and ((non_marked and tr.find('img', src=rc['filter']))
|
||||
or (not non_marked and not tr.find('img', src=rc['filter'])))):
|
||||
continue
|
||||
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) or not tr.find('a', href=rc['cats']):
|
||||
continue
|
||||
title = tr.find('a', href=rc['info']).get_text().strip()
|
||||
download_url = self._link(tr.find('a', href=rc['get'])['href'])
|
||||
except (AttributeError, TypeError, ValueError, IndexError):
|
||||
continue
|
||||
|
||||
if title and download_url:
|
||||
items[mode].append((title, download_url, seeders, self._bytesizer(size)))
|
||||
|
||||
except generic.HaltParseException:
|
||||
pass
|
||||
except (StandardError, Exception):
|
||||
logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR)
|
||||
|
||||
self._log_search(mode, len(items[mode]) - cnt, log + search_url)
|
||||
|
||||
results = self._sort_seeding(mode, results + items[mode])
|
||||
|
||||
return results
|
||||
|
||||
def _season_strings(self, ep_obj, **kwargs):
|
||||
return generic.TorrentProvider._season_strings(self, ep_obj, scene=False, **kwargs)
|
||||
|
||||
def _episode_strings(self, ep_obj, **kwargs):
|
||||
return generic.TorrentProvider._episode_strings(self, ep_obj, scene=False, sep_date=' ', **kwargs)
|
||||
|
||||
|
||||
provider = HDTorrentsProvider()
|
|
@ -1,106 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import re
|
||||
import traceback
|
||||
|
||||
from . import generic
|
||||
from sickbeard import logger
|
||||
from sickbeard.bs4_parser import BS4Parser
|
||||
from sickbeard.helpers import tryInt
|
||||
from lib.unidecode import unidecode
|
||||
|
||||
|
||||
class ILTProvider(generic.TorrentProvider):
|
||||
|
||||
def __init__(self):
|
||||
generic.TorrentProvider.__init__(self, 'ILoveTorrents')
|
||||
|
||||
self.url_base = 'https://www.ilovetorrents.me/'
|
||||
self.urls = {'config_provider_home_uri': self.url_base,
|
||||
'login_action': self.url_base + 'login.php',
|
||||
'search': self.url_base + 'browse.php?search=%s&%s&incldead=0&blah=0',
|
||||
'get': self.url_base + '%s'}
|
||||
|
||||
self.categories = {'Season': [5], 'Episode': [7, 8, 40], 'anime': [23]}
|
||||
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]
|
||||
|
||||
def _authorised(self, **kwargs):
|
||||
|
||||
return super(ILTProvider, self)._authorised()
|
||||
|
||||
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': 'details', '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
|
||||
|
||||
html = self.get_url(self.urls['search'] % ('+'.join(search_string.split()),
|
||||
self._categories_string(mode)))
|
||||
|
||||
cnt = len(items[mode])
|
||||
try:
|
||||
if not html or self._has_no_results(html):
|
||||
raise generic.HaltParseException
|
||||
|
||||
with BS4Parser(html, features=['html5lib', 'permissive']) as soup:
|
||||
torrent_table = soup.find('table', '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) or not tr.find('a', href=rc['cats']):
|
||||
continue
|
||||
|
||||
title = tr.find('a', href=rc['info']).get_text().strip()
|
||||
download_url = self._link(tr.find('a', href=rc['get'])['href'])
|
||||
except (AttributeError, TypeError, ValueError, IndexError):
|
||||
continue
|
||||
|
||||
if title and download_url:
|
||||
items[mode].append((title, download_url, seeders, self._bytesizer(size)))
|
||||
|
||||
except generic.HaltParseException:
|
||||
pass
|
||||
except (StandardError, Exception):
|
||||
logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR)
|
||||
|
||||
self._log_search(mode, len(items[mode]) - cnt, self.session.response.get('url'))
|
||||
|
||||
results = self._sort_seeding(mode, results + items[mode])
|
||||
|
||||
return results
|
||||
|
||||
|
||||
provider = ILTProvider()
|
|
@ -49,7 +49,7 @@ class NcoreProvider(generic.TorrentProvider):
|
|||
|
||||
return super(NcoreProvider, self)._authorised(
|
||||
logged_in=(lambda y='': all([bool(y), 'action="login' not in y, self.has_all_cookies('PHPSESSID')])),
|
||||
post_params={'nev': self.username, 'pass': self.password, 'form_tmpl': 'name=[\'"]login[\'"]'})
|
||||
post_params={'nev': self.username, 'form_tmpl': 'name=[\'"]login[\'"]'})
|
||||
|
||||
def _search_provider(self, search_params, **kwargs):
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class PiSexyProvider(generic.TorrentProvider):
|
|||
|
||||
self.url = self.urls['config_provider_home_uri']
|
||||
|
||||
self.username, self.password, self.minseed, self.minleech = 4 * [None]
|
||||
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
|
||||
|
||||
def _authorised(self, **kwargs):
|
||||
|
||||
|
@ -51,9 +51,9 @@ class PiSexyProvider(generic.TorrentProvider):
|
|||
|
||||
items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []}
|
||||
|
||||
rc = dict((k, re.compile('(?i)' + v))
|
||||
for (k, v) in {'info': 'download', 'get': 'download', 'valid_cat': 'cat=(?:0|50[12])',
|
||||
'title': r'Download\s([^\s]+).*', 'seeders': r'(^\d+)', 'leechers': r'(\d+)$'}.items())
|
||||
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {
|
||||
'info': 'download', 'get': 'download', 'valid_cat': 'cat=(?:0|50[12])', 'filter': 'free',
|
||||
'title': r'Download\s([^\s]+).*', 'seeders': r'(^\d+)', 'leechers': r'(\d+)$'}.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
|
||||
|
@ -78,7 +78,8 @@ class PiSexyProvider(generic.TorrentProvider):
|
|||
seeders, leechers = 2 * [tr.find_all('td')[-4].get_text().strip()]
|
||||
seeders, leechers = [tryInt(n) for n in [
|
||||
rc['seeders'].findall(seeders)[0], rc['leechers'].findall(leechers)[0]]]
|
||||
if self._peers_fail(mode, seeders, leechers) or not tr.find('a', href=rc['valid_cat']):
|
||||
if self._peers_fail(mode, seeders, leechers) or not tr.find('a', href=rc['valid_cat']) \
|
||||
or (self.freeleech and not tr.find('img', src=rc['filter'])):
|
||||
continue
|
||||
|
||||
info = tr.find('a', href=rc['info'])
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from requests.compat import OrderedDict
|
||||
import re
|
||||
import traceback
|
||||
|
||||
|
@ -35,13 +39,18 @@ class PrivateHDProvider(generic.TorrentProvider):
|
|||
'login_action': self.url_base + 'auth/login',
|
||||
'search': self.url_base + 'torrents?%s' % '&'.join(
|
||||
['in=1', 'tags=', 'type=2', 'language=0', 'subtitle=0', 'rip_type=0',
|
||||
'video_quality=0', 'uploader=', 'search=%s', 'tv_type[]=%s', 'discount[]=%s'])}
|
||||
'video_quality=0', 'uploader=', 'search=%s', 'tv_type[]=%s'])}
|
||||
|
||||
self.categories = {'Season': [2], 'Episode': [1], 'Cache': [0]}
|
||||
|
||||
self.url = self.urls['config_provider_home_uri']
|
||||
|
||||
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
|
||||
self.filter = []
|
||||
self.may_filter = OrderedDict([
|
||||
('f0', ('not marked', False)), ('free', ('free', True)),
|
||||
('half', ('50% down', True)), ('double', ('2x up', True))])
|
||||
self.username, self.password, self.minseed, self.minleech = 4 * [None]
|
||||
self.confirmed = False
|
||||
|
||||
def _authorised(self, **kwargs):
|
||||
|
||||
|
@ -59,6 +68,21 @@ class PrivateHDProvider(generic.TorrentProvider):
|
|||
|
||||
rc = dict((k, re.compile('(?i)' + v))
|
||||
for (k, v) in {'info': '.*?details\s*-\s*', 'get': 'download'}.items())
|
||||
log = ''
|
||||
if self.filter:
|
||||
non_marked = 'f0' in self.filter
|
||||
# if search_any, use unselected to exclude, else use selected to keep
|
||||
filters = ([f for f in self.may_filter if f in self.filter],
|
||||
[f for f in self.may_filter if f not in self.filter])[non_marked]
|
||||
filters += (((all([x in filters for x in 'free', 'double']) and ['freedouble'] or [])
|
||||
+ (all([x in filters for x in 'half', 'double']) and ['halfdouble'] or [])),
|
||||
((not all([x not in filters for x in 'free', 'double']) and ['freedouble'] or [])
|
||||
+ (not all([x not in filters for x in 'half', 'double']) and ['halfdouble'] or []))
|
||||
)[non_marked]
|
||||
rc['filter'] = re.compile('(?i)^(%s)$' % '|'.join(
|
||||
['%s' % f for f in filters if (f in self.may_filter and self.may_filter[f][1]) or f]))
|
||||
log = '%sing (%s) ' % (('keep', 'skipp')[non_marked], ', '.join(
|
||||
[f in self.may_filter and self.may_filter[f][0] or f for f in filters]))
|
||||
for mode in search_params.keys():
|
||||
if mode in ['Season', 'Episode']:
|
||||
show_type = self.show.air_by_date and 'Air By Date' \
|
||||
|
@ -70,7 +94,7 @@ class PrivateHDProvider(generic.TorrentProvider):
|
|||
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'] % (
|
||||
'+'.join(search_string.split()), self._categories_string(mode, ''), (1, 0)[not self.freeleech])
|
||||
'+'.join(search_string.split()), self._categories_string(mode, ''))
|
||||
|
||||
html = self.get_url(search_url)
|
||||
|
||||
|
@ -87,6 +111,15 @@ class PrivateHDProvider(generic.TorrentProvider):
|
|||
raise generic.HaltParseException
|
||||
|
||||
for tr in torrent_rows[1:]:
|
||||
if self.confirmed and tr.find('i', title=re.compile('(?i)unverified')):
|
||||
continue
|
||||
if any(self.filter):
|
||||
marked = ','.join([x.attrs.get('title', '').lower() for x in tr.find_all(
|
||||
'i', attrs={'class': ['fa-star', 'fa-diamond', 'fa-star-half-o']})])
|
||||
munged = ''.join(filter(marked.__contains__, ['free', 'half', 'double']))
|
||||
if ((non_marked and rc['filter'].search(munged)) or
|
||||
(not non_marked and not rc['filter'].search(munged))):
|
||||
continue
|
||||
try:
|
||||
seeders, leechers, size = [tryInt(n, n) for n in [
|
||||
tr.find_all('td')[x].get_text().strip() for x in -3, -2, -4]]
|
||||
|
@ -106,7 +139,7 @@ class PrivateHDProvider(generic.TorrentProvider):
|
|||
except (StandardError, 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._log_search(mode, len(items[mode]) - cnt, log + search_url)
|
||||
|
||||
results = self._sort_seeding(mode, results + items[mode])
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from requests.compat import OrderedDict
|
||||
import re
|
||||
import time
|
||||
import traceback
|
||||
|
@ -22,7 +26,7 @@ import traceback
|
|||
from . import generic
|
||||
from sickbeard import logger
|
||||
from sickbeard.bs4_parser import BS4Parser
|
||||
from sickbeard.helpers import tryInt
|
||||
from sickbeard.helpers import tryInt, anon_url
|
||||
from lib.unidecode import unidecode
|
||||
|
||||
|
||||
|
@ -33,9 +37,8 @@ class PTFProvider(generic.TorrentProvider):
|
|||
|
||||
self.url_base = 'https://ptfiles.net/'
|
||||
self.urls = {'config_provider_home_uri': self.url_base,
|
||||
'login_action': self.url_base + 'loginproc/',
|
||||
'login_base': self.url_base + 'loginproc/',
|
||||
'search': self.url_base + 'browse.php?search=%s&%s&incldead=0&title=0%s',
|
||||
'login': self.url_base + 'panel.php?tool=links',
|
||||
'search': self.url_base + 'browse.php?search=%s&%s&incldead=0&title=0',
|
||||
'get': self.url_base + '%s'}
|
||||
|
||||
self.categories = {'Season': [39], 'Episode': [7, 33, 42], 'anime': [23]}
|
||||
|
@ -43,12 +46,19 @@ class PTFProvider(generic.TorrentProvider):
|
|||
|
||||
self.url = self.urls['config_provider_home_uri']
|
||||
|
||||
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
|
||||
self.filter = []
|
||||
self.may_filter = OrderedDict([
|
||||
('f0', ('not marked', False, '')), ('free', ('free', True, '^free$')),
|
||||
('freeday', ('free day', True, '^free[^!]+day')), ('freeweek', ('free week', True, '^free[^!]+week'))])
|
||||
self.digest, self.minseed, self.minleech = 3 * [None]
|
||||
|
||||
def _authorised(self, **kwargs):
|
||||
|
||||
return super(PTFProvider, self)._authorised(logged_in=(lambda y=None: self.has_all_cookies('session_key')),
|
||||
post_params={'force_ssl': 'on', 'ssl': '', 'form_tmpl': True})
|
||||
return super(PTFProvider, self)._authorised(
|
||||
logged_in=(lambda y='': all(
|
||||
['RSS Feed' in y, self.has_all_cookies('session_key')] +
|
||||
[(self.session.cookies.get(x) or 'sg!no!pw') in self.digest for x in ['session_key']])),
|
||||
failed_msg=(lambda y=None: u'Invalid cookie details for %s. Check settings'))
|
||||
|
||||
def _search_provider(self, search_params, **kwargs):
|
||||
|
||||
|
@ -60,13 +70,21 @@ class PTFProvider(generic.TorrentProvider):
|
|||
|
||||
rc = dict((k, re.compile('(?i)' + v)) for (k, v) in {'info': 'details', 'get': 'dl.php', 'snatch': 'snatches',
|
||||
'seeders': r'(^\d+)', 'leechers': r'(\d+)$'}.items())
|
||||
log = ''
|
||||
if self.filter:
|
||||
non_marked = 'f0' in self.filter
|
||||
# if search_any, use unselected to exclude, else use selected to keep
|
||||
filters = ([f for f in self.may_filter if f in self.filter],
|
||||
[f for f in self.may_filter if f not in self.filter])[non_marked]
|
||||
rc['filter'] = re.compile('(?i)(%s)' % '|'.join(
|
||||
[self.may_filter[f][2] for f in filters if self.may_filter[f][1]]))
|
||||
log = '%sing (%s) ' % (('keep', 'skipp')[non_marked], ', '.join([self.may_filter[f][0] for f in filters]))
|
||||
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'] % ('+'.join(search_string.split()), self._categories_string(mode),
|
||||
('&free=1', '')[not self.freeleech])
|
||||
search_url = self.urls['search'] % ('+'.join(search_string.split()), self._categories_string(mode))
|
||||
html = self.get_url(search_url)
|
||||
time.sleep(2)
|
||||
if not self.has_all_cookies(['session_key']):
|
||||
|
@ -87,6 +105,15 @@ class PTFProvider(generic.TorrentProvider):
|
|||
raise generic.HaltParseException
|
||||
|
||||
for tr in torrent_rows[1:]:
|
||||
if any(self.filter):
|
||||
marker = ''
|
||||
try:
|
||||
marker = tr.select('a[href^="browse"] .tip')[0].get_text().strip()
|
||||
except (StandardError, Exception):
|
||||
pass
|
||||
if ((non_marked and rc['filter'].search(marker)) or
|
||||
(not non_marked and not rc['filter'].search(marker))):
|
||||
continue
|
||||
try:
|
||||
seeders, leechers = 2 * [tr.find_all('td')[-2].get_text().strip()]
|
||||
seeders, leechers = [tryInt(n) for n in [
|
||||
|
@ -110,11 +137,19 @@ class PTFProvider(generic.TorrentProvider):
|
|||
except (StandardError, Exception):
|
||||
logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR)
|
||||
|
||||
self._log_search(mode, len(items[mode]) - cnt, self.session.response.get('url'))
|
||||
self._log_search(mode, len(items[mode]) - cnt, log + self.session.response.get('url'))
|
||||
|
||||
results = self._sort_seeding(mode, results + items[mode])
|
||||
|
||||
return results
|
||||
|
||||
def ui_string(self, key):
|
||||
if 'ptfiles_digest' == key and self._valid_home():
|
||||
current_url = getattr(self, 'urls', {}).get('config_provider_home_uri')
|
||||
return ('use... \'session_key=xx\'' +
|
||||
(current_url and (' from a session logged in at <a target="_blank" href="%s">%s</a>' %
|
||||
(anon_url(current_url), current_url.strip('/'))) or ''))
|
||||
return ''
|
||||
|
||||
|
||||
provider = PTFProvider()
|
||||
|
|
|
@ -22,7 +22,7 @@ import traceback
|
|||
from . import generic
|
||||
from sickbeard import logger
|
||||
from sickbeard.bs4_parser import BS4Parser
|
||||
from sickbeard.helpers import tryInt
|
||||
from sickbeard.helpers import tryInt, anon_url
|
||||
from lib.unidecode import unidecode
|
||||
|
||||
|
||||
|
@ -31,22 +31,27 @@ class SceneTimeProvider(generic.TorrentProvider):
|
|||
def __init__(self):
|
||||
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,
|
||||
'login_action': self.url_base + 'login.php',
|
||||
'browse': self.url_base + 'browse_API.php',
|
||||
'params': {'sec': 'jax', 'cata': 'yes'},
|
||||
'get': self.url_base + 'download.php/%(id)s/%(title)s.torrent'}
|
||||
self.url_home = ['https://%s.scenetime.com/' % u for u in 'www', 'uk']
|
||||
|
||||
self.url_vars = {'login': 'support.php', 'browse': 'browse_API.php', 'get': 'download.php/%s.torrent'}
|
||||
self.url_tmpl = {'config_provider_home_uri': '%(home)s', 'login': '%(home)s%(vars)s',
|
||||
'browse': '%(home)s%(vars)s', 'get': '%(home)s%(vars)s'}
|
||||
|
||||
self.categories = {'shows': [2, 43, 9, 63, 77, 79, 83]}
|
||||
|
||||
self.url = self.urls['config_provider_home_uri']
|
||||
|
||||
self.username, self.password, self.freeleech, self.minseed, self.minleech = 5 * [None]
|
||||
self.digest, self.freeleech, self.minseed, self.minleech = 4 * [None]
|
||||
|
||||
def _authorised(self, **kwargs):
|
||||
|
||||
return super(SceneTimeProvider, self)._authorised(post_params={'form_tmpl': True})
|
||||
return super(SceneTimeProvider, self)._authorised(
|
||||
logged_in=(lambda y='': all(
|
||||
['staff-support' in y, self.has_all_cookies()] +
|
||||
[(self.session.cookies.get(x) or 'sg!no!pw') in self.digest for x in 'uid', 'pass'])),
|
||||
failed_msg=(lambda y=None: u'Invalid cookie details for %s. Check settings'))
|
||||
|
||||
@staticmethod
|
||||
def _has_signature(data=None):
|
||||
return generic.TorrentProvider._has_signature(data) or (data and re.search(r'(?i)<title[^<]+?(Scenetim)', data))
|
||||
|
||||
def _search_provider(self, search_params, **kwargs):
|
||||
|
||||
|
@ -63,7 +68,7 @@ class SceneTimeProvider(generic.TorrentProvider):
|
|||
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 = {'sec': 'jax', 'cata': 'yes'}
|
||||
post_data.update(ast.literal_eval(
|
||||
'{%s}' % self._categories_string(template='"c%s": "1"', delimiter=',')))
|
||||
if 'Cache' != mode:
|
||||
|
@ -99,9 +104,8 @@ class SceneTimeProvider(generic.TorrentProvider):
|
|||
|
||||
info = tr.find('a', href=rc['info'])
|
||||
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._link('%s/%s' % (
|
||||
re.sub(rc['get'], r'\1', str(info.attrs['href'])), str(title).replace(' ', '.')))
|
||||
except (AttributeError, TypeError, ValueError, KeyError):
|
||||
continue
|
||||
|
||||
|
@ -120,5 +124,13 @@ class SceneTimeProvider(generic.TorrentProvider):
|
|||
|
||||
return results
|
||||
|
||||
def ui_string(self, key):
|
||||
if 'scenetime_digest' == key and self._valid_home():
|
||||
current_url = getattr(self, 'urls', {}).get('config_provider_home_uri')
|
||||
return ('use... \'uid=xx; pass=yy\'' +
|
||||
(current_url and (' from a session logged in at <a target="_blank" href="%s">%s</a>' %
|
||||
(anon_url(current_url), current_url.strip('/'))) or ''))
|
||||
return ''
|
||||
|
||||
|
||||
provider = SceneTimeProvider()
|
||||
|
|
|
@ -51,8 +51,7 @@ class ShazbatProvider(generic.TorrentProvider):
|
|||
|
||||
return super(ShazbatProvider, self)._authorised(
|
||||
logged_in=(lambda y=None: '<input type="password"' not in helpers.getURL(
|
||||
self.urls['feeds'], session=self.session)),
|
||||
post_params={'tv_login': self.username, 'tv_password': self.password, 'form_tmpl': True})
|
||||
self.urls['feeds'], session=self.session)), post_params={'tv_login': self.username, 'form_tmpl': True})
|
||||
|
||||
def _search_provider(self, search_params, **kwargs):
|
||||
|
||||
|
@ -107,7 +106,7 @@ class ShazbatProvider(generic.TorrentProvider):
|
|||
if self._peers_fail(mode, seeders, leechers):
|
||||
continue
|
||||
sizes = [(tryInt(x[0], x[0]), tryInt(x[1], False)) for x in
|
||||
re.findall('([\d\.]+\w+)?(?:\s*[\(\[](\d+)[\)\]])?', stats) if x[0]][0]
|
||||
re.findall('([\d.]+\w+)?(?:\s*[(\[](\d+)[)\]])?', stats) if x[0]][0]
|
||||
size = sizes[(0, 1)[1 < len(sizes)]]
|
||||
|
||||
for element in [x for x in tr.find_all('td')[2].contents[::-1] if unicode(x).strip()]:
|
||||
|
|
|
@ -35,7 +35,7 @@ class TorrentDayProvider(generic.TorrentProvider):
|
|||
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, 34, 2], 'Anime': [29]}
|
||||
self.categories = {'Season': [31, 33, 14], 'Episode': [24, 32, 26, 7, 34, 2], 'anime': [29]}
|
||||
self.categories['Cache'] = self.categories['Season'] + self.categories['Episode']
|
||||
|
||||
self.proper_search_terms = None
|
||||
|
|
|
@ -5060,6 +5060,12 @@ class ConfigProviders(Config):
|
|||
if hasattr(torrent_src, attr):
|
||||
setattr(torrent_src, attr, str(kwargs.get(src_id_prefix + attr, '')).strip() or 'eponly')
|
||||
|
||||
attr = 'filter'
|
||||
if hasattr(torrent_src, attr):
|
||||
setattr(torrent_src, attr,
|
||||
[k for k in torrent_src.may_filter.keys()
|
||||
if config.checkbox_to_value(kwargs.get('%sfilter_%s' % (src_id_prefix, k)))])
|
||||
|
||||
# update nzb source settings
|
||||
for nzb_src in [src for src in sickbeard.providers.sortedProviderList() if
|
||||
sickbeard.GenericProvider.NZB == src.providerType]:
|
||||
|
|
Loading…
Reference in a new issue