@ -3,22 +3,26 @@ from couchpotato.core.helpers.encoding import simplifyString, toUnicode
from couchpotato . core . logger import CPLog
from couchpotato . core . logger import CPLog
from couchpotato . core . providers . show . base import ShowProvider
from couchpotato . core . providers . show . base import ShowProvider
from tvdb_api import tvdb_api , tvdb_exceptions
from tvdb_api import tvdb_api , tvdb_exceptions
from datetime import datetime
from datetime import datetime
import traceback
import traceback
log = CPLog ( __name__ )
log = CPLog ( __name__ )
# XXX: I return None in alot of functions when there is error or no value; check if I
# XXX: I return None in alot of functions when there is error or no value; check if I
# should be returning an empty list or dictionary
# should be returning an empty list or dictionary
# XXX: Consider grabbing zips to put less strain on tvdb
# XXX: Consider grabbing zips to put less strain on tvdb
# XXX: Consider a cache; not implenented everywhere yet or at all
# XXX: Consider a cache; not implenented everywhere yet or at all
# XXX: Search by language; now ists defualt of "en"
# XXX: alternate titles do exist for show and episodes; add them
# XXX: Unicode stuff
# XXX: we have a getShow function but it it being used?
class TheTVDb ( ShowProvider ) :
class TheTVDb ( ShowProvider ) :
def __init__ ( self ) :
def __init__ ( self ) :
#addEvent('show.by_hash', self.byHash)
#addEvent('show.by_hash', self.byHash)
addEvent ( ' show.search ' , self . search , priority = 1 )
addEvent ( ' show.search ' , self . search , priority = 1 )
addEvent ( ' show.info ' , self . getShowInfo , priority = 1 )
addEvent ( ' show.info ' , self . getShowInfo , priority = 1 )
addEvent ( ' show.episodes ' , self . getEpisodes , priority = 1 )
addEvent ( ' season.info ' , self . getSeasonInfo , priority = 1 )
addEvent ( ' episode.info ' , self . getEpisodeInfo , priority = 1 )
addEvent ( ' episode.info ' , self . getEpisodeInfo , priority = 1 )
#addEvent('show.info_by_thetvdb', self.getInfoByTheTVDBId)
#addEvent('show.info_by_thetvdb', self.getInfoByTheTVDBId)
@ -27,7 +31,7 @@ class TheTVDb(ShowProvider):
' apikey ' : " 7966C02F860586D2 " ,
' apikey ' : " 7966C02F860586D2 " ,
' banners ' : True
' banners ' : True
}
}
self . tvdb = tvdb_api . Tvdb ( * * tvdb_api_parms )
self . tvdb = tvdb_api . Tvdb ( * * tvdb_api_parms )
#def byHash(self, file):
#def byHash(self, file):
@ -62,7 +66,7 @@ class TheTVDb(ShowProvider):
#return results
#return results
def search ( self , q , limit = 12 ) :
def search ( self , q , limit = 12 ) :
''' Find show by name
''' Find show by name
show = { ' id ' : 74713 ,
show = { ' id ' : 74713 ,
' language ' : ' en ' ,
' language ' : ' en ' ,
' lid ' : 7 ,
' lid ' : 7 ,
@ -76,6 +80,7 @@ class TheTVDb(ShowProvider):
search_string = simplifyString ( q )
search_string = simplifyString ( q )
cache_key = ' thetvdb.cache. %s . %s ' % ( search_string , limit )
cache_key = ' thetvdb.cache. %s . %s ' % ( search_string , limit )
results = self . getCache ( cache_key )
results = self . getCache ( cache_key )
# TODO: cache is not returned
if not results :
if not results :
log . debug ( ' Searching for show: %s ' , q )
log . debug ( ' Searching for show: %s ' , q )
@ -83,7 +88,6 @@ class TheTVDb(ShowProvider):
raw = None
raw = None
try :
try :
raw = self . tvdb . search ( search_string )
raw = self . tvdb . search ( search_string )
except ( tvdb_exceptions . tvdb_error , IOError ) , e :
except ( tvdb_exceptions . tvdb_error , IOError ) , e :
log . error ( ' Failed searching TheTVDB for " %s " : %s ' , ( search_string , traceback . format_exc ( ) ) )
log . error ( ' Failed searching TheTVDB for " %s " : %s ' , ( search_string , traceback . format_exc ( ) ) )
return None
return None
@ -114,51 +118,107 @@ class TheTVDb(ShowProvider):
return results
return results
def getEpisodes ( self , identifier = None , episode_identifier = None ) :
def getShow ( self , identifier = None ) :
""" Either return a list of all episodes or a single episode.
show = None
If episode_identifer contains an episode to search for it will be returned if found
try :
log . debug ( ' Getting show: %s ' , identifier )
show = self . tvdb [ int ( identifier ) ]
except ( tvdb_exceptions . tvdb_error , IOError ) , e :
log . error ( ' Failed to getShowInfo for show id " %s " : %s ' , ( identifier , traceback . format_exc ( ) ) )
return None
return show
def getSeasonInfo ( self , identifier = None , season_identifier = None ) :
""" Either return a list of all seasons or a single season by number.
identifier is the show ' id '
"""
"""
if not identifier :
if not identifier :
return None
return None
# season_identifier must contain the 'show id : season number' since there is no tvdb id
# for season and we need a reference to both the show id and season number
if season_identifier :
try : season_identifier = int ( season_identifier . split ( ' : ' ) [ 1 ] )
except : return None
cache_key = ' thetvdb.cache. %s . %s ' % ( identifier , season_identifier )
log . debug ( ' Getting SeasonInfo: %s ' , cache_key )
result = self . getCache ( cache_key ) or { }
if result :
return result
try :
try :
show = self . tvdb [ int ( identifier ) ]
show = self . tvdb [ int ( identifier ) ]
except ( tvdb_exceptions . tvdb_error , IOError ) , e :
except ( tvdb_exceptions . tvdb_error , IOError ) , e :
log . error ( ' Failed parsing TheTVDB for " %s " id " %s " : %s ' , ( show , identifier , traceback . format_exc ( ) ) )
log . error ( ' Failed parsing TheTVDB SeasonInfo for " %s " id " %s " : %s ' , ( show , identifier , traceback . format_exc ( ) ) )
return None
return None
result = [ ]
result = [ ]
for season in show . values ( ) :
for number , season in show . items ( ) :
for episode in season . values ( ) :
if season_identifier is not None and number == season_identifier :
if episode_identifier :
result = self . parseSeason ( show , ( number , season ) )
if episode [ ' id ' ] == toUnicode ( episode_identifier ) :
self . setCache ( cache_key , result )
return episode
return result
else :
else :
result . append ( self . parseEpisode ( show , episode ) )
result . append ( self . parseSeason ( show , ( number , season ) ) )
self . setCache ( cache_key , result )
return result
return result
def getShow ( self , identifier = None ) :
def getEpisodeInfo ( self , identifier = None , season_identifier = None , episode_identifier = None ) :
show = None
""" Either return a list of all episodes or a single episode.
If episode_identifer contains an episode number to search for
"""
if not identifier and season_identifier is None :
return None
# season_identifier must contain the 'show id : season number' since there is no tvdb id
# for season and we need a reference to both the show id and season number
if season_identifier :
try :
identifier , season_identifier = season_identifier . split ( ' : ' )
season_identifier = int ( season_identifier )
except : return None
cache_key = ' thetvdb.cache. %s . %s . %s ' % ( identifier , episode_identifier , season_identifier )
log . debug ( ' Getting EpisodeInfo: %s ' , cache_key )
result = self . getCache ( cache_key ) or { }
if result :
return result
try :
try :
log . debug ( ' Getting show: %s ' , identifier )
show = self . tvdb [ int ( identifier ) ]
show = self . tvdb [ int ( identifier ) ]
except ( tvdb_exceptions . tvdb_error , IOError ) , e :
except ( tvdb_exceptions . tvdb_error , IOError ) , e :
log . error ( ' Failed to getShowInfo for show id " %s " : %s ' , ( identifier , traceback . format_exc ( ) ) )
log . error ( ' Failed parsing TheTVDB EpisodeInfo for " %s " id " %s " : %s ' , ( show , identifier , traceback . format_exc ( ) ) )
return None
return None
return show
result = [ ]
for number , season in show . items ( ) :
if season_identifier is not None and number != season_identifier :
continue
for episode in season . values ( ) :
if episode_identifier is not None and episode [ ' id ' ] == toUnicode ( episode_identifier ) :
result = self . parseEpisode ( show , episode )
self . setCache ( cache_key , result )
return result
else :
result . append ( self . parseEpisode ( show , episode ) )
self . setCache ( cache_key , result )
return result
def getShowInfo ( self , identifier = None ) :
def getShowInfo ( self , identifier = None ) :
if not identifier :
if not identifier :
return None
return None
cache_key = ' thetvdb.cache. %s ' % identifier
cache_key = ' thetvdb.cache. %s ' % identifier
log . debug ( ' Getting showInfo: %s ' , cache_key )
log . debug ( ' Getting showInfo: %s ' , cache_key )
result = self . getCache ( cache_key ) or { }
result = self . getCache ( cache_key ) or { }
if result :
if result :
return result
return result
show = self . getShow ( identifier = identifier )
show = self . getShow ( identifier = identifier )
if show :
if show :
result = self . parseShow ( show )
result = self . parseShow ( show )
@ -166,26 +226,6 @@ class TheTVDb(ShowProvider):
return result
return result
def getEpisodeInfo ( self , identifier = None , parent_identifier = None ) :
if not identifier or not parent_identifier :
return None
cache_key = ' thetvdb.cache. %s . %s ' % ( parent_identifier , identifier )
log . debug ( ' Getting EpisodeInfo: %s ' , cache_key )
result = self . getCache ( cache_key ) or { }
if result :
return result
show = self . getShow ( identifier = parent_identifier )
if show :
episode = self . getEpisodes ( identifier = parent_identifier , episode_identifier = identifier )
if episode :
result = self . parseEpisode ( show , episode )
self . setCache ( cache_key , result )
return result
#def getInfoByTheTVDBId(self, id = None):
#def getInfoByTheTVDBId(self, id = None):
#cache_key = 'thetvdb.cache.%s' % id
#cache_key = 'thetvdb.cache.%s' % id
@ -208,7 +248,7 @@ class TheTVDb(ShowProvider):
#return result
#return result
def parseShow ( self , show ) :
def parseShow ( self , show ) :
"""
"""
show [ 74713 ] = {
show [ 74713 ] = {
' actors ' : u ' |Bryan Cranston|Aaron Paul|Dean Norris|RJ Mitte|Betsy Brandt|Anna Gunn|Laura Fraser|Jesse Plemons|Christopher Cousins|Steven Michael Quezada|Jonathan Banks|Giancarlo Esposito|Bob Odenkirk| ' ,
' actors ' : u ' |Bryan Cranston|Aaron Paul|Dean Norris|RJ Mitte|Betsy Brandt|Anna Gunn|Laura Fraser|Jesse Plemons|Christopher Cousins|Steven Michael Quezada|Jonathan Banks|Giancarlo Esposito|Bob Odenkirk| ' ,
' added ' : None ,
' added ' : None ,
@ -234,25 +274,23 @@ class TheTVDb(ShowProvider):
' seriesid ' : u ' 74713 ' ,
' seriesid ' : u ' 74713 ' ,
' seriesname ' : u ' Breaking Bad ' ,
' seriesname ' : u ' Breaking Bad ' ,
' status ' : u ' Continuing ' ,
' status ' : u ' Continuing ' ,
' zap2it_id ' : u ' SH01009396 ' }
' zap2it_id ' : u ' SH01009396 ' }
"""
"""
# Make sure we have a valid show id, not '' or None
# Make sure we have a valid show id, not '' or None
#if len (show['id']) is 0:
#if len (show['id']) is 0:
# return None
# return None
## Images
## Images
poster = self . getImage ( show , type = ' poster ' , size = ' cover ' )
poster = self . getImage ( show , type = ' poster ' , size = ' cover ' )
backdrop = self . getImage ( show , type = ' fanart ' , size = ' w1280 ' )
backdrop = self . getImage ( show , type = ' fanart ' , size = ' w1280 ' )
#poster_original = self.getImage(show, type = 'poster', size = 'original')
#poster_original = self.getImage(show, type = 'poster', size = 'original')
#backdrop_original = self.getImage(show, type = 'backdrop', size = 'original')
#backdrop_original = self.getImage(show, type = 'backdrop', size = 'original')
## Genres
genres = [ ] if show [ ' genre ' ] is None else show [ ' genre ' ] . strip ( ' | ' ) . split ( ' | ' )
## Year
genres = [ ] if show [ ' genre ' ] is None else show [ ' genre ' ] . strip ( ' | ' ) . split ( ' | ' )
if show [ ' firstaired ' ] :
if show [ ' firstaired ' ] is not None :
year = datetime . strptime ( show [ ' firstaired ' ] , ' % Y- % m- %d ' ) . year
try : year = datetime . strptime ( show [ ' firstaired ' ] , ' % Y- % m- %d ' ) . year
except : year = None
else :
else :
year = None
year = None
@ -268,26 +306,71 @@ class TheTVDb(ShowProvider):
' poster_original ' : [ ] ,
' poster_original ' : [ ] ,
' backdrop_original ' : [ ] ,
' backdrop_original ' : [ ] ,
} ,
} ,
' imdb ' : show [ ' imdb_id ' ] ,
' runtime ' : show [ ' runtime ' ] ,
' released ' : show [ ' firstaired ' ] ,
' year ' : year ,
' year ' : year ,
' plot ' : show [ ' overview ' ] ,
' genres ' : genres ,
' genres ' : genres ,
' imdb ' : show [ ' imdb_id ' ] ,
' zap2it_id ' : show [ ' zap2it_id ' ] ,
' seriesid ' : show [ ' seriesid ' ] ,
' network ' : show [ ' network ' ] ,
' networkid ' : show [ ' networkid ' ] ,
' airs_dayofweek ' : show [ ' airs_dayofweek ' ] ,
' airs_time ' : show [ ' airs_time ' ] ,
' firstaired ' : show [ ' firstaired ' ] ,
' released ' : show [ ' firstaired ' ] ,
' runtime ' : show [ ' runtime ' ] ,
' contentrating ' : show [ ' contentrating ' ] ,
' rating ' : show [ ' rating ' ] ,
' ratingcount ' : show [ ' ratingcount ' ] ,
' actors ' : show [ ' actors ' ] ,
' lastupdated ' : show [ ' lastupdated ' ] ,
' status ' : show [ ' status ' ] ,
' language ' : show [ ' language ' ] ,
}
}
show_data = dict ( ( k , v ) for k , v in show_data . iteritems ( ) if v )
show_data = dict ( ( k , v ) for k , v in show_data . iteritems ( ) if v )
## Add alternative names
## Add alternative names
#for alt in ['original_name', 'alternative_name']:
#for alt in ['original_name', 'alternative_name']:
#alt_name = toUnicode(show.get(alt))
#alt_name = toUnicode(show[' alt))
#if alt_name and not alt_name in show_data['titles'] and alt_name.lower() != 'none' and alt_name != None:
#if alt_name and not alt_name in show_data['titles'] and alt_name.lower() != 'none' and alt_name != None:
#show_data['titles'].append(alt_name)
#show_data['titles'].append(alt_name)
return show_data
return show_data
def parseSeason ( self , show , season_tuple ) :
"""
contains no data
"""
number , season = season_tuple
title = toUnicode ( ' %s - Season %s ' % ( show [ ' seriesname ' ] , str ( number ) ) )
# XXX: work on title; added defualt_title to fix an error
season_data = {
' id ' : ( show [ ' id ' ] + ' : ' + str ( number ) ) ,
' type ' : ' season ' ,
' primary_provider ' : ' thetvdb ' ,
' titles ' : [ title , ] ,
' original_title ' : title ,
' via_thetvdb ' : True ,
' parent_identifier ' : show [ ' id ' ] ,
' seasonnumber ' : str ( number ) ,
' images ' : {
' poster ' : [ ] ,
' backdrop ' : [ ] ,
' poster_original ' : [ ] ,
' backdrop_original ' : [ ] ,
} ,
' year ' : None ,
' genres ' : None ,
' imdb ' : None ,
}
season_data = dict ( ( k , v ) for k , v in season_data . iteritems ( ) if v )
return season_data
def parseEpisode ( self , show , episode ) :
def parseEpisode ( self , show , episode ) :
"""
"""
( ' episodenumber ' , u ' 1 ' ) ,
( ' episodenumber ' , u ' 1 ' ) ,
( ' thumb_added ' , None ) ,
( ' thumb_added ' , None ) ,
( ' rating ' , u ' 7.7 ' ) ,
( ' rating ' , u ' 7.7 ' ) ,
@ -321,23 +404,23 @@ class TheTVDb(ShowProvider):
( ' firstaired ' , u ' 2011-09-19 ' ) ,
( ' firstaired ' , u ' 2011-09-19 ' ) ,
( ' episodename ' , u ' Pilot ' ) ]
( ' episodename ' , u ' Pilot ' ) ]
"""
"""
## Images
## Images
#poster = self.getImage(episode, type = 'poster', size = 'cover')
#poster = self.getImage(episode, type = 'poster', size = 'cover')
#backdrop = self.getImage(episode, type = 'fanart', size = 'w1280')
#backdrop = self.getImage(episode, type = 'fanart', size = 'w1280')
##poster_original = self.getImage(episode, type = 'poster', size = 'original')
##poster_original = self.getImage(episode, type = 'poster', size = 'original')
##backdrop_original = self.getImage(episode, type = 'backdrop', size = 'original')
##backdrop_original = self.getImage(episode, type = 'backdrop', size = 'original')
poster = episode [ ' filename ' ] or [ ]
poster = episode [ ' filename ' ] or [ ]
backdrop = [ ]
backdrop = [ ]
## Genres
genres = [ ]
genres = [ ]
plot = " %s - %s x %s - %s " % ( show [ ' seriesname ' ] ,
plot = " %s - %s x %s - %s " % ( show [ ' seriesname ' ] , episode [ ' seasonnumber ' ] , episode [ ' episodenumber ' ] , episode [ ' overview ' ] )
episode [ ' seasonnumber ' ] ,
episode [ ' episodenumber ' ] ,
## Year
episode [ ' overview ' ] )
if episode [ ' firstaired ' ] :
if episode [ ' firstaired ' ] is not None :
year = datetime . strptime ( episode [ ' firstaired ' ] , ' % Y- % m- %d ' ) . year
try : year = datetime . strptime ( episode [ ' firstaired ' ] , ' % Y- % m- %d ' ) . year
except : year = None
else :
else :
year = None
year = None
@ -348,7 +431,7 @@ class TheTVDb(ShowProvider):
' via_thetvdb ' : True ,
' via_thetvdb ' : True ,
' thetvdb_id ' : int ( episode [ ' id ' ] ) ,
' thetvdb_id ' : int ( episode [ ' id ' ] ) ,
' titles ' : [ episode [ ' episodename ' ] , ] ,
' titles ' : [ episode [ ' episodename ' ] , ] ,
' original_title ' : episode [ ' episodename ' ] ,
' original_title ' : episode [ ' episodename ' ] ,
' images ' : {
' images ' : {
' poster ' : [ poster ] if poster else [ ] ,
' poster ' : [ poster ] if poster else [ ] ,
' backdrop ' : [ backdrop ] if backdrop else [ ] ,
' backdrop ' : [ backdrop ] if backdrop else [ ] ,
@ -362,13 +445,38 @@ class TheTVDb(ShowProvider):
' plot ' : plot ,
' plot ' : plot ,
' genres ' : genres ,
' genres ' : genres ,
' parent_identifier ' : show [ ' id ' ] ,
' parent_identifier ' : show [ ' id ' ] ,
' seasonnumber ' : episode [ ' seasonnumber ' ] ,
' episodenumber ' : episode [ ' episodenumber ' ] ,
' combined_episodenumber ' : episode [ ' combined_episodenumber ' ] ,
' absolute_number ' : episode [ ' absolute_number ' ] ,
' combined_season ' : episode [ ' combined_season ' ] ,
' productioncode ' : episode [ ' productioncode ' ] ,
' seriesid ' : episode [ ' seriesid ' ] ,
' seasonid ' : episode [ ' seasonid ' ] ,
' firstaired ' : episode [ ' firstaired ' ] ,
' thumb_added ' : episode [ ' thumb_added ' ] ,
' thumb_height ' : episode [ ' thumb_height ' ] ,
' thumb_width ' : episode [ ' thumb_width ' ] ,
' rating ' : episode [ ' rating ' ] ,
' ratingcount ' : episode [ ' ratingcount ' ] ,
' epimgflag ' : episode [ ' epimgflag ' ] ,
' dvd_episodenumber ' : episode [ ' dvd_episodenumber ' ] ,
' dvd_discid ' : episode [ ' dvd_discid ' ] ,
' dvd_chapter ' : episode [ ' dvd_chapter ' ] ,
' dvd_season ' : episode [ ' dvd_season ' ] ,
' tms_export ' : episode [ ' tms_export ' ] ,
' writer ' : episode [ ' writer ' ] ,
' director ' : episode [ ' director ' ] ,
' gueststars ' : episode [ ' gueststars ' ] ,
' lastupdated ' : episode [ ' lastupdated ' ] ,
' language ' : episode [ ' language ' ] ,
}
}
episode_data = dict ( ( k , v ) for k , v in episode_data . iteritems ( ) if v )
episode_data = dict ( ( k , v ) for k , v in episode_data . iteritems ( ) if v )
## Add alternative names
## Add alternative names
#for alt in ['original_name', 'alternative_name']:
#for alt in ['original_name', 'alternative_name']:
#alt_name = toUnicode(episode.get(alt))
#alt_name = toUnicode(episode[' alt))
#if alt_name and not alt_name in episode_data['titles'] and alt_name.lower() != 'none' and alt_name != None:
#if alt_name and not alt_name in episode_data['titles'] and alt_name.lower() != 'none' and alt_name != None:
#episode_data['titles'].append(alt_name)
#episode_data['titles'].append(alt_name)
@ -378,11 +486,11 @@ class TheTVDb(ShowProvider):
""" """
""" """
# XXX: Need to implement size
# XXX: Need to implement size
image_url = ' '
image_url = ' '
for res , res_data in show [ ' _banners ' ] . get ( type , { } ) . items ( ) :
for res , res_data in show [ ' _banners ' ] . get ( type , { } ) . items ( ) :
for bid , banner_info in res_data . items ( ) :
for bid , banner_info in res_data . items ( ) :
image_url = banner_info . get ( ' _bannerpath ' , ' ' )
image_url = banner_info . get ( ' _bannerpath ' , ' ' )
break
break
return image_url
return image_url