2014-03-10 05:18:05 +00:00
|
|
|
# Author: Tyler Fenby <tylerfenby@gmail.com>
|
|
|
|
#
|
2014-11-12 16:43:14 +00:00
|
|
|
# This file is part of SickGear.
|
2014-03-10 05:18:05 +00:00
|
|
|
#
|
2014-11-12 16:43:14 +00:00
|
|
|
# SickGear is free software: you can redistribute it and/or modify
|
2014-03-10 05:18:05 +00:00
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
2014-11-12 16:43:14 +00:00
|
|
|
# SickGear is distributed in the hope that it will be useful,
|
2014-03-10 05:18:05 +00:00
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
2014-11-12 16:43:14 +00:00
|
|
|
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
import datetime
|
2014-03-10 05:18:05 +00:00
|
|
|
import re
|
|
|
|
import urllib
|
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
from sickbeard import db, logger
|
|
|
|
from sickbeard.common import FAILED, WANTED, Quality, statusStrings
|
|
|
|
from sickbeard.exceptions import EpisodeNotFoundException, ex
|
2014-03-10 05:18:05 +00:00
|
|
|
from sickbeard.history import dateFormat
|
|
|
|
|
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def db_cmd(sql, params, select=True):
|
|
|
|
|
|
|
|
my_db = db.DBConnection('failed.db')
|
|
|
|
sql_result = select and my_db.select(sql, params) or my_db.action(sql, params)
|
|
|
|
return sql_result
|
|
|
|
|
|
|
|
|
|
|
|
def db_select(sql, params):
|
|
|
|
|
|
|
|
return db_cmd(sql, params)
|
|
|
|
|
|
|
|
|
|
|
|
def db_action(sql, params=None):
|
|
|
|
|
|
|
|
return db_cmd(sql, params, False)
|
|
|
|
|
|
|
|
|
|
|
|
def prepare_failed_name(release):
|
2014-03-10 05:18:05 +00:00
|
|
|
"""Standardizes release name for failed DB"""
|
|
|
|
|
|
|
|
fixed = urllib.unquote(release)
|
2017-02-17 03:16:51 +00:00
|
|
|
if fixed.endswith('.nzb'):
|
|
|
|
fixed = fixed.rpartition('.')[0]
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
fixed = re.sub('[.\-+ ]', '_', fixed)
|
2014-05-13 11:16:32 +00:00
|
|
|
|
|
|
|
if not isinstance(fixed, unicode):
|
2014-07-15 02:00:53 +00:00
|
|
|
fixed = unicode(fixed, 'utf-8', 'replace')
|
2014-05-13 11:16:32 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
return fixed
|
|
|
|
|
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def add_failed(release):
|
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
size = -1
|
2017-02-17 03:16:51 +00:00
|
|
|
provider = ''
|
|
|
|
|
|
|
|
release = prepare_failed_name(release)
|
|
|
|
|
|
|
|
sql_results = db_select('SELECT * FROM history t WHERE t.release=?', [release])
|
|
|
|
|
|
|
|
if not any(sql_results):
|
|
|
|
logger.log('Release not found in failed.db snatch history', logger.WARNING)
|
|
|
|
|
|
|
|
elif 1 < len(sql_results):
|
|
|
|
logger.log('Multiple logged snatches found for release in failed.db', logger.WARNING)
|
|
|
|
sizes = len(set(x['size'] for x in sql_results))
|
|
|
|
providers = len(set(x['provider'] for x in sql_results))
|
|
|
|
|
|
|
|
if 1 == sizes:
|
|
|
|
logger.log('However, they\'re all the same size. Continuing with found size', logger.WARNING)
|
|
|
|
size = sql_results[0]['size']
|
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
else:
|
2014-05-13 11:16:32 +00:00
|
|
|
logger.log(
|
2017-02-17 03:16:51 +00:00
|
|
|
'They also vary in size. Deleting logged snatches and recording this release with no size/provider',
|
2014-03-25 05:57:24 +00:00
|
|
|
logger.WARNING)
|
2014-03-10 05:18:05 +00:00
|
|
|
for result in sql_results:
|
2017-02-17 03:16:51 +00:00
|
|
|
remove_snatched(result['release'], result['size'], result['provider'])
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
if 1 == providers:
|
|
|
|
logger.log('They\'re also from the same provider. Using it as well')
|
|
|
|
provider = sql_results[0]['provider']
|
2014-03-10 05:18:05 +00:00
|
|
|
else:
|
2017-02-17 03:16:51 +00:00
|
|
|
size = sql_results[0]['size']
|
|
|
|
provider = sql_results[0]['provider']
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
if not has_failed(release, size, provider):
|
|
|
|
db_action('INSERT INTO failed (`release`, `size`, `provider`) VALUES (?, ?, ?)', [release, size, provider])
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
remove_snatched(release, size, provider)
|
2014-03-10 05:18:05 +00:00
|
|
|
|
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def add_snatched(search_result):
|
|
|
|
"""
|
|
|
|
:param search_result: SearchResult object
|
|
|
|
"""
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
log_date = datetime.datetime.today().strftime(dateFormat)
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
provider = 'unknown'
|
|
|
|
if None is not search_result.provider:
|
|
|
|
provider = search_result.provider.name
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
for episode in search_result.episodes:
|
|
|
|
db_action(
|
|
|
|
'INSERT INTO history (`date`, `size`, `release`, `provider`, `showid`, `season`, `episode`, `old_status`)'
|
|
|
|
'VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
|
|
|
[log_date, search_result.size, prepare_failed_name(search_result.name), provider,
|
|
|
|
search_result.episodes[0].show.indexerid, episode.season, episode.episode, episode.status])
|
2014-03-10 05:18:05 +00:00
|
|
|
|
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def set_episode_failed(ep_obj):
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
try:
|
|
|
|
with ep_obj.lock:
|
|
|
|
quality = Quality.splitCompositeStatus(ep_obj.status)[1]
|
|
|
|
ep_obj.status = Quality.compositeStatus(FAILED, quality)
|
|
|
|
ep_obj.saveToDB()
|
2014-05-13 16:30:25 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
except EpisodeNotFoundException as e:
|
|
|
|
logger.log('Unable to get episode, please set its status manually: %s' % ex(e), logger.WARNING)
|
2014-03-10 05:18:05 +00:00
|
|
|
|
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def remove_failed(release):
|
2014-06-07 21:32:38 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
db_action('DELETE FROM history WHERE %s=?' % '`release`', [prepare_failed_name(release)])
|
2014-03-10 05:18:05 +00:00
|
|
|
|
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def remove_snatched(release, size, provider):
|
2014-03-19 14:59:34 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
db_action('DELETE FROM history WHERE %s=? AND %s=? AND %s=?' % ('`release`', '`size`', '`provider`'),
|
|
|
|
[prepare_failed_name(release), size, provider])
|
2014-06-07 21:32:38 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def remove_old_history():
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
db_action('DELETE FROM history WHERE date < %s' %
|
|
|
|
str((datetime.datetime.today() - datetime.timedelta(days=30)).strftime(dateFormat)))
|
2014-03-19 14:59:34 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def has_failed(release, size, provider='%'):
|
|
|
|
"""
|
|
|
|
Returns True if a release has previously failed.
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
If provider is given, return True only if the release is found
|
|
|
|
with that specific provider. Otherwise, return True if the release
|
|
|
|
is found with any provider.
|
|
|
|
"""
|
|
|
|
return any(db_select('SELECT * FROM failed t WHERE t.release=? AND t.size=? AND t.provider LIKE ?',
|
|
|
|
[prepare_failed_name(release), size, provider]))
|
2014-03-25 05:57:24 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def revert_episode(ep_obj):
|
|
|
|
"""Restore the episodes of a failed download to their original state"""
|
|
|
|
sql_results = db_select(
|
|
|
|
'SELECT * FROM history t WHERE t.showid=? AND t.season=?', [ep_obj.show.indexerid, ep_obj.season])
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
history_eps = {r['episode']: r for r in sql_results}
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
try:
|
|
|
|
logger.log('Reverting episode %sx%s: [%s]' % (ep_obj.season, ep_obj.episode, ep_obj.name))
|
|
|
|
with ep_obj.lock:
|
|
|
|
if ep_obj.episode in history_eps:
|
|
|
|
status_revert = history_eps[ep_obj.episode]['old_status']
|
|
|
|
|
|
|
|
status, quality = Quality.splitCompositeStatus(status_revert)
|
|
|
|
logger.log('Found in failed.db history with status: %s quality: %s' % (
|
|
|
|
statusStrings[status], Quality.qualityStrings[quality]))
|
|
|
|
else:
|
|
|
|
status_revert = WANTED
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
logger.log('Episode not found in failed.db history. Setting it to WANTED', logger.WARNING)
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
ep_obj.status = status_revert
|
|
|
|
ep_obj.saveToDB()
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
except EpisodeNotFoundException as e:
|
|
|
|
logger.log('Unable to create episode, please set its status manually: %s' % ex(e), logger.WARNING)
|
2014-03-10 05:18:05 +00:00
|
|
|
|
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def find_old_status(ep_obj):
|
|
|
|
"""
|
|
|
|
:param ep_obj:
|
|
|
|
:return: Old status if failed history item found
|
|
|
|
"""
|
|
|
|
# Search for release in snatch history
|
|
|
|
results = db_select(
|
|
|
|
'SELECT t.old_status FROM history t WHERE t.showid=? AND t.season=? AND t.episode=? '
|
|
|
|
+ 'ORDER BY t.date DESC LIMIT 1', [ep_obj.show.indexerid, ep_obj.season, ep_obj.episode])
|
|
|
|
if any(results):
|
|
|
|
return results[0]['old_status']
|
2014-06-07 21:32:38 +00:00
|
|
|
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
def find_release(ep_obj):
|
2014-03-10 05:18:05 +00:00
|
|
|
"""
|
|
|
|
Find releases in history by show ID and season.
|
|
|
|
Return None for release if multiple found or no release found.
|
|
|
|
"""
|
|
|
|
# Clear old snatches for this release if any exist
|
2017-02-17 03:16:51 +00:00
|
|
|
from_where = ' FROM history WHERE showid=%s AND season=%s AND episode=%s' % \
|
|
|
|
(ep_obj.show.indexerid, ep_obj.season, ep_obj.episode)
|
|
|
|
db_action('DELETE %s AND date < (SELECT max(date) %s)' % (from_where, from_where))
|
2014-06-21 22:46:59 +00:00
|
|
|
|
|
|
|
# Search for release in snatch history
|
2017-02-17 03:16:51 +00:00
|
|
|
results = db_select(
|
|
|
|
'SELECT t.release, t.provider, t.date FROM history t WHERE t.showid=? AND t.season=? AND t.episode=?',
|
|
|
|
[ep_obj.show.indexerid, ep_obj.season, ep_obj.episode])
|
2014-06-21 22:46:59 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
if any(results):
|
|
|
|
r = results[0]
|
|
|
|
release = r['release']
|
|
|
|
provider = r['provider']
|
2014-06-21 22:46:59 +00:00
|
|
|
|
|
|
|
# Clear any incomplete snatch records for this release if any exist
|
2017-02-17 03:16:51 +00:00
|
|
|
db_action('DELETE FROM history WHERE %s=? AND %s!=?' % ('`release`', '`date`'), [release, r['date']])
|
2014-06-21 22:46:59 +00:00
|
|
|
|
|
|
|
# Found a previously failed release
|
2017-02-17 03:16:51 +00:00
|
|
|
logger.log('Found failed.db history release %sx%s: [%s]' % (
|
|
|
|
ep_obj.season, ep_obj.episode, release), logger.DEBUG)
|
|
|
|
else:
|
|
|
|
release = None
|
|
|
|
provider = None
|
|
|
|
|
|
|
|
# Release not found
|
|
|
|
logger.log('No found failed.db history release for %sx%s: [%s]' % (
|
|
|
|
ep_obj.season, ep_obj.episode, ep_obj.show.name), logger.DEBUG)
|
2014-03-10 05:18:05 +00:00
|
|
|
|
2017-02-17 03:16:51 +00:00
|
|
|
return release, provider
|