|
|
@ -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) |
|
|
|