From 1030d0d748c3db962a4f576b26c357ae53231edd Mon Sep 17 00:00:00 2001 From: Ofir Brukner Date: Mon, 13 Oct 2014 00:50:29 +0300 Subject: [PATCH 01/11] Added support for subscenter. Updated both plugin and lib. --- couchpotato/core/plugins/subtitle.py | 2 +- libs/subliminal/core.py | 2 +- libs/subliminal/services/subscenter.py | 100 +++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 libs/subliminal/services/subscenter.py diff --git a/couchpotato/core/plugins/subtitle.py b/couchpotato/core/plugins/subtitle.py index fdb640b1..1766088e 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', 'podnapisi'] + services = ['opensubtitles', 'thesubdb', 'subswiki', 'podnapisi', 'subscenter'] def __init__(self): addEvent('renamer.before', self.searchSingle) diff --git a/libs/subliminal/core.py b/libs/subliminal/core.py index 537fa655..66619683 100755 --- a/libs/subliminal/core.py +++ b/libs/subliminal/core.py @@ -32,7 +32,7 @@ __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'] +SERVICES = ['opensubtitles', 'bierdopje', 'subswiki', 'subtitulos', 'thesubdb', 'addic7ed', 'tvsubtitles', 'subscenter'] LANGUAGE_INDEX, SERVICE_INDEX, SERVICE_CONFIDENCE, MATCHING_CONFIDENCE = range(4) diff --git a/libs/subliminal/services/subscenter.py b/libs/subliminal/services/subscenter.py new file mode 100644 index 00000000..6eeafa27 --- /dev/null +++ b/libs/subliminal/services/subscenter.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +# Copyright 2012 Ofir Brukner +# +# 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 . +import logging +import re +import json +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, get_keywords + + +logger = logging.getLogger(__name__) + + +class Subscenter(ServiceBase): + server_url = 'http://subscenter.cinemast.com/he/' + api_based = False + languages = language_set(['he', 'en']) + videos = [Episode, Movie] + require_video = False + required_features = ['permissive'] + + @staticmethod + def slugify(string): + new_string = string.replace(' ', '-').replace("'", '').replace(':', '').lower() + # We remove multiple spaces by using this regular expression. + return re.sub('-+', '-', new_string) + + def list_checked(self, video, languages): + series = None + season = None + episode = None + title = video.title + if isinstance(video, Episode): + series = video.series + season = video.season + episode = video.episode + return self.query(video.path or video.release, languages, get_keywords(video.guess), series, season, + episode, title) + + def query(self, filepath, languages=None, keywords=None, series=None, season=None, episode=None, title=None): + logger.debug(u'Getting subtitles for %s season %d episode %d with languages %r' % (series, season, episode, languages)) + # Converts the title to Subscenter format by replacing whitespaces and removing specific chars. + if series and season and episode: + # Search for a TV show. + kind = 'episode' + slugified_series = self.slugify(series) + url = self.server_url + 'cinemast/data/series/sb/' + slugified_series + '/' + str(season) + '/' + \ + str(episode) + '/' + elif title: + # Search for a movie. + kind = 'movie' + slugified_title = self.slugify(title) + url = self.server_url + 'cinemast/data/movie/sb/' + slugified_title + '/' + else: + raise ServiceError('One or more parameters are missing') + logger.debug('Searching subtitles %r', {'title': title, 'season': season, 'episode': episode}) + response = self.session.get(url) + if response.status_code != 200: + raise ServiceError('Request failed with status code %d' % response.status_code) + + subtitles = [] + response_json = json.loads(response.content) + for lang, lang_json in response_json.items(): + lang_obj = self.get_language(lang) + if lang_obj in self.languages and lang_obj in languages: + for group_data in lang_json.values(): + for quality in group_data.values(): + for sub in quality.values(): + release = sub.get('subtitle_version') + sub_path = get_subtitle_path(filepath, lang_obj, self.config.multi) + link = self.server_url + 'subtitle/download/' + lang + '/' + str(sub.get('id')) + \ + '/?v=' + release + '&key=' + str(sub.get('key')) + subtitles.append(ResultSubtitle(sub_path, lang_obj, self.__class__.__name__.lower(), + link, release=to_unicode(release))) + return subtitles + + def download(self, subtitle): + self.download_zip_file(subtitle.link, subtitle.path) + return subtitle + + +Service = Subscenter \ No newline at end of file From d626fda7109f4fa7199221084745dd21fe182d79 Mon Sep 17 00:00:00 2001 From: georgewhewell Date: Fri, 17 Oct 2014 15:14:44 +0100 Subject: [PATCH 02/11] add option for internal only for hdbits provider --- .../core/media/_base/providers/torrent/hdbits.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/couchpotato/core/media/_base/providers/torrent/hdbits.py b/couchpotato/core/media/_base/providers/torrent/hdbits.py index ebf2899b..f29fd157 100644 --- a/couchpotato/core/media/_base/providers/torrent/hdbits.py +++ b/couchpotato/core/media/_base/providers/torrent/hdbits.py @@ -29,6 +29,9 @@ class Base(TorrentProvider): } post_data.update(params) + if self.conf('internal_only'): + post_data.update({'origin': [1]}) + try: result = self.getJsonData(self.urls['api'], data = json.dumps(post_data)) @@ -110,6 +113,14 @@ config = [{ 'default': 0, 'description': 'Starting score for each release found via this provider.', }, + { + 'name': 'internal_only', + 'advanced': True, + 'label': 'Internal Only', + 'type': 'bool', + 'default': False, + 'description': 'Only download releases marked as HDBits internal' + } ], }, ], From 0766a27a71e6c7b789723e12be5d538244d1f0e1 Mon Sep 17 00:00:00 2001 From: Roy Kokkelkoren Date: Thu, 6 Nov 2014 04:40:39 -0600 Subject: [PATCH 03/11] Fixed bug in init.d script which prevented the writing of the PID file. Altered default value of DATA_DIR to /var/opt/couchpotato in order to comply to linux file structure --- init/ubuntu | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/init/ubuntu b/init/ubuntu index 8c5d556a..a21e2d34 100755 --- a/init/ubuntu +++ b/init/ubuntu @@ -33,8 +33,8 @@ DESC=CouchPotato ## ## CP_USER= #$RUN_AS, username to run couchpotato under, the default is couchpotato ## CP_HOME= #$APP_PATH, the location of couchpotato.py, the default is /opt/couchpotato -## CP_DATA= #$DATA_DIR, the location of couchpotato.db, cache, logs, the default is /var/couchpotato -## CP_PIDFILE= #$PID_FILE, the location of couchpotato.pid, the default is /var/run/couchpotato.pid +## CP_DATA= #$DATA_DIR, the location of couchpotato.db, cache, logs, the default is /var/opt/couchpotato +## CP_PIDFILE= #$PID_FILE, the location of couchpotato.pid, the default is /var/run/couchpotato/couchpotato.pid ## PYTHON_BIN= #$DAEMON, the location of the python binary, the default is /usr/bin/python ## CP_OPTS= #$EXTRA_DAEMON_OPTS, extra cli option for couchpotato, i.e. " --config_file=/home/couchpotato/couchpotato.ini" ## SSD_OPTS= #$EXTRA_SSD_OPTS, extra start-stop-daemon option like " --group=users" @@ -51,10 +51,10 @@ RUN_AS=${CP_USER-couchpotato} APP_PATH=${CP_HOME-/opt/couchpotato/} # Data directory where couchpotato.db, cache and logs are stored -DATA_DIR=${CP_DATA-/var/couchpotato} +DATA_DIR=${CP_DATA-/var/opt/couchpotato} # Path to store PID file -PID_FILE=${CP_PIDFILE-/var/run/couchpotato.pid} +PID_FILE=${CP_PIDFILE-/var/run/couchpotato/couchpotato.pid} # path to python bin DAEMON=${PYTHON_BIN-/usr/bin/python} From 43af80a1375322626b13c040f060b6be288c0e02 Mon Sep 17 00:00:00 2001 From: Rutger van Sleen Date: Thu, 6 Nov 2014 14:33:38 +0100 Subject: [PATCH 04/11] Update SSL protocol for Deluge connections Since Deluge 1.3.10 the SSL protocol is updated to TLSv1 instead of SSLv3. This resulted in CP not being able to add new torrents. Link to change in Deluge: http://git.deluge-torrent.org/deluge/commit/?h=1.3-stable&id=26f5be17609a8312c4ba06aa120ed208cd7876f2 --- libs/synchronousdeluge/transfer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/synchronousdeluge/transfer.py b/libs/synchronousdeluge/transfer.py index 979ffb16..472bb125 100644 --- a/libs/synchronousdeluge/transfer.py +++ b/libs/synchronousdeluge/transfer.py @@ -19,7 +19,7 @@ class DelugeTransfer(object): self.disconnect() self.sock = socket.create_connection(hostport) - self.conn = ssl.wrap_socket(self.sock, None, None, False, ssl.CERT_NONE, ssl.PROTOCOL_SSLv3) + self.conn = ssl.wrap_socket(self.sock, None, None, False, ssl.CERT_NONE, ssl.PROTOCOL_TLSv1) self.connected = True def disconnect(self): From 1087eb3a0611dadd93cc231b93aa131549ce799a Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 9 Nov 2014 14:10:23 +0100 Subject: [PATCH 05/11] Add adding parameter to is_movie --- .../core/media/movie/providers/info/couchpotatoapi.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/movie/providers/info/couchpotatoapi.py b/couchpotato/core/media/movie/providers/info/couchpotatoapi.py index 51afbaef..92b3fb3f 100644 --- a/couchpotato/core/media/movie/providers/info/couchpotatoapi.py +++ b/couchpotato/core/media/movie/providers/info/couchpotatoapi.py @@ -69,12 +69,15 @@ class CouchPotatoApi(MovieProvider): name_enc = base64.b64encode(ss(name)) return self.getJsonData(self.urls['validate'] % name_enc, headers = self.getRequestHeaders()) - def isMovie(self, identifier = None): + def isMovie(self, identifier = None, adding = False): if not identifier: return - data = self.getJsonData(self.urls['is_movie'] % identifier, headers = self.getRequestHeaders()) + url = self.urls['is_movie'] % identifier + url += '?adding=1' if adding else '' + + data = self.getJsonData(url, headers = self.getRequestHeaders()) if data: return data.get('is_movie', True) From 3669aef42d6cc35d21f75b4674f69308f0a9daf9 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 9 Nov 2014 14:14:06 +0100 Subject: [PATCH 06/11] is_movie param --- couchpotato/core/media/movie/_base/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/media/movie/_base/main.py b/couchpotato/core/media/movie/_base/main.py index 1b0881b5..48a66b05 100755 --- a/couchpotato/core/media/movie/_base/main.py +++ b/couchpotato/core/media/movie/_base/main.py @@ -65,7 +65,7 @@ class MovieBase(MovieTypeBase): return False elif not params.get('info'): try: - is_movie = fireEvent('movie.is_movie', identifier = params.get('identifier'), single = True) + is_movie = fireEvent('movie.is_movie', identifier = params.get('identifier'), adding = True, single = True) if not is_movie: msg = 'Can\'t add movie, seems to be a TV show.' log.error(msg) From 269e785888ae1eef7d3d38975f9bfd343fd3e4ab Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 9 Nov 2014 14:30:22 +0100 Subject: [PATCH 07/11] Yify, don't include quality in search fix #4190 --- .../core/media/_base/providers/torrent/yify.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/couchpotato/core/media/_base/providers/torrent/yify.py b/couchpotato/core/media/_base/providers/torrent/yify.py index 0daf20a0..725aabbc 100644 --- a/couchpotato/core/media/_base/providers/torrent/yify.py +++ b/couchpotato/core/media/_base/providers/torrent/yify.py @@ -12,17 +12,16 @@ class Base(TorrentMagnetProvider): urls = { 'test': '%s/api', - 'search': '%s/api/list.json?keywords=%s&quality=%s', + 'search': '%s/api/list.json?keywords=%s', 'detail': '%s/api/movie.json?id=%s' } http_time_between_calls = 1 # seconds proxy_list = [ - 'http://yify.unlocktorrent.com', - 'http://yify-torrents.com.come.in', - 'http://yts.re', - 'http://yts.im' + 'https://yts.re', + 'http://ytsproxy.come.in', + 'http://yts.im', 'http://yify-torrents.im', ] @@ -39,7 +38,7 @@ class Base(TorrentMagnetProvider): if not domain: return - search_url = self.urls['search'] % (domain, getIdentifier(movie), quality['identifier']) + search_url = self.urls['search'] % (domain, getIdentifier(movie)) data = self.getJsonData(search_url) From 7d7b76b2e9f522bae64847d29b5542e64aebf9b8 Mon Sep 17 00:00:00 2001 From: Kamil Date: Mon, 10 Nov 2014 20:18:38 -0500 Subject: [PATCH 08/11] adding a fix to handle missing directories in the file browser in webkit browsers --- couchpotato/static/scripts/page/settings.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js index b5aae3d1..dadfd353 100644 --- a/couchpotato/static/scripts/page/settings.js +++ b/couchpotato/static/scripts/page/settings.js @@ -885,7 +885,10 @@ Option.Directory = new Class({ new Element('li.empty', { 'text': 'Selected folder is empty' }).inject(self.dir_list) - + + //fix for webkit type browsers to refresh the dom for the file browser + //http://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes + self.dir_list.setStyle("webkitTransform", "scale(1)") self.caretAtEnd(); }, From 6d79f316a6be6105680398e253409bd8f7033e68 Mon Sep 17 00:00:00 2001 From: Clinton Hall Date: Tue, 25 Nov 2014 11:02:47 +1030 Subject: [PATCH 09/11] NZBGet 13 includes more status information nzb['Status'] returns total (SUCESS/ALL) status and also failed status in V13+ This is particularly important when using fake detector scripts or stopping download due to health checks etc. http://nzbget.net/RPC_API_reference#Method_.22history.22 https://couchpota.to/forum/viewtopic.php?f=5&t=4644 --- couchpotato/core/downloaders/nzbget.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/downloaders/nzbget.py b/couchpotato/core/downloaders/nzbget.py index b46de778..54725bd5 100644 --- a/couchpotato/core/downloaders/nzbget.py +++ b/couchpotato/core/downloaders/nzbget.py @@ -163,12 +163,12 @@ class NZBGet(DownloaderBase): nzb_id = nzb['NZBID'] if nzb_id in ids: - log.debug('Found %s in NZBGet history. ParStatus: %s, ScriptStatus: %s, Log: %s', (nzb['NZBFilename'] , nzb['ParStatus'], nzb['ScriptStatus'] , nzb['Log'])) + log.debug('Found %s in NZBGet history. TotalStatus: %s, ParStatus: %s, ScriptStatus: %s, Log: %s', (nzb['NZBFilename'] , nzb['Status'], nzb['ParStatus'], nzb['ScriptStatus'] , nzb['Log'])) release_downloads.append({ 'id': nzb_id, 'name': nzb['NZBFilename'], - 'status': 'completed' if nzb['ParStatus'] in ['SUCCESS', 'NONE'] and nzb['ScriptStatus'] in ['SUCCESS', 'NONE'] else 'failed', - 'original_status': nzb['ParStatus'] + ', ' + nzb['ScriptStatus'], + 'status': 'completed' if 'SUCCESS' in nzb['Status'] else 'failed', + 'original_status': nzb['Status'], 'timeleft': str(timedelta(seconds = 0)), 'folder': sp(nzb['DestDir']) }) From 38c6266f9c5abd0e336a0fd279c5d10e91c8dd5d Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 26 Nov 2014 21:47:39 +0100 Subject: [PATCH 10/11] Use single quotes --- couchpotato/static/scripts/page/settings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js index dadfd353..9d083a1f 100644 --- a/couchpotato/static/scripts/page/settings.js +++ b/couchpotato/static/scripts/page/settings.js @@ -885,10 +885,10 @@ Option.Directory = new Class({ new Element('li.empty', { 'text': 'Selected folder is empty' }).inject(self.dir_list) - + //fix for webkit type browsers to refresh the dom for the file browser //http://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes - self.dir_list.setStyle("webkitTransform", "scale(1)") + self.dir_list.setStyle('webkitTransform', 'scale(1)'); self.caretAtEnd(); }, From 1a43ce6ecc2ea31501f243dd64e159b148ac0e11 Mon Sep 17 00:00:00 2001 From: sammy2142 Date: Sun, 30 Nov 2014 20:48:31 +0000 Subject: [PATCH 11/11] Update Kickass url to https://kickass.so Kickass has recently changed its web address from https://kickass.to to https://kickass.so --- .../core/media/_base/providers/torrent/kickasstorrents.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py b/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py index d6e3ee72..fb58814d 100644 --- a/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py +++ b/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py @@ -30,7 +30,7 @@ class Base(TorrentMagnetProvider): cat_backup_id = None proxy_list = [ - 'https://kickass.to', + 'https://kickass.so', 'http://kickass.pw', 'http://kickassto.come.in', 'http://katproxy.ws',