From cca593753af62b420367ff5f0f253d56862c7148 Mon Sep 17 00:00:00 2001 From: JackDandy Date: Wed, 17 Jun 2015 00:58:50 +0100 Subject: [PATCH] Change refactor TPB to use torrent provider simplification and PEP8. --- CHANGES.md | 1 + gui/slick/images/providers/the_pirate_bay.png | Bin 3743 -> 3539 bytes sickbeard/providers/thepiratebay.py | 378 ++++++------------ 3 files changed, 115 insertions(+), 264 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d3177ca9..c773c87e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -35,6 +35,7 @@ * Change refactor SCC to use torrent provider simplification and PEP8 * Change refactor SCD to use torrent provider simplification * Change refactor TB to use torrent provider simplification and PEP8 +* Change refactor TBP to use torrent provider simplification and PEP8 * Change refactor TD to use torrent provider simplification and PEP8 * Change refactor TL to use torrent provider simplification and PEP8 * Remove HDTorrents torrent provider diff --git a/gui/slick/images/providers/the_pirate_bay.png b/gui/slick/images/providers/the_pirate_bay.png index 9fce30b6a9617b67ab3b699b2daa66ff7291891b..4d209da3515795cfef9908c4ede43dba2902eabb 100644 GIT binary patch delta 3500 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 JPDHLkV1j%D3@HEr diff --git a/sickbeard/providers/thepiratebay.py b/sickbeard/providers/thepiratebay.py index 2e1481b6..3e9f5cf3 100644 --- a/sickbeard/providers/thepiratebay.py +++ b/sickbeard/providers/thepiratebay.py @@ -1,5 +1,4 @@ -# Author: Mr_Orange -# URL: http://code.google.com/p/sickbeard/ +# coding=utf-8 # # This file is part of SickGear. # @@ -18,84 +17,47 @@ from __future__ import with_statement -import re -import urllib import os +import re import datetime +import urllib +import traceback -import sickbeard -import generic +from . import generic +from sickbeard import config, logger, tvcache, show_name_helpers from sickbeard.common import Quality, mediaExtensions from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException -from sickbeard import db, classes, logger, tvcache, helpers -from sickbeard.show_name_helpers import allPossibleShowNames, sanitizeSceneName +from sickbeard.bs4_parser import BS4Parser from lib.unidecode import unidecode class ThePirateBayProvider(generic.TorrentProvider): + def __init__(self): - generic.TorrentProvider.__init__(self, 'The Pirate Bay', True, False) - self.ratio = None + generic.TorrentProvider.__init__(self, 'The Pirate Bay') + + self.urls = {'config_provider_home_uri': ['https://thepiratebay.gd/', 'https://thepiratebay.mn/', + 'https://thepiratebay.am/', 'https://thepiratebay.vg/', + 'https://thepiratebay.la/'], + 'search': 'search/%s/0/7/200', + 'cache': 'tv/latest/'} # order by seed + + self.url = self.urls['config_provider_home_uri'][0] + + self.minseed, self.minleech = 2 * [None] self.confirmed = False - self.minseed = None - self.minleech = None self.cache = ThePirateBayCache(self) - # self.proxy = ThePirateBayWebproxy() - self.urls = {'base_url': ['https://thepiratebay.gd', 'https://thepiratebay.mn', - 'https://thepiratebay.am', 'https://thepiratebay.vg', 'https://thepiratebay.la'], - 'search': '/search/%s/0/7/200'} # order by seed - self.url = self.urls['base_url'][4] - self.re_title_url = '/torrent/(?P\d+)/(?P.*?)//1".+?(?P<url>magnet.*?)//1".+?(?P<seeders>\d+)</td>.+?(?P<leechers>\d+)</td>' - - def getQuality(self, item, anime=False): - - quality = Quality.sceneQuality(item[0], anime) - return quality - - def _reverseQuality(self, quality): - - quality_string = '' - - if Quality.SDTV == quality: - quality_string = 'HDTV x264' - if Quality.SDDVD == quality: - quality_string = 'DVDRIP' - elif Quality.HDTV == quality: - quality_string = '720p HDTV x264' - elif Quality.FULLHDTV == quality: - quality_string = '1080p HDTV x264' - elif Quality.RAWHDTV == quality: - quality_string = '1080i HDTV mpeg2' - elif Quality.HDWEBDL == quality: - quality_string = '720p WEB-DL h264' - elif Quality.FULLHDWEBDL == quality: - quality_string = '1080p WEB-DL h264' - elif Quality.HDBLURAY == quality: - quality_string = '720p Bluray x264' - elif Quality.FULLHDBLURAY == quality: - quality_string = '1080p Bluray x264' - - return quality_string 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 """ quality = Quality.UNKNOWN - - fileName = None - + 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['base_url']): - url += details_url - if hasattr(self, 'proxy'): - url = self.proxy._buildURL(url) - - if self.proxy and self.proxy.isEnabled(): - self.headers.update({'referer': self.proxy.getProxyURL()}) - - data = self.getURL(url) + for idx, url in enumerate(self.urls['config_provider_home_uri']): + data = self.getURL(url + details_url) if data and re.search(r'<title>The\sPirate\sBay', data[33:200:]): has_signature = True break @@ -103,22 +65,22 @@ class ThePirateBayProvider(generic.TorrentProvider): 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['base_url']), logger.ERROR) + 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) if not data: return None - filesList = re.findall('<td.+>(.*?)</td>', data) + files_list = re.findall('<td.+>(.*?)</td>', data) - if not filesList: + if not files_list: logger.log(u'Unable to get the torrent file list for ' + title, logger.ERROR) - videoFiles = filter(lambda x: x.rpartition('.')[2].lower() in mediaExtensions, filesList) + video_files = filter(lambda x: x.rpartition('.')[2].lower() in mediaExtensions, files_list) # Filtering SingleEpisode/MultiSeason Torrent - if ep_number > len(videoFiles) or float(ep_number * 1.1) < len(videoFiles): + if ep_number > len(video_files) or float(ep_number * 1.1) < len(video_files): logger.log(u'Result %s has episode %s and total episodes retrieved in torrent are %s' - % (title, str(ep_number), str(len(videoFiles))), logger.DEBUG) + % (title, str(ep_number), str(len(video_files))), logger.DEBUG) logger.log(u'Result %s seems to be a single episode or multiseason torrent, skipping result...' % title, logger.DEBUG) return None @@ -126,21 +88,21 @@ class ThePirateBayProvider(generic.TorrentProvider): if Quality.UNKNOWN != Quality.sceneQuality(title): return title - for fileName in videoFiles: - quality = Quality.sceneQuality(os.path.basename(fileName)) + for file_name in video_files: + quality = Quality.sceneQuality(os.path.basename(file_name)) if Quality.UNKNOWN != quality: break - if None is not fileName and Quality.UNKNOWN == quality: - quality = Quality.assumeQuality(os.path.basename(fileName)) + if None is not file_name and Quality.UNKNOWN == quality: + quality = Quality.assumeQuality(os.path.basename(file_name)) if Quality.UNKNOWN == quality: logger.log(u'Unable to obtain a Season Quality for ' + title, logger.DEBUG) return None try: - myParser = NameParser(showObj=self.show) - parse_result = myParser.parse(fileName) + my_parser = NameParser(showObj=self.show) + parse_result = my_parser.parse(file_name) except (InvalidNameException, InvalidShowException): return None @@ -149,249 +111,137 @@ class ThePirateBayProvider(generic.TorrentProvider): if parse_result.series_name and parse_result.season_number: title = '%s S%02d %s' % (parse_result.series_name, int(parse_result.season_number), - self._reverseQuality(quality)) + self._reverse_quality(quality)) return title - def _get_season_search_strings(self, ep_obj): + def _get_season_search_strings(self, ep_obj, **kwargs): - search_string = {'Season': []} - for show_name in set(allPossibleShowNames(self.show)): - if ep_obj.show.air_by_date or ep_obj.show.sports: - ep_string = show_name + ' ' + str(ep_obj.airdate).split('-')[0] - search_string['Season'].append(ep_string) - ep_string = show_name + ' Season ' + str(ep_obj.airdate).split('-')[0] - search_string['Season'].append(ep_string) - elif ep_obj.show.anime: - ep_string = show_name + ' ' + '%02d' % ep_obj.scene_absolute_number - search_string['Season'].append(ep_string) - else: - ep_string = show_name + ' S%02d' % int(ep_obj.scene_season) - search_string['Season'].append(ep_string) - ep_string = show_name + ' Season %s -Ep*' % str(ep_obj.scene_season) - search_string['Season'].append(ep_string) - - search_string['Season'].append(ep_string) - - return [search_string] - - def _get_episode_search_strings(self, ep_obj, add_string=''): - - search_string = {'Episode': []} - - if self.show.air_by_date: - for show_name in set(allPossibleShowNames(self.show)): - ep_string = sanitizeSceneName(show_name) + ' ' + \ - str(ep_obj.airdate).replace('-', ' ') - search_string['Episode'].append(ep_string) - elif self.show.sports: - for show_name in set(allPossibleShowNames(self.show)): - ep_string = sanitizeSceneName(show_name) + ' ' + \ - str(ep_obj.airdate).replace('-', '|') + '|' + \ - ep_obj.airdate.strftime('%b') - search_string['Episode'].append(ep_string) - elif self.show.anime: - for show_name in set(allPossibleShowNames(self.show)): - ep_string = sanitizeSceneName(show_name) + ' ' + \ - '%02i' % int(ep_obj.scene_absolute_number) - search_string['Episode'].append(ep_string) + if ep_obj.show.air_by_date or ep_obj.show.sports: + airdate = str(ep_obj.airdate).split('-')[0] + ep_detail = [airdate, 'Season ' + airdate] + elif ep_obj.show.anime: + ep_detail = '%02i' % ep_obj.scene_absolute_number else: - for show_name in set(allPossibleShowNames(self.show)): - ep_string = sanitizeSceneName(show_name) + ' ' + \ - sickbeard.config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, - 'episodenumber': ep_obj.scene_episode} + '|' + \ - sickbeard.config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season, - 'episodenumber': ep_obj.scene_episode} + ' %s' % add_string - search_string['Episode'].append(re.sub('\s+', ' ', ep_string)) + ep_detail = ['S%02d' % int(ep_obj.scene_season), + 'Season %s -Ep*' % ep_obj.scene_season] - return [search_string] + return [{'Season': self._build_search_strings(ep_detail)}] + + def _get_episode_search_strings(self, ep_obj, add_string='', **kwargs): + + if self.show.air_by_date or self.show.sports: + ep_detail = str(ep_obj.airdate).replace('-', ' ') + if self.show.sports: + ep_detail += '|' + ep_obj.airdate.strftime('%b') + elif self.show.anime: + ep_detail = '%02i' % ep_obj.scene_absolute_number + else: + ep_detail = '%s|%s' % (config.naming_ep_type[2] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode}, + config.naming_ep_type[0] % {'seasonnumber': ep_obj.scene_season, + 'episodenumber': ep_obj.scene_episode}) + + return [{'Episode': self._build_search_strings(ep_detail, append=(add_string, '')[self.show.anime])}] def _doSearch(self, search_params, search_mode='eponly', epcount=0, age=0): results = [] - items = {'Season': [], 'Episode': [], 'RSS': []} - - if hasattr(self, 'proxy') and self.proxy and self.proxy.isEnabled(): - self.headers.update({'referer': self.proxy.getProxyURL()}) + items = {'Season': [], 'Episode': [], 'Cache': []} + rc = dict((k, re.compile('(?i)' + v)) + for (k, v) in {'info': 'detail', 'get': 'download[^"]+magnet', 'tid': '.*/(\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, url = self._get_title_and_url([search_string, '', '', '', '']) if isinstance(search_string, unicode): search_string = unidecode(search_string) - for idx, url in enumerate(self.urls['base_url']): - if 'RSS' == mode: - url += '/tv/latest/' - else: - url += self.urls['search'] % (urllib.quote(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['cache'] if 'Cache' == mode\ + else self.urls['search'] % (urllib.quote(search_string)) - if hasattr(self, 'proxy'): - url = self.proxy._buildURL(url) + log_url = u'(%s/%s): %s' % (idx + 1, len(self.urls['config_provider_home_uri']), search_url) - logger.log(u'Search string at server(%s/%s): %s' % (idx + 1, len(self.urls['base_url']), url), - logger.DEBUG) - - data = self.getURL(url) - if data and re.search(r'Pirate\sBay', data[33:7632:]): + html = self.getURL(search_url) + if html and re.search(r'Pirate\sBay', html[33:7632:]): has_signature = True break else: - data = None + html = None - if not data: - continue + cnt = len(items[mode]) + try: + if not html or self._has_no_results(html): + raise generic.HaltParseException - if hasattr(self, 'proxy'): - re_title_url = self.proxy._buildRE(self.re_title_url) - else: - re_title_url = re.sub('//1', '', self.re_title_url) + with BS4Parser(html, features=['html5lib', 'permissive']) as soup: + torrent_table = soup.find('table', attrs={'id': 'searchResult'}) + torrent_rows = [] if not torrent_table else torrent_table.find_all('tr') - # Extracting torrent information from data returned by searchURL - match = re.compile(re_title_url, re.DOTALL).finditer(urllib.unquote(data)) - for torrent in match: + if 2 > len(torrent_rows): + raise generic.HaltParseException - title = torrent.group('title').replace('_', '.') # Do not know why but SickBeard skip release with '_' in name - url = torrent.group('url') - id = int(torrent.group('id')) - seeders = int(torrent.group('seeders')) - leechers = int(torrent.group('leechers')) + for tr in torrent_table.find_all('tr')[1:]: + try: + seeders, leechers = [int(tr.find_all('td')[x].get_text().strip()) for x in (-2, -1)] + if 'Cache' != mode and (seeders < self.minseed or leechers < self.minleech): + continue - # Filter unseeded torrent - if 'RSS' != mode and (self.minseed > seeders or self.minleech > leechers): - continue + info = tr.find('a', title=rc['info']) + title = info.get_text().strip().replace('_', '.') + tid = rc['tid'].sub(r'\1', str(info['href'])) - # Accept Torrent only from Good People for every Episode Search - if self.confirmed and re.search('(VIP|Trusted|Helper|Moderator)', torrent.group(0)) is None: - logger.log(u'ThePirateBay Provider found result ' + torrent.group( - 'title') + ' but that doesn\'t seem like a trusted result so I\'m ignoring it', logger.DEBUG) - continue + download_magnet = tr.find('a', title=rc['get'])['href'] + except (AttributeError, TypeError): + continue - # 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(allPossibleShowNames(self.show)))) - title = self._find_season_quality(title, id, ep_number) + if self.confirmed and not tr.find('img', title=rc['verify']): + logger.log(u'Skipping untrusted non-verified result: ' + title, logger.DEBUG) + continue - if not title or not url: - continue + # 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, tid, ep_number) - item = title, url, id, seeders, leechers + if title and download_magnet: + items[mode].append((title, download_magnet, seeders)) - items[mode].append(item) + except generic.HaltParseException: + pass + except Exception: + logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR) + self._log_result(mode, len(items[mode]) - cnt, log_url) # For each search mode sort all the items by seeders - items[mode].sort(key=lambda tup: tup[3], reverse=True) + items[mode].sort(key=lambda tup: tup[2], reverse=True) 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['base_url']), logger.ERROR) + 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 - def _get_title_and_url(self, item): - - title, url, id, seeders, leechers = item - - if title: - title += u'' - title = re.sub(r'\s+', '.', title) - - if url: - url = url.replace('&', '&') - - return title, url - def findPropers(self, search_date=datetime.datetime.today()): - results = [] - - myDB = db.DBConnection() - sqlResults = myDB.select( - 'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e' + - ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)' + - ' WHERE e.airdate >= ' + str(search_date.toordinal()) + - ' AND (e.status IN (' + ','.join([str(x) for x in Quality.DOWNLOADED]) + ')' + - ' OR (e.status IN (' + ','.join([str(x) for x in Quality.SNATCHED]) + ')))' - ) - - if not sqlResults: - return results - - for sqlshow in sqlResults: - self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow['showid'])) - - if self.show: - curEp = self.show.getEpisode(int(sqlshow['season']), int(sqlshow['episode'])) - - searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') - - for item in self._doSearch(searchString[0]): - title, url = self._get_title_and_url(item) - results.append(classes.Proper(title, url, datetime.datetime.today(), self.show)) - - return results - - def seedRatio(self): - return self.ratio + return self._find_propers(search_date, '') class ThePirateBayCache(tvcache.TVCache): - def __init__(self, provider): - tvcache.TVCache.__init__(self, provider) + def __init__(self, this_provider): + tvcache.TVCache.__init__(self, this_provider) - # only poll ThePirateBay every 10 minutes max - self.minTime = 20 + self.minTime = 20 # cache update frequency def _getRSSData(self): - search_params = {'RSS': ['rss']} - return self.provider._doSearch(search_params) - -class ThePirateBayWebproxy: - def __init__(self): - self.Type = 'GlypeProxy' - self.param = 'browse.php?u=' - self.option = '&b=32' - self.enabled = False - self.url = None - - self.urls = { - 'Getprivate.eu (NL)': 'http://getprivate.eu/', - 'Hideme.nl (NL)': 'http://hideme.nl/', - 'Hiload.org (NL)': 'http://hiload.org/', - 'Hiload.org (NL) SSL': 'https://hiload.org/', - 'Interproxy.net (EU)': 'http://interproxy.net/', - 'Interproxy.net (EU) SSL': 'https://interproxy.net/', - 'Proxite.eu (DE)': 'http://proxite.eu/', - 'Proxite.eu (DE) SSL ': 'https://proxite.eu/', - } - - def isEnabled(self): - """ Return True if we Choose to call TPB via Proxy """ - return self.enabled - - def getProxyURL(self): - """ Return the Proxy URL Choosen via Provider Setting """ - return str(self.url) - - def _buildURL(self, url): - """ Return the Proxyfied URL of the page """ - if self.isEnabled(): - url = self.getProxyURL() + self.param + url + self.option - - return url - - def _buildRE(self, regx): - """ Return the Proxyfied RE string """ - if self.isEnabled(): - regx = re.sub('//1', self.option, regx).replace('&', '&') - else: - regx = re.sub('//1', '', regx) - - return regx + return self.provider.get_cache_data() provider = ThePirateBayProvider()