diff --git a/CHANGES.md b/CHANGES.md
index d87155f0..ab358454 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -159,6 +159,11 @@
* Change show loaded log message at start up and include info source
* Change if episode has no airdate then set status to unaired (was skipped)
* Fix only replace initial quality releases from the upgrade to list
+* Change optimise TheTVDB processes, 40% to 66% saved adding new and existing shows, 40% to 50% saved per show update
+* Change improve shows with more episodes gain largest reductions in time spent processing
+* Change when using "Add new show" reduce search time outs
+* Change always allow incomplete show data
+* Remove redundant config/general/"Allow incomplete show data"
[develop changelog]
* Change send nzb data to NZBGet for Anizb instead of url
diff --git a/gui/slick/interfaces/default/config_general.tmpl b/gui/slick/interfaces/default/config_general.tmpl
index bfe43244..3dd852b1 100644
--- a/gui/slick/interfaces/default/config_general.tmpl
+++ b/gui/slick/interfaces/default/config_general.tmpl
@@ -88,18 +88,6 @@
-#if hasattr($sickbeard, 'ALLOW_INCOMPLETE_SHOWDATA')
-
-
-
-#end if
-
Send to trash for actions
diff --git a/lib/etreetodict.py b/lib/etreetodict.py
new file mode 100644
index 00000000..4c34e302
--- /dev/null
+++ b/lib/etreetodict.py
@@ -0,0 +1,141 @@
+try:
+ from lxml import ElementTree
+except ImportError:
+ try:
+ import xml.etree.cElementTree as ElementTree
+ except ImportError:
+ import xml.etree.ElementTree as ElementTree
+
+
+class XmlDictObject(dict):
+ """
+ Adds object like functionality to the standard dictionary.
+ """
+
+ def __init__(self, initdict=None):
+ if initdict is None:
+ initdict = {}
+ dict.__init__(self, initdict)
+
+ def __getattr__(self, item):
+ return self.__getitem__(item)
+
+ def __setattr__(self, item, value):
+ self.__setitem__(item, value)
+
+ def __str__(self):
+ if self.has_key('_text'):
+ return self.__getitem__('_text')
+ else:
+ return ''
+
+ @staticmethod
+ def Wrap(x):
+ """
+ Static method to wrap a dictionary recursively as an XmlDictObject
+ """
+
+ if isinstance(x, dict):
+ return XmlDictObject((k, XmlDictObject.Wrap(v)) for (k, v) in x.iteritems())
+ elif isinstance(x, list):
+ return [XmlDictObject.Wrap(v) for v in x]
+ else:
+ return x
+
+ @staticmethod
+ def _UnWrap(x):
+ if isinstance(x, dict):
+ return dict((k, XmlDictObject._UnWrap(v)) for (k, v) in x.iteritems())
+ elif isinstance(x, list):
+ return [XmlDictObject._UnWrap(v) for v in x]
+ else:
+ return x
+
+ def UnWrap(self):
+ """
+ Recursively converts an XmlDictObject to a standard dictionary and returns the result.
+ """
+
+ return XmlDictObject._UnWrap(self)
+
+
+def _ConvertDictToXmlRecurse(parent, dictitem):
+ assert type(dictitem) is not type([])
+
+ if isinstance(dictitem, dict):
+ for (tag, child) in dictitem.iteritems():
+ if str(tag) == '_text':
+ parent.text = str(child)
+ elif type(child) is type([]):
+ # iterate through the array and convert
+ for listchild in child:
+ elem = ElementTree.Element(tag)
+ parent.append(elem)
+ _ConvertDictToXmlRecurse(elem, listchild)
+ else:
+ elem = ElementTree.Element(tag)
+ parent.append(elem)
+ _ConvertDictToXmlRecurse(elem, child)
+ else:
+ parent.text = str(dictitem)
+
+
+def ConvertDictToXml(xmldict):
+ """
+ Converts a dictionary to an XML ElementTree Element
+ """
+
+ roottag = xmldict.keys()[0]
+ root = ElementTree.Element(roottag)
+ _ConvertDictToXmlRecurse(root, xmldict[roottag])
+ return root
+
+
+def _ConvertXmlToDictRecurse(node, dictclass):
+ nodedict = dictclass()
+
+ if len(node.items()) > 0:
+ # if we have attributes, set them
+ nodedict.update(dict(node.items()))
+
+ for child in node:
+ # recursively add the element's children
+ newitem = _ConvertXmlToDictRecurse(child, dictclass)
+ if nodedict.has_key(child.tag):
+ # found duplicate tag, force a list
+ if type(nodedict[child.tag]) is type([]):
+ # append to existing list
+ nodedict[child.tag].append(newitem)
+ else:
+ # convert to list
+ nodedict[child.tag] = [nodedict[child.tag], newitem]
+ else:
+ # only one, directly set the dictionary
+ nodedict[child.tag] = newitem
+
+ if node.text is None:
+ text = ''
+ else:
+ text = node.text.strip()
+
+ if len(nodedict) > 0:
+ # if we have a dictionary add the text as a dictionary value (if there is any)
+ if len(text) > 0:
+ nodedict['_text'] = text
+ else:
+ # if we don't have child nodes or attributes, just set the text
+ nodedict = text
+
+ return nodedict
+
+def ConvertXmlToDict(root, dictclass=XmlDictObject):
+ """
+ Converts an XML String to a dictionary
+ """
+
+ if isinstance(root, basestring):
+ root = ElementTree.fromstring(root)
+ elif not isinstance(root, ElementTree.Element):
+ raise TypeError, 'Expected string'
+
+ return dictclass({root.tag: _ConvertXmlToDictRecurse(root, dictclass)})
diff --git a/lib/tvdb_api/tvdb_api.py b/lib/tvdb_api/tvdb_api.py
index ad3ce83d..f8f2f1c4 100644
--- a/lib/tvdb_api/tvdb_api.py
+++ b/lib/tvdb_api/tvdb_api.py
@@ -5,8 +5,8 @@
# repository:http://github.com/dbr/tvdb_api
# license:unlicense (http://unlicense.org/)
-from functools import wraps
import traceback
+from functools import wraps
__author__ = 'dbr/Ben'
__version__ = '1.9'
@@ -21,12 +21,6 @@ import logging
import zipfile
import requests
import requests.exceptions
-import xmltodict
-
-try:
- import xml.etree.cElementTree as ElementTree
-except ImportError:
- import xml.etree.ElementTree as ElementTree
try:
import gzip
@@ -36,6 +30,7 @@ except ImportError:
from lib.dateutil.parser import parse
from lib.cachecontrol import CacheControl, caches
+from lib.etreetodict import ConvertXmlToDict
from tvdb_ui import BaseUI, ConsoleUI
from tvdb_exceptions import (tvdb_error, tvdb_shownotfound,
tvdb_seasonnotfound, tvdb_episodenotfound, tvdb_attributenotfound)
@@ -565,18 +560,17 @@ class Tvdb:
except Exception:
raise tvdb_error('Unknown exception while loading URL %s: %s' % (url, traceback.format_exc()))
- def process(path, key, value):
- key = key.lower()
-
- # clean up value and do type changes
- if value:
- if 'firstaired' == key:
- try:
- value = parse(value, fuzzy=True).strftime('%Y-%m-%d')
- except:
- value = None
-
- return key, value
+ def process_data(data):
+ te = ConvertXmlToDict(data)
+ if isinstance(te, dict) and 'Data' in te and isinstance(te['Data'], dict) and \
+ 'Series' in te['Data'] and isinstance(te['Data']['Series'], dict) and \
+ 'FirstAired' in te['Data']['Series']:
+ try:
+ value = parse(te['Data']['Series']['FirstAired'], fuzzy=True).strftime('%Y-%m-%d')
+ except:
+ value = None
+ te['Data']['Series']['firstaired'] = value
+ return te
if resp.ok:
if 'application/zip' in resp.headers.get('Content-Type', ''):
@@ -586,12 +580,12 @@ class Tvdb:
zipdata = StringIO.StringIO()
zipdata.write(resp.content)
myzipfile = zipfile.ZipFile(zipdata)
- return xmltodict.parse(myzipfile.read('%s.xml' % language), postprocessor=process)
+ return process_data(myzipfile.read('%s.xml' % language))
except zipfile.BadZipfile:
raise tvdb_error('Bad zip file received from thetvdb.com, could not read it')
else:
try:
- return xmltodict.parse(resp.content.strip(), postprocessor=process)
+ return process_data(resp.content.strip())
except:
return dict([(u'data', None)])
@@ -641,7 +635,7 @@ class Tvdb:
- Replaces & with &
- Trailing whitespace
"""
- return data if data is None else data.strip().replace(u'&', u'&')
+ return data if not isinstance(data, basestring) else data.strip().replace(u'&', u'&')
def search(self, series):
"""This searches TheTVDB.com for the series name
@@ -654,6 +648,7 @@ class Tvdb:
try:
series_found = self._getetsrc(self.config['url_get_series'], self.config['params_get_series'])
if series_found:
+ series_found['Series'] = [{k.lower(): v for k, v in s.iteritems()} for s in series_found['Series']]
return series_found.values()[0]
except:
pass
@@ -804,21 +799,21 @@ class Tvdb:
# Parse show information
log().debug('Getting all series data for %s' % sid)
- url = self.config['url_epInfo%s' % ('', '_zip')[self.config['useZip']]] % (sid, language)
+ url = (self.config['url_seriesInfo'] % (sid, language), self.config['url_epInfo%s' % ('', '_zip')[self.config['useZip']]] % (sid, language))[get_ep_info]
show_data = self._getetsrc(url, language=get_show_in_language)
# check and make sure we have data to process and that it contains a series name
- if not len(show_data) or (isinstance(show_data, dict) and 'seriesname' not in show_data['series']):
+ if not len(show_data) or (isinstance(show_data, dict) and 'SeriesName' not in show_data['Series']):
return False
- for k, v in show_data['series'].items():
+ for k, v in show_data['Series'].iteritems():
if None is not v:
if k in ['banner', 'fanart', 'poster']:
v = self.config['url_artworkPrefix'] % v
else:
v = self._clean_data(v)
- self._set_show_data(sid, k, v)
+ self._set_show_data(sid, k.lower(), v)
if get_ep_info:
# Parse banners
@@ -832,24 +827,24 @@ class Tvdb:
# Parse episode data
log().debug('Getting all episodes of %s' % sid)
- if 'episode' not in show_data:
+ if 'Episode' not in show_data:
return False
- episodes = show_data['episode']
+ episodes = show_data['Episode']
if not isinstance(episodes, list):
episodes = [episodes]
for cur_ep in episodes:
if self.config['dvdorder']:
log().debug('Using DVD ordering.')
- use_dvd = None is not cur_ep['dvd_season'] and None is not cur_ep['dvd_episodenumber']
+ use_dvd = None is not cur_ep['DVD_season'] and None is not cur_ep['DVD_episodenumber']
else:
use_dvd = False
if use_dvd:
- elem_seasnum, elem_epno = cur_ep['dvd_season'], cur_ep['dvd_episodenumber']
+ elem_seasnum, elem_epno = cur_ep['DVD_season'], cur_ep['DVD_episodenumber']
else:
- elem_seasnum, elem_epno = cur_ep['seasonnumber'], cur_ep['episodenumber']
+ elem_seasnum, elem_epno = cur_ep['SeasonNumber'], cur_ep['EpisodeNumber']
if None is elem_seasnum or None is elem_epno:
log().warning('An episode has incomplete season/episode number (season: %r, episode: %r)' % (
@@ -895,10 +890,16 @@ class Tvdb:
"""Handles tvdb_instance['seriesname'] calls.
The dict index should be the show id
"""
+ arg = None
+ if isinstance(key, tuple) and 2 == len(key):
+ key, arg = key
+ if not isinstance(arg, bool):
+ arg = None
+
if isinstance(key, (int, long)):
# Item is integer, treat as show id
if key not in self.shows:
- self._get_show_data(key, self.config['language'], True)
+ self._get_show_data(key, self.config['language'], (True, arg)[arg is not None])
return None if key not in self.shows else self.shows[key]
key = str(key).lower()
diff --git a/lib/tvrage_api/tvrage_api.py b/lib/tvrage_api/tvrage_api.py
index 6700fb1c..23a70292 100644
--- a/lib/tvrage_api/tvrage_api.py
+++ b/lib/tvrage_api/tvrage_api.py
@@ -657,10 +657,16 @@ class TVRage:
"""Handles tvrage_instance['seriesname'] calls.
The dict index should be the show id
"""
+ arg = None
+ if isinstance(key, tuple) and 2 == len(key):
+ key, arg = key
+ if not isinstance(arg, bool):
+ arg = None
+
if isinstance(key, (int, long)):
# Item is integer, treat as show id
if key not in self.shows:
- self._getShowData(key, True)
+ self._getShowData(key, (True, arg)[arg is not None])
return None if key not in self.shows else self.shows[key]
key = key.lower()
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py
index 9bb2ba00..f76873fb 100755
--- a/sickbeard/__init__.py
+++ b/sickbeard/__init__.py
@@ -89,7 +89,6 @@ background_mapping_task = None
showList = None
UPDATE_SHOWS_ON_START = False
SHOW_UPDATE_HOUR = 3
-ALLOW_INCOMPLETE_SHOWDATA = False
providerList = []
newznabProviderList = []
@@ -514,7 +513,7 @@ def initialize(consoleLogging=True):
PLEX_UPDATE_LIBRARY, PLEX_SERVER_HOST, PLEX_HOST, PLEX_USERNAME, PLEX_PASSWORD, \
USE_TRAKT, TRAKT_CONNECTED_ACCOUNT, TRAKT_ACCOUNTS, TRAKT_MRU, TRAKT_VERIFY, TRAKT_REMOVE_WATCHLIST, TRAKT_TIMEOUT, TRAKT_USE_WATCHLIST, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, traktCheckerScheduler, TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, TRAKT_REMOVE_SERIESLIST, TRAKT_UPDATE_COLLECTION, \
BACKLOG_FREQUENCY, DEFAULT_BACKLOG_FREQUENCY, MIN_BACKLOG_FREQUENCY, MAX_BACKLOG_FREQUENCY, BACKLOG_STARTUP, SKIP_REMOVED_FILES, \
- showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, HOME_SEARCH_FOCUS, SORT_ARTICLE, showList, loadingShowList, UPDATE_SHOWS_ON_START, SHOW_UPDATE_HOUR, ALLOW_INCOMPLETE_SHOWDATA, \
+ showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, HOME_SEARCH_FOCUS, SORT_ARTICLE, showList, loadingShowList, UPDATE_SHOWS_ON_START, SHOW_UPDATE_HOUR, \
NEWZNAB_DATA, INDEXER_DEFAULT, INDEXER_TIMEOUT, USENET_RETENTION, TORRENT_DIR, \
QUALITY_DEFAULT, FLATTEN_FOLDERS_DEFAULT, SUBTITLES_DEFAULT, STATUS_DEFAULT, WANTED_BEGIN_DEFAULT, WANTED_LATEST_DEFAULT, RECENTSEARCH_STARTUP, \
GROWL_NOTIFY_ONSNATCH, GROWL_NOTIFY_ONDOWNLOAD, GROWL_NOTIFY_ONSUBTITLEDOWNLOAD, TWITTER_NOTIFY_ONSNATCH, TWITTER_NOTIFY_ONDOWNLOAD, TWITTER_NOTIFY_ONSUBTITLEDOWNLOAD, \
@@ -666,7 +665,6 @@ def initialize(consoleLogging=True):
UPDATE_SHOWS_ON_START = bool(check_setting_int(CFG, 'General', 'update_shows_on_start', 0))
SHOW_UPDATE_HOUR = check_setting_int(CFG, 'General', 'show_update_hour', 3)
SHOW_UPDATE_HOUR = minimax(SHOW_UPDATE_HOUR, 3, 0, 23)
- ALLOW_INCOMPLETE_SHOWDATA = bool(check_setting_int(CFG, 'General', 'allow_incomplete_showdata', 0))
TRASH_REMOVE_SHOW = bool(check_setting_int(CFG, 'General', 'trash_remove_show', 0))
TRASH_ROTATE_LOGS = bool(check_setting_int(CFG, 'General', 'trash_rotate_logs', 0))
@@ -1524,7 +1522,6 @@ def save_config():
new_config['General']['launch_browser'] = int(LAUNCH_BROWSER)
new_config['General']['update_shows_on_start'] = int(UPDATE_SHOWS_ON_START)
new_config['General']['show_update_hour'] = int(SHOW_UPDATE_HOUR)
- new_config['General']['allow_incomplete_showdata'] = int(ALLOW_INCOMPLETE_SHOWDATA)
new_config['General']['trash_remove_show'] = int(TRASH_REMOVE_SHOW)
new_config['General']['trash_rotate_logs'] = int(TRASH_ROTATE_LOGS)
new_config['General']['home_search_focus'] = int(HOME_SEARCH_FOCUS)
diff --git a/sickbeard/show_queue.py b/sickbeard/show_queue.py
index 7549317c..b205beab 100644
--- a/sickbeard/show_queue.py
+++ b/sickbeard/show_queue.py
@@ -296,7 +296,7 @@ class QueueItemAdd(ShowQueueItem):
logger.log(u'' + str(sickbeard.indexerApi(self.indexer).name) + ': ' + repr(lINDEXER_API_PARMS))
t = sickbeard.indexerApi(self.indexer).indexer(**lINDEXER_API_PARMS)
- s = t[self.indexer_id]
+ s = t[self.indexer_id, False]
# this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that has no proper english version of the show
if getattr(s, 'seriesname', None) is None:
@@ -307,14 +307,6 @@ class QueueItemAdd(ShowQueueItem):
(self.showDir, sickbeard.indexerApi(self.indexer).name))
self._finishEarly()
return
- # if the show has no episodes/seasons
- if not sickbeard.ALLOW_INCOMPLETE_SHOWDATA and not s:
- msg = 'Show %s is on %s but contains no season/episode data. Only the show folder was created.'\
- % (s['seriesname'], sickbeard.indexerApi(self.indexer).name)
- logger.log(msg, logger.ERROR)
- ui.notifications.error('Unable to add show', msg)
- self._finishEarly()
- return
except Exception as e:
logger.log('Unable to find show ID:%s on Indexer: %s' % (self.indexer_id, sickbeard.indexerApi(self.indexer).name),
logger.ERROR)
diff --git a/sickbeard/tv.py b/sickbeard/tv.py
index 29802cf2..028411bb 100644
--- a/sickbeard/tv.py
+++ b/sickbeard/tv.py
@@ -559,6 +559,8 @@ class TVShow(object):
if self.dvdorder != 0:
lINDEXER_API_PARMS['dvdorder'] = True
+ logger.log('%s: Loading all episodes from %s..' % (self.indexerid, sickbeard.indexerApi(self.indexer).name))
+
try:
t = sickbeard.indexerApi(self.indexer).indexer(**lINDEXER_API_PARMS)
showObj = t[self.indexerid]
@@ -567,8 +569,6 @@ class TVShow(object):
(sickbeard.indexerApi(self.indexer).name, sickbeard.indexerApi(self.indexer).name), logger.ERROR)
return None
- logger.log('%s: Loading all episodes from %s..' % (self.indexerid, sickbeard.indexerApi(self.indexer).name))
-
scannedEps = {}
sql_l = []
@@ -912,7 +912,7 @@ class TVShow(object):
else:
t = tvapi
- myEp = t[self.indexerid]
+ myEp = t[self.indexerid, False]
if None is myEp:
logger.log('Show not found (maybe even removed?)', logger.WARNING)
return False
@@ -931,7 +931,7 @@ class TVShow(object):
self.imdbid = getattr(myEp, 'imdb_id', '')
if getattr(myEp, 'airs_dayofweek', None) is not None and getattr(myEp, 'airs_time', None) is not None:
- self.airs = myEp["airs_dayofweek"] + " " + myEp["airs_time"]
+ self.airs = ('%s %s' % (myEp['airs_dayofweek'], myEp['airs_time'])).strip()
if getattr(myEp, 'firstaired', None) is not None:
self.startyear = int(str(myEp["firstaired"]).split('-')[0])
@@ -1076,15 +1076,15 @@ class TVShow(object):
for path, dirs, files in ek.ek(os.walk, image_cache_dir):
for filename in ek.ek(fnmatch.filter, files, '%s.*' % self.indexerid):
cache_file = ek.ek(os.path.join, path, filename)
- logger.log('Attempt to %s cache file %s' % (action, cache_file))
- try:
- if sickbeard.TRASH_REMOVE_SHOW:
- send2trash(cache_file)
- else:
- os.remove(cache_file)
+ logger.log('Attempt to %s cache file %s' % (action, cache_file))
+ try:
+ if sickbeard.TRASH_REMOVE_SHOW:
+ send2trash(cache_file)
+ else:
+ os.remove(cache_file)
- except OSError as e:
- logger.log('Unable to %s %s: %s / %s' % (action, cache_file, repr(e), str(e)), logger.WARNING)
+ except OSError as e:
+ logger.log('Unable to %s %s: %s / %s' % (action, cache_file, repr(e), str(e)), logger.WARNING)
# remove entire show folder
if full:
@@ -1771,15 +1771,7 @@ class TVEpisode(object):
self.deleteEpisode()
return
- if not sickbeard.ALLOW_INCOMPLETE_SHOWDATA and None is getattr(myEp, 'episodename', None):
- logger.log('This episode (%s - %sx%s) has no name on %s' %
- (self.show.name, season, episode, sickbeard.indexerApi(self.indexer).name))
- # if I'm incomplete on TVDB but I once was complete then just delete myself from the DB for now
- if -1 != self.indexerid:
- self.deleteEpisode()
- return False
-
- if None is getattr(myEp, 'absolute_number', None):
+ if getattr(myEp, 'absolute_number', None) in (None, ''):
logger.log('This episode (%s - %sx%s) has no absolute number on %s' %
(self.show.name, season, episode, sickbeard.indexerApi(self.indexer).name), logger.DEBUG)
else:
@@ -1827,8 +1819,7 @@ class TVEpisode(object):
self.indexerid = getattr(myEp, 'id', None)
if None is self.indexerid:
logger.log('Failed to retrieve ID from %s' % sickbeard.indexerApi(self.indexer).name, logger.ERROR)
- if -1 != self.indexerid:
- self.deleteEpisode()
+ self.deleteEpisode()
return False
# don't update show status if show dir is missing, unless it's missing on purpose
@@ -2060,42 +2051,26 @@ class TVEpisode(object):
logger.log('%s: Not creating SQL queue - record is not dirty' % self.show.indexerid, logger.DEBUG)
return
- myDB = db.DBConnection()
- rows = myDB.select(
- 'SELECT episode_id FROM tv_episodes WHERE showid = ? AND indexer=? AND season = ? AND episode = ?',
- [self.show.indexerid, self.show.indexer, self.season, self.episode])
-
- epID = None
- if rows:
- epID = int(rows[0]['episode_id'])
-
self.dirty = False
- if epID:
- # use a custom update method to get the data into the DB for existing records.
- return [
- 'UPDATE tv_episodes SET indexerid = ?, indexer = ?, name = ?, description = ?, subtitles = ?, '
- 'subtitles_searchcount = ?, subtitles_lastsearch = ?, airdate = ?, hasnfo = ?, hastbn = ?, status = ?, '
- 'location = ?, file_size = ?, release_name = ?, is_proper = ?, showid = ?, season = ?, episode = ?, '
- 'absolute_number = ?, version = ?, release_group = ? WHERE episode_id = ?',
- [self.indexerid, self.indexer, self.name, self.description, ",".join([sub for sub in self.subtitles]),
- self.subtitles_searchcount, self.subtitles_lastsearch, self.airdate.toordinal(), self.hasnfo,
- self.hastbn,
- self.status, self.location, self.file_size, self.release_name, self.is_proper, self.show.indexerid,
- self.season, self.episode, self.absolute_number, self.version, self.release_group, epID]]
- else:
- # use a custom insert method to get the data into the DB.
- return [
- 'INSERT OR IGNORE INTO tv_episodes (episode_id, indexerid, indexer, name, description, subtitles, '
- 'subtitles_searchcount, subtitles_lastsearch, airdate, hasnfo, hastbn, status, location, file_size, '
- 'release_name, is_proper, showid, season, episode, absolute_number, version, release_group) VALUES '
- '((SELECT episode_id FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?)'
- ',?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);',
- [self.show.indexerid, self.season, self.episode, self.indexerid, self.indexer, self.name,
- self.description,
- ",".join([sub for sub in self.subtitles]), self.subtitles_searchcount, self.subtitles_lastsearch,
- self.airdate.toordinal(), self.hasnfo, self.hastbn, self.status, self.location, self.file_size,
- self.release_name, self.is_proper, self.show.indexerid, self.season, self.episode,
- self.absolute_number, self.version, self.release_group]]
+ return [
+ 'INSERT OR REPLACE INTO tv_episodes (episode_id, indexerid, indexer, name, description, subtitles, '
+ 'subtitles_searchcount, subtitles_lastsearch, airdate, hasnfo, hastbn, status, location, file_size, '
+ 'release_name, is_proper, showid, season, episode, absolute_number, version, release_group, '
+ 'scene_absolute_number, scene_season, scene_episode) VALUES '
+ '((SELECT episode_id FROM tv_episodes WHERE indexer = ? AND showid = ? AND season = ? AND episode = ?)'
+ ',?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,'
+ '(SELECT scene_absolute_number FROM tv_episodes WHERE indexer = ? AND showid = ? AND season = ? AND episode = ?),'
+ '(SELECT scene_season FROM tv_episodes WHERE indexer = ? AND showid = ? AND season = ? AND episode = ?),'
+ '(SELECT scene_episode FROM tv_episodes WHERE indexer = ? AND showid = ? AND season = ? AND episode = ?));',
+ [self.show.indexer, self.show.indexerid, self.season, self.episode, self.indexerid, self.indexer, self.name,
+ self.description,
+ ",".join([sub for sub in self.subtitles]), self.subtitles_searchcount, self.subtitles_lastsearch,
+ self.airdate.toordinal(), self.hasnfo, self.hastbn, self.status, self.location, self.file_size,
+ self.release_name, self.is_proper, self.show.indexerid, self.season, self.episode,
+ self.absolute_number, self.version, self.release_group,
+ self.show.indexer, self.show.indexerid, self.season, self.episode,
+ self.show.indexer, self.show.indexerid, self.season, self.episode,
+ self.show.indexer, self.show.indexerid, self.season, self.episode]]
def saveToDB(self, forceSave=False):
"""
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index 51a17475..b6a3f81c 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -2368,11 +2368,11 @@ class NewHomeAddShows(Home):
logger.log('Fetching show using id: %s (%s) from tv datasource %s' % (
search_id, search_term, sickbeard.indexerApi(indexer).name), logger.DEBUG)
results.setdefault('tt' in search_id and 3 or indexer, []).extend(
- [{'id': indexer_id, 'seriesname': t[indexer_id]['seriesname'],
- 'firstaired': t[indexer_id]['firstaired'], 'network': t[indexer_id]['network'],
- 'overview': t[indexer_id]['overview'],
- 'genres': '' if not t[indexer_id]['genre'] else
- t[indexer_id]['genre'].lower().strip('|').replace('|', ', '),
+ [{'id': indexer_id, 'seriesname': t[indexer_id, False]['seriesname'],
+ 'firstaired': t[indexer_id, False]['firstaired'], 'network': t[indexer_id, False]['network'],
+ 'overview': t[indexer_id, False]['overview'],
+ 'genres': '' if not t[indexer_id, False]['genre'] else
+ t[indexer_id, False]['genre'].lower().strip('|').replace('|', ', '),
}])
break
else:
@@ -4305,7 +4305,7 @@ class ConfigGeneral(Config):
return m.hexdigest()
def saveGeneral(self, log_dir=None, web_port=None, web_log=None, encryption_version=None, web_ipv6=None,
- update_shows_on_start=None, show_update_hour=None, allow_incomplete_showdata=None,
+ update_shows_on_start=None, show_update_hour=None,
trash_remove_show=None, trash_rotate_logs=None, update_frequency=None, launch_browser=None, web_username=None,
use_api=None, api_key=None, indexer_default=None, timezone_display=None, cpu_preset=None, file_logging_preset=None,
web_password=None, version_notify=None, enable_https=None, https_cert=None, https_key=None,
@@ -4327,7 +4327,6 @@ class ConfigGeneral(Config):
sickbeard.UPDATE_SHOWS_ON_START = config.checkbox_to_value(update_shows_on_start)
sickbeard.SHOW_UPDATE_HOUR = config.minimax(show_update_hour, 3, 0, 23)
- sickbeard.ALLOW_INCOMPLETE_SHOWDATA = config.checkbox_to_value(allow_incomplete_showdata)
sickbeard.TRASH_REMOVE_SHOW = config.checkbox_to_value(trash_remove_show)
sickbeard.TRASH_ROTATE_LOGS = config.checkbox_to_value(trash_rotate_logs)
config.change_UPDATE_FREQUENCY(update_frequency)