From e1a311de40ab787f862f585ad41b44117b0b247c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20K=C3=A5berg?= Date: Thu, 21 Nov 2013 19:55:36 +0100 Subject: [PATCH 01/21] initial couchtarter provider (torrent newznab) initial ground work based on newznab provider needs UI changes: http://i.imgur.com/4MiJUH5.png (need to add ratio and seed hours also) untested code --- .../providers/torrent/couchtater/__init__.py | 53 ++++++++ .../core/providers/torrent/couchtater/main.py | 121 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 couchpotato/core/providers/torrent/couchtater/__init__.py create mode 100644 couchpotato/core/providers/torrent/couchtater/main.py diff --git a/couchpotato/core/providers/torrent/couchtater/__init__.py b/couchpotato/core/providers/torrent/couchtater/__init__.py new file mode 100644 index 00000000..1b1cf9c5 --- /dev/null +++ b/couchpotato/core/providers/torrent/couchtater/__init__.py @@ -0,0 +1,53 @@ +from .main import Couchtarter + +def start(): + return Couchtarter() + +config = [{ + 'name': 'couchtart', + 'groups': [ + { + 'tab': 'searcher', + 'list': 'torrent_providers', + 'name': 'couchtart', + 'order': 10, + 'description': 'Cocuhtart providers.', + 'wizard': True, + 'options': [ + { + 'name': 'enabled', + 'type': 'enabler', + 'default': True, + }, + { + 'name': 'use', + 'default': '0,0,0,0,0,0' + }, + { + 'name': 'host', + 'default': '', + 'description': 'The url path of your Couchtart provider.', + }, + { + 'name': 'extra_score', + 'advanced': True, + 'label': 'Extra Score', + 'default': '0', + 'description': 'Starting score for each release found via this provider.', + }, + { + 'name': 'username', + 'default': '', + }, + { + 'name': 'pass_key', + 'default': ',', + 'label': 'Pass Key', + 'description': 'Can be found on your profile page', + 'type': 'combined', + 'combine': ['use', 'host', 'username', 'pass_key', 'extra_score'], + }, + ], + }, + ], +}] diff --git a/couchpotato/core/providers/torrent/couchtater/main.py b/couchpotato/core/providers/torrent/couchtater/main.py new file mode 100644 index 00000000..c7d2fa5a --- /dev/null +++ b/couchpotato/core/providers/torrent/couchtater/main.py @@ -0,0 +1,121 @@ +from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode +from couchpotato.core.helpers.variable import splitString, tryInt +from couchpotato.core.logger import CPLog +from couchpotato.core.providers.base import ResultList +from couchpotato.core.providers.torrent.base import TorrentProvider +from couchpotato.environment import Env +import traceback + +log = CPLog(__name__) + +class Couchtarter(TorrentProvider): + + limits_reached = {} + + http_time_between_calls = 1 # Seconds + + def search(self, movie, quality): + hosts = self.getHosts() + + results = ResultList(self, movie, quality, imdb_results = True) + + for host in hosts: + if self.isDisabled(host): + continue + + self._searchOnHost(host, movie, quality, results) + + return results + + def _searchOnHost(self, host, movie, quality, results): + + arguments = tryUrlencode({ + 'user': host['username'], + 'passkey': host['pass_key'], + 'imdbid': movie['library']['identifier'].replace('tt', '') + }) + url = '%s&%s' % (host['host'], arguments) + + torrents = self.getJsonData(url, cache_timeout = 1800) + + if torrents: + try: + if torrents.get('Error'): + if 'Incorrect parameters.' in torrents['Error']: + log.error('Wrong parameters passed to: %s', host['host']) + elif 'Death by authorization.' in torrents['Error']: + log.error('Wrong username or pass key for: %s', host['host']) + else: + log.error('Unknown error for: %s', host['host']) + return #(can I disable this host somehow? and notify user?) + + elif torrents.get('Results'): + if 'None found' in torrents['Results']: + return + else: + for torrent in torrents['Results']: + print torrent['ReleaseName'] + print torrent['Size'] + print torrent['DownloadURL'] + #results.append({ + # 'id': tryInt(result['TorrentID']), + # 'name': toUnicode(result['ReleaseName']), + # 'size': tryInt(self.parseSize(result['Size'])), + # 'url': result['DownloadURL'], + # 'detail_url': result['DetailURL'], + # 'resoultion': result['Resolution'], + # 'score': host['extra_score'], + # 'get_more_info': result['IMDbID'] + #}) + + except: + log.error('Failed getting results from %s: %s', (host['host'], traceback.format_exc())) + + def getHosts(self): + + uses = splitString(str(self.conf('use')), clean = False) + hosts = splitString(self.conf('host'), clean = False) + usernames = splitString(self.conf('username'), clean = False) + pass_keys = splitString(self.conf('pass_key'), clean = False) + extra_score = splitString(self.conf('extra_score'), clean = False) + + list = [] + for nr in range(len(hosts)): + + try: key = pass_keys[nr] + except: key = '' + + try: host = hosts[nr] + except: host = '' + + list.append({ + 'use': uses[nr], + 'host': host, + 'pass_key': key, + 'extra_score': tryInt(extra_score[nr]) if len(extra_score) > nr else 0 + }) + + return list + + def belongsTo(self, url, provider = None, host = None): + + hosts = self.getHosts() + + for host in hosts: + result = super(Couchtater, self).belongsTo(url, host = host['host'], provider = provider) + if result: + return result + + def isDisabled(self, host = None): + return not self.isEnabled(host) + + def isEnabled(self, host = None): + + # Return true if at least one is enabled and no host is given + if host is None: + for host in self.getHosts(): + if self.isEnabled(host): + return True + return False + + return TorrentProvider.isEnabled(self) and host['host'] and host['pass_key'] and int(host['use']) From 357166414cd2946656da6d75bac163741d6fc6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20K=C3=A5berg?= Date: Thu, 21 Nov 2013 22:20:45 +0100 Subject: [PATCH 02/21] use .get() and added more options --- .../core/providers/torrent/couchtater/main.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/couchpotato/core/providers/torrent/couchtater/main.py b/couchpotato/core/providers/torrent/couchtater/main.py index c7d2fa5a..79c65110 100644 --- a/couchpotato/core/providers/torrent/couchtater/main.py +++ b/couchpotato/core/providers/torrent/couchtater/main.py @@ -58,14 +58,17 @@ class Couchtarter(TorrentProvider): print torrent['Size'] print torrent['DownloadURL'] #results.append({ - # 'id': tryInt(result['TorrentID']), - # 'name': toUnicode(result['ReleaseName']), - # 'size': tryInt(self.parseSize(result['Size'])), - # 'url': result['DownloadURL'], - # 'detail_url': result['DetailURL'], - # 'resoultion': result['Resolution'], + # 'id': tryInt(result.get('TorrentID')), + # 'name': toUnicode(result.get('ReleaseName')), + # 'url': result.get('DownloadURL'), + # 'detail_url': result.get('DetailURL'), + # 'size': tryInt(self.parseSize(result.get('Size'))), # 'score': host['extra_score'], - # 'get_more_info': result['IMDbID'] + # 'seeders': tryInt(result.get('Seeders'), + # 'leechers': tryInt(result.get('leechers'), + # 'resoultion': result.get('Resolution'), + # 'source': result.get('Media'), + # 'get_more_info': result.get('IMDbID') #}) except: From 8951e9fc9007a4bb08ede97af6493404c38664d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20K=C3=A5berg?= Date: Thu, 21 Nov 2013 22:22:19 +0100 Subject: [PATCH 03/21] typo --- couchpotato/core/providers/torrent/couchtater/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/providers/torrent/couchtater/main.py b/couchpotato/core/providers/torrent/couchtater/main.py index 79c65110..e0262a5c 100644 --- a/couchpotato/core/providers/torrent/couchtater/main.py +++ b/couchpotato/core/providers/torrent/couchtater/main.py @@ -65,7 +65,7 @@ class Couchtarter(TorrentProvider): # 'size': tryInt(self.parseSize(result.get('Size'))), # 'score': host['extra_score'], # 'seeders': tryInt(result.get('Seeders'), - # 'leechers': tryInt(result.get('leechers'), + # 'leechers': tryInt(result.get('Leechers'), # 'resoultion': result.get('Resolution'), # 'source': result.get('Media'), # 'get_more_info': result.get('IMDbID') From 379f62a339e899ee4719d27edc45f75dd2a49c26 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 23 Nov 2013 00:31:26 +0100 Subject: [PATCH 04/21] CouchTater fixes --- .../providers/torrent/couchtater/__init__.py | 16 +++--- .../core/providers/torrent/couchtater/main.py | 57 +++++++++---------- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/couchpotato/core/providers/torrent/couchtater/__init__.py b/couchpotato/core/providers/torrent/couchtater/__init__.py index 1b1cf9c5..9be23f93 100644 --- a/couchpotato/core/providers/torrent/couchtater/__init__.py +++ b/couchpotato/core/providers/torrent/couchtater/__init__.py @@ -1,27 +1,27 @@ -from .main import Couchtarter +from .main import Couchtater def start(): - return Couchtarter() + return Couchtater() config = [{ - 'name': 'couchtart', + 'name': 'couchtater', 'groups': [ { 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'couchtart', 'order': 10, - 'description': 'Cocuhtart providers.', + 'description': 'Couchtater providers.', 'wizard': True, 'options': [ { 'name': 'enabled', 'type': 'enabler', - 'default': True, + 'default': False, }, { 'name': 'use', - 'default': '0,0,0,0,0,0' + 'default': '' }, { 'name': 'host', @@ -36,7 +36,7 @@ config = [{ 'description': 'Starting score for each release found via this provider.', }, { - 'name': 'username', + 'name': 'name', 'default': '', }, { @@ -45,7 +45,7 @@ config = [{ 'label': 'Pass Key', 'description': 'Can be found on your profile page', 'type': 'combined', - 'combine': ['use', 'host', 'username', 'pass_key', 'extra_score'], + 'combine': ['use', 'host', 'name', 'pass_key', 'extra_score'], }, ], }, diff --git a/couchpotato/core/providers/torrent/couchtater/main.py b/couchpotato/core/providers/torrent/couchtater/main.py index e0262a5c..25270b06 100644 --- a/couchpotato/core/providers/torrent/couchtater/main.py +++ b/couchpotato/core/providers/torrent/couchtater/main.py @@ -1,14 +1,14 @@ -from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode +from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.variable import splitString, tryInt from couchpotato.core.logger import CPLog from couchpotato.core.providers.base import ResultList from couchpotato.core.providers.torrent.base import TorrentProvider -from couchpotato.environment import Env import traceback log = CPLog(__name__) -class Couchtarter(TorrentProvider): + +class Couchtater(TorrentProvider): limits_reached = {} @@ -30,17 +30,17 @@ class Couchtarter(TorrentProvider): def _searchOnHost(self, host, movie, quality, results): arguments = tryUrlencode({ - 'user': host['username'], + 'user': host['name'], 'passkey': host['pass_key'], - 'imdbid': movie['library']['identifier'].replace('tt', '') + 'imdbid': movie['library']['identifier'] }) - url = '%s&%s' % (host['host'], arguments) + url = '%s?%s' % (host['host'], arguments) torrents = self.getJsonData(url, cache_timeout = 1800) if torrents: try: - if torrents.get('Error'): + if torrents.get('error'): if 'Incorrect parameters.' in torrents['Error']: log.error('Wrong parameters passed to: %s', host['host']) elif 'Death by authorization.' in torrents['Error']: @@ -49,27 +49,22 @@ class Couchtarter(TorrentProvider): log.error('Unknown error for: %s', host['host']) return #(can I disable this host somehow? and notify user?) - elif torrents.get('Results'): - if 'None found' in torrents['Results']: - return - else: - for torrent in torrents['Results']: - print torrent['ReleaseName'] - print torrent['Size'] - print torrent['DownloadURL'] - #results.append({ - # 'id': tryInt(result.get('TorrentID')), - # 'name': toUnicode(result.get('ReleaseName')), - # 'url': result.get('DownloadURL'), - # 'detail_url': result.get('DetailURL'), - # 'size': tryInt(self.parseSize(result.get('Size'))), - # 'score': host['extra_score'], - # 'seeders': tryInt(result.get('Seeders'), - # 'leechers': tryInt(result.get('Leechers'), - # 'resoultion': result.get('Resolution'), - # 'source': result.get('Media'), - # 'get_more_info': result.get('IMDbID') - #}) + elif torrents.get('results'): + for torrent in torrents['results']: + print torrent + #results.append({ + # 'id': tryInt(result.get('TorrentID')), + # 'name': toUnicode(result.get('ReleaseName')), + # 'url': result.get('DownloadURL'), + # 'detail_url': result.get('DetailURL'), + # 'size': tryInt(self.parseSize(result.get('Size'))), + # 'score': host['extra_score'], + # 'seeders': tryInt(result.get('Seeders'), + # 'leechers': tryInt(result.get('Leechers'), + # 'resoultion': result.get('Resolution'), + # 'source': result.get('Media'), + # 'get_more_info': result.get('IMDbID') + #}) except: log.error('Failed getting results from %s: %s', (host['host'], traceback.format_exc())) @@ -78,7 +73,7 @@ class Couchtarter(TorrentProvider): uses = splitString(str(self.conf('use')), clean = False) hosts = splitString(self.conf('host'), clean = False) - usernames = splitString(self.conf('username'), clean = False) + names = splitString(self.conf('name'), clean = False) pass_keys = splitString(self.conf('pass_key'), clean = False) extra_score = splitString(self.conf('extra_score'), clean = False) @@ -91,9 +86,13 @@ class Couchtarter(TorrentProvider): try: host = hosts[nr] except: host = '' + try: name = names[nr] + except: name = '' + list.append({ 'use': uses[nr], 'host': host, + 'name': name, 'pass_key': key, 'extra_score': tryInt(extra_score[nr]) if len(extra_score) > nr else 0 }) From df60d7059233963acb4da80a524a5edc604e406d Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 23 Nov 2013 12:06:46 +0100 Subject: [PATCH 05/21] Move it --- .../providers/torrent/{couchtater => torrentpotato}/__init__.py | 0 .../core/providers/torrent/{couchtater => torrentpotato}/main.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename couchpotato/core/providers/torrent/{couchtater => torrentpotato}/__init__.py (100%) rename couchpotato/core/providers/torrent/{couchtater => torrentpotato}/main.py (100%) diff --git a/couchpotato/core/providers/torrent/couchtater/__init__.py b/couchpotato/core/providers/torrent/torrentpotato/__init__.py similarity index 100% rename from couchpotato/core/providers/torrent/couchtater/__init__.py rename to couchpotato/core/providers/torrent/torrentpotato/__init__.py diff --git a/couchpotato/core/providers/torrent/couchtater/main.py b/couchpotato/core/providers/torrent/torrentpotato/main.py similarity index 100% rename from couchpotato/core/providers/torrent/couchtater/main.py rename to couchpotato/core/providers/torrent/torrentpotato/main.py From 4b9f9862fc035dcbc83aed62be977c2c1dcd479e Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 23 Nov 2013 12:07:00 +0100 Subject: [PATCH 06/21] Change name and response --- .../torrent/torrentpotato/__init__.py | 12 ++--- .../providers/torrent/torrentpotato/main.py | 44 ++++++++----------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/couchpotato/core/providers/torrent/torrentpotato/__init__.py b/couchpotato/core/providers/torrent/torrentpotato/__init__.py index 9be23f93..3d711e9c 100644 --- a/couchpotato/core/providers/torrent/torrentpotato/__init__.py +++ b/couchpotato/core/providers/torrent/torrentpotato/__init__.py @@ -1,17 +1,17 @@ -from .main import Couchtater +from .main import TorrentPotato def start(): - return Couchtater() + return TorrentPotato() config = [{ - 'name': 'couchtater', + 'name': 'torrentpotato', 'groups': [ { 'tab': 'searcher', 'list': 'torrent_providers', - 'name': 'couchtart', + 'name': 'TorrentPotato', 'order': 10, - 'description': 'Couchtater providers.', + 'description': 'CouchPotato torrent provider providers.', 'wizard': True, 'options': [ { @@ -26,7 +26,7 @@ config = [{ { 'name': 'host', 'default': '', - 'description': 'The url path of your Couchtart provider.', + 'description': 'The url path of your TorrentPotato provider.', }, { 'name': 'extra_score', diff --git a/couchpotato/core/providers/torrent/torrentpotato/main.py b/couchpotato/core/providers/torrent/torrentpotato/main.py index 25270b06..15ab323d 100644 --- a/couchpotato/core/providers/torrent/torrentpotato/main.py +++ b/couchpotato/core/providers/torrent/torrentpotato/main.py @@ -1,15 +1,17 @@ -from couchpotato.core.helpers.encoding import tryUrlencode +from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode from couchpotato.core.helpers.variable import splitString, tryInt from couchpotato.core.logger import CPLog from couchpotato.core.providers.base import ResultList from couchpotato.core.providers.torrent.base import TorrentProvider +import re import traceback log = CPLog(__name__) -class Couchtater(TorrentProvider): +class TorrentPotato(TorrentProvider): + urls = {} limits_reached = {} http_time_between_calls = 1 # Seconds @@ -41,30 +43,20 @@ class Couchtater(TorrentProvider): if torrents: try: if torrents.get('error'): - if 'Incorrect parameters.' in torrents['Error']: - log.error('Wrong parameters passed to: %s', host['host']) - elif 'Death by authorization.' in torrents['Error']: - log.error('Wrong username or pass key for: %s', host['host']) - else: - log.error('Unknown error for: %s', host['host']) - return #(can I disable this host somehow? and notify user?) - + log.error('%s: %s', (torrents.get('error'), host['host'])) elif torrents.get('results'): - for torrent in torrents['results']: - print torrent - #results.append({ - # 'id': tryInt(result.get('TorrentID')), - # 'name': toUnicode(result.get('ReleaseName')), - # 'url': result.get('DownloadURL'), - # 'detail_url': result.get('DetailURL'), - # 'size': tryInt(self.parseSize(result.get('Size'))), - # 'score': host['extra_score'], - # 'seeders': tryInt(result.get('Seeders'), - # 'leechers': tryInt(result.get('Leechers'), - # 'resoultion': result.get('Resolution'), - # 'source': result.get('Media'), - # 'get_more_info': result.get('IMDbID') - #}) + for torrent in torrents.get('results', []): + results.append({ + 'id': torrent.get('torrent_id'), + 'protocol': 'torrent' if re.match('^(http|https|ftp)://.*$', torrent.get('download_url')) else 'torrent_magnet', + 'name': toUnicode(torrent.get('name')), + 'url': torrent.get('download_url'), + 'detail_url': torrent.get('details_url'), + 'size': torrent.get('size'), + 'score': host['extra_score'], + 'seeders': torrent.get('seeders'), + 'leechers': torrent.get('leechers'), + }) except: log.error('Failed getting results from %s: %s', (host['host'], traceback.format_exc())) @@ -104,7 +96,7 @@ class Couchtater(TorrentProvider): hosts = self.getHosts() for host in hosts: - result = super(Couchtater, self).belongsTo(url, host = host['host'], provider = provider) + result = super(TorrentPotato, self).belongsTo(url, host = host['host'], provider = provider) if result: return result From 50262112b8bb8a8e4e26c0af718d677d1cad474f Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 24 Nov 2013 00:27:47 +0100 Subject: [PATCH 07/21] Use release_name --- couchpotato/core/providers/torrent/torrentpotato/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/providers/torrent/torrentpotato/main.py b/couchpotato/core/providers/torrent/torrentpotato/main.py index 15ab323d..99511578 100644 --- a/couchpotato/core/providers/torrent/torrentpotato/main.py +++ b/couchpotato/core/providers/torrent/torrentpotato/main.py @@ -49,7 +49,7 @@ class TorrentPotato(TorrentProvider): results.append({ 'id': torrent.get('torrent_id'), 'protocol': 'torrent' if re.match('^(http|https|ftp)://.*$', torrent.get('download_url')) else 'torrent_magnet', - 'name': toUnicode(torrent.get('name')), + 'name': toUnicode(torrent.get('release_name')), 'url': torrent.get('download_url'), 'detail_url': torrent.get('details_url'), 'size': torrent.get('size'), From 37b98cb83505a078a41ce2bd53c5a6dd12331c17 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 24 Nov 2013 00:52:51 +0100 Subject: [PATCH 08/21] TorrentPotato styling of inputs --- .../torrent/torrentpotato/__init__.py | 5 +++-- couchpotato/static/style/settings.css | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/providers/torrent/torrentpotato/__init__.py b/couchpotato/core/providers/torrent/torrentpotato/__init__.py index 3d711e9c..2e4b4662 100644 --- a/couchpotato/core/providers/torrent/torrentpotato/__init__.py +++ b/couchpotato/core/providers/torrent/torrentpotato/__init__.py @@ -11,7 +11,7 @@ config = [{ 'list': 'torrent_providers', 'name': 'TorrentPotato', 'order': 10, - 'description': 'CouchPotato torrent provider providers.', + 'description': 'CouchPotato torrent provider. Checkout the wiki page about this provider for more info.', 'wizard': True, 'options': [ { @@ -37,6 +37,7 @@ config = [{ }, { 'name': 'name', + 'label': 'Username', 'default': '', }, { @@ -45,7 +46,7 @@ config = [{ 'label': 'Pass Key', 'description': 'Can be found on your profile page', 'type': 'combined', - 'combine': ['use', 'host', 'name', 'pass_key', 'extra_score'], + 'combine': ['use', 'host', 'pass_key', 'name', 'extra_score'], }, ], }, diff --git a/couchpotato/static/style/settings.css b/couchpotato/static/style/settings.css index 744531a9..e47284db 100644 --- a/couchpotato/static/style/settings.css +++ b/couchpotato/static/style/settings.css @@ -546,11 +546,28 @@ display: none; } .page .combined_table .head abbr.host { - margin-right: 190px; + margin-right: 195px; } + .page .combined_table input.host { + width: 215px; + } + .page .combined_table .head abbr.name { + margin-right: 67px; + } + .page .combined_table input.name { + width: 120px; + } .page .combined_table .head abbr.api_key { + margin-right: 178px; + } + .page .combined_table .head abbr.pass_key { margin-right: 171px; } + .page .combined_table input.api_key, + .page .combined_table input.pass_key { + width: 213px; + } + .page .combined_table .head .extra_score, .page .combined_table .extra_score { width: 70px; From 8a58d7f9737a1f1e7ae6dbc64147c87d6f0716f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20K=C3=A5berg?= Date: Sun, 24 Nov 2013 14:51:03 +0100 Subject: [PATCH 09/21] use hostname instead of TorrentPotato (dashboard) --- couchpotato/core/providers/torrent/torrentpotato/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/couchpotato/core/providers/torrent/torrentpotato/main.py b/couchpotato/core/providers/torrent/torrentpotato/main.py index 99511578..70320954 100644 --- a/couchpotato/core/providers/torrent/torrentpotato/main.py +++ b/couchpotato/core/providers/torrent/torrentpotato/main.py @@ -3,6 +3,7 @@ from couchpotato.core.helpers.variable import splitString, tryInt from couchpotato.core.logger import CPLog from couchpotato.core.providers.base import ResultList from couchpotato.core.providers.torrent.base import TorrentProvider +from urlparse import urlparse import re import traceback @@ -49,6 +50,7 @@ class TorrentPotato(TorrentProvider): results.append({ 'id': torrent.get('torrent_id'), 'protocol': 'torrent' if re.match('^(http|https|ftp)://.*$', torrent.get('download_url')) else 'torrent_magnet', + 'provider_extra': urlparse(host['host']).hostname or host['host'], 'name': toUnicode(torrent.get('release_name')), 'url': torrent.get('download_url'), 'detail_url': torrent.get('details_url'), From f3380c4fed0b73da6bca71f5705e21dc69aa1f4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20K=C3=A5berg?= Date: Sun, 24 Nov 2013 19:33:29 +0100 Subject: [PATCH 10/21] seed_time and seed_ratio --- .../providers/torrent/torrentpotato/__init__.py | 14 ++++++++++++++ .../core/providers/torrent/torrentpotato/main.py | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/couchpotato/core/providers/torrent/torrentpotato/__init__.py b/couchpotato/core/providers/torrent/torrentpotato/__init__.py index 2e4b4662..fab6d178 100644 --- a/couchpotato/core/providers/torrent/torrentpotato/__init__.py +++ b/couchpotato/core/providers/torrent/torrentpotato/__init__.py @@ -40,6 +40,20 @@ config = [{ 'label': 'Username', 'default': '', }, + { + 'name': 'seed_ratio', + 'label': 'Seed ratio', + 'type': 'float', + 'default': 1, + 'description': 'Will not be (re)moved until this seed ratio is met.', + }, + { + 'name': 'seed_time', + 'label': 'Seed time', + 'type': 'int', + 'default': 40, + 'description': 'Will not be (re)moved until this seed time (in hours) is met.', + }, { 'name': 'pass_key', 'default': ',', diff --git a/couchpotato/core/providers/torrent/torrentpotato/main.py b/couchpotato/core/providers/torrent/torrentpotato/main.py index 70320954..501dbd56 100644 --- a/couchpotato/core/providers/torrent/torrentpotato/main.py +++ b/couchpotato/core/providers/torrent/torrentpotato/main.py @@ -68,6 +68,8 @@ class TorrentPotato(TorrentProvider): uses = splitString(str(self.conf('use')), clean = False) hosts = splitString(self.conf('host'), clean = False) names = splitString(self.conf('name'), clean = False) + seed_times = splitString(self.conf('seed_time'), clean = False) + seed_ratios = splitString(self.conf('seed_ratio'), clean = False) pass_keys = splitString(self.conf('pass_key'), clean = False) extra_score = splitString(self.conf('extra_score'), clean = False) @@ -83,10 +85,18 @@ class TorrentPotato(TorrentProvider): try: name = names[nr] except: name = '' + try: ratio = seed_ratios + except: ratio = '' + + try: seed_time = seed_times + except: seed_time = '' + list.append({ 'use': uses[nr], 'host': host, 'name': name, + 'seed_ratio': ratio, + 'seed_time': seed_time, 'pass_key': key, 'extra_score': tryInt(extra_score[nr]) if len(extra_score) > nr else 0 }) From 8d2e3a1919db73ae4536c69a18870a64e3cbc0cf Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 24 Nov 2013 21:43:54 +0100 Subject: [PATCH 11/21] Add ratio and seed time styling --- .../torrent/torrentpotato/__init__.py | 8 ++-- .../providers/torrent/torrentpotato/main.py | 8 ++-- couchpotato/static/style/settings.css | 42 ++++++++++--------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/couchpotato/core/providers/torrent/torrentpotato/__init__.py b/couchpotato/core/providers/torrent/torrentpotato/__init__.py index fab6d178..5054f98c 100644 --- a/couchpotato/core/providers/torrent/torrentpotato/__init__.py +++ b/couchpotato/core/providers/torrent/torrentpotato/__init__.py @@ -43,15 +43,13 @@ config = [{ { 'name': 'seed_ratio', 'label': 'Seed ratio', - 'type': 'float', - 'default': 1, + 'default': '1', 'description': 'Will not be (re)moved until this seed ratio is met.', }, { 'name': 'seed_time', 'label': 'Seed time', - 'type': 'int', - 'default': 40, + 'default': '40', 'description': 'Will not be (re)moved until this seed time (in hours) is met.', }, { @@ -60,7 +58,7 @@ config = [{ 'label': 'Pass Key', 'description': 'Can be found on your profile page', 'type': 'combined', - 'combine': ['use', 'host', 'pass_key', 'name', 'extra_score'], + 'combine': ['use', 'host', 'pass_key', 'name', 'seed_ratio', 'seed_time', 'extra_score'], }, ], }, diff --git a/couchpotato/core/providers/torrent/torrentpotato/main.py b/couchpotato/core/providers/torrent/torrentpotato/main.py index 501dbd56..a81d0ed4 100644 --- a/couchpotato/core/providers/torrent/torrentpotato/main.py +++ b/couchpotato/core/providers/torrent/torrentpotato/main.py @@ -1,5 +1,5 @@ from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode -from couchpotato.core.helpers.variable import splitString, tryInt +from couchpotato.core.helpers.variable import splitString, tryInt, tryFloat from couchpotato.core.logger import CPLog from couchpotato.core.providers.base import ResultList from couchpotato.core.providers.torrent.base import TorrentProvider @@ -58,6 +58,8 @@ class TorrentPotato(TorrentProvider): 'score': host['extra_score'], 'seeders': torrent.get('seeders'), 'leechers': torrent.get('leechers'), + 'seed_ratio': host['seed_ratio'], + 'seed_time': host['seed_time'], }) except: @@ -95,8 +97,8 @@ class TorrentPotato(TorrentProvider): 'use': uses[nr], 'host': host, 'name': name, - 'seed_ratio': ratio, - 'seed_time': seed_time, + 'seed_ratio': tryFloat(ratio), + 'seed_time': tryInt(seed_time), 'pass_key': key, 'extra_score': tryInt(extra_score[nr]) if len(extra_score) > nr else 0 }) diff --git a/couchpotato/static/style/settings.css b/couchpotato/static/style/settings.css index e47284db..0ee7479a 100644 --- a/couchpotato/static/style/settings.css +++ b/couchpotato/static/style/settings.css @@ -545,28 +545,30 @@ .page .combined_table .head abbr:first-child { display: none; } - .page .combined_table .head abbr.host { - margin-right: 195px; + .page .combined_table .head abbr.host { margin-right: 120px; } + .page .combined_table input.host { width: 140px; } + .page .section_newznab .combined_table .head abbr.host { margin-right: 200px; } + .page .section_newznab .combined_table input.host { width: 220px; } + + .page .combined_table .head abbr.name { margin-right: 57px; } + .page .combined_table input.name { width: 120px; } + .page .combined_table .head abbr.api_key { margin-right: 75px; } + + .page .combined_table .head abbr.pass_key { margin-right: 71px; } + .page .combined_table input.pass_key { width: 113px; } + + .page .section_newznab .combined_table .head abbr.api_key { margin-right: 185px; } + .page .section_newznab .combined_table input.api_key { width: 223px; } + + .page .combined_table .seed_ratio, + .page .combined_table .seed_time { + width: 70px; + text-align: center; + margin-left: 10px; } - .page .combined_table input.host { - width: 215px; - } - .page .combined_table .head abbr.name { - margin-right: 67px; + .page .combined_table .seed_time { + margin-right: 10px; } - .page .combined_table input.name { - width: 120px; - } - .page .combined_table .head abbr.api_key { - margin-right: 178px; - } - .page .combined_table .head abbr.pass_key { - margin-right: 171px; - } - .page .combined_table input.api_key, - .page .combined_table input.pass_key { - width: 213px; - } .page .combined_table .head .extra_score, .page .combined_table .extra_score { From e9a3059be2592e3334e5cde1f131a4816504c212 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 25 Nov 2013 22:16:02 +0100 Subject: [PATCH 12/21] Allow longer description in formhint --- .../static/scripts/library/mootools_more.js | 265 +++++++++++++++++- couchpotato/static/scripts/page/settings.js | 64 ++++- couchpotato/static/style/settings.css | 18 +- 3 files changed, 334 insertions(+), 13 deletions(-) diff --git a/couchpotato/static/scripts/library/mootools_more.js b/couchpotato/static/scripts/library/mootools_more.js index d2d70369..d51c4c15 100644 --- a/couchpotato/static/scripts/library/mootools_more.js +++ b/couchpotato/static/scripts/library/mootools_more.js @@ -1,6 +1,6 @@ // MooTools: the javascript framework. -// Load this file's selection again by visiting: http://mootools.net/more/43db227db7a621ebb062ee621432ae3d -// Or build this file again with packager using: packager build More/Events.Pseudos More/Date More/Date.Extras More/Element.Forms More/Element.Position More/Element.Shortcuts More/Fx.Scroll More/Fx.Slide More/Sortables More/Request.JSONP More/Request.Periodical +// Load this file's selection again by visiting: http://mootools.net/more/7a819726f7f5e85fc48bef295ff78dbe +// Or build this file again with packager using: packager build More/Events.Pseudos More/Date More/Date.Extras More/Element.Forms More/Element.Position More/Element.Shortcuts More/Fx.Scroll More/Fx.Slide More/Sortables More/Request.JSONP More/Request.Periodical More/Tips /* --- @@ -3161,3 +3161,264 @@ Request.implement({ }); + +/* +--- + +script: Tips.js + +name: Tips + +description: Class for creating nice tips that follow the mouse cursor when hovering an element. + +license: MIT-style license + +authors: + - Valerio Proietti + - Christoph Pojer + - Luis Merino + +requires: + - Core/Options + - Core/Events + - Core/Element.Event + - Core/Element.Style + - Core/Element.Dimensions + - /MooTools.More + +provides: [Tips] + +... +*/ + +(function(){ + +var read = function(option, element){ + return (option) ? (typeOf(option) == 'function' ? option(element) : element.get(option)) : ''; +}; + +this.Tips = new Class({ + + Implements: [Events, Options], + + options: {/* + id: null, + onAttach: function(element){}, + onDetach: function(element){}, + onBound: function(coords){},*/ + onShow: function(){ + this.tip.setStyle('display', 'block'); + }, + onHide: function(){ + this.tip.setStyle('display', 'none'); + }, + title: 'title', + text: function(element){ + return element.get('rel') || element.get('href'); + }, + showDelay: 100, + hideDelay: 100, + className: 'tip-wrap', + offset: {x: 16, y: 16}, + windowPadding: {x:0, y:0}, + fixed: false, + waiAria: true + }, + + initialize: function(){ + var params = Array.link(arguments, { + options: Type.isObject, + elements: function(obj){ + return obj != null; + } + }); + this.setOptions(params.options); + if (params.elements) this.attach(params.elements); + this.container = new Element('div', {'class': 'tip'}); + + if (this.options.id){ + this.container.set('id', this.options.id); + if (this.options.waiAria) this.attachWaiAria(); + } + }, + + toElement: function(){ + if (this.tip) return this.tip; + + this.tip = new Element('div', { + 'class': this.options.className, + styles: { + position: 'absolute', + top: 0, + left: 0 + } + }).adopt( + new Element('div', {'class': 'tip-top'}), + this.container, + new Element('div', {'class': 'tip-bottom'}) + ); + + return this.tip; + }, + + attachWaiAria: function(){ + var id = this.options.id; + this.container.set('role', 'tooltip'); + + if (!this.waiAria){ + this.waiAria = { + show: function(element){ + if (id) element.set('aria-describedby', id); + this.container.set('aria-hidden', 'false'); + }, + hide: function(element){ + if (id) element.erase('aria-describedby'); + this.container.set('aria-hidden', 'true'); + } + }; + } + this.addEvents(this.waiAria); + }, + + detachWaiAria: function(){ + if (this.waiAria){ + this.container.erase('role'); + this.container.erase('aria-hidden'); + this.removeEvents(this.waiAria); + } + }, + + attach: function(elements){ + $$(elements).each(function(element){ + var title = read(this.options.title, element), + text = read(this.options.text, element); + + element.set('title', '').store('tip:native', title).retrieve('tip:title', title); + element.retrieve('tip:text', text); + this.fireEvent('attach', [element]); + + var events = ['enter', 'leave']; + if (!this.options.fixed) events.push('move'); + + events.each(function(value){ + var event = element.retrieve('tip:' + value); + if (!event) event = function(event){ + this['element' + value.capitalize()].apply(this, [event, element]); + }.bind(this); + + element.store('tip:' + value, event).addEvent('mouse' + value, event); + }, this); + }, this); + + return this; + }, + + detach: function(elements){ + $$(elements).each(function(element){ + ['enter', 'leave', 'move'].each(function(value){ + element.removeEvent('mouse' + value, element.retrieve('tip:' + value)).eliminate('tip:' + value); + }); + + this.fireEvent('detach', [element]); + + if (this.options.title == 'title'){ // This is necessary to check if we can revert the title + var original = element.retrieve('tip:native'); + if (original) element.set('title', original); + } + }, this); + + return this; + }, + + elementEnter: function(event, element){ + clearTimeout(this.timer); + this.timer = (function(){ + this.container.empty(); + + ['title', 'text'].each(function(value){ + var content = element.retrieve('tip:' + value); + var div = this['_' + value + 'Element'] = new Element('div', { + 'class': 'tip-' + value + }).inject(this.container); + if (content) this.fill(div, content); + }, this); + this.show(element); + this.position((this.options.fixed) ? {page: element.getPosition()} : event); + }).delay(this.options.showDelay, this); + }, + + elementLeave: function(event, element){ + clearTimeout(this.timer); + this.timer = this.hide.delay(this.options.hideDelay, this, element); + this.fireForParent(event, element); + }, + + setTitle: function(title){ + if (this._titleElement){ + this._titleElement.empty(); + this.fill(this._titleElement, title); + } + return this; + }, + + setText: function(text){ + if (this._textElement){ + this._textElement.empty(); + this.fill(this._textElement, text); + } + return this; + }, + + fireForParent: function(event, element){ + element = element.getParent(); + if (!element || element == document.body) return; + if (element.retrieve('tip:enter')) element.fireEvent('mouseenter', event); + else this.fireForParent(event, element); + }, + + elementMove: function(event, element){ + this.position(event); + }, + + position: function(event){ + if (!this.tip) document.id(this); + + var size = window.getSize(), scroll = window.getScroll(), + tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight}, + props = {x: 'left', y: 'top'}, + bounds = {y: false, x2: false, y2: false, x: false}, + obj = {}; + + for (var z in props){ + obj[props[z]] = event.page[z] + this.options.offset[z]; + if (obj[props[z]] < 0) bounds[z] = true; + if ((obj[props[z]] + tip[z] - scroll[z]) > size[z] - this.options.windowPadding[z]){ + obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z]; + bounds[z+'2'] = true; + } + } + + this.fireEvent('bound', bounds); + this.tip.setStyles(obj); + }, + + fill: function(element, contents){ + if (typeof contents == 'string') element.set('html', contents); + else element.adopt(contents); + }, + + show: function(element){ + if (!this.tip) document.id(this); + if (!this.tip.getParent()) this.tip.inject(document.body); + this.fireEvent('show', [this.tip, element]); + }, + + hide: function(element){ + if (!this.tip) document.id(this); + this.fireEvent('hide', [this.tip, element]); + } + +}); + +})(); + diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js index 213c0d96..d4c65e3c 100644 --- a/couchpotato/static/scripts/page/settings.js +++ b/couchpotato/static/scripts/page/settings.js @@ -265,16 +265,37 @@ Page.Settings = new Class({ }, createGroup: function(group){ + + if((typeOf(group.description) == 'array')){ + var hint = new Element('span.hint.more_hint', { + 'html': group.description[0], + 'title': group.description[1] + }); + var tip = new Tips(hint, { + 'fixed': true, + 'offset': {'x': 0, 'y': 0}, + 'onShow': function(tip, hint){ + tip.setStyles({ + 'margin-top': hint.getSize().y, + 'visibility': 'hidden', + 'display': 'block' + }).fade('in'); + } + }); + } + else { + var hint = new Element('span.hint', { + 'html': group.description || '' + }) + } + + return new Element('fieldset', { 'class': (group.advanced ? 'inlineLabels advanced' : 'inlineLabels') + ' group_' + (group.name || '') + ' subtab_' + (group.subtab || '') - }).adopt( + }).grab( new Element('h2', { 'text': group.label || (group.name).capitalize() - }).adopt( - new Element('span.hint', { - 'html': group.description || '' - }) - ) + }).grab(hint) ); }, @@ -343,10 +364,33 @@ var OptionBase = new Class({ createHint: function(){ var self = this; - if(self.options.description) - new Element('p.formHint', { - 'html': self.options.description - }).inject(self.el); + if(self.options.description){ + + + if((typeOf(self.options.description) == 'array')){ + var hint = new Element('p.formHint.more_hint', { + 'html': self.options.description[0], + 'title': self.options.description[1] + }).inject(self.el); + var tip = new Tips(hint, { + 'fixed': true, + 'offset': {'x': 0, 'y': 0}, + 'onShow': function(tip, hint){ + tip.setStyles({ + 'margin-left': 13, + 'margin-top': hint.getSize().y+3, + 'visibility': 'hidden', + 'display': 'block' + }).fade('in'); + } + }); + } + else { + var hint = new Element('p.formHint', { + 'html': self.options.description || '' + }).inject(self.el) + } + } }, afterInject: function(){ diff --git a/couchpotato/static/style/settings.css b/couchpotato/static/style/settings.css index 744531a9..996d04f3 100644 --- a/couchpotato/static/style/settings.css +++ b/couchpotato/static/style/settings.css @@ -699,4 +699,20 @@ .active .group_imdb_automation:not(.disabled) { background: url('../images/imdb_watchlist.png') no-repeat right 50px; min-height: 210px; -} \ No newline at end of file +} + +.tip-wrap { + background: #FFF; + color: #000; + padding: 10px; + width: 300px; + z-index: 200; +} + .more_hint:after { + position: relative; + font-family: 'Elusive-Icons'; + content: "\e089"; + display: inline-block; + top: 1px; + left: 6px; + } \ No newline at end of file From ccc2028690c217322d9711a171325e026f5adf75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20K=C3=A5berg?= Date: Tue, 26 Nov 2013 15:51:12 +0100 Subject: [PATCH 13/21] remove directory option in utorrent doesn't behave as expected on windows --- couchpotato/core/downloaders/utorrent/__init__.py | 5 ----- couchpotato/core/downloaders/utorrent/main.py | 10 ++-------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/couchpotato/core/downloaders/utorrent/__init__.py b/couchpotato/core/downloaders/utorrent/__init__.py index 0c4c323c..d45e2e6c 100644 --- a/couchpotato/core/downloaders/utorrent/__init__.py +++ b/couchpotato/core/downloaders/utorrent/__init__.py @@ -36,11 +36,6 @@ config = [{ 'name': 'label', 'description': 'Label to add torrent as.', }, - { - 'name': 'directory', - 'type': 'directory', - 'description': 'Download to this directory. Keep empty for default uTorrent download directory.', - }, { 'name': 'remove_complete', 'label': 'Remove torrent', diff --git a/couchpotato/core/downloaders/utorrent/main.py b/couchpotato/core/downloaders/utorrent/main.py index e05d1043..9ae5fcb3 100644 --- a/couchpotato/core/downloaders/utorrent/main.py +++ b/couchpotato/core/downloaders/utorrent/main.py @@ -92,12 +92,6 @@ class uTorrent(Downloader): if len(torrent_hash) == 32: torrent_hash = b16encode(b32decode(torrent_hash)) - # Set download directory - if self.conf('directory'): - directory = self.conf('directory') - else: - directory = False - # Send request to uTorrent if data.get('protocol') == 'torrent_magnet': self.utorrent_api.add_torrent_uri(torrent_filename, data.get('url'), directory) @@ -256,13 +250,13 @@ class uTorrentAPI(object): def add_torrent_uri(self, filename, torrent, add_folder = False): action = "action=add-url&s=%s" % urllib.quote(torrent) if add_folder: - action += "&path=%s" % urllib.quote(add_folder) + action += "&path=%s" % urllib.quote(filename) return self._request(action) def add_torrent_file(self, filename, filedata, add_folder = False): action = "action=add-file" if add_folder: - action += "&path=%s" % urllib.quote(add_folder) + action += "&path=%s" % urllib.quote(filename) return self._request(action, {"torrent_file": (ss(filename), filedata)}) def set_torrent(self, hash, params): From 3e2e6385cf4b7413c4159f2e7277879147eb47e2 Mon Sep 17 00:00:00 2001 From: Ruud Burger Date: Tue, 26 Nov 2013 17:10:56 +0100 Subject: [PATCH 14/21] Properly split seed ratios and seed times --- couchpotato/core/providers/torrent/torrentpotato/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/providers/torrent/torrentpotato/main.py b/couchpotato/core/providers/torrent/torrentpotato/main.py index a81d0ed4..a76c0c8f 100644 --- a/couchpotato/core/providers/torrent/torrentpotato/main.py +++ b/couchpotato/core/providers/torrent/torrentpotato/main.py @@ -87,10 +87,10 @@ class TorrentPotato(TorrentProvider): try: name = names[nr] except: name = '' - try: ratio = seed_ratios + try: ratio = seed_ratios[nr] except: ratio = '' - try: seed_time = seed_times + try: seed_time = seed_times[nr] except: seed_time = '' list.append({ From 2e96860380e4ce9490a5c7153bbc1d2f257b3165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20K=C3=A5berg?= Date: Wed, 27 Nov 2013 07:58:23 +0100 Subject: [PATCH 15/21] directory properly removed --- couchpotato/core/downloaders/utorrent/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/downloaders/utorrent/main.py b/couchpotato/core/downloaders/utorrent/main.py index 9ae5fcb3..182d932f 100644 --- a/couchpotato/core/downloaders/utorrent/main.py +++ b/couchpotato/core/downloaders/utorrent/main.py @@ -94,9 +94,9 @@ class uTorrent(Downloader): # Send request to uTorrent if data.get('protocol') == 'torrent_magnet': - self.utorrent_api.add_torrent_uri(torrent_filename, data.get('url'), directory) + self.utorrent_api.add_torrent_uri(torrent_filename, data.get('url')) else: - self.utorrent_api.add_torrent_file(torrent_filename, filedata, directory) + self.utorrent_api.add_torrent_file(torrent_filename, filedata) # Change settings of added torrent self.utorrent_api.set_torrent(torrent_hash, torrent_params) From d833a04293a34a458ac3be2c4fbf8c8112a3f578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20K=C3=A5berg?= Date: Fri, 29 Nov 2013 22:10:02 +0100 Subject: [PATCH 16/21] move long texts into formhint --- couchpotato/core/plugins/renamer/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/plugins/renamer/__init__.py b/couchpotato/core/plugins/renamer/__init__.py index c8f6b37f..8b602cbd 100755 --- a/couchpotato/core/plugins/renamer/__init__.py +++ b/couchpotato/core/plugins/renamer/__init__.py @@ -93,7 +93,7 @@ config = [{ 'default': 1, 'type': 'int', 'unit': 'min(s)', - 'description': 'Detect movie status every X minutes. Will start the renamer if movie is completed or handle failed download if these options are enabled', + 'description': ('Detect movie status every X minutes.', 'Will start the renamer if movie is completed or handle failed download if these options are enabled'), }, { 'advanced': True, @@ -122,13 +122,13 @@ config = [{ 'advanced': True, 'name': 'separator', 'label': 'File-Separator', - 'description': 'Replace all the spaces with a character. Example: ".", "-" (without quotes). Leave empty to use spaces.', + 'description': ('Replace all the spaces with a character.', 'Example: ".", "-" (without quotes). Leave empty to use spaces.'), }, { 'advanced': True, 'name': 'foldersep', 'label': 'Folder-Separator', - 'description': 'Replace all the spaces with a character. Example: ".", "-" (without quotes). Leave empty to use spaces.', + 'description': ('Replace all the spaces with a character.', 'Example: ".", "-" (without quotes). Leave empty to use spaces.'), }, { 'name': 'file_action', @@ -136,7 +136,7 @@ config = [{ 'default': 'link', 'type': 'dropdown', 'values': [('Link', 'link'), ('Copy', 'copy'), ('Move', 'move')], - 'description': 'Link or Copy after downloading completed (and allow for seeding), or Move after seeding completed. Link first tries hard link, then sym link and falls back to Copy.', + 'description': ('Link, Copy or Move after download completed.', 'Link first tries hard link, then sym link and falls back to Copy. It is perfered to use link when downloading torrents as it will save you space, while still beeing able to seed.'), 'advanced': True, }, { From 76f3f5253ac858e9c68fb1fa1ee02306b788b122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20K=C3=A5berg?= Date: Fri, 29 Nov 2013 22:14:28 +0100 Subject: [PATCH 17/21] move long automation text into formhint --- couchpotato/core/plugins/automation/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/automation/__init__.py b/couchpotato/core/plugins/automation/__init__.py index 440232b2..a81719c4 100644 --- a/couchpotato/core/plugins/automation/__init__.py +++ b/couchpotato/core/plugins/automation/__init__.py @@ -41,7 +41,7 @@ config = [{ 'label': 'Required Genres', 'default': '', 'placeholder': 'Example: Action, Crime & Drama', - 'description': 'Ignore movies that don\'t contain at least one set of genres. Sets are separated by "," and each word within a set must be separated with "&"' + 'description': ('Ignore movies that don\'t contain at least one set of genres.', 'Sets are separated by "," and each word within a set must be separated with "&"') }, { 'name': 'ignored_genres', From cddf47f1131bca6902491c8e3a381864a77ce7ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20K=C3=A5berg?= Date: Fri, 29 Nov 2013 22:28:51 +0100 Subject: [PATCH 18/21] move long subtitle text into formhint --- couchpotato/core/plugins/subtitle/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/subtitle/__init__.py b/couchpotato/core/plugins/subtitle/__init__.py index bbd40853..fcff4cdf 100644 --- a/couchpotato/core/plugins/subtitle/__init__.py +++ b/couchpotato/core/plugins/subtitle/__init__.py @@ -20,7 +20,7 @@ config = [{ }, { 'name': 'languages', - 'description': 'Comma separated, 2 letter country code. Example: en, nl. See the codes at on Wikipedia', + 'description': ('Comma separated, 2 letter country code.', 'Example: en, nl. See the codes at on Wikipedia'), }, # { # 'name': 'automatic', From 0f071be762c8613b00550dbc8bd397f80bb8a9aa Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 30 Nov 2013 11:52:41 +0100 Subject: [PATCH 19/21] Use Object.each for object looping --- couchpotato/core/media/movie/_base/static/movie.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/movie/_base/static/movie.js b/couchpotato/core/media/movie/_base/static/movie.js index bc258451..9c0ae015 100644 --- a/couchpotato/core/media/movie/_base/static/movie.js +++ b/couchpotato/core/media/movie/_base/static/movie.js @@ -78,9 +78,9 @@ var Movie = new Class({ self.list.checkIfEmpty(); // Remove events - self.global_events.each(function(handle, listener){ + Object.each(self.global_events, function(handle, listener){ App.off(listener, handle); - }) + }); }, busy: function(set_busy, timeout){ From bde6de178986596a657b028053e26e33da13e302 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 30 Nov 2013 12:23:53 +0100 Subject: [PATCH 20/21] Move movie listing to media --- couchpotato/core/media/_base/media/main.py | 417 +++++++++++++++++- couchpotato/core/media/movie/_base/main.py | 366 +-------------- .../core/media/movie/_base/static/list.js | 7 +- .../media/movie/_base/static/movie.actions.js | 4 +- couchpotato/core/media/movie/searcher/main.py | 6 +- couchpotato/core/plugins/automation/main.py | 4 +- couchpotato/core/plugins/manage/main.py | 6 +- couchpotato/core/plugins/release/main.py | 2 +- couchpotato/core/plugins/renamer/main.py | 2 +- .../core/providers/info/_modifier/main.py | 4 +- 10 files changed, 434 insertions(+), 384 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 68ae5314..851933bd 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -1,10 +1,15 @@ from couchpotato import get_session from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, fireEventAsync, addEvent -from couchpotato.core.helpers.variable import splitString +from couchpotato.core.helpers.encoding import toUnicode +from couchpotato.core.helpers.variable import mergeDicts, splitString, getImdb from couchpotato.core.logger import CPLog from couchpotato.core.media import MediaBase -from couchpotato.core.settings.model import Media +from couchpotato.core.settings.model import Library, LibraryTitle, Release, \ + Media +from sqlalchemy.orm import joinedload_all +from sqlalchemy.sql.expression import or_, asc, not_, desc +from string import ascii_lowercase log = CPLog(__name__) @@ -20,7 +25,49 @@ class MediaPlugin(MediaBase): } }) - addEvent('app.load', self.addSingleRefresh) + addApiView('media.list', self.listView, docs = { + 'desc': 'List media', + 'params': { + 'type': {'type': 'string', 'desc': 'Media type to filter on.'}, + 'status': {'type': 'array or csv', 'desc': 'Filter movie by status. Example:"active,done"'}, + 'release_status': {'type': 'array or csv', 'desc': 'Filter movie by status of its releases. Example:"snatched,available"'}, + 'limit_offset': {'desc': 'Limit and offset the movie list. Examples: "50" or "50,30"'}, + 'starts_with': {'desc': 'Starts with these characters. Example: "a" returns all movies starting with the letter "a"'}, + 'search': {'desc': 'Search movie title'}, + }, + 'return': {'type': 'object', 'example': """{ + 'success': True, + 'empty': bool, any movies returned or not, + 'media': array, media found, +}"""} + }) + + addApiView('media.get', self.getView, docs = { + 'desc': 'Get media by id', + 'params': { + 'id': {'desc': 'The id of the media'}, + } + }) + + addApiView('media.delete', self.deleteView, docs = { + 'desc': 'Delete a media from the wanted list', + 'params': { + 'id': {'desc': 'Media ID(s) you want to delete.', 'type': 'int (comma separated)'}, + 'delete_from': {'desc': 'Delete media from this page', 'type': 'string: all (default), wanted, manage'}, + } + }) + + addApiView('media.available_chars', self.charView) + + addEvent('app.load', self.addSingleRefreshView) + addEvent('app.load', self.addSingleListView) + addEvent('app.load', self.addSingleCharView) + addEvent('app.load', self.addSingleDeleteView) + + addEvent('media.get', self.get) + addEvent('media.list', self.list) + addEvent('media.delete', self.delete) + addEvent('media.restatus', self.restatus) def refresh(self, id = '', **kwargs): db = get_session() @@ -43,7 +90,369 @@ class MediaPlugin(MediaBase): 'success': True, } - def addSingleRefresh(self): + def addSingleRefreshView(self): for media_type in fireEvent('media.types', merge = True): addApiView('%s.refresh' % media_type, self.refresh) + + def get(self, media_id): + + db = get_session() + + imdb_id = getImdb(str(media_id)) + + if imdb_id: + m = db.query(Media).filter(Media.library.has(identifier = imdb_id)).first() + else: + m = db.query(Media).filter_by(id = media_id).first() + + results = None + if m: + results = m.to_dict(self.default_dict) + + db.expire_all() + return results + + def getView(self, id = None, **kwargs): + + movie = self.get(id) if id else None + + return { + 'success': movie is not None, + 'movie': movie, + } + + def list(self, types = None, status = None, release_status = None, limit_offset = None, starts_with = None, search = None, order = None): + + db = get_session() + + # Make a list from string + if status and not isinstance(status, (list, tuple)): + status = [status] + if release_status and not isinstance(release_status, (list, tuple)): + release_status = [release_status] + if types and not isinstance(types, (list, tuple)): + types = [types] + + # query movie ids + q = db.query(Media) \ + .with_entities(Media.id) \ + .group_by(Media.id) + + # Filter on movie status + if status and len(status) > 0: + statuses = fireEvent('status.get', status, single = len(status) > 1) + statuses = [s.get('id') for s in statuses] + + q = q.filter(Media.status_id.in_(statuses)) + + # Filter on release status + if release_status and len(release_status) > 0: + q = q.join(Media.releases) + + statuses = fireEvent('status.get', release_status, single = len(release_status) > 1) + statuses = [s.get('id') for s in statuses] + + q = q.filter(Release.status_id.in_(statuses)) + + # Filter on type + if types and len(types) > 0: + try: q = q.filter(Media.type.in_(types)) + except: pass + + # Only join when searching / ordering + if starts_with or search or order != 'release_order': + q = q.join(Media.library, Library.titles) \ + .filter(LibraryTitle.default == True) + + # Add search filters + filter_or = [] + if starts_with: + starts_with = toUnicode(starts_with.lower()) + if starts_with in ascii_lowercase: + filter_or.append(LibraryTitle.simple_title.startswith(starts_with)) + else: + ignore = [] + for letter in ascii_lowercase: + ignore.append(LibraryTitle.simple_title.startswith(toUnicode(letter))) + filter_or.append(not_(or_(*ignore))) + + if search: + filter_or.append(LibraryTitle.simple_title.like('%%' + search + '%%')) + + if len(filter_or) > 0: + q = q.filter(or_(*filter_or)) + + total_count = q.count() + if total_count == 0: + return 0, [] + + if order == 'release_order': + q = q.order_by(desc(Release.last_edit)) + else: + q = q.order_by(asc(LibraryTitle.simple_title)) + + if limit_offset: + splt = splitString(limit_offset) if isinstance(limit_offset, (str, unicode)) else limit_offset + limit = splt[0] + offset = 0 if len(splt) is 1 else splt[1] + q = q.limit(limit).offset(offset) + + # Get all media_ids in sorted order + media_ids = [m.id for m in q.all()] + + # List release statuses + releases = db.query(Release) \ + .filter(Release.movie_id.in_(media_ids)) \ + .all() + + release_statuses = dict((m, set()) for m in media_ids) + releases_count = dict((m, 0) for m in media_ids) + for release in releases: + release_statuses[release.movie_id].add('%d,%d' % (release.status_id, release.quality_id)) + releases_count[release.movie_id] += 1 + + # Get main movie data + q2 = db.query(Media) \ + .options(joinedload_all('library.titles')) \ + .options(joinedload_all('library.files')) \ + .options(joinedload_all('status')) \ + .options(joinedload_all('files')) + + q2 = q2.filter(Media.id.in_(media_ids)) + + results = q2.all() + + # Create dict by movie id + movie_dict = {} + for movie in results: + movie_dict[movie.id] = movie + + # List movies based on media_ids order + movies = [] + for media_id in media_ids: + + releases = [] + for r in release_statuses.get(media_id): + x = splitString(r) + releases.append({'status_id': x[0], 'quality_id': x[1]}) + + # Merge releases with movie dict + movies.append(mergeDicts(movie_dict[media_id].to_dict({ + 'library': {'titles': {}, 'files':{}}, + 'files': {}, + }), { + 'releases': releases, + 'releases_count': releases_count.get(media_id), + })) + + db.expire_all() + return total_count, movies + + def listView(self, **kwargs): + + types = splitString(kwargs.get('types')) + status = splitString(kwargs.get('status')) + release_status = splitString(kwargs.get('release_status')) + limit_offset = kwargs.get('limit_offset') + starts_with = kwargs.get('starts_with') + search = kwargs.get('search') + order = kwargs.get('order') + + total_movies, movies = self.list( + types = types, + status = status, + release_status = release_status, + limit_offset = limit_offset, + starts_with = starts_with, + search = search, + order = order + ) + + return { + 'success': True, + 'empty': len(movies) == 0, + 'total': total_movies, + 'movies': movies, + } + + def addSingleListView(self): + + for media_type in fireEvent('media.types', merge = True): + def tempList(*args, **kwargs): + return self.listView(types = media_type, *args, **kwargs) + addApiView('%s.list' % media_type, tempList) + + def availableChars(self, types = None, status = None, release_status = None): + + types = types or [] + status = status or [] + release_status = release_status or [] + + db = get_session() + + # Make a list from string + if not isinstance(status, (list, tuple)): + status = [status] + if release_status and not isinstance(release_status, (list, tuple)): + release_status = [release_status] + if types and not isinstance(types, (list, tuple)): + types = [types] + + q = db.query(Media) + + # Filter on movie status + if status and len(status) > 0: + statuses = fireEvent('status.get', status, single = len(release_status) > 1) + statuses = [s.get('id') for s in statuses] + + q = q.filter(Media.status_id.in_(statuses)) + + # Filter on release status + if release_status and len(release_status) > 0: + + statuses = fireEvent('status.get', release_status, single = len(release_status) > 1) + statuses = [s.get('id') for s in statuses] + + q = q.join(Media.releases) \ + .filter(Release.status_id.in_(statuses)) + + # Filter on type + if types and len(types) > 0: + try: q = q.filter(Media.type.in_(types)) + except: pass + + q = q.join(Library, LibraryTitle) \ + .with_entities(LibraryTitle.simple_title) \ + .filter(LibraryTitle.default == True) + + titles = q.all() + + chars = set() + for title in titles: + try: + char = title[0][0] + char = char if char in ascii_lowercase else '#' + chars.add(str(char)) + except: + log.error('Failed getting title for %s', title.libraries_id) + + if len(chars) == 25: + break + + db.expire_all() + return ''.join(sorted(chars)) + + def charView(self, **kwargs): + + type = splitString(kwargs.get('type', 'movie')) + status = splitString(kwargs.get('status', None)) + release_status = splitString(kwargs.get('release_status', None)) + chars = self.availableChars(type, status, release_status) + + return { + 'success': True, + 'empty': len(chars) == 0, + 'chars': chars, + } + + def addSingleCharView(self): + + for media_type in fireEvent('media.types', merge = True): + def tempChar(*args, **kwargs): + return self.charView(types = media_type, *args, **kwargs) + addApiView('%s.available_chars' % media_type, tempChar) + + def delete(self, media_id, delete_from = None): + + db = get_session() + + movie = db.query(Media).filter_by(id = media_id).first() + if movie: + deleted = False + if delete_from == 'all': + db.delete(movie) + db.commit() + deleted = True + else: + done_status = fireEvent('status.get', 'done', single = True) + + total_releases = len(movie.releases) + total_deleted = 0 + new_movie_status = None + for release in movie.releases: + if delete_from in ['wanted', 'snatched', 'late']: + if release.status_id != done_status.get('id'): + db.delete(release) + total_deleted += 1 + new_movie_status = 'done' + elif delete_from == 'manage': + if release.status_id == done_status.get('id'): + db.delete(release) + total_deleted += 1 + new_movie_status = 'active' + db.commit() + + if total_releases == total_deleted: + db.delete(movie) + db.commit() + deleted = True + elif new_movie_status: + new_status = fireEvent('status.get', new_movie_status, single = True) + movie.profile_id = None + movie.status_id = new_status.get('id') + db.commit() + else: + fireEvent('media.restatus', movie.id, single = True) + + if deleted: + fireEvent('notify.frontend', type = 'movie.deleted', data = movie.to_dict()) + + db.expire_all() + return True + + def deleteView(self, id = '', **kwargs): + + ids = splitString(id) + for media_id in ids: + self.delete(media_id, delete_from = kwargs.get('delete_from', 'all')) + + return { + 'success': True, + } + + def addSingleDeleteView(self): + + for media_type in fireEvent('media.types', merge = True): + def tempDelete(*args, **kwargs): + return self.deleteView(types = media_type, *args, **kwargs) + addApiView('%s.delete' % media_type, tempDelete) + + def restatus(self, media_id): + + active_status, done_status = fireEvent('status.get', ['active', 'done'], single = True) + + db = get_session() + + m = db.query(Media).filter_by(id = media_id).first() + if not m or len(m.library.titles) == 0: + log.debug('Can\'t restatus movie, doesn\'t seem to exist.') + return False + + log.debug('Changing status for %s', m.library.titles[0].title) + if not m.profile: + m.status_id = done_status.get('id') + else: + move_to_wanted = True + + for t in m.profile.types: + for release in m.releases: + if t.quality.identifier is release.quality.identifier and (release.status_id is done_status.get('id') and t.finish): + move_to_wanted = False + + m.status_id = active_status.get('id') if move_to_wanted else done_status.get('id') + + db.commit() + + return True + diff --git a/couchpotato/core/media/movie/_base/main.py b/couchpotato/core/media/movie/_base/main.py index 3ca36eda..aa8c5130 100644 --- a/couchpotato/core/media/movie/_base/main.py +++ b/couchpotato/core/media/movie/_base/main.py @@ -2,15 +2,10 @@ from couchpotato import get_session from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, fireEventAsync, addEvent from couchpotato.core.helpers.encoding import toUnicode -from couchpotato.core.helpers.variable import getImdb, splitString, tryInt, \ - mergeDicts +from couchpotato.core.helpers.variable import splitString, tryInt from couchpotato.core.logger import CPLog from couchpotato.core.media.movie import MovieTypeBase -from couchpotato.core.settings.model import Library, LibraryTitle, Media, \ - Release -from sqlalchemy.orm import joinedload_all -from sqlalchemy.sql.expression import or_, asc, not_, desc -from string import ascii_lowercase +from couchpotato.core.settings.model import Media import time log = CPLog(__name__) @@ -26,28 +21,6 @@ class MovieBase(MovieTypeBase): super(MovieBase, self).__init__() self.initType() - addApiView('movie.list', self.listView, docs = { - 'desc': 'List movies in wanted list', - 'params': { - 'status': {'type': 'array or csv', 'desc': 'Filter movie by status. Example:"active,done"'}, - 'release_status': {'type': 'array or csv', 'desc': 'Filter movie by status of its releases. Example:"snatched,available"'}, - 'limit_offset': {'desc': 'Limit and offset the movie list. Examples: "50" or "50,30"'}, - 'starts_with': {'desc': 'Starts with these characters. Example: "a" returns all movies starting with the letter "a"'}, - 'search': {'desc': 'Search movie title'}, - }, - 'return': {'type': 'object', 'example': """{ - 'success': True, - 'empty': bool, any movies returned or not, - 'movies': array, movies found, -}"""} - }) - addApiView('movie.get', self.getView, docs = { - 'desc': 'Get a movie by id', - 'params': { - 'id': {'desc': 'The id of the movie'}, - } - }) - addApiView('movie.available_chars', self.charView) addApiView('movie.add', self.addView, docs = { 'desc': 'Add new movie to the wanted list', 'params': { @@ -65,255 +38,8 @@ class MovieBase(MovieTypeBase): 'default_title': {'desc': 'Movie title to use for searches. Has to be one of the titles returned by movie.search.'}, } }) - addApiView('movie.delete', self.deleteView, docs = { - 'desc': 'Delete a movie from the wanted list', - 'params': { - 'id': {'desc': 'Movie ID(s) you want to delete.', 'type': 'int (comma separated)'}, - 'delete_from': {'desc': 'Delete movie from this page', 'type': 'string: all (default), wanted, manage'}, - } - }) addEvent('movie.add', self.add) - addEvent('movie.delete', self.delete) - addEvent('movie.get', self.get) - addEvent('movie.list', self.list) - addEvent('movie.restatus', self.restatus) - - def getView(self, id = None, **kwargs): - - movie = self.get(id) if id else None - - return { - 'success': movie is not None, - 'movie': movie, - } - - def get(self, movie_id): - - db = get_session() - - imdb_id = getImdb(str(movie_id)) - - if imdb_id: - m = db.query(Media).filter(Media.library.has(identifier = imdb_id)).first() - else: - m = db.query(Media).filter_by(id = movie_id).first() - - results = None - if m: - results = m.to_dict(self.default_dict) - - db.expire_all() - return results - - def list(self, status = None, release_status = None, limit_offset = None, starts_with = None, search = None, order = None): - - db = get_session() - - # Make a list from string - if status and not isinstance(status, (list, tuple)): - status = [status] - if release_status and not isinstance(release_status, (list, tuple)): - release_status = [release_status] - - # query movie ids - q = db.query(Media) \ - .with_entities(Media.id) \ - .group_by(Media.id) - - # Filter on movie status - if status and len(status) > 0: - statuses = fireEvent('status.get', status, single = len(status) > 1) - statuses = [s.get('id') for s in statuses] - - q = q.filter(Media.status_id.in_(statuses)) - - # Filter on release status - if release_status and len(release_status) > 0: - q = q.join(Media.releases) - - statuses = fireEvent('status.get', release_status, single = len(release_status) > 1) - statuses = [s.get('id') for s in statuses] - - q = q.filter(Release.status_id.in_(statuses)) - - # Only join when searching / ordering - if starts_with or search or order != 'release_order': - q = q.join(Media.library, Library.titles) \ - .filter(LibraryTitle.default == True) - - # Add search filters - filter_or = [] - if starts_with: - starts_with = toUnicode(starts_with.lower()) - if starts_with in ascii_lowercase: - filter_or.append(LibraryTitle.simple_title.startswith(starts_with)) - else: - ignore = [] - for letter in ascii_lowercase: - ignore.append(LibraryTitle.simple_title.startswith(toUnicode(letter))) - filter_or.append(not_(or_(*ignore))) - - if search: - filter_or.append(LibraryTitle.simple_title.like('%%' + search + '%%')) - - if len(filter_or) > 0: - q = q.filter(or_(*filter_or)) - - total_count = q.count() - if total_count == 0: - return 0, [] - - if order == 'release_order': - q = q.order_by(desc(Release.last_edit)) - else: - q = q.order_by(asc(LibraryTitle.simple_title)) - - if limit_offset: - splt = splitString(limit_offset) if isinstance(limit_offset, (str, unicode)) else limit_offset - limit = splt[0] - offset = 0 if len(splt) is 1 else splt[1] - q = q.limit(limit).offset(offset) - - # Get all movie_ids in sorted order - movie_ids = [m.id for m in q.all()] - - # List release statuses - releases = db.query(Release) \ - .filter(Release.movie_id.in_(movie_ids)) \ - .all() - - release_statuses = dict((m, set()) for m in movie_ids) - releases_count = dict((m, 0) for m in movie_ids) - for release in releases: - release_statuses[release.movie_id].add('%d,%d' % (release.status_id, release.quality_id)) - releases_count[release.movie_id] += 1 - - # Get main movie data - q2 = db.query(Media) \ - .options(joinedload_all('library.titles')) \ - .options(joinedload_all('library.files')) \ - .options(joinedload_all('status')) \ - .options(joinedload_all('files')) - - q2 = q2.filter(Media.id.in_(movie_ids)) - - results = q2.all() - - # Create dict by movie id - movie_dict = {} - for movie in results: - movie_dict[movie.id] = movie - - # List movies based on movie_ids order - movies = [] - for movie_id in movie_ids: - - releases = [] - for r in release_statuses.get(movie_id): - x = splitString(r) - releases.append({'status_id': x[0], 'quality_id': x[1]}) - - # Merge releases with movie dict - movies.append(mergeDicts(movie_dict[movie_id].to_dict({ - 'library': {'titles': {}, 'files':{}}, - 'files': {}, - }), { - 'releases': releases, - 'releases_count': releases_count.get(movie_id), - })) - - db.expire_all() - return total_count, movies - - def availableChars(self, status = None, release_status = None): - - status = status or [] - release_status = release_status or [] - - db = get_session() - - # Make a list from string - if not isinstance(status, (list, tuple)): - status = [status] - if release_status and not isinstance(release_status, (list, tuple)): - release_status = [release_status] - - q = db.query(Media) - - # Filter on movie status - if status and len(status) > 0: - statuses = fireEvent('status.get', status, single = len(release_status) > 1) - statuses = [s.get('id') for s in statuses] - - q = q.filter(Media.status_id.in_(statuses)) - - # Filter on release status - if release_status and len(release_status) > 0: - - statuses = fireEvent('status.get', release_status, single = len(release_status) > 1) - statuses = [s.get('id') for s in statuses] - - q = q.join(Media.releases) \ - .filter(Release.status_id.in_(statuses)) - - q = q.join(Library, LibraryTitle) \ - .with_entities(LibraryTitle.simple_title) \ - .filter(LibraryTitle.default == True) - - titles = q.all() - - chars = set() - for title in titles: - try: - char = title[0][0] - char = char if char in ascii_lowercase else '#' - chars.add(str(char)) - except: - log.error('Failed getting title for %s', title.libraries_id) - - if len(chars) == 25: - break - - db.expire_all() - return ''.join(sorted(chars)) - - def listView(self, **kwargs): - - status = splitString(kwargs.get('status')) - release_status = splitString(kwargs.get('release_status')) - limit_offset = kwargs.get('limit_offset') - starts_with = kwargs.get('starts_with') - search = kwargs.get('search') - order = kwargs.get('order') - - total_movies, movies = self.list( - status = status, - release_status = release_status, - limit_offset = limit_offset, - starts_with = starts_with, - search = search, - order = order - ) - - return { - 'success': True, - 'empty': len(movies) == 0, - 'total': total_movies, - 'movies': movies, - } - - def charView(self, **kwargs): - - status = splitString(kwargs.get('status', None)) - release_status = splitString(kwargs.get('release_status', None)) - chars = self.availableChars(status, release_status) - - return { - 'success': True, - 'empty': len(chars) == 0, - 'chars': chars, - } def add(self, params = None, force_readd = True, search_after = True, update_library = False, status_id = None): if not params: params = {} @@ -447,7 +173,7 @@ class MovieBase(MovieTypeBase): db.commit() - fireEvent('movie.restatus', m.id) + fireEvent('media.restatus', m.id) movie_dict = m.to_dict(self.default_dict) fireEventAsync('movie.searcher.single', movie_dict, on_complete = self.createNotifyFront(movie_id)) @@ -456,89 +182,3 @@ class MovieBase(MovieTypeBase): return { 'success': True, } - - def deleteView(self, id = '', **kwargs): - - ids = splitString(id) - for movie_id in ids: - self.delete(movie_id, delete_from = kwargs.get('delete_from', 'all')) - - return { - 'success': True, - } - - def delete(self, movie_id, delete_from = None): - - db = get_session() - - movie = db.query(Media).filter_by(id = movie_id).first() - if movie: - deleted = False - if delete_from == 'all': - db.delete(movie) - db.commit() - deleted = True - else: - done_status = fireEvent('status.get', 'done', single = True) - - total_releases = len(movie.releases) - total_deleted = 0 - new_movie_status = None - for release in movie.releases: - if delete_from in ['wanted', 'snatched', 'late']: - if release.status_id != done_status.get('id'): - db.delete(release) - total_deleted += 1 - new_movie_status = 'done' - elif delete_from == 'manage': - if release.status_id == done_status.get('id'): - db.delete(release) - total_deleted += 1 - new_movie_status = 'active' - db.commit() - - if total_releases == total_deleted: - db.delete(movie) - db.commit() - deleted = True - elif new_movie_status: - new_status = fireEvent('status.get', new_movie_status, single = True) - movie.profile_id = None - movie.status_id = new_status.get('id') - db.commit() - else: - fireEvent('movie.restatus', movie.id, single = True) - - if deleted: - fireEvent('notify.frontend', type = 'movie.deleted', data = movie.to_dict()) - - db.expire_all() - return True - - def restatus(self, movie_id): - - active_status, done_status = fireEvent('status.get', ['active', 'done'], single = True) - - db = get_session() - - m = db.query(Media).filter_by(id = movie_id).first() - if not m or len(m.library.titles) == 0: - log.debug('Can\'t restatus movie, doesn\'t seem to exist.') - return False - - log.debug('Changing status for %s', m.library.titles[0].title) - if not m.profile: - m.status_id = done_status.get('id') - else: - move_to_wanted = True - - for t in m.profile.types: - for release in m.releases: - if t.quality.identifier is release.quality.identifier and (release.status_id is done_status.get('id') and t.finish): - move_to_wanted = False - - m.status_id = active_status.get('id') if move_to_wanted else done_status.get('id') - - db.commit() - - return True diff --git a/couchpotato/core/media/movie/_base/static/list.js b/couchpotato/core/media/movie/_base/static/list.js index db598b20..85dee2e5 100644 --- a/couchpotato/core/media/movie/_base/static/list.js +++ b/couchpotato/core/media/movie/_base/static/list.js @@ -281,7 +281,7 @@ var MovieList = new Class({ // Get available chars and highlight if(!available_chars && (self.navigation.isDisplayed() || self.navigation.isVisible())) - Api.request('movie.available_chars', { + Api.request('media.available_chars', { 'data': Object.merge({ 'status': self.options.status }, self.filter), @@ -372,7 +372,7 @@ var MovieList = new Class({ 'click': function(e){ (e).preventDefault(); this.set('text', 'Deleting..') - Api.request('movie.delete', { + Api.request('media.delete', { 'data': { 'id': ids.join(','), 'delete_from': self.options.identifier @@ -550,8 +550,9 @@ var MovieList = new Class({ } - Api.request(self.options.api_call || 'movie.list', { + Api.request(self.options.api_call || 'media.list', { 'data': Object.merge({ + 'type': 'movie', 'status': self.options.status, 'limit_offset': self.options.limit ? self.options.limit + ',' + self.offset : null }, self.filter), diff --git a/couchpotato/core/media/movie/_base/static/movie.actions.js b/couchpotato/core/media/movie/_base/static/movie.actions.js index e3591f34..22a55c08 100644 --- a/couchpotato/core/media/movie/_base/static/movie.actions.js +++ b/couchpotato/core/media/movie/_base/static/movie.actions.js @@ -431,7 +431,7 @@ MA.Release = new Class({ markMovieDone: function(){ var self = this; - Api.request('movie.delete', { + Api.request('media.delete', { 'data': { 'id': self.movie.get('id'), 'delete_from': 'wanted' @@ -821,7 +821,7 @@ MA.Delete = new Class({ self.callChain(); }, function(){ - Api.request('movie.delete', { + Api.request('media.delete', { 'data': { 'id': self.movie.get('id'), 'delete_from': self.movie.list.options.identifier diff --git a/couchpotato/core/media/movie/searcher/main.py b/couchpotato/core/media/movie/searcher/main.py index f80f63fe..02b037a4 100644 --- a/couchpotato/core/media/movie/searcher/main.py +++ b/couchpotato/core/media/movie/searcher/main.py @@ -145,7 +145,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): default_title = getTitle(movie['library']) if not default_title: log.error('No proper info found for movie, removing it from library to cause it from having more issues.') - fireEvent('movie.delete', movie['id'], single = True) + fireEvent('media.delete', movie['id'], single = True) return fireEvent('notify.frontend', type = 'movie.searcher.started', data = {'id': movie['id']}, message = 'Searching for "%s"' % default_title) @@ -192,7 +192,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): else: log.info('Better quality (%s) already available or snatched for %s', (quality_type['quality']['label'], default_title)) - fireEvent('movie.restatus', movie['id']) + fireEvent('media.restatus', movie['id']) break # Break if CP wants to shut down @@ -333,7 +333,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): rel.status_id = ignored_status.get('id') db.commit() - movie_dict = fireEvent('movie.get', movie_id, single = True) + movie_dict = fireEvent('media.get', movie_id, single = True) log.info('Trying next release for: %s', getTitle(movie_dict['library'])) fireEvent('movie.searcher.single', movie_dict, manual = manual) diff --git a/couchpotato/core/plugins/automation/main.py b/couchpotato/core/plugins/automation/main.py index 92547cb0..2edcd3be 100644 --- a/couchpotato/core/plugins/automation/main.py +++ b/couchpotato/core/plugins/automation/main.py @@ -43,7 +43,7 @@ class Automation(Plugin): if self.shuttingDown(): break - movie_dict = fireEvent('movie.get', movie_id, single = True) + movie_dict = fireEvent('media.get', movie_id, single = True) fireEvent('movie.searcher.single', movie_dict) - return True \ No newline at end of file + return True diff --git a/couchpotato/core/plugins/manage/main.py b/couchpotato/core/plugins/manage/main.py index 87207615..ebafb8fe 100644 --- a/couchpotato/core/plugins/manage/main.py +++ b/couchpotato/core/plugins/manage/main.py @@ -112,11 +112,11 @@ class Manage(Plugin): if self.conf('cleanup') and full and not self.shuttingDown(): # Get movies with done status - total_movies, done_movies = fireEvent('movie.list', status = 'done', single = True) + total_movies, done_movies = fireEvent('media.list', types = 'movie', status = 'done', single = True) for done_movie in done_movies: if done_movie['library']['identifier'] not in added_identifiers: - fireEvent('movie.delete', movie_id = done_movie['id'], delete_from = 'all') + fireEvent('media.delete', movie_id = done_movie['id'], delete_from = 'all') else: releases = fireEvent('release.for_movie', id = done_movie.get('id'), single = True) @@ -202,7 +202,7 @@ class Manage(Plugin): self.in_progress[folder]['to_go'] -= 1 total = self.in_progress[folder]['total'] - movie_dict = fireEvent('movie.get', identifier, single = True) + movie_dict = fireEvent('media.get', identifier, single = True) fireEvent('notify.frontend', type = 'movie.added', data = movie_dict, message = None if total > 5 else 'Added "%s" to manage.' % getTitle(movie_dict['library'])) diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index a74e853b..37481964 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -142,7 +142,7 @@ class Release(Plugin): except: log.debug('Failed to attach "%s" to release: %s', (added_files, traceback.format_exc())) - fireEvent('movie.restatus', movie.id) + fireEvent('media.restatus', movie.id) return True diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 54bdcdc7..422699e3 100755 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -820,7 +820,7 @@ Remove it if you want it to be renamed (again, or at least let it try again) try: for rel in rels: rel_dict = rel.to_dict({'info': {}}) - movie_dict = fireEvent('movie.get', rel.movie_id, single = True) + movie_dict = fireEvent('media.get', rel.movie_id, single = True) if not isinstance(rel_dict['info'], (dict)): log.error('Faulty release found without any info, ignoring.') diff --git a/couchpotato/core/providers/info/_modifier/main.py b/couchpotato/core/providers/info/_modifier/main.py index 0bb2e6a4..daf2a306 100644 --- a/couchpotato/core/providers/info/_modifier/main.py +++ b/couchpotato/core/providers/info/_modifier/main.py @@ -93,11 +93,11 @@ class MovieResultModifier(Plugin): for movie in l.movies: if movie.status_id == active_status['id']: - temp['in_wanted'] = fireEvent('movie.get', movie.id, single = True) + temp['in_wanted'] = fireEvent('media.get', movie.id, single = True) for release in movie.releases: if release.status_id == done_status['id']: - temp['in_library'] = fireEvent('movie.get', movie.id, single = True) + temp['in_library'] = fireEvent('media.get', movie.id, single = True) except: log.error('Tried getting more info on searched movies: %s', traceback.format_exc()) From 2fc4809821cf7d4b002a41842de313d1db9a0e9d Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 30 Nov 2013 12:41:06 +0100 Subject: [PATCH 21/21] Variable renaming movie to media --- couchpotato/core/downloaders/base.py | 6 ++--- .../core/downloaders/blackhole/main.py | 6 ++--- couchpotato/core/downloaders/deluge/main.py | 7 +++-- couchpotato/core/downloaders/nzbget/main.py | 6 ++--- .../core/downloaders/nzbvortex/main.py | 6 ++--- .../core/downloaders/pneumatic/main.py | 8 +++--- couchpotato/core/downloaders/rtorrent/main.py | 5 +++- couchpotato/core/downloaders/sabnzbd/main.py | 8 +++--- couchpotato/core/downloaders/synology/main.py | 4 +-- .../core/downloaders/transmission/main.py | 4 ++- couchpotato/core/downloaders/utorrent/main.py | 6 ++--- couchpotato/core/media/_base/media/main.py | 26 +++++++++---------- couchpotato/core/plugins/base.py | 12 ++++----- couchpotato/core/plugins/release/main.py | 14 +++++----- couchpotato/core/providers/base.py | 10 +++---- 15 files changed, 68 insertions(+), 60 deletions(-) diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index 9e24d914..b99aacc9 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -49,13 +49,13 @@ class Downloader(Provider): return [] - def _download(self, data = None, movie = None, manual = False, filedata = None): - if not movie: movie = {} + def _download(self, data = None, media = None, manual = False, filedata = None): + if not media: media = {} if not data: data = {} if self.isDisabled(manual, data): return - return self.download(data = data, movie = movie, filedata = filedata) + return self.download(data = data, media = media, filedata = filedata) def _getAllDownloadStatus(self): if self.isDisabled(manual = True, data = {}): diff --git a/couchpotato/core/downloaders/blackhole/main.py b/couchpotato/core/downloaders/blackhole/main.py index 854860cd..93740515 100644 --- a/couchpotato/core/downloaders/blackhole/main.py +++ b/couchpotato/core/downloaders/blackhole/main.py @@ -12,8 +12,8 @@ class Blackhole(Downloader): protocol = ['nzb', 'torrent', 'torrent_magnet'] - def download(self, data = None, movie = None, filedata = None): - if not movie: movie = {} + def download(self, data = None, media = None, filedata = None): + if not media: media = {} if not data: data = {} directory = self.conf('directory') @@ -33,7 +33,7 @@ class Blackhole(Downloader): log.error('No nzb/torrent available: %s', data.get('url')) return False - file_name = self.createFileName(data, filedata, movie) + file_name = self.createFileName(data, filedata, media) full_path = os.path.join(directory, file_name) if self.conf('create_subdir'): diff --git a/couchpotato/core/downloaders/deluge/main.py b/couchpotato/core/downloaders/deluge/main.py index f3a1238f..454a501b 100644 --- a/couchpotato/core/downloaders/deluge/main.py +++ b/couchpotato/core/downloaders/deluge/main.py @@ -32,7 +32,10 @@ class Deluge(Downloader): return self.drpc - def download(self, data, movie, filedata = None): + def download(self, data = None, media = None, filedata = None): + if not media: media = {} + if not data: data = {} + log.info('Sending "%s" (%s) to Deluge.', (data.get('name'), data.get('protocol'))) if not self.connect(): @@ -73,7 +76,7 @@ class Deluge(Downloader): if data.get('protocol') == 'torrent_magnet': remote_torrent = self.drpc.add_torrent_magnet(data.get('url'), options) else: - filename = self.createFileName(data, filedata, movie) + filename = self.createFileName(data, filedata, media) remote_torrent = self.drpc.add_torrent_file(filename, filedata, options) if not remote_torrent: diff --git a/couchpotato/core/downloaders/nzbget/main.py b/couchpotato/core/downloaders/nzbget/main.py index f8506134..1cc2648b 100644 --- a/couchpotato/core/downloaders/nzbget/main.py +++ b/couchpotato/core/downloaders/nzbget/main.py @@ -19,8 +19,8 @@ class NZBGet(Downloader): url = 'http://%(username)s:%(password)s@%(host)s/xmlrpc' - def download(self, data = None, movie = None, filedata = None): - if not movie: movie = {} + def download(self, data = None, media = None, filedata = None): + if not media: media = {} if not data: data = {} if not filedata: @@ -30,7 +30,7 @@ class NZBGet(Downloader): log.info('Sending "%s" to NZBGet.', data.get('name')) url = self.url % {'host': self.conf('host'), 'username': self.conf('username'), 'password': self.conf('password')} - nzb_name = ss('%s.nzb' % self.createNzbName(data, movie)) + nzb_name = ss('%s.nzb' % self.createNzbName(data, media)) rpc = xmlrpclib.ServerProxy(url) try: diff --git a/couchpotato/core/downloaders/nzbvortex/main.py b/couchpotato/core/downloaders/nzbvortex/main.py index f4e233be..9e160486 100644 --- a/couchpotato/core/downloaders/nzbvortex/main.py +++ b/couchpotato/core/downloaders/nzbvortex/main.py @@ -23,13 +23,13 @@ class NZBVortex(Downloader): api_level = None session_id = None - def download(self, data = None, movie = None, filedata = None): - if not movie: movie = {} + def download(self, data = None, media = None, filedata = None): + if not media: media = {} if not data: data = {} # Send the nzb try: - nzb_filename = self.createFileName(data, filedata, movie) + nzb_filename = self.createFileName(data, filedata, media) self.call('nzb/add', params = {'file': (nzb_filename, filedata)}, multipart = True) raw_statuses = self.call('nzb') diff --git a/couchpotato/core/downloaders/pneumatic/main.py b/couchpotato/core/downloaders/pneumatic/main.py index 643350e1..0c2c46d1 100644 --- a/couchpotato/core/downloaders/pneumatic/main.py +++ b/couchpotato/core/downloaders/pneumatic/main.py @@ -12,8 +12,8 @@ class Pneumatic(Downloader): protocol = ['nzb'] strm_syntax = 'plugin://plugin.program.pneumatic/?mode=strm&type=add_file&nzb=%s&nzbname=%s' - def download(self, data = None, movie = None, filedata = None): - if not movie: movie = {} + def download(self, data = None, media = None, filedata = None): + if not media: media = {} if not data: data = {} directory = self.conf('directory') @@ -25,7 +25,7 @@ class Pneumatic(Downloader): log.error('No nzb available!') return False - fullPath = os.path.join(directory, self.createFileName(data, filedata, movie)) + fullPath = os.path.join(directory, self.createFileName(data, filedata, media)) try: if not os.path.isfile(fullPath): @@ -33,7 +33,7 @@ class Pneumatic(Downloader): with open(fullPath, 'wb') as f: f.write(filedata) - nzb_name = self.createNzbName(data, movie) + nzb_name = self.createNzbName(data, media) strm_path = os.path.join(directory, nzb_name) strm_file = open(strm_path + '.strm', 'wb') diff --git a/couchpotato/core/downloaders/rtorrent/main.py b/couchpotato/core/downloaders/rtorrent/main.py index 8381f0a2..0281c49f 100755 --- a/couchpotato/core/downloaders/rtorrent/main.py +++ b/couchpotato/core/downloaders/rtorrent/main.py @@ -77,7 +77,10 @@ class rTorrent(Downloader): return True - def download(self, data, movie, filedata = None): + def download(self, data = None, media = None, filedata = None): + if not media: media = {} + if not data: data = {} + log.debug('Sending "%s" to rTorrent.', (data.get('name'))) if not self.connect(): diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index aba21231..d934e6c9 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -16,8 +16,8 @@ class Sabnzbd(Downloader): protocol = ['nzb'] - def download(self, data = None, movie = None, filedata = None): - if not movie: movie = {} + def download(self, data = None, media = None, filedata = None): + if not media: media = {} if not data: data = {} log.info('Sending "%s" to SABnzbd.', data.get('name')) @@ -25,7 +25,7 @@ class Sabnzbd(Downloader): req_params = { 'cat': self.conf('category'), 'mode': 'addurl', - 'nzbname': self.createNzbName(data, movie), + 'nzbname': self.createNzbName(data, media), 'priority': self.conf('priority'), } @@ -36,7 +36,7 @@ class Sabnzbd(Downloader): return False # If it's a .rar, it adds the .rar extension, otherwise it stays .nzb - nzb_filename = self.createFileName(data, filedata, movie) + nzb_filename = self.createFileName(data, filedata, media) req_params['mode'] = 'addfile' else: req_params['name'] = data.get('url') diff --git a/couchpotato/core/downloaders/synology/main.py b/couchpotato/core/downloaders/synology/main.py index 0721085c..79b8e87a 100644 --- a/couchpotato/core/downloaders/synology/main.py +++ b/couchpotato/core/downloaders/synology/main.py @@ -13,8 +13,8 @@ class Synology(Downloader): protocol = ['nzb', 'torrent', 'torrent_magnet'] log = CPLog(__name__) - def download(self, data = None, movie = None, filedata = None): - if not movie: movie = {} + def download(self, data = None, media = None, filedata = None): + if not media: media = {} if not data: data = {} response = False diff --git a/couchpotato/core/downloaders/transmission/main.py b/couchpotato/core/downloaders/transmission/main.py index 2eabb2e8..c5a55d4b 100644 --- a/couchpotato/core/downloaders/transmission/main.py +++ b/couchpotato/core/downloaders/transmission/main.py @@ -31,7 +31,9 @@ class Transmission(Downloader): return self.trpc - def download(self, data, movie, filedata = None): + def download(self, data = None, media = None, filedata = None): + if not media: media = {} + if not data: data = {} log.info('Sending "%s" (%s) to Transmission.', (data.get('name'), data.get('protocol'))) diff --git a/couchpotato/core/downloaders/utorrent/main.py b/couchpotato/core/downloaders/utorrent/main.py index 182d932f..18b607f0 100644 --- a/couchpotato/core/downloaders/utorrent/main.py +++ b/couchpotato/core/downloaders/utorrent/main.py @@ -36,8 +36,8 @@ class uTorrent(Downloader): return self.utorrent_api - def download(self, data = None, movie = None, filedata = None): - if not movie: movie = {} + def download(self, data = None, media = None, filedata = None): + if not media: media = {} if not data: data = {} log.debug('Sending "%s" (%s) to uTorrent.', (data.get('name'), data.get('protocol'))) @@ -78,7 +78,7 @@ class uTorrent(Downloader): info = bdecode(filedata)["info"] torrent_hash = sha1(benc(info)).hexdigest().upper() - torrent_filename = self.createFileName(data, filedata, movie) + torrent_filename = self.createFileName(data, filedata, media) if data.get('seed_ratio'): torrent_params['seed_override'] = 1 diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 851933bd..86d5a4bc 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -115,11 +115,11 @@ class MediaPlugin(MediaBase): def getView(self, id = None, **kwargs): - movie = self.get(id) if id else None + media = self.get(id) if id else None return { - 'success': movie is not None, - 'movie': movie, + 'success': media is not None, + 'media': media, } def list(self, types = None, status = None, release_status = None, limit_offset = None, starts_with = None, search = None, order = None): @@ -367,20 +367,20 @@ class MediaPlugin(MediaBase): db = get_session() - movie = db.query(Media).filter_by(id = media_id).first() - if movie: + media = db.query(Media).filter_by(id = media_id).first() + if media: deleted = False if delete_from == 'all': - db.delete(movie) + db.delete(media) db.commit() deleted = True else: done_status = fireEvent('status.get', 'done', single = True) - total_releases = len(movie.releases) + total_releases = len(media.releases) total_deleted = 0 new_movie_status = None - for release in movie.releases: + for release in media.releases: if delete_from in ['wanted', 'snatched', 'late']: if release.status_id != done_status.get('id'): db.delete(release) @@ -394,19 +394,19 @@ class MediaPlugin(MediaBase): db.commit() if total_releases == total_deleted: - db.delete(movie) + db.delete(media) db.commit() deleted = True elif new_movie_status: new_status = fireEvent('status.get', new_movie_status, single = True) - movie.profile_id = None - movie.status_id = new_status.get('id') + media.profile_id = None + media.status_id = new_status.get('id') db.commit() else: - fireEvent('media.restatus', movie.id, single = True) + fireEvent('media.restatus', media.id, single = True) if deleted: - fireEvent('notify.frontend', type = 'movie.deleted', data = movie.to_dict()) + fireEvent('notify.frontend', type = 'movie.deleted', data = media.to_dict()) db.expire_all() return True diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index 649e359d..2bc8fb9e 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -289,19 +289,19 @@ class Plugin(object): Env.get('cache').set(cache_key_md5, value, timeout) return value - def createNzbName(self, data, movie): - tag = self.cpTag(movie) + def createNzbName(self, data, media): + tag = self.cpTag(media) return '%s%s' % (toSafeString(toUnicode(data.get('name'))[:127 - len(tag)]), tag) - def createFileName(self, data, filedata, movie): - name = sp(os.path.join(self.createNzbName(data, movie))) + def createFileName(self, data, filedata, media): + name = sp(os.path.join(self.createNzbName(data, media))) if data.get('protocol') == 'nzb' and 'DOCTYPE nzb' not in filedata and '' not in filedata: return '%s.%s' % (name, 'rar') return '%s.%s' % (name, data.get('protocol')) - def cpTag(self, movie): + def cpTag(self, media): if Env.setting('enabled', 'renamer'): - return '.cp(' + movie['library'].get('identifier') + ')' if movie['library'].get('identifier') else '' + return '.cp(' + media['library'].get('identifier') + ')' if media['library'].get('identifier') else '' return '' diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 37481964..be85c87f 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -100,14 +100,14 @@ class Release(Plugin): done_status, snatched_status = fireEvent('status.get', ['done', 'snatched'], single = True) # Add movie - movie = db.query(Media).filter_by(library_id = group['library'].get('id')).first() - if not movie: - movie = Media( + media = db.query(Media).filter_by(library_id = group['library'].get('id')).first() + if not media: + media = Media( library_id = group['library'].get('id'), profile_id = 0, status_id = done_status.get('id') ) - db.add(movie) + db.add(media) db.commit() # Add Release @@ -120,7 +120,7 @@ class Release(Plugin): if not rel: rel = Relea( identifier = identifier, - movie = movie, + movie = media, quality_id = group['meta_data']['quality'].get('id'), status_id = done_status.get('id') ) @@ -142,7 +142,7 @@ class Release(Plugin): except: log.debug('Failed to attach "%s" to release: %s', (added_files, traceback.format_exc())) - fireEvent('media.restatus', movie.id) + fireEvent('media.restatus', media.id) return True @@ -269,7 +269,7 @@ class Release(Plugin): if filedata == 'try_next': return filedata - download_result = fireEvent('download', data = data, movie = media, manual = manual, filedata = filedata, single = True) + download_result = fireEvent('download', data = data, media = media, manual = manual, filedata = filedata, single = True) log.debug('Downloader result: %s', download_result) if download_result: diff --git a/couchpotato/core/providers/base.py b/couchpotato/core/providers/base.py index da27d853..41b1e62f 100644 --- a/couchpotato/core/providers/base.py +++ b/couchpotato/core/providers/base.py @@ -264,14 +264,14 @@ class ResultList(list): result_ids = None provider = None - movie = None + media = None quality = None - def __init__(self, provider, movie, quality, **kwargs): + def __init__(self, provider, media, quality, **kwargs): self.result_ids = [] self.provider = provider - self.movie = movie + self.media = media self.quality = quality self.kwargs = kwargs @@ -285,13 +285,13 @@ class ResultList(list): new_result = self.fillResult(result) - is_correct = fireEvent('searcher.correct_release', new_result, self.movie, self.quality, + is_correct = fireEvent('searcher.correct_release', new_result, self.media, self.quality, imdb_results = self.kwargs.get('imdb_results', False), single = True) if is_correct and new_result['id'] not in self.result_ids: is_correct_weight = float(is_correct) - new_result['score'] += fireEvent('score.calculate', new_result, self.movie, single = True) + new_result['score'] += fireEvent('score.calculate', new_result, self.media, single = True) old_score = new_result['score'] new_result['score'] = int(old_score * is_correct_weight)