diff --git a/couchpotato/core/media/__init__.py b/couchpotato/core/media/__init__.py index 2d339e5a..8187f98a 100644 --- a/couchpotato/core/media/__init__.py +++ b/couchpotato/core/media/__init__.py @@ -2,16 +2,13 @@ from couchpotato.core.event import addEvent from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin -log = CPLog(__name__) - class MediaBase(Plugin): - identifier = None - - def __init__(self): + _type = None + def initType(self): addEvent('media.types', self.getType) def getType(self): - return self.identifier + return self._type diff --git a/couchpotato/core/media/_base/searcher/base.py b/couchpotato/core/media/_base/searcher/base.py new file mode 100644 index 00000000..ab294397 --- /dev/null +++ b/couchpotato/core/media/_base/searcher/base.py @@ -0,0 +1,51 @@ +from couchpotato.api import addApiView +from couchpotato.core.event import addEvent, fireEvent +from couchpotato.core.logger import CPLog +from couchpotato.core.plugins.base import Plugin + +log = CPLog(__name__) + + +class SearcherBase(Plugin): + + in_progress = False + + def __init__(self): + super(SearcherBase, self).__init__() + + + addEvent('searcher.progress', self.getProgress) + addEvent('%s.searcher.progress' % self.getType(), self.getProgress) + + self.initCron() + + + """ Set the searcher cronjob + Make sure to reset cronjob after setting has changed + + """ + def initCron(self): + + _type = self.getType() + + def setCrons(): + + fireEvent('schedule.cron', '%s.searcher.all' % _type, self.searchAll, + day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute')) + + addEvent('app.load', setCrons) + addEvent('setting.save.%s_searcher.cron_day.after' % _type, setCrons) + addEvent('setting.save.%s_searcher.cron_hour.after' % _type, setCrons) + addEvent('setting.save.%s_searcher.cron_minute.after' % _type, setCrons) + + + """ Return progress of current searcher + + """ + def getProgress(self, **kwargs): + + progress = {} + progress[self.getType()] = self.in_progress + + return progress + diff --git a/couchpotato/core/media/_base/searcher/main.py b/couchpotato/core/media/_base/searcher/main.py index 772a8acf..55dfe3e3 100644 --- a/couchpotato/core/media/_base/searcher/main.py +++ b/couchpotato/core/media/_base/searcher/main.py @@ -1,9 +1,10 @@ from couchpotato import get_session +from couchpotato.api import addApiView from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.encoding import simplifyString, toUnicode from couchpotato.core.helpers.variable import md5, getTitle from couchpotato.core.logger import CPLog -from couchpotato.core.plugins.base import Plugin +from couchpotato.core.media._base.searcher.base import SearcherBase from couchpotato.core.settings.model import Movie, Release, ReleaseInfo from couchpotato.environment import Env from inspect import ismethod, isfunction @@ -15,7 +16,7 @@ import traceback log = CPLog(__name__) -class Searcher(Plugin): +class Searcher(SearcherBase): def __init__(self): addEvent('searcher.get_types', self.getSearchTypes) @@ -24,6 +25,30 @@ class Searcher(Plugin): addEvent('searcher.correct_name', self.correctName) addEvent('searcher.download', self.download) + addApiView('searcher.full_search', self.searchAllView, docs = { + 'desc': 'Starts a full search for all media', + }) + + addApiView('searcher.progress', self.getProgressForAll, docs = { + 'desc': 'Get the progress of all media searches', + 'return': {'type': 'object', 'example': """{ + 'movie': False || object, total & to_go, + 'show': False || object, total & to_go, +}"""}, + }) + + def searchAllView(self): + + results = {} + for _type in fireEvent('media.types'): + results[_type] = fireEvent('%s.searcher.all_view' % _type) + + return results + + def getProgressForAll(self): + progress = fireEvent('searcher.progress', merge = True) + return progress + def download(self, data, movie, manual = False): # Test to see if any downloaders are enabled for this type diff --git a/couchpotato/core/media/movie/__init__.py b/couchpotato/core/media/movie/__init__.py index e69de29b..898529c1 100644 --- a/couchpotato/core/media/movie/__init__.py +++ b/couchpotato/core/media/movie/__init__.py @@ -0,0 +1,6 @@ +from couchpotato.core.media import MediaBase + + +class MovieTypeBase(MediaBase): + + _type = 'movie' diff --git a/couchpotato/core/media/movie/_base/main.py b/couchpotato/core/media/movie/_base/main.py index fc537ef0..448e9985 100644 --- a/couchpotato/core/media/movie/_base/main.py +++ b/couchpotato/core/media/movie/_base/main.py @@ -4,7 +4,7 @@ from couchpotato.core.event import fireEvent, fireEventAsync, addEvent from couchpotato.core.helpers.encoding import toUnicode, simplifyString from couchpotato.core.helpers.variable import getImdb, splitString, tryInt from couchpotato.core.logger import CPLog -from couchpotato.core.media import MediaBase +from couchpotato.core.media.movie import MovieTypeBase from couchpotato.core.settings.model import Library, LibraryTitle, Movie, \ Release from couchpotato.environment import Env @@ -16,9 +16,7 @@ import time log = CPLog(__name__) -class MovieBase(MediaBase): - - identifier = 'movie' +class MovieBase(MovieTypeBase): default_dict = { 'profile': {'types': {'quality': {}}}, @@ -29,7 +27,10 @@ class MovieBase(MediaBase): } def __init__(self): + + # Initialize this type super(MovieBase, self).__init__() + self.initType() addApiView('movie.search', self.search, docs = { 'desc': 'Search the movie providers for a movie', diff --git a/couchpotato/core/media/movie/searcher/__init__.py b/couchpotato/core/media/movie/searcher/__init__.py index 791bff2e..bf6ff218 100644 --- a/couchpotato/core/media/movie/searcher/__init__.py +++ b/couchpotato/core/media/movie/searcher/__init__.py @@ -5,7 +5,7 @@ def start(): return MovieSearcher() config = [{ - 'name': 'searcher', + 'name': 'moviesearcher', 'order': 20, 'groups': [ { @@ -18,12 +18,14 @@ config = [{ { 'name': 'always_search', 'default': False, + 'migrate_from': 'searcher', 'type': 'bool', 'label': 'Always search', 'description': 'Search for movies even before there is a ETA. Enabling this will probably get you a lot of fakes.', }, { 'name': 'run_on_launch', + 'migrate_from': 'searcher', 'label': 'Run on launch', 'advanced': True, 'default': 0, @@ -32,6 +34,7 @@ config = [{ }, { 'name': 'cron_day', + 'migrate_from': 'searcher', 'label': 'Day', 'advanced': True, 'default': '*', @@ -40,6 +43,7 @@ config = [{ }, { 'name': 'cron_hour', + 'migrate_from': 'searcher', 'label': 'Hour', 'advanced': True, 'default': random.randint(0, 23), @@ -48,6 +52,7 @@ config = [{ }, { 'name': 'cron_minute', + 'migrate_from': 'searcher', 'label': 'Minute', 'advanced': True, 'default': random.randint(0, 59), diff --git a/couchpotato/core/media/movie/searcher/main.py b/couchpotato/core/media/movie/searcher/main.py index 21803cc6..30f27d7f 100644 --- a/couchpotato/core/media/movie/searcher/main.py +++ b/couchpotato/core/media/movie/searcher/main.py @@ -5,12 +5,12 @@ from couchpotato.core.helpers.encoding import simplifyString, toUnicode from couchpotato.core.helpers.variable import md5, getTitle, splitString, \ possibleTitles, getImdb from couchpotato.core.logger import CPLog -from couchpotato.core.plugins.base import Plugin +from couchpotato.core.media._base.searcher.base import SearcherBase +from couchpotato.core.media.movie import MovieTypeBase from couchpotato.core.settings.model import Movie, Release, ReleaseInfo from couchpotato.environment import Env from datetime import date from sqlalchemy.exc import InterfaceError -import datetime import random import re import time @@ -19,12 +19,15 @@ import traceback log = CPLog(__name__) -class MovieSearcher(Plugin): +class MovieSearcher(SearcherBase, MovieTypeBase): in_progress = False def __init__(self): + super(MovieSearcher, self).__init__() + addEvent('movie.searcher.all', self.searchAll) + addEvent('movie.searcher.all_view', self.searchAllView) addEvent('movie.searcher.single', self.single) addEvent('movie.searcher.correct_movie', self.correctMovie) addEvent('movie.searcher.try_next_release', self.tryNextRelease) @@ -48,45 +51,26 @@ class MovieSearcher(Plugin): }"""}, }) - if self.conf('run_on_launch', section = 'searcher'): + if self.conf('run_on_launch'): addEvent('app.load', self.searchAll) - addEvent('app.load', self.setCrons) - addEvent('setting.save.searcher.cron_day.after', self.setCrons) - addEvent('setting.save.searcher.cron_hour.after', self.setCrons) - addEvent('setting.save.searcher.cron_minute.after', self.setCrons) - - def setCrons(self): - - fireEvent('schedule.cron', 'movie.searcher.all', self.searchAll, - day = self.conf('cron_day', section = 'searcher'), hour = self.conf('cron_hour', section = 'searcher'), minute = self.conf('cron_minute', section = 'searcher')) - def searchAllView(self, **kwargs): - in_progress = self.in_progress - if not in_progress: - fireEventAsync('movie.searcher.all') - fireEvent('notify.frontend', type = 'movie.searcher.started', data = True, message = 'Full search started') - else: - fireEvent('notify.frontend', type = 'movie.searcher.already_started', data = True, message = 'Full search already in progress') + fireEventAsync('movie.searcher.all') return { - 'success': not in_progress - } - - def getProgress(self, **kwargs): - - return { - 'progress': self.in_progress + 'success': not self.in_progress } def searchAll(self): if self.in_progress: log.info('Search already in progress') + fireEvent('notify.frontend', type = 'movie.searcher.already_started', data = True, message = 'Full search already in progress') return self.in_progress = True + fireEvent('notify.frontend', type = 'movie.searcher.started', data = True, message = 'Full search started') db = get_session() @@ -166,7 +150,7 @@ class MovieSearcher(Plugin): ret = False for quality_type in movie['profile']['types']: - if not self.conf('always_search', section = 'searcher') and not self.couldBeReleased(quality_type['quality']['identifier'] in pre_releases, release_dates, movie['library']['year']): + if not self.conf('always_search') and not self.couldBeReleased(quality_type['quality']['identifier'] in pre_releases, release_dates, movie['library']['year']): too_early_to_search.append(quality_type['quality']['identifier']) continue @@ -382,54 +366,6 @@ class MovieSearcher(Plugin): log.info("Wrong: %s, undetermined naming. Looking for '%s (%s)'", (nzb['name'], movie_name, movie['library']['year'])) return False - def containsOtherQuality(self, nzb, movie_year = None, preferred_quality = {}): - - name = nzb['name'] - size = nzb.get('size', 0) - nzb_words = re.split('\W+', simplifyString(name)) - - qualities = fireEvent('quality.all', single = True) - - found = {} - for quality in qualities: - # Main in words - if quality['identifier'] in nzb_words: - found[quality['identifier']] = True - - # Alt in words - if list(set(nzb_words) & set(quality['alternative'])): - found[quality['identifier']] = True - - # Try guessing via quality tags - guess = fireEvent('quality.guess', [nzb.get('name')], single = True) - if guess: - found[guess['identifier']] = True - - # Hack for older movies that don't contain quality tag - year_name = fireEvent('scanner.name_year', name, single = True) - if len(found) == 0 and movie_year < datetime.datetime.now().year - 3 and not year_name.get('year', None): - if size > 3000: # Assume dvdr - log.info('Quality was missing in name, assuming it\'s a DVD-R based on the size: %s', (size)) - found['dvdr'] = True - else: # Assume dvdrip - log.info('Quality was missing in name, assuming it\'s a DVD-Rip based on the size: %s', (size)) - found['dvdrip'] = True - - # Allow other qualities - for allowed in preferred_quality.get('allow'): - if found.get(allowed): - del found[allowed] - - return not (found.get(preferred_quality['identifier']) and len(found) == 1) - - def checkIMDB(self, haystack, imdbId): - - for string in haystack: - if 'imdb.com/title/' + imdbId in string: - return True - - return False - def couldBeReleased(self, is_pre_release, dates, year = None): now = int(time.time()) diff --git a/couchpotato/core/providers/torrent/thepiratebay/main.py b/couchpotato/core/providers/torrent/thepiratebay/main.py index 10608157..82cbbe9e 100644 --- a/couchpotato/core/providers/torrent/thepiratebay/main.py +++ b/couchpotato/core/providers/torrent/thepiratebay/main.py @@ -15,12 +15,13 @@ class ThePirateBay(TorrentMagnetProvider): urls = { 'detail': '%s/torrent/%s', - 'search': '%s/search/%s/%s/7/%d' + 'search': '%s/search/%s/%s/7/%s' } cat_ids = [ ([207], ['720p', '1080p']), - ([201], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr', 'brrip']), + ([201], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr']), + ([201, 207], ['brrip']), ([202], ['dvdr']) ] @@ -50,10 +51,11 @@ class ThePirateBay(TorrentMagnetProvider): page = 0 total_pages = 1 + cats = self.getCatId(quality['identifier']) while page < total_pages: - search_url = self.urls['search'] % (self.getDomain(), tryUrlencode('"%s" %s' % (title, movie['library']['year'])), page, self.getCatId(quality['identifier'])[0]) + search_url = self.urls['search'] % (self.getDomain(), tryUrlencode('"%s" %s' % (title, movie['library']['year'])), page, ','.join(str(x) for x in cats)) page += 1 data = self.getHTMLData(search_url) diff --git a/couchpotato/core/settings/__init__.py b/couchpotato/core/settings/__init__.py index cdf58aa2..e08adb87 100644 --- a/couchpotato/core/settings/__init__.py +++ b/couchpotato/core/settings/__init__.py @@ -2,7 +2,7 @@ from __future__ import with_statement from couchpotato.api import addApiView from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.encoding import isInt, toUnicode -from couchpotato.core.helpers.variable import mergeDicts, tryInt +from couchpotato.core.helpers.variable import mergeDicts, tryInt, tryFloat from couchpotato.core.settings.model import Properties import ConfigParser import os.path @@ -77,9 +77,17 @@ class Settings(object): def registerDefaults(self, section_name, options = {}, save = True): self.addSection(section_name) + for option_name, option in options.iteritems(): self.setDefault(section_name, option_name, option.get('default', '')) + # Migrate old settings from old location to the new location + if option.get('migrate_from'): + if self.p.has_option(option.get('migrate_from'), option_name): + previous_value = self.p.get(option.get('migrate_from'), option_name) + self.p.set(section_name, option_name, previous_value) + self.p.remove_option(option.get('migrate_from'), option_name) + if option.get('type'): self.setType(section_name, option_name, option.get('type')) @@ -122,7 +130,7 @@ class Settings(object): try: return self.p.getfloat(section, option) except: - return tryInt(self.p.get(section, option)) + return tryFloat(self.p.get(section, option)) def getUnicode(self, section, option): value = self.p.get(section, option).decode('unicode_escape') diff --git a/couchpotato/static/scripts/page/wanted.js b/couchpotato/static/scripts/page/wanted.js index 41bd4bcd..6adffbd5 100644 --- a/couchpotato/static/scripts/page/wanted.js +++ b/couchpotato/static/scripts/page/wanted.js @@ -56,13 +56,13 @@ Page.Wanted = new Class({ self.search_progress = Api.request('movie.searcher.progress', { 'onComplete': function(json){ self.search_in_progress = true; - if(!json.progress){ + if(!json.movie){ clearInterval(self.progress_interval); self.search_in_progress = false; self.manual_search.set('text', start_text); } else { - var progress = json.progress; + var progress = json.movie; self.manual_search.set('text', 'Searching.. (' + (((progress.total-progress.to_go)/progress.total)*100).round() + '%)'); } }