Fixed issues with TVDB retrieving banners and posters.

Fixed unicode issues with Indexer API's
Fixed issues with scene numbering.
Fixed issues with black and white lists for anime shows when editing a show.
This commit is contained in:
echel0n 2014-05-29 06:27:05 -07:00
parent 4a4eec0a9e
commit e1ee01579d
6 changed files with 127 additions and 76 deletions

View File

@ -3,6 +3,7 @@
#from sickbeard import common
#from sickbeard import exceptions
#from sickbeard import scene_exceptions
#from sickbeard.blackandwhitelist import *
#set global $title="Edit " + $show.name
#set global $header=$show.name
@ -170,6 +171,7 @@ Realease Groups:
<br/>
<input id="addW" value="&lt;&lt; Add" type="button"/>
<input id="addB" value="Add &gt;&gt;" type="button"/>
<input id="removeP" value="Remove" type="button"/>
</div>
<div class="blackwhiteliste black">
@ -198,13 +200,26 @@ Realease Groups:
\$('#submit').click(function(){
all_exceptions = []
\$("#exceptions_list option").each ( function() {
all_exceptions.push( \$(this).val() );
});
\$("#exceptions_list").val(all_exceptions);
var realvalues = [];
\$('#white option').each(function(i, selected) {
realvalues[i] = \$(selected).val();
});
\$("#whitelist").val(realvalues.join(","));
realvalues = [];
\$('#black option').each(function(i, selected) {
realvalues[i] = \$(selected).val();
});
\$("#blacklist").val(realvalues.join(","));
});
\$('#addSceneName').click(function() {
@ -247,8 +262,45 @@ Realease Groups:
\$("#SceneException").show();
}
\$(this).toggle_SceneException();
\$(this).toggle_SceneException();
\$('#removeW').click(function() {
return !\$('#white option:selected').remove().appendTo('#pool');
});
\$('#addW').click(function() {
return !\$('#pool option:selected').remove().appendTo('#white');
});
\$('#addB').click(function() {
return !\$('#pool option:selected').remove().appendTo('#black');
});
\$('#removeP').click(function() {
return !\$('#pool option:selected').remove();
});
\$('#removeB').click(function() {
return !\$('#black option:selected').remove().appendTo('#pool');
});
\$('#addToWhite').click(function() {
var group = \$('#addToPoolText').attr("value")
if(group == "")
return
\$('#addToPoolText').attr("value", "")
var option = \$("<option>")
option.attr("value",group)
option.html(group)
return option.appendTo('#white');
});
\$('#addToBlack').click(function() {
var group = \$('#addToPoolText').attr("value")
if(group == "")
return
\$('#addToPoolText').attr("value", "")
var option = \$("<option>")
option.attr("value",group)
option.html(group)
return option.appendTo('#black');
});
//-->
</script>

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python2
# !/usr/bin/env python2
#encoding:utf-8
#author:dbr/Ben
#project:tvdb_api
@ -41,9 +41,11 @@ from tvdb_ui import BaseUI, ConsoleUI
from tvdb_exceptions import (tvdb_error, tvdb_userabort, tvdb_shownotfound,
tvdb_seasonnotfound, tvdb_episodenotfound, tvdb_attributenotfound)
def log():
return logging.getLogger("tvdb_api")
def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
"""Retry calling the decorated function using an exponential backoff.
@ -87,6 +89,7 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
return deco_retry
class ShowContainer(dict):
"""Simple dict that holds a series of Show instances
"""
@ -569,18 +572,6 @@ class Tvdb:
# clean up value and do type changes
if value:
try:
# convert to integer if needed
if value.isdigit():
value = int(value)
except:
pass
if key in ['banner', 'fanart', 'poster']:
value = self.config['url_artworkPrefix'] % (value)
else:
value = self._cleanData(value)
try:
if key == 'firstaired' and value in "0000-00-00":
new_value = str(dt.date.fromordinal(1))
@ -590,10 +581,13 @@ class Tvdb:
elif key == 'firstaired':
value = parse(value, fuzzy=True).date()
value = value.strftime("%Y-%m-%d")
if key == 'airs_time':
value = parse(value).time()
value = value.strftime("%I:%M")
except:
pass
value = self._cleanData(value)
return (key, value)
if resp.ok:
@ -604,11 +598,11 @@ class Tvdb:
zipdata = StringIO.StringIO()
zipdata.write(resp.content)
myzipfile = zipfile.ZipFile(zipdata)
return xmltodict.parse(myzipfile.read('%s.xml' % language), postprocessor=process)
return xmltodict.parse(myzipfile.read('%s.xml' % language).strip(), postprocessor=process)
except zipfile.BadZipfile:
raise tvdb_error("Bad zip file received from thetvdb.com, could not read it")
else:
return xmltodict.parse(resp.text.strip(), postprocessor=process)
return xmltodict.parse(resp.content.strip(), postprocessor=process)
def _getetsrc(self, url, params=None, language=None):
"""Loads a URL using caching, returns an ElementTree of the source
@ -667,9 +661,8 @@ class Tvdb:
- Replaces &amp; with &
- Trailing whitespace
"""
if isinstance(data, str):
data = data.replace(u"&amp;", u"&")
data = data.strip()
data = data.replace(u"&amp;", u"&")
data = data.strip()
return data
def search(self, series):
@ -729,13 +722,12 @@ class Tvdb:
log().debug('Getting season banners for %s' % (sid))
bannersEt = self._getetsrc(self.config['url_seriesBanner'] % (sid))
banners = {}
for cur_banner in bannersEt.findall('Banner'):
bid = cur_banner.find('id').text
btype = cur_banner.find('BannerType')
btype2 = cur_banner.find('BannerType2')
for cur_banner in bannersEt['banner']:
bid = cur_banner['id']
btype = cur_banner['bannertype']
btype2 = cur_banner['bannertype2']
if btype is None or btype2 is None:
continue
btype, btype2 = btype.text, btype2.text
if not btype in banners:
banners[btype] = {}
if not btype2 in banners[btype]:
@ -743,13 +735,12 @@ class Tvdb:
if not bid in banners[btype][btype2]:
banners[btype][btype2][bid] = {}
for cur_element in cur_banner.getchildren():
tag = cur_element.tag.lower()
value = cur_element.text
if tag is None or value is None:
for k, v in cur_banner.items():
if k is None or v is None:
continue
tag, value = tag.lower(), value.lower()
banners[btype][btype2][bid][tag] = value
k, v = k.lower(), v.lower()
banners[btype][btype2][bid][k] = v
for k, v in banners[btype][btype2][bid].items():
if k.endswith("path"):
@ -788,17 +779,16 @@ class Tvdb:
actorsEt = self._getetsrc(self.config['url_actorsInfo'] % (sid))
cur_actors = Actors()
for curActorItem in actorsEt.findall("Actor"):
for curActorItem in actorsEt["actor"]:
curActor = Actor()
for curInfo in curActorItem:
tag = curInfo.tag.lower()
value = curInfo.text
if value is not None:
if tag == "image":
value = self.config['url_artworkPrefix'] % (value)
for k, v in curActorItem.items():
k = k.lower()
if v is not None:
if k == "image":
v = self.config['url_artworkPrefix'] % (v)
else:
value = self._cleanData(value)
curActor[tag] = value
v = self._cleanData(v)
curActor[k] = v
cur_actors.append(curActor)
self._setShowData(sid, '_actors', cur_actors)
@ -833,6 +823,12 @@ class Tvdb:
return False
for k, v in seriesInfoEt['series'].items():
if v is not None:
if k in ['banner', 'fanart', 'poster']:
v = self.config['url_artworkPrefix'] % (v)
else:
v = self._cleanData(v)
self._setShowData(sid, k, v)
if seriesSearch:
@ -871,25 +867,22 @@ class Tvdb:
if seasnum is None or epno is None:
log().warning("An episode has incomplete season/episode number (season: %r, episode: %r)" % (
seasnum, epno))
continue # Skip to next episode
continue # Skip to next episode
# float() is because https://github.com/dbr/tvnamer/issues/95 - should probably be fixed in TVDB data
seas_no = int(float(seasnum))
ep_no = int(float(epno))
for k,v in cur_ep.items():
for k, v in cur_ep.items():
k = k.lower()
if v is not None:
if k == 'id':
v = int(v)
if k == 'filename':
v = self.config['url_artworkPrefix'] % (v)
else:
v = self._cleanData(v)
self._setItem(sid, seas_no, ep_no, k, v)
self._setItem(sid, seas_no, ep_no, k, v)
return True
@ -906,7 +899,8 @@ class Tvdb:
selected_series = self._getSeries(name)
if isinstance(selected_series, dict):
selected_series = [selected_series]
sids = list(int(x['id']) for x in selected_series if self._getShowData(int(x['id']), self.config['language'], seriesSearch=True))
sids = list(int(x['id']) for x in selected_series if
self._getShowData(int(x['id']), self.config['language'], seriesSearch=True))
self.corrections.update(dict((x['seriesname'], int(x['id'])) for x in selected_series))
return sids
@ -925,7 +919,7 @@ class Tvdb:
selected_series = self._getSeries(key)
if isinstance(selected_series, dict):
selected_series = [selected_series]
[[self._setShowData(show['id'], k, v) for k,v in show.items()] for show in selected_series]
[[self._setShowData(show['id'], k, v) for k, v in show.items()] for show in selected_series]
return selected_series
#test = self._getSeries(key)
#sids = self._nameToSid(key)

View File

@ -431,10 +431,14 @@ class TVRage:
try:
key = name_map[key.lower()]
except (ValueError, TypeError, KeyError):
key.lower()
key = key.lower()
# clean up value and do type changes
if value:
if key == 'link':
value = value.rsplit('/', 1)[1]
key = 'id'
if isinstance(value, dict):
if key == 'network':
value = value['#text']
@ -444,13 +448,6 @@ class TVRage:
value = [value]
value = '|' + '|'.join(value) + '|'
try:
# convert to integer if needed
if value.isdigit():
value = int(value)
except:
pass
try:
if key == 'firstaired' and value in "0000-00-00":
new_value = str(dt.date.fromordinal(1))
@ -460,14 +457,17 @@ class TVRage:
elif key == 'firstaired':
value = parse(value, fuzzy=True).date()
value = value.strftime("%Y-%m-%d")
if key == 'airs_time':
value = parse(value).time()
value = value.strftime("%I:%M")
except:
pass
value = self._cleanData(value)
return (key, value)
if resp.ok:
return xmltodict.parse(resp.text.strip(), postprocessor=remap_keys)
return xmltodict.parse(resp.content.strip(), postprocessor=remap_keys)
def _getetsrc(self, url, params=None):
"""Loads a URL using caching, returns an ElementTree of the source
@ -526,9 +526,8 @@ class TVRage:
- Replaces &amp; with &
- Trailing whitespace
"""
if isinstance(data, str):
data = data.replace(u"&amp;", u"&")
data = data.strip()
data = data.replace(u"&amp;", u"&")
data = data.strip()
return data
def search(self, series):
@ -582,6 +581,9 @@ class TVRage:
return False
for k, v in seriesInfoEt.items():
if v is not None:
v = self._cleanData(v)
self._setShowData(sid, k, v)
# series search ends here
@ -608,13 +610,6 @@ class TVRage:
try:
k = k.lower()
if v is not None:
if k == 'link':
v = v.rsplit('/', 1)[1]
k = 'id'
if k == 'id':
v = int(v)
v = self._cleanData(v)
self._setItem(sid, seas_no, ep_no, k, v)

View File

@ -133,7 +133,7 @@ def get_absolute_numbering(indexer_id, indexer, sceneAbsoluteNumber, fallback_to
return (int(rows[0]["season"]), int(rows[0]["episode"]), int(rows[0]["absolute_number"]))
else:
if fallback_to_xem:
return get_indexer_numbering_for_xem(indexer_id, indexer, sceneAbsoluteNumber)
return get_absolute_numbering_for_xem(indexer_id, indexer, sceneAbsoluteNumber)
return (None, None, None)
def get_scene_numbering_for_show(indexer_id, indexer):

View File

@ -367,6 +367,10 @@ class QueueItemAdd(ShowQueueItem):
myDB.action("UPDATE tv_episodes SET status = ? WHERE status = ? AND showid = ? AND season != 0",
[self.default_status, SKIPPED, self.show.indexerid])
# Load XEM data to DB for show
if sickbeard.scene_numbering.xem_refresh_needed(self.show.indexerid, self.show.indexer):
sickbeard.scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer)
# if they started with WANTED eps then run the backlog
if self.default_status == WANTED:
logger.log(u"Launching backlog for this show since its episodes are WANTED")
@ -404,7 +408,6 @@ class QueueItemRefresh(ShowQueueItem):
self.show.refreshDir()
self.show.writeMetadata()
#self.show.updateMetadata()
self.show.populateCache()
self.inProgress = False
@ -418,6 +421,9 @@ class QueueItemRename(ShowQueueItem):
ShowQueueItem.execute(self)
# Load XEM data to DB for show
sickbeard.scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer)
logger.log(u"Performing rename on " + self.show.name)
try:
@ -476,6 +482,9 @@ class QueueItemUpdate(ShowQueueItem):
logger.log(u"Beginning update of " + self.show.name)
# Load XEM data to DB for show
sickbeard.scene_numbering.xem_refresh(self.show.indexerid, self.show.indexer)
logger.log(u"Retrieving show info from " + sickbeard.indexerApi(self.show.indexer).name + "", logger.DEBUG)
try:
self.show.loadFromIndexer(cache=not self.force)

View File

@ -812,8 +812,7 @@ class TVShow(object):
myEp = t[self.indexerid]
try:
if getattr(myEp, 'seriesname', None) is not None:
self.name = myEp['seriesname'].strip()
self.name = myEp['seriesname'].strip()
except AttributeError:
raise sickbeard.indexer_attributenotfound(
"Found %s, but attribute 'seriesname' was empty." % (self.indexerid))
@ -935,7 +934,9 @@ class TVShow(object):
sql_l = [["DELETE FROM tv_episodes WHERE showid = ?", [self.indexerid]],
["DELETE FROM tv_shows WHERE indexer_id = ?", [self.indexerid]],
["DELETE FROM imdb_info WHERE indexer_id = ?", [self.indexerid]]]
["DELETE FROM imdb_info WHERE indexer_id = ?", [self.indexerid]],
["DELETE FROM xem_refresh WHERE indexer_id = ?", [self.indexerid]],
["DELETE FROM scene_numbering WHERE indexer_id = ?", [self.indexerid]]]
myDB.mass_action(sql_l)