From cbecb7430783501b446af94e0cab7496581e7104 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 14 Jun 2014 18:57:27 +0200 Subject: [PATCH 001/117] Show ETA on soon list. fix #2702 --- .../core/media/movie/_base/static/movie.css | 26 ++++++++++++++++++++++ couchpotato/core/media/movie/_base/static/movie.js | 19 ++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/couchpotato/core/media/movie/_base/static/movie.css b/couchpotato/core/media/movie/_base/static/movie.css index 52f503c..311b111 100644 --- a/couchpotato/core/media/movie/_base/static/movie.css +++ b/couchpotato/core/media/movie/_base/static/movie.css @@ -365,6 +365,32 @@ display: none; } + .movies .data .eta { + display: none; + } + + .movies.details_list .data .eta { + position: absolute; + bottom: 0; + right: 0; + display: block; + min-height: 20px; + text-align: right; + font-style: italic; + opacity: .8; + font-size: 11px; + } + + .movies.details_list .movie:hover .data .eta { + display: none; + } + + .movies.thumbs_list .data .eta { + display: block; + position: absolute; + bottom: 40px; + } + .movies .data .quality { position: absolute; bottom: 2px; diff --git a/couchpotato/core/media/movie/_base/static/movie.js b/couchpotato/core/media/movie/_base/static/movie.js index 679bbc2..4788008 100644 --- a/couchpotato/core/media/movie/_base/static/movie.js +++ b/couchpotato/core/media/movie/_base/static/movie.js @@ -136,6 +136,21 @@ var Movie = new Class({ self.el.addClass('status_'+self.get('status')); + var eta = null, + eta_date = null, + now = Math.round(+new Date()/1000); + + if(self.data.info.release_date) + [self.data.info.release_date.dvd, self.data.info.release_date.theater].each(function(timestamp){ + if (timestamp > 0 && (eta == null || Math.abs(timestamp - now) < Math.abs(eta - now))) + eta = timestamp; + }); + + if(eta){ + eta_date = new Date(eta * 1000); + eta_date = eta_date.toLocaleString('en-us', { month: "long" }) + ' ' + eta_date.getFullYear(); + } + self.el.adopt( self.select_checkbox = new Element('input[type=checkbox].inlay', { 'events': { @@ -161,6 +176,10 @@ var Movie = new Class({ self.description = new Element('div.description.tiny_scroll', { 'text': self.data.info.plot }), + self.eta = eta_date && (now+8035200 > eta) ? new Element('div.eta', { + 'text': eta_date, + 'title': 'ETA' + }) : null, self.quality = new Element('div.quality', { 'events': { 'click': function(e){ From 9dd9f850c6a27498e3c18a48107bf28584cd3bc4 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 14 Jun 2014 18:59:52 +0200 Subject: [PATCH 002/117] Treat seeding as "done" --- couchpotato/static/scripts/page/home.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/static/scripts/page/home.js b/couchpotato/static/scripts/page/home.js index 7cde7d2..aff8fbb 100644 --- a/couchpotato/static/scripts/page/home.js +++ b/couchpotato/static/scripts/page/home.js @@ -54,7 +54,7 @@ Page.Home = new Class({ }) ), 'filter': { - 'release_status': 'snatched,seeding,missing,available,downloaded' + 'release_status': 'snatched,missing,available,downloaded' }, 'limit': null, 'onLoaded': function(){ From 58bd9cd7a1af2ff01d3657618d92a7f32e2a98ec Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 15 Jun 2014 14:59:02 +0200 Subject: [PATCH 003/117] Unable to hide & reorder profiles. fix #3437 --- couchpotato/core/plugins/quality/static/quality.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/couchpotato/core/plugins/quality/static/quality.js b/couchpotato/core/plugins/quality/static/quality.js index 29324c2..d233b1c 100644 --- a/couchpotato/core/plugins/quality/static/quality.js +++ b/couchpotato/core/plugins/quality/static/quality.js @@ -8,6 +8,7 @@ var QualityBase = new Class({ self.qualities = data.qualities; + self.profiles_list = null; self.profiles = []; Array.each(data.profiles, self.createProfilesClass.bind(self)); @@ -35,7 +36,7 @@ var QualityBase = new Class({ }).pick(); } catch(e){} - + return {} }, @@ -106,14 +107,13 @@ var QualityBase = new Class({ createProfileOrdering: function(){ var self = this; - var profile_list; self.settings.createGroup({ 'label': 'Profile Defaults', 'description': '(Needs refresh \'' +(App.isMac() ? 'CMD+R' : 'F5')+ '\' after editing)' }).adopt( new Element('.ctrlHolder#profile_ordering').adopt( new Element('label[text=Order]'), - profile_list = new Element('ul'), + self.profiles_list = new Element('ul'), new Element('p.formHint', { 'html': 'Change the order the profiles are in the dropdown list. Uncheck to hide it completely.
First one will be default.' }) @@ -133,7 +133,7 @@ var QualityBase = new Class({ 'text': profile.data.label }), new Element('span.handle') - ).inject(profile_list); + ).inject(self.profiles_list); new Form.Check(check); @@ -141,7 +141,7 @@ var QualityBase = new Class({ // Sortable var sorted_changed = false; - self.profile_sortable = new Sortables(profile_list, { + self.profile_sortable = new Sortables(self.profiles_list, { 'revert': true, 'handle': '.handle', 'opacity': 0.5, @@ -163,7 +163,7 @@ var QualityBase = new Class({ ids = [], hidden = []; - self.profile_sortable.list.getElements('li').each(function(el, nr){ + self.profiles_list.getElements('li').each(function(el, nr){ ids.include(el.get('data-id')); hidden[nr] = +!el.getElement('input[type=checkbox]').get('checked'); }); From a196a499ae0ec48fe22fdba81bb54af46a13d09e Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 15 Jun 2014 22:13:01 +0200 Subject: [PATCH 004/117] Only cache qualities if list length is correct --- couchpotato/core/plugins/quality/main.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 6304924..677ee48 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -95,15 +95,14 @@ class QualityPlugin(Plugin): db = get_db() - qualities = db.all('quality', with_doc = True) - temp = [] - for quality in qualities: - quality = quality['doc'] - q = mergeDicts(self.getQuality(quality.get('identifier')), quality) + for quality in self.qualities: + quality_doc = db.get('quality', quality.get('identifier'), with_doc = True)['doc'] + q = mergeDicts(quality, quality_doc) temp.append(q) - self.cached_qualities = temp + if len(temp) == len(self.qualities): + self.cached_qualities = temp return temp From e659aba176bc2c2cb53bdde41503e2b4420c09e5 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 15 Jun 2014 22:22:34 +0200 Subject: [PATCH 005/117] Clean .pyc files before starting --- CouchPotato.py | 7 ++++++- couchpotato/core/_base/updater/main.py | 29 +++-------------------------- couchpotato/core/helpers/variable.py | 30 +++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/CouchPotato.py b/CouchPotato.py index f21b939..f5b9c04 100755 --- a/CouchPotato.py +++ b/CouchPotato.py @@ -19,7 +19,12 @@ base_path = dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.join(base_path, 'libs')) from couchpotato.environment import Env -from couchpotato.core.helpers.variable import getDataDir +from couchpotato.core.helpers.variable import getDataDir, removePyc + + +# Remove pyc files before dynamic load (sees .pyc files regular .py modules) +removePyc(base_path) + class Loader(object): diff --git a/couchpotato/core/_base/updater/main.py b/couchpotato/core/_base/updater/main.py index 27f9917..093977d 100644 --- a/couchpotato/core/_base/updater/main.py +++ b/couchpotato/core/_base/updater/main.py @@ -11,6 +11,7 @@ from threading import RLock from couchpotato.api import addApiView from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.helpers.encoding import sp +from couchpotato.core.helpers.variable import removePyc from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.environment import Env @@ -143,7 +144,7 @@ class Updater(Plugin): def doShutdown(self): if not Env.get('dev'): - self.updater.deletePyc(show_logs = False) + removePyc(Env.get('app_dir'), show_logs = False) return super(Updater, self).doShutdown() @@ -181,30 +182,6 @@ class BaseUpdater(Plugin): def check(self): pass - def deletePyc(self, only_excess = True, show_logs = True): - - for root, dirs, files in os.walk(Env.get('app_dir')): - - pyc_files = filter(lambda filename: filename.endswith('.pyc'), files) - py_files = set(filter(lambda filename: filename.endswith('.py'), files)) - excess_pyc_files = filter(lambda pyc_filename: pyc_filename[:-1] not in py_files, pyc_files) if only_excess else pyc_files - - for excess_pyc_file in excess_pyc_files: - full_path = os.path.join(root, excess_pyc_file) - if show_logs: log.debug('Removing old PYC file: %s', full_path) - try: - os.remove(full_path) - except: - log.error('Couldn\'t remove %s: %s', (full_path, traceback.format_exc())) - - for dir_name in dirs: - full_path = os.path.join(root, dir_name) - if len(os.listdir(full_path)) == 0: - try: - os.rmdir(full_path) - except: - log.error('Couldn\'t remove empty directory %s: %s', (full_path, traceback.format_exc())) - class GitUpdater(BaseUpdater): @@ -328,7 +305,7 @@ class SourceUpdater(BaseUpdater): data_dir = Env.get('data_dir') # Get list of files we want to overwrite - self.deletePyc() + removePyc(app_dir) existing_files = [] for root, subfiles, filenames in os.walk(app_dir): for filename in filenames: diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index 16207a6..66e01f5 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -6,8 +6,9 @@ import random import re import string import sys +import traceback -from couchpotato.core.helpers.encoding import simplifyString, toSafeString, ss +from couchpotato.core.helpers.encoding import simplifyString, toSafeString, ss, sp from couchpotato.core.logger import CPLog import six from six.moves import map, zip, filter @@ -313,3 +314,30 @@ under_pat = re.compile(r'_([a-z])') def underscoreToCamel(name): return under_pat.sub(lambda x: x.group(1).upper(), name) + + +def removePyc(folder, only_excess = True, show_logs = True): + + folder = sp(folder) + + for root, dirs, files in os.walk(folder): + + pyc_files = filter(lambda filename: filename.endswith('.pyc'), files) + py_files = set(filter(lambda filename: filename.endswith('.py'), files)) + excess_pyc_files = filter(lambda pyc_filename: pyc_filename[:-1] not in py_files, pyc_files) if only_excess else pyc_files + + for excess_pyc_file in excess_pyc_files: + full_path = os.path.join(root, excess_pyc_file) + if show_logs: log.debug('Removing old PYC file: %s', full_path) + try: + os.remove(full_path) + except: + log.error('Couldn\'t remove %s: %s', (full_path, traceback.format_exc())) + + for dir_name in dirs: + full_path = os.path.join(root, dir_name) + if len(os.listdir(full_path)) == 0: + try: + os.rmdir(full_path) + except: + log.error('Couldn\'t remove empty directory %s: %s', (full_path, traceback.format_exc())) From 530d3cd91ecc79c384da922e5e2d2655242ee377 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 15 Jun 2014 22:37:18 +0200 Subject: [PATCH 006/117] Update rentals URL --- couchpotato/core/media/movie/providers/automation/imdb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/movie/providers/automation/imdb.py b/couchpotato/core/media/movie/providers/automation/imdb.py index 9b4c117..783e8f5 100644 --- a/couchpotato/core/media/movie/providers/automation/imdb.py +++ b/couchpotato/core/media/movie/providers/automation/imdb.py @@ -263,7 +263,7 @@ config = [{ 'name': 'automation_charts_rentals', 'type': 'bool', 'label': 'DVD Rentals', - 'description': 'Top DVD rentals chart', + 'description': 'Top DVD rentals chart', 'default': True, }, { @@ -312,7 +312,7 @@ config = [{ 'name': 'chart_display_rentals', 'type': 'bool', 'label': 'DVD Rentals', - 'description': 'Top DVD rentals chart', + 'description': 'Top DVD rentals chart', 'default': True, }, { From 3faece0b4cdac07c7efb4c47a2c6445c9ce58b08 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 16 Jun 2014 21:21:55 +0200 Subject: [PATCH 007/117] Don't log already deleted releases. --- couchpotato/core/plugins/manage.py | 12 ++++++------ couchpotato/core/plugins/release/main.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/couchpotato/core/plugins/manage.py b/couchpotato/core/plugins/manage.py index 97f66a7..f0e0faf 100644 --- a/couchpotato/core/plugins/manage.py +++ b/couchpotato/core/plugins/manage.py @@ -136,6 +136,7 @@ class Manage(Plugin): # Get movies with done status total_movies, done_movies = fireEvent('media.list', types = 'movie', status = 'done', release_status = 'done', status_or = True, single = True) + deleted_releases = [] for done_movie in done_movies: if getIdentifier(done_movie) not in added_identifiers: fireEvent('media.delete', media_id = done_movie['_id'], delete_from = 'all') @@ -165,12 +166,11 @@ class Manage(Plugin): already_used = used_files.get(release_file) if already_used: - # delete current one - if already_used.get('last_edit', 0) < release.get('last_edit', 0): - fireEvent('release.delete', release['_id'], single = True) - # delete previous one - else: - fireEvent('release.delete', already_used['_id'], single = True) + if release_id not in deleted_releases: + release_id = release['_id'] if already_used.get('last_edit', 0) < release.get('last_edit', 0) else already_used['_id'] + fireEvent('release.delete', release_id, single = True) + + deleted_releases.append(release_id) break else: used_files[release_file] = release diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 08f0248..db2b0c8 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -149,7 +149,7 @@ class Release(Plugin): r = db.get('release_identifier', release_identifier, with_doc = True)['doc'] r['media_id'] = media['_id'] except: - log.error('Failed updating release by identifier: %s', traceback.format_exc()) + log.debug('Failed updating release by identifier "%s". Inserting new.', release_identifier) r = db.insert(release) # Update with ref and _id @@ -184,7 +184,7 @@ class Release(Plugin): db.delete(rel) return True except RecordDeleted: - log.error('Already deleted: %s', release_id) + log.debug('Already deleted: %s', release_id) return True except: log.error('Failed: %s', traceback.format_exc()) From 76126271fc743ff26a306c016e7287a7dc50b53e Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 16 Jun 2014 22:06:39 +0200 Subject: [PATCH 008/117] Don't add default profile if status is done --- couchpotato/core/media/movie/_base/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/media/movie/_base/main.py b/couchpotato/core/media/movie/_base/main.py index 4c5c2f2..2740e0d 100644 --- a/couchpotato/core/media/movie/_base/main.py +++ b/couchpotato/core/media/movie/_base/main.py @@ -90,7 +90,7 @@ class MovieBase(MovieTypeBase): # Default profile and category default_profile = {} - if not params.get('profile_id'): + if not params.get('profile_id') and status != 'done': default_profile = fireEvent('profile.default', single = True) cat_id = params.get('category_id') From f65ddbbb9e35a3fccc521787cee8cd7d377f2292 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 16 Jun 2014 22:39:02 +0200 Subject: [PATCH 009/117] Encode environments args in html --- couchpotato/environment.py | 8 ++++++-- couchpotato/templates/index.html | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/couchpotato/environment.py b/couchpotato/environment.py index 658b744..1000d48 100644 --- a/couchpotato/environment.py +++ b/couchpotato/environment.py @@ -2,6 +2,7 @@ import os from couchpotato.core.database import Database from couchpotato.core.event import fireEvent, addEvent +from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.loader import Loader from couchpotato.core.settings import Settings @@ -38,8 +39,11 @@ class Env(object): return Env._debug @staticmethod - def get(attr): - return getattr(Env, '_' + attr) + def get(attr, unicode = False): + if unicode: + return toUnicode(getattr(Env, '_' + attr)) + else: + return getattr(Env, '_' + attr) @staticmethod def all(): diff --git a/couchpotato/templates/index.html b/couchpotato/templates/index.html index b432800..0d8acbc 100644 --- a/couchpotato/templates/index.html +++ b/couchpotato/templates/index.html @@ -73,10 +73,10 @@ App.setup({ 'base_url': {{ json_encode(Env.get('web_base')) }}, - 'args': {{ json_encode(Env.get('args')) }}, + 'args': {{ json_encode(Env.get('args', unicode = True)) }}, 'options': {{ json_encode(('%s' % Env.get('options'))) }}, - 'app_dir': {{ json_encode(Env.get('app_dir')) }}, - 'data_dir': {{ json_encode(Env.get('data_dir')) }}, + 'app_dir': {{ json_encode(Env.get('app_dir', unicode = True)) }}, + 'data_dir': {{ json_encode(Env.get('data_dir', unicode = True)) }}, 'pid': {{ json_encode(Env.getPid()) }}, 'userscript_version': {{ json_encode(fireEvent('userscript.get_version', single = True)) }} }); From cfb77a1076c9dc5a66b3809f2b530d84e9aed8e6 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 17 Jun 2014 14:22:42 +0200 Subject: [PATCH 010/117] Don't use extension to test for quality tags. fix #3457 --- couchpotato/core/plugins/quality/main.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 677ee48..ef18647 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -22,12 +22,12 @@ class QualityPlugin(Plugin): } qualities = [ - {'identifier': 'bd50', 'hd': True, 'allow_3d': True, 'size': (20000, 60000), 'label': 'BR-Disk', 'alternative': ['bd25'], 'allow': ['1080p'], 'ext':['iso', 'img'], 'tags': ['bdmv', 'certificate', ('complete', 'bluray'), 'avc', 'mvc']}, - {'identifier': '1080p', 'hd': True, 'allow_3d': True, 'size': (4000, 20000), 'label': '1080p', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv', 'm2ts'], 'tags': ['m2ts', 'x264', 'h264']}, + {'identifier': 'bd50', 'hd': True, 'allow_3d': True, 'size': (20000, 60000), 'label': 'BR-Disk', 'alternative': ['bd25', ('br', 'disk')], 'allow': ['1080p'], 'ext':['iso', 'img'], 'tags': ['bdmv', 'certificate', ('complete', 'bluray'), 'avc', 'mvc']}, + {'identifier': '1080p', 'hd': True, 'allow_3d': True, 'size': (4000, 20000), 'label': '1080p', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv', 'm2ts', 'ts'], 'tags': ['m2ts', 'x264', 'h264']}, {'identifier': '720p', 'hd': True, 'allow_3d': True, 'size': (3000, 10000), 'label': '720p', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv', 'ts'], 'tags': ['x264', 'h264']}, - {'identifier': 'brrip', 'hd': True, 'allow_3d': True, 'size': (700, 7000), 'label': 'BR-Rip', 'alternative': ['bdrip'], 'allow': ['720p', '1080p'], 'ext':[], 'tags': ['hdtv', 'hdrip', 'webdl', ('web', 'dl')]}, - {'identifier': 'dvdr', 'size': (3000, 10000), 'label': 'DVD-R', 'alternative': ['br2dvd'], 'allow': [], 'ext':['iso', 'img', 'vob'], 'tags': ['pal', 'ntsc', 'video_ts', 'audio_ts', ('dvd', 'r'), 'dvd9']}, - {'identifier': 'dvdrip', 'size': (600, 2400), 'label': 'DVD-Rip', 'width': 720, 'alternative': [], 'allow': [], 'ext':[], 'tags': [('dvd', 'rip'), ('dvd', 'xvid'), ('dvd', 'divx')]}, + {'identifier': 'brrip', 'hd': True, 'allow_3d': True, 'size': (700, 7000), 'label': 'BR-Rip', 'alternative': ['bdrip', ('br', 'rip')], 'allow': ['720p', '1080p'], 'ext':[], 'tags': ['hdtv', 'hdrip', 'webdl', ('web', 'dl')]}, + {'identifier': 'dvdr', 'size': (3000, 10000), 'label': 'DVD-R', 'alternative': ['br2dvd', ('dvd', 'r')], 'allow': [], 'ext':['iso', 'img', 'vob'], 'tags': ['pal', 'ntsc', 'video_ts', 'audio_ts', ('dvd', 'r'), 'dvd9']}, + {'identifier': 'dvdrip', 'size': (600, 2400), 'label': 'DVD-Rip', 'width': 720, 'alternative': [('dvd', 'rip')], 'allow': [], 'ext':[], 'tags': [('dvd', 'rip'), ('dvd', 'xvid'), ('dvd', 'divx')]}, {'identifier': 'scr', 'size': (600, 1600), 'label': 'Screener', 'alternative': ['screener', 'dvdscr', 'ppvrip', 'dvdscreener', 'hdscr'], 'allow': ['dvdr', 'dvdrip', '720p', '1080p'], 'ext':[], 'tags': ['webrip', ('web', 'rip')]}, {'identifier': 'r5', 'size': (600, 1000), 'label': 'R5', 'alternative': ['r6'], 'allow': ['dvdr'], 'ext':[]}, {'identifier': 'tc', 'size': (600, 1000), 'label': 'TeleCine', 'alternative': ['telecine'], 'allow': [], 'ext':[]}, @@ -256,6 +256,9 @@ class QualityPlugin(Plugin): cur_file = ss(cur_file) score = 0 + extension = words[-1] + words = words[:-1] + points = { 'identifier': 10, 'label': 10, @@ -275,7 +278,7 @@ class QualityPlugin(Plugin): log.debug('Found %s via %s %s in %s', (quality['identifier'], tag_type, quality.get(tag_type), cur_file)) score += points.get(tag_type) - if isinstance(alt, (str, unicode)) and ss(alt.lower()) in cur_file.lower(): + if isinstance(alt, (str, unicode)) and ss(alt.lower()) in words: log.debug('Found %s via %s %s in %s', (quality['identifier'], tag_type, quality.get(tag_type), cur_file)) score += points.get(tag_type) / 2 @@ -285,8 +288,8 @@ class QualityPlugin(Plugin): # Check extention for ext in quality.get('ext', []): - if ext == words[-1]: - log.debug('Found %s extension in %s', (ext, cur_file)) + if ext == extension: + log.debug('Found %s with .%s extension in %s', (quality['identifier'], ext, cur_file)) score += points['ext'] return score @@ -432,7 +435,9 @@ class QualityPlugin(Plugin): 'Movie Monuments 2013 BrRip 720p': {'size': 1300, 'quality': 'brrip'}, 'The.Movie.2014.3D.1080p.BluRay.AVC.DTS-HD.MA.5.1-GroupName': {'size': 30000, 'quality': 'bd50', 'is_3d': True}, '/home/namehou/Movie Monuments (2013)/Movie Monuments.mkv': {'size': 4500, 'quality': '1080p', 'is_3d': False}, - '/home/namehou/Movie Monuments (2013)/Movie Monuments Full-OU.mkv': {'size': 4500, 'quality': '1080p', 'is_3d': True} + '/home/namehou/Movie Monuments (2013)/Movie Monuments Full-OU.mkv': {'size': 4500, 'quality': '1080p', 'is_3d': True}, + '/volume1/Public/3D/Moviename/Moviename (2009).3D.SBS.ts': {'size': 7500, 'quality': '1080p', 'is_3d': True}, + '/volume1/Public/Moviename/Moviename (2009).ts': {'size': 5500, 'quality': '1080p'}, } correct = 0 @@ -440,7 +445,10 @@ class QualityPlugin(Plugin): test_quality = self.guess(files = [name], extra = tests[name].get('extra', None), size = tests[name].get('size', None)) or {} success = test_quality.get('identifier') == tests[name]['quality'] and test_quality.get('is_3d') == tests[name].get('is_3d', False) if not success: - log.error('%s failed check, thinks it\'s %s', (name, test_quality.get('identifier'))) + log.error('%s failed check, thinks it\'s "%s" expecting "%s"', (name, + test_quality.get('identifier') + (' 3D' if test_quality.get('is_3d') else ''), + tests[name]['quality'] + (' 3D' if tests[name].get('is_3d') else '') + )) correct += success From 664ce6421fd03ead21f03a99fef712d975b3a4de Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 17 Jun 2014 15:21:08 +0200 Subject: [PATCH 011/117] Try only parse filename for release name --- couchpotato/core/plugins/scanner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/plugins/scanner.py b/couchpotato/core/plugins/scanner.py index 0b46186..ce7facd 100644 --- a/couchpotato/core/plugins/scanner.py +++ b/couchpotato/core/plugins/scanner.py @@ -903,6 +903,7 @@ class Scanner(Plugin): log.debug('Could not detect via guessit "%s": %s', (file_name, traceback.format_exc())) # Backup to simple + release_name = os.path.basename(release_name.replace('\\', '/')) cleaned = ' '.join(re.split('\W+', simplifyString(release_name))) cleaned = re.sub(self.clean, ' ', cleaned) From 648ac7793ffc43cb7f450d05cbd11ef23586e546 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 17 Jun 2014 15:21:30 +0200 Subject: [PATCH 012/117] Add multiple 3d tags to clean regex --- couchpotato/core/plugins/scanner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/scanner.py b/couchpotato/core/plugins/scanner.py index ce7facd..d5937ea 100644 --- a/couchpotato/core/plugins/scanner.py +++ b/couchpotato/core/plugins/scanner.py @@ -105,7 +105,7 @@ class Scanner(Plugin): 'HDTV': ['hdtv'] } - clean = '([ _\,\.\(\)\[\]\-]|^)(3d|hsbs|sbs|ou|extended.cut|directors.cut|french|fr|swedisch|sw|danish|dutch|nl|swesub|subs|spanish|german|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdr|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip' \ + clean = '([ _\,\.\(\)\[\]\-]|^)(3d|hsbs|sbs|half.sbs|full.sbs|ou|half.ou|full.ou|extended.cut|directors.cut|french|fr|swedisch|sw|danish|dutch|nl|swesub|subs|spanish|german|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdr|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip' \ '|hdtvrip|webdl|web.dl|webrip|web.rip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|r3|r5|bd5|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|video_ts|audio_ts|480p|480i|576p|576i|720p|720i|1080p|1080i|hrhd|hrhdtv|hddvd|bluray|x264|h264|xvid|xvidvd|xxx|www.www|hc|\[.*\])(?=[ _\,\.\(\)\[\]\-]|$)' multipart_regex = [ '[ _\.-]+cd[ _\.-]*([0-9a-d]+)', #*cd1 From 1857e047b0e4e4a1dfddf92dc144571c0a00a554 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 17 Jun 2014 15:22:20 +0200 Subject: [PATCH 013/117] Remove moviename words when scanning for 3d tags. fix #3395 --- couchpotato/core/plugins/quality/main.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index ef18647..ef88534 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -1,12 +1,12 @@ import traceback import re -from CodernityDB.database import RecordNotFound +from CodernityDB.database import RecordNotFound from couchpotato import get_db from couchpotato.api import addApiView -from couchpotato.core.event import addEvent +from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.encoding import toUnicode, ss -from couchpotato.core.helpers.variable import mergeDicts, getExt, tryInt +from couchpotato.core.helpers.variable import mergeDicts, getExt, tryInt, splitString from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.quality.index import QualityIndex @@ -192,7 +192,7 @@ class QualityPlugin(Plugin): # Create hash for cache cache_key = str([f.replace('.' + getExt(f), '') if len(getExt(f)) < 4 else f for f in files]) - cached = self.getCache(cache_key) + cached = None #self.getCache(cache_key) if cached and len(extra) == 0: return cached @@ -208,6 +208,10 @@ class QualityPlugin(Plugin): for cur_file in files: words = re.split('\W+', cur_file.lower()) + name_year = fireEvent('scanner.name_year', cur_file, file_name = cur_file, single = True) + if name_year and name_year.get('name'): + split_name = splitString(name_year.get('name'), ' ') + words = [x for x in words if x not in split_name] for quality in qualities: contains_score = self.containsTagScore(quality, words, cur_file) @@ -438,6 +442,9 @@ class QualityPlugin(Plugin): '/home/namehou/Movie Monuments (2013)/Movie Monuments Full-OU.mkv': {'size': 4500, 'quality': '1080p', 'is_3d': True}, '/volume1/Public/3D/Moviename/Moviename (2009).3D.SBS.ts': {'size': 7500, 'quality': '1080p', 'is_3d': True}, '/volume1/Public/Moviename/Moviename (2009).ts': {'size': 5500, 'quality': '1080p'}, + '/movies/BluRay HDDVD H.264 MKV 720p EngSub/QuiQui le fou (criterion collection #123, 1915)/QuiQui le fou (1915) 720p x264 BluRay.mkv': {'size': 5500, 'quality': '720p'}, + 'C:\\movies\QuiQui le fou (collection #123, 1915)\QuiQui le fou (1915) 720p x264 BluRay.mkv': {'size': 5500, 'quality': '720p'}, + 'C:\\movies\QuiQui le fou (collection #123, 1915)\QuiQui le fou (1915) half-sbs 720p x264 BluRay.mkv': {'size': 5500, 'quality': '720p', 'is_3d': True}, } correct = 0 From 3786b5435f05847e94cdf1786e9dda4509a59126 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 17 Jun 2014 15:36:18 +0200 Subject: [PATCH 014/117] Only remove movie title from 3d words check --- couchpotato/core/plugins/quality/main.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index ef88534..dd820cf 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -192,7 +192,7 @@ class QualityPlugin(Plugin): # Create hash for cache cache_key = str([f.replace('.' + getExt(f), '') if len(getExt(f)) < 4 else f for f in files]) - cached = None #self.getCache(cache_key) + cached = self.getCache(cache_key) if cached and len(extra) == 0: return cached @@ -209,13 +209,14 @@ class QualityPlugin(Plugin): for cur_file in files: words = re.split('\W+', cur_file.lower()) name_year = fireEvent('scanner.name_year', cur_file, file_name = cur_file, single = True) + threed_words = words if name_year and name_year.get('name'): split_name = splitString(name_year.get('name'), ' ') - words = [x for x in words if x not in split_name] + threed_words = [x for x in words if x not in split_name] for quality in qualities: contains_score = self.containsTagScore(quality, words, cur_file) - threedscore = self.contains3D(quality, words, cur_file) if quality.get('allow_3d') else (0, None) + threedscore = self.contains3D(quality, threed_words, cur_file) if quality.get('allow_3d') else (0, None) self.calcScore(score, quality, contains_score, threedscore) From dd61c7dc211852d910c627d5ad3cc8eda1faf953 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 17 Jun 2014 16:27:22 +0200 Subject: [PATCH 015/117] Compact DB every 7 days if needed --- couchpotato/core/database.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/couchpotato/core/database.py b/couchpotato/core/database.py index 1b9501c..d753d87 100644 --- a/couchpotato/core/database.py +++ b/couchpotato/core/database.py @@ -26,7 +26,9 @@ class Database(object): addApiView('database.document.update', self.updateDocument) addApiView('database.document.delete', self.deleteDocument) + addEvent('database.setup.after', self.startup_compact) addEvent('database.setup_index', self.setupIndex) + addEvent('app.migrate', self.migrate) addEvent('app.after_shutdown', self.close) @@ -140,8 +142,14 @@ class Database(object): success = True try: + start = time.time() db = self.getDB() + size = float(db.get_db_details().get('size', 0)) + log.debug('Compacting database, current size: %sMB', round(size/1048576, 2)) + db.compact() + new_size = float(db.get_db_details().get('size', 0)) + log.debug('Done compacting database in %ss, new size: %sMB, saved: %sMB', (round(time.time()-start, 2), round(new_size/1048576, 2), round((size-new_size)/1048576, 2))) except: log.error('Failed compact: %s', traceback.format_exc()) success = False @@ -150,6 +158,18 @@ class Database(object): 'success': success } + # Compact on start + def startup_compact(self): + from couchpotato import Env + + db = self.getDB() + size = db.get_db_details().get('size') + prop_name = 'last_db_compact' + last_check = int(Env.prop(prop_name, default = 0)) + if size > 26214400 and last_check < time.time()-604800: # 25MB / 7 days + self.compact() + Env.prop(prop_name, value = int(time.time())) + def migrate(self): from couchpotato import Env From 67fbcc8238b951378ea4614aa318480f29f5c66a Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 17 Jun 2014 23:32:27 +0200 Subject: [PATCH 016/117] Tag filter index --- couchpotato/core/media/_base/media/index.py | 21 +++++++++++++++++++++ couchpotato/core/media/_base/media/main.py | 18 ++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/media/_base/media/index.py b/couchpotato/core/media/_base/media/index.py index 1b77b70..2166c0a 100644 --- a/couchpotato/core/media/_base/media/index.py +++ b/couchpotato/core/media/_base/media/index.py @@ -176,3 +176,24 @@ class MediaChildrenIndex(TreeBasedIndex): if data.get('_t') == 'media' and data.get('parent_id'): return data.get('parent_id'), None + +class MediaTagIndex(MultiTreeBasedIndex): + _version = 1 + + custom_header = """from CodernityDB.tree_index import MultiTreeBasedIndex""" + + def __init__(self, *args, **kwargs): + kwargs['key_format'] = '32s' + super(MediaTagIndex, self).__init__(*args, **kwargs) + + def make_key_value(self, data): + if data.get('_t') == 'media' and len(data.get('tags', [])) > 0: + + tags = set() + for tag in data.get('tags', []): + tags.add(self.make_key(tag)) + + return list(tags), None + + def make_key(self, key): + return md5(key).hexdigest() diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 3c1bf69..bd0d53c 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -9,7 +9,7 @@ from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.variable import splitString, getImdb, getTitle from couchpotato.core.logger import CPLog from couchpotato.core.media import MediaBase -from .index import MediaIndex, MediaStatusIndex, MediaTypeIndex, TitleSearchIndex, TitleIndex, StartsWithIndex, MediaChildrenIndex +from .index import MediaIndex, MediaStatusIndex, MediaTypeIndex, TitleSearchIndex, TitleIndex, StartsWithIndex, MediaChildrenIndex, MediaTagIndex log = CPLog(__name__) @@ -21,6 +21,7 @@ class MediaPlugin(MediaBase): 'media': MediaIndex, 'media_search_title': TitleSearchIndex, 'media_status': MediaStatusIndex, + 'media_tag': MediaTagIndex, 'media_by_type': MediaTypeIndex, 'media_title': TitleIndex, 'media_startswith': StartsWithIndex, @@ -177,7 +178,7 @@ class MediaPlugin(MediaBase): log.debug('No media found with identifiers: %s', identifiers) - def list(self, types = None, status = None, release_status = None, status_or = False, limit_offset = None, starts_with = None, search = None): + def list(self, types = None, status = None, release_status = None, status_or = False, limit_offset = None, with_tags = None, starts_with = None, search = None): db = get_db() @@ -188,6 +189,8 @@ class MediaPlugin(MediaBase): release_status = [release_status] if types and not isinstance(types, (list, tuple)): types = [types] + if with_tags and not isinstance(with_tags, (list, tuple)): + with_tags = [with_tags] # query media ids if types: @@ -214,11 +217,17 @@ class MediaPlugin(MediaBase): # Add search filters if starts_with: - filter_by['starts_with'] = set() starts_with = toUnicode(starts_with.lower())[0] starts_with = starts_with if starts_with in ascii_lowercase else '#' filter_by['starts_with'] = [x['_id'] for x in db.get_many('media_startswith', starts_with)] + # Add tag filter + if with_tags: + filter_by['with_tags'] = set() + for tag in with_tags: + for x in db.get_many('media_tag', tag): + filter_by['with_tags'].add(x['_id']) + # Filter with search query if search: filter_by['search'] = [x['_id'] for x in db.get_many('media_search_title', search)] @@ -271,7 +280,8 @@ class MediaPlugin(MediaBase): release_status = splitString(kwargs.get('release_status')), status_or = kwargs.get('status_or') is not None, limit_offset = kwargs.get('limit_offset'), - starts_with = kwargs.get('starts_with'), + with_tags = kwargs.get('with_tags'), + starts_with = splitString(kwargs.get('starts_with')), search = kwargs.get('search') ) From 0b5dfe826abaeaeec521d824ed5f0ebfc0b4f73b Mon Sep 17 00:00:00 2001 From: Ruud Date: Thu, 19 Jun 2014 14:15:42 +0200 Subject: [PATCH 017/117] Fix BitSoup parsing. close #3465 --- couchpotato/core/media/_base/providers/torrent/bitsoup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/_base/providers/torrent/bitsoup.py b/couchpotato/core/media/_base/providers/torrent/bitsoup.py index f32e79e..d70579e 100644 --- a/couchpotato/core/media/_base/providers/torrent/bitsoup.py +++ b/couchpotato/core/media/_base/providers/torrent/bitsoup.py @@ -1,6 +1,6 @@ import traceback -from bs4 import BeautifulSoup +from bs4 import BeautifulSoup, SoupStrainer from couchpotato.core.helpers.variable import tryInt from couchpotato.core.logger import CPLog from couchpotato.core.media._base.providers.torrent.base import TorrentProvider @@ -20,6 +20,7 @@ class Base(TorrentProvider): } http_time_between_calls = 1 # Seconds + only_tables_tags = SoupStrainer('table') def _searchOnTitle(self, title, movie, quality, results): @@ -27,7 +28,7 @@ class Base(TorrentProvider): data = self.getHTMLData(url) if data: - html = BeautifulSoup(data) + html = BeautifulSoup(data, 'html.parser', parse_only = self.only_tables_tags) try: result_table = html.find('table', attrs = {'class': 'koptekst'}) From 57ca5067ffd5b7f42db1cdf7f634e558f13c3861 Mon Sep 17 00:00:00 2001 From: Ruud Date: Thu, 19 Jun 2014 16:48:30 +0200 Subject: [PATCH 018/117] Insert themoviedb original_title in by default. --- couchpotato/core/media/movie/providers/info/themoviedb.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/media/movie/providers/info/themoviedb.py b/couchpotato/core/media/movie/providers/info/themoviedb.py index 16299f2..4a397ed 100644 --- a/couchpotato/core/media/movie/providers/info/themoviedb.py +++ b/couchpotato/core/media/movie/providers/info/themoviedb.py @@ -153,8 +153,10 @@ class TheMovieDb(MovieProvider): movie_data = dict((k, v) for k, v in movie_data.items() if v) # Add alternative names + if movie_data['original_title'] and movie_data['original_title'] not in movie_data['titles']: + movie_data['titles'].insert(0, movie_data['original_title']) + if extended: - movie_data['titles'].append(movie.originaltitle) for alt in movie.alternate_titles: alt_name = alt.title if alt_name and alt_name not in movie_data['titles'] and alt_name.lower() != 'none' and alt_name is not None: From 5797348bb379a92bd43864aa91eed703f0a3bcd1 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 12:10:40 +0200 Subject: [PATCH 019/117] Update tag index --- couchpotato/core/media/_base/media/index.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/_base/media/index.py b/couchpotato/core/media/_base/media/index.py index 2166c0a..b40e162 100644 --- a/couchpotato/core/media/_base/media/index.py +++ b/couchpotato/core/media/_base/media/index.py @@ -178,7 +178,7 @@ class MediaChildrenIndex(TreeBasedIndex): class MediaTagIndex(MultiTreeBasedIndex): - _version = 1 + _version = 2 custom_header = """from CodernityDB.tree_index import MultiTreeBasedIndex""" @@ -187,7 +187,7 @@ class MediaTagIndex(MultiTreeBasedIndex): super(MediaTagIndex, self).__init__(*args, **kwargs) def make_key_value(self, data): - if data.get('_t') == 'media' and len(data.get('tags', [])) > 0: + if data.get('_t') == 'media' and data.get('tags') and len(data.get('tags', [])) > 0: tags = set() for tag in data.get('tags', []): From 6f766aae8c424208614eddd255d032044e3a7e9d Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 12:13:54 +0200 Subject: [PATCH 020/117] Tag and untag dashboard media --- couchpotato/core/media/_base/media/main.py | 40 ++++++++++++++++++++++++++++++ couchpotato/core/media/movie/_base/main.py | 1 + couchpotato/core/media/movie/searcher.py | 5 ++++ couchpotato/core/plugins/release/main.py | 4 +++ couchpotato/core/plugins/renamer.py | 13 ++++++++++ couchpotato/static/scripts/page/home.js | 3 ++- 6 files changed, 65 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index bd0d53c..b4c8ced 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -82,6 +82,8 @@ class MediaPlugin(MediaBase): addEvent('media.list', self.list) addEvent('media.delete', self.delete) addEvent('media.restatus', self.restatus) + addEvent('media.tag', self.tag) + addEvent('media.untag', self.unTag) def refresh(self, id = '', **kwargs): handlers = [] @@ -469,3 +471,41 @@ class MediaPlugin(MediaBase): return True except: log.error('Failed restatus: %s', traceback.format_exc()) + + def tag(self, media_id, tag): + + try: + db = get_db() + m = db.get('id', media_id) + + tags = m.get('tags') or [] + if tag not in tags: + tags.append(tag) + m['tags'] = tags + db.update(m) + + return True + except: + log.error('Failed tagging: %s', traceback.format_exc()) + + return False + + def unTag(self, media_id, tag): + + try: + db = get_db() + m = db.get('id', media_id) + + tags = m.get('tags') or [] + if tag in tags: + new_tags = list(set(tags)) + new_tags.remove(tag) + + m['tags'] = new_tags + db.update(m) + + return True + except: + log.error('Failed untagging: %s', traceback.format_exc()) + + return False diff --git a/couchpotato/core/media/movie/_base/main.py b/couchpotato/core/media/movie/_base/main.py index 2740e0d..9475ec0 100644 --- a/couchpotato/core/media/movie/_base/main.py +++ b/couchpotato/core/media/movie/_base/main.py @@ -149,6 +149,7 @@ class MovieBase(MovieTypeBase): m['profile_id'] = params.get('profile_id', default_profile.get('id')) m['category_id'] = cat_id if cat_id is not None and len(cat_id) > 0 else (m.get('category_id') or None) m['last_edit'] = int(time.time()) + m['tags'] = [] do_search = True db.update(m) diff --git a/couchpotato/core/media/movie/searcher.py b/couchpotato/core/media/movie/searcher.py index 81d6200..0f4b417 100644 --- a/couchpotato/core/media/movie/searcher.py +++ b/couchpotato/core/media/movie/searcher.py @@ -131,6 +131,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): outside_eta_results = 0 alway_search = self.conf('always_search') ignore_eta = manual + total_result_count = 0 default_title = getTitle(movie) if not default_title: @@ -199,6 +200,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): results = fireEvent('searcher.search', search_protocols, movie, quality, single = True) or [] results_count = len(results) + total_result_count += results_count if results_count == 0: log.debug('Nothing found for %s in %s', (default_title, quality['label'])) @@ -235,6 +237,9 @@ class MovieSearcher(SearcherBase, MovieTypeBase): if self.shuttingDown() or ret: break + if total_result_count > 0: + fireEvent('media.tag', movie['_id'], 'recent', single = True) + if len(too_early_to_search) > 0: log.info2('Too early to search for %s, %s', (too_early_to_search, default_title)) diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index db2b0c8..e3c93b4 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -104,6 +104,8 @@ class Release(Plugin): elif rel['status'] in ['snatched', 'downloaded']: self.updateStatus(rel['_id'], status = 'ignore') + fireEvent('media.untag', media.get('_id'), 'recent', single = True) + def add(self, group, update_info = True, update_id = None): try: @@ -346,6 +348,8 @@ class Release(Plugin): mdia['last_edit'] = int(time.time()) db.update(mdia) + fireEvent('media.tag', media['_id'], 'recent', single = True) + return True # Assume release downloaded diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 1158580..8b57103 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -457,9 +457,15 @@ class Renamer(Plugin): mdia['last_edit'] = int(time.time()) db.update(mdia) + # List movie on dashboard + fireEvent('media.tag', media['_id'], 'recent', single = True) + except: log.error('Failed marking movie finished: %s', (traceback.format_exc())) + # Mark media for dashboard + mark_as_recent = False + # Go over current movie releases for release in fireEvent('release.for_media', media['_id'], single = True): @@ -506,14 +512,21 @@ class Renamer(Plugin): # Set the release to downloaded fireEvent('release.update_status', release['_id'], status = 'downloaded', single = True) group['release_download'] = release_download + mark_as_recent = True elif release_download['status'] == 'seeding': # Set the release to seeding fireEvent('release.update_status', release['_id'], status = 'seeding', single = True) + mark_as_recent = True elif release.get('identifier') == group['meta_data']['quality']['identifier']: # Set the release to downloaded fireEvent('release.update_status', release['_id'], status = 'downloaded', single = True) group['release_download'] = release_download + mark_as_recent = True + + # Mark media for dashboard + if mark_as_recent: + fireEvent('media.tag', group['media'].get('_id'), 'recent', single = True) # Remove leftover files if not remove_leftovers: # Don't remove anything diff --git a/couchpotato/static/scripts/page/home.js b/couchpotato/static/scripts/page/home.js index aff8fbb..792b4a0 100644 --- a/couchpotato/static/scripts/page/home.js +++ b/couchpotato/static/scripts/page/home.js @@ -54,7 +54,8 @@ Page.Home = new Class({ }) ), 'filter': { - 'release_status': 'snatched,missing,available,downloaded' + 'release_status': 'snatched,missing,available,downloaded,done,seeding', + 'with_tags': 'recent' }, 'limit': null, 'onLoaded': function(){ From 8e17b9aea59e8cf43714c80031ff380e5dcaaca1 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 14:12:43 +0200 Subject: [PATCH 021/117] Remove BoxCar --- couchpotato/core/notifications/boxcar.py | 69 -------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 couchpotato/core/notifications/boxcar.py diff --git a/couchpotato/core/notifications/boxcar.py b/couchpotato/core/notifications/boxcar.py deleted file mode 100644 index a7acc88..0000000 --- a/couchpotato/core/notifications/boxcar.py +++ /dev/null @@ -1,69 +0,0 @@ -import time - -from couchpotato.core.helpers.encoding import toUnicode -from couchpotato.core.logger import CPLog -from couchpotato.core.notifications.base import Notification - - -log = CPLog(__name__) - -autoload = 'Boxcar' - - -class Boxcar(Notification): - - url = 'https://boxcar.io/devices/providers/7MNNXY3UIzVBwvzkKwkC/notifications' - - def notify(self, message = '', data = None, listener = None): - if not data: data = {} - - try: - message = message.strip() - - data = { - 'email': self.conf('email'), - 'notification[from_screen_name]': self.default_title, - 'notification[message]': toUnicode(message), - 'notification[from_remote_service_id]': int(time.time()), - } - - self.urlopen(self.url, data = data) - except: - log.error('Check your email and added services on boxcar.io') - return False - - log.info('Boxcar notification successful.') - return True - - def isEnabled(self): - return super(Boxcar, self).isEnabled() and self.conf('email') - - -config = [{ - 'name': 'boxcar', - 'groups': [ - { - 'tab': 'notifications', - 'list': 'notification_providers', - 'name': 'boxcar', - 'options': [ - { - 'name': 'enabled', - 'default': 0, - 'type': 'enabler', - }, - { - 'name': 'email', - 'description': 'Your Boxcar registration emailaddress.' - }, - { - 'name': 'on_snatch', - 'default': 0, - 'type': 'bool', - 'advanced': True, - 'description': 'Also send message when movie is snatched.', - }, - ], - } - ], -}] From 578b74f2c0068bb047c48dfec98da2dfe31ded18 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 14:14:10 +0200 Subject: [PATCH 022/117] Fix PushBullet url. fix #3470 --- couchpotato/core/notifications/pushbullet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/notifications/pushbullet.py b/couchpotato/core/notifications/pushbullet.py index 56cf228..77738c3 100644 --- a/couchpotato/core/notifications/pushbullet.py +++ b/couchpotato/core/notifications/pushbullet.py @@ -14,7 +14,7 @@ autoload = 'Pushbullet' class Pushbullet(Notification): - url = 'https://api.pushbullet.com/api/%s' + url = 'https://api.pushbullet.com/v2/%s' def notify(self, message = '', data = None, listener = None): if not data: data = {} From 3f92ed0ea0d20bad145a48d810e8a7c381911ffd Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 14:33:20 +0200 Subject: [PATCH 023/117] Don't autodownload releases with no file size. fix #3467 --- couchpotato/core/plugins/release/main.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index e3c93b4..9e7e4ca 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -375,7 +375,11 @@ class Release(Plugin): continue if rel['score'] <= 0: - log.info('Ignored, score to low: %s', rel['name']) + log.info('Ignored, score "%s" to low: %s', (rel['score'], rel['name'])) + continue + + if rel['size'] <= 50: + log.info('Ignored, size "%sMB" to low: %s', (rel['size'], rel['name'])) continue rel['wait_for'] = False From cf95e417f12a700be5c2a942567765a4c9a1b60b Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 17:11:11 +0200 Subject: [PATCH 024/117] Delete publichd --- .../core/media/_base/providers/torrent/publichd.py | 136 --------------------- .../core/media/movie/providers/torrent/publichd.py | 14 --- 2 files changed, 150 deletions(-) delete mode 100644 couchpotato/core/media/_base/providers/torrent/publichd.py delete mode 100644 couchpotato/core/media/movie/providers/torrent/publichd.py diff --git a/couchpotato/core/media/_base/providers/torrent/publichd.py b/couchpotato/core/media/_base/providers/torrent/publichd.py deleted file mode 100644 index 1090be2..0000000 --- a/couchpotato/core/media/_base/providers/torrent/publichd.py +++ /dev/null @@ -1,136 +0,0 @@ -from urlparse import parse_qs -import re -import traceback - -from bs4 import BeautifulSoup -from couchpotato.core.helpers.encoding import tryUrlencode, toUnicode -from couchpotato.core.helpers.variable import tryInt -from couchpotato.core.logger import CPLog -from couchpotato.core.media._base.providers.torrent.base import TorrentMagnetProvider -import six - - -log = CPLog(__name__) - - -class Base(TorrentMagnetProvider): - - urls = { - 'test': 'https://publichd.se', - 'detail': 'https://publichd.se/index.php?page=torrent-details&id=%s', - 'search': 'https://publichd.se/index.php', - } - http_time_between_calls = 0 - - def search(self, movie, quality): - - if not quality.get('hd', False): - return [] - - return super(Base, self).search(movie, quality) - - def _search(self, media, quality, results): - - query = self.buildUrl(media) - - params = tryUrlencode({ - 'page': 'torrents', - 'search': query, - 'active': 1, - }) - - data = self.getHTMLData('%s?%s' % (self.urls['search'], params)) - - if data: - - try: - soup = BeautifulSoup(data) - - results_table = soup.find('table', attrs = {'id': 'bgtorrlist2'}) - entries = results_table.find_all('tr') - - for result in entries[2:len(entries) - 1]: - info_url = result.find(href = re.compile('torrent-details')) - download = result.find(href = re.compile('magnet:')) - - if info_url and download: - - url = parse_qs(info_url['href']) - - results.append({ - 'id': url['id'][0], - 'name': six.text_type(info_url.string), - 'url': download['href'], - 'detail_url': self.urls['detail'] % url['id'][0], - 'size': self.parseSize(result.find_all('td')[7].string), - 'seeders': tryInt(result.find_all('td')[4].string), - 'leechers': tryInt(result.find_all('td')[5].string), - 'get_more_info': self.getMoreInfo - }) - - except: - log.error('Failed getting results from %s: %s', (self.getName(), traceback.format_exc())) - - def getMoreInfo(self, item): - - cache_key = 'publichd.%s' % item['id'] - description = self.getCache(cache_key) - - if not description: - - try: - full_description = self.urlopen(item['detail_url']) - html = BeautifulSoup(full_description) - nfo_pre = html.find('div', attrs = {'id': 'torrmain'}) - description = toUnicode(nfo_pre.text) if nfo_pre else '' - except: - log.error('Failed getting more info for %s', item['name']) - description = '' - - self.setCache(cache_key, description, timeout = 25920000) - - item['description'] = description - return item - - -config = [{ - 'name': 'publichd', - 'groups': [ - { - 'tab': 'searcher', - 'list': 'torrent_providers', - 'name': 'PublicHD', - 'description': 'Public Torrent site with only HD content. See PublicHD', - 'wizard': True, - 'options': [ - { - 'name': 'enabled', - 'type': 'enabler', - 'default': True, - }, - { - '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': 'extra_score', - 'advanced': True, - 'label': 'Extra Score', - 'type': 'int', - 'default': 0, - 'description': 'Starting score for each release found via this provider.', - } - ], - }, - ], -}] diff --git a/couchpotato/core/media/movie/providers/torrent/publichd.py b/couchpotato/core/media/movie/providers/torrent/publichd.py deleted file mode 100644 index 9fed461..0000000 --- a/couchpotato/core/media/movie/providers/torrent/publichd.py +++ /dev/null @@ -1,14 +0,0 @@ -from couchpotato.core.logger import CPLog -from couchpotato.core.event import fireEvent -from couchpotato.core.media._base.providers.torrent.publichd import Base -from couchpotato.core.media.movie.providers.base import MovieProvider - -log = CPLog(__name__) - -autoload = 'PublicHD' - - -class PublicHD(MovieProvider, Base): - - def buildUrl(self, media): - return fireEvent('library.query', media, single = True).replace(':', '') From 07063d855ab0130be7a2ccb98c0a6a6a930fd341 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 17:35:15 +0200 Subject: [PATCH 025/117] Add icons to torrent providers --- couchpotato/core/media/_base/providers/torrent/awesomehd.py | 1 + couchpotato/core/media/_base/providers/torrent/bithdtv.py | 1 + couchpotato/core/media/_base/providers/torrent/bitsoup.py | 1 + couchpotato/core/media/_base/providers/torrent/hdbits.py | 1 + couchpotato/core/media/_base/providers/torrent/ilovetorrents.py | 1 + couchpotato/core/media/_base/providers/torrent/iptorrents.py | 1 + couchpotato/core/media/_base/providers/torrent/kickasstorrents.py | 1 + couchpotato/core/media/_base/providers/torrent/passthepopcorn.py | 1 + couchpotato/core/media/_base/providers/torrent/sceneaccess.py | 1 + couchpotato/core/media/_base/providers/torrent/thepiratebay.py | 1 + couchpotato/core/media/_base/providers/torrent/torrentbytes.py | 1 + couchpotato/core/media/_base/providers/torrent/torrentday.py | 1 + couchpotato/core/media/_base/providers/torrent/torrentleech.py | 1 + couchpotato/core/media/_base/providers/torrent/torrentpotato.py | 1 + couchpotato/core/media/_base/providers/torrent/torrentshack.py | 1 + couchpotato/core/media/_base/providers/torrent/torrentz.py | 1 + couchpotato/core/media/_base/providers/torrent/yify.py | 3 ++- 17 files changed, 18 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/media/_base/providers/torrent/awesomehd.py b/couchpotato/core/media/_base/providers/torrent/awesomehd.py index 1372f6c..ccdf766 100644 --- a/couchpotato/core/media/_base/providers/torrent/awesomehd.py +++ b/couchpotato/core/media/_base/providers/torrent/awesomehd.py @@ -80,6 +80,7 @@ config = [{ 'name': 'Awesome-HD', 'description': 'See AHD', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAC+UlEQVR4AV1SO0y6dxQ9H4g8CoIoohZ5NA0aR2UgkYpNB5uocTSaLlrDblMH09Gt8d90r3YpJkanxjA4GGkbO7RNxSABq8jDGnkpD+UD5NV7Bxvbk9wvv+/3uPece66A/yEWi42FQqHVfD7/cbPZtIEglUpjOp3uZHR0dBvAn3gDIRqNgjE4OKj0+Xzf3NzcfD4wMCCjf5TLZbTbbajVatzf3+Pu7q5uNpt35ufnvwBQAScQRREEldfr9RWLxan+/n5YrVa+jFarhVfQQyQSCU4EhULhX15engEgSrjC0dHRVqlUmjQYDBgaGgKtuTqz4mTgIoVCASaTCX19fajVapOHh4dbFJBks9mxcDi8qtFoJEajkfVyJWi1WkxMTMDhcIAT8x6D7/Dd6+vr1fHx8TGp2+3+iqo5+YCzBwIBToK5ubl/mQwPDyMSibAs2Gw2UHNRrValz8/PDUk8Hv9EqVRCr9fj4uICTNflcqFer+Pg4AB7e3uoVCq8x9Rxfn6O7u5uqFQq8FspZXxHTekggByA3W4Hr9PpNDeRL3I1cMhkMrBrnZ2dyGQyvNYIs7OzVbJNPjIyAraLwYdcjR8wXl5eIJfLwRIFQQDLYkm3t7c1CdGPPT4+cpOImp4PODMeaK+n10As2jBbrHifHOjS6qAguVFimkqlwAMmIQnHV1dX4NDQhVwuhyZTV6pgIktzDzkkk0lEwhEEzs7ASQr5Ai4vL1nuccfCwsLO/v6+p9FoyJhF6ekJro/cPCzIZLNQa7rQoK77/SdgWWpKkCaJ5EB9aWnpe6nH40nRMBnJV4f5gw+FX3/5GX/8/htXRZdOzzqhJWn6nl6YbTZqqhrhULD16fT0d8FgcFtYW1vD5uamfGVl5cd4IjldKhZACdkJvKfWUANrxEaJV4hiGVaL1b+7653hXzwRZQr2X76xsfG1xWIRaZzbNPv/CdrjEL9cX/+WXFBSgEPgzxuwG3Yans9OT0+naBZMIJDNfzudzp8WFxd/APAX3uAf9WOTxOPLdosAAAAASUVORK5CYII=', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/bithdtv.py b/couchpotato/core/media/_base/providers/torrent/bithdtv.py index bb12c66..34a21f9 100644 --- a/couchpotato/core/media/_base/providers/torrent/bithdtv.py +++ b/couchpotato/core/media/_base/providers/torrent/bithdtv.py @@ -95,6 +95,7 @@ config = [{ 'name': 'BiT-HDTV', 'description': 'See BiT-HDTV', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABMklEQVR4AZ3Qu0ojcQCF8W9MJcQbJNgEEQUbQVIqWgnaWfkIvoCgggixEAmIhRtY2GV3w7KwU61B0EYIxmiw0YCik84ipaCuc0nmP5dcjIUgOjqDvxf4OAdf9mnMLcUJyPyGSCP+YRdC+Kp8iagJKhuS+InYRhTGgDbeV2uEMand4ZRxizjXHQEimxhraAnUr73BNqQxMiNeV2SwcjTLEVtb4Zl10mXutvOWm2otw5Sxz6TGTbdd6ncuYvVLXAXrvM+ruyBpy1S3JLGDfUQ1O6jn5vTsrJXvqSt4UNfj6vxTRPxBHER5QeSirhLGk/5rWN+ffB1XZuxjnDy1q87m7TS+xOGA+Iv4gfkbaw+nOMXHDHnITGEk0VfRFnn4Po4vNYm6RGukmggR0L08+l+e4HMeASo/i6AJUjLgAAAAAElFTkSuQmCC', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/bitsoup.py b/couchpotato/core/media/_base/providers/torrent/bitsoup.py index d70579e..2b1a0e7 100644 --- a/couchpotato/core/media/_base/providers/torrent/bitsoup.py +++ b/couchpotato/core/media/_base/providers/torrent/bitsoup.py @@ -90,6 +90,7 @@ config = [{ 'name': 'Bitsoup', 'description': 'See Bitsoup', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAB8ElEQVR4AbWSS2sTURiGz3euk0mswaE37HhNhIrajQheFgF3rgR/lAt/gOBCXNZlo6AbqfUWRVCxi04wqUnTRibpJLaJzdzOOZ6WUumyC5/VHOb9eN/FA91uFx0FjI4IPfgiGLTWH73tn348GKmN7ijD0d2b41fO5qJEaX24AWNIUrVQCTTJ3Llx6vbV6Vtzk7Gi9+ebi996guFDDYAQAVj4FExP5qdOZB49W62t/zH3hECcwsPnbWeMXz6Xi2K1f0ApeK3hMCHHbP5gvvoriBgFAAQJEAxhjJ4u+YWTNsVI6b1JgtPWZkoIefKy4fcii2OTw2BABs7wj3bYDlLL4rvjGWOdTser1j5Xf7c3Q/MbHQYApxItvnm31mhQQ71eX2vUB76/vsWB2hg0QuogrMwLIG8P3InM2/eVGXeDViqVwWB79vRU2lgJYmdHcgXCTAXQFJTN5HguvDCR2Hxsxe8EvT54nlcul5vNpqDIEgwRQanAhAAABgRIyiQcjpIkkTOuWyqVoN/vSylX67XXH74uV1vHRUyxxFqbLBCSmBpiXSq6xcL5QrGYzWZ3XQIAwdlOJB+/aL764ucdmncYs0WsCI7kvTnn+qyDMEnTVCn1Tz5KsBFg6fvWcmsUAcnYNC/g2hnromvvqbHvxv+39S+MX+bWkFXwAgAAAABJRU5ErkJggg==', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/hdbits.py b/couchpotato/core/media/_base/providers/torrent/hdbits.py index 6cf8d57..0887f97 100644 --- a/couchpotato/core/media/_base/providers/torrent/hdbits.py +++ b/couchpotato/core/media/_base/providers/torrent/hdbits.py @@ -72,6 +72,7 @@ config = [{ 'list': 'torrent_providers', 'name': 'HDBits', 'description': 'See HDBits', + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABi0lEQVR4AZWSzUsbQRjGdyabTcvSNPTSHlpQQeMHJApC8CJRvHgQQU969+LJP8G7f4N3DwpeFRQvRr0EKaUl0ATSpkigUNFsMl/r9NmZLCEHA/nNO5PfvMPDm0DI6fV3ZxiolEICe1oZCBVCCmBPKwOh2ErKBHGE4KYEXBpSLkUlqO4LcM7f+6nVhRnOhSkOz/hexk+tL+YL0yPF2YmN4tynD++4gTLGkNNac9YFLoREBR1+cnF3dFY6v/m6PD+FaXiNJtgA4xYbABxiGrz6+6HWaI5/+Qh37YS0/3Znc8UxwNGBIIBX22z+/ZdJ+4wzyjpR4PEpODg8tgUXBv2iWUzSpa12B0IR6n6lvt8Aek2lZHb084+fdRNgrwY8z81PjhVy2d2ttUrtV/lbBa+JXGEpDMPnoF2tN1QYRqVUtf6nFbThb7wk7le395elcqhASLb39okDiHY00VCtCTEHwSiH4AI0lkOiT1dwMeSfT3SRxiQWNO7Zwj1egkoVIQFMKvSiC3bcjXq9Jf8DcDIRT3hh10kAAAAASUVORK5CYII=', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/ilovetorrents.py b/couchpotato/core/media/_base/providers/torrent/ilovetorrents.py index 33edff7..b6ccecd 100644 --- a/couchpotato/core/media/_base/providers/torrent/ilovetorrents.py +++ b/couchpotato/core/media/_base/providers/torrent/ilovetorrents.py @@ -146,6 +146,7 @@ config = [{ 'name': 'ILoveTorrents', 'description': 'Where the Love of Torrents is Born', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAACPUlEQVR4AYWM0U9SbxjH3+v266I/oNvWZTfd2J1d0ZqbZEFwWrUImOKs4YwtumFKZvvlJJADR2TCQQlMPKg5NmpREgaekAPnBATKgmK1LqQlx6awHnZWF1Tr2Xfvvs+7z+dB0mlO7StpAh+M4S/2jbo3w8+xvJvlnSneEt+10zwer5ujNUOoChjALWFw5XOwdCAk/P57cGvPl+Oht0W7VJHN5NC1uW1BON4hGjXbwpVWMZhsy9v7sEIXAsDNYBXgdkEoIKyWD2CF8ut/aOXTZc/fBSgLWw1BgA4BDHOV0GkT90cBQpXahU5TFomsb38XhJC5/Tbh1P8c6rJlBeGfAeyMhUFwNVcs9lxV9Ot0dwmyd+mrNvRtbJ2fSPC6Z3Vsvub2z3sDFACAAYzk0+kUyxEkyfN7PopqNBro55A+P6yPKIrL5zF1HwjdeBJJCObIsZO79bo3sHhWhglo5WMV3mazuVPb4fLvSL8/FAkB1hK6rXQPwYhMyROK8VK5LAiH/jsMt0HQjxiN4/ePdoilllcqDyt3Mkg8mRBNbIhMb8RERkowQA/p76g0/UDDdCoNmDminM0qSK5vlpE5kugCHhNPxntwWmJPYTMZtYcFR6ABHQsVRlYLukVORaaULvqKI46keFSCv77kSPS6kxrPptLNDHgz16fWBtyxe6v5h08LUy+KI8ushqTPWWIX8Sg6b45IrGtyW6zXFb/hpQf9m3oqfWuB0fpSw0uZ4WB69En69uOk2rmO2V52PXj+A/mI4ESKpb2HAAAAAElFTkSuQmCC', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/iptorrents.py b/couchpotato/core/media/_base/providers/torrent/iptorrents.py index 0433d3e..e68808d 100644 --- a/couchpotato/core/media/_base/providers/torrent/iptorrents.py +++ b/couchpotato/core/media/_base/providers/torrent/iptorrents.py @@ -122,6 +122,7 @@ config = [{ 'name': 'IPTorrents', 'description': 'See IPTorrents', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABRklEQVR42qWQO0vDUBiG8zeKY3EqQUtNO7g0J6ZJ1+ifKIIFQXAqDYKCyaaYxM3udrZLHdRFhXrZ6liCW6mubfk874EESgqaeOCF7/Y8hEh41aq6yZi2nyZgBGya9XKtZs4No05pAkZV2YbEmyMMsoSxLQeC46wCTdPPY4HruPQyGIhF97qLWsS78Miydn4XdK46NJ9OsQAYBzMIMf8MQ9wtCnTdWCaIDx/u7uljOIQEe0hiIWPamSTLay3+RxOCSPI9+RJAo7Er9r2bnqjBFAqyK+VyK4f5/Cr5ni8OFKVCz49PFI5GdNvvU7ttE1M1zMU+8AMqFksEhrMnQsBDzqmDAwzx2ehRLwT7yyCI+vSC99c3mozH1NxrJgWWtR1BOECfEJSVCm6WCzJGCA7+IWhBsM4zywDPwEp4vCjx2DzBH2ODAfsDb33Ps6dQwJgAAAAASUVORK5CYII=', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py b/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py index 65bab4d..d611ddf 100644 --- a/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py +++ b/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py @@ -134,6 +134,7 @@ config = [{ 'name': 'KickAssTorrents', 'description': 'See KickAssTorrents', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACD0lEQVR42pXK20uTcRjA8d/fsJsuap0orBuFlm3hir3JJvQOVmuwllN20Lb2isI2nVHKjBqrCWYaNnNuBrkSWxglhDVJOkBdSWUOq5FgoiOrMdRJ2xPPxW+8OUf1ge/FcyCUSVe2qedK5U/OxNTTXRNXEQ52Glb4O6dNEfK1auJkvRY7+/zxnQbA/D596laXcY3OWOiaIX2393SGznUmxkUo/YkDgqHemuzobQ7+NV+reo5Q1mqp68GABdY3+/EloO+JeN4tEqiFU8f3CwhyWo9E7wfMgI0ELTDx0AvjIxcgvZoC9P7NMN7yMmrFeoKa68rfDfmrARsNN0Ihr55cx59ctZWSiwS5bLKpwW4dYJH+M/B6/CYszE0BFZ+egG+Ln+HRoBN/cpl1pV6COIMkOnBVA/w+fXgGKJVM4LxhumMleoL06hJ3wKcCfl+/TAKKx17gnFePRwkqxR4BQSpFkbCrrQJueI7mWpyfATQ9OQY43+uv/+PutBycJ3y2qn2x7jY50GJvnwLKZjOwspyE5I8F4N+1yr1uwqcs3ym63Hwo29EiAyzUWQVr6WVAS4lZCPutQG/2GtES2YiW3d3XflYKtL72kzAcdEDHeSa3czeIMyyz/TApRKvcFfE0isHbJMnrHCf6xTLb1ORvWNlWo91cvHrJUQo0o6ZoRi7dIiT/g2WEDi27Iyov21xMCvgNfXvtwIACfHwAAAAASUVORK5CYII=', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py b/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py index 80e2348..0a49075 100644 --- a/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py +++ b/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py @@ -189,6 +189,7 @@ config = [{ 'name': 'PassThePopcorn', 'description': 'See PassThePopcorn.me', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAARklEQVQoz2NgIAP8BwMiGWRpIN1JNWn/t6T9f532+W8GkNt7vzz9UkfarZVpb68BuWlbnqW1nU7L2DMx7eCoBlpqGOppCQB83zIgIg+wWQAAAABJRU5ErkJggg==', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/sceneaccess.py b/couchpotato/core/media/_base/providers/torrent/sceneaccess.py index e488b63..1ee6e47 100644 --- a/couchpotato/core/media/_base/providers/torrent/sceneaccess.py +++ b/couchpotato/core/media/_base/providers/torrent/sceneaccess.py @@ -91,6 +91,7 @@ config = [{ 'name': 'SceneAccess', 'description': 'See SceneAccess', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAACT0lEQVR4AYVQS0sbURidO3OTmajJ5FElTTOkPmZ01GhHrIq0aoWAj1Vc+A/cuRMXbl24V9SlCGqrLhVFCrooEhCp2BAx0mobTY2kaR7qmOm87EXL1EWxh29xL+c7nPMdgGHYO5bF/gdbefnr6WlbWRnxluMwAB4Z0uEgXa7nwaDL7+/RNPzxbYvb/XJ0FBYVfd/ayh0fQ4qCGEHcm0KLRZUk7Pb2YRJPRwcsKMidnKD3t9VVT3s7BDh+z5FOZ3Vfn3h+Hltfx00mRRSRWFcUmmVNhYVqPn8dj3va2oh+txvcQRVF9ebm1fi4k+dRFbosY5rm4Hk7xxULQnJnx93S4g0EIEEQRoDLo6PrWEw8Pc0eHLwYGopMTDirqlJ7eyhYYGHhfgfHCcKYksZGVB/NcXI2mw6HhZERqrjYTNPHi4tFPh8aJIYIhgPlcCRDoZLW1s75+Z/7+59nZ/OJhLWigqAoKZX6Mjf3dXkZ3pydGYLc4aEoCCkInzQ1fRobS2xuvllaonkedfArnY5OTdGVldBkOADgqq2Nr6z8CIWaJietDHOhKB+HhwFKC6Gnq4ukKJvP9zcSbjYDXbeVlkKzuZBhnnV3e3t6UOmaJO0ODibW1hB1GYkg8R/gup7Z3TVZLJ5AILW9LcZiVpYtYBhw16O3t7cauckyeF9Tgz0ATpL2+nopmWycmbnY2LiKRjFk6/d7+/vRJfl4HGzV1T0UIM43MGBvaIBWK/YvwM5w+IMgGH8tkyEgvIpE7M3Nt6qqZrNyOq1kMmouh455Ggz+BhKY4GEc2CfwAAAAAElFTkSuQmCC', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/thepiratebay.py b/couchpotato/core/media/_base/providers/torrent/thepiratebay.py index 487ce36..d963e22 100644 --- a/couchpotato/core/media/_base/providers/torrent/thepiratebay.py +++ b/couchpotato/core/media/_base/providers/torrent/thepiratebay.py @@ -131,6 +131,7 @@ config = [{ 'name': 'ThePirateBay', 'description': 'The world\'s largest bittorrent tracker. See ThePirateBay', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAA3UlEQVQY02P4DwT/YADIZvj//7qnozMYODmtAAusZoCDELDAegYGViZhAWZmRoYoqIDupfhNN1M3dTBEggXWMZg9jZRXV77YxhAOFpjDwMAPMoCXmcHsF1SAQZ6bQY2VgUEbKHClcAYzg3mINEO8jSCD478/DPsZmvqWblu1bOmStes3Pp0ezVDF4Gif0Hfx9///74/ObRZ2YNiZ47C8XIRBxFJR0jbSSUud4f9zAQWn8NTuziAt2zy5xIMM/z8LFX0E+fD/x0MRDCeA1v7Z++Y/FDzyvAtyBxIA+h8A8ZKLeT+lJroAAAAASUVORK5CYII=', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/torrentbytes.py b/couchpotato/core/media/_base/providers/torrent/torrentbytes.py index 85a4fda..0d95f5f 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentbytes.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentbytes.py @@ -92,6 +92,7 @@ config = [{ 'name': 'TorrentBytes', 'description': 'See TorrentBytes', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAeFBMVEUAAAAAAEQAA1QAEmEAKnQALHYAMoEAOokAQpIASYsASZgAS5UATZwATosATpgAVJ0AWZwAYZ4AZKAAaZ8Ab7IAcbMAfccAgcQAgcsAhM4AiscAjMkAmt0AoOIApecAp/EAqvQAs+kAt+wA3P8A4f8A//8VAAAfDbiaAl08AAAAjUlEQVQYGQXBO04DQRAFwHqz7Z8sECIl5f73ISRD5GBs7UxTlWfg9vYXnvJRQJqOL88D6BAwJtMMumHUVCl60aa6H93IrIv0b+157f1lpk+fm87lMWrZH0vncKbXdRUQrRmrh9C6Iwkq6rg4PXZcyXmbizzeV/g+rDra0rGve8jPKLSOJNi2AQAwAGjwD7ApPkEHdtPQAAAAAElFTkSuQmCC', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/torrentday.py b/couchpotato/core/media/_base/providers/torrent/torrentday.py index e690925..7e8eeb8 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentday.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentday.py @@ -70,6 +70,7 @@ config = [{ 'name': 'TorrentDay', 'description': 'See TorrentDay', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAC5ElEQVQ4y12TXUgUURTH//fO7Di7foeQJH6gEEEIZZllVohfSG/6UA+RSFAQQj74VA8+Bj30lmAlRVSEvZRfhNhaka5ZUG1paKaW39tq5O6Ou+PM3M4o6m6X+XPPzD3zm/+dcy574r515WfIW8CZBM4YAA5Gc/aQC3yd7oXYEONcsISE5dTDh91HS0t7FEWhBUAeN9ynV/d9qJAgE4AECURAcVsGlCCnly26LMA0IQwTa52dje3d3e3hcPi8qqrrMjcVYI3EHCQZlkFOHBwR2QHh2ASAAIJxWGAQEDxjePhs3527XjJwnb37OHBq0T+Tyyjh+9KnEzNJ7nouc1Q/3A3HGsOvnJy+PSUlj81w2Lny9WuJ6+3AmTjD4HOcrdR2dWXLRQePvyaSLfQOPMPC8mC9iHCsOxSyzJCelzdSXlNzD5ujpb25Wbfc/XXJemTXF4+nnCNq+AMLe50uFfEJTiw4GXSFtiHL0SnIq66+p0kSArqO+eH3RdsAv9+f5vW7L7GICq6rmM8XBCAXlBw90rOyxibn5yzfkg/L09M52/jxqdESaIrBXHYZZbB1GX8cEpySxKIB8S5XcOnvqpli1zuwmrTtoLjw5LOK/eeuWsE4JH5IRPaPZKiKigmPp+5pa+u1aEjIMhEgrRkmi9mgxGUhM7LNJSzOzsE3+cOeExovXOjdytE0LV4zqNZUtV0uZzAGoGkhDH/2YHZiErmv4uyWQnZZWc+hoqL3WzlTExN5hhA8IEwkZWZOxwB++30YG/9GkYCPvqAaHAW5uWPROW86OmqCprUR7z1yZDAGQNuCvkoB/baIKUBWMTYymv+gra3eJNvjXu+B562tFyXqTJ6YuHK8rKwvBmC3vR7cOCPQLWFz8LnfXWUrJo9U19BwMyUlJRjTSMJ2ENxUiGxq9KXQfwqYlnWstvbR5aamG9g0uzM8Q4OFt++3NNixQ2NgYmeN03FOTUv7XVpV9aKisvLl1vN/WVhNc/Fi1NEAAAAASUVORK5CYII=', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/torrentleech.py b/couchpotato/core/media/_base/providers/torrent/torrentleech.py index a591627..3f2edae 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentleech.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentleech.py @@ -82,6 +82,7 @@ config = [{ 'name': 'TorrentLeech', 'description': 'See TorrentLeech', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAACHUlEQVR4AZVSO48SYRSdGTCBEMKzILLAWiybkKAGMZRUUJEoDZX7B9zsbuQPYEEjNLTQkYgJDwsoSaxspEBsCITXjjNAIKi8AkzceXgmbHQ1NJ5iMufmO9/9zrmXlCSJ+B8o75J8Pp/NZj0eTzweBy0Wi4PBYD6f12o1r9ebTCZx+22HcrnMsuxms7m6urTZ7LPZDMVYLBZ8ZV3yo8aq9Pq0wzCMTqe77dDv9y8uLyAWBH6xWOyL0K/56fcb+rrPgPZ6PZfLRe1fsl6vCUmGKIqoqNXqdDr9Dbjps9znUV0uTqdTjuPkDoVCIfcuJ4gizjMMm8u9vW+1nr04czqdK56c37CbKY9j2+1WEARZ0Gq1RFHAz2q1qlQqXxoN69HRcDjUarW8ZD6QUigUOnY8uKYH8N1sNkul9yiGw+F6vS4Rxn8EsodEIqHRaOSnq9T7ajQazWQycEIR1AEBYDabSZJyHDucJyegwWBQr9ebTCaKvHd4cCQANUU9evwQ1Ofz4YvUKUI43GE8HouSiFiNRhOowWBIpVLyHITJkuW3PwgAEf3pgIwxF5r+OplMEsk3CPT5szCMnY7EwUdhwUh/CXiej0Qi3idPz89fdrpdbsfBzH7S3Q9K5pP4c0sAKpVKoVAQGO1ut+t0OoFAQHkH2Da/3/+but3uarWK0ZMQoNdyucRutdttmqZxMTzY7XaYxsrgtUjEZrNhkSwWyy/0NCatZumrNQAAAABJRU5ErkJggg==', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/torrentpotato.py b/couchpotato/core/media/_base/providers/torrent/torrentpotato.py index 84718f0..fe0d5be 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentpotato.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentpotato.py @@ -134,6 +134,7 @@ config = [{ 'order': 10, 'description': 'CouchPotato torrent provider. Checkout the wiki page about this provider for more info.', 'wizard': True, + 'icon': '', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/torrentshack.py b/couchpotato/core/media/_base/providers/torrent/torrentshack.py index 2a285b2..639beaf 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentshack.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentshack.py @@ -81,6 +81,7 @@ config = [{ 'list': 'torrent_providers', 'name': 'TorrentShack', 'description': 'See TorrentShack', + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABmElEQVQoFQXBzY2cVRiE0afqvd84CQiAnxWWtyxsS6ThINBYg2Dc7mZBMEjE4mzs6e9WcY5+ePNuVFJJodQAoLo+SaWCy9rcV8cmjah3CI6iYu7oRU30kE5xxELRfamklY3k1NL19sSm7vPzP/ZdNZzKVDaY2sPZJBh9fv5ITrmG2+Vp4e1sPchVqTCQZJnVXi+/L4uuAJGly1+Pw8CprLbi8Om7tbT19/XRqJUk11JP9uHj9ulxhXbvJbI9qJvr5YkGXFG2IBT8tXczt+sfzDZCp3765f3t9tHEHGEDACma77+8o4oATKk+/PfW9YmHruRFjWoVSFsVsGu1YSKq6Oc37+n98unPZSRlY7vsKDqN+92X3yR9+PdXee3iJNKMStqdcZqoTJbUSi5JOkpfRlhSI0mSpEmCFKoU7FqSNOLAk54uGwCStMUCgLrVic62g7oDoFmmdI+P3S0pDe1xvDqb6XrZqbtzShWNoh9fv/XQHaDdM9OqrZi2M7M3UrB2vlkPS1IbdEBk7UiSoD6VlZ6aKWer4aH4f/AvKoHUTjuyAAAAAElFTkSuQmCC', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/torrentz.py b/couchpotato/core/media/_base/providers/torrent/torrentz.py index 3937f64..51e505d 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentz.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentz.py @@ -80,6 +80,7 @@ config = [{ 'name': 'Torrentz', 'description': 'Torrentz is a free, fast and powerful meta-search engine. Torrentz', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAQklEQVQ4y2NgAALjtJn/ycEMlGiGG0IVAxiwAKzOxaKGARcgxgC8YNSAwWoAzuRMjgsIugqfAUR5CZcBRIcHsWEAADSA96Ig020yAAAAAElFTkSuQmCC', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/torrent/yify.py b/couchpotato/core/media/_base/providers/torrent/yify.py index b1380cd..0daf20a 100644 --- a/couchpotato/core/media/_base/providers/torrent/yify.py +++ b/couchpotato/core/media/_base/providers/torrent/yify.py @@ -49,7 +49,7 @@ class Base(TorrentMagnetProvider): if result['Quality'] and result['Quality'] not in result['MovieTitle']: title = result['MovieTitle'] + ' BrRip ' + result['Quality'] - else: + else: title = result['MovieTitle'] + ' BrRip' results.append({ @@ -79,6 +79,7 @@ config = [{ 'name': 'Yify', 'description': 'Free provider, less accurate. Small HD movies, encoded by Yify.', 'wizard': False, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAACL0lEQVR4AS1SPW/UQBAd23fxne/Ld2dvzvHuzPocEBAKokCBqGiQ6IgACYmvUKRBFEQgKKGg4BAlUoggggYUEQpSHOI7CIEoQs/fYcbLaU/efTvvvZlnA1qydoxU5kcxX0CkgmQZtPy0hCUjvK+WgEByOZ5dns1O5bzna8fRVkgsxH8B0YouIvBhdD5T11NiVOoKrsttyUcpRW0InUrFnwe9HzuP2uaQZYhF2LQ76TTXw2RVMTK8mYYbjfh+zNquMVCrqn93aArLSixPxnafdGDLaz1tjY5rmNa8z5BczEQOxQfCl1GyoqoWxYRN1bkh7ELw3q/vhP6HIL4TG9KumpjgvwuyM7OsjSj98E/vszMfZ7xvPtMaWxGO5crwIumKCR5HxDtJ0AWKGG204RfUd/3smJYqwem/Q7BTS1ZGfM4LNpVwuKAz6cMeROst0S2EwNE7GjTehO2H3dxqIpdkydat15G3F8SXBi4GlpBNlSz012L/k2+W0CLLk/jbcf13rf41yJeMQ8QWUZiHCfCA9ad+81nEKPtoS9mJOf9v0NmMJHgUT6xayheK9EIK7JJeU/AF4scDF7Y5SPlJrRcxJ+um4ibNEdObxLiIwJim+eT2AL5D9CIcnZ5zvSJi9eIlNHVVtZ831dk5svPgvjPWTq+ktWkd/kD0qtm71x+sDQe3kt6DXnM7Ct+GajmTxKlkAokWljyAKSm5oWa2w+BH4P2UuVub7eTyiGOQYapY/wEztHduSDYz5gAAAABJRU5ErkJggg==', 'options': [ { 'name': 'enabled', From 21a1770f3f4f4ef011692b5dd4d2e590a13c8356 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 18:14:08 +0200 Subject: [PATCH 026/117] Nzb icons --- couchpotato/core/media/_base/providers/nzb/binsearch.py | 1 + couchpotato/core/media/_base/providers/nzb/newznab.py | 1 + couchpotato/core/media/_base/providers/nzb/nzbclub.py | 1 + couchpotato/core/media/_base/providers/nzb/nzbindex.py | 1 + couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py | 1 + 5 files changed, 5 insertions(+) diff --git a/couchpotato/core/media/_base/providers/nzb/binsearch.py b/couchpotato/core/media/_base/providers/nzb/binsearch.py index 84c7b31..c61b72d 100644 --- a/couchpotato/core/media/_base/providers/nzb/binsearch.py +++ b/couchpotato/core/media/_base/providers/nzb/binsearch.py @@ -100,6 +100,7 @@ config = [{ 'name': 'binsearch', 'description': 'Free provider, less accurate. See BinSearch', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAATklEQVQY02NwQAMMWAXOnz+PKvD//3/CAvM//z+fgiwAAs+RBab4PP//vwbFjPlAffgEChzOo2r5fBuIfRAC5w8D+QUofkkp8MHjOWQAAM3Sbogztg2wAAAAAElFTkSuQmCC', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/nzb/newznab.py b/couchpotato/core/media/_base/providers/nzb/newznab.py index 628a55f..7db7e86 100644 --- a/couchpotato/core/media/_base/providers/nzb/newznab.py +++ b/couchpotato/core/media/_base/providers/nzb/newznab.py @@ -222,6 +222,7 @@ config = [{ Spotweb, NZBGeek, \ SmackDown, NZBFinder', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEVjhwD///86aRovd/sBAAAAMklEQVQI12NgAIPQUCCRmQkjssDEShiRuRIqwZqZGcDAGBrqANUhGgIkWAOABKMDxCAA24UK50b26SAAAAAASUVORK5CYII=', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/nzb/nzbclub.py b/couchpotato/core/media/_base/providers/nzb/nzbclub.py index 06ae7fe..a266089 100644 --- a/couchpotato/core/media/_base/providers/nzb/nzbclub.py +++ b/couchpotato/core/media/_base/providers/nzb/nzbclub.py @@ -80,6 +80,7 @@ config = [{ 'name': 'NZBClub', 'description': 'Free provider, less accurate. See NZBClub', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACEUlEQVQ4y3VSMWgUQRR9/8/s7OzeJSdnTsVGghLEYBNQjBpQiRBFhIB2EcHG1kbs0murhZAmVocExEZQ0c7CxkLINYcJJpoYj9wZcnu72fF21uJSXMzuhyne58/j/fcf4b+KokgBIOSU53lxP5b9oNVqDT36dH+5UjoiKvIwPFEEgWBshGZ3E7/NOupL9fMjx0e+ZhKsrq+c/FPZKJi0w4FsQXMBDEJsd7BNW9h2tuyP9vfTALIJkMIu1hYRtINM+dpzcWc0sbkreK4fUEogyraAmKGF3+7vcT/wtR9QwkCabSAzQQuvk0uglAo5YaQ5DASGYjfMXcHVOqKu6NmR7iehlKAdHWUqWPv1c3i+9uwVdRlEBGaGEAJCCrDo9ShhvF6qPq8tL57bp+DbRn2sHtUuCY9YphLMu5921VhrwYJ5tbt0tt6sjQP4vEfB2Ikz7/ytwbeR6ljHkXCUA6UcOLtPOg4MYhtH8ZcLw5er+xQMDAwEURRNl96X596Y6oxFwsw9fmtTOAr2Ik19nL365FZpsLSdnQPPM8aYewc+lDcX4rkHqbQMAGTJXulOLzycmr1bKBTi3DOGYagajcahiaOT89fbM0/dxEsUu3aidfPljWO3HzebzYNBELi5Z5RSJlrrHd/3w8lT114MrVTWOn875fHRiYVisRhorWMpZXdvNnLKGCOstb0AMlulVJI19w/+nceU4D0aCwAAAABJRU5ErkJggg==', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/nzb/nzbindex.py b/couchpotato/core/media/_base/providers/nzb/nzbindex.py index ddcce8a..58f4b23 100644 --- a/couchpotato/core/media/_base/providers/nzb/nzbindex.py +++ b/couchpotato/core/media/_base/providers/nzb/nzbindex.py @@ -105,6 +105,7 @@ config = [{ 'name': 'nzbindex', 'description': 'Free provider, less accurate. See NZBIndex', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAo0lEQVR42t2SQQ2AMBAEcUCwUAv94QMLfHliAQtYqIVawEItYAG6yZFMLkUANNlk79Kbbtp2P1j9uKxVV9VWFeStl+Wh3fWK9hNwEoADZkJtMD49AqS5AUjWGx6A+m+ARICGrM5W+wSTB0gETKzdHZwCEZAJ8PGZQN4AiQAmkR9s06EBAugJiBoAAPFfAQcBgZcIHzwA6TYP4JsXeSg3P9L31w3eksbH3zMb/wAAAABJRU5ErkJggg==', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py b/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py index acd12cf..bac0614 100644 --- a/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py +++ b/couchpotato/core/media/_base/providers/nzb/omgwtfnzbs.py @@ -74,6 +74,7 @@ config = [{ 'name': 'OMGWTFNZBs', 'description': 'See OMGWTFNZBs', 'wizard': True, + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAIAAADAAbR1AAADbElEQVR4AZ2UW0ybZRiAy/OvdHaLYvB0YTRIFi7GkM44zRLmIfNixkWdiRMyYoxRE8/TC7MYvXCGEBmr3mxLwVMwY0wYA7e6Wso4lB6h/U9taSlMGIfBXLYlJMyo0S///2dJI5lxN8/F2/f9nu9737e/jYmXr6KTbN9BGG9HE/NotQ76UWziNzrXFiETk/5ARUNH+7+0kW7fSgTl0VKGOLZzidOkmuuIo7q2oTArNLPIzhdIkqXkerFOm2CaD/5bcKrjIL2c3fkhPxOq93Kcb91v46fV9TQKF4TgV/TbUsQtzfCaK6jMOd5DJrguSIIhexmqqVxN0FXbRR8/ND/LYTTj6J7nl2gnL47OkDW4KJhnQHCa6JpKVNJGA3OC58nwBJoZ//ebbIyKpBxjrr0o1q1FMRkrKXZnHWF85VvxMrJxibwhGyd0f5bLnKzqJs1k0Sfo+EU8hdAUvkbcwKEgs2D0OiV4jmmD1zb+Tp6er0JMMvDxPo5xev9zTBF683NS+N56n1YiB95B5crr93KRuKhKI0tb0Kw2mgLLqTjLEWO8424i9IvURaYeOckwf3+/yCC9e3bQQ/MuD+Monk0k+XFXMUfx7z5EEP+XlXi5tLlMxH8zLppw7idJrugcus30kC86gc7UrQqjLIukM8zWHOACeU+TiMxXN6ExVOkgz4lvPEzice1GIVhxhG4CrZvpl6TH55giKWqXGLy9hZh5aUtgDSew/msSyCKpl+DDNfxJc8NBIsxUxUnz14O/oONu+IIIvso9TLBQ1SY5rUhuSzUhAqJ2mRXBLDOCeUtgUZXsaObT8BffhUJPqWgiV+3zKKzYH0ClvTRLhD77HIqVkyh5jThnivehoG+qJctIRSPn6bxvO4FCgTl9c1DmbpjLajbQFE8aW5SU3rg+zOPGUjTUF9NFpLEbH2c/KmGYlY69/GQJVtGMSUcEp9eCbB1nctbxHTLRdTUkGDf+B02uGWRG3OvpJ/zSMwzif+oxVBID3cQKBavLCiPmB2PM2UuSCUPgrX4VDb97AwEG67bh4+KTOlncvu3M31BwA5rLHbCfEjwkNDky9e/SSbSxnD46Pg0RJtpXRvhmBSZHpRjWtKwFybjuQeXaKxto4WjLZZZvVmC17pZLJFkwxm5++PS2Mrwc7nyIMYZe/IzoP5d6QgEybqTXAAAAAElFTkSuQmCC', 'options': [ { 'name': 'enabled', From 643be197118467e9abfaf9b965d0edef33ceb06d Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 20:45:17 +0200 Subject: [PATCH 027/117] Update descriptions --- couchpotato/core/media/_base/providers/torrent/bithdtv.py | 2 +- couchpotato/core/media/_base/providers/torrent/bitsoup.py | 2 +- couchpotato/core/media/_base/providers/torrent/hdbits.py | 2 +- couchpotato/core/media/_base/providers/torrent/iptorrents.py | 2 +- couchpotato/core/media/_base/providers/torrent/kickasstorrents.py | 2 +- couchpotato/core/media/_base/providers/torrent/passthepopcorn.py | 2 +- couchpotato/core/media/_base/providers/torrent/sceneaccess.py | 2 +- couchpotato/core/media/_base/providers/torrent/thepiratebay.py | 2 +- couchpotato/core/media/_base/providers/torrent/torrentbytes.py | 2 +- couchpotato/core/media/_base/providers/torrent/torrentday.py | 2 +- couchpotato/core/media/_base/providers/torrent/torrentleech.py | 2 +- couchpotato/core/media/_base/providers/torrent/torrentshack.py | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/couchpotato/core/media/_base/providers/torrent/bithdtv.py b/couchpotato/core/media/_base/providers/torrent/bithdtv.py index 34a21f9..57bc221 100644 --- a/couchpotato/core/media/_base/providers/torrent/bithdtv.py +++ b/couchpotato/core/media/_base/providers/torrent/bithdtv.py @@ -93,7 +93,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'BiT-HDTV', - 'description': 'See BiT-HDTV', + 'description': 'BiT-HDTV', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABMklEQVR4AZ3Qu0ojcQCF8W9MJcQbJNgEEQUbQVIqWgnaWfkIvoCgggixEAmIhRtY2GV3w7KwU61B0EYIxmiw0YCik84ipaCuc0nmP5dcjIUgOjqDvxf4OAdf9mnMLcUJyPyGSCP+YRdC+Kp8iagJKhuS+InYRhTGgDbeV2uEMand4ZRxizjXHQEimxhraAnUr73BNqQxMiNeV2SwcjTLEVtb4Zl10mXutvOWm2otw5Sxz6TGTbdd6ncuYvVLXAXrvM+ruyBpy1S3JLGDfUQ1O6jn5vTsrJXvqSt4UNfj6vxTRPxBHER5QeSirhLGk/5rWN+ffB1XZuxjnDy1q87m7TS+xOGA+Iv4gfkbaw+nOMXHDHnITGEk0VfRFnn4Po4vNYm6RGukmggR0L08+l+e4HMeASo/i6AJUjLgAAAAAElFTkSuQmCC', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/bitsoup.py b/couchpotato/core/media/_base/providers/torrent/bitsoup.py index 2b1a0e7..9519e58 100644 --- a/couchpotato/core/media/_base/providers/torrent/bitsoup.py +++ b/couchpotato/core/media/_base/providers/torrent/bitsoup.py @@ -88,7 +88,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'Bitsoup', - 'description': 'See Bitsoup', + 'description': 'Bitsoup', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAB8ElEQVR4AbWSS2sTURiGz3euk0mswaE37HhNhIrajQheFgF3rgR/lAt/gOBCXNZlo6AbqfUWRVCxi04wqUnTRibpJLaJzdzOOZ6WUumyC5/VHOb9eN/FA91uFx0FjI4IPfgiGLTWH73tn348GKmN7ijD0d2b41fO5qJEaX24AWNIUrVQCTTJ3Llx6vbV6Vtzk7Gi9+ebi996guFDDYAQAVj4FExP5qdOZB49W62t/zH3hECcwsPnbWeMXz6Xi2K1f0ApeK3hMCHHbP5gvvoriBgFAAQJEAxhjJ4u+YWTNsVI6b1JgtPWZkoIefKy4fcii2OTw2BABs7wj3bYDlLL4rvjGWOdTser1j5Xf7c3Q/MbHQYApxItvnm31mhQQ71eX2vUB76/vsWB2hg0QuogrMwLIG8P3InM2/eVGXeDViqVwWB79vRU2lgJYmdHcgXCTAXQFJTN5HguvDCR2Hxsxe8EvT54nlcul5vNpqDIEgwRQanAhAAABgRIyiQcjpIkkTOuWyqVoN/vSylX67XXH74uV1vHRUyxxFqbLBCSmBpiXSq6xcL5QrGYzWZ3XQIAwdlOJB+/aL764ucdmncYs0WsCI7kvTnn+qyDMEnTVCn1Tz5KsBFg6fvWcmsUAcnYNC/g2hnromvvqbHvxv+39S+MX+bWkFXwAgAAAABJRU5ErkJggg==', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/hdbits.py b/couchpotato/core/media/_base/providers/torrent/hdbits.py index 0887f97..a09fe7d 100644 --- a/couchpotato/core/media/_base/providers/torrent/hdbits.py +++ b/couchpotato/core/media/_base/providers/torrent/hdbits.py @@ -71,7 +71,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'HDBits', - 'description': 'See HDBits', + 'description': 'HDBits', 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABi0lEQVR4AZWSzUsbQRjGdyabTcvSNPTSHlpQQeMHJApC8CJRvHgQQU969+LJP8G7f4N3DwpeFRQvRr0EKaUl0ATSpkigUNFsMl/r9NmZLCEHA/nNO5PfvMPDm0DI6fV3ZxiolEICe1oZCBVCCmBPKwOh2ErKBHGE4KYEXBpSLkUlqO4LcM7f+6nVhRnOhSkOz/hexk+tL+YL0yPF2YmN4tynD++4gTLGkNNac9YFLoREBR1+cnF3dFY6v/m6PD+FaXiNJtgA4xYbABxiGrz6+6HWaI5/+Qh37YS0/3Znc8UxwNGBIIBX22z+/ZdJ+4wzyjpR4PEpODg8tgUXBv2iWUzSpa12B0IR6n6lvt8Aek2lZHb084+fdRNgrwY8z81PjhVy2d2ttUrtV/lbBa+JXGEpDMPnoF2tN1QYRqVUtf6nFbThb7wk7le395elcqhASLb39okDiHY00VCtCTEHwSiH4AI0lkOiT1dwMeSfT3SRxiQWNO7Zwj1egkoVIQFMKvSiC3bcjXq9Jf8DcDIRT3hh10kAAAAASUVORK5CYII=', 'options': [ { diff --git a/couchpotato/core/media/_base/providers/torrent/iptorrents.py b/couchpotato/core/media/_base/providers/torrent/iptorrents.py index e68808d..0915ca3 100644 --- a/couchpotato/core/media/_base/providers/torrent/iptorrents.py +++ b/couchpotato/core/media/_base/providers/torrent/iptorrents.py @@ -120,7 +120,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'IPTorrents', - 'description': 'See IPTorrents', + 'description': 'IPTorrents', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABRklEQVR42qWQO0vDUBiG8zeKY3EqQUtNO7g0J6ZJ1+ifKIIFQXAqDYKCyaaYxM3udrZLHdRFhXrZ6liCW6mubfk874EESgqaeOCF7/Y8hEh41aq6yZi2nyZgBGya9XKtZs4No05pAkZV2YbEmyMMsoSxLQeC46wCTdPPY4HruPQyGIhF97qLWsS78Miydn4XdK46NJ9OsQAYBzMIMf8MQ9wtCnTdWCaIDx/u7uljOIQEe0hiIWPamSTLay3+RxOCSPI9+RJAo7Er9r2bnqjBFAqyK+VyK4f5/Cr5ni8OFKVCz49PFI5GdNvvU7ttE1M1zMU+8AMqFksEhrMnQsBDzqmDAwzx2ehRLwT7yyCI+vSC99c3mozH1NxrJgWWtR1BOECfEJSVCm6WCzJGCA7+IWhBsM4zywDPwEp4vCjx2DzBH2ODAfsDb33Ps6dQwJgAAAAASUVORK5CYII=', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py b/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py index d611ddf..730bb60 100644 --- a/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py +++ b/couchpotato/core/media/_base/providers/torrent/kickasstorrents.py @@ -132,7 +132,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'KickAssTorrents', - 'description': 'See KickAssTorrents', + 'description': 'KickAssTorrents', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACD0lEQVR42pXK20uTcRjA8d/fsJsuap0orBuFlm3hir3JJvQOVmuwllN20Lb2isI2nVHKjBqrCWYaNnNuBrkSWxglhDVJOkBdSWUOq5FgoiOrMdRJ2xPPxW+8OUf1ge/FcyCUSVe2qedK5U/OxNTTXRNXEQ52Glb4O6dNEfK1auJkvRY7+/zxnQbA/D596laXcY3OWOiaIX2393SGznUmxkUo/YkDgqHemuzobQ7+NV+reo5Q1mqp68GABdY3+/EloO+JeN4tEqiFU8f3CwhyWo9E7wfMgI0ELTDx0AvjIxcgvZoC9P7NMN7yMmrFeoKa68rfDfmrARsNN0Ihr55cx59ctZWSiwS5bLKpwW4dYJH+M/B6/CYszE0BFZ+egG+Ln+HRoBN/cpl1pV6COIMkOnBVA/w+fXgGKJVM4LxhumMleoL06hJ3wKcCfl+/TAKKx17gnFePRwkqxR4BQSpFkbCrrQJueI7mWpyfATQ9OQY43+uv/+PutBycJ3y2qn2x7jY50GJvnwLKZjOwspyE5I8F4N+1yr1uwqcs3ym63Hwo29EiAyzUWQVr6WVAS4lZCPutQG/2GtES2YiW3d3XflYKtL72kzAcdEDHeSa3czeIMyyz/TApRKvcFfE0isHbJMnrHCf6xTLb1ORvWNlWo91cvHrJUQo0o6ZoRi7dIiT/g2WEDi27Iyov21xMCvgNfXvtwIACfHwAAAAASUVORK5CYII=', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py b/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py index 0a49075..609ef2d 100644 --- a/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py +++ b/couchpotato/core/media/_base/providers/torrent/passthepopcorn.py @@ -187,7 +187,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'PassThePopcorn', - 'description': 'See PassThePopcorn.me', + 'description': 'PassThePopcorn.me', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAARklEQVQoz2NgIAP8BwMiGWRpIN1JNWn/t6T9f532+W8GkNt7vzz9UkfarZVpb68BuWlbnqW1nU7L2DMx7eCoBlpqGOppCQB83zIgIg+wWQAAAABJRU5ErkJggg==', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/sceneaccess.py b/couchpotato/core/media/_base/providers/torrent/sceneaccess.py index 1ee6e47..e172f6a 100644 --- a/couchpotato/core/media/_base/providers/torrent/sceneaccess.py +++ b/couchpotato/core/media/_base/providers/torrent/sceneaccess.py @@ -89,7 +89,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'SceneAccess', - 'description': 'See SceneAccess', + 'description': 'SceneAccess', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAACT0lEQVR4AYVQS0sbURidO3OTmajJ5FElTTOkPmZ01GhHrIq0aoWAj1Vc+A/cuRMXbl24V9SlCGqrLhVFCrooEhCp2BAx0mobTY2kaR7qmOm87EXL1EWxh29xL+c7nPMdgGHYO5bF/gdbefnr6WlbWRnxluMwAB4Z0uEgXa7nwaDL7+/RNPzxbYvb/XJ0FBYVfd/ayh0fQ4qCGEHcm0KLRZUk7Pb2YRJPRwcsKMidnKD3t9VVT3s7BDh+z5FOZ3Vfn3h+Hltfx00mRRSRWFcUmmVNhYVqPn8dj3va2oh+txvcQRVF9ebm1fi4k+dRFbosY5rm4Hk7xxULQnJnx93S4g0EIEEQRoDLo6PrWEw8Pc0eHLwYGopMTDirqlJ7eyhYYGHhfgfHCcKYksZGVB/NcXI2mw6HhZERqrjYTNPHi4tFPh8aJIYIhgPlcCRDoZLW1s75+Z/7+59nZ/OJhLWigqAoKZX6Mjf3dXkZ3pydGYLc4aEoCCkInzQ1fRobS2xuvllaonkedfArnY5OTdGVldBkOADgqq2Nr6z8CIWaJietDHOhKB+HhwFKC6Gnq4ukKJvP9zcSbjYDXbeVlkKzuZBhnnV3e3t6UOmaJO0ODibW1hB1GYkg8R/gup7Z3TVZLJ5AILW9LcZiVpYtYBhw16O3t7cauckyeF9Tgz0ATpL2+nopmWycmbnY2LiKRjFk6/d7+/vRJfl4HGzV1T0UIM43MGBvaIBWK/YvwM5w+IMgGH8tkyEgvIpE7M3Nt6qqZrNyOq1kMmouh455Ggz+BhKY4GEc2CfwAAAAAElFTkSuQmCC', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/thepiratebay.py b/couchpotato/core/media/_base/providers/torrent/thepiratebay.py index d963e22..57bcfbd 100644 --- a/couchpotato/core/media/_base/providers/torrent/thepiratebay.py +++ b/couchpotato/core/media/_base/providers/torrent/thepiratebay.py @@ -129,7 +129,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'ThePirateBay', - 'description': 'The world\'s largest bittorrent tracker. See ThePirateBay', + 'description': 'The world\'s largest bittorrent tracker. ThePirateBay', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAA3UlEQVQY02P4DwT/YADIZvj//7qnozMYODmtAAusZoCDELDAegYGViZhAWZmRoYoqIDupfhNN1M3dTBEggXWMZg9jZRXV77YxhAOFpjDwMAPMoCXmcHsF1SAQZ6bQY2VgUEbKHClcAYzg3mINEO8jSCD478/DPsZmvqWblu1bOmStes3Pp0ezVDF4Gif0Hfx9///74/ObRZ2YNiZ47C8XIRBxFJR0jbSSUud4f9zAQWn8NTuziAt2zy5xIMM/z8LFX0E+fD/x0MRDCeA1v7Z++Y/FDzyvAtyBxIA+h8A8ZKLeT+lJroAAAAASUVORK5CYII=', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/torrentbytes.py b/couchpotato/core/media/_base/providers/torrent/torrentbytes.py index 0d95f5f..156243e 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentbytes.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentbytes.py @@ -90,7 +90,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'TorrentBytes', - 'description': 'See TorrentBytes', + 'description': 'TorrentBytes', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAeFBMVEUAAAAAAEQAA1QAEmEAKnQALHYAMoEAOokAQpIASYsASZgAS5UATZwATosATpgAVJ0AWZwAYZ4AZKAAaZ8Ab7IAcbMAfccAgcQAgcsAhM4AiscAjMkAmt0AoOIApecAp/EAqvQAs+kAt+wA3P8A4f8A//8VAAAfDbiaAl08AAAAjUlEQVQYGQXBO04DQRAFwHqz7Z8sECIl5f73ISRD5GBs7UxTlWfg9vYXnvJRQJqOL88D6BAwJtMMumHUVCl60aa6H93IrIv0b+157f1lpk+fm87lMWrZH0vncKbXdRUQrRmrh9C6Iwkq6rg4PXZcyXmbizzeV/g+rDra0rGve8jPKLSOJNi2AQAwAGjwD7ApPkEHdtPQAAAAAElFTkSuQmCC', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/torrentday.py b/couchpotato/core/media/_base/providers/torrent/torrentday.py index 7e8eeb8..a3e9b78 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentday.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentday.py @@ -68,7 +68,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'TorrentDay', - 'description': 'See TorrentDay', + 'description': 'TorrentDay', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAC5ElEQVQ4y12TXUgUURTH//fO7Di7foeQJH6gEEEIZZllVohfSG/6UA+RSFAQQj74VA8+Bj30lmAlRVSEvZRfhNhaka5ZUG1paKaW39tq5O6Ou+PM3M4o6m6X+XPPzD3zm/+dcy574r515WfIW8CZBM4YAA5Gc/aQC3yd7oXYEONcsISE5dTDh91HS0t7FEWhBUAeN9ynV/d9qJAgE4AECURAcVsGlCCnly26LMA0IQwTa52dje3d3e3hcPi8qqrrMjcVYI3EHCQZlkFOHBwR2QHh2ASAAIJxWGAQEDxjePhs3527XjJwnb37OHBq0T+Tyyjh+9KnEzNJ7nouc1Q/3A3HGsOvnJy+PSUlj81w2Lny9WuJ6+3AmTjD4HOcrdR2dWXLRQePvyaSLfQOPMPC8mC9iHCsOxSyzJCelzdSXlNzD5ujpb25Wbfc/XXJemTXF4+nnCNq+AMLe50uFfEJTiw4GXSFtiHL0SnIq66+p0kSArqO+eH3RdsAv9+f5vW7L7GICq6rmM8XBCAXlBw90rOyxibn5yzfkg/L09M52/jxqdESaIrBXHYZZbB1GX8cEpySxKIB8S5XcOnvqpli1zuwmrTtoLjw5LOK/eeuWsE4JH5IRPaPZKiKigmPp+5pa+u1aEjIMhEgrRkmi9mgxGUhM7LNJSzOzsE3+cOeExovXOjdytE0LV4zqNZUtV0uZzAGoGkhDH/2YHZiErmv4uyWQnZZWc+hoqL3WzlTExN5hhA8IEwkZWZOxwB++30YG/9GkYCPvqAaHAW5uWPROW86OmqCprUR7z1yZDAGQNuCvkoB/baIKUBWMTYymv+gra3eJNvjXu+B562tFyXqTJ6YuHK8rKwvBmC3vR7cOCPQLWFz8LnfXWUrJo9U19BwMyUlJRjTSMJ2ENxUiGxq9KXQfwqYlnWstvbR5aamG9g0uzM8Q4OFt++3NNixQ2NgYmeN03FOTUv7XVpV9aKisvLl1vN/WVhNc/Fi1NEAAAAASUVORK5CYII=', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/torrentleech.py b/couchpotato/core/media/_base/providers/torrent/torrentleech.py index 3f2edae..5f59dab 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentleech.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentleech.py @@ -80,7 +80,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'TorrentLeech', - 'description': 'See TorrentLeech', + 'description': 'TorrentLeech', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAACHUlEQVR4AZVSO48SYRSdGTCBEMKzILLAWiybkKAGMZRUUJEoDZX7B9zsbuQPYEEjNLTQkYgJDwsoSaxspEBsCITXjjNAIKi8AkzceXgmbHQ1NJ5iMufmO9/9zrmXlCSJ+B8o75J8Pp/NZj0eTzweBy0Wi4PBYD6f12o1r9ebTCZx+22HcrnMsuxms7m6urTZ7LPZDMVYLBZ8ZV3yo8aq9Pq0wzCMTqe77dDv9y8uLyAWBH6xWOyL0K/56fcb+rrPgPZ6PZfLRe1fsl6vCUmGKIqoqNXqdDr9Dbjps9znUV0uTqdTjuPkDoVCIfcuJ4gizjMMm8u9vW+1nr04czqdK56c37CbKY9j2+1WEARZ0Gq1RFHAz2q1qlQqXxoN69HRcDjUarW8ZD6QUigUOnY8uKYH8N1sNkul9yiGw+F6vS4Rxn8EsodEIqHRaOSnq9T7ajQazWQycEIR1AEBYDabSZJyHDucJyegwWBQr9ebTCaKvHd4cCQANUU9evwQ1Ofz4YvUKUI43GE8HouSiFiNRhOowWBIpVLyHITJkuW3PwgAEf3pgIwxF5r+OplMEsk3CPT5szCMnY7EwUdhwUh/CXiej0Qi3idPz89fdrpdbsfBzH7S3Q9K5pP4c0sAKpVKoVAQGO1ut+t0OoFAQHkH2Da/3/+but3uarWK0ZMQoNdyucRutdttmqZxMTzY7XaYxsrgtUjEZrNhkSwWyy/0NCatZumrNQAAAABJRU5ErkJggg==', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/torrentshack.py b/couchpotato/core/media/_base/providers/torrent/torrentshack.py index 639beaf..bab508a 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentshack.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentshack.py @@ -80,7 +80,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'TorrentShack', - 'description': 'See TorrentShack', + 'description': 'TorrentShack', 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABmElEQVQoFQXBzY2cVRiE0afqvd84CQiAnxWWtyxsS6ThINBYg2Dc7mZBMEjE4mzs6e9WcY5+ePNuVFJJodQAoLo+SaWCy9rcV8cmjah3CI6iYu7oRU30kE5xxELRfamklY3k1NL19sSm7vPzP/ZdNZzKVDaY2sPZJBh9fv5ITrmG2+Vp4e1sPchVqTCQZJnVXi+/L4uuAJGly1+Pw8CprLbi8Om7tbT19/XRqJUk11JP9uHj9ulxhXbvJbI9qJvr5YkGXFG2IBT8tXczt+sfzDZCp3765f3t9tHEHGEDACma77+8o4oATKk+/PfW9YmHruRFjWoVSFsVsGu1YSKq6Oc37+n98unPZSRlY7vsKDqN+92X3yR9+PdXee3iJNKMStqdcZqoTJbUSi5JOkpfRlhSI0mSpEmCFKoU7FqSNOLAk54uGwCStMUCgLrVic62g7oDoFmmdI+P3S0pDe1xvDqb6XrZqbtzShWNoh9fv/XQHaDdM9OqrZi2M7M3UrB2vlkPS1IbdEBk7UiSoD6VlZ6aKWer4aH4f/AvKoHUTjuyAAAAAElFTkSuQmCC', 'options': [ { From 1e183625c9581966ebb4035782c1f5dc39889d32 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 20:45:26 +0200 Subject: [PATCH 028/117] Description update --- couchpotato/core/media/_base/providers/torrent/awesomehd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/media/_base/providers/torrent/awesomehd.py b/couchpotato/core/media/_base/providers/torrent/awesomehd.py index ccdf766..78c4648 100644 --- a/couchpotato/core/media/_base/providers/torrent/awesomehd.py +++ b/couchpotato/core/media/_base/providers/torrent/awesomehd.py @@ -78,7 +78,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'Awesome-HD', - 'description': 'See AHD', + 'description': 'AHD', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAC+UlEQVR4AV1SO0y6dxQ9H4g8CoIoohZ5NA0aR2UgkYpNB5uocTSaLlrDblMH09Gt8d90r3YpJkanxjA4GGkbO7RNxSABq8jDGnkpD+UD5NV7Bxvbk9wvv+/3uPece66A/yEWi42FQqHVfD7/cbPZtIEglUpjOp3uZHR0dBvAn3gDIRqNgjE4OKj0+Xzf3NzcfD4wMCCjf5TLZbTbbajVatzf3+Pu7q5uNpt35ufnvwBQAScQRREEldfr9RWLxan+/n5YrVa+jFarhVfQQyQSCU4EhULhX15engEgSrjC0dHRVqlUmjQYDBgaGgKtuTqz4mTgIoVCASaTCX19fajVapOHh4dbFJBks9mxcDi8qtFoJEajkfVyJWi1WkxMTMDhcIAT8x6D7/Dd6+vr1fHx8TGp2+3+iqo5+YCzBwIBToK5ubl/mQwPDyMSibAs2Gw2UHNRrValz8/PDUk8Hv9EqVRCr9fj4uICTNflcqFer+Pg4AB7e3uoVCq8x9Rxfn6O7u5uqFQq8FspZXxHTekggByA3W4Hr9PpNDeRL3I1cMhkMrBrnZ2dyGQyvNYIs7OzVbJNPjIyAraLwYdcjR8wXl5eIJfLwRIFQQDLYkm3t7c1CdGPPT4+cpOImp4PODMeaK+n10As2jBbrHifHOjS6qAguVFimkqlwAMmIQnHV1dX4NDQhVwuhyZTV6pgIktzDzkkk0lEwhEEzs7ASQr5Ai4vL1nuccfCwsLO/v6+p9FoyJhF6ekJro/cPCzIZLNQa7rQoK77/SdgWWpKkCaJ5EB9aWnpe6nH40nRMBnJV4f5gw+FX3/5GX/8/htXRZdOzzqhJWn6nl6YbTZqqhrhULD16fT0d8FgcFtYW1vD5uamfGVl5cd4IjldKhZACdkJvKfWUANrxEaJV4hiGVaL1b+7653hXzwRZQr2X76xsfG1xWIRaZzbNPv/CdrjEL9cX/+WXFBSgEPgzxuwG3Yans9OT0+naBZMIJDNfzudzp8WFxd/APAX3uAf9WOTxOPLdosAAAAASUVORK5CYII=', 'options': [ From 9df14bd55ad5e92b155b256747d81b22fa499004 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 21:04:24 +0200 Subject: [PATCH 029/117] Cleanup provider lists --- .../media/_base/providers/torrent/torrentpotato.py | 2 +- couchpotato/static/scripts/page/settings.js | 25 ++++++++++++++---- couchpotato/static/style/settings.css | 30 +++++++++++++++++++--- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/couchpotato/core/media/_base/providers/torrent/torrentpotato.py b/couchpotato/core/media/_base/providers/torrent/torrentpotato.py index fe0d5be..d142676 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentpotato.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentpotato.py @@ -134,7 +134,7 @@ config = [{ 'order': 10, 'description': 'CouchPotato torrent provider. Checkout the wiki page about this provider for more info.', 'wizard': True, - 'icon': '', + 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABSElEQVR4AZ2Nz0oCURTGv8t1YMpqUxt9ARFxoQ/gQtppgvUKcu/sxB5iBJkogspaBC6iVUplEC6kv+oiiKDNhAtt16roP0HQgdsMLgaxfvy4nHP4Pi48qE2g4v91JOqT1CH/UnA7w7icUlLawyEdj+ZI/7h6YluWbRiddHonHh9M70aj7VTKzuXuikUMci/EO/ACnAI15599oAk8AR/AgxBQNCzreD7bmpl+FOIVuAHqQDUcJo+AK+CZFKLt95/MpSmMt0TiW9POxse6UvYZ6zB2wFgjFiNpOGesR0rZ0PVPXf8KhUCl22CwClz4eN8weoZBb9c0bdPsOWvHx/cYu9Y0CoNoZTJrwAbn5DrnZc6XOV+igVbnsgo0IxEomlJuA1vUIYGyq3PZBChwmExCUSmVZgMBDIUCK4UCFIv5vHIhm/XUDeAf/ADbcpd5+aXSWQAAAABJRU5ErkJggg==', 'options': [ { 'name': 'enabled', diff --git a/couchpotato/static/scripts/page/settings.js b/couchpotato/static/scripts/page/settings.js index 054f531..b9f72ab 100644 --- a/couchpotato/static/scripts/page/settings.js +++ b/couchpotato/static/scripts/page/settings.js @@ -120,7 +120,13 @@ Page.Settings = new Class({ var self = this; self.tabs_container = new Element('ul.tabs'); - self.containers = new Element('form.uniForm.containers').adopt( + self.containers = new Element('form.uniForm.containers', { + 'events': { + 'click:relay(.enabler.disabled h2)': function(e, el){ + el.getPrevious().getElements('.check').fireEvent('click'); + } + } + }).adopt( new Element('label.advanced_toggle').adopt( new Element('span', { 'text': 'Show advanced settings' @@ -285,14 +291,23 @@ Page.Settings = new Class({ }) } + var icon; + if(group.icon){ + icon = new Element('span.icon').grab(new Element('img', { + 'src': 'data:image/png;base64,' + group.icon + })); + } + + var label = new Element('span.group_label', { + 'text': group.label || (group.name).capitalize() + }) return new Element('fieldset', { 'class': (group.advanced ? 'inlineLabels advanced' : 'inlineLabels') + ' group_' + (group.name || '') + ' subtab_' + (group.subtab || '') }).grab( - new Element('h2', { - 'text': group.label || (group.name).capitalize() - }).grab(hint) - ); + new Element('h2').adopt(icon, label, hint) + ); + }, createList: function(content_container){ diff --git a/couchpotato/static/style/settings.css b/couchpotato/static/style/settings.css index 1f77b8e..50b305e 100644 --- a/couchpotato/static/style/settings.css +++ b/couchpotato/static/style/settings.css @@ -92,6 +92,22 @@ border-bottom: 1px solid #333; box-shadow: 0 1px 0 rgba(255,255,255, 0.15); } + + .page fieldset h2 .icon { + vertical-align: bottom; + position: absolute; + left: -25px; + top: 3px; + background: #FFF; + border-radius: 2.5px; + line-height: 0; + overflow: hidden; + } + + .page fieldset.enabler:hover h2 .icon { + display: none; + } + .page fieldset h2 .hint { font-size: 12px; margin-left: 10px; @@ -200,17 +216,23 @@ .page .option_list .enabler.disabled { display: inline-block; - margin: 3px 3px 3px 20px; - padding: 4px 0; - width: 173px; + padding: 4px 0 5px; + width: 24%; vertical-align: top; } + .page .option_list .enabler:not(.disabled) .icon { + display: none; + } .page .option_list .enabler.disabled h2 { + cursor: pointer; border: none; box-shadow: none; - padding: 0 10px 0 25px; + padding: 0 10px 0 0; font-size: 16px; + position: relative; + left: 25px; + margin-right: 25px; } .page .option_list .enabler:not(.disabled) h2 { From 7db291fc93807e1ddb180a63e016c5c3b0b25049 Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 21:07:17 +0200 Subject: [PATCH 030/117] Show all in wizard --- couchpotato/core/media/_base/providers/torrent/hdbits.py | 1 + couchpotato/core/media/_base/providers/torrent/torrentshack.py | 1 + couchpotato/core/media/_base/providers/torrent/torrentz.py | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/media/_base/providers/torrent/hdbits.py b/couchpotato/core/media/_base/providers/torrent/hdbits.py index a09fe7d..ebf2899 100644 --- a/couchpotato/core/media/_base/providers/torrent/hdbits.py +++ b/couchpotato/core/media/_base/providers/torrent/hdbits.py @@ -71,6 +71,7 @@ config = [{ 'tab': 'searcher', 'list': 'torrent_providers', 'name': 'HDBits', + 'wizard': True, 'description': 'HDBits', 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABi0lEQVR4AZWSzUsbQRjGdyabTcvSNPTSHlpQQeMHJApC8CJRvHgQQU969+LJP8G7f4N3DwpeFRQvRr0EKaUl0ATSpkigUNFsMl/r9NmZLCEHA/nNO5PfvMPDm0DI6fV3ZxiolEICe1oZCBVCCmBPKwOh2ErKBHGE4KYEXBpSLkUlqO4LcM7f+6nVhRnOhSkOz/hexk+tL+YL0yPF2YmN4tynD++4gTLGkNNac9YFLoREBR1+cnF3dFY6v/m6PD+FaXiNJtgA4xYbABxiGrz6+6HWaI5/+Qh37YS0/3Znc8UxwNGBIIBX22z+/ZdJ+4wzyjpR4PEpODg8tgUXBv2iWUzSpa12B0IR6n6lvt8Aek2lZHb084+fdRNgrwY8z81PjhVy2d2ttUrtV/lbBa+JXGEpDMPnoF2tN1QYRqVUtf6nFbThb7wk7le395elcqhASLb39okDiHY00VCtCTEHwSiH4AI0lkOiT1dwMeSfT3SRxiQWNO7Zwj1egkoVIQFMKvSiC3bcjXq9Jf8DcDIRT3hh10kAAAAASUVORK5CYII=', 'options': [ diff --git a/couchpotato/core/media/_base/providers/torrent/torrentshack.py b/couchpotato/core/media/_base/providers/torrent/torrentshack.py index bab508a..0cfa04d 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentshack.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentshack.py @@ -81,6 +81,7 @@ config = [{ 'list': 'torrent_providers', 'name': 'TorrentShack', 'description': 'TorrentShack', + 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABmElEQVQoFQXBzY2cVRiE0afqvd84CQiAnxWWtyxsS6ThINBYg2Dc7mZBMEjE4mzs6e9WcY5+ePNuVFJJodQAoLo+SaWCy9rcV8cmjah3CI6iYu7oRU30kE5xxELRfamklY3k1NL19sSm7vPzP/ZdNZzKVDaY2sPZJBh9fv5ITrmG2+Vp4e1sPchVqTCQZJnVXi+/L4uuAJGly1+Pw8CprLbi8Om7tbT19/XRqJUk11JP9uHj9ulxhXbvJbI9qJvr5YkGXFG2IBT8tXczt+sfzDZCp3765f3t9tHEHGEDACma77+8o4oATKk+/PfW9YmHruRFjWoVSFsVsGu1YSKq6Oc37+n98unPZSRlY7vsKDqN+92X3yR9+PdXee3iJNKMStqdcZqoTJbUSi5JOkpfRlhSI0mSpEmCFKoU7FqSNOLAk54uGwCStMUCgLrVic62g7oDoFmmdI+P3S0pDe1xvDqb6XrZqbtzShWNoh9fv/XQHaDdM9OqrZi2M7M3UrB2vlkPS1IbdEBk7UiSoD6VlZ6aKWer4aH4f/AvKoHUTjuyAAAAAElFTkSuQmCC', 'options': [ { diff --git a/couchpotato/core/media/_base/providers/torrent/torrentz.py b/couchpotato/core/media/_base/providers/torrent/torrentz.py index 51e505d..8a5455c 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentz.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentz.py @@ -85,7 +85,7 @@ config = [{ { 'name': 'enabled', 'type': 'enabler', - 'default': False + 'default': True }, { 'name': 'verified_only', From 33884deb6c5de6273b79945ed1913b7a095b093c Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 20 Jun 2014 21:29:43 +0200 Subject: [PATCH 031/117] Send single Pushbullet when no device is selected. fix #3471 --- couchpotato/core/notifications/pushbullet.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/couchpotato/core/notifications/pushbullet.py b/couchpotato/core/notifications/pushbullet.py index 77738c3..361294e 100644 --- a/couchpotato/core/notifications/pushbullet.py +++ b/couchpotato/core/notifications/pushbullet.py @@ -25,11 +25,7 @@ class Pushbullet(Notification): # Get all the device IDs linked to this user if not len(devices): - response = self.request('devices') - if not response: - return False - - devices += [device.get('id') for device in response['devices']] + devices = [None] successful = 0 for device in devices: From 96275adaff4c9e53578921aa5b7b7594c847edc3 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 21 Jun 2014 18:44:09 +0200 Subject: [PATCH 032/117] Use always search and ignore ETA. fix #3475 --- couchpotato/core/media/movie/searcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/media/movie/searcher.py b/couchpotato/core/media/movie/searcher.py index 0f4b417..1053ec3 100644 --- a/couchpotato/core/media/movie/searcher.py +++ b/couchpotato/core/media/movie/searcher.py @@ -220,7 +220,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): log.debug('Found %s releases for "%s", but ETA isn\'t correct yet.', (results_count, default_title)) # Try find a valid result and download it - if (force_download or not could_not_be_released) and fireEvent('release.try_download_result', results, movie, quality_custom, single = True): + if (force_download or not could_not_be_released or alway_search) and fireEvent('release.try_download_result', results, movie, quality_custom, single = True): ret = True # Remove releases that aren't found anymore From 443866ef048183ff0b166c29aa14a90ceeb9acba Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 21 Jun 2014 18:50:36 +0200 Subject: [PATCH 033/117] Use default title for search query. fix #3477 --- couchpotato/core/media/movie/library.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/couchpotato/core/media/movie/library.py b/couchpotato/core/media/movie/library.py index a6e29f3..28cb1b4 100644 --- a/couchpotato/core/media/movie/library.py +++ b/couchpotato/core/media/movie/library.py @@ -1,4 +1,5 @@ from couchpotato.core.event import addEvent +from couchpotato.core.helpers.variable import getTitle from couchpotato.core.logger import CPLog from couchpotato.core.media._base.library.base import LibraryBase @@ -17,7 +18,9 @@ class MovieLibraryPlugin(LibraryBase): if media.get('type') != 'movie': return + default_title = getTitle(media) titles = media['info'].get('titles', []) + titles.insert(0, default_title) # Add year identifier to titles if include_year: From 5a08fed0b621e6d692fac0dfbca3b4892ff8dad3 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 15:53:43 +0200 Subject: [PATCH 034/117] Manage release_id not assigned. fix #3479 --- couchpotato/core/plugins/manage.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/manage.py b/couchpotato/core/plugins/manage.py index f0e0faf..bec204b 100644 --- a/couchpotato/core/plugins/manage.py +++ b/couchpotato/core/plugins/manage.py @@ -166,10 +166,9 @@ class Manage(Plugin): already_used = used_files.get(release_file) if already_used: + release_id = release['_id'] if already_used.get('last_edit', 0) < release.get('last_edit', 0) else already_used['_id'] if release_id not in deleted_releases: - release_id = release['_id'] if already_used.get('last_edit', 0) < release.get('last_edit', 0) else already_used['_id'] fireEvent('release.delete', release_id, single = True) - deleted_releases.append(release_id) break else: From 37214dd41351f34c71d740f491a6662d31918e80 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 16:15:36 +0200 Subject: [PATCH 035/117] Put Pushover in config. close #3480 --- couchpotato/core/notifications/pushover.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/notifications/pushover.py b/couchpotato/core/notifications/pushover.py index ea4b00a..7507396 100644 --- a/couchpotato/core/notifications/pushover.py +++ b/couchpotato/core/notifications/pushover.py @@ -13,7 +13,6 @@ autoload = 'Pushover' class Pushover(Notification): - app_token = 'YkxHMYDZp285L265L3IwH3LmzkTaCy' def notify(self, message = '', data = None, listener = None): if not data: data = {} @@ -22,7 +21,7 @@ class Pushover(Notification): api_data = { 'user': self.conf('user_key'), - 'token': self.app_token, + 'token': self.conf('api_token'), 'message': toUnicode(message), 'priority': self.conf('priority'), 'sound': self.conf('sound'), @@ -49,7 +48,7 @@ class Pushover(Notification): log.error('Pushover auth failed: %s', response.reason) return False else: - log.error('Pushover notification failed.') + log.error('Pushover notification failed: %s', request_status) return False @@ -71,6 +70,12 @@ config = [{ 'description': 'Register on pushover.net to get one.' }, { + 'name': 'api_token', + 'description': 'Register on pushover.net to get one.', + 'hidden': True, + 'default': 'YkxHMYDZp285L265L3IwH3LmzkTaCy', + }, + { 'name': 'priority', 'default': 0, 'type': 'dropdown', From 964144996f1e18c674b75af35496ff0da4a6c4e1 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 16:17:11 +0200 Subject: [PATCH 036/117] Advanced not hidden. --- couchpotato/core/notifications/pushover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/notifications/pushover.py b/couchpotato/core/notifications/pushover.py index 7507396..d9ef226 100644 --- a/couchpotato/core/notifications/pushover.py +++ b/couchpotato/core/notifications/pushover.py @@ -72,7 +72,7 @@ config = [{ { 'name': 'api_token', 'description': 'Register on pushover.net to get one.', - 'hidden': True, + 'advanced': True, 'default': 'YkxHMYDZp285L265L3IwH3LmzkTaCy', }, { From 5617953d39018f25b0c8d6e48481333aef2aa622 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 20:23:47 +0200 Subject: [PATCH 037/117] Mark as done missing. #3472 --- couchpotato/core/media/movie/_base/static/movie.actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/media/movie/_base/static/movie.actions.js b/couchpotato/core/media/movie/_base/static/movie.actions.js index b3878fd..ff71f31 100644 --- a/couchpotato/core/media/movie/_base/static/movie.actions.js +++ b/couchpotato/core/media/movie/_base/static/movie.actions.js @@ -302,7 +302,7 @@ MA.Release = new Class({ self.movie.data.releases.each(function(release){ if(has_available && has_snatched) return; - if(['snatched', 'downloaded', 'seeding'].contains(release.status)) + if(['snatched', 'downloaded', 'seeding', 'done'].contains(release.status)) has_snatched = true; if(['available'].contains(release.status)) From fdcdf07fa6ee5664a550ab1023127d2ef9baa67e Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 20:35:19 +0200 Subject: [PATCH 038/117] Untag on delete from dashboard --- couchpotato/core/media/_base/media/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index b4c8ced..1340aa6 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -411,6 +411,8 @@ class MediaPlugin(MediaBase): elif new_media_status: media['status'] = new_media_status db.update(media) + + fireEvent('media.untag', media['_id'], 'recent', single = True) else: fireEvent('media.restatus', media.get('_id'), single = True) From 0b6843a1b95df88ac34a4c0d076166217ae6bb9b Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 20:58:56 +0200 Subject: [PATCH 039/117] Force readd not adding with proper profile --- couchpotato/core/media/movie/_base/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/movie/_base/main.py b/couchpotato/core/media/movie/_base/main.py index 9475ec0..6e32386 100644 --- a/couchpotato/core/media/movie/_base/main.py +++ b/couchpotato/core/media/movie/_base/main.py @@ -90,7 +90,7 @@ class MovieBase(MovieTypeBase): # Default profile and category default_profile = {} - if not params.get('profile_id') and status != 'done': + if (not params.get('profile_id') and status != 'done') or params.get('ignore_previous', False): default_profile = fireEvent('profile.default', single = True) cat_id = params.get('category_id') @@ -146,7 +146,7 @@ class MovieBase(MovieTypeBase): else: fireEvent('release.delete', release['_id'], single = True) - m['profile_id'] = params.get('profile_id', default_profile.get('id')) + m['profile_id'] = params.get('profile_id') or default_profile.get('_id') m['category_id'] = cat_id if cat_id is not None and len(cat_id) > 0 else (m.get('category_id') or None) m['last_edit'] = int(time.time()) m['tags'] = [] From 474cd45fc544988237d6b4768b12673a2efe51d6 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 21:14:31 +0200 Subject: [PATCH 040/117] Reset profile to default when old one is empty or doesn't exist anymore --- couchpotato/core/media/movie/_base/main.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/media/movie/_base/main.py b/couchpotato/core/media/movie/_base/main.py index 6e32386..07c4751 100644 --- a/couchpotato/core/media/movie/_base/main.py +++ b/couchpotato/core/media/movie/_base/main.py @@ -2,6 +2,7 @@ import os import traceback import time +from CodernityDB.database import RecordNotFound from couchpotato import get_db from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, fireEventAsync, addEvent @@ -117,8 +118,17 @@ class MovieBase(MovieTypeBase): media['info'] = info new = False + previous_profile = None try: m = db.get('media', 'imdb-%s' % params.get('identifier'), with_doc = True)['doc'] + + try: + db.get('id', m.get('profile_id')) + previous_profile = m.get('profile_id') + except RecordNotFound: + pass + except: + log.error('Failed getting previous profile: %s', traceback.format_exc()) except: new = True m = db.insert(media) @@ -146,7 +156,7 @@ class MovieBase(MovieTypeBase): else: fireEvent('release.delete', release['_id'], single = True) - m['profile_id'] = params.get('profile_id') or default_profile.get('_id') + m['profile_id'] = (params.get('profile_id') or default_profile.get('_id')) if not previous_profile else previous_profile m['category_id'] = cat_id if cat_id is not None and len(cat_id) > 0 else (m.get('category_id') or None) m['last_edit'] = int(time.time()) m['tags'] = [] From b11bb9cdac1f0fd63fc93c7efd0507d1dcbd0ae7 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 21:32:52 +0200 Subject: [PATCH 041/117] Catch missing profile in restatus --- couchpotato/core/media/_base/media/main.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 1340aa6..1e882d1 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -454,17 +454,20 @@ class MediaPlugin(MediaBase): else: move_to_wanted = True - profile = db.get('id', m['profile_id']) - media_releases = fireEvent('release.for_media', m['_id'], single = True) + try: + profile = db.get('id', m['profile_id']) + media_releases = fireEvent('release.for_media', m['_id'], single = True) - for q_identifier in profile['qualities']: - index = profile['qualities'].index(q_identifier) + for q_identifier in profile['qualities']: + index = profile['qualities'].index(q_identifier) - for release in media_releases: - if q_identifier == release['quality'] and (release.get('status') == 'done' and profile['finish'][index]): - move_to_wanted = False + for release in media_releases: + if q_identifier == release['quality'] and (release.get('status') == 'done' and profile['finish'][index]): + move_to_wanted = False - m['status'] = 'active' if move_to_wanted else 'done' + m['status'] = 'active' if move_to_wanted else 'done' + except RecordNotFound: + log.debug('Failed restatus: %s', traceback.format_exc()) # Only update when status has changed if previous_status != m['status']: From 15980471b0b17407928bd303189d05a13eaf4966 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 22:41:56 +0200 Subject: [PATCH 042/117] Create api lock on the fly --- couchpotato/api.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/couchpotato/api.py b/couchpotato/api.py index 1794258..99a2c6a 100644 --- a/couchpotato/api.py +++ b/couchpotato/api.py @@ -91,6 +91,10 @@ class ApiHandler(RequestHandler): self.write('API call doesn\'t seem to exist') return + # Create lock if it doesn't exist + if route in api_locks and not api_locks.get(route): + api_locks[route] = threading.Lock() + api_locks[route].acquire() try: From fb9080c18a17b3554de29c8cc9eee34b8c34b7bc Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 23:38:51 +0200 Subject: [PATCH 043/117] Except value error --- couchpotato/runner.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/couchpotato/runner.py b/couchpotato/runner.py index b2b918a..8e872b1 100644 --- a/couchpotato/runner.py +++ b/couchpotato/runner.py @@ -314,6 +314,8 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En continue else: return + except ValueError: + return except: pass From a26abd0dbb0e81181cf4b088363f1a4968c9b8fc Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 23:39:43 +0200 Subject: [PATCH 044/117] Don't use nonblock requests results if empty --- couchpotato/core/notifications/core/static/notification.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/notifications/core/static/notification.js b/couchpotato/core/notifications/core/static/notification.js index 81bf950..93bfa15 100644 --- a/couchpotato/core/notifications/core/static/notification.js +++ b/couchpotato/core/notifications/core/static/notification.js @@ -122,9 +122,12 @@ var NotificationBase = new Class({ startPoll: function(){ var self = this; - if(self.stopped || (self.request && self.request.isRunning())) + if(self.stopped) return; + if(self.request && self.request.isRunning()) + self.request.cancel(); + self.request = Api.request('nonblock/notification.listener', { 'onSuccess': function(json){ self.processData(json, false) @@ -149,7 +152,7 @@ var NotificationBase = new Class({ var self = this; // Process data - if(json){ + if(json && json.result){ Array.each(json.result, function(result){ App.trigger(result._t || result.type, [result]); if(result.message && result.read === undefined && !init) From 1c5f19a68a5d2aed400319b80b55579fa7da30b7 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 22 Jun 2014 23:41:31 +0200 Subject: [PATCH 045/117] Better reload hook name --- couchpotato/runner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/runner.py b/couchpotato/runner.py index 8e872b1..ed291a9 100644 --- a/couchpotato/runner.py +++ b/couchpotato/runner.py @@ -277,9 +277,9 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En loop = IOLoop.current() # Reload hook - def test(): + def reload_hook(): fireEvent('app.shutdown') - add_reload_hook(test) + add_reload_hook(reload_hook) # Some logging and fire load event try: log.info('Starting server on port %(port)s', config) From 94064ac7dab2fc7d96008677a6263e4c51a3a1b4 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 01:09:32 +0200 Subject: [PATCH 046/117] Rework restart methods --- CouchPotato.py | 6 +++--- couchpotato/core/_base/_core.py | 8 +++++--- couchpotato/core/_base/scheduler.py | 4 ++-- couchpotato/core/_base/updater/main.py | 4 ++-- couchpotato/core/plugins/base.py | 2 +- couchpotato/runner.py | 11 +++++++---- couchpotato/static/scripts/couchpotato.js | 15 +++++++++++---- 7 files changed, 31 insertions(+), 19 deletions(-) diff --git a/CouchPotato.py b/CouchPotato.py index f5b9c04..7049cda 100755 --- a/CouchPotato.py +++ b/CouchPotato.py @@ -72,10 +72,11 @@ class Loader(object): signal.signal(signal.SIGTERM, lambda signum, stack_frame: sys.exit(1)) from couchpotato.core.event import addEvent - addEvent('app.after_shutdown', self.afterShutdown) + addEvent('app.do_shutdown', self.setRestart) - def afterShutdown(self, restart): + def setRestart(self, restart): self.do_restart = restart + return True def onExit(self, signal, frame): from couchpotato.core.event import fireEvent @@ -103,7 +104,6 @@ class Loader(object): # Release log files and shutdown logger logging.shutdown() - time.sleep(3) args = [sys.executable] + [os.path.join(base_path, os.path.basename(__file__))] + sys.argv[1:] subprocess.Popen(args) diff --git a/couchpotato/core/_base/_core.py b/couchpotato/core/_base/_core.py index 1171478..852c42c 100644 --- a/couchpotato/core/_base/_core.py +++ b/couchpotato/core/_base/_core.py @@ -118,7 +118,7 @@ class Core(Plugin): self.shutdown_started = True - fireEvent('app.do_shutdown') + fireEvent('app.do_shutdown', restart = restart) log.debug('Every plugin got shutdown event') loop = True @@ -143,9 +143,11 @@ class Core(Plugin): log.debug('Safe to shutdown/restart') + loop = IOLoop.current() + try: - if not IOLoop.current()._closing: - IOLoop.current().stop() + if not loop._closing: + loop.stop() except RuntimeError: pass except: diff --git a/couchpotato/core/_base/scheduler.py b/couchpotato/core/_base/scheduler.py index 16a3a4f..271a2d8 100644 --- a/couchpotato/core/_base/scheduler.py +++ b/couchpotato/core/_base/scheduler.py @@ -33,9 +33,9 @@ class Scheduler(Plugin): except: pass - def doShutdown(self): + def doShutdown(self, *args, **kwargs): self.stop() - return super(Scheduler, self).doShutdown() + return super(Scheduler, self).doShutdown(*args, **kwargs) def stop(self): if self.started: diff --git a/couchpotato/core/_base/updater/main.py b/couchpotato/core/_base/updater/main.py index 093977d..9f6613a 100644 --- a/couchpotato/core/_base/updater/main.py +++ b/couchpotato/core/_base/updater/main.py @@ -142,11 +142,11 @@ class Updater(Plugin): 'success': success } - def doShutdown(self): + def doShutdown(self, *args, **kwargs): if not Env.get('dev'): removePyc(Env.get('app_dir'), show_logs = False) - return super(Updater, self).doShutdown() + return super(Updater, self).doShutdown(*args, **kwargs) class BaseUpdater(Plugin): diff --git a/couchpotato/core/plugins/base.py b/couchpotato/core/plugins/base.py index ac5ca87..bc66123 100644 --- a/couchpotato/core/plugins/base.py +++ b/couchpotato/core/plugins/base.py @@ -263,7 +263,7 @@ class Plugin(object): def afterCall(self, handler): self.isRunning('%s.%s' % (self.getName(), handler.__name__), False) - def doShutdown(self): + def doShutdown(self, *args, **kwargs): self.shuttingDown(True) return True diff --git a/couchpotato/runner.py b/couchpotato/runner.py index ed291a9..6560f55 100644 --- a/couchpotato/runner.py +++ b/couchpotato/runner.py @@ -286,13 +286,14 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En except: pass fireEventAsync('app.load') + ssl_options = None if config['ssl_cert'] and config['ssl_key']: - server = HTTPServer(application, no_keep_alive = True, ssl_options = { + ssl_options = { 'certfile': config['ssl_cert'], 'keyfile': config['ssl_key'], - }) - else: - server = HTTPServer(application, no_keep_alive = True) + } + + server = HTTPServer(application, no_keep_alive = True) try_restart = True restart_tries = 5 @@ -301,6 +302,8 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En try: server.listen(config['port'], config['host']) loop.start() + server.close_all_connections() + server.stop() except Exception as e: log.error('Failed starting: %s', traceback.format_exc()) try: diff --git a/couchpotato/static/scripts/couchpotato.js b/couchpotato/static/scripts/couchpotato.js index b71c1f0..19b9f45 100644 --- a/couchpotato/static/scripts/couchpotato.js +++ b/couchpotato/static/scripts/couchpotato.js @@ -272,11 +272,18 @@ (function(){ - Api.request('app.available', { - 'onFailure': function(){ - self.checkAvailable.delay(1000, self, [delay, onAvailable]); - self.fireEvent('unload'); + var onFailure = function(){ + self.checkAvailable.delay(1000, self, [delay, onAvailable]); + self.fireEvent('unload'); + } + + var request = Api.request('app.available', { + 'timeout': 2000, + 'onTimeout': function(){ + request.cancel(); + onFailure(); }, + 'onFailure': onFailure, 'onSuccess': function(){ if(onAvailable) onAvailable(); From 50d6882a9826ae99e38d8dd373fe2a8e4c02241f Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 01:17:06 +0200 Subject: [PATCH 047/117] Close all attached after start --- couchpotato/runner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/runner.py b/couchpotato/runner.py index 6560f55..3a779ba 100644 --- a/couchpotato/runner.py +++ b/couchpotato/runner.py @@ -304,6 +304,7 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En loop.start() server.close_all_connections() server.stop() + loop.close(all_fds = True) except Exception as e: log.error('Failed starting: %s', traceback.format_exc()) try: From fab9b96c8e64790b2ff7a5bc5397ff7fc9f0639a Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 13:16:05 +0200 Subject: [PATCH 048/117] Keep done releases when removing from wanted/dashboard. fix #3488 --- couchpotato/core/media/_base/media/main.py | 2 +- couchpotato/core/plugins/release/main.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 1e882d1..4cfe597 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -405,7 +405,7 @@ class MediaPlugin(MediaBase): db.delete(release) total_deleted += 1 - if (total_releases == total_deleted and media['status'] != 'active') or (delete_from == 'wanted' and media['status'] == 'active') or (not new_media_status and delete_from == 'late'): + if (total_releases == total_deleted and media['status'] != 'active') or (not new_media_status and delete_from == 'late'): db.delete(media) deleted = True elif new_media_status: diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 9e7e4ca..cb16c5a 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -477,7 +477,7 @@ class Release(Plugin): rel = db.get('id', release_id) if rel and rel.get('status') != status: - release_name = rel['info'].get('name') + release_name = None if rel.get('files'): for file_type in rel.get('files', {}): if file_type == 'movie': @@ -485,6 +485,9 @@ class Release(Plugin): release_name = os.path.basename(release_file) break + if not release_name and rel.get('info'): + release_name = rel['info'].get('name') + #update status in Db log.debug('Marking release %s as %s', (release_name, status)) rel['status'] = status From a37517bf6a09ab9e1ccdb5d4a459c70f09bc1554 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 13:37:13 +0200 Subject: [PATCH 049/117] Use ssl startup options. fix #3490 Thanks @sjmcinness --- couchpotato/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/runner.py b/couchpotato/runner.py index 3a779ba..8a44605 100644 --- a/couchpotato/runner.py +++ b/couchpotato/runner.py @@ -293,7 +293,7 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En 'keyfile': config['ssl_key'], } - server = HTTPServer(application, no_keep_alive = True) + server = HTTPServer(application, no_keep_alive = True, ssl_options = ssl_options) try_restart = True restart_tries = 5 From 28ffad10ab5f562c8d3fd7e24fdf2d44680b25d0 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 13:43:33 +0200 Subject: [PATCH 050/117] Standardize path for list directory api call. #3487 --- couchpotato/core/plugins/browser.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/couchpotato/core/plugins/browser.py b/couchpotato/core/plugins/browser.py index 6880f3b..013a482 100644 --- a/couchpotato/core/plugins/browser.py +++ b/couchpotato/core/plugins/browser.py @@ -3,6 +3,7 @@ import os import string from couchpotato.api import addApiView +from couchpotato.core.helpers.encoding import sp from couchpotato.core.helpers.variable import getUserDir from couchpotato.core.plugins.base import Plugin import six @@ -50,6 +51,7 @@ class FileBrowser(Plugin): path = '/' dirs = [] + path = sp(path) for f in os.listdir(path): p = os.path.join(path, f) if os.path.isdir(p) and ((self.is_hidden(p) and bool(int(show_hidden))) or not self.is_hidden(p)): From 5350dbf0ce2e737a2f18949efb2c2d1cb2d08224 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 14:13:32 +0200 Subject: [PATCH 051/117] Filter out extended and try other result on determine media. fix #3489 --- couchpotato/core/plugins/scanner.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/scanner.py b/couchpotato/core/plugins/scanner.py index d5937ea..de80d27 100644 --- a/couchpotato/core/plugins/scanner.py +++ b/couchpotato/core/plugins/scanner.py @@ -105,7 +105,7 @@ class Scanner(Plugin): 'HDTV': ['hdtv'] } - clean = '([ _\,\.\(\)\[\]\-]|^)(3d|hsbs|sbs|half.sbs|full.sbs|ou|half.ou|full.ou|extended.cut|directors.cut|french|fr|swedisch|sw|danish|dutch|nl|swesub|subs|spanish|german|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdr|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip' \ + clean = '([ _\,\.\(\)\[\]\-]|^)(3d|hsbs|sbs|half.sbs|full.sbs|ou|half.ou|full.ou|extended|extended.cut|directors.cut|french|fr|swedisch|sw|danish|dutch|nl|swesub|subs|spanish|german|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdr|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip' \ '|hdtvrip|webdl|web.dl|webrip|web.rip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|r3|r5|bd5|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|video_ts|audio_ts|480p|480i|576p|576i|720p|720i|1080p|1080i|hrhd|hrhdtv|hddvd|bluray|x264|h264|xvid|xvidvd|xxx|www.www|hc|\[.*\])(?=[ _\,\.\(\)\[\]\-]|$)' multipart_regex = [ '[ _\.-]+cd[ _\.-]*([0-9a-d]+)', #*cd1 @@ -636,6 +636,10 @@ class Scanner(Plugin): if name_year.get('name') and name_year.get('year'): movie = fireEvent('movie.search', q = '%(name)s %(year)s' % name_year, merge = True, limit = 1) + # Try with other + if len(movie) == 0 and name_year.get('other') and name_year['other'].get('name') and name_year['other'].get('year'): + movie = fireEvent('movie.search', q = '%(name)s %(year)s' % name_year.get('other'), merge = True, limit = 1) + if len(movie) > 0: imdb_id = movie[0].get('imdb') log.debug('Found movie via search: %s', identifier) @@ -938,8 +942,11 @@ class Scanner(Plugin): pass if cp_guess.get('year') == guess.get('year') and len(cp_guess.get('name', '')) > len(guess.get('name', '')): + cp_guess['other'] = guess return cp_guess elif guess == {}: + cp_guess['other'] = guess return cp_guess + guess['other'] = cp_guess return guess From eaaa8dc834bc528b3810320e078a3404a972e61f Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 14:15:00 +0200 Subject: [PATCH 052/117] Only try other if it's different --- couchpotato/core/plugins/scanner.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/scanner.py b/couchpotato/core/plugins/scanner.py index de80d27..01a88fb 100644 --- a/couchpotato/core/plugins/scanner.py +++ b/couchpotato/core/plugins/scanner.py @@ -634,11 +634,14 @@ class Scanner(Plugin): name_year = self.getReleaseNameYear(identifier, file_name = filename if not group['is_dvd'] else None) if name_year.get('name') and name_year.get('year'): - movie = fireEvent('movie.search', q = '%(name)s %(year)s' % name_year, merge = True, limit = 1) + search_q = '%(name)s %(year)s' % name_year + movie = fireEvent('movie.search', q = search_q, merge = True, limit = 1) # Try with other if len(movie) == 0 and name_year.get('other') and name_year['other'].get('name') and name_year['other'].get('year'): - movie = fireEvent('movie.search', q = '%(name)s %(year)s' % name_year.get('other'), merge = True, limit = 1) + search_q2 = '%(name)s %(year)s' % name_year + if search_q2 != search_q: + movie = fireEvent('movie.search', q = '%(name)s %(year)s' % name_year.get('other'), merge = True, limit = 1) if len(movie) > 0: imdb_id = movie[0].get('imdb') From 8d85dde2c67f0fdcd14dcd7e027fede600dbd2a6 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 16:19:40 +0200 Subject: [PATCH 053/117] Don't use empty name_year return for moviemeter. fix #3493 --- .../core/media/movie/providers/automation/moviemeter.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/couchpotato/core/media/movie/providers/automation/moviemeter.py b/couchpotato/core/media/movie/providers/automation/moviemeter.py index 883fcfa..b06046f 100644 --- a/couchpotato/core/media/movie/providers/automation/moviemeter.py +++ b/couchpotato/core/media/movie/providers/automation/moviemeter.py @@ -21,11 +21,15 @@ class Moviemeter(Automation, RSS): for movie in rss_movies: - name_year = fireEvent('scanner.name_year', self.getTextElement(movie, 'title'), single = True) - imdb = self.search(name_year.get('name'), name_year.get('year')) - - if imdb and self.isMinimalMovie(imdb): - movies.append(imdb['imdb']) + title = self.getTextElement(movie, 'title') + name_year = fireEvent('scanner.name_year', title, single = True) + if name_year.get('name') and name_year.get('year'): + imdb = self.search(name_year.get('name'), name_year.get('year')) + + if imdb and self.isMinimalMovie(imdb): + movies.append(imdb['imdb']) + else: + log.error('Failed getting name and year from: %s', title) return movies From b933cd8718f014474641c34aea0fd915a32f33a9 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 20:40:04 +0200 Subject: [PATCH 054/117] Delete when total releases was 0 --- couchpotato/core/media/_base/media/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 4cfe597..dc9e97a 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -405,7 +405,7 @@ class MediaPlugin(MediaBase): db.delete(release) total_deleted += 1 - if (total_releases == total_deleted and media['status'] != 'active') or (not new_media_status and delete_from == 'late'): + if (total_releases == total_deleted and media['status'] != 'active') or (total_releases == 0 and not new_media_status) or (not new_media_status and delete_from == 'late'): db.delete(media) deleted = True elif new_media_status: From 9f07dd5a21a912038eb207618c2a80a40ce92191 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 20:46:26 +0200 Subject: [PATCH 055/117] Reindex after full scan. fix #3492 --- couchpotato/core/plugins/manage.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/couchpotato/core/plugins/manage.py b/couchpotato/core/plugins/manage.py index bec204b..637facf 100644 --- a/couchpotato/core/plugins/manage.py +++ b/couchpotato/core/plugins/manage.py @@ -4,6 +4,7 @@ import sys import time import traceback +from couchpotato import get_db from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, addEvent, fireEventAsync from couchpotato.core.helpers.encoding import sp @@ -179,6 +180,10 @@ class Manage(Plugin): if self.shuttingDown(): break + if not self.shuttingDown(): + db = get_db() + db.reindex() + Env.prop(last_update_key, time.time()) except: log.error('Failed updating library: %s', (traceback.format_exc())) From dbeaab052d40b3feba93c97e4210c5ba8426bc35 Mon Sep 17 00:00:00 2001 From: mano3m Date: Tue, 13 May 2014 22:44:12 +0200 Subject: [PATCH 056/117] Wait before marking media as done --- couchpotato/core/media/movie/searcher.py | 32 ++++++++++++++++------ couchpotato/core/plugins/profile/main.py | 4 +++ couchpotato/core/plugins/profile/static/profile.js | 11 +++++++- couchpotato/core/plugins/quality/main.py | 10 +++++-- couchpotato/core/plugins/release/main.py | 7 +---- 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/couchpotato/core/media/movie/searcher.py b/couchpotato/core/media/movie/searcher.py index 1053ec3..9048d17 100644 --- a/couchpotato/core/media/movie/searcher.py +++ b/couchpotato/core/media/movie/searcher.py @@ -1,4 +1,5 @@ -from datetime import date +from datetime import date, timedelta +from operator import itemgetter import random import re import time @@ -139,6 +140,27 @@ class MovieSearcher(SearcherBase, MovieTypeBase): fireEvent('media.delete', movie['_id'], single = True) return + db = get_db() + profile = db.get('id', movie['profile_id']) + + # Find out if we need to stop searching because 'stop_after' is met. Compare with the newest release found. + done_releases = [release for release in previous_releases if release.get('status') == 'done'] + + if done_releases: + done_release = sorted(done_releases, key = itemgetter('last_edit'), reverse = True)[0] + if fireEvent('quality.isfinish', {'identifier': done_release['quality'], 'is_3d': done_release.get('is_3d', False)}, profile, timedelta(seconds = time.time() - done_release['last_edit']).days, single = True): + + log.debug('No better quality than %s%s found for %s days, marking movie %s as done.', \ + (done_release['quality'], ' 3D' if done_release.get('is_3d', False) else '', profile['stop_after'][0], default_title)) + + # Mark media done + mdia = db.get('id', movie['_id']) + mdia['status'] = 'done' + mdia['last_edit'] = int(time.time()) + db.update(mdia) + + return + fireEvent('notify.frontend', type = 'movie.searcher.started', data = {'_id': movie['_id']}, message = 'Searching for "%s"' % default_title) # Ignore eta once every 7 days @@ -149,13 +171,9 @@ class MovieSearcher(SearcherBase, MovieTypeBase): ignore_eta = True Env.prop(prop_name, value = time.time()) - db = get_db() - - profile = db.get('id', movie['profile_id']) ret = False - index = 0 - for q_identifier in profile.get('qualities'): + for index, q_identifier in enumerate(profile.get('qualities', [])): quality_custom = { 'index': index, 'quality': q_identifier, @@ -164,8 +182,6 @@ class MovieSearcher(SearcherBase, MovieTypeBase): '3d': profile['3d'][index] if profile.get('3d') else False } - index += 1 - could_not_be_released = not self.couldBeReleased(q_identifier in pre_releases, release_dates, movie['info']['year']) if not alway_search and could_not_be_released: too_early_to_search.append(q_identifier) diff --git a/couchpotato/core/plugins/profile/main.py b/couchpotato/core/plugins/profile/main.py index 1098719..489c34d 100644 --- a/couchpotato/core/plugins/profile/main.py +++ b/couchpotato/core/plugins/profile/main.py @@ -88,6 +88,7 @@ class ProfilePlugin(Plugin): 'core': kwargs.get('core', False), 'qualities': [], 'wait_for': [], + 'stop_after': [], 'finish': [], '3d': [] } @@ -97,6 +98,7 @@ class ProfilePlugin(Plugin): for type in kwargs.get('types', []): profile['qualities'].append(type.get('quality')) profile['wait_for'].append(tryInt(kwargs.get('wait_for', 0))) + profile['stop_after'].append(tryInt(kwargs.get('stop_after', 0))) profile['finish'].append((tryInt(type.get('finish')) == 1) if order > 0 else True) profile['3d'].append(tryInt(type.get('3d'))) order += 1 @@ -217,6 +219,7 @@ class ProfilePlugin(Plugin): 'qualities': profile.get('qualities'), 'finish': [], 'wait_for': [], + 'stop_after': [], '3d': [] } @@ -224,6 +227,7 @@ class ProfilePlugin(Plugin): for q in profile.get('qualities'): pro['finish'].append(True) pro['wait_for'].append(0) + pro['stop_after'].append(0) pro['3d'].append(threed.pop() if threed else False) db.insert(pro) diff --git a/couchpotato/core/plugins/profile/static/profile.js b/couchpotato/core/plugins/profile/static/profile.js index c62b137..2bdd950 100644 --- a/couchpotato/core/plugins/profile/static/profile.js +++ b/couchpotato/core/plugins/profile/static/profile.js @@ -51,7 +51,15 @@ var Profile = new Class({ new Element('div.formHint', { 'html': "Search these qualities (2 minimum), from top to bottom. Use the checkbox, to stop searching after it found this quality." }) - ) + ), + new Element('div.stop_after.ctrlHolder').adopt( + new Element('span', {'text':'Stop searching for better than first checked quality after'}), + new Element('input.inlay.xsmall', { + 'type':'text', + 'value': data.stop_after && data.stop_after.length > 0 ? data.stop_after[0] : 0 + }), + new Element('span', {'text':'day(s).'}) + ) ); self.makeSortable(); @@ -117,6 +125,7 @@ var Profile = new Class({ 'id' : self.data._id, 'label' : self.el.getElement('.quality_label input').get('value'), 'wait_for' : self.el.getElement('.wait_for input').get('value'), + 'stop_after' : self.el.getElement('.stop_after input').get('value'), 'types': [] }; diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index dd820cf..40ef8cf 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -379,13 +379,17 @@ class QualityPlugin(Plugin): if score.get(q.get('identifier')): score[q.get('identifier')]['score'] -= 1 - def isFinish(self, quality, profile): + def isFinish(self, quality, profile, release_age = 0): if not isinstance(profile, dict) or not profile.get('qualities'): return False try: - quality_order = [i for i, identifier in enumerate(profile['qualities']) if identifier == quality['identifier'] and bool(profile['3d'][i] if profile.get('3d') else 0) == bool(quality.get('is_3d', 0))][0] - return profile['finish'][quality_order] + index = [i for i, identifier in enumerate(profile['qualities']) if identifier == quality['identifier'] and bool(profile['3d'][i] if profile.get('3d') else False) == bool(quality.get('is_3d', False))][0] + + if index == 0 or profile['finish'][index] and int(release_age) >= int(profile['stop_after'][0]): + return True + + return False except: return False diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index cb16c5a..df710c3 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -331,12 +331,7 @@ class Release(Plugin): if media['status'] == 'active': profile = db.get('id', media['profile_id']) - finished = False - if rls['quality'] in profile['qualities']: - nr = profile['qualities'].index(rls['quality']) - finished = profile['finish'][nr] - - if finished: + if fireEvent('quality.isfinish', {'identifier': rls['quality'], 'is_3d': rls.get('is_3d', False)}, profile, single = True): log.info('Renamer disabled, marking media as finished: %s', log_movie) # Mark release done From e55302592ae20b2d0295246170e8227b611ebdcf Mon Sep 17 00:00:00 2001 From: mano3m Date: Mon, 2 Jun 2014 19:04:04 +0200 Subject: [PATCH 057/117] Improve description --- couchpotato/core/plugins/profile/static/profile.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/couchpotato/core/plugins/profile/static/profile.js b/couchpotato/core/plugins/profile/static/profile.js index 2bdd950..5ce6eaf 100644 --- a/couchpotato/core/plugins/profile/static/profile.js +++ b/couchpotato/core/plugins/profile/static/profile.js @@ -44,6 +44,7 @@ var Profile = new Class({ 'value': data.wait_for && data.wait_for.length > 0 ? data.wait_for[0] : 0 }), new Element('span', {'text':'day(s) for a better quality.'}) + // "Wait the entered number of days for a checked quality, before downloading a lower quality release." ), new Element('div.qualities.ctrlHolder').adopt( new Element('label', {'text': 'Search for'}), @@ -52,14 +53,15 @@ var Profile = new Class({ 'html': "Search these qualities (2 minimum), from top to bottom. Use the checkbox, to stop searching after it found this quality." }) ), - new Element('div.stop_after.ctrlHolder').adopt( - new Element('span', {'text':'Stop searching for better than first checked quality after'}), - new Element('input.inlay.xsmall', { - 'type':'text', - 'value': data.stop_after && data.stop_after.length > 0 ? data.stop_after[0] : 0 - }), - new Element('span', {'text':'day(s).'}) - ) + new Element('div.stop_after.ctrlHolder').adopt( + new Element('span', {'text':'Keep searching'}), + new Element('input.inlay.xsmall', { + 'type':'text', + 'value': data.stop_after && data.stop_after.length > 0 ? data.stop_after[0] : 0 + }), + new Element('span', {'text':'day(s) for a better checked quality.'}) + // "After a checked quality is found and downloaded, continue searching for even better quality releases for the entered number of days." + ) ); self.makeSortable(); @@ -125,7 +127,7 @@ var Profile = new Class({ 'id' : self.data._id, 'label' : self.el.getElement('.quality_label input').get('value'), 'wait_for' : self.el.getElement('.wait_for input').get('value'), - 'stop_after' : self.el.getElement('.stop_after input').get('value'), + 'stop_after' : self.el.getElement('.stop_after input').get('value'), 'types': [] }; From 03dff14ee95202e2e0e52fb1f075abe183511125 Mon Sep 17 00:00:00 2001 From: mano3m Date: Mon, 2 Jun 2014 19:52:41 +0200 Subject: [PATCH 058/117] Massive bug fix --- couchpotato/core/plugins/release/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index df710c3..f9c563f 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -102,7 +102,7 @@ class Release(Plugin): # Set all snatched and downloaded releases to ignored to make sure they are ignored when re-adding the move elif rel['status'] in ['snatched', 'downloaded']: - self.updateStatus(rel['_id'], status = 'ignore') + self.updateStatus(rel['_id'], status = 'ignored') fireEvent('media.untag', media.get('_id'), 'recent', single = True) From f01449f14c75b677f8b3551da5a02d948ffa9413 Mon Sep 17 00:00:00 2001 From: mano3m Date: Sat, 7 Jun 2014 15:50:50 +0200 Subject: [PATCH 059/117] Rename scanned files for done media properly --- couchpotato/core/plugins/quality/main.py | 6 +++--- couchpotato/core/plugins/renamer.py | 29 +++++++++++++++-------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 40ef8cf..8f1484d 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -381,7 +381,7 @@ class QualityPlugin(Plugin): def isFinish(self, quality, profile, release_age = 0): if not isinstance(profile, dict) or not profile.get('qualities'): - return False + profile = fireEvent('profile.default', single = True) try: index = [i for i, identifier in enumerate(profile['qualities']) if identifier == quality['identifier'] and bool(profile['3d'][i] if profile.get('3d') else False) == bool(quality.get('is_3d', False))][0] @@ -395,14 +395,14 @@ class QualityPlugin(Plugin): def isHigher(self, quality, compare_with, profile = None): if not isinstance(profile, dict) or not profile.get('qualities'): - profile = {'qualities': self.order} + profile = fireEvent('profile.default', single = True) # Try to find quality in profile, if not found: a quality we do not want is lower than anything else try: quality_order = [i for i, identifier in enumerate(profile['qualities']) if identifier == quality['identifier'] and bool(profile['3d'][i] if profile.get('3d') else 0) == bool(quality.get('is_3d', 0))][0] except: log.debug('Quality %s not found in profile identifiers %s', (quality['identifier'] + (' 3D' if quality.get('is_3d', 0) else ''), \ - [identifier + ('3D' if (profile['3d'][i] if profile.get('3d') else 0) else '') for i, identifier in enumerate(profile['qualities'])])) + [identifier + (' 3D' if (profile['3d'][i] if profile.get('3d') else 0) else '') for i, identifier in enumerate(profile['qualities'])])) return 'lower' # Try to find compare quality in profile, if not found: anything is higher than a not wanted quality diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 8b57103..2a6c4a8 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -446,22 +446,23 @@ class Renamer(Plugin): # Before renaming, remove the lower quality files remove_leftovers = True - # Mark movie "done" once it's found the quality with the finish check + # Get media quality profile profile = None - try: - if media.get('status') == 'active' and media.get('profile_id'): - profile = db.get('id', media['profile_id']) - if fireEvent('quality.isfinish', group['meta_data']['quality'], profile, single = True): - mdia = db.get('id', media['_id']) - mdia['status'] = 'done' - mdia['last_edit'] = int(time.time()) - db.update(mdia) + if media.get('profile_id'): + profile = db.get('id', media['profile_id']) + else: + log.debug('Media has no quality profile: %s', media_title) - # List movie on dashboard - fireEvent('media.tag', media['_id'], 'recent', single = True) + # Mark movie "done" once it's found the quality with the finish check + if media.get('status') == 'active': + if fireEvent('quality.isfinish', group['meta_data']['quality'], profile, single = True): + mdia = db.get('id', media['_id']) + mdia['status'] = 'done' + mdia['last_edit'] = int(time.time()) + db.update(mdia) - except: - log.error('Failed marking movie finished: %s', (traceback.format_exc())) + # List movie on dashboard + fireEvent('media.tag', media['_id'], 'recent', single = True) # Mark media for dashboard mark_as_recent = False @@ -474,7 +475,7 @@ class Renamer(Plugin): # This is where CP removes older, lesser quality releases or releases that are not wanted anymore is_higher = fireEvent('quality.ishigher', \ - group['meta_data']['quality'], {'identifier': release['quality'], 'is_3d': release.get('is_3d', 0)}, profile, single = True) + group['meta_data']['quality'], {'identifier': release['quality'], 'is_3d': release.get('is_3d', False)}, profile, single = True) if is_higher == 'higher': log.info('Removing lesser or not wanted quality %s for %s.', (media_title, release.get('quality'))) From 5af5749d4ad3d30514b3ca53d61a7e07273eb3cf Mon Sep 17 00:00:00 2001 From: mano3m Date: Sat, 7 Jun 2014 16:04:54 +0200 Subject: [PATCH 060/117] Catch missing deleted profile error @RuudBurger should we reset the profile of the media to default or None in case this happens or leave it the way it is? --- couchpotato/core/plugins/renamer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 2a6c4a8..1e35b84 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -449,7 +449,10 @@ class Renamer(Plugin): # Get media quality profile profile = None if media.get('profile_id'): - profile = db.get('id', media['profile_id']) + try: + profile = db.get('id', media['profile_id']) + except: + log.error('Error getting quality profile for %s: %s', (media_title, traceback.format_exc())) else: log.debug('Media has no quality profile: %s', media_title) From 9f6036c8d61783213cb40882e34b939d26542428 Mon Sep 17 00:00:00 2001 From: mano3m Date: Sat, 14 Jun 2014 23:18:19 +0200 Subject: [PATCH 061/117] Redo status update for media --- couchpotato/core/media/_base/media/main.py | 25 +++++++++++---------- couchpotato/core/media/movie/searcher.py | 35 ++++++++++-------------------- couchpotato/core/plugins/release/main.py | 2 +- couchpotato/core/plugins/renamer.py | 15 +++++-------- 4 files changed, 31 insertions(+), 46 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index dc9e97a..84bc564 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -1,3 +1,6 @@ +from datetime import timedelta +from operator import itemgetter +import time import traceback from string import ascii_lowercase @@ -452,20 +455,20 @@ class MediaPlugin(MediaBase): if not m['profile_id']: m['status'] = 'done' else: - move_to_wanted = True + m['status'] = 'active' try: - profile = db.get('id', m['profile_id']) - media_releases = fireEvent('release.for_media', m['_id'], single = True) + profile = db.get('id', m['profile_id']) + media_releases = fireEvent('release.for_media', m['_id'], single = True) + done_releases = [release for release in media_releases if release.get('status') == 'done'] - for q_identifier in profile['qualities']: - index = profile['qualities'].index(q_identifier) + if done_releases: + # Only look at latest added release + release = sorted(done_releases, key = itemgetter('last_edit'), reverse = True)[0] - for release in media_releases: - if q_identifier == release['quality'] and (release.get('status') == 'done' and profile['finish'][index]): - move_to_wanted = False - - m['status'] = 'active' if move_to_wanted else 'done' + # Check if we are finished with the media + if fireEvent('quality.isfinish', {'identifier': release['quality'], 'is_3d': release.get('is_3d', False)}, profile, timedelta(seconds = time.time() - release['last_edit']).days, single = True): + m['status'] = 'done' except RecordNotFound: log.debug('Failed restatus: %s', traceback.format_exc()) @@ -473,7 +476,7 @@ class MediaPlugin(MediaBase): if previous_status != m['status']: db.update(m) - return True + return m['status'] except: log.error('Failed restatus: %s', traceback.format_exc()) diff --git a/couchpotato/core/media/movie/searcher.py b/couchpotato/core/media/movie/searcher.py index 9048d17..e8b6a52 100644 --- a/couchpotato/core/media/movie/searcher.py +++ b/couchpotato/core/media/movie/searcher.py @@ -121,8 +121,19 @@ class MovieSearcher(SearcherBase, MovieTypeBase): if not movie['profile_id'] or (movie['status'] == 'done' and not manual): log.debug('Movie doesn\'t have a profile or already done, assuming in manage tab.') + fireEvent('media.restatus', movie['_id']) return + default_title = getTitle(movie) + if not default_title: + log.error('No proper info found for movie, removing it from library to stop it from causing more issues.') + fireEvent('media.delete', movie['_id'], single = True) + return + + # Update media status and check if it is still not done (due to the stop searching after feature + if fireEvent('media.restatus', movie['_id'], single = True) == 'done': + log.debug('No better quality found, marking movie %s as done.', default_title) + pre_releases = fireEvent('quality.pre_releases', single = True) release_dates = fireEvent('movie.update_release_dates', movie['_id'], merge = True) @@ -134,33 +145,9 @@ class MovieSearcher(SearcherBase, MovieTypeBase): ignore_eta = manual total_result_count = 0 - default_title = getTitle(movie) - if not default_title: - log.error('No proper info found for movie, removing it from library to cause it from having more issues.') - fireEvent('media.delete', movie['_id'], single = True) - return - db = get_db() profile = db.get('id', movie['profile_id']) - # Find out if we need to stop searching because 'stop_after' is met. Compare with the newest release found. - done_releases = [release for release in previous_releases if release.get('status') == 'done'] - - if done_releases: - done_release = sorted(done_releases, key = itemgetter('last_edit'), reverse = True)[0] - if fireEvent('quality.isfinish', {'identifier': done_release['quality'], 'is_3d': done_release.get('is_3d', False)}, profile, timedelta(seconds = time.time() - done_release['last_edit']).days, single = True): - - log.debug('No better quality than %s%s found for %s days, marking movie %s as done.', \ - (done_release['quality'], ' 3D' if done_release.get('is_3d', False) else '', profile['stop_after'][0], default_title)) - - # Mark media done - mdia = db.get('id', movie['_id']) - mdia['status'] = 'done' - mdia['last_edit'] = int(time.time()) - db.update(mdia) - - return - fireEvent('notify.frontend', type = 'movie.searcher.started', data = {'_id': movie['_id']}, message = 'Searching for "%s"' % default_title) # Ignore eta once every 7 days diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index f9c563f..ab0a022 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -100,7 +100,7 @@ class Release(Plugin): if rel['status'] in ['available']: self.delete(rel['_id']) - # Set all snatched and downloaded releases to ignored to make sure they are ignored when re-adding the move + # Set all snatched and downloaded releases to ignored to make sure they are ignored when re-adding the media elif rel['status'] in ['snatched', 'downloaded']: self.updateStatus(rel['_id'], status = 'ignored') diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 1e35b84..c0ee28d 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -452,20 +452,15 @@ class Renamer(Plugin): try: profile = db.get('id', media['profile_id']) except: + # Set profile to None as it does not exist anymore + media['profile_id'] = None + db.update(media) log.error('Error getting quality profile for %s: %s', (media_title, traceback.format_exc())) else: log.debug('Media has no quality profile: %s', media_title) - # Mark movie "done" once it's found the quality with the finish check - if media.get('status') == 'active': - if fireEvent('quality.isfinish', group['meta_data']['quality'], profile, single = True): - mdia = db.get('id', media['_id']) - mdia['status'] = 'done' - mdia['last_edit'] = int(time.time()) - db.update(mdia) - - # List movie on dashboard - fireEvent('media.tag', media['_id'], 'recent', single = True) + # # List movie on dashboard + # fireEvent('media.tag', media['_id'], 'recent', single = True) # Mark media for dashboard mark_as_recent = False From 424a3cd892054d574ecc6ffc81e39c470a7e4ead Mon Sep 17 00:00:00 2001 From: mano3m Date: Sat, 14 Jun 2014 23:30:44 +0200 Subject: [PATCH 062/117] Clean-up --- couchpotato/core/media/movie/_base/main.py | 2 +- couchpotato/core/media/movie/searcher.py | 13 ++++++------- couchpotato/core/plugins/quality/main.py | 3 ++- couchpotato/core/plugins/release/main.py | 2 +- couchpotato/core/plugins/renamer.py | 5 +++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/couchpotato/core/media/movie/_base/main.py b/couchpotato/core/media/movie/_base/main.py index 07c4751..336d803 100644 --- a/couchpotato/core/media/movie/_base/main.py +++ b/couchpotato/core/media/movie/_base/main.py @@ -236,7 +236,7 @@ class MovieBase(MovieTypeBase): db.update(m) - fireEvent('media.restatus', m['_id']) + fireEvent('media.restatus', m['_id'], single = True) m = db.get('id', media_id) diff --git a/couchpotato/core/media/movie/searcher.py b/couchpotato/core/media/movie/searcher.py index e8b6a52..7d92c57 100644 --- a/couchpotato/core/media/movie/searcher.py +++ b/couchpotato/core/media/movie/searcher.py @@ -1,5 +1,4 @@ -from datetime import date, timedelta -from operator import itemgetter +from datetime import date import random import re import time @@ -121,7 +120,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): if not movie['profile_id'] or (movie['status'] == 'done' and not manual): log.debug('Movie doesn\'t have a profile or already done, assuming in manage tab.') - fireEvent('media.restatus', movie['_id']) + fireEvent('media.restatus', movie['_id'], single = True) return default_title = getTitle(movie) @@ -145,9 +144,6 @@ class MovieSearcher(SearcherBase, MovieTypeBase): ignore_eta = manual total_result_count = 0 - db = get_db() - profile = db.get('id', movie['profile_id']) - fireEvent('notify.frontend', type = 'movie.searcher.started', data = {'_id': movie['_id']}, message = 'Searching for "%s"' % default_title) # Ignore eta once every 7 days @@ -158,6 +154,9 @@ class MovieSearcher(SearcherBase, MovieTypeBase): ignore_eta = True Env.prop(prop_name, value = time.time()) + db = get_db() + + profile = db.get('id', movie['profile_id']) ret = False for index, q_identifier in enumerate(profile.get('qualities', [])): @@ -192,7 +191,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): # Don't search for quality lower then already available. if has_better_quality > 0: log.info('Better quality (%s) already available or snatched for %s', (q_identifier, default_title)) - fireEvent('media.restatus', movie['_id']) + fireEvent('media.restatus', movie['_id'], single = True) break quality = fireEvent('quality.single', identifier = q_identifier, single = True) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 8f1484d..856cc22 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -381,7 +381,8 @@ class QualityPlugin(Plugin): def isFinish(self, quality, profile, release_age = 0): if not isinstance(profile, dict) or not profile.get('qualities'): - profile = fireEvent('profile.default', single = True) + # No profile so anything (scanned) is good enough + return True try: index = [i for i, identifier in enumerate(profile['qualities']) if identifier == quality['identifier'] and bool(profile['3d'][i] if profile.get('3d') else False) == bool(quality.get('is_3d', False))][0] diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index ab0a022..628bd69 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -164,7 +164,7 @@ class Release(Plugin): release['files'] = dict((k, [toUnicode(x) for x in v]) for k, v in group['files'].items() if v) db.update(release) - fireEvent('media.restatus', media['_id']) + fireEvent('media.restatus', media['_id'], single = True) return True except: diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index c0ee28d..824aa79 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -453,8 +453,9 @@ class Renamer(Plugin): profile = db.get('id', media['profile_id']) except: # Set profile to None as it does not exist anymore - media['profile_id'] = None - db.update(media) + mdia = db.get('id', media['_id']) + mdia['profile_id'] = None + db.update(mdia) log.error('Error getting quality profile for %s: %s', (media_title, traceback.format_exc())) else: log.debug('Media has no quality profile: %s', media_title) From 40e910192e5fe046540883090bf861650256d34f Mon Sep 17 00:00:00 2001 From: mano3m Date: Fri, 20 Jun 2014 19:25:01 +0200 Subject: [PATCH 063/117] Fix tagging --- couchpotato/core/media/_base/media/main.py | 3 +++ couchpotato/core/plugins/release/main.py | 7 +------ couchpotato/core/plugins/renamer.py | 3 --- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 84bc564..f8efb7c 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -476,6 +476,9 @@ class MediaPlugin(MediaBase): if previous_status != m['status']: db.update(m) + # Tag media as recent + self.tag(media_id, 'recent') + return m['status'] except: log.error('Failed restatus: %s', traceback.format_exc()) diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 628bd69..404dede 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -338,12 +338,7 @@ class Release(Plugin): self.updateStatus(rls['_id'], status = 'done') # Mark media done - mdia = db.get('id', media['_id']) - mdia['status'] = 'done' - mdia['last_edit'] = int(time.time()) - db.update(mdia) - - fireEvent('media.tag', media['_id'], 'recent', single = True) + fireEvent('media.restatus', media['_id'], single = True) return True diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 824aa79..6c6d6b8 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -460,9 +460,6 @@ class Renamer(Plugin): else: log.debug('Media has no quality profile: %s', media_title) - # # List movie on dashboard - # fireEvent('media.tag', media['_id'], 'recent', single = True) - # Mark media for dashboard mark_as_recent = False From b4e25d434501512f0d7a06384b798d5a8a9e1650 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 21:50:23 +0200 Subject: [PATCH 064/117] Indent fixes --- couchpotato/core/media/_base/media/main.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index f8efb7c..c0639d2 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -458,17 +458,17 @@ class MediaPlugin(MediaBase): m['status'] = 'active' try: - profile = db.get('id', m['profile_id']) - media_releases = fireEvent('release.for_media', m['_id'], single = True) - done_releases = [release for release in media_releases if release.get('status') == 'done'] + profile = db.get('id', m['profile_id']) + media_releases = fireEvent('release.for_media', m['_id'], single = True) + done_releases = [release for release in media_releases if release.get('status') == 'done'] - if done_releases: - # Only look at latest added release - release = sorted(done_releases, key = itemgetter('last_edit'), reverse = True)[0] + if done_releases: + # Only look at latest added release + release = sorted(done_releases, key = itemgetter('last_edit'), reverse = True)[0] - # Check if we are finished with the media - if fireEvent('quality.isfinish', {'identifier': release['quality'], 'is_3d': release.get('is_3d', False)}, profile, timedelta(seconds = time.time() - release['last_edit']).days, single = True): - m['status'] = 'done' + # Check if we are finished with the media + if fireEvent('quality.isfinish', {'identifier': release['quality'], 'is_3d': release.get('is_3d', False)}, profile, timedelta(seconds = time.time() - release['last_edit']).days, single = True): + m['status'] = 'done' except RecordNotFound: log.debug('Failed restatus: %s', traceback.format_exc()) From 508649e6b6d4f387fa556d1b7246572d6e1150a9 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 21:51:14 +0200 Subject: [PATCH 065/117] Optimize import --- couchpotato/__init__.py | 7 ++++--- couchpotato/core/downloaders/rtorrent_.py | 1 - couchpotato/core/media/movie/suggestion/main.py | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/couchpotato/__init__.py b/couchpotato/__init__.py index fb6b4dc..daa93bc 100644 --- a/couchpotato/__init__.py +++ b/couchpotato/__init__.py @@ -1,3 +1,7 @@ +import os +import time +import traceback + from couchpotato.api import api_docs, api_docs_missing, api from couchpotato.core.event import fireEvent from couchpotato.core.helpers.variable import md5, tryInt @@ -5,9 +9,6 @@ from couchpotato.core.logger import CPLog from couchpotato.environment import Env from tornado import template from tornado.web import RequestHandler, authenticated -import os -import time -import traceback log = CPLog(__name__) diff --git a/couchpotato/core/downloaders/rtorrent_.py b/couchpotato/core/downloaders/rtorrent_.py index 822501a..7474697 100644 --- a/couchpotato/core/downloaders/rtorrent_.py +++ b/couchpotato/core/downloaders/rtorrent_.py @@ -5,7 +5,6 @@ from urlparse import urlparse import os from couchpotato.core._base.downloader.main import DownloaderBase, ReleaseDownloadList - from couchpotato.core.event import addEvent from couchpotato.core.helpers.encoding import sp from couchpotato.core.helpers.variable import cleanHost, splitString diff --git a/couchpotato/core/media/movie/suggestion/main.py b/couchpotato/core/media/movie/suggestion/main.py index c2cc907..146a6a0 100644 --- a/couchpotato/core/media/movie/suggestion/main.py +++ b/couchpotato/core/media/movie/suggestion/main.py @@ -1,4 +1,3 @@ -from couchpotato import get_db from couchpotato.api import addApiView from couchpotato.core.event import fireEvent from couchpotato.core.helpers.variable import splitString, removeDuplicate, getIdentifier From d2271055274f0fa8d048dfa6b19e375070c1216b Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 22:04:42 +0200 Subject: [PATCH 066/117] Make keep search advanced --- .../core/plugins/profile/static/profile.css | 5 ++--- couchpotato/core/plugins/profile/static/profile.js | 24 ++++++++++------------ couchpotato/static/style/settings.css | 4 +++- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/couchpotato/core/plugins/profile/static/profile.css b/couchpotato/core/plugins/profile/static/profile.css index f8a1b42..edab831 100644 --- a/couchpotato/core/plugins/profile/static/profile.css +++ b/couchpotato/core/plugins/profile/static/profile.css @@ -43,9 +43,8 @@ } .profile .wait_for { - position: absolute; - right: 60px; - top: 0; + padding-top: 0; + padding-bottom: 20px; } .profile .wait_for input { diff --git a/couchpotato/core/plugins/profile/static/profile.js b/couchpotato/core/plugins/profile/static/profile.js index 5ce6eaf..20c706d 100644 --- a/couchpotato/core/plugins/profile/static/profile.js +++ b/couchpotato/core/plugins/profile/static/profile.js @@ -37,15 +37,6 @@ var Profile = new Class({ 'placeholder': 'Profile name' }) ), - new Element('div.wait_for.ctrlHolder').adopt( - new Element('span', {'text':'Wait'}), - new Element('input.inlay.xsmall', { - 'type':'text', - 'value': data.wait_for && data.wait_for.length > 0 ? data.wait_for[0] : 0 - }), - new Element('span', {'text':'day(s) for a better quality.'}) - // "Wait the entered number of days for a checked quality, before downloading a lower quality release." - ), new Element('div.qualities.ctrlHolder').adopt( new Element('label', {'text': 'Search for'}), self.type_container = new Element('ol.types'), @@ -53,14 +44,21 @@ var Profile = new Class({ 'html': "Search these qualities (2 minimum), from top to bottom. Use the checkbox, to stop searching after it found this quality." }) ), - new Element('div.stop_after.ctrlHolder').adopt( - new Element('span', {'text':'Keep searching'}), + new Element('div.wait_for.ctrlHolder').adopt( + // "Wait the entered number of days for a checked quality, before downloading a lower quality release." + new Element('span', {'text':'Wait'}), new Element('input.inlay.xsmall', { 'type':'text', - 'value': data.stop_after && data.stop_after.length > 0 ? data.stop_after[0] : 0 + 'value': data.wait_for && data.wait_for.length > 0 ? data.wait_for[0] : 0 }), - new Element('span', {'text':'day(s) for a better checked quality.'}) + new Element('span', {'text':'day(s) for a better quality '}), + new Element('span.advanced', {'text':'and keep searching'}), // "After a checked quality is found and downloaded, continue searching for even better quality releases for the entered number of days." + new Element('input.inlay.xsmall.advanced', { + 'type':'text', + 'value': data.stop_after && data.stop_after.length > 0 ? data.stop_after[0] : 0 + }), + new Element('span.advanced', {'text':'day(s) for a better (checked) quality.'}) ) ); diff --git a/couchpotato/static/style/settings.css b/couchpotato/static/style/settings.css index 50b305e..7fb1df2 100644 --- a/couchpotato/static/style/settings.css +++ b/couchpotato/static/style/settings.css @@ -75,6 +75,8 @@ color: #edc07f; } .page.show_advanced .advanced { display: block; } + .page.show_advanced span.advanced, + .page.show_advanced input.advanced { display: inline; } .page.settings .tab_content { display: none; @@ -176,7 +178,7 @@ padding: 6px 0 0; } - .page .xsmall { width: 20px !important; text-align: center; } + .page .xsmall { width: 25px !important; text-align: center; } .page .enabler { display: block; From 4008cce12f5705886fe210407a378ba277d6ec91 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 23:37:17 +0200 Subject: [PATCH 067/117] Manually get media with status --- couchpotato/core/media/_base/media/main.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index c0639d2..06f1661 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -167,8 +167,15 @@ class MediaPlugin(MediaBase): status = list(status if isinstance(status, (list, tuple)) else [status]) for s in status: - for ms in db.get_many('media_status', s, with_doc = with_doc): - yield ms['doc'] if with_doc else ms + for ms in db.get_many('media_status', s): + if with_doc: + try: + doc = db.get('id', ms['_id']) + yield doc + except RecordNotFound: + log.debug('Record not found, skipping: %s', ms['_id']) + else: + yield ms def withIdentifiers(self, identifiers, with_doc = False): From 5425fcae9eb65b66a8892e29e91690b9225863e1 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 23:40:36 +0200 Subject: [PATCH 068/117] Manually get with_status releases --- couchpotato/core/plugins/release/main.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 404dede..b92816c 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -3,7 +3,7 @@ import os import time import traceback -from CodernityDB.database import RecordDeleted +from CodernityDB.database import RecordDeleted, RecordNotFound from couchpotato import md5, get_db from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, addEvent @@ -501,8 +501,15 @@ class Release(Plugin): status = list(status if isinstance(status, (list, tuple)) else [status]) for s in status: - for ms in db.get_many('release_status', s, with_doc = with_doc): - yield ms['doc'] if with_doc else ms + for ms in db.get_many('release_status', s): + if with_doc: + try: + doc = db.get('id', ms['_id']) + yield doc + except RecordNotFound: + log.debug('Record not found, skipping: %s', ms['_id']) + else: + yield ms def forMedia(self, media_id): From 5c891b7e8ed898e0e7792c85ee47d4c296f238bb Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 23 Jun 2014 23:47:30 +0200 Subject: [PATCH 069/117] Try next on failed trailer download --- couchpotato/core/plugins/trailer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/trailer.py b/couchpotato/core/plugins/trailer.py index ae52586..82216b8 100644 --- a/couchpotato/core/plugins/trailer.py +++ b/couchpotato/core/plugins/trailer.py @@ -32,7 +32,7 @@ class Trailer(Plugin): destination = os.path.join(group['destination_dir'], filename) if not os.path.isfile(destination): trailer_file = fireEvent('file.download', url = trailer, dest = destination, urlopen_kwargs = {'headers': {'User-Agent': 'Quicktime'}}, single = True) - if os.path.getsize(trailer_file) < (1024 * 1024): # Don't trust small trailers (1MB), try next one + if trailer_file and os.path.getsize(trailer_file) < (1024 * 1024): # Don't trust small trailers (1MB), try next one os.unlink(trailer_file) continue else: From 5c586fbf3027080de8993c5167522aa801701985 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 24 Jun 2014 10:02:14 +0200 Subject: [PATCH 070/117] Update isSubFolder test --- couchpotato/core/helpers/variable.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index 66e01f5..f98adaa 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -291,9 +291,14 @@ def dictIsSubset(a, b): return all([k in b and b[k] == v for k, v in a.items()]) +# Returns True if sub_folder is the same as or inside base_folder def isSubFolder(sub_folder, base_folder): - # Returns True if sub_folder is the same as or inside base_folder - return base_folder and sub_folder and ss(os.path.normpath(base_folder).rstrip(os.path.sep) + os.path.sep) in ss(os.path.normpath(sub_folder).rstrip(os.path.sep) + os.path.sep) + if base_folder and sub_folder: + base = sp(os.path.realpath(base_folder)) + subfolder = sp(os.path.realpath(sub_folder)) + return os.path.commonprefix([subfolder, base]) == base + + return False # From SABNZBD From 7401201af21429847acf9ebaac297a086e5673a7 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 24 Jun 2014 10:02:43 +0200 Subject: [PATCH 071/117] Add subfolder path test --- couchpotato/core/plugins/file.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/file.py b/couchpotato/core/plugins/file.py index 51adf8c..2145ffe 100644 --- a/couchpotato/core/plugins/file.py +++ b/couchpotato/core/plugins/file.py @@ -5,7 +5,7 @@ from couchpotato import get_db from couchpotato.api import addApiView from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.encoding import toUnicode -from couchpotato.core.helpers.variable import md5, getExt +from couchpotato.core.helpers.variable import md5, getExt, isSubFolder from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.environment import Env @@ -32,6 +32,8 @@ class FileManager(Plugin): fireEvent('schedule.interval', 'file.cleanup', self.cleanup, hours = 24) + addEvent('app.test', self.doSubfolderTest) + def cleanup(self): # Wait a bit after starting before cleanup @@ -76,3 +78,32 @@ class FileManager(Plugin): self.createFile(dest, filedata, binary = True) return dest + + def doSubfolderTest(self): + + tests = { + ('/test/sub/folder', '/test/sub'): True, + ('/test/sub/folder', '/test/sub2'): False, + ('/sub/fold', '/test/sub/fold'): False, + ('/sub/fold', '/test/sub/folder'): False, + ('/opt/couchpotato', '/var/opt/couchpotato'): False, + ('/var/opt', '/var/opt/couchpotato'): False, + ('/CapItaLs/Are/OK', '/CapItaLs/Are/OK'): True, + ('/CapItaLs/Are/OK', '/CapItaLs/Are/OK2'): False, + ('/capitals/are/not/OK', '/capitals/are/NOT'): False, + ('\\\\Mounted\\Volume\\Test', '\\\\Mounted\\Volume'): True, + ('C:\\\\test\\path', 'C:\\\\test2'): False + } + + failed = 0 + for x in tests: + if isSubFolder(x[0], x[1]) is not tests[x]: + log.error('Failed subfolder test %s %s', x) + failed += 1 + + if failed > 0: + log.error('Subfolder test failed %s tests', failed) + else: + log.info('Subfolder test succeeded') + + return failed == 0 \ No newline at end of file From 3941076c06d35a191efbdfa54588422cd281b272 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 24 Jun 2014 10:09:34 +0200 Subject: [PATCH 072/117] Forgot to add the separator to test --- couchpotato/core/helpers/variable.py | 4 ++-- couchpotato/core/plugins/file.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index f98adaa..b3de683 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -294,8 +294,8 @@ def dictIsSubset(a, b): # Returns True if sub_folder is the same as or inside base_folder def isSubFolder(sub_folder, base_folder): if base_folder and sub_folder: - base = sp(os.path.realpath(base_folder)) - subfolder = sp(os.path.realpath(sub_folder)) + base = sp(os.path.realpath(base_folder)) + os.path.sep + subfolder = sp(os.path.realpath(sub_folder)) + os.path.sep return os.path.commonprefix([subfolder, base]) == base return False diff --git a/couchpotato/core/plugins/file.py b/couchpotato/core/plugins/file.py index 2145ffe..80c073f 100644 --- a/couchpotato/core/plugins/file.py +++ b/couchpotato/core/plugins/file.py @@ -82,6 +82,7 @@ class FileManager(Plugin): def doSubfolderTest(self): tests = { + ('/test/subfolder', '/test/sub'): False, ('/test/sub/folder', '/test/sub'): True, ('/test/sub/folder', '/test/sub2'): False, ('/sub/fold', '/test/sub/fold'): False, From b00b6acba8127b08f86e20074f2388ddc20f8ae1 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 24 Jun 2014 20:18:51 +0200 Subject: [PATCH 073/117] Profile don't save. fix #3437 --- couchpotato/core/plugins/profile/static/profile.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/plugins/profile/static/profile.js b/couchpotato/core/plugins/profile/static/profile.js index 20c706d..89f1a69 100644 --- a/couchpotato/core/plugins/profile/static/profile.js +++ b/couchpotato/core/plugins/profile/static/profile.js @@ -47,14 +47,14 @@ var Profile = new Class({ new Element('div.wait_for.ctrlHolder').adopt( // "Wait the entered number of days for a checked quality, before downloading a lower quality release." new Element('span', {'text':'Wait'}), - new Element('input.inlay.xsmall', { + new Element('input.inlay.wait_for_input.xsmall', { 'type':'text', 'value': data.wait_for && data.wait_for.length > 0 ? data.wait_for[0] : 0 }), new Element('span', {'text':'day(s) for a better quality '}), new Element('span.advanced', {'text':'and keep searching'}), // "After a checked quality is found and downloaded, continue searching for even better quality releases for the entered number of days." - new Element('input.inlay.xsmall.advanced', { + new Element('input.inlay.xsmall.stop_after_input.advanced', { 'type':'text', 'value': data.stop_after && data.stop_after.length > 0 ? data.stop_after[0] : 0 }), @@ -124,8 +124,8 @@ var Profile = new Class({ var data = { 'id' : self.data._id, 'label' : self.el.getElement('.quality_label input').get('value'), - 'wait_for' : self.el.getElement('.wait_for input').get('value'), - 'stop_after' : self.el.getElement('.stop_after input').get('value'), + 'wait_for' : self.el.getElement('.wait_for_input').get('value'), + 'stop_after' : self.el.getElement('.stop_after_input').get('value'), 'types': [] }; From b6b936ddf3350612d7375a40073bc7c1604bf0b7 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 24 Jun 2014 20:50:25 +0200 Subject: [PATCH 074/117] Use other name guess. fix #3501 --- couchpotato/core/plugins/scanner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/scanner.py b/couchpotato/core/plugins/scanner.py index 01a88fb..6a4d537 100644 --- a/couchpotato/core/plugins/scanner.py +++ b/couchpotato/core/plugins/scanner.py @@ -639,9 +639,9 @@ class Scanner(Plugin): # Try with other if len(movie) == 0 and name_year.get('other') and name_year['other'].get('name') and name_year['other'].get('year'): - search_q2 = '%(name)s %(year)s' % name_year + search_q2 = '%(name)s %(year)s' % name_year.get('other') if search_q2 != search_q: - movie = fireEvent('movie.search', q = '%(name)s %(year)s' % name_year.get('other'), merge = True, limit = 1) + movie = fireEvent('movie.search', q = search_q2, merge = True, limit = 1) if len(movie) > 0: imdb_id = movie[0].get('imdb') From bb19b380b46a93a21020ffd21efa4f6e7ad79000 Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 24 Jun 2014 21:20:13 +0200 Subject: [PATCH 075/117] Don't start CP when less then 100MB is available. fix #3502 --- couchpotato/core/helpers/variable.py | 35 +++++++++++++++++++++++++++++++++++ couchpotato/core/plugins/manage.py | 30 ++---------------------------- couchpotato/runner.py | 11 ++++++++++- 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index b3de683..5d9f1ad 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -1,4 +1,5 @@ import collections +import ctypes import hashlib import os import platform @@ -346,3 +347,37 @@ def removePyc(folder, only_excess = True, show_logs = True): os.rmdir(full_path) except: log.error('Couldn\'t remove empty directory %s: %s', (full_path, traceback.format_exc())) + + +def getFreeSpace(directories): + + single = not isinstance(directories, (tuple, list)) + if single: + directories = [directories] + + free_space = {} + for folder in directories: + + size = None + if os.path.isdir(folder): + if os.name == 'nt': + _, total, free = ctypes.c_ulonglong(), ctypes.c_ulonglong(), \ + ctypes.c_ulonglong() + if sys.version_info >= (3,) or isinstance(folder, unicode): + fun = ctypes.windll.kernel32.GetDiskFreeSpaceExW #@UndefinedVariable + else: + fun = ctypes.windll.kernel32.GetDiskFreeSpaceExA #@UndefinedVariable + ret = fun(folder, ctypes.byref(_), ctypes.byref(total), ctypes.byref(free)) + if ret == 0: + raise ctypes.WinError() + used = total.value - free.value + return [total.value, used, free.value] + else: + s = os.statvfs(folder) + size = [s.f_blocks * s.f_frsize / (1024 * 1024), (s.f_bavail * s.f_frsize) / (1024 * 1024)] + + if single: return size + + free_space[folder] = size + + return free_space diff --git a/couchpotato/core/plugins/manage.py b/couchpotato/core/plugins/manage.py index 637facf..c8d53ea 100644 --- a/couchpotato/core/plugins/manage.py +++ b/couchpotato/core/plugins/manage.py @@ -1,6 +1,4 @@ -import ctypes import os -import sys import time import traceback @@ -8,7 +6,7 @@ from couchpotato import get_db from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, addEvent, fireEventAsync from couchpotato.core.helpers.encoding import sp -from couchpotato.core.helpers.variable import splitString, getTitle, tryInt, getIdentifier +from couchpotato.core.helpers.variable import splitString, getTitle, tryInt, getIdentifier, getFreeSpace from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.environment import Env @@ -273,31 +271,7 @@ class Manage(Plugin): fireEvent('release.add', group = group) def getDiskSpace(self): - - free_space = {} - for folder in self.directories(): - - size = None - if os.path.isdir(folder): - if os.name == 'nt': - _, total, free = ctypes.c_ulonglong(), ctypes.c_ulonglong(), \ - ctypes.c_ulonglong() - if sys.version_info >= (3,) or isinstance(folder, unicode): - fun = ctypes.windll.kernel32.GetDiskFreeSpaceExW #@UndefinedVariable - else: - fun = ctypes.windll.kernel32.GetDiskFreeSpaceExA #@UndefinedVariable - ret = fun(folder, ctypes.byref(_), ctypes.byref(total), ctypes.byref(free)) - if ret == 0: - raise ctypes.WinError() - used = total.value - free.value - return [total.value, used, free.value] - else: - s = os.statvfs(folder) - size = [s.f_blocks * s.f_frsize / (1024 * 1024), (s.f_bavail * s.f_frsize) / (1024 * 1024)] - - free_space[folder] = size - - return free_space + return getFreeSpace(self.directories()) config = [{ diff --git a/couchpotato/runner.py b/couchpotato/runner.py index 8a44605..e5f9bca 100644 --- a/couchpotato/runner.py +++ b/couchpotato/runner.py @@ -17,7 +17,7 @@ from couchpotato import KeyHandler, LoginHandler, LogoutHandler from couchpotato.api import NonBlockHandler, ApiHandler from couchpotato.core.event import fireEventAsync, fireEvent from couchpotato.core.helpers.encoding import sp -from couchpotato.core.helpers.variable import getDataDir, tryInt +from couchpotato.core.helpers.variable import getDataDir, tryInt, getFreeSpace import requests from tornado.httpserver import HTTPServer from tornado.web import Application, StaticFileHandler, RedirectHandler @@ -195,6 +195,15 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En log = CPLog(__name__) log.debug('Started with options %s', options) + # Check available space + try: + total_space, available_space = getFreeSpace(data_dir) + if available_space < 100: + log.error('Shutting down as CP needs some space to work. You\'ll get corrupted data otherwise. Only %sMB left', available_space) + return + except: + log.error('Failed getting diskspace: %s', traceback.format_exc()) + def customwarn(message, category, filename, lineno, file = None, line = None): log.warning('%s %s %s line:%s', (category, message, filename, lineno)) warnings.showwarning = customwarn From 1de0443492774bee8cece103758a18af39f48efc Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 24 Jun 2014 21:56:46 +0200 Subject: [PATCH 076/117] Get default "stop after" if it isn't set yet. fix #3499 --- couchpotato/core/plugins/quality/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 856cc22..27939a7 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -387,8 +387,8 @@ class QualityPlugin(Plugin): try: index = [i for i, identifier in enumerate(profile['qualities']) if identifier == quality['identifier'] and bool(profile['3d'][i] if profile.get('3d') else False) == bool(quality.get('is_3d', False))][0] - if index == 0 or profile['finish'][index] and int(release_age) >= int(profile['stop_after'][0]): - return True + if index == 0 or (profile['finish'][index] and int(release_age) >= int(profile.get('stop_after', [0])[0])): + return True return False except: From 24a8cb41fe2d9977caf4de5fad50458ac2c6da3b Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 24 Jun 2014 22:01:27 +0200 Subject: [PATCH 077/117] Keep previous status if restatus check fails --- couchpotato/core/media/_base/media/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 06f1661..2178ea1 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -477,7 +477,8 @@ class MediaPlugin(MediaBase): if fireEvent('quality.isfinish', {'identifier': release['quality'], 'is_3d': release.get('is_3d', False)}, profile, timedelta(seconds = time.time() - release['last_edit']).days, single = True): m['status'] = 'done' except RecordNotFound: - log.debug('Failed restatus: %s', traceback.format_exc()) + log.debug('Failed restatus, keeping previous: %s', traceback.format_exc()) + m['status'] = previous_status # Only update when status has changed if previous_status != m['status']: From 69819460f393b69e7e190c3c8d52fa87120cf74c Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 25 Jun 2014 09:27:23 +0200 Subject: [PATCH 078/117] Add zoink.it for torrent caching --- couchpotato/core/_base/downloader/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/core/_base/downloader/main.py b/couchpotato/core/_base/downloader/main.py index 70e5cc9..7ef98af 100644 --- a/couchpotato/core/_base/downloader/main.py +++ b/couchpotato/core/_base/downloader/main.py @@ -25,6 +25,7 @@ class DownloaderBase(Provider): status_support = True torrent_sources = [ + 'https://zoink.it/torrent/%s.torrent', 'http://torrage.com/torrent/%s.torrent', 'https://torcache.net/torrent/%s.torrent', ] From a566b4f4284904acc7592ed72f5ba8a25011fc27 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 25 Jun 2014 16:13:35 +0200 Subject: [PATCH 079/117] Setup property index with database module --- couchpotato/core/settings.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/couchpotato/core/settings.py b/couchpotato/core/settings.py index c6de952..4315ec1 100644 --- a/couchpotato/core/settings.py +++ b/couchpotato/core/settings.py @@ -71,15 +71,7 @@ class Settings(object): self.connectEvents() def databaseSetup(self): - from couchpotato import get_db - - db = get_db() - - try: - db.add_index(PropertyIndex(db.path, 'property')) - except: - self.log.debug('Index for properties already exists') - db.edit_index(PropertyIndex(db.path, 'property')) + fireEvent('database.setup_index', 'property', PropertyIndex) def parser(self): return self.p From ffc3fc9ec456bf0b908912038d3c22190a60dc13 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 25 Jun 2014 18:16:45 +0200 Subject: [PATCH 080/117] Check for broken indexes and reindex if needed --- couchpotato/core/database.py | 100 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 18 deletions(-) diff --git a/couchpotato/core/database.py b/couchpotato/core/database.py index d753d87..c7051f5 100644 --- a/couchpotato/core/database.py +++ b/couchpotato/core/database.py @@ -3,10 +3,11 @@ import os import time import traceback +from CodernityDB.index import IndexException, IndexNotFoundException, IndexConflict from couchpotato import CPLog from couchpotato.api import addApiView from couchpotato.core.event import addEvent, fireEvent -from couchpotato.core.helpers.encoding import toUnicode +from couchpotato.core.helpers.encoding import toUnicode, sp from couchpotato.core.helpers.variable import getImdb, tryInt @@ -15,11 +16,13 @@ log = CPLog(__name__) class Database(object): - indexes = [] + indexes = None db = None def __init__(self): + self.indexes = {} + addApiView('database.list_documents', self.listDocuments) addApiView('database.reindex', self.reindex) addApiView('database.compact', self.compact) @@ -45,26 +48,45 @@ class Database(object): def setupIndex(self, index_name, klass): - self.indexes.append(index_name) + self.indexes[index_name] = klass db = self.getDB() # Category index index_instance = klass(db.path, index_name) try: - db.add_index(index_instance) - db.reindex_index(index_name) - except: - previous = db.indexes_names[index_name] - previous_version = previous._version - current_version = klass._version - - # Only edit index if versions are different - if previous_version < current_version: - log.debug('Index "%s" already exists, updating and reindexing', index_name) - db.destroy_index(previous) + + # Make sure store and bucket don't exist + exists = [] + for x in ['buck', 'stor']: + full_path = os.path.join(db.path, '%s_%s' % (index_name, x)) + if os.path.exists(full_path): + exists.append(full_path) + + if index_name not in db.indexes_names: + + # Remove existing buckets if index isn't there + for x in exists: + os.unlink(x) + + # Add index (will restore buckets) db.add_index(index_instance) db.reindex_index(index_name) + else: + # Previous info + previous = db.indexes_names[index_name] + previous_version = previous._version + current_version = klass._version + + # Only edit index if versions are different + if previous_version < current_version: + log.debug('Index "%s" already exists, updating and reindexing', index_name) + db.destroy_index(previous) + db.add_index(index_instance) + db.reindex_index(index_name) + + except: + log.error('Failed adding index %s: %s', (index_name, traceback.format_exc())) def deleteDocument(self, **kwargs): @@ -138,21 +160,62 @@ class Database(object): 'success': success } - def compact(self, **kwargs): + def compact(self, try_repair = True, **kwargs): + + success = False + db = self.getDB() + + # Removing left over compact files + db_path = sp(db.path) + for f in os.listdir(sp(db.path)): + for x in ['_compact_buck', '_compact_stor']: + if f[-len(x):] == x: + os.unlink(os.path.join(db_path, f)) - success = True try: start = time.time() - db = self.getDB() size = float(db.get_db_details().get('size', 0)) log.debug('Compacting database, current size: %sMB', round(size/1048576, 2)) db.compact() new_size = float(db.get_db_details().get('size', 0)) log.debug('Done compacting database in %ss, new size: %sMB, saved: %sMB', (round(time.time()-start, 2), round(new_size/1048576, 2), round((size-new_size)/1048576, 2))) + success = True + except (IndexException, AttributeError): + if try_repair: + log.error('Something wrong with indexes, trying repair') + + # Remove all indexes + old_indexes = self.indexes.keys() + for index_name in old_indexes: + try: + db.destroy_index(index_name) + except IndexNotFoundException: + pass + except: + log.error('Failed removing old index %s', index_name) + + # Add them again + for index_name in self.indexes: + klass = self.indexes[index_name] + + # Category index + index_instance = klass(db.path, index_name) + try: + db.add_index(index_instance) + db.reindex_index(index_name) + except IndexConflict: + pass + except: + log.error('Failed adding index %s', index_name) + raise + + self.compact(try_repair = False) + else: + log.error('Failed compact: %s', traceback.format_exc()) + except: log.error('Failed compact: %s', traceback.format_exc()) - success = False return { 'success': success @@ -166,6 +229,7 @@ class Database(object): size = db.get_db_details().get('size') prop_name = 'last_db_compact' last_check = int(Env.prop(prop_name, default = 0)) + if size > 26214400 and last_check < time.time()-604800: # 25MB / 7 days self.compact() Env.prop(prop_name, value = int(time.time())) From 9ec4c2837e7e2588078e756f5ce43464f8b2cb9f Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 25 Jun 2014 18:20:42 +0200 Subject: [PATCH 081/117] Don't put original title first --- couchpotato/core/media/movie/providers/info/themoviedb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/media/movie/providers/info/themoviedb.py b/couchpotato/core/media/movie/providers/info/themoviedb.py index 4a397ed..ac1daec 100644 --- a/couchpotato/core/media/movie/providers/info/themoviedb.py +++ b/couchpotato/core/media/movie/providers/info/themoviedb.py @@ -154,7 +154,7 @@ class TheMovieDb(MovieProvider): # Add alternative names if movie_data['original_title'] and movie_data['original_title'] not in movie_data['titles']: - movie_data['titles'].insert(0, movie_data['original_title']) + movie_data['titles'].append(movie_data['original_title']) if extended: for alt in movie.alternate_titles: From b88d8efc8d79101eff73a16d3bf0c612662adfe4 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 25 Jun 2014 22:56:40 +0200 Subject: [PATCH 082/117] Allow 720p in cam quality. fix #3512 --- couchpotato/core/plugins/quality/main.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 27939a7..18816c4 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -32,7 +32,7 @@ class QualityPlugin(Plugin): {'identifier': 'r5', 'size': (600, 1000), 'label': 'R5', 'alternative': ['r6'], 'allow': ['dvdr'], 'ext':[]}, {'identifier': 'tc', 'size': (600, 1000), 'label': 'TeleCine', 'alternative': ['telecine'], 'allow': [], 'ext':[]}, {'identifier': 'ts', 'size': (600, 1000), 'label': 'TeleSync', 'alternative': ['telesync', 'hdts'], 'allow': [], 'ext':[]}, - {'identifier': 'cam', 'size': (600, 1000), 'label': 'Cam', 'alternative': ['camrip', 'hdcam'], 'allow': [], 'ext':[]} + {'identifier': 'cam', 'size': (600, 1000), 'label': 'Cam', 'alternative': ['camrip', 'hdcam'], 'allow': ['720p'], 'ext':[]} ] pre_releases = ['cam', 'ts', 'tc', 'r5', 'scr'] threed_tags = { @@ -451,6 +451,8 @@ class QualityPlugin(Plugin): '/movies/BluRay HDDVD H.264 MKV 720p EngSub/QuiQui le fou (criterion collection #123, 1915)/QuiQui le fou (1915) 720p x264 BluRay.mkv': {'size': 5500, 'quality': '720p'}, 'C:\\movies\QuiQui le fou (collection #123, 1915)\QuiQui le fou (1915) 720p x264 BluRay.mkv': {'size': 5500, 'quality': '720p'}, 'C:\\movies\QuiQui le fou (collection #123, 1915)\QuiQui le fou (1915) half-sbs 720p x264 BluRay.mkv': {'size': 5500, 'quality': '720p', 'is_3d': True}, + 'Moviename 2014 720p HDCAM XviD DualAudio': {'size': 4000, 'quality': 'cam'}, + 'Moviename (2014) - 720p CAM x264': {'size': 2250, 'quality': 'cam'} } correct = 0 From e27ece512f65a05d98156ce6df9fa205342f0c3f Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 25 Jun 2014 23:08:37 +0200 Subject: [PATCH 083/117] Use release quality, not identifier to match downloaded release --- couchpotato/core/plugins/renamer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 6c6d6b8..9b3e999 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -496,7 +496,7 @@ class Renamer(Plugin): self.tagRelease(group = group, tag = 'exists') # Notify on rename fail - download_message = 'Renaming of %s (%s) cancelled, exists in %s already.' % (media_title, group['meta_data']['quality']['label'], release.get('identifier')) + download_message = 'Renaming of %s (%s) cancelled, exists in %s already.' % (media_title, group['meta_data']['quality']['label'], release.get('quality')) fireEvent('movie.renaming.canceled', message = download_message, data = group) remove_leftovers = False @@ -515,7 +515,7 @@ class Renamer(Plugin): fireEvent('release.update_status', release['_id'], status = 'seeding', single = True) mark_as_recent = True - elif release.get('identifier') == group['meta_data']['quality']['identifier']: + elif release.get('quality') == group['meta_data']['quality']['identifier']: # Set the release to downloaded fireEvent('release.update_status', release['_id'], status = 'downloaded', single = True) group['release_download'] = release_download From 14d3ab93daaad0b56c76827874e7a0f152f64e0b Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 25 Jun 2014 23:22:35 +0200 Subject: [PATCH 084/117] Add mp4 quality brrip --- couchpotato/core/plugins/quality/main.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index 18816c4..bc61afa 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -25,9 +25,9 @@ class QualityPlugin(Plugin): {'identifier': 'bd50', 'hd': True, 'allow_3d': True, 'size': (20000, 60000), 'label': 'BR-Disk', 'alternative': ['bd25', ('br', 'disk')], 'allow': ['1080p'], 'ext':['iso', 'img'], 'tags': ['bdmv', 'certificate', ('complete', 'bluray'), 'avc', 'mvc']}, {'identifier': '1080p', 'hd': True, 'allow_3d': True, 'size': (4000, 20000), 'label': '1080p', 'width': 1920, 'height': 1080, 'alternative': [], 'allow': [], 'ext':['mkv', 'm2ts', 'ts'], 'tags': ['m2ts', 'x264', 'h264']}, {'identifier': '720p', 'hd': True, 'allow_3d': True, 'size': (3000, 10000), 'label': '720p', 'width': 1280, 'height': 720, 'alternative': [], 'allow': [], 'ext':['mkv', 'ts'], 'tags': ['x264', 'h264']}, - {'identifier': 'brrip', 'hd': True, 'allow_3d': True, 'size': (700, 7000), 'label': 'BR-Rip', 'alternative': ['bdrip', ('br', 'rip')], 'allow': ['720p', '1080p'], 'ext':[], 'tags': ['hdtv', 'hdrip', 'webdl', ('web', 'dl')]}, + {'identifier': 'brrip', 'hd': True, 'allow_3d': True, 'size': (700, 7000), 'label': 'BR-Rip', 'alternative': ['bdrip', ('br', 'rip')], 'allow': ['720p', '1080p'], 'ext':['mp4', 'avi'], 'tags': ['hdtv', 'hdrip', 'webdl', ('web', 'dl')]}, {'identifier': 'dvdr', 'size': (3000, 10000), 'label': 'DVD-R', 'alternative': ['br2dvd', ('dvd', 'r')], 'allow': [], 'ext':['iso', 'img', 'vob'], 'tags': ['pal', 'ntsc', 'video_ts', 'audio_ts', ('dvd', 'r'), 'dvd9']}, - {'identifier': 'dvdrip', 'size': (600, 2400), 'label': 'DVD-Rip', 'width': 720, 'alternative': [('dvd', 'rip')], 'allow': [], 'ext':[], 'tags': [('dvd', 'rip'), ('dvd', 'xvid'), ('dvd', 'divx')]}, + {'identifier': 'dvdrip', 'size': (600, 2400), 'label': 'DVD-Rip', 'width': 720, 'alternative': [('dvd', 'rip')], 'allow': [], 'ext':['avi'], 'tags': [('dvd', 'rip'), ('dvd', 'xvid'), ('dvd', 'divx')]}, {'identifier': 'scr', 'size': (600, 1600), 'label': 'Screener', 'alternative': ['screener', 'dvdscr', 'ppvrip', 'dvdscreener', 'hdscr'], 'allow': ['dvdr', 'dvdrip', '720p', '1080p'], 'ext':[], 'tags': ['webrip', ('web', 'rip')]}, {'identifier': 'r5', 'size': (600, 1000), 'label': 'R5', 'alternative': ['r6'], 'allow': ['dvdr'], 'ext':[]}, {'identifier': 'tc', 'size': (600, 1000), 'label': 'TeleCine', 'alternative': ['telecine'], 'allow': [], 'ext':[]}, @@ -452,7 +452,8 @@ class QualityPlugin(Plugin): 'C:\\movies\QuiQui le fou (collection #123, 1915)\QuiQui le fou (1915) 720p x264 BluRay.mkv': {'size': 5500, 'quality': '720p'}, 'C:\\movies\QuiQui le fou (collection #123, 1915)\QuiQui le fou (1915) half-sbs 720p x264 BluRay.mkv': {'size': 5500, 'quality': '720p', 'is_3d': True}, 'Moviename 2014 720p HDCAM XviD DualAudio': {'size': 4000, 'quality': 'cam'}, - 'Moviename (2014) - 720p CAM x264': {'size': 2250, 'quality': 'cam'} + 'Moviename (2014) - 720p CAM x264': {'size': 2250, 'quality': 'cam'}, + 'Movie Name (2014).mp4': {'size': 750, 'quality': 'brrip'}, } correct = 0 From 12e556e1d10eee9ba418d52ac8b9d2b5ae968d57 Mon Sep 17 00:00:00 2001 From: genial123 Date: Sat, 28 Jun 2014 08:19:05 +0200 Subject: [PATCH 085/117] Finish non-existent API calls instead of timing out --- couchpotato/api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/couchpotato/api.py b/couchpotato/api.py index 99a2c6a..b21cfeb 100644 --- a/couchpotato/api.py +++ b/couchpotato/api.py @@ -89,6 +89,7 @@ class ApiHandler(RequestHandler): route = route.strip('/') if not api.get(route): self.write('API call doesn\'t seem to exist') + self.finish() return # Create lock if it doesn't exist From 59e248d7deae3de8e34e234e6616c63c60d480d8 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 28 Jun 2014 22:57:42 +0200 Subject: [PATCH 086/117] Wrong argument split. fix #3518 --- couchpotato/core/media/_base/media/main.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 2178ea1..1e10582 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -229,6 +229,7 @@ class MediaPlugin(MediaBase): # Add search filters if starts_with: + print starts_with starts_with = toUnicode(starts_with.lower())[0] starts_with = starts_with if starts_with in ascii_lowercase else '#' filter_by['starts_with'] = [x['_id'] for x in db.get_many('media_startswith', starts_with)] @@ -292,8 +293,8 @@ class MediaPlugin(MediaBase): release_status = splitString(kwargs.get('release_status')), status_or = kwargs.get('status_or') is not None, limit_offset = kwargs.get('limit_offset'), - with_tags = kwargs.get('with_tags'), - starts_with = splitString(kwargs.get('starts_with')), + with_tags = splitString(kwargs.get('with_tags')), + starts_with = kwargs.get('starts_with'), search = kwargs.get('search') ) From d92de8ec4ec12886e378f6f20b28d504177a67ff Mon Sep 17 00:00:00 2001 From: mano3m Date: Sat, 28 Jun 2014 23:43:16 +0200 Subject: [PATCH 087/117] Fix torrentshack --- couchpotato/core/media/_base/providers/torrent/torrentshack.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/media/_base/providers/torrent/torrentshack.py b/couchpotato/core/media/_base/providers/torrent/torrentshack.py index 0cfa04d..1af7e55 100644 --- a/couchpotato/core/media/_base/providers/torrent/torrentshack.py +++ b/couchpotato/core/media/_base/providers/torrent/torrentshack.py @@ -48,9 +48,9 @@ class Base(TorrentProvider): 'name': six.text_type(link.span.string).translate({ord(six.u('\xad')): None}), 'url': self.urls['download'] % url['href'], 'detail_url': self.urls['download'] % link['href'], - 'size': self.parseSize(result.find_all('td')[4].string), - 'seeders': tryInt(result.find_all('td')[6].string), - 'leechers': tryInt(result.find_all('td')[7].string), + 'size': self.parseSize(result.find_all('td')[5].string), + 'seeders': tryInt(result.find_all('td')[7].string), + 'leechers': tryInt(result.find_all('td')[8].string), }) except: From dbf7feca3ef705c055fe4cc06e7b98e7451366a3 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 28 Jun 2014 23:46:28 +0200 Subject: [PATCH 088/117] Properly delete from manage --- couchpotato/core/media/_base/media/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 1e10582..1d3e153 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -229,7 +229,6 @@ class MediaPlugin(MediaBase): # Add search filters if starts_with: - print starts_with starts_with = toUnicode(starts_with.lower())[0] starts_with = starts_with if starts_with in ascii_lowercase else '#' filter_by['starts_with'] = [x['_id'] for x in db.get_many('media_startswith', starts_with)] @@ -412,7 +411,7 @@ class MediaPlugin(MediaBase): total_deleted += 1 new_media_status = 'done' elif delete_from == 'manage': - if release.get('status') == 'done': + if release.get('status') == 'done' or media.get('status') == 'done': db.delete(release) total_deleted += 1 @@ -477,6 +476,9 @@ class MediaPlugin(MediaBase): # Check if we are finished with the media if fireEvent('quality.isfinish', {'identifier': release['quality'], 'is_3d': release.get('is_3d', False)}, profile, timedelta(seconds = time.time() - release['last_edit']).days, single = True): m['status'] = 'done' + elif previous_status == 'done': + m['status'] = 'done' + except RecordNotFound: log.debug('Failed restatus, keeping previous: %s', traceback.format_exc()) m['status'] = previous_status From 1c0178dbaf1d054eb6b9814e1e812ebf2fecc281 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 28 Jun 2014 23:54:52 +0200 Subject: [PATCH 089/117] Fix 'ignore' mis-tagging --- couchpotato/core/plugins/release/main.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index b92816c..196892c 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -79,6 +79,13 @@ class Release(Plugin): try: db.get('id', release.get('key')) media_exist.append(release.get('key')) + + try: + if release['doc'].get('status') == 'ignore': + release['doc']['status'] = 'ignored' + db.update(release['doc']) + except: + log.error('Failed fixing mis-status tag: %s', traceback.format_exc()) except RecordDeleted: db.delete(release['doc']) log.debug('Deleted orphaned release: %s', release['doc']) From 7afc524a9fa48d49f15eb9e1bf2950dc208ab784 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 28 Jun 2014 23:58:02 +0200 Subject: [PATCH 090/117] Freespace Windows not working. fix #3535 --- couchpotato/core/helpers/variable.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/couchpotato/core/helpers/variable.py b/couchpotato/core/helpers/variable.py index 5d9f1ad..fc844aa 100644 --- a/couchpotato/core/helpers/variable.py +++ b/couchpotato/core/helpers/variable.py @@ -370,8 +370,7 @@ def getFreeSpace(directories): ret = fun(folder, ctypes.byref(_), ctypes.byref(total), ctypes.byref(free)) if ret == 0: raise ctypes.WinError() - used = total.value - free.value - return [total.value, used, free.value] + return [total.value, free.value] else: s = os.statvfs(folder) size = [s.f_blocks * s.f_frsize / (1024 * 1024), (s.f_bavail * s.f_frsize) / (1024 * 1024)] From 61a9037835b3749e366c852e3bb7a1b6014634a1 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 29 Jun 2014 09:49:48 +0200 Subject: [PATCH 091/117] Don't error out if XBMC is turned off. fix #3515 --- couchpotato/core/notifications/xbmc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/notifications/xbmc.py b/couchpotato/core/notifications/xbmc.py index 8dbf936..eb0b699 100644 --- a/couchpotato/core/notifications/xbmc.py +++ b/couchpotato/core/notifications/xbmc.py @@ -8,7 +8,7 @@ from couchpotato.core.helpers.variable import splitString, getTitle from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification import requests -from requests.packages.urllib3.exceptions import MaxRetryError +from requests.packages.urllib3.exceptions import MaxRetryError, ConnectionError log = CPLog(__name__) @@ -172,7 +172,7 @@ class XBMC(Notification): # manually fake expected response array return [{'result': 'Error'}] - except (MaxRetryError, requests.exceptions.Timeout): + except (MaxRetryError, requests.exceptions.Timeout, ConnectionError): log.info2('Couldn\'t send request to XBMC, assuming it\'s turned off') return [{'result': 'Error'}] except: From c45c04659f760f580d5a488cb0a9bf3e2e67d99f Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 29 Jun 2014 10:24:19 +0200 Subject: [PATCH 092/117] Use html parser for hdtrailers --- couchpotato/core/media/movie/providers/trailer/hdtrailers.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/media/movie/providers/trailer/hdtrailers.py b/couchpotato/core/media/movie/providers/trailer/hdtrailers.py index 7942533..828f017 100644 --- a/couchpotato/core/media/movie/providers/trailer/hdtrailers.py +++ b/couchpotato/core/media/movie/providers/trailer/hdtrailers.py @@ -21,6 +21,7 @@ class HDTrailers(TrailerProvider): 'backup': 'http://www.hd-trailers.net/blog/', } providers = ['apple.ico', 'yahoo.ico', 'moviefone.ico', 'myspace.ico', 'favicon.ico'] + only_tables_tags = SoupStrainer('table') def search(self, group): @@ -67,8 +68,7 @@ class HDTrailers(TrailerProvider): return results try: - tables = SoupStrainer('div') - html = BeautifulSoup(data, parse_only = tables) + html = BeautifulSoup(data, 'html.parser', parse_only = self.only_tables_tags) result_table = html.find_all('h2', text = re.compile(movie_name)) for h2 in result_table: @@ -90,8 +90,7 @@ class HDTrailers(TrailerProvider): results = {'480p':[], '720p':[], '1080p':[]} try: - tables = SoupStrainer('table') - html = BeautifulSoup(data, parse_only = tables) + html = BeautifulSoup(data, 'html.parser', parse_only = self.only_tables_tags) result_table = html.find('table', attrs = {'class':'bottomTable'}) for tr in result_table.find_all('tr'): From 4cbc089de26d3049a23d1866f23ad1b9eed661c6 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 29 Jun 2014 10:51:33 +0200 Subject: [PATCH 093/117] Log subfolder errors in renamer --- couchpotato/core/plugins/renamer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 9b3e999..481c9dd 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -136,7 +136,7 @@ class Renamer(Plugin): else: for item in no_process: if isSubFolder(item, base_folder): - log.error('To protect your data, the media libraries can\'t be inside of or the same as the "from" folder.') + log.error('To protect your data, the media libraries can\'t be inside of or the same as the "from" folder. "%s" in "%s"', (item, base_folder)) return # Check to see if the no_process folders are inside the provided media_folder @@ -168,7 +168,7 @@ class Renamer(Plugin): if media_folder: for item in no_process: if isSubFolder(item, media_folder): - log.error('To protect your data, the media libraries can\'t be inside of or the same as the provided media folder.') + log.error('To protect your data, the media libraries can\'t be inside of or the same as the provided media folder. "%s" in "%s"', (item, media_folder)) return # Make sure a checkSnatched marked all downloads/seeds as such From f6030a333a17e027607b69ddb42d10d1ae2d04cf Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 29 Jun 2014 23:15:36 +0200 Subject: [PATCH 094/117] Don't remove pyc files when using desktop updater --- couchpotato/core/_base/updater/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/_base/updater/main.py b/couchpotato/core/_base/updater/main.py index 9f6613a..7730d3b 100644 --- a/couchpotato/core/_base/updater/main.py +++ b/couchpotato/core/_base/updater/main.py @@ -143,7 +143,7 @@ class Updater(Plugin): } def doShutdown(self, *args, **kwargs): - if not Env.get('dev'): + if not Env.get('dev') and not Env.get('desktop'): removePyc(Env.get('app_dir'), show_logs = False) return super(Updater, self).doShutdown(*args, **kwargs) From d20c0ee37ea306a2a27c09d1bf3d5e8daa5f1cc8 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 29 Jun 2014 23:34:48 +0200 Subject: [PATCH 095/117] Remove Smackdown from defaults --- couchpotato/core/media/_base/providers/nzb/newznab.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/couchpotato/core/media/_base/providers/nzb/newznab.py b/couchpotato/core/media/_base/providers/nzb/newznab.py index 7db7e86..495463b 100644 --- a/couchpotato/core/media/_base/providers/nzb/newznab.py +++ b/couchpotato/core/media/_base/providers/nzb/newznab.py @@ -220,7 +220,7 @@ config = [{ 'description': 'Enable NewzNab such as NZB.su, \ NZBs.org, DOGnzb.cr, \ Spotweb, NZBGeek, \ - SmackDown, NZBFinder', + NZBFinder', 'wizard': True, 'icon': 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEVjhwD///86aRovd/sBAAAAMklEQVQI12NgAIPQUCCRmQkjssDEShiRuRIqwZqZGcDAGBrqANUhGgIkWAOABKMDxCAA24UK50b26SAAAAAASUVORK5CYII=', 'options': [ @@ -231,30 +231,30 @@ config = [{ }, { 'name': 'use', - 'default': '0,0,0,0,0,0' + 'default': '0,0,0,0,0' }, { 'name': 'host', - 'default': 'api.nzb.su,api.dognzb.cr,nzbs.org,https://index.nzbgeek.info, https://smackdownonyou.com, https://www.nzbfinder.ws', + 'default': 'api.nzb.su,api.dognzb.cr,nzbs.org,https://index.nzbgeek.info,https://www.nzbfinder.ws', 'description': 'The hostname of your newznab provider', }, { 'name': 'extra_score', 'advanced': True, 'label': 'Extra Score', - 'default': '0,0,0,0,0,0', + 'default': '0,0,0,0,0', 'description': 'Starting score for each release found via this provider.', }, { 'name': 'custom_tag', 'advanced': True, 'label': 'Custom tag', - 'default': ',,,,,', + 'default': ',,,,', 'description': 'Add custom tags, for example add rls=1 to get only scene releases from nzbs.org', }, { 'name': 'api_key', - 'default': ',,,,,', + 'default': ',,,,', 'label': 'Api Key', 'description': 'Can be found on your profile page', 'type': 'combined', From 099b72ed2759f664937e6c15584752f3375ead33 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 30 Jun 2014 16:28:45 +0200 Subject: [PATCH 096/117] Allow 720p in lower qualities. fix #3539 --- couchpotato/core/plugins/quality/main.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index bc61afa..2687cb1 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -29,9 +29,9 @@ class QualityPlugin(Plugin): {'identifier': 'dvdr', 'size': (3000, 10000), 'label': 'DVD-R', 'alternative': ['br2dvd', ('dvd', 'r')], 'allow': [], 'ext':['iso', 'img', 'vob'], 'tags': ['pal', 'ntsc', 'video_ts', 'audio_ts', ('dvd', 'r'), 'dvd9']}, {'identifier': 'dvdrip', 'size': (600, 2400), 'label': 'DVD-Rip', 'width': 720, 'alternative': [('dvd', 'rip')], 'allow': [], 'ext':['avi'], 'tags': [('dvd', 'rip'), ('dvd', 'xvid'), ('dvd', 'divx')]}, {'identifier': 'scr', 'size': (600, 1600), 'label': 'Screener', 'alternative': ['screener', 'dvdscr', 'ppvrip', 'dvdscreener', 'hdscr'], 'allow': ['dvdr', 'dvdrip', '720p', '1080p'], 'ext':[], 'tags': ['webrip', ('web', 'rip')]}, - {'identifier': 'r5', 'size': (600, 1000), 'label': 'R5', 'alternative': ['r6'], 'allow': ['dvdr'], 'ext':[]}, - {'identifier': 'tc', 'size': (600, 1000), 'label': 'TeleCine', 'alternative': ['telecine'], 'allow': [], 'ext':[]}, - {'identifier': 'ts', 'size': (600, 1000), 'label': 'TeleSync', 'alternative': ['telesync', 'hdts'], 'allow': [], 'ext':[]}, + {'identifier': 'r5', 'size': (600, 1000), 'label': 'R5', 'alternative': ['r6'], 'allow': ['dvdr', '720p'], 'ext':[]}, + {'identifier': 'tc', 'size': (600, 1000), 'label': 'TeleCine', 'alternative': ['telecine'], 'allow': ['720p'], 'ext':[]}, + {'identifier': 'ts', 'size': (600, 1000), 'label': 'TeleSync', 'alternative': ['telesync', 'hdts'], 'allow': ['720p'], 'ext':[]}, {'identifier': 'cam', 'size': (600, 1000), 'label': 'Cam', 'alternative': ['camrip', 'hdcam'], 'allow': ['720p'], 'ext':[]} ] pre_releases = ['cam', 'ts', 'tc', 'r5', 'scr'] @@ -454,6 +454,9 @@ class QualityPlugin(Plugin): 'Moviename 2014 720p HDCAM XviD DualAudio': {'size': 4000, 'quality': 'cam'}, 'Moviename (2014) - 720p CAM x264': {'size': 2250, 'quality': 'cam'}, 'Movie Name (2014).mp4': {'size': 750, 'quality': 'brrip'}, + 'Moviename.2014.720p.R6.WEB-DL.x264.AC3-xyz': {'size': 750, 'quality': 'r5'}, + 'Movie name 2014 New Source 720p HDCAM x264 AC3 xyz': {'size': 750, 'quality': 'cam'}, + 'Movie.Name.2014.720p.HD.TS.AC3.x264': {'size': 750, 'quality': 'ts'} } correct = 0 From 265f90fe6941bf0b7aa31b3a4e2e03adc4811e6c Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 30 Jun 2014 21:36:32 +0200 Subject: [PATCH 097/117] Unrar cleanup --- libs/unrar2/unix.py | 8 +++++--- libs/unrar2/windows.py | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/libs/unrar2/unix.py b/libs/unrar2/unix.py index 9ebab40..a37b6df 100644 --- a/libs/unrar2/unix.py +++ b/libs/unrar2/unix.py @@ -24,12 +24,14 @@ import subprocess import gc - -import os, os.path -import time, re +import os +import os.path +import time +import re from rar_exceptions import * + class UnpackerNotInstalled(Exception): pass rar_executable_cached = None diff --git a/libs/unrar2/windows.py b/libs/unrar2/windows.py index e249f8f..bf8ffa5 100644 --- a/libs/unrar2/windows.py +++ b/libs/unrar2/windows.py @@ -174,7 +174,7 @@ class PassiveReader: def __init__(self, usercallback = None): self.buf = [] self.ucb = usercallback - + def _callback(self, msg, UserData, P1, P2): if msg == UCM_PROCESSDATA: data = (ctypes.c_char*P2).from_address(P1).raw @@ -183,7 +183,7 @@ class PassiveReader: else: self.buf.append(data) return 1 - + def get_result(self): return ''.join(self.buf) @@ -197,10 +197,10 @@ class RarInfoIterator(object): raise IncorrectRARPassword self.arc.lockStatus = "locked" self.arc.needskip = False - + def __iter__(self): return self - + def next(self): if self.index>0: if self.arc.needskip: @@ -208,9 +208,9 @@ class RarInfoIterator(object): self.res = RARReadHeaderEx(self.arc._handle, ctypes.byref(self.headerData)) if self.res: - raise StopIteration + raise StopIteration self.arc.needskip = True - + data = {} data['index'] = self.index data['filename'] = self.headerData.FileName @@ -224,7 +224,7 @@ class RarInfoIterator(object): self.index += 1 return data - + def __del__(self): self.arc.lockStatus = "finished" @@ -254,9 +254,9 @@ class RarFileImplementation(object): if password: RARSetPassword(self._handle, password) - + self.lockStatus = "ready" - + def destruct(self): @@ -287,7 +287,7 @@ class RarFileImplementation(object): self.needskip = False res.append((info, reader.get_result())) return res - + def extract(self, checker, path, withSubpath, overwrite): res = [] @@ -300,7 +300,7 @@ class RarFileImplementation(object): fn = os.path.split(fn)[-1] target = os.path.join(path, fn) else: - raise DeprecationWarning, "Condition callbacks returning strings are deprecated and only supported in Windows" + raise DeprecationWarning, "Condition callbacks returning strings are deprecated and only supported in Windows" target = checkres if overwrite or (not os.path.exists(target)): tmpres = RARProcessFile(self._handle, RAR_EXTRACT, None, target) From 33ad4c22c7f8edc8062c13731da2bfc6a0644e6d Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 30 Jun 2014 21:58:19 +0200 Subject: [PATCH 098/117] Try make unrar executable for user --- libs/unrar2/unix.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libs/unrar2/unix.py b/libs/unrar2/unix.py index a37b6df..ce2d6a7 100644 --- a/libs/unrar2/unix.py +++ b/libs/unrar2/unix.py @@ -21,7 +21,8 @@ # SOFTWARE. # Unix version uses unrar command line executable - +import platform +import stat import subprocess import gc import os @@ -37,11 +38,19 @@ class UnpackerNotInstalled(Exception): pass rar_executable_cached = None rar_executable_version = None +osx_unrar = os.path.join(os.path.dirname(__file__), 'unrar') +if os.path.isfile(osx_unrar) and 'darwin' in platform.platform().lower(): + try: + st = os.stat(osx_unrar) + os.chmod(osx_unrar, st.st_mode | stat.S_IEXEC) + except: + pass + def call_unrar(params): "Calls rar/unrar command line executable, returns stdout pipe" global rar_executable_cached if rar_executable_cached is None: - for command in ('unrar', 'rar', os.path.join(os.path.dirname(__file__), 'unrar')): + for command in ('unrar', 'rar', osx_unrar): try: subprocess.Popen([command], stdout = subprocess.PIPE) rar_executable_cached = command From 169ddeef5df2eb898ea2496fb9240f0cbb70d6fb Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 30 Jun 2014 22:38:18 +0200 Subject: [PATCH 099/117] Allow custom unrar path. fix #3460 --- couchpotato/core/plugins/renamer.py | 7 ++++++- libs/unrar2/__init__.py | 28 ++++++++++++++-------------- libs/unrar2/unix.py | 11 ++++++----- libs/unrar2/windows.py | 2 +- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 481c9dd..46cd677 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -1140,7 +1140,7 @@ Remove it if you want it to be renamed (again, or at least let it try again) log.info('Archive %s found. Extracting...', os.path.basename(archive['file'])) try: - rar_handle = RarFile(archive['file']) + rar_handle = RarFile(archive['file'], custom_path = self.conf('unrar_path')) extr_path = os.path.join(from_folder, os.path.relpath(os.path.dirname(archive['file']), folder)) self.makeDir(extr_path) for packedinfo in rar_handle.infolist(): @@ -1283,6 +1283,11 @@ config = [{ 'default': False, }, { + 'advanced': True, + 'name': 'unrar_path', + 'description': 'Custom path to unrar bin', + }, + { 'name': 'cleanup', 'type': 'bool', 'description': 'Cleanup leftover files after successful rename.', diff --git a/libs/unrar2/__init__.py b/libs/unrar2/__init__.py index fe27cfe..41b0d71 100644 --- a/libs/unrar2/__init__.py +++ b/libs/unrar2/__init__.py @@ -21,7 +21,7 @@ # SOFTWARE. """ -pyUnRAR2 is a ctypes based wrapper around the free UnRAR.dll. +pyUnRAR2 is a ctypes based wrapper around the free UnRAR.dll. It is an modified version of Jimmy Retzlaff's pyUnRAR - more simple, stable and foolproof. @@ -45,8 +45,8 @@ if in_windows: from windows import RarFileImplementation else: from unix import RarFileImplementation - - + + import fnmatch, time, weakref class RarInfo(object): @@ -62,7 +62,7 @@ class RarInfo(object): isdir - True if the file is a directory size - size in bytes of the uncompressed file comment - comment associated with the file - + Note - this is not currently intended to be a Python file-like object. """ @@ -74,7 +74,7 @@ class RarInfo(object): self.size = data['size'] self.datetime = data['datetime'] self.comment = data['comment'] - + def __str__(self): @@ -86,7 +86,7 @@ class RarInfo(object): class RarFile(RarFileImplementation): - def __init__(self, archiveName, password=None): + def __init__(self, archiveName, password=None, custom_path = None): """Instantiate the archive. archiveName is the name of the RAR file. @@ -99,7 +99,7 @@ class RarFile(RarFileImplementation): This is a test. """ self.archiveName = archiveName - RarFileImplementation.init(self, password) + RarFileImplementation.init(self, password, custom_path) def __del__(self): self.destruct() @@ -130,31 +130,31 @@ class RarFile(RarFileImplementation): """Read specific files from archive into memory. If "condition" is a list of numbers, then return files which have those positions in infolist. If "condition" is a string, then it is treated as a wildcard for names of files to extract. - If "condition" is a function, it is treated as a callback function, which accepts a RarInfo object + If "condition" is a function, it is treated as a callback function, which accepts a RarInfo object and returns boolean True (extract) or False (skip). If "condition" is omitted, all files are returned. - + Returns list of tuples (RarInfo info, str contents) """ checker = condition2checker(condition) return RarFileImplementation.read_files(self, checker) - + def extract(self, condition='*', path='.', withSubpath=True, overwrite=True): """Extract specific files from archive to disk. - + If "condition" is a list of numbers, then extract files which have those positions in infolist. If "condition" is a string, then it is treated as a wildcard for names of files to extract. If "condition" is a function, it is treated as a callback function, which accepts a RarInfo object and returns either boolean True (extract) or boolean False (skip). - DEPRECATED: If "condition" callback returns string (only supported for Windows) - + DEPRECATED: If "condition" callback returns string (only supported for Windows) - that string will be used as a new name to save the file under. If "condition" is omitted, all files are extracted. - + "path" is a directory to extract to "withSubpath" flag denotes whether files are extracted with their full path in the archive. "overwrite" flag denotes whether extracted files will overwrite old ones. Defaults to true. - + Returns list of RarInfos for extracted files.""" checker = condition2checker(condition) return RarFileImplementation.extract(self, checker, path, withSubpath, overwrite) diff --git a/libs/unrar2/unix.py b/libs/unrar2/unix.py index ce2d6a7..91ed4b6 100644 --- a/libs/unrar2/unix.py +++ b/libs/unrar2/unix.py @@ -46,11 +46,12 @@ if os.path.isfile(osx_unrar) and 'darwin' in platform.platform().lower(): except: pass -def call_unrar(params): +def call_unrar(params, custom_path = None): "Calls rar/unrar command line executable, returns stdout pipe" global rar_executable_cached if rar_executable_cached is None: - for command in ('unrar', 'rar', osx_unrar): + for command in (custom_path, 'unrar', 'rar', osx_unrar): + if not command: continue try: subprocess.Popen([command], stdout = subprocess.PIPE) rar_executable_cached = command @@ -70,10 +71,10 @@ def call_unrar(params): class RarFileImplementation(object): - def init(self, password = None): + def init(self, password = None, custom_path = None): global rar_executable_version self.password = password - + self.custom_path = custom_path stdoutdata, stderrdata = self.call('v', []).communicate() @@ -129,7 +130,7 @@ class RarFileImplementation(object): def call(self, cmd, options = [], files = []): options2 = options + ['p' + self.escaped_password()] soptions = ['-' + x for x in options2] - return call_unrar([cmd] + soptions + ['--', self.archiveName] + files) + return call_unrar([cmd] + soptions + ['--', self.archiveName] + files, self.custom_path) def infoiter(self): diff --git a/libs/unrar2/windows.py b/libs/unrar2/windows.py index bf8ffa5..e3d920f 100644 --- a/libs/unrar2/windows.py +++ b/libs/unrar2/windows.py @@ -237,7 +237,7 @@ def generate_password_provider(password): class RarFileImplementation(object): - def init(self, password=None): + def init(self, password=None, custom_path = None): self.password = password archiveData = RAROpenArchiveDataEx(ArcNameW=self.archiveName, OpenMode=RAR_OM_EXTRACT) self._handle = RAROpenArchiveEx(ctypes.byref(archiveData)) From 34320e617d7c908c3c9f1bad0387ca40f7596865 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 30 Jun 2014 22:47:41 +0200 Subject: [PATCH 100/117] Unrar extract time options. closes #2733 --- couchpotato/core/plugins/renamer.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 46cd677..ef56309 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -1144,10 +1144,16 @@ Remove it if you want it to be renamed (again, or at least let it try again) extr_path = os.path.join(from_folder, os.path.relpath(os.path.dirname(archive['file']), folder)) self.makeDir(extr_path) for packedinfo in rar_handle.infolist(): - if not packedinfo.isdir and not os.path.isfile(sp(os.path.join(extr_path, os.path.basename(packedinfo.filename)))): + extr_file_path = sp(os.path.join(extr_path, os.path.basename(packedinfo.filename))) + if not packedinfo.isdir and not os.path.isfile(extr_file_path): log.debug('Extracting %s...', packedinfo.filename) rar_handle.extract(condition = [packedinfo.index], path = extr_path, withSubpath = False, overwrite = False) - extr_files.append(sp(os.path.join(extr_path, os.path.basename(packedinfo.filename)))) + if self.conf('unrar_modify_date'): + try: + os.utime(extr_file_path, (os.path.getatime(archive['file']), os.path.getmtime(archive['file']))) + except: + log.error('Rar modify date enabled, but failed: %s', traceback.format_exc()) + extr_files.append(extr_file_path) del rar_handle except Exception as e: log.error('Failed to extract %s: %s %s', (archive['file'], e, traceback.format_exc())) @@ -1288,6 +1294,13 @@ config = [{ 'description': 'Custom path to unrar bin', }, { + 'advanced': True, + 'name': 'unrar_modify_date', + 'type': 'bool', + 'description': ('Set modify date of unrar-ed files to the rar-file\'s date.', 'This will allow XBMC to recognize extracted files as recently added even if the movie was released some time ago.'), + 'default': False, + }, + { 'name': 'cleanup', 'type': 'bool', 'description': 'Cleanup leftover files after successful rename.', From f765794c99feaf548db0a77c50883b93e0fd85df Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 1 Jul 2014 21:00:05 +0200 Subject: [PATCH 101/117] Don't add managed to no-process renamer list. fix #3538 --- couchpotato/core/plugins/renamer.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index ef56309..024c438 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -123,11 +123,6 @@ class Renamer(Plugin): no_process = [to_folder] cat_list = fireEvent('category.all', single = True) or [] no_process.extend([item['destination'] for item in cat_list]) - try: - if Env.setting('library', section = 'manage').strip(): - no_process.extend([sp(manage_folder) for manage_folder in splitString(Env.setting('library', section = 'manage'), '::')]) - except: - pass # Check to see if the no_process folders are inside the "from" folder. if not os.path.isdir(base_folder) or not os.path.isdir(to_folder): From d201d9fff9f99e264ac914c2f3b24f7797abb556 Mon Sep 17 00:00:00 2001 From: Ruud Date: Wed, 2 Jul 2014 19:02:55 +0200 Subject: [PATCH 102/117] Allow change of file move action --- couchpotato/core/plugins/renamer.py | 47 +++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 024c438..2bc4787 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -197,14 +197,18 @@ class Renamer(Plugin): db = get_db() # Extend the download info with info stored in the downloaded release + keep_original = self.moveTypeIsLinked() + is_torrent = False if release_download: release_download = self.extendReleaseDownload(release_download) + is_torrent = self.downloadIsTorrent(release_download) + keep_original = True if is_torrent and self.conf('file_action') not in ['move'] else keep_original # Unpack any archives extr_files = None if self.conf('unrar'): folder, media_folder, files, extr_files = self.extractFiles(folder = folder, media_folder = media_folder, files = files, - cleanup = self.conf('cleanup') and not self.downloadIsTorrent(release_download)) + cleanup = self.conf('cleanup') and not keep_original) groups = fireEvent('scanner.scan', folder = folder if folder else base_folder, files = files, release_download = release_download, return_ignored = False, single = True) or [] @@ -321,7 +325,7 @@ class Renamer(Plugin): if file_type is 'nfo' and not self.conf('rename_nfo'): log.debug('Skipping, renaming of %s disabled', file_type) for current_file in group['files'][file_type]: - if self.conf('cleanup') and (not self.downloadIsTorrent(release_download) or self.fileIsAdded(current_file, group)): + if self.conf('cleanup') and (not keep_original or self.fileIsAdded(current_file, group)): remove_files.append(current_file) continue @@ -527,7 +531,7 @@ class Renamer(Plugin): log.debug('Removing leftover files') for current_file in group['files']['leftover']: if self.conf('cleanup') and not self.conf('move_leftover') and \ - (not self.downloadIsTorrent(release_download) or self.fileIsAdded(current_file, group)): + (not keep_original or self.fileIsAdded(current_file, group)): remove_files.append(current_file) # Remove files @@ -574,7 +578,7 @@ class Renamer(Plugin): self.makeDir(os.path.dirname(dst)) try: - self.moveFile(src, dst, forcemove = not self.downloadIsTorrent(release_download) or self.fileIsAdded(src, group)) + self.moveFile(src, dst, use_default = not is_torrent or self.fileIsAdded(src, group)) group['renamed_files'].append(dst) except: log.error('Failed renaming the file "%s" : %s', (os.path.basename(src), traceback.format_exc())) @@ -590,7 +594,7 @@ class Renamer(Plugin): self.untagRelease(group = group, tag = 'failed_rename') # Tag folder if it is in the 'from' folder and it will not be removed because it is a torrent - if self.movieInFromFolder(media_folder) and self.downloadIsTorrent(release_download): + if self.movieInFromFolder(media_folder) and keep_original: self.tagRelease(group = group, tag = 'renamed_already') # Remove matching releases @@ -601,7 +605,7 @@ class Renamer(Plugin): except: log.error('Failed removing %s: %s', (release, traceback.format_exc())) - if group['dirname'] and group['parentdir'] and not self.downloadIsTorrent(release_download): + if group['dirname'] and group['parentdir'] and not keep_original: if media_folder: # Delete the movie folder group_folder = media_folder @@ -763,10 +767,15 @@ Remove it if you want it to be renamed (again, or at least let it try again) return False - def moveFile(self, old, dest, forcemove = False): + def moveFile(self, old, dest, use_default = False): dest = sp(dest) try: - if forcemove or self.conf('file_action') not in ['copy', 'link']: + + move_type = self.conf('file_action') + if use_default: + move_type = self.conf('default_file_action') + + if move_type not in ['copy', 'link']: try: shutil.move(old, dest) except: @@ -775,16 +784,16 @@ Remove it if you want it to be renamed (again, or at least let it try again) os.unlink(old) else: raise - elif self.conf('file_action') == 'copy': + elif move_type == 'copy': shutil.copy(old, dest) - elif self.conf('file_action') == 'link': + else: # First try to hardlink try: log.debug('Hardlinking file "%s" to "%s"...', (old, dest)) link(old, dest) except: # Try to simlink next - log.debug('Couldn\'t hardlink file "%s" to "%s". Simlinking instead. Error: %s.', (old, dest, traceback.format_exc())) + log.debug('Couldn\'t hardlink file "%s" to "%s". Symlinking instead. Error: %s.', (old, dest, traceback.format_exc())) shutil.copy(old, dest) try: symlink(dest, old + '.link') @@ -1084,6 +1093,9 @@ Remove it if you want it to be renamed (again, or at least let it try again) return False return src in group['before_rename'] + def moveTypeIsLinked(self): + return self.conf('default_file_action') in ['copy', 'link'] + def statusInfoComplete(self, release_download): return release_download.get('id') and release_download.get('downloader') and release_download.get('folder') @@ -1346,13 +1358,22 @@ config = [{ 'description': ('Replace all the spaces with a character.', 'Example: ".", "-" (without quotes). Leave empty to use spaces.'), }, { + 'name': 'default_file_action', + 'label': 'Default File Action', + 'default': 'move', + 'type': 'dropdown', + 'values': [('Link', 'link'), ('Copy', 'copy'), ('Move', 'move')], + 'description': ('Link, Copy or Move after download completed.', + 'Link first tries hard link, then sym link and falls back to Copy.'), + 'advanced': True, + }, + { 'name': 'file_action', 'label': 'Torrent File Action', 'default': 'link', 'type': 'dropdown', 'values': [('Link', 'link'), ('Copy', 'copy'), ('Move', 'move')], - '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.'), + 'description': 'See above. It is prefered to use link when downloading torrents as it will save you space, while still beeing able to seed.', 'advanced': True, }, { From 330e15bbcb56d44766d5bb89ce2905e7841fd22e Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 4 Jul 2014 20:36:48 +0200 Subject: [PATCH 103/117] Snatched not giving enough data to show notification. fix #3564 --- couchpotato/core/notifications/pushover.py | 6 +++--- couchpotato/core/plugins/release/main.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/notifications/pushover.py b/couchpotato/core/notifications/pushover.py index d9ef226..46dc0ad 100644 --- a/couchpotato/core/notifications/pushover.py +++ b/couchpotato/core/notifications/pushover.py @@ -1,7 +1,7 @@ from httplib import HTTPSConnection from couchpotato.core.helpers.encoding import toUnicode, tryUrlencode -from couchpotato.core.helpers.variable import getTitle +from couchpotato.core.helpers.variable import getTitle, getIdentifier from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification @@ -27,9 +27,9 @@ class Pushover(Notification): 'sound': self.conf('sound'), } - if data and data.get('identifier'): + if data and getIdentifier(data): api_data.update({ - 'url': toUnicode('http://www.imdb.com/title/%s/' % data['identifier']), + 'url': toUnicode('http://www.imdb.com/title/%s/' % getIdentifier(data)), 'url_title': toUnicode('%s on IMDb' % getTitle(data)), }) diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 196892c..7b47aa9 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -327,7 +327,7 @@ class Release(Plugin): log_movie = '%s (%s) in %s' % (getTitle(media), media['info']['year'], rls['quality']) snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie) log.info(snatch_message) - fireEvent('%s.snatched' % data['type'], message = snatch_message, data = rls) + fireEvent('%s.snatched' % data['type'], message = snatch_message, data = media) # Mark release as snatched if renamer_enabled: From 40a5ce087b52a7f9b940fed25a08c83aa8c94da4 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 6 Jul 2014 22:19:45 +0200 Subject: [PATCH 104/117] Better label for Pushbullet settings --- couchpotato/core/notifications/pushbullet.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/notifications/pushbullet.py b/couchpotato/core/notifications/pushbullet.py index 361294e..e9d4605 100644 --- a/couchpotato/core/notifications/pushbullet.py +++ b/couchpotato/core/notifications/pushbullet.py @@ -84,7 +84,8 @@ config = [{ }, { 'name': 'api_key', - 'label': 'User API Key' + 'label': 'Access Token', + 'description': 'Can be found on Account Settings', }, { 'name': 'devices', From 04e22b3966977085cd706bbcb9f1806ee2d4d1fc Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 8 Jul 2014 20:09:24 +0200 Subject: [PATCH 105/117] XBMC error > info2 --- couchpotato/core/notifications/xbmc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/notifications/xbmc.py b/couchpotato/core/notifications/xbmc.py index eb0b699..bf5310e 100644 --- a/couchpotato/core/notifications/xbmc.py +++ b/couchpotato/core/notifications/xbmc.py @@ -208,7 +208,7 @@ class XBMC(Notification): log.debug('Returned from request %s: %s', (host, response)) return response - except (MaxRetryError, requests.exceptions.Timeout): + except (MaxRetryError, requests.exceptions.Timeout, ConnectionError): log.info2('Couldn\'t send request to XBMC, assuming it\'s turned off') return [] except: From e0479e79bd7295c549dfc61a70694e8e1e9d30cd Mon Sep 17 00:00:00 2001 From: Ruud Date: Tue, 8 Jul 2014 20:24:18 +0200 Subject: [PATCH 106/117] AwesomeHD not returning proper size. fix #3587 --- couchpotato/core/media/_base/providers/torrent/awesomehd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/media/_base/providers/torrent/awesomehd.py b/couchpotato/core/media/_base/providers/torrent/awesomehd.py index 78c4648..bd9e193 100644 --- a/couchpotato/core/media/_base/providers/torrent/awesomehd.py +++ b/couchpotato/core/media/_base/providers/torrent/awesomehd.py @@ -61,7 +61,7 @@ class Base(TorrentProvider): 'name': re.sub('[^A-Za-z0-9\-_ \(\).]+', '', '%s (%s) %s' % (name, year, torrent_desc)), 'url': self.urls['download'] % (torrent_id, authkey, self.conf('passkey')), 'detail_url': self.urls['detail'] % torrent_id, - 'size': self.parseSize(entry.find('size').get_text()), + 'size': tryInt(entry.find('size').get_text()) / 1048576, 'seeders': tryInt(entry.find('seeders').get_text()), 'leechers': tryInt(entry.find('leechers').get_text()), 'score': torrentscore From 32ce93d2e9bccbaa5768324984d956627694eadd Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 11 Jul 2014 10:30:32 +0200 Subject: [PATCH 107/117] Encode video path --- couchpotato/core/plugins/scanner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/plugins/scanner.py b/couchpotato/core/plugins/scanner.py index 6a4d537..3d39b29 100644 --- a/couchpotato/core/plugins/scanner.py +++ b/couchpotato/core/plugins/scanner.py @@ -553,7 +553,7 @@ class Scanner(Plugin): scan_result = [] for p in paths: if not group['is_dvd']: - video = Video.from_path(toUnicode(p)) + video = Video.from_path(sp(p)) video_result = [(video, video.scan())] scan_result.extend(video_result) From 0b48ad5084fdafa56abbe21dccfedabea8b12b0e Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 11 Jul 2014 16:24:45 +0200 Subject: [PATCH 108/117] Change fanart api url --- couchpotato/core/media/movie/providers/info/fanarttv.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/couchpotato/core/media/movie/providers/info/fanarttv.py b/couchpotato/core/media/movie/providers/info/fanarttv.py index 8bfa92c..fcd3891 100644 --- a/couchpotato/core/media/movie/providers/info/fanarttv.py +++ b/couchpotato/core/media/movie/providers/info/fanarttv.py @@ -14,7 +14,7 @@ autoload = 'FanartTV' class FanartTV(MovieProvider): urls = { - 'api': 'http://api.fanart.tv/webservice/movie/b28b14e9be662e027cfbc7c3dd600405/%s/JSON/all/1/2' + 'api': 'http://webservice.fanart.tv/v3/movies/%s?api_key=b28b14e9be662e027cfbc7c3dd600405' } MAX_EXTRAFANART = 20 @@ -36,9 +36,8 @@ class FanartTV(MovieProvider): fanart_data = self.getJsonData(url) if fanart_data: - name, resource = fanart_data.items()[0] - log.debug('Found images for %s', name) - images = self._parseMovie(resource) + log.debug('Found images for %s', fanart_data.get('name')) + images = self._parseMovie(fanart_data) except: log.error('Failed getting extra art for %s: %s', @@ -95,7 +94,7 @@ class FanartTV(MovieProvider): for image in images: if tryInt(image.get('likes')) > highscore: highscore = tryInt(image.get('likes')) - image_url = image.get('url') + image_url = image.get('url') or image.get('href') return image_url @@ -118,7 +117,9 @@ class FanartTV(MovieProvider): if tryInt(image.get('likes')) > highscore: highscore = tryInt(image.get('likes')) best = image - image_urls.append(best.get('url')) + url = best.get('url') or best.get('href') + if url: + image_urls.append(url) pool.remove(best) return image_urls From 06f49be09007406d1608c04d84ca1cd77df52a7b Mon Sep 17 00:00:00 2001 From: Ruud Date: Fri, 11 Jul 2014 16:47:15 +0200 Subject: [PATCH 109/117] Don't error out on media.get. fix #3611 --- couchpotato/core/media/_base/media/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 1d3e153..e79e3ea 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -4,7 +4,7 @@ import time import traceback from string import ascii_lowercase -from CodernityDB.database import RecordNotFound +from CodernityDB.database import RecordNotFound, RecordDeleted from couchpotato import tryInt, get_db from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, fireEventAsync, addEvent @@ -146,7 +146,7 @@ class MediaPlugin(MediaBase): return media - except RecordNotFound: + except (RecordNotFound, RecordDeleted): log.error('Media with id "%s" not found', media_id) except: raise From b13df16b53bbd35c2b59c35ce2b309de3f63b1f1 Mon Sep 17 00:00:00 2001 From: peerster Date: Sat, 12 Jul 2014 16:29:42 +0200 Subject: [PATCH 110/117] Added systemd specific instructions --- README.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4dbe75b..05e3c8d 100644 --- a/README.md +++ b/README.md @@ -29,17 +29,23 @@ OS X: * Then do `python CouchPotatoServer/CouchPotato.py` * Your browser should open up, but if it doesn't go to `http://localhost:5050/` -Linux (Ubuntu / Debian): +Linux: -* Install [GIT](http://git-scm.com/) with `apt-get install git-core` +* (Ubuntu / Debian) Install [GIT](http://git-scm.com/) with `apt-get install git-core` +* (Fedora / CentOS) Install [GIT](http://git-scm.com/) with `yum install git` * 'cd' to the folder of your choosing. * Run `git clone https://github.com/RuudBurger/CouchPotatoServer.git` * Then do `python CouchPotatoServer/CouchPotato.py` to start -* To run on boot copy the init script `sudo cp CouchPotatoServer/init/ubuntu /etc/init.d/couchpotato` -* Copy the default paths file `sudo cp CouchPotatoServer/init/ubuntu.default /etc/default/couchpotato` -* Change the paths inside the default file `sudo nano /etc/default/couchpotato` -* Make it executable `sudo chmod +x /etc/init.d/couchpotato` -* Add it to defaults `sudo update-rc.d couchpotato defaults` +* (Ubuntu / Debian) To run on boot copy the init script `sudo cp CouchPotatoServer/init/ubuntu /etc/init.d/couchpotato` +* (Ubuntu / Debian) Copy the default paths file `sudo cp CouchPotatoServer/init/ubuntu.default /etc/default/couchpotato` +* (Ubuntu / Debian) Change the paths inside the default file `sudo nano /etc/default/couchpotato` +* (Ubuntu / Debian) Make it executable `sudo chmod +x /etc/init.d/couchpotato` +* (Ubuntu / Debian) Add it to defaults `sudo update-rc.d couchpotato defaults` +Systemd specific: +* To run on boot copy the systemd config `sudo cp CouchPotatoServer/init/couchpotato.fedora.service /etc/systemd/system/couchpotato.service` +* Update the systemd config file with your user and path to CouchPotato.py +* Enable it at boot with `sudo systemctl enable couchpotato` + * Open your browser and go to `http://localhost:5050/` From bd6690b159b3a510757e262bee8dafa7e7824f87 Mon Sep 17 00:00:00 2001 From: peerster Date: Sat, 12 Jul 2014 16:34:41 +0200 Subject: [PATCH 111/117] layout fix --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 05e3c8d..4d5a39e 100644 --- a/README.md +++ b/README.md @@ -41,10 +41,9 @@ Linux: * (Ubuntu / Debian) Change the paths inside the default file `sudo nano /etc/default/couchpotato` * (Ubuntu / Debian) Make it executable `sudo chmod +x /etc/init.d/couchpotato` * (Ubuntu / Debian) Add it to defaults `sudo update-rc.d couchpotato defaults` -Systemd specific: -* To run on boot copy the systemd config `sudo cp CouchPotatoServer/init/couchpotato.fedora.service /etc/systemd/system/couchpotato.service` -* Update the systemd config file with your user and path to CouchPotato.py -* Enable it at boot with `sudo systemctl enable couchpotato` +* (systemd) To run on boot copy the systemd config `sudo cp CouchPotatoServer/init/couchpotato.fedora.service /etc/systemd/system/couchpotato.service` +* (systemd) Update the systemd config file with your user and path to CouchPotato.py +* (systemd) Enable it at boot with `sudo systemctl enable couchpotato` * Open your browser and go to `http://localhost:5050/` From a99d52392fce799075c230bdef4f93af62344976 Mon Sep 17 00:00:00 2001 From: peerster Date: Sat, 12 Jul 2014 16:40:24 +0200 Subject: [PATCH 112/117] Another layout fix --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 4d5a39e..a38c052 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,6 @@ Linux: * (systemd) To run on boot copy the systemd config `sudo cp CouchPotatoServer/init/couchpotato.fedora.service /etc/systemd/system/couchpotato.service` * (systemd) Update the systemd config file with your user and path to CouchPotato.py * (systemd) Enable it at boot with `sudo systemctl enable couchpotato` - * Open your browser and go to `http://localhost:5050/` From 687221f035587ad0339c1bb8c433c94a993f2b98 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sat, 12 Jul 2014 19:38:49 +0200 Subject: [PATCH 113/117] Update last_edit when tagging with recent --- couchpotato/core/media/_base/media/main.py | 7 +++++-- couchpotato/core/media/movie/searcher.py | 2 +- couchpotato/core/plugins/renamer.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index e79e3ea..ee9e6cc 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -488,18 +488,21 @@ class MediaPlugin(MediaBase): db.update(m) # Tag media as recent - self.tag(media_id, 'recent') + self.tag(media_id, 'recent', update_edited = True) return m['status'] except: log.error('Failed restatus: %s', traceback.format_exc()) - def tag(self, media_id, tag): + def tag(self, media_id, tag, update_edited = False): try: db = get_db() m = db.get('id', media_id) + if update_edited: + m['last_edit'] = int(time.time()) + tags = m.get('tags') or [] if tag not in tags: tags.append(tag) diff --git a/couchpotato/core/media/movie/searcher.py b/couchpotato/core/media/movie/searcher.py index 7d92c57..4bd8c8d 100644 --- a/couchpotato/core/media/movie/searcher.py +++ b/couchpotato/core/media/movie/searcher.py @@ -240,7 +240,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): break if total_result_count > 0: - fireEvent('media.tag', movie['_id'], 'recent', single = True) + fireEvent('media.tag', movie['_id'], 'recent', update_edited = True, single = True) if len(too_early_to_search) > 0: log.info2('Too early to search for %s, %s', (too_early_to_search, default_title)) diff --git a/couchpotato/core/plugins/renamer.py b/couchpotato/core/plugins/renamer.py index 2bc4787..9f6792a 100644 --- a/couchpotato/core/plugins/renamer.py +++ b/couchpotato/core/plugins/renamer.py @@ -522,7 +522,7 @@ class Renamer(Plugin): # Mark media for dashboard if mark_as_recent: - fireEvent('media.tag', group['media'].get('_id'), 'recent', single = True) + fireEvent('media.tag', group['media'].get('_id'), 'recent', update_edited = True, single = True) # Remove leftover files if not remove_leftovers: # Don't remove anything From 12cda35494770ae4a3d8b1f4eabf4c5a416f68c7 Mon Sep 17 00:00:00 2001 From: Ruud Date: Thu, 17 Jul 2014 22:24:48 +0200 Subject: [PATCH 114/117] Try fix migration failure from 2.5.1 --- couchpotato/core/database.py | 30 +++++++++++++++++++++++++++++- couchpotato/runner.py | 7 +++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/couchpotato/core/database.py b/couchpotato/core/database.py index c7051f5..47be7f5 100644 --- a/couchpotato/core/database.py +++ b/couchpotato/core/database.py @@ -3,10 +3,11 @@ import os import time import traceback +from CodernityDB.database import RecordNotFound from CodernityDB.index import IndexException, IndexNotFoundException, IndexConflict from couchpotato import CPLog from couchpotato.api import addApiView -from couchpotato.core.event import addEvent, fireEvent +from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.helpers.encoding import toUnicode, sp from couchpotato.core.helpers.variable import getImdb, tryInt @@ -226,6 +227,33 @@ class Database(object): from couchpotato import Env db = self.getDB() + + # Try fix for migration failures on desktop + if Env.get('desktop'): + try: + list(db.all('profile', with_doc = True)) + except RecordNotFound: + + failed_location = '%s_failed' % db.path + old_db = os.path.join(Env.get('data_dir'), 'couchpotato.db.old') + + if not os.path.isdir(failed_location) and os.path.isfile(old_db): + db.close() + + # Rename database folder + os.rename(db.path, '%s_failed' % db.path) + + # Rename .old database to try another migrate + os.rename(old_db, old_db[:-4]) + + fireEventAsync('app.restart') + else: + log.error('Migration failed and couldn\'t recover database. Please report on GitHub, with this message.') + db.reindex() + + return + + # Check size and compact if needed size = db.get_db_details().get('size') prop_name = 'last_db_compact' last_check = int(Env.prop(prop_name, default = 0)) diff --git a/couchpotato/runner.py b/couchpotato/runner.py index e5f9bca..5d3f62b 100644 --- a/couchpotato/runner.py +++ b/couchpotato/runner.py @@ -87,6 +87,13 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En # Do db stuff db_path = sp(os.path.join(data_dir, 'database')) + old_db_path = os.path.join(data_dir, 'couchpotato.db') + + # Remove database folder if both exists + if os.path.isdir(db_path) and os.path.isfile(old_db_path): + db = SuperThreadSafeDatabase(db_path) + db.open() + db.destroy() # Check if database exists db = SuperThreadSafeDatabase(db_path) From 324920cd8c6f080f391a99610c19d863072a190b Mon Sep 17 00:00:00 2001 From: Ruud Date: Thu, 17 Jul 2014 23:09:26 +0200 Subject: [PATCH 115/117] Don't migrate when db is closed --- couchpotato/core/database.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/couchpotato/core/database.py b/couchpotato/core/database.py index 47be7f5..10ae26c 100644 --- a/couchpotato/core/database.py +++ b/couchpotato/core/database.py @@ -238,6 +238,7 @@ class Database(object): old_db = os.path.join(Env.get('data_dir'), 'couchpotato.db.old') if not os.path.isdir(failed_location) and os.path.isfile(old_db): + log.error('Corrupt database, trying migrate again') db.close() # Rename database folder @@ -331,6 +332,8 @@ class Database(object): log.info('Getting data took %s', time.time() - migrate_start) db = self.getDB() + if not db.opened: + return # Use properties properties = migrate_data['properties'] From cd0afd20e56571ab82f927e8dd5ba68e169a106e Mon Sep 17 00:00:00 2001 From: Ruud Date: Thu, 17 Jul 2014 23:58:51 +0200 Subject: [PATCH 116/117] Always reconnect Transmission. fix #3631 --- couchpotato/core/downloaders/transmission.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/couchpotato/core/downloaders/transmission.py b/couchpotato/core/downloaders/transmission.py index d941cca..53ca9b8 100644 --- a/couchpotato/core/downloaders/transmission.py +++ b/couchpotato/core/downloaders/transmission.py @@ -23,17 +23,14 @@ class Transmission(DownloaderBase): log = CPLog(__name__) trpc = None - def connect(self, reconnect = False): + def connect(self): # Load host from config and split out port. host = cleanHost(self.conf('host'), protocol = False).split(':') if not isInt(host[1]): log.error('Config properties are not filled in correctly, port is missing.') return False - if not self.trpc or reconnect: - self.trpc = TransmissionRPC(host[0], port = host[1], rpc_url = self.conf('rpc_url').strip('/ '), username = self.conf('username'), password = self.conf('password')) - - return self.trpc + self.trpc = TransmissionRPC(host[0], port = host[1], rpc_url = self.conf('rpc_url').strip('/ '), username = self.conf('username'), password = self.conf('password')) def download(self, data = None, media = None, filedata = None): if not media: media = {} @@ -88,7 +85,7 @@ class Transmission(DownloaderBase): return self.downloadReturnId(remote_torrent['torrent-added']['hashString']) def test(self): - if self.connect(True) and self.trpc.get_session(): + if self.connect() and self.trpc.get_session(): return True return False From 0771aeac3bbeebe9af58db7cd04504bb0ad6e310 Mon Sep 17 00:00:00 2001 From: Ruud Date: Sun, 20 Jul 2014 16:20:12 +0200 Subject: [PATCH 117/117] Update nzbgeek api url --- couchpotato/core/media/_base/providers/nzb/newznab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/couchpotato/core/media/_base/providers/nzb/newznab.py b/couchpotato/core/media/_base/providers/nzb/newznab.py index 495463b..b1a8ec6 100644 --- a/couchpotato/core/media/_base/providers/nzb/newznab.py +++ b/couchpotato/core/media/_base/providers/nzb/newznab.py @@ -235,7 +235,7 @@ config = [{ }, { 'name': 'host', - 'default': 'api.nzb.su,api.dognzb.cr,nzbs.org,https://index.nzbgeek.info,https://www.nzbfinder.ws', + 'default': 'api.nzb.su,api.dognzb.cr,nzbs.org,https://api.nzbgeek.info,https://www.nzbfinder.ws', 'description': 'The hostname of your newznab provider', }, {