diff --git a/couchpotato/core/media/_base/searcher/main.py b/couchpotato/core/media/_base/searcher/main.py index e557e94..b665011 100644 --- a/couchpotato/core/media/_base/searcher/main.py +++ b/couchpotato/core/media/_base/searcher/main.py @@ -1,18 +1,11 @@ -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, splitString from couchpotato.core.logger import CPLog from couchpotato.core.media._base.searcher.base import SearcherBase -from couchpotato.core.settings.model import Media, Release, ReleaseInfo -from couchpotato.environment import Env -from inspect import ismethod, isfunction -from sqlalchemy.exc import InterfaceError import datetime import re -import time -import traceback log = CPLog(__name__) @@ -25,8 +18,6 @@ class Searcher(SearcherBase): addEvent('searcher.correct_year', self.correctYear) addEvent('searcher.correct_name', self.correctName) addEvent('searcher.correct_words', self.correctWords) - addEvent('searcher.try_download_result', self.tryDownloadResult) - addEvent('searcher.download', self.download) addEvent('searcher.search', self.search) addApiView('searcher.full_search', self.searchAllView, docs = { @@ -53,105 +44,6 @@ class Searcher(SearcherBase): progress = fireEvent('searcher.progress', merge = True) return progress - def tryDownloadResult(self, results, media, quality_type, manual = False): - ignored_status, failed_status = fireEvent('status.get', ['ignored', 'failed'], single = True) - - for rel in results: - if not quality_type.get('finish', False) and quality_type.get('wait_for', 0) > 0 and rel.get('age') <= quality_type.get('wait_for', 0): - log.info('Ignored, waiting %s days: %s', (quality_type.get('wait_for'), rel['name'])) - continue - - if rel['status_id'] in [ignored_status.get('id'), failed_status.get('id')]: - log.info('Ignored: %s', rel['name']) - continue - - if rel['score'] <= 0: - log.info('Ignored, score to low: %s', rel['name']) - continue - - downloaded = fireEvent('searcher.download', data = rel, media = media, manual = manual, single = True) - if downloaded is True: - return True - elif downloaded != 'try_next': - break - - return False - - def download(self, data, media, manual = False): - - if not data.get('protocol'): - data['protocol'] = data['type'] - data['type'] = 'movie' - - # Test to see if any downloaders are enabled for this type - downloader_enabled = fireEvent('download.enabled', manual, data, single = True) - - if downloader_enabled: - snatched_status, done_status, active_status = fireEvent('status.get', ['snatched', 'done', 'active'], single = True) - - # Download release to temp - filedata = None - if data.get('download') and (ismethod(data.get('download')) or isfunction(data.get('download'))): - filedata = data.get('download')(url = data.get('url'), nzb_id = data.get('id')) - if filedata == 'try_next': - return filedata - - download_result = fireEvent('download', data = data, movie = media, manual = manual, filedata = filedata, single = True) - log.debug('Downloader result: %s', download_result) - - if download_result: - try: - # Mark release as snatched - db = get_session() - rls = db.query(Release).filter_by(identifier = md5(data['url'])).first() - if rls: - renamer_enabled = Env.setting('enabled', 'renamer') - - # Save download-id info if returned - if isinstance(download_result, dict): - for key in download_result: - rls_info = ReleaseInfo( - identifier = 'download_%s' % key, - value = toUnicode(download_result.get(key)) - ) - rls.info.append(rls_info) - db.commit() - - log_movie = '%s (%s) in %s' % (getTitle(media['library']), media['library']['year'], rls.quality.label) - snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie) - log.info(snatch_message) - fireEvent('%s.snatched' % data['type'], message = snatch_message, data = rls.to_dict()) - - # If renamer isn't used, mark media done - if not renamer_enabled: - try: - if media['status_id'] == active_status.get('id'): - for profile_type in media['profile']['types']: - if profile_type['quality_id'] == rls.quality.id and profile_type['finish']: - log.info('Renamer disabled, marking media as finished: %s', log_movie) - - # Mark release done - fireEvent('release.update_status', rls.id, status = done_status, single = True) - - # Mark media done - mdia = db.query(Media).filter_by(id = media['id']).first() - mdia.status_id = done_status.get('id') - mdia.last_edit = int(time.time()) - db.commit() - except: - log.error('Failed marking media finished, renamer disabled: %s', traceback.format_exc()) - else: - fireEvent('release.update_status', rls.id, status = snatched_status, single = True) - - except: - log.error('Failed marking media finished: %s', traceback.format_exc()) - - return True - - log.info('Tried to download, but none of the "%s" downloaders are enabled or gave an error', (data.get('protocol'))) - - return False - def search(self, protocols, media, quality): results = [] diff --git a/couchpotato/core/media/movie/_base/static/movie.actions.js b/couchpotato/core/media/movie/_base/static/movie.actions.js index 0e9e5bf..3eb9fdd 100644 --- a/couchpotato/core/media/movie/_base/static/movie.actions.js +++ b/couchpotato/core/media/movie/_base/static/movie.actions.js @@ -393,7 +393,7 @@ MA.Release = new Class({ if(icon) icon.addClass('icon spinner').removeClass('download'); - Api.request('release.download', { + Api.request('release.manual_download', { 'data': { 'id': release.id }, diff --git a/couchpotato/core/media/movie/searcher/main.py b/couchpotato/core/media/movie/searcher/main.py index 6dca8f1..e67bbc5 100644 --- a/couchpotato/core/media/movie/searcher/main.py +++ b/couchpotato/core/media/movie/searcher/main.py @@ -183,7 +183,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): found_releases += fireEvent('release.create_from_search', results, movie, quality_type, single = True) # Try find a valid result and download it - if fireEvent('searcher.try_download_result', results, movie, quality_type, manual, single = True): + if fireEvent('release.try_download_result', results, movie, quality_type, manual, single = True): ret = True # Remove releases that aren't found anymore diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 6d20da4..62964c5 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -2,10 +2,13 @@ from couchpotato import get_session, md5 from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, addEvent from couchpotato.core.helpers.encoding import ss, toUnicode +from couchpotato.core.helpers.variable import getTitle from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.scanner.main import Scanner from couchpotato.core.settings.model import File, Release as Relea, Media, ReleaseInfo +from couchpotato.environment import Env +from inspect import ismethod, isfunction from sqlalchemy.exc import InterfaceError from sqlalchemy.orm import joinedload_all from sqlalchemy.sql.expression import and_, or_ @@ -21,7 +24,7 @@ class Release(Plugin): def __init__(self): addEvent('release.add', self.add) - addApiView('release.download', self.download, docs = { + addApiView('release.manual_download', self.manualDownload, docs = { 'desc': 'Send a release manually to the downloaders', 'params': { 'id': {'type': 'id', 'desc': 'ID of the release object in release-table'} @@ -46,6 +49,8 @@ class Release(Plugin): } }) + addEvent('release.download', self.download) + addEvent('release.try_download_result', self.tryDownloadResult) addEvent('release.create_from_search', self.createFromSearch) addEvent('release.for_movie', self.forMovie) addEvent('release.delete', self.delete) @@ -140,7 +145,6 @@ class Release(Plugin): return True - def saveFile(self, filepath, type = 'unknown', include_media_info = False): properties = {} @@ -201,7 +205,7 @@ class Release(Plugin): 'success': True } - def download(self, id = None, **kwargs): + def manualDownload(self, id = None, **kwargs): db = get_session() @@ -213,7 +217,7 @@ class Release(Plugin): for info in rel.info: item[info.identifier] = info.value - fireEvent('notify.frontend', type = 'release.download', data = True, message = 'Snatching "%s"' % item['name']) + fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Snatching "%s"' % item['name']) # Get matching provider provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True) @@ -225,7 +229,7 @@ class Release(Plugin): if item.get('protocol') != 'torrent_magnet': item['download'] = provider.loginDownload if provider.urls.get('login') else provider.download - success = fireEvent('searcher.download', data = item, media = rel.movie.to_dict({ + success = fireEvent('release.download', data = item, media = rel.movie.to_dict({ 'profile': {'types': {'quality': {}}}, 'releases': {'status': {}, 'quality': {}}, 'library': {'titles': {}, 'files':{}}, @@ -236,7 +240,7 @@ class Release(Plugin): db.expunge_all() rel = db.query(Relea).filter_by(id = id).first() # Get release again @RuudBurger why do we need to get it again?? - fireEvent('notify.frontend', type = 'release.download', data = True, message = 'Successfully snatched "%s"' % item['name']) + fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Successfully snatched "%s"' % item['name']) return { 'success': success } @@ -247,6 +251,105 @@ class Release(Plugin): 'success': False } + def download(self, data, media, manual = False): + + if not data.get('protocol'): + data['protocol'] = data['type'] + data['type'] = 'movie' + + # Test to see if any downloaders are enabled for this type + downloader_enabled = fireEvent('download.enabled', manual, data, single = True) + + if downloader_enabled: + snatched_status, done_status, active_status = fireEvent('status.get', ['snatched', 'done', 'active'], single = True) + + # Download release to temp + filedata = None + if data.get('download') and (ismethod(data.get('download')) or isfunction(data.get('download'))): + filedata = data.get('download')(url = data.get('url'), nzb_id = data.get('id')) + if filedata == 'try_next': + return filedata + + download_result = fireEvent('download', data = data, movie = media, manual = manual, filedata = filedata, single = True) + log.debug('Downloader result: %s', download_result) + + if download_result: + try: + # Mark release as snatched + db = get_session() + rls = db.query(Relea).filter_by(identifier = md5(data['url'])).first() + if rls: + renamer_enabled = Env.setting('enabled', 'renamer') + + # Save download-id info if returned + if isinstance(download_result, dict): + for key in download_result: + rls_info = ReleaseInfo( + identifier = 'download_%s' % key, + value = toUnicode(download_result.get(key)) + ) + rls.info.append(rls_info) + db.commit() + + log_movie = '%s (%s) in %s' % (getTitle(media['library']), media['library']['year'], rls.quality.label) + snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie) + log.info(snatch_message) + fireEvent('%s.snatched' % data['type'], message = snatch_message, data = rls.to_dict()) + + # If renamer isn't used, mark media done + if not renamer_enabled: + try: + if media['status_id'] == active_status.get('id'): + for profile_type in media['profile']['types']: + if profile_type['quality_id'] == rls.quality.id and profile_type['finish']: + log.info('Renamer disabled, marking media as finished: %s', log_movie) + + # Mark release done + fireEvent('release.update_status', rls.id, status = done_status, single = True) + + # Mark media done + mdia = db.query(Media).filter_by(id = media['id']).first() + mdia.status_id = done_status.get('id') + mdia.last_edit = int(time.time()) + db.commit() + except: + log.error('Failed marking media finished, renamer disabled: %s', traceback.format_exc()) + else: + fireEvent('release.update_status', rls.id, status = snatched_status, single = True) + + except: + log.error('Failed marking media finished: %s', traceback.format_exc()) + + return True + + log.info('Tried to download, but none of the "%s" downloaders are enabled or gave an error', (data.get('protocol'))) + + return False + + def tryDownloadResult(self, results, media, quality_type, manual = False): + ignored_status, failed_status = fireEvent('status.get', ['ignored', 'failed'], single = True) + + for rel in results: + if not quality_type.get('finish', False) and quality_type.get('wait_for', 0) > 0 and rel.get('age') <= quality_type.get('wait_for', 0): + log.info('Ignored, waiting %s days: %s', (quality_type.get('wait_for'), rel['name'])) + continue + + if rel['status_id'] in [ignored_status.get('id'), failed_status.get('id')]: + log.info('Ignored: %s', rel['name']) + continue + + if rel['score'] <= 0: + log.info('Ignored, score to low: %s', rel['name']) + continue + + downloaded = fireEvent('release.download', data = rel, media = media, manual = manual, single = True) + if downloaded is True: + return True + elif downloaded != 'try_next': + break + + return False + def createFromSearch(self, search_results, media, quality_type): available_status = fireEvent('status.get', ['available'], single = True)