From 6225ed92b1a9512b57e44c48de7727fef53b4d9d Mon Sep 17 00:00:00 2001 From: mano3m <-> Date: Sun, 29 Jul 2012 18:56:05 +0200 Subject: [PATCH] Added failed download handling for sabnzbd. It will check for failed downloads from the sabnzbd api and then set the failed release to ignore and try the search again. --- couchpotato/core/downloaders/base.py | 5 ++- couchpotato/core/downloaders/sabnzbd/main.py | 43 ++++++++++++++++++ couchpotato/core/plugins/renamer/main.py | 46 +++++++++++++++++++- 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/downloaders/base.py b/couchpotato/core/downloaders/base.py index 74e04de6..e0dad913 100644 --- a/couchpotato/core/downloaders/base.py +++ b/couchpotato/core/downloaders/base.py @@ -7,17 +7,20 @@ import os log = CPLog(__name__) - class Downloader(Plugin): type = [] def __init__(self): addEvent('download', self.download) + addEvent('getdownloadfailed', self.getdownloadfailed) def download(self, data = {}): pass + def getdownloadfailed(self, data = {}): + pass + def createNzbName(self, data, movie): return '%s%s' % (toSafeString(data.get('name')), self.cpTag(movie)) diff --git a/couchpotato/core/downloaders/sabnzbd/main.py b/couchpotato/core/downloaders/sabnzbd/main.py index 64b24509..8983c1ad 100644 --- a/couchpotato/core/downloaders/sabnzbd/main.py +++ b/couchpotato/core/downloaders/sabnzbd/main.py @@ -3,6 +3,8 @@ from couchpotato.core.helpers.encoding import tryUrlencode from couchpotato.core.helpers.variable import cleanHost from couchpotato.core.logger import CPLog import traceback +import urllib2 +import json log = CPLog(__name__) @@ -61,3 +63,44 @@ class Sabnzbd(Downloader): else: log.error("Unknown error: " + result[:40]) return False + + def getdownloadfailed(self, data = {}, movie = {}, manual = False): + if self.isDisabled(manual) or not self.isCorrectType(data.get('type')): + return + + log.info('Checking download status of "%s" at SABnzbd.', data.get('name')) + + params = { + 'apikey': self.conf('api_key'), + 'mode': 'history', + 'ouput': 'json' + } + url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) + log.debug('Opening: %s', url) + history = json.load(urllib2.urlopen(url)) + + nzbname = self.createNzbName(data, movie) + + # Go through history items + for slot in history['history']['slots']: + log.debug('Found %s in SabNZBd history, which has %s', (slot['name'], slot['status'])) + if slot['name'] == nzbname and slot['status'] == 'Failed': + log.debug('%s failed downloading, deleting...', slot['name']) + + # Delete failed download + params = { + 'apikey': self.conf('api_key'), + 'mode': 'history', + 'name': 'delete', + 'value' : slot['id'] + } + url = cleanHost(self.conf('host')) + "api?" + tryUrlencode(params) + try: + data = self.urlopen(url, timeout = 60, show_error = False) + except: + log.error(traceback.format_exc()) + + # Return failed + return True + + return False diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index 4c6e6b89..c8a76944 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -6,7 +6,7 @@ from couchpotato.core.helpers.request import jsonified from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin -from couchpotato.core.settings.model import Library, File, Profile +from couchpotato.core.settings.model import Library, File, Profile, Release as Relea from couchpotato.environment import Env import os import re @@ -48,6 +48,8 @@ class Renamer(Plugin): log.info('Renamer is disabled to avoid infinite looping of the same error.') return + self.checkSnatchedStatusses() + # Check to see if the "to" folder is inside the "from" folder. if not os.path.isdir(self.conf('from')) or not os.path.isdir(self.conf('to')): log.debug('"To" and "From" have to exist.') @@ -471,3 +473,45 @@ class Renamer(Plugin): os.rmdir(folder) except: log.error('Couldn\'t remove empty directory %s: %s', (folder, traceback.format_exc())) + + def checkSnatchedStatusses(self): + snatched_status = fireEvent('status.get', 'snatched', single = True) + ignored_status = fireEvent('status.get', 'ignored', single = True) + + db = get_session() + rels = db.query(Relea).filter_by(status_id = snatched_status.get('id')) + + log.debug('Checking snatched releases... %s', 'ops') + + for rel in rels: + log.debug('Checking snatched release: %s' , rel.movie.library.titles[0].title) + item = {} + for info in rel.info: + item[info.identifier] = info.value + + log.debug('Checking status snatched release: %s' , item.get('name')) + + mymovie = rel.movie.to_dict({ + 'profile': {'types': {'quality': {}}}, + 'releases': {'status': {}, 'quality': {}}, + 'library': {'titles': {}, 'files':{}}, + 'files': {} + }) + + log.debug('Checking status snatched release: %s' , mymovie['library'].get('identifier')) + + # check status + downloadfailed = fireEvent('getdownloadfailed', data = item, movie = mymovie) + + if downloadfailed: + log.debug('Download of %s failed', item['name']) + + # if failed set status to ignored + rel.status_id = ignored_status.get('id') + db.commit() + + # search/download again + log.info('Download of %s failed, trying next release...', item['name']) + fireEvent('searcher.single', rel.movie) + + return