diff --git a/couchpotato/core/downloaders/utorrent.py b/couchpotato/core/downloaders/utorrent.py index 2bfc64e..264e496 100644 --- a/couchpotato/core/downloaders/utorrent.py +++ b/couchpotato/core/downloaders/utorrent.py @@ -176,7 +176,7 @@ class uTorrent(DownloaderBase): status = 'busy' if (torrent[1] & self.status_flags['STARTED'] or torrent[1] & self.status_flags['QUEUED']) and torrent[4] == 1000: status = 'seeding' - elif torrent[1] & self.status_flags['ERROR']: + elif torrent[1] & self.status_flags['ERROR'] and 'There is not enough space on the disk' not in torrent[21]: status = 'failed' elif torrent[4] == 1000: status = 'completed' diff --git a/couchpotato/core/media/_base/providers/torrent/torrentday.py b/couchpotato/core/media/_base/providers/torrent/torrentday.py index 2d27d24..aecb682 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentday.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentday.py @@ -9,12 +9,12 @@ log = CPLog(__name__) class Base(TorrentProvider): urls = { - 'test': 'https://classic.torrentday.com/', - 'login': 'https://classic.torrentday.com/torrents/', - 'login_check': 'https://classic.torrentday.com/userdetails.php', - 'detail': 'https://classic.torrentday.com/details.php?id=%s', - 'search': 'https://classic.torrentday.com/V3/API/API.php', - 'download': 'https://classic.torrentday.com/download.php/%s/%s', + 'test': 'https://www.torrentday.com/', + 'login': 'https://www.torrentday.com/torrents/', + 'login_check': 'https://www.torrentday.com/userdetails.php', + 'detail': 'https://www.torrentday.com/details.php?id=%s', + 'search': 'https://www.torrentday.com/V3/API/API.php', + 'download': 'https://www.torrentday.com/download.php/%s/%s', } http_time_between_calls = 1 # Seconds @@ -86,7 +86,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'TorrentDay', - 'description': 'TorrentDay', + 'description': 'TorrentDay', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAC5ElEQVQ4y12TXUgUURTH//fO7Di7foeQJH6gEEEIZZllVohfSG/6UA+RSFAQQj74VA8+Bj30lmAlRVSEvZRfhNhaka5ZUG1paKaW39tq5O6Ou+PM3M4o6m6X+XPPzD3zm/+dcy574r515WfIW8CZBM4YAA5Gc/aQC3yd7oXYEONcsISE5dTDh91HS0t7FEWhBUAeN9ynV/d9qJAgE4AECURAcVsGlCCnly26LMA0IQwTa52dje3d3e3hcPi8qqrrMjcVYI3EHCQZlkFOHBwR2QHh2ASAAIJxWGAQEDxjePhs3527XjJwnb37OHBq0T+Tyyjh+9KnEzNJ7nouc1Q/3A3HGsOvnJy+PSUlj81w2Lny9WuJ6+3AmTjD4HOcrdR2dWXLRQePvyaSLfQOPMPC8mC9iHCsOxSyzJCelzdSXlNzD5ujpb25Wbfc/XXJemTXF4+nnCNq+AMLe50uFfEJTiw4GXSFtiHL0SnIq66+p0kSArqO+eH3RdsAv9+f5vW7L7GICq6rmM8XBCAXlBw90rOyxibn5yzfkg/L09M52/jxqdESaIrBXHYZZbB1GX8cEpySxKIB8S5XcOnvqpli1zuwmrTtoLjw5LOK/eeuWsE4JH5IRPaPZKiKigmPp+5pa+u1aEjIMhEgrRkmi9mgxGUhM7LNJSzOzsE3+cOeExovXOjdytE0LV4zqNZUtV0uZzAGoGkhDH/2YHZiErmv4uyWQnZZWc+hoqL3WzlTExN5hhA8IEwkZWZOxwB++30YG/9GkYCPvqAaHAW5uWPROW86OmqCprUR7z1yZDAGQNuCvkoB/baIKUBWMTYymv+gra3eJNvjXu+B562tFyXqTJ6YuHK8rKwvBmC3vR7cOCPQLWFz8LnfXWUrJo9U19BwMyUlJRjTSMJ2ENxUiGxq9KXQfwqYlnWstvbR5aamG9g0uzM8Q4OFt++3NNixQ2NgYmeN03FOTUv7XVpV9aKisvLl1vN/WVhNc/Fi1NEAAAAASUVORK5CYII=', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/yts.py b/couchpotato/core/media/_base/providers/torrent/yts.py index f4567a9..188f9e5 100644 --- a/couchpotato/core/media/_base/providers/torrent/yts.py +++ b/couchpotato/core/media/_base/providers/torrent/yts.py @@ -1,7 +1,6 @@ from datetime import datetime -from couchpotato.core.helpers.variable import tryInt +from couchpotato.core.helpers.variable import tryInt, getIdentifier from couchpotato.core.logger import CPLog -from couchpotato.core.helpers.variable import getTitle from couchpotato.core.media._base.providers.torrent.base import TorrentMagnetProvider import random @@ -19,7 +18,7 @@ class Base(TorrentMagnetProvider): def _search(self, movie, quality, results): limit = 10 page = 1 - data = self.getJsonData(self.urls['search'] % (getTitle(movie), limit, page)) + data = self.getJsonData(self.urls['search'] % (getIdentifier(movie), limit, page)) if data: movie_count = tryInt(data['data']['movie_count']) @@ -32,37 +31,32 @@ class Base(TorrentMagnetProvider): for i in range(0,len(movie_results)): result = data['data']['movies'][i] name = result['title'] - - t = movie['info']['original_title'].split(' ') - - if all(word in name for word in t) and movie['info']['year'] == result['year']: - - year = result['year'] - detail_url = result['url'] - - for torrent in result['torrents']: - t_quality = torrent['quality'] - - if t_quality in quality['label']: - hash = torrent['hash'] - size = tryInt(torrent['size_bytes'] / 1048576) - seeders = tryInt(torrent['seeds']) - leechers = tryInt(torrent['peers']) - pubdate = torrent['date_uploaded'] # format: 2017-02-17 18:40:03 - pubdate = datetime.strptime(pubdate, '%Y-%m-%d %H:%M:%S') - age = (datetime.now() - pubdate).days - - results.append({ - 'id': random.randint(100, 9999), - 'name': '%s (%s) %s %s %s' % (name, year, 'YTS', t_quality, 'BR-Rip'), - 'url': self.make_magnet(hash, name), - 'size': size, - 'seeders': seeders, - 'leechers': leechers, - 'age': age, - 'detail_url': detail_url, - 'score': 1 - }) + year = result['year'] + detail_url = result['url'] + + for torrent in result['torrents']: + t_quality = torrent['quality'] + + if t_quality in quality['label']: + hash = torrent['hash'] + size = tryInt(torrent['size_bytes'] / 1048576) + seeders = tryInt(torrent['seeds']) + leechers = tryInt(torrent['peers']) + pubdate = torrent['date_uploaded'] # format: 2017-02-17 18:40:03 + pubdate = datetime.strptime(pubdate, '%Y-%m-%d %H:%M:%S') + age = (datetime.now() - pubdate).days + + results.append({ + 'id': random.randint(100, 9999), + 'name': '%s (%s) %s %s %s' % (name, year, 'YTS', t_quality, 'BR-Rip'), + 'url': self.make_magnet(hash, name), + 'size': size, + 'seeders': seeders, + 'leechers': leechers, + 'age': age, + 'detail_url': detail_url, + 'score': 1 + }) return diff --git a/couchpotato/core/media/movie/providers/automation/kinepolis.py b/couchpotato/core/media/movie/providers/automation/kinepolis.py deleted file mode 100644 index a0f2596..0000000 --- a/couchpotato/core/media/movie/providers/automation/kinepolis.py +++ /dev/null @@ -1,54 +0,0 @@ -import datetime - -from couchpotato.core.helpers.rss import RSS -from couchpotato.core.logger import CPLog -from couchpotato.core.media.movie.providers.automation.base import Automation - - -log = CPLog(__name__) - -autoload = 'Kinepolis' - - -class Kinepolis(Automation, RSS): - - interval = 1800 - rss_url = 'http://kinepolis.be/nl/top10-box-office/feed' - - def getIMDBids(self): - - movies = [] - - rss_movies = self.getRSSData(self.rss_url) - - for movie in rss_movies: - name = self.getTextElement(movie, 'title') - year = datetime.datetime.now().strftime('%Y') - - imdb = self.search(name, year) - - if imdb and self.isMinimalMovie(imdb): - movies.append(imdb['imdb']) - - return movies - - -config = [{ - 'name': 'kinepolis', - 'groups': [ - { - 'tab': 'automation', - 'list': 'automation_providers', - 'name': 'kinepolis_automation', - 'label': 'Kinepolis', - 'description': 'Imports movies from the current top 10 of kinepolis.', - 'options': [ - { - 'name': 'automation_enabled', - 'default': False, - 'type': 'enabler', - }, - ], - }, - ], -}] diff --git a/couchpotato/core/media/movie/providers/automation/moviemeter.py b/couchpotato/core/media/movie/providers/automation/moviemeter.py deleted file mode 100644 index 624ffb6..0000000 --- a/couchpotato/core/media/movie/providers/automation/moviemeter.py +++ /dev/null @@ -1,48 +0,0 @@ -from couchpotato.core.helpers.rss import RSS -from couchpotato.core.logger import CPLog -from couchpotato.core.media.movie.providers.automation.base import Automation - -log = CPLog(__name__) - -autoload = 'Moviemeter' - - -class Moviemeter(Automation, RSS): - - interval = 1800 - rss_url = 'http://www.moviemeter.nl/rss/cinema' - - def getIMDBids(self): - - movies = [] - - rss_movies = self.getRSSData(self.rss_url) - - for movie in rss_movies: - imdb = self.search(self.getTextElement(movie, 'title')) - - if imdb and self.isMinimalMovie(imdb): - movies.append(imdb['imdb']) - - return movies - - -config = [{ - 'name': 'moviemeter', - 'groups': [ - { - 'tab': 'automation', - 'list': 'automation_providers', - 'name': 'moviemeter_automation', - 'label': 'Moviemeter', - 'description': 'Imports movies from the current top 10 of moviemeter.nl.', - 'options': [ - { - 'name': 'automation_enabled', - 'default': False, - 'type': 'enabler', - }, - ], - }, - ], -}] diff --git a/couchpotato/core/media/movie/providers/automation/movies_io.py b/couchpotato/core/media/movie/providers/automation/movies_io.py deleted file mode 100644 index 3930906..0000000 --- a/couchpotato/core/media/movie/providers/automation/movies_io.py +++ /dev/null @@ -1,72 +0,0 @@ -from couchpotato.core.event import fireEvent -from couchpotato.core.helpers.rss import RSS -from couchpotato.core.helpers.variable import tryInt, splitString -from couchpotato.core.logger import CPLog -from couchpotato.core.media.movie.providers.automation.base import Automation - -log = CPLog(__name__) - -autoload = 'MoviesIO' - - -class MoviesIO(Automation, RSS): - - interval = 1800 - - def getIMDBids(self): - - movies = [] - - enablers = [tryInt(x) for x in splitString(self.conf('automation_urls_use'))] - - index = -1 - for rss_url in splitString(self.conf('automation_urls')): - - index += 1 - if not enablers[index]: - continue - - rss_movies = self.getRSSData(rss_url, headers = {'Referer': ''}) - - for movie in rss_movies: - - nameyear = fireEvent('scanner.name_year', self.getTextElement(movie, 'title'), single = True) - imdb = self.search(nameyear.get('name'), nameyear.get('year'), imdb_only = True) - - if not imdb: - continue - - movies.append(imdb) - - return movies - - -config = [{ - 'name': 'moviesio', - 'groups': [ - { - 'tab': 'automation', - 'list': 'watchlist_providers', - 'name': 'moviesio', - 'label': 'Movies.IO', - 'description': 'Imports movies from Movies.io RSS watchlists', - 'options': [ - { - 'name': 'automation_enabled', - 'default': False, - 'type': 'enabler', - }, - { - 'name': 'automation_urls_use', - 'label': 'Use', - }, - { - 'name': 'automation_urls', - 'label': 'url', - 'type': 'combined', - 'combine': ['automation_urls_use', 'automation_urls'], - }, - ], - }, - ], -}] diff --git a/couchpotato/core/media/movie/providers/info/omdbapi.py b/couchpotato/core/media/movie/providers/info/omdbapi.py index 3f257c6..e72762f 100644 --- a/couchpotato/core/media/movie/providers/info/omdbapi.py +++ b/couchpotato/core/media/movie/providers/info/omdbapi.py @@ -18,8 +18,8 @@ autoload = 'OMDBAPI' class OMDBAPI(MovieProvider): urls = { - 'search': 'http://www.omdbapi.com/?type=movie&%s', - 'info': 'http://www.omdbapi.com/?type=movie&i=%s', + 'search': 'https://www.omdbapi.com/?apikey=%s&type=movie&%s', + 'info': 'https://www.omdbapi.com/?apikey=%s&type=movie&i=%s', } http_time_between_calls = 0 @@ -30,6 +30,8 @@ class OMDBAPI(MovieProvider): addEvent('movie.info', self.getInfo) def search(self, q, limit = 12): + if self.isDisabled(): + return [] name_year = fireEvent('scanner.name_year', q, single = True) @@ -39,7 +41,7 @@ class OMDBAPI(MovieProvider): } cache_key = 'omdbapi.cache.%s' % q - url = self.urls['search'] % tryUrlencode({'t': name_year.get('name'), 'y': name_year.get('year', '')}) + url = self.urls['search'] % (self.getApiKey(), tryUrlencode({'t': name_year.get('name'), 'y': name_year.get('year', '')})) cached = self.getCache(cache_key, url, timeout = 3, headers = {'User-Agent': Env.getIdentifier()}) if cached: @@ -53,12 +55,12 @@ class OMDBAPI(MovieProvider): return [] def getInfo(self, identifier = None, **kwargs): - - if not identifier: + if self.isDisabled() or not identifier: return {} cache_key = 'omdbapi.cache.%s' % identifier - cached = self.getCache(cache_key, self.urls['info'] % identifier, timeout = 3, headers = {'User-Agent': Env.getIdentifier()}) + url = self.urls['info'] % (self.getApiKey(), identifier) + cached = self.getCache(cache_key, url, timeout = 3, headers = {'User-Agent': Env.getIdentifier()}) if cached: result = self.parseMovie(cached) @@ -89,7 +91,7 @@ class OMDBAPI(MovieProvider): tmp_movie = movie.copy() for key in tmp_movie: tmp_movie_elem = tmp_movie.get(key) - if not isinstance(tmp_movie_elem, str) or tmp_movie_elem.lower() == 'n/a': + if not isinstance(tmp_movie_elem, (str, unicode)) or tmp_movie_elem.lower() == 'n/a': del movie[key] year = tryInt(movie.get('Year', '')) @@ -123,6 +125,16 @@ class OMDBAPI(MovieProvider): return movie_data + def isDisabled(self): + if self.getApiKey() == '': + log.error('No API key provided.') + return True + return False + + def getApiKey(self): + apikey = self.conf('api_key') + return apikey + def runtimeToMinutes(self, runtime_str): runtime = 0 @@ -133,3 +145,24 @@ class OMDBAPI(MovieProvider): runtime += tryInt(nr) * (60 if 'h' is str(size)[0] else 1) return runtime + + +config = [{ + 'name': 'omdbapi', + 'groups': [ + { + 'tab': 'providers', + 'name': 'tmdb', + 'label': 'OMDB API', + 'hidden': True, + 'description': 'Used for all calls to TheMovieDB.', + 'options': [ + { + 'name': 'api_key', + 'default': 'bbc0e412', # Don't be a dick and use this somewhere else + 'label': 'Api Key', + }, + ], + }, + ], +}] diff --git a/couchpotato/core/media/movie/providers/userscript/filmstarts.py b/couchpotato/core/media/movie/providers/userscript/filmstarts.py index 4e61f29..5201ce0 100644 --- a/couchpotato/core/media/movie/providers/userscript/filmstarts.py +++ b/couchpotato/core/media/movie/providers/userscript/filmstarts.py @@ -1,5 +1,6 @@ from bs4 import BeautifulSoup from couchpotato.core.media._base.providers.userscript.base import UserscriptBase +import re autoload = 'Filmstarts' @@ -15,16 +16,16 @@ class Filmstarts(UserscriptBase): return html = BeautifulSoup(data) - table = html.find("table", attrs={"class": "table table-standard thead-standard table-striped_2 fs11"}) + table = html.find("section", attrs={"class": "section ovw ovw-synopsis", "id": "synopsis-details"}) - if table.find(text='Originaltitel'): + if table.find(text=re.compile('Originaltitel')): #some trailing whitespaces on some pages # Get original film title from the table specified above - name = table.find("div", text="Originaltitel").parent.parent.parent.td.text + name = name = table.find("span", text=re.compile("Originaltitel")).findNext('h2').text else: # If none is available get the title from the meta data name = html.find("meta", {"property":"og:title"})['content'] # Year of production is not available in the meta data, so get it from the table - year = table.find(text="Produktionsjahr").parent.parent.next_sibling.text + year = table.find("span", text=re.compile("Produktionsjahr")).findNext('span').text return self.search(name, year) diff --git a/couchpotato/core/notifications/script.py b/couchpotato/core/notifications/script.py index 9d8f753..1736c33 100644 --- a/couchpotato/core/notifications/script.py +++ b/couchpotato/core/notifications/script.py @@ -1,38 +1,48 @@ import traceback import subprocess +import os from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.variable import getIdentifier +from couchpotato.api import addApiView +from couchpotato.core.event import addEvent from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification + + log = CPLog(__name__) autoload = 'Script' class Script(Notification): - def notify(self, message = '', data = None, listener = None): - if not data: data = {} + def __init__(self): + addApiView(self.testNotifyName(), self.test) - script_data = { - 'message': toUnicode(message) - } + addEvent('renamer.after', self.runScript) - if getIdentifier(data): - script_data.update({ - 'imdb_id': getIdentifier(data) - }) + def runScript(self, message = None, group = None): + if self.isDisabled(): return + if not group: group = {} + command = [self.conf('path'), group.get('destination_dir')] + log.info('Executing script command: %s ', command) try: - subprocess.call([self.conf('path'), message]) + p = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.STDOUT) + out = p.communicate() + log.info('Result from script: %s', str(out)) return True - except: - log.error('Script notification failed: %s', traceback.format_exc()) + except OSError as e: + log.error('Unable to run script: %s', e) return False + def test(self, **kwargs): + return { + 'success': os.path.isfile(self.conf('path')) + } config = [{ 'name': 'script', diff --git a/couchpotato/core/plugins/log/static/log.js b/couchpotato/core/plugins/log/static/log.js index a0b1f7c..997ec87 100644 --- a/couchpotato/core/plugins/log/static/log.js +++ b/couchpotato/core/plugins/log/static/log.js @@ -250,7 +250,7 @@ Page.Log = new Class({ new Element('a.button', { 'target': '_blank', 'text': 'the contributing guide', - 'href': 'https://github.com/CouchPotato/CouchPotatoServer/blob/develop/contributing.md' + 'href': 'https://github.com/CouchPotato/CouchPotatoServer/wiki/Developer-branch' }), new Element('span', { 'html': ' before posting, then copy the text below and FILL IN the dots.' diff --git a/couchpotato/core/plugins/subtitle.py b/couchpotato/core/plugins/subtitle.py index 135ec2d..110fe11 100644 --- a/couchpotato/core/plugins/subtitle.py +++ b/couchpotato/core/plugins/subtitle.py @@ -16,7 +16,7 @@ autoload = 'Subtitle' class Subtitle(Plugin): - services = ['opensubtitles', 'thesubdb', 'subswiki', 'subscenter'] + services = ['opensubtitles', 'thesubdb', 'subswiki', 'subscenter', 'wizdom'] def __init__(self): addEvent('renamer.before', self.searchSingle) diff --git a/couchpotato/static/scripts/combined.plugins.min.js b/couchpotato/static/scripts/combined.plugins.min.js index 475c053..b93d282 100644 --- a/couchpotato/static/scripts/combined.plugins.min.js +++ b/couchpotato/static/scripts/combined.plugins.min.js @@ -3093,7 +3093,7 @@ Page.Log = new Class({ }), new Element("a.button", { target: "_blank", text: "the contributing guide", - href: "https://github.com/CouchPotato/CouchPotatoServer/blob/develop/contributing.md" + href: "https://github.com/CouchPotato/CouchPotatoServer/wiki/Developer-branch" }), new Element("span", { html: " before posting, then copy the text below and FILL IN the dots." })), textarea = new Element("textarea", { diff --git a/libs/rtorrent/__init__.py b/libs/rtorrent/__init__.py index 0d64e81..f6980bd 100644 --- a/libs/rtorrent/__init__.py +++ b/libs/rtorrent/__init__.py @@ -74,7 +74,9 @@ class RTorrent: if m.is_retriever() and m.is_available(self)] m = rtorrent.rpc.Multicall(self) - m.add("d.multicall", view, "d.get_hash=", + # multicall2 wants .. something .. as its first argument. It accepts a blank string, so let's go with that. + MCFirstArg = "" + m.add("d.multicall2", MCFirstArg, view, "d.hash=", *[method.rpc_call + "=" for method in retriever_methods]) results = m.call()[0] # only sent one call, only need first result @@ -116,7 +118,7 @@ class RTorrent: elif verbose: func_name = "load.verbose" else: - func_name = "load" + func_name = "load.normal" elif file_type in ["file", "raw"]: if start and verbose: func_name = "load.raw_start_verbose" @@ -137,31 +139,49 @@ class RTorrent: func_name = self._get_load_function("url", start, verbose) + # rtorrent > 0.9.6 requires first parameter @target + target = "" # load magnet - getattr(p, func_name)(magneturl) + getattr(p, func_name)(target, magneturl) if verify_load: + magnet = False i = 0 while i < verify_retries: - for torrent in self.get_torrents(): - if torrent.info_hash != info_hash: - continue + for m in self.get_torrents(): + # This block finds the magnet that was just added, starts it, breaks + # out of the for loop, and then out of the while loop. + # If it can't find the magnet, magnet won't get defined. + if m.info_hash == info_hash: + magnet = m + magnet.start() + i += 999 + break + + # If torrent hasn't been defined, sleep for a second and check again. + if not magnet: time.sleep(1) i += 1 - # Resolve magnet to torrent - torrent.start() + # This bit waits for the magnet to be resolved into an actual + # torrent, and then starts it. + torrent = False + i = 0 + while i < verify_retries: + for t in self.get_torrents(): + if t.info_hash == info_hash: + if str(info_hash) not in str(t.name): + torrent = t + torrent.start() + i += 999 + break + if not torrent: + time.sleep(1) + i += 1 assert info_hash in [t.info_hash for t in self.torrents],\ "Adding magnet was unsuccessful." - i = 0 - while i < verify_retries: - for torrent in self.get_torrents(): - if torrent.info_hash == info_hash: - if str(info_hash) not in str(torrent.name): - time.sleep(1) - i += 1 return(torrent) diff --git a/libs/rtorrent/file.py b/libs/rtorrent/file.py index a3db35c..758ed76 100755 --- a/libs/rtorrent/file.py +++ b/libs/rtorrent/file.py @@ -59,29 +59,29 @@ class File: methods = [ # RETRIEVERS - Method(File, 'get_last_touched', 'f.get_last_touched'), - Method(File, 'get_range_second', 'f.get_range_second'), - Method(File, 'get_size_bytes', 'f.get_size_bytes'), - Method(File, 'get_priority', 'f.get_priority'), - Method(File, 'get_match_depth_next', 'f.get_match_depth_next'), + Method(File, 'get_last_touched', 'f.last_touched'), + Method(File, 'get_range_second', 'f.range_second'), + Method(File, 'get_size_bytes', 'f.size_bytes'), + Method(File, 'get_priority', 'f.priority'), + Method(File, 'get_match_depth_next', 'f.match_depth_next'), Method(File, 'is_resize_queued', 'f.is_resize_queued', boolean=True, ), - Method(File, 'get_range_first', 'f.get_range_first'), - Method(File, 'get_match_depth_prev', 'f.get_match_depth_prev'), - Method(File, 'get_path', 'f.get_path'), - Method(File, 'get_completed_chunks', 'f.get_completed_chunks'), - Method(File, 'get_path_components', 'f.get_path_components'), + Method(File, 'get_range_first', 'f.range_first'), + Method(File, 'get_match_depth_prev', 'f.match_depth_prev'), + Method(File, 'get_path', 'f.path'), + Method(File, 'get_completed_chunks', 'f.completed_chunks'), + Method(File, 'get_path_components', 'f.path_components'), Method(File, 'is_created', 'f.is_created', boolean=True, ), Method(File, 'is_open', 'f.is_open', boolean=True, ), - Method(File, 'get_size_chunks', 'f.get_size_chunks'), - Method(File, 'get_offset', 'f.get_offset'), - Method(File, 'get_frozen_path', 'f.get_frozen_path'), - Method(File, 'get_path_depth', 'f.get_path_depth'), + Method(File, 'get_size_chunks', 'f.size_chunks'), + Method(File, 'get_offset', 'f.offset'), + Method(File, 'get_frozen_path', 'f.frozen_path'), + Method(File, 'get_path_depth', 'f.path_depth'), Method(File, 'is_create_queued', 'f.is_create_queued', boolean=True, ), diff --git a/libs/rtorrent/peer.py b/libs/rtorrent/peer.py index 61ca094..f998812 100755 --- a/libs/rtorrent/peer.py +++ b/libs/rtorrent/peer.py @@ -60,39 +60,39 @@ methods = [ Method(Peer, 'is_preferred', 'p.is_preferred', boolean=True, ), - Method(Peer, 'get_down_rate', 'p.get_down_rate'), + Method(Peer, 'get_down_rate', 'p.down_rate'), Method(Peer, 'is_unwanted', 'p.is_unwanted', boolean=True, ), - Method(Peer, 'get_peer_total', 'p.get_peer_total'), - Method(Peer, 'get_peer_rate', 'p.get_peer_rate'), - Method(Peer, 'get_port', 'p.get_port'), + Method(Peer, 'get_peer_total', 'p.peer_total'), + Method(Peer, 'get_peer_rate', 'p.peer_rate'), + Method(Peer, 'get_port', 'p.port'), Method(Peer, 'is_snubbed', 'p.is_snubbed', boolean=True, ), - Method(Peer, 'get_id_html', 'p.get_id_html'), - Method(Peer, 'get_up_rate', 'p.get_up_rate'), + Method(Peer, 'get_id_html', 'p.id_html'), + Method(Peer, 'get_up_rate', 'p.up_rate'), Method(Peer, 'is_banned', 'p.banned', boolean=True, ), - Method(Peer, 'get_completed_percent', 'p.get_completed_percent'), + Method(Peer, 'get_completed_percent', 'p.completed_percent'), Method(Peer, 'completed_percent', 'p.completed_percent'), - Method(Peer, 'get_id', 'p.get_id'), + Method(Peer, 'get_id', 'p.id'), Method(Peer, 'is_obfuscated', 'p.is_obfuscated', boolean=True, ), - Method(Peer, 'get_down_total', 'p.get_down_total'), - Method(Peer, 'get_client_version', 'p.get_client_version'), - Method(Peer, 'get_address', 'p.get_address'), + Method(Peer, 'get.down.total', 'p.down_total'), + Method(Peer, 'get_client_version', 'p.client_version'), + Method(Peer, 'get_address', 'p.address'), Method(Peer, 'is_incoming', 'p.is_incoming', boolean=True, ), Method(Peer, 'is_encrypted', 'p.is_encrypted', boolean=True, ), - Method(Peer, 'get_options_str', 'p.get_options_str'), + Method(Peer, 'get_options_str', 'p.options_str'), Method(Peer, 'get_client_version', 'p.client_version'), - Method(Peer, 'get_up_total', 'p.get_up_total'), + Method(Peer, 'get_up_total', 'p.up_total'), # MODIFIERS ] diff --git a/libs/rtorrent/rpc/__init__.py b/libs/rtorrent/rpc/__init__.py index 607d409..e294a72 100755 --- a/libs/rtorrent/rpc/__init__.py +++ b/libs/rtorrent/rpc/__init__.py @@ -38,13 +38,13 @@ def get_varname(rpc_call): r = re.search( "([ptdf]\.|system\.|get\_|is\_|set\_)+([^=]*)", rpc_call, re.I) if r: - return(r.groups()[-1]) + return(r.groups()[-1].replace(".","_")) else: return(None) def _handle_unavailable_rpc_method(method, rt_obj): - msg = "Method isn't available." + msg = "Method " + str(method) + " isn't available." if rt_obj.connection._get_client_version_tuple() < method.min_version: msg = "This method is only available in " \ "RTorrent version v{0} or later".format( @@ -91,7 +91,7 @@ class Method: def _get_method_type(self): """Determine whether method is a modifier or a retriever""" - if self.method_name[:4] == "set_": return('m') # modifier + if self.method_name[:4] == "set_" or self.method_name[-4:] == ".set": return('m') # modifier else: return('r') # retriever diff --git a/libs/rtorrent/torrent.py b/libs/rtorrent/torrent.py index bd6bb68..f4f1406 100755 --- a/libs/rtorrent/torrent.py +++ b/libs/rtorrent/torrent.py @@ -139,7 +139,7 @@ class Torrent: results = m.call()[0] # only sent one call, only need first result offset_method_index = retriever_methods.index( - rtorrent.rpc.find_method("f.get_offset")) + rtorrent.rpc.find_method("f.offset")) # make a list of the offsets of all the files, sort appropriately offset_list = sorted([r[offset_method_index] for r in results]) @@ -168,7 +168,7 @@ class Torrent: """ m = rtorrent.rpc.Multicall(self) self.multicall_add(m, "d.try_stop") - self.multicall_add(m, "d.set_directory", d) + self.multicall_add(m, "d.directory.set", d) self.directory = m.call()[-1] @@ -181,7 +181,7 @@ class Torrent: """ m = rtorrent.rpc.Multicall(self) self.multicall_add(m, "d.try_stop") - self.multicall_add(m, "d.set_directory_base", d) + self.multicall_add(m, "d.directory_base.set", d) def start(self): """Start the torrent""" @@ -304,7 +304,7 @@ class Torrent: m = rtorrent.rpc.Multicall(self) field = "custom{0}".format(key) - self.multicall_add(m, "d.get_{0}".format(field)) + self.multicall_add(m, "d.{0}".format(field)) setattr(self, field, m.call()[-1]) return (getattr(self, field)) @@ -326,7 +326,7 @@ class Torrent: self._assert_custom_key_valid(key) m = rtorrent.rpc.Multicall(self) - self.multicall_add(m, "d.set_custom{0}".format(key), value) + self.multicall_add(m, "d.custom{0}.set".format(key), value) return(m.call()[-1]) @@ -355,7 +355,7 @@ class Torrent: @note: Variable where the result for this method is stored Torrent.hash_checking_queued""" m = rtorrent.rpc.Multicall(self) - self.multicall_add(m, "d.get_hashing") + self.multicall_add(m, "d.hashing") self.multicall_add(m, "d.is_hash_checking") results = m.call() @@ -397,86 +397,86 @@ methods = [ Method(Torrent, 'is_hash_checking', 'd.is_hash_checking', boolean=True, ), - Method(Torrent, 'get_peers_max', 'd.get_peers_max'), - Method(Torrent, 'get_tracker_focus', 'd.get_tracker_focus'), - Method(Torrent, 'get_skip_total', 'd.get_skip_total'), - Method(Torrent, 'get_state', 'd.get_state'), - Method(Torrent, 'get_peer_exchange', 'd.get_peer_exchange'), - Method(Torrent, 'get_down_rate', 'd.get_down_rate'), - Method(Torrent, 'get_connection_seed', 'd.get_connection_seed'), - Method(Torrent, 'get_uploads_max', 'd.get_uploads_max'), - Method(Torrent, 'get_priority_str', 'd.get_priority_str'), + Method(Torrent, 'get_peers_max', 'd.peers_max'), + Method(Torrent, 'get_tracker_focus', 'd.tracker_focus'), + Method(Torrent, 'get_skip_total', 'd.skip.total'), + Method(Torrent, 'get_state', 'd.state'), + Method(Torrent, 'get_peer_exchange', 'd.peer_exchange'), + Method(Torrent, 'get_down_rate', 'd.down.rate'), + Method(Torrent, 'get_connection_seed', 'd.connection_seed'), + Method(Torrent, 'get_uploads_max', 'd.uploads_max'), + Method(Torrent, 'get_priority_str', 'd.priority_str'), Method(Torrent, 'is_open', 'd.is_open', boolean=True, ), - Method(Torrent, 'get_peers_min', 'd.get_peers_min'), - Method(Torrent, 'get_peers_complete', 'd.get_peers_complete'), - Method(Torrent, 'get_tracker_numwant', 'd.get_tracker_numwant'), - Method(Torrent, 'get_connection_current', 'd.get_connection_current'), - Method(Torrent, 'is_complete', 'd.get_complete', + Method(Torrent, 'get_peers_min', 'd.peers_min'), + Method(Torrent, 'get_peers_complete', 'd.peers_complete'), + Method(Torrent, 'get_tracker_numwant', 'd.tracker_numwant'), + Method(Torrent, 'get_connection_current', 'd.connection_current'), + Method(Torrent, 'is_complete', 'd.complete', boolean=True, ), - Method(Torrent, 'get_peers_connected', 'd.get_peers_connected'), - Method(Torrent, 'get_chunk_size', 'd.get_chunk_size'), - Method(Torrent, 'get_state_counter', 'd.get_state_counter'), - Method(Torrent, 'get_base_filename', 'd.get_base_filename'), - Method(Torrent, 'get_state_changed', 'd.get_state_changed'), - Method(Torrent, 'get_peers_not_connected', 'd.get_peers_not_connected'), - Method(Torrent, 'get_directory', 'd.get_directory'), + Method(Torrent, 'get_peers_connected', 'd.peers_connected'), + Method(Torrent, 'get_chunk_size', 'd.chunk_size'), + Method(Torrent, 'get_state_counter', 'd.state_counter'), + Method(Torrent, 'get_base_filename', 'd.base_filename'), + Method(Torrent, 'get_state_changed', 'd.state_changed'), + Method(Torrent, 'get_peers_not_connected', 'd.peers_not_connected'), + Method(Torrent, 'get_directory', 'd.directory'), Method(Torrent, 'is_incomplete', 'd.incomplete', boolean=True, ), - Method(Torrent, 'get_tracker_size', 'd.get_tracker_size'), + Method(Torrent, 'get_tracker_size', 'd.tracker_size'), Method(Torrent, 'is_multi_file', 'd.is_multi_file', boolean=True, ), - Method(Torrent, 'get_local_id', 'd.get_local_id'), - Method(Torrent, 'get_ratio', 'd.get_ratio', + Method(Torrent, 'get_local_id', 'd.local_id'), + Method(Torrent, 'get_ratio', 'd.ratio', post_process_func=lambda x: x / 1000.0, ), - Method(Torrent, 'get_loaded_file', 'd.get_loaded_file'), - Method(Torrent, 'get_max_file_size', 'd.get_max_file_size'), - Method(Torrent, 'get_size_chunks', 'd.get_size_chunks'), + Method(Torrent, 'get_loaded_file', 'd.loaded_file'), + Method(Torrent, 'get_max_file_size', 'd.max_file_size'), + Method(Torrent, 'get_size_chunks', 'd.size_chunks'), Method(Torrent, 'is_pex_active', 'd.is_pex_active', boolean=True, ), - Method(Torrent, 'get_hashing', 'd.get_hashing'), - Method(Torrent, 'get_bitfield', 'd.get_bitfield'), - Method(Torrent, 'get_local_id_html', 'd.get_local_id_html'), - Method(Torrent, 'get_connection_leech', 'd.get_connection_leech'), - Method(Torrent, 'get_peers_accounted', 'd.get_peers_accounted'), - Method(Torrent, 'get_message', 'd.get_message'), + Method(Torrent, 'get_hashing', 'd.hashing'), + Method(Torrent, 'get_bitfield', 'd.bitfield'), + Method(Torrent, 'get_local_id_html', 'd.local_id_html'), + Method(Torrent, 'get_connection_leech', 'd.connection_leech'), + Method(Torrent, 'get_peers_accounted', 'd.peers_accounted'), + Method(Torrent, 'get_message', 'd.message'), Method(Torrent, 'is_active', 'd.is_active', boolean=True, ), - Method(Torrent, 'get_size_bytes', 'd.get_size_bytes'), - Method(Torrent, 'get_ignore_commands', 'd.get_ignore_commands'), - Method(Torrent, 'get_creation_date', 'd.get_creation_date'), - Method(Torrent, 'get_base_path', 'd.get_base_path'), - Method(Torrent, 'get_left_bytes', 'd.get_left_bytes'), - Method(Torrent, 'get_size_files', 'd.get_size_files'), - Method(Torrent, 'get_size_pex', 'd.get_size_pex'), + Method(Torrent, 'get_size_bytes', 'd.size_bytes'), + Method(Torrent, 'get_ignore_commands', 'd.ignore_commands'), + Method(Torrent, 'get_creation_date', 'd.creation_date'), + Method(Torrent, 'get_base_path', 'd.base_path'), + Method(Torrent, 'get_left_bytes', 'd.left_bytes'), + Method(Torrent, 'get_size_files', 'd.size_files'), + Method(Torrent, 'get_size_pex', 'd.size_pex'), Method(Torrent, 'is_private', 'd.is_private', boolean=True, ), - Method(Torrent, 'get_max_size_pex', 'd.get_max_size_pex'), - Method(Torrent, 'get_num_chunks_hashed', 'd.get_chunks_hashed', + Method(Torrent, 'get_max_size_pex', 'd.max_size_pex'), + Method(Torrent, 'get_num_chunks_hashed', 'd.chunks_hashed', aliases=("get_chunks_hashed",)), Method(Torrent, 'get_num_chunks_wanted', 'd.wanted_chunks'), - Method(Torrent, 'get_priority', 'd.get_priority'), - Method(Torrent, 'get_skip_rate', 'd.get_skip_rate'), - Method(Torrent, 'get_completed_bytes', 'd.get_completed_bytes'), - Method(Torrent, 'get_name', 'd.get_name'), - Method(Torrent, 'get_completed_chunks', 'd.get_completed_chunks'), - Method(Torrent, 'get_throttle_name', 'd.get_throttle_name'), - Method(Torrent, 'get_free_diskspace', 'd.get_free_diskspace'), - Method(Torrent, 'get_directory_base', 'd.get_directory_base'), - Method(Torrent, 'get_hashing_failed', 'd.get_hashing_failed'), - Method(Torrent, 'get_tied_to_file', 'd.get_tied_to_file'), - Method(Torrent, 'get_down_total', 'd.get_down_total'), - Method(Torrent, 'get_bytes_done', 'd.get_bytes_done'), - Method(Torrent, 'get_up_rate', 'd.get_up_rate'), - Method(Torrent, 'get_up_total', 'd.get_up_total'), + Method(Torrent, 'get_priority', 'd.priority'), + Method(Torrent, 'get_skip_rate', 'd.skip.rate'), + Method(Torrent, 'get_completed_bytes', 'd.completed_bytes'), + Method(Torrent, 'get_name', 'd.name'), + Method(Torrent, 'get_completed_chunks', 'd.completed_chunks'), + Method(Torrent, 'get_throttle_name', 'd.throttle_name'), + Method(Torrent, 'get_free_diskspace', 'd.free_diskspace'), + Method(Torrent, 'get_directory_base', 'd.directory_base'), + Method(Torrent, 'get_hashing_failed', 'd.hashing_failed'), + Method(Torrent, 'get_tied_to_file', 'd.tied_to_file'), + Method(Torrent, 'get_down_total', 'd.down.total'), + Method(Torrent, 'get_bytes_done', 'd.bytes_done'), + Method(Torrent, 'get_up_rate', 'd.up.rate'), + Method(Torrent, 'get_up_total', 'd.up.total'), Method(Torrent, 'is_accepting_seeders', 'd.accepting_seeders', boolean=True, ), @@ -490,28 +490,28 @@ methods = [ boolean=True, ), Method(Torrent, "get_time_started", "d.timestamp.started"), - Method(Torrent, "get_custom1", "d.get_custom1"), - Method(Torrent, "get_custom2", "d.get_custom2"), - Method(Torrent, "get_custom3", "d.get_custom3"), - Method(Torrent, "get_custom4", "d.get_custom4"), - Method(Torrent, "get_custom5", "d.get_custom5"), + Method(Torrent, "get_custom1", "d.custom1"), + Method(Torrent, "get_custom2", "d.custom2"), + Method(Torrent, "get_custom3", "d.custom3"), + Method(Torrent, "get_custom4", "d.custom4"), + Method(Torrent, "get_custom5", "d.custom5"), # MODIFIERS - Method(Torrent, 'set_uploads_max', 'd.set_uploads_max'), - Method(Torrent, 'set_tied_to_file', 'd.set_tied_to_file'), - Method(Torrent, 'set_tracker_numwant', 'd.set_tracker_numwant'), - Method(Torrent, 'set_priority', 'd.set_priority'), - Method(Torrent, 'set_peers_max', 'd.set_peers_max'), - Method(Torrent, 'set_hashing_failed', 'd.set_hashing_failed'), - Method(Torrent, 'set_message', 'd.set_message'), - Method(Torrent, 'set_throttle_name', 'd.set_throttle_name'), - Method(Torrent, 'set_peers_min', 'd.set_peers_min'), - Method(Torrent, 'set_ignore_commands', 'd.set_ignore_commands'), - Method(Torrent, 'set_max_file_size', 'd.set_max_file_size'), - Method(Torrent, 'set_custom5', 'd.set_custom5'), - Method(Torrent, 'set_custom4', 'd.set_custom4'), - Method(Torrent, 'set_custom2', 'd.set_custom2'), - Method(Torrent, 'set_custom1', 'd.set_custom1'), - Method(Torrent, 'set_custom3', 'd.set_custom3'), - Method(Torrent, 'set_connection_current', 'd.set_connection_current'), + Method(Torrent, 'set_uploads_max', 'd.uploads_max.set'), + Method(Torrent, 'set_tied_to_file', 'd.tied_to_file.set'), + Method(Torrent, 'set_tracker_numwant', 'd.tracker_numwant.set'), + Method(Torrent, 'set_priority', 'd.priority.set'), + Method(Torrent, 'set_peers_max', 'd.peers_max.set'), + Method(Torrent, 'set_hashing_failed', 'd.hashing_failed.set'), + Method(Torrent, 'set_message', 'd.message.set'), + Method(Torrent, 'set_throttle_name', 'd.throttle_name.set'), + Method(Torrent, 'set_peers_min', 'd.peers_min.set'), + Method(Torrent, 'set_ignore_commands', 'd.ignore_commands.set'), + Method(Torrent, 'set_max_file_size', 'd.max_file_size.set'), + Method(Torrent, 'set_custom5', 'd.custom5.set'), + Method(Torrent, 'set_custom4', 'd.custom4.set'), + Method(Torrent, 'set_custom2', 'd.custom2.set'), + Method(Torrent, 'set_custom1', 'd.custom1.set'), + Method(Torrent, 'set_custom3', 'd.custom3.set'), + Method(Torrent, 'set_connection_current', 'd.connection_current.set'), ] diff --git a/libs/rtorrent/tracker.py b/libs/rtorrent/tracker.py index 81af2e4..03cec4b 100755 --- a/libs/rtorrent/tracker.py +++ b/libs/rtorrent/tracker.py @@ -70,17 +70,17 @@ class Tracker: methods = [ # RETRIEVERS Method(Tracker, 'is_enabled', 't.is_enabled', boolean=True), - Method(Tracker, 'get_id', 't.get_id'), - Method(Tracker, 'get_scrape_incomplete', 't.get_scrape_incomplete'), + Method(Tracker, 'get_id', 't.id'), + Method(Tracker, 'get_scrape_incomplete', 't.scrape_incomplete'), Method(Tracker, 'is_open', 't.is_open', boolean=True), - Method(Tracker, 'get_min_interval', 't.get_min_interval'), - Method(Tracker, 'get_scrape_downloaded', 't.get_scrape_downloaded'), - Method(Tracker, 'get_group', 't.get_group'), - Method(Tracker, 'get_scrape_time_last', 't.get_scrape_time_last'), - Method(Tracker, 'get_type', 't.get_type'), - Method(Tracker, 'get_normal_interval', 't.get_normal_interval'), - Method(Tracker, 'get_url', 't.get_url'), - Method(Tracker, 'get_scrape_complete', 't.get_scrape_complete', + Method(Tracker, 'get_min_interval', 't.min_interval'), + Method(Tracker, 'get_scrape_downloaded', 't.scrape_downloaded'), + Method(Tracker, 'get_group', 't.group'), + Method(Tracker, 'get_scrape_time_last', 't.scrape_time_last'), + Method(Tracker, 'get_type', 't.type'), + Method(Tracker, 'get_normal_interval', 't.normal_interval'), + Method(Tracker, 'get_url', 't.url'), + Method(Tracker, 'get_scrape_complete', 't.scrape_complete', min_version=(0, 8, 9), ), Method(Tracker, 'get_activity_time_last', 't.activity_time_last', @@ -134,5 +134,5 @@ methods = [ ), # MODIFIERS - Method(Tracker, 'set_enabled', 't.set_enabled'), + Method(Tracker, 'set_enabled', 't.is_enabled.set'), ] diff --git a/libs/subliminal/core.py b/libs/subliminal/core.py index 6661968..5cb4a96 100755 --- a/libs/subliminal/core.py +++ b/libs/subliminal/core.py @@ -32,7 +32,8 @@ __all__ = ['SERVICES', 'LANGUAGE_INDEX', 'SERVICE_INDEX', 'SERVICE_CONFIDENCE', 'create_list_tasks', 'create_download_tasks', 'consume_task', 'matching_confidence', 'key_subtitles', 'group_by_video'] logger = logging.getLogger(__name__) -SERVICES = ['opensubtitles', 'bierdopje', 'subswiki', 'subtitulos', 'thesubdb', 'addic7ed', 'tvsubtitles', 'subscenter'] +SERVICES = ['opensubtitles', 'bierdopje', 'subswiki', 'subtitulos', 'thesubdb', 'addic7ed', 'tvsubtitles', + 'subscenter', 'wizdom'] LANGUAGE_INDEX, SERVICE_INDEX, SERVICE_CONFIDENCE, MATCHING_CONFIDENCE = range(4) diff --git a/libs/subliminal/services/subscenter.py b/libs/subliminal/services/subscenter.py index 9a5511c..258edad 100644 --- a/libs/subliminal/services/subscenter.py +++ b/libs/subliminal/services/subscenter.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2012 Ofir Brukner +# Copyright 2012 Ofir123 # # This file is part of subliminal. # @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with subliminal. If not, see . from . import ServiceBase -from ..exceptions import ServiceError +from ..exceptions import DownloadFailedError, ServiceError from ..language import language_set from ..subtitles import get_subtitle_path, ResultSubtitle from ..videos import Episode, Movie @@ -30,7 +30,7 @@ logger = logging.getLogger(__name__) class Subscenter(ServiceBase): - server = 'http://www.subscenter.co/he/' + server = 'http://www.subscenter.info/he/' api_based = False languages = language_set(['he']) videos = [Episode, Movie] @@ -110,10 +110,11 @@ class Subscenter(ServiceBase): # Read the item. subtitle_id = subtitle_item['id'] subtitle_key = subtitle_item['key'] + subtitle_version = subtitle_item['h_version'] release = subtitle_item['subtitle_version'] subtitle_path = get_subtitle_path(filepath, language_object, self.config.multi) download_link = self.server_url + 'subtitle/download/{0}/{1}/?v={2}&key={3}'.format( - language_code, subtitle_id, release, subtitle_key) + language_code, subtitle_id, subtitle_version, subtitle_key) # Add the release and increment downloaded count if we already have the subtitle. if subtitle_id in subtitles: logger.debug('Found additional release {0} for subtitle {1}'.format( @@ -128,7 +129,11 @@ class Subscenter(ServiceBase): return subtitles.values() def download(self, subtitle): - self.download_zip_file(subtitle.link, subtitle.path) + try: + self.download_zip_file(subtitle.link, subtitle.path) + except DownloadFailedError: + # If no zip file was retrieved, daily downloads limit has exceeded. + raise ServiceError('Daily limit exceeded') return subtitle diff --git a/libs/subliminal/services/wizdom.py b/libs/subliminal/services/wizdom.py new file mode 100644 index 0000000..675dccf --- /dev/null +++ b/libs/subliminal/services/wizdom.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Ofir123 +# +# This file is part of subliminal. +# +# subliminal is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# subliminal 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with subliminal. If not, see . +from . import ServiceBase +from ..exceptions import ServiceError +from ..language import language_set +from ..subtitles import get_subtitle_path, ResultSubtitle +from ..videos import Episode, Movie +from ..utils import to_unicode +import bisect +import logging + +logger = logging.getLogger(__name__) + + +class Wizdom(ServiceBase): + server = 'http://wizdom.xyz' + api_based = True + languages = language_set(['he']) + videos = [Episode, Movie] + require_video = False + + _tmdb_api_key = 'a51ee051bcd762543373903de296e0a3' + + def _search_imdb_id(self, title, year, is_movie): + """Search the IMDB ID for the given `title` and `year`. + + :param str title: title to search for. + :param int year: year to search for (or 0 if not relevant). + :param bool is_movie: If True, IMDB ID will be searched for in TMDB instead of Wizdom. + :return: the IMDB ID for the given title and year (or None if not found). + :rtype: str + """ + # make the search + logger.info('Searching IMDB ID for %r%r', title, '' if not year else ' ({})'.format(year)) + category = 'movie' if is_movie else 'tv' + title = title.replace('\'', '') + # get TMDB ID first + r = self.session.get('http://api.tmdb.org/3/search/{}?api_key={}&query={}{}&language=en'.format( + category, self._tmdb_api_key, title, '' if not year else '&year={}'.format(year))) + r.raise_for_status() + tmdb_results = r.json().get('results') + if tmdb_results: + tmdb_id = tmdb_results[0].get('id') + if tmdb_id: + # get actual IMDB ID from TMDB + r = self.session.get('http://api.tmdb.org/3/{}/{}{}?api_key={}&language=en'.format( + category, tmdb_id, '' if is_movie else '/external_ids', self._tmdb_api_key)) + r.raise_for_status() + return str(r.json().get('imdb_id', '')) or None + return None + + def list_checked(self, video, languages): + series = None + season = None + episode = None + title = video.title + imdb_id = video.imdbid + year = video.year + if isinstance(video, Episode): + series = video.series + season = video.season + episode = video.episode + return self.query(video.path or video.release, languages, series, season, + episode, title, imdb_id, year) + + def query(self, filepath, languages=None, series=None, season=None, episode=None, title=None, imdbid=None, + year=None): + logger.debug(u'Getting subtitles for {0} season {1} episode {2} with languages {3}'.format( + series, season, episode, languages)) + # search for the IMDB ID if needed + is_movie = not (series and season and episode) + if is_movie and not title: + raise ServiceError('One or more parameters are missing') + # for TV series, we need the series IMDB ID, and not the specific episode ID + imdb_id = imdbid or self._search_imdb_id(title, year, is_movie) + + # search + logger.debug(u'Using IMDB ID {0}'.format(imdb_id)) + url = 'http://json.{}/{}.json'.format(self.server_url, imdb_id) + + # get the list of subtitles + logger.debug('Getting the list of subtitles') + r = self.session.get(url) + r.raise_for_status() + try: + results = r.json() + except ValueError: + return {} + + # filter irrelevant results + if not is_movie: + results = results.get('subs', {}).get(str(season), {}).get(str(episode), []) + else: + results = results.get('subs', []) + + # loop over results + subtitles = dict() + for result in results: + language_object = self.get_language('heb') + subtitle_id = result['id'] + release = result['version'] + subtitle_path = get_subtitle_path(filepath, language_object, self.config.multi) + download_link = 'http://zip.{}/{}.zip'.format(self.server_url, subtitle_id) + # add the release and increment downloaded count if we already have the subtitle + if subtitle_id in subtitles: + logger.debug(u'Found additional release {0} for subtitle {1}'.format(release, subtitle_id)) + bisect.insort_left(subtitles[subtitle_id].releases, release) # deterministic order + subtitles[subtitle_id].downloaded += 1 + continue + # otherwise create it + subtitle = ResultSubtitle(subtitle_path, language_object, self.__class__.__name__.lower(), + download_link, release=to_unicode(release)) + logger.debug(u'Found subtitle {0}'.format(subtitle)) + subtitles[subtitle_id] = subtitle + + return subtitles.values() + + def download(self, subtitle): + self.download_zip_file(subtitle.link, subtitle.path) + return subtitle + + +Service = Wizdom diff --git a/libs/xmpp/transports.py b/libs/xmpp/transports.py index f3d1316..bf59266 100644 --- a/libs/xmpp/transports.py +++ b/libs/xmpp/transports.py @@ -27,7 +27,7 @@ Transports are stackable so you - f.e. TLS use HTPPROXYsocket or TCPsocket as mo Also exception 'error' is defined to allow capture of this module specific exceptions. """ -import socket, select, base64, dispatcher, sys +import socket, ssl, select, base64, dispatcher, sys from simplexml import ustr from client import PlugIn from protocol import * @@ -312,9 +312,9 @@ class TLS(PlugIn): """ Immidiatedly switch socket to TLS mode. Used internally.""" """ Here we should switch pending_data to hint mode.""" tcpsock = self._owner.Connection - tcpsock._sslObj = socket.ssl(tcpsock._sock, None, None) - tcpsock._sslIssuer = tcpsock._sslObj.issuer() - tcpsock._sslServer = tcpsock._sslObj.server() + tcpsock._sslObj = ssl.wrap_socket(tcpsock._sock, None, None) + tcpsock._sslIssuer = tcpsock._sslObj.getpeercert().get('issuer') + tcpsock._sslServer = tcpsock._sslObj.getpeercert().get('server') tcpsock._recv = tcpsock._sslObj.read tcpsock._send = tcpsock._sslObj.write