From 04688dd41ce72ce4f45ca3d4bab10b83fd4ff273 Mon Sep 17 00:00:00 2001 From: ofir123 Date: Sat, 22 Apr 2017 14:36:30 +0300 Subject: [PATCH 01/16] Added support for the Hebrew subtitles website - TheWiz. --- couchpotato/core/plugins/subtitle.py | 2 +- libs/subliminal/core.py | 3 +- libs/subliminal/services/thewiz.py | 140 +++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 libs/subliminal/services/thewiz.py diff --git a/couchpotato/core/plugins/subtitle.py b/couchpotato/core/plugins/subtitle.py index 135ec2d..ef4a806 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', 'thewiz'] def __init__(self): addEvent('renamer.before', self.searchSingle) diff --git a/libs/subliminal/core.py b/libs/subliminal/core.py index 6661968..fcecd06 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', 'thewiz'] LANGUAGE_INDEX, SERVICE_INDEX, SERVICE_CONFIDENCE, MATCHING_CONFIDENCE = range(4) diff --git a/libs/subliminal/services/thewiz.py b/libs/subliminal/services/thewiz.py new file mode 100644 index 0000000..da351a8 --- /dev/null +++ b/libs/subliminal/services/thewiz.py @@ -0,0 +1,140 @@ +# -*- 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 +import os + +logger = logging.getLogger(__name__) + + +class TheWiz(ServiceBase): + server = 'http://subs.thewiz.info/' + api_based = True + languages = language_set(['he']) + videos = [Episode, Movie] + require_video = False + + _tmdb_api_key = 'f7f51775877e0bb6703520952b3c7840' + + 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 TheWiz. + :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)) + title = title.replace('\'', '') + if is_movie: + # get TMDB ID first + r = self.session.get('http://api.tmdb.org/3/search/movie?api_key={}&query={}{}&language=en'.format( + 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/movie/{}?api_key={}&language=en'.format( + tmdb_id, self._tmdb_api_key)) + r.raise_for_status() + return str(r.json().get('imdb_id', '')) or None + return None + + # handle TV series + r = self.session.get(self.server_url + 'search.tv.php', params={'name': title}, timeout=10) + r.raise_for_status() + return r.text or 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 = (is_movie and imdbid) or self._search_imdb_id(title, year, is_movie) + # get search parameters + season = season or 0 + episode = episode or 0 + version = os.path.splitext(os.path.basename(filepath))[0] if filepath else 0 + + # search + logger.debug(u'Using IMDB ID {0}'.format(imdb_id)) + url = 'http://subs.thewiz.info/search.id.php?imdb={}&season={}&episode={}&version={}'.format( + imdb_id, season, episode, version) + + # get the list of subtitles + logger.debug(u'Getting the list of subtitles') + r = self.session.get(url) + r.raise_for_status() + results = r.json() + + # loop over results + + subtitles = dict() + for result in results: + language_object = self.get_language('heb') + subtitle_id = result['id'] + release = result['versioname'] + subtitle_path = get_subtitle_path(filepath, language_object, self.config.multi) + download_link = self.server_url + 'zip/{0}.zip'.format(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 = TheWiz From f1b993745c41094fa54ae0a22be355bbc1fd19ef Mon Sep 17 00:00:00 2001 From: ofir123 Date: Sat, 22 Apr 2017 23:48:58 +0300 Subject: [PATCH 02/16] SubsCenter service now supports the new API. --- libs/subliminal/services/subscenter.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/libs/subliminal/services/subscenter.py b/libs/subliminal/services/subscenter.py index 9a5511c..253d925 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.org/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 From 714a942bc5d8cf72b45369c9bb73566cdacebd68 Mon Sep 17 00:00:00 2001 From: Fmstrat Date: Thu, 11 May 2017 07:15:18 -0400 Subject: [PATCH 03/16] Updated script notification to use Popen instead of call. --- couchpotato/core/notifications/script.py | 34 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 12 deletions(-) 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', From 8b7934e50a50bab420a29ea36552cc03c02fa176 Mon Sep 17 00:00:00 2001 From: jbarr13 Date: Thu, 25 May 2017 09:41:09 -0500 Subject: [PATCH 04/16] Use IMDb codes for search and comparison Using the movie title to search was inaccurate and often failed. Also, the original title is not always correct. YTS offers lookup by imdb code and always finds an exact match if they have it. --- .../core/media/_base/providers/torrent/yts.py | 62 ++++++++++------------ 1 file changed, 28 insertions(+), 34 deletions(-) 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 From 1d7376080876b16c9de307737d39d8bb7cd7c41c Mon Sep 17 00:00:00 2001 From: QuasimodoNZ Date: Fri, 2 Jun 2017 00:17:14 +1200 Subject: [PATCH 05/16] Prevent removal of download if disk is full. Download hasn't failed but rather been temporarily stalled. It should leave the download a lone until a proper error that cannot be fixed. If the disk is full it will also likely prevent any other downloads as well so even more reason to leave it alone. --- couchpotato/core/downloaders/utorrent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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' From 30a529659c911cfc6285815a23adecb35631a340 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 10 Jun 2017 14:22:00 +0200 Subject: [PATCH 06/16] OMDB changed api. closes #7214 --- .../core/media/movie/providers/info/omdbapi.py | 44 +++++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/couchpotato/core/media/movie/providers/info/omdbapi.py b/couchpotato/core/media/movie/providers/info/omdbapi.py index 3f257c6..ddb336e 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/?apikiey=%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,8 +55,7 @@ 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 @@ -89,7 +90,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 +124,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 +144,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', + }, + ], + }, + ], +}] From 9efc94f7d257900212502b054b9f9b81d00813fa Mon Sep 17 00:00:00 2001 From: Jens Kat Date: Sat, 10 Jun 2017 14:45:37 +0200 Subject: [PATCH 07/16] Remove automations that do not work anymore Since end of 2016 the RSS feed of moviemeter.nl is disabled (see https://www.moviemeter.nl/forum/1/8593/30#4523045). When having the automation enabled, this causes errors in the logfile and the feature doesn't work of course. ``` 6-10 13:31:30 ERROR [edia._base.providers.base] Invalid XML returned, check "http://www.moviemeter.nl/rss/cinema" manually for issues ``` kinepolis.be website doesn't have a top 10 list anymore. movies.io is not online anymore --- .../media/movie/providers/automation/kinepolis.py | 54 ---------------- .../media/movie/providers/automation/moviemeter.py | 48 --------------- .../media/movie/providers/automation/movies_io.py | 72 ---------------------- 3 files changed, 174 deletions(-) delete mode 100644 couchpotato/core/media/movie/providers/automation/kinepolis.py delete mode 100644 couchpotato/core/media/movie/providers/automation/moviemeter.py delete mode 100644 couchpotato/core/media/movie/providers/automation/movies_io.py 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'], - }, - ], - }, - ], -}] From e38333dfc14ae53e8ec8fa1396329bfac1f40bd1 Mon Sep 17 00:00:00 2001 From: Jeremy Shapiro Date: Wed, 14 Jun 2017 13:51:39 -0700 Subject: [PATCH 08/16] torrentday has depcreated the classic URL --- .../core/media/_base/providers/torrent/torrentday.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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': [ From 9f1124b0bbc7e7aabfe21cce91224ce96334e8d4 Mon Sep 17 00:00:00 2001 From: Alexandre Boucey Date: Tue, 20 Jun 2017 15:25:08 +0200 Subject: [PATCH 09/16] Update omdbapi.py Fixed API key support for OMDb --- couchpotato/core/media/movie/providers/info/omdbapi.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/movie/providers/info/omdbapi.py b/couchpotato/core/media/movie/providers/info/omdbapi.py index ddb336e..e72762f 100644 --- a/couchpotato/core/media/movie/providers/info/omdbapi.py +++ b/couchpotato/core/media/movie/providers/info/omdbapi.py @@ -19,7 +19,7 @@ class OMDBAPI(MovieProvider): urls = { 'search': 'https://www.omdbapi.com/?apikey=%s&type=movie&%s', - 'info': 'https://www.omdbapi.com/?apikiey=%s&type=movie&i=%s', + 'info': 'https://www.omdbapi.com/?apikey=%s&type=movie&i=%s', } http_time_between_calls = 0 @@ -59,7 +59,8 @@ class OMDBAPI(MovieProvider): 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) From b59e6ba8d3cdeb12f803e50bee6978faa5907294 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 26 Jun 2017 13:38:55 +0200 Subject: [PATCH 10/16] Rtorrent api changes --- libs/rtorrent/__init__.py | 50 +++++++++---- libs/rtorrent/file.py | 28 +++---- libs/rtorrent/peer.py | 26 +++---- libs/rtorrent/rpc/__init__.py | 6 +- libs/rtorrent/torrent.py | 168 +++++++++++++++++++++--------------------- libs/rtorrent/tracker.py | 22 +++--- 6 files changed, 160 insertions(+), 140 deletions(-) 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'), ] From 6dc7c583160ebba44f4ebe3958779573be951d31 Mon Sep 17 00:00:00 2001 From: ofir123 Date: Sun, 2 Jul 2017 23:20:26 +0300 Subject: [PATCH 11/16] Tiny fix for Subscenter new URL. --- libs/subliminal/services/subscenter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/subliminal/services/subscenter.py b/libs/subliminal/services/subscenter.py index 253d925..258edad 100644 --- a/libs/subliminal/services/subscenter.py +++ b/libs/subliminal/services/subscenter.py @@ -30,7 +30,7 @@ logger = logging.getLogger(__name__) class Subscenter(ServiceBase): - server = 'http://www.subscenter.org/he/' + server = 'http://www.subscenter.info/he/' api_based = False languages = language_set(['he']) videos = [Episode, Movie] From 9c9dc32c6fd5ac1668ae0d0e5491a81a0b8d4599 Mon Sep 17 00:00:00 2001 From: ofir123 Date: Sun, 2 Jul 2017 23:31:44 +0300 Subject: [PATCH 12/16] Switched from thewiz to wizdom. --- couchpotato/core/plugins/subtitle.py | 2 +- libs/subliminal/core.py | 2 +- libs/subliminal/services/thewiz.py | 140 ----------------------------------- libs/subliminal/services/wizdom.py | 138 ++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 142 deletions(-) delete mode 100644 libs/subliminal/services/thewiz.py create mode 100644 libs/subliminal/services/wizdom.py diff --git a/couchpotato/core/plugins/subtitle.py b/couchpotato/core/plugins/subtitle.py index ef4a806..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', 'thewiz'] + services = ['opensubtitles', 'thesubdb', 'subswiki', 'subscenter', 'wizdom'] def __init__(self): addEvent('renamer.before', self.searchSingle) diff --git a/libs/subliminal/core.py b/libs/subliminal/core.py index fcecd06..5cb4a96 100755 --- a/libs/subliminal/core.py +++ b/libs/subliminal/core.py @@ -33,7 +33,7 @@ __all__ = ['SERVICES', 'LANGUAGE_INDEX', 'SERVICE_INDEX', 'SERVICE_CONFIDENCE', 'key_subtitles', 'group_by_video'] logger = logging.getLogger(__name__) SERVICES = ['opensubtitles', 'bierdopje', 'subswiki', 'subtitulos', 'thesubdb', 'addic7ed', 'tvsubtitles', - 'subscenter', 'thewiz'] + 'subscenter', 'wizdom'] LANGUAGE_INDEX, SERVICE_INDEX, SERVICE_CONFIDENCE, MATCHING_CONFIDENCE = range(4) diff --git a/libs/subliminal/services/thewiz.py b/libs/subliminal/services/thewiz.py deleted file mode 100644 index da351a8..0000000 --- a/libs/subliminal/services/thewiz.py +++ /dev/null @@ -1,140 +0,0 @@ -# -*- 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 -import os - -logger = logging.getLogger(__name__) - - -class TheWiz(ServiceBase): - server = 'http://subs.thewiz.info/' - api_based = True - languages = language_set(['he']) - videos = [Episode, Movie] - require_video = False - - _tmdb_api_key = 'f7f51775877e0bb6703520952b3c7840' - - 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 TheWiz. - :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)) - title = title.replace('\'', '') - if is_movie: - # get TMDB ID first - r = self.session.get('http://api.tmdb.org/3/search/movie?api_key={}&query={}{}&language=en'.format( - 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/movie/{}?api_key={}&language=en'.format( - tmdb_id, self._tmdb_api_key)) - r.raise_for_status() - return str(r.json().get('imdb_id', '')) or None - return None - - # handle TV series - r = self.session.get(self.server_url + 'search.tv.php', params={'name': title}, timeout=10) - r.raise_for_status() - return r.text or 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 = (is_movie and imdbid) or self._search_imdb_id(title, year, is_movie) - # get search parameters - season = season or 0 - episode = episode or 0 - version = os.path.splitext(os.path.basename(filepath))[0] if filepath else 0 - - # search - logger.debug(u'Using IMDB ID {0}'.format(imdb_id)) - url = 'http://subs.thewiz.info/search.id.php?imdb={}&season={}&episode={}&version={}'.format( - imdb_id, season, episode, version) - - # get the list of subtitles - logger.debug(u'Getting the list of subtitles') - r = self.session.get(url) - r.raise_for_status() - results = r.json() - - # loop over results - - subtitles = dict() - for result in results: - language_object = self.get_language('heb') - subtitle_id = result['id'] - release = result['versioname'] - subtitle_path = get_subtitle_path(filepath, language_object, self.config.multi) - download_link = self.server_url + 'zip/{0}.zip'.format(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 = TheWiz diff --git a/libs/subliminal/services/wizdom.py b/libs/subliminal/services/wizdom.py new file mode 100644 index 0000000..01fcc05 --- /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 = 'f7f51775877e0bb6703520952b3c7840' + + 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 From 8b802f9c521fbc4885bcd61e4a2be3f267d44f50 Mon Sep 17 00:00:00 2001 From: ofir123 Date: Fri, 7 Jul 2017 15:35:41 +0300 Subject: [PATCH 13/16] TMDB API key fix. --- libs/subliminal/services/wizdom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/subliminal/services/wizdom.py b/libs/subliminal/services/wizdom.py index 01fcc05..675dccf 100644 --- a/libs/subliminal/services/wizdom.py +++ b/libs/subliminal/services/wizdom.py @@ -34,7 +34,7 @@ class Wizdom(ServiceBase): videos = [Episode, Movie] require_video = False - _tmdb_api_key = 'f7f51775877e0bb6703520952b3c7840' + _tmdb_api_key = 'a51ee051bcd762543373903de296e0a3' def _search_imdb_id(self, title, year, is_movie): """Search the IMDB ID for the given `title` and `year`. From a6dc2561dc64862e8e523fbfe2d9baf8989b91af Mon Sep 17 00:00:00 2001 From: softcat Date: Wed, 12 Jul 2017 18:17:15 +0200 Subject: [PATCH 14/16] Fixed filmstarts.de provider --- couchpotato/core/media/movie/providers/userscript/filmstarts.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) 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) From b31009faed891ecdb2ec1793e2858c87ee4564b7 Mon Sep 17 00:00:00 2001 From: mvn23 Date: Fri, 21 Jul 2017 01:36:13 +0200 Subject: [PATCH 15/16] Implement the patch from freebsd located at https://raw.githubusercontent.com/freebsd/freebsd-ports/master/net-im/py-xmpppy/files/patch-xmpp-transports.py Fixes ssl connections for xmpp notifications. --- libs/xmpp/transports.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 From 6adf56b14449d59afe254b3923a4a151c43e7556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20Gro=CC=88n?= Date: Fri, 21 Jul 2017 10:04:30 +0200 Subject: [PATCH 16/16] More sane URL for information on contribution. Also, Github issues should be re-enabled in the main resository settings... --- couchpotato/core/plugins/log/static/log.js | 2 +- couchpotato/static/scripts/combined.plugins.min.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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", {