mirror of
https://github.com/moparisthebest/SickRage
synced 2024-10-31 15:35:01 -04:00
831248b412
Fixed issues with Backup/Restore. Fixed issues with banners, posters, images via showPoster method. Fixed issues with WebAPI apikeys. Fixed issues with WebUI and url pattern matching.
361 lines
14 KiB
Python
361 lines
14 KiB
Python
# Author: Nic Wolfe <nic@wolfeden.ca>
|
|
# URL: http://code.google.com/p/sickbeard/
|
|
#
|
|
# This file is part of SickRage.
|
|
#
|
|
# SickRage is free software: you can redistribute it and/or modify
|
|
# 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.
|
|
#
|
|
# SickRage is distributed in the hope that it will be useful,
|
|
# 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
|
|
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import datetime
|
|
|
|
import sickbeard
|
|
|
|
import mediabrowser
|
|
|
|
from sickbeard import logger, exceptions, helpers
|
|
from sickbeard.exceptions import ex
|
|
|
|
try:
|
|
import xml.etree.cElementTree as etree
|
|
except ImportError:
|
|
import elementtree.ElementTree as etree
|
|
|
|
|
|
class Mede8erMetadata(mediabrowser.MediaBrowserMetadata):
|
|
"""
|
|
Metadata generation class for Mede8er based on the MediaBrowser.
|
|
|
|
The following file structure is used:
|
|
|
|
show_root/series.xml (show metadata)
|
|
show_root/folder.jpg (poster)
|
|
show_root/fanart.jpg (fanart)
|
|
show_root/Season ##/folder.jpg (season thumb)
|
|
show_root/Season ##/filename.ext (*)
|
|
show_root/Season ##/filename.xml (episode metadata)
|
|
show_root/Season ##/filename.jpg (episode thumb)
|
|
"""
|
|
|
|
def __init__(self,
|
|
show_metadata=False,
|
|
episode_metadata=False,
|
|
fanart=False,
|
|
poster=False,
|
|
banner=False,
|
|
episode_thumbnails=False,
|
|
season_posters=False,
|
|
season_banners=False,
|
|
season_all_poster=False,
|
|
season_all_banner=False):
|
|
|
|
mediabrowser.MediaBrowserMetadata.__init__(self,
|
|
show_metadata,
|
|
episode_metadata,
|
|
fanart,
|
|
poster,
|
|
banner,
|
|
episode_thumbnails,
|
|
season_posters,
|
|
season_banners,
|
|
season_all_poster,
|
|
season_all_banner)
|
|
|
|
self.name = "Mede8er"
|
|
|
|
self.fanart_name = "fanart.jpg"
|
|
|
|
# web-ui metadata template
|
|
# self.eg_show_metadata = "series.xml"
|
|
self.eg_episode_metadata = "Season##\\<i>filename</i>.xml"
|
|
self.eg_fanart = "fanart.jpg"
|
|
# self.eg_poster = "folder.jpg"
|
|
# self.eg_banner = "banner.jpg"
|
|
self.eg_episode_thumbnails = "Season##\\<i>filename</i>.jpg"
|
|
# self.eg_season_posters = "Season##\\folder.jpg"
|
|
# self.eg_season_banners = "Season##\\banner.jpg"
|
|
# self.eg_season_all_poster = "<i>not supported</i>"
|
|
# self.eg_season_all_banner = "<i>not supported</i>"
|
|
|
|
def get_episode_file_path(self, ep_obj):
|
|
return helpers.replaceExtension(ep_obj.location, self._ep_nfo_extension)
|
|
|
|
def get_episode_thumb_path(self, ep_obj):
|
|
return helpers.replaceExtension(ep_obj.location, 'jpg')
|
|
|
|
def _show_data(self, show_obj):
|
|
"""
|
|
Creates an elementTree XML structure for a MediaBrowser-style series.xml
|
|
returns the resulting data object.
|
|
|
|
show_obj: a TVShow instance to create the NFO for
|
|
"""
|
|
|
|
indexer_lang = show_obj.lang
|
|
lINDEXER_API_PARMS = sickbeard.indexerApi(show_obj.indexer).api_params.copy()
|
|
|
|
lINDEXER_API_PARMS['actors'] = True
|
|
|
|
if indexer_lang and not indexer_lang == 'en':
|
|
lINDEXER_API_PARMS['language'] = indexer_lang
|
|
|
|
if show_obj.dvdorder != 0:
|
|
lINDEXER_API_PARMS['dvdorder'] = True
|
|
|
|
t = sickbeard.indexerApi(show_obj.indexer).indexer(**lINDEXER_API_PARMS)
|
|
|
|
rootNode = etree.Element("details")
|
|
tv_node = etree.SubElement(rootNode, "movie")
|
|
tv_node.attrib["isExtra"] = "false"
|
|
tv_node.attrib["isSet"] = "false"
|
|
tv_node.attrib["isTV"] = "true"
|
|
|
|
try:
|
|
myShow = t[int(show_obj.indexerid)]
|
|
except sickbeard.indexer_shownotfound:
|
|
logger.log(u"Unable to find show with id " + str(show_obj.indexerid) + " on tvdb, skipping it", logger.ERROR)
|
|
raise
|
|
|
|
except sickbeard.indexer_error:
|
|
logger.log(u"TVDB is down, can't use its data to make the NFO", logger.ERROR)
|
|
raise
|
|
|
|
# check for title and id
|
|
try:
|
|
if myShow['seriesname'] == None or myShow['seriesname'] == "" or myShow['id'] == None or myShow['id'] == "":
|
|
logger.log(u"Incomplete info for show with id " + str(show_obj.indexerid) + " on tvdb, skipping it", logger.ERROR)
|
|
return False
|
|
except sickbeard.indexer_attributenotfound:
|
|
logger.log(u"Incomplete info for show with id " + str(show_obj.indexerid) + " on tvdb, skipping it", logger.ERROR)
|
|
return False
|
|
|
|
SeriesName = etree.SubElement(tv_node, "title")
|
|
if myShow['seriesname'] != None:
|
|
SeriesName.text = myShow['seriesname']
|
|
else:
|
|
SeriesName.text = ""
|
|
|
|
Genres = etree.SubElement(tv_node, "genres")
|
|
if myShow["genre"] != None:
|
|
for genre in myShow['genre'].split('|'):
|
|
if genre and genre.strip():
|
|
cur_genre = etree.SubElement(Genres, "Genre")
|
|
cur_genre.text = genre.strip()
|
|
|
|
FirstAired = etree.SubElement(tv_node, "premiered")
|
|
if myShow['firstaired'] != None:
|
|
FirstAired.text = myShow['firstaired']
|
|
|
|
year = etree.SubElement(tv_node, "year")
|
|
if myShow["firstaired"] != None:
|
|
try:
|
|
year_text = str(datetime.datetime.strptime(myShow["firstaired"], '%Y-%m-%d').year)
|
|
if year_text:
|
|
year.text = year_text
|
|
except:
|
|
pass
|
|
|
|
if myShow['rating'] != None:
|
|
try:
|
|
rating = int((float(myShow['rating']) * 10))
|
|
except ValueError:
|
|
rating = 0
|
|
Rating = etree.SubElement(tv_node, "rating")
|
|
rating_text = str(rating)
|
|
if rating_text != None:
|
|
Rating.text = rating_text
|
|
|
|
Status = etree.SubElement(tv_node, "status")
|
|
if myShow['status'] != None:
|
|
Status.text = myShow['status']
|
|
|
|
mpaa = etree.SubElement(tv_node, "mpaa")
|
|
if myShow["contentrating"] != None:
|
|
mpaa.text = myShow["contentrating"]
|
|
|
|
IMDB_ID = etree.SubElement(tv_node, "id")
|
|
if myShow['imdb_id'] != None:
|
|
IMDB_ID.attrib["moviedb"] = "imdb"
|
|
IMDB_ID.text = myShow['imdb_id']
|
|
|
|
indexerid = etree.SubElement(tv_node, "indexerid")
|
|
if myShow['id'] != None:
|
|
indexerid.text = myShow['id']
|
|
|
|
Runtime = etree.SubElement(tv_node, "runtime")
|
|
if myShow['runtime'] != None:
|
|
Runtime.text = myShow['runtime']
|
|
|
|
cast = etree.SubElement(tv_node, "cast")
|
|
|
|
if getattr(myShow, '_actors', None) is not None:
|
|
for actor in myShow['_actors']:
|
|
cur_actor_name_text = getattr(actor, 'name', None)
|
|
if cur_actor_name_text != None and cur_actor_name_text.strip():
|
|
cur_actor = etree.SubElement(cast, "actor")
|
|
cur_actor.text = cur_actor_name_text.strip()
|
|
|
|
helpers.indentXML(rootNode)
|
|
|
|
data = etree.ElementTree(rootNode)
|
|
|
|
return data
|
|
|
|
def _ep_data(self, ep_obj):
|
|
"""
|
|
Creates an elementTree XML structure for a MediaBrowser style episode.xml
|
|
and returns the resulting data object.
|
|
|
|
show_obj: a TVShow instance to create the NFO for
|
|
"""
|
|
|
|
eps_to_write = [ep_obj] + ep_obj.relatedEps
|
|
|
|
indexer_lang = ep_obj.show.lang
|
|
|
|
try:
|
|
# There's gotta be a better way of doing this but we don't wanna
|
|
# change the language value elsewhere
|
|
lINDEXER_API_PARMS = sickbeard.indexerApi(ep_obj.show.indexer).api_params.copy()
|
|
|
|
if indexer_lang and not indexer_lang == 'en':
|
|
lINDEXER_API_PARMS['language'] = indexer_lang
|
|
|
|
if ep_obj.show.dvdorder != 0:
|
|
lINDEXER_API_PARMS['dvdorder'] = True
|
|
|
|
t = sickbeard.indexerApi(ep_obj.show.indexer).indexer(**lINDEXER_API_PARMS)
|
|
myShow = t[ep_obj.show.indexerid]
|
|
except sickbeard.indexer_shownotfound, e:
|
|
raise exceptions.ShowNotFoundException(e.message)
|
|
except sickbeard.indexer_error, e:
|
|
logger.log(u"Unable to connect to TVDB while creating meta files - skipping - " + ex(e), logger.ERROR)
|
|
return False
|
|
|
|
rootNode = etree.Element("details")
|
|
movie = etree.SubElement(rootNode, "movie")
|
|
|
|
movie.attrib["isExtra"] = "false"
|
|
movie.attrib["isSet"] = "false"
|
|
movie.attrib["isTV"] = "true"
|
|
|
|
# write an MediaBrowser XML containing info for all matching episodes
|
|
for curEpToWrite in eps_to_write:
|
|
|
|
try:
|
|
myEp = myShow[curEpToWrite.season][curEpToWrite.episode]
|
|
except (sickbeard.indexer_episodenotfound, sickbeard.indexer_seasonnotfound):
|
|
logger.log(u"Unable to find episode " + str(curEpToWrite.season) + "x" + str(curEpToWrite.episode) + " on tvdb... has it been removed? Should I delete from db?")
|
|
return None
|
|
|
|
if curEpToWrite == ep_obj:
|
|
# root (or single) episode
|
|
|
|
# default to today's date for specials if firstaired is not set
|
|
if myEp['firstaired'] == None and ep_obj.season == 0:
|
|
myEp['firstaired'] = str(datetime.date.fromordinal(1))
|
|
|
|
if myEp['episodename'] == None or myEp['firstaired'] == None:
|
|
return None
|
|
|
|
episode = movie
|
|
|
|
EpisodeName = etree.SubElement(episode, "title")
|
|
if curEpToWrite.name != None:
|
|
EpisodeName.text = curEpToWrite.name
|
|
else:
|
|
EpisodeName.text = ""
|
|
|
|
SeasonNumber = etree.SubElement(episode, "season")
|
|
SeasonNumber.text = str(curEpToWrite.season)
|
|
|
|
EpisodeNumber = etree.SubElement(episode, "episode")
|
|
EpisodeNumber.text = str(ep_obj.episode)
|
|
|
|
year = etree.SubElement(episode, "year")
|
|
if myShow["firstaired"] != None:
|
|
try:
|
|
year_text = str(datetime.datetime.strptime(myShow["firstaired"], '%Y-%m-%d').year)
|
|
if year_text:
|
|
year.text = year_text
|
|
except:
|
|
pass
|
|
|
|
plot = etree.SubElement(episode, "plot")
|
|
if myShow["overview"] != None:
|
|
plot.text = myShow["overview"]
|
|
|
|
Overview = etree.SubElement(episode, "episodeplot")
|
|
if curEpToWrite.description != None:
|
|
Overview.text = curEpToWrite.description
|
|
else:
|
|
Overview.text = ""
|
|
|
|
mpaa = etree.SubElement(episode, "mpaa")
|
|
if myShow["contentrating"] != None:
|
|
mpaa.text = myShow["contentrating"]
|
|
|
|
if not ep_obj.relatedEps:
|
|
if myEp["rating"] != None:
|
|
try:
|
|
rating = int((float(myEp['rating']) * 10))
|
|
except ValueError:
|
|
rating = 0
|
|
Rating = etree.SubElement(episode, "rating")
|
|
rating_text = str(rating)
|
|
if rating_text != None:
|
|
Rating.text = rating_text
|
|
|
|
director = etree.SubElement(episode, "director")
|
|
director_text = myEp['director']
|
|
if director_text != None:
|
|
director.text = director_text
|
|
|
|
credits = etree.SubElement(episode, "credits")
|
|
credits_text = myEp['writer']
|
|
if credits_text != None:
|
|
credits.text = credits_text
|
|
|
|
cast = etree.SubElement(episode, "cast")
|
|
|
|
if getattr(myShow, '_actors', None) is not None:
|
|
for actor in myShow['_actors']:
|
|
cur_actor_name_text = actor['name']
|
|
|
|
if cur_actor_name_text != None and cur_actor_name_text.strip():
|
|
cur_actor = etree.SubElement(cast, "actor")
|
|
cur_actor.text = cur_actor_name_text.strip()
|
|
|
|
else:
|
|
# append data from (if any) related episodes
|
|
|
|
if curEpToWrite.name:
|
|
if not EpisodeName.text:
|
|
EpisodeName.text = curEpToWrite.name
|
|
else:
|
|
EpisodeName.text = EpisodeName.text + ", " + curEpToWrite.name
|
|
|
|
if curEpToWrite.description:
|
|
if not Overview.text:
|
|
Overview.text = curEpToWrite.description
|
|
else:
|
|
Overview.text = Overview.text + "\r" + curEpToWrite.description
|
|
|
|
helpers.indentXML(rootNode)
|
|
data = etree.ElementTree(rootNode)
|
|
|
|
return data
|
|
|
|
|
|
# present a standard "interface" from the module
|
|
metadata_class = Mede8erMetadata
|