# -*- coding: utf-8 -*- # Code de depart par AnthonyBloomer # Modif pour vStream # https://github.com/Kodi-vStream/venom-xbmc-addons/ import re import json import xbmcvfs import string import unicodedata import webbrowser from resources.lib.util import QuotePlus from resources.lib.comaddon import addon, dialog, VSlog, VSPath, isMatrix from resources.lib.handler.requestHandler import cRequestHandler try: import urllib2 except ImportError: import urllib.request as urllib2 try: from sqlite3 import dbapi2 as sqlite VSlog('SQLITE 3 as DB engine for tmdb') except: from pysqlite2 import dbapi2 as sqlite VSlog('SQLITE 2 as DB engine for tmdb') class cTMDb: # https://developers.themoviedb.org/3/genres/get-movie-list # https://developers.themoviedb.org/3/genres/get-tv-list TMDB_GENRES = { 12: 'Aventure', 14: 'Fantastique', 16: 'Animation', 18: 'Drame', 27: 'Horreur', 28: 'Action', 35: 'Comédie', 36: 'Histoire', 37: 'Western', 53: 'Thriller', 80: 'Crime', 99: 'Documentaire', 878: 'Science-Fiction', 9648: 'Mystère', 10402: 'Musique', 10749: 'Romance', 10751: 'Familial', 10752: 'Guerre', 10759: 'Action & Aventure', 10762: 'Kids', 10763: 'News', 10764: 'Realité', 10765: 'Science-Fiction & Fantastique', 10766: 'Feuilleton', 10767: 'Talk', 10768: 'Guerre & Politique', 10769: 'Etranger', 10770: 'Téléfilm' } URL = 'https://api.themoviedb.org/3/' URL_TRAILER = 'plugin://plugin.video.youtube/play/?video_id=%s' # ancien : 'plugin://plugin.video.youtube/?action=play_video&videoid=%s' CACHE = 'special://home/userdata/addon_data/plugin.video.vstream/video_cache.db' # important seul xbmcvfs peux lire le special if not isMatrix: REALCACHE = VSPath(CACHE).decode('utf-8') else: REALCACHE = VSPath(CACHE) def __init__(self, api_key='', debug=False, lang='fr'): self.ADDON = addon() self.api_key = self.ADDON.getSetting('api_tmdb') self.debug = debug self.lang = lang self.poster = 'https://image.tmdb.org/t/p/%s' % self.ADDON.getSetting('poster_tmdb') self.fanart = 'https://image.tmdb.org/t/p/%s' % self.ADDON.getSetting('backdrop_tmdb') try: if not xbmcvfs.exists(self.CACHE): # f = open(self.cache, 'w') # f.close() self.db = sqlite.connect(self.REALCACHE) self.db.row_factory = sqlite.Row self.dbcur = self.db.cursor() self.__createdb() return except: VSlog('Error: Unable to write on %s' % self.REALCACHE) pass try: self.db = sqlite.connect(self.REALCACHE) self.db.row_factory = sqlite.Row self.dbcur = self.db.cursor() except: VSlog('Error: Unable to connect to %s' % self.REALCACHE) pass def __createdb(self): sql_create = "CREATE TABLE IF NOT EXISTS movie ("\ "imdb_id TEXT, "\ "tmdb_id TEXT, "\ "title TEXT, "\ "year INTEGER,"\ "director TEXT, "\ "writer TEXT, "\ "tagline TEXT, "\ "credits TEXT,"\ "vote_average FLOAT, "\ "vote_count TEXT, "\ "runtime TEXT, "\ "overview TEXT,"\ "mpaa TEXT, "\ "premiered TEXT, "\ "genre TEXT, "\ "studio TEXT,"\ "status TEXT,"\ "poster_path TEXT, "\ "trailer TEXT, "\ "backdrop_path TEXT,"\ "playcount INTEGER,"\ "UNIQUE(imdb_id, tmdb_id, title, year)"\ ");" try: self.dbcur.execute(sql_create) except: VSlog('Error: Cannot create table movie') sql_create = "CREATE TABLE IF NOT EXISTS tvshow ("\ "imdb_id TEXT, "\ "tmdb_id TEXT, "\ "title TEXT, "\ "year INTEGER,"\ "director TEXT, "\ "writer TEXT, "\ "credits TEXT,"\ "vote_average FLOAT, "\ "vote_count TEXT, "\ "runtime TEXT, "\ "overview TEXT,"\ "mpaa TEXT, "\ "premiered TEXT, "\ "genre TEXT, "\ "studio TEXT,"\ "status TEXT,"\ "poster_path TEXT,"\ "trailer TEXT, "\ "backdrop_path TEXT,"\ "playcount INTEGER,"\ "UNIQUE(imdb_id, tmdb_id, title)"\ ");" self.dbcur.execute(sql_create) sql_create = "CREATE TABLE IF NOT EXISTS season ("\ "imdb_id TEXT, "\ "tmdb_id TEXT, " \ "season INTEGER, "\ "year INTEGER,"\ "premiered TEXT, "\ "poster_path TEXT,"\ "playcount INTEGER,"\ "UNIQUE(imdb_id, tmdb_id, season)"\ ");" self.dbcur.execute(sql_create) sql_create = "CREATE TABLE IF NOT EXISTS episode ("\ "imdb_id TEXT, "\ "tmdb_id TEXT, "\ "episode_id TEXT, "\ "season INTEGER, "\ "episode INTEGER, "\ "title TEXT, "\ "director TEXT, "\ "writer TEXT, "\ "overview TEXT, "\ "vote_average FLOAT, "\ "premiered TEXT, "\ "poster_path TEXT, "\ "playcount INTEGER, "\ "UNIQUE(imdb_id, tmdb_id, episode_id, title)"\ ");" self.dbcur.execute(sql_create) VSlog('table movie creee') def __del__(self): """ Cleanup db when object destroyed """ try: self.dbcur.close() self.db.close() except: pass def getToken(self): result = self._call('authentication/token/new', '') total = len(result) if (total > 0): url = 'https://www.themoviedb.org/authenticate/' try: #Si possible on ouvre la page automatiquement dans un navigateur internet. webbrowser.open(url + result['request_token']) except: pass sText = (self.ADDON.VSlang(30421)) % (url, result['request_token']) DIALOG = dialog() if not DIALOG.VSyesno(sText): return False result = self._call('authentication/session/new', 'request_token=' + result['request_token']) if 'success' in result and result['success']: self.ADDON.setSetting('tmdb_session', str(result['session_id'])) DIALOG.VSinfo(self.ADDON.VSlang(30000)) return else: DIALOG.VSerror('Erreur' + self.ADDON.VSlang(30000)) return # xbmc.executebuiltin('Container.Refresh') return return # cherche dans les films ou serie l'id par le nom, return ID ou FALSE def get_idbyname(self, name, year='', mediaType='movie', page=1): if year: term = QuotePlus(name) + '&year=' + year else: term = QuotePlus(name) if mediaType == "tv": term = term.split('aison')[0].replace('+', ' ') meta = self._call('search/' + str(mediaType), 'query=' + term + '&page=' + str(page)) # si pas de résultat avec l'année, on teste sans l'année if 'total_results' in meta and meta['total_results'] == 0 and year: meta = self.search_movie_name(name, '') # cherche 1 seul resultat if 'total_results' in meta and meta['total_results'] != 0: if meta['total_results'] > 1: qua = [] url = [] for aEntry in meta['results']: url.append(aEntry["id"]) qua.append(aEntry['title']) #Affichage du tableau tmdb_id = dialog().VSselectqual(qua, url) else: tmdb_id = meta['results'][0]['id'] return tmdb_id else: return False return False # Search for movies by title. def search_movie_name(self, name, year='', page=1): name = re.sub(" +", " ", name) # nettoyage du titre if year: term = QuotePlus(name) + '&year=' + year else: term = QuotePlus(name) meta = self._call('search/movie', 'query=' + term + '&page=' + str(page)) if 'errors' not in meta and 'status_code' not in meta: # si pas de résultat avec l'année, on teste sans l'année if 'total_results' in meta and meta['total_results'] == 0 and year: meta = self.search_movie_name(name, '') # cherche 1 seul resultat if 'total_results' in meta and meta['total_results'] != 0: movie = '' # s'il n'y en a qu'un, c'est le bon if meta['total_results'] == 1: movie = meta['results'][0] else: # premiere boucle, recherche la correspondance parfaite sur le nom for searchMovie in meta['results']: if searchMovie['genre_ids'] and 99 not in searchMovie['genre_ids']: if self._clean_title(searchMovie['title']) == self._clean_title(name): movie = searchMovie break # sinon, hors documentaire et année proche if not movie: for searchMovie in meta['results']: if searchMovie['genre_ids'] and 99 not in searchMovie['genre_ids']: # controle supplémentaire sur l'année meme si déjà dans la requete if year: if 'release_date' in searchMovie and searchMovie['release_date']: release_date = searchMovie['release_date'] yy = release_date[:4] if int(year)-int(yy) > 1 : continue # plus de deux ans d'écart, c'est pas bon movie = searchMovie break # Rien d'interessant, on prend le premier if not movie: movie = meta['results'][0] # recherche de toutes les infos tmdb_id = movie['id'] meta = self.search_movie_id(tmdb_id) else: meta = {} return meta # Search for collections by title. def search_collection_name(self, name): name = re.sub(" +", " ", name) # nettoyage du titre term = QuotePlus(name) meta = self._call('search/collection', 'query=' + term) if 'errors' not in meta and 'status_code' not in meta: # cherche 1 seul resultat if 'total_results' in meta and meta['total_results'] != 0: collection = '' # s'il n'y en a qu'un, c'est le bon if meta['total_results'] == 1: collection = meta['results'][0] else: # premiere boucle, recherche la correspondance parfaite sur le nom for searchCollec in meta['results']: cleanTitleTMDB = self._clean_title(searchCollec['name']) cleanTitleSearch = self._clean_title(name) if not cleanTitleSearch.endswith('saga'): cleanTitleSearch += 'saga' if cleanTitleTMDB == cleanTitleSearch: collection = searchCollec break elif (cleanTitleSearch + 'saga')== cleanTitleTMDB: collection = searchCollec break # sinon, le premier qui n'est pas du genre animation if not collection: for searchCollec in meta['results']: if 'animation' not in searchCollec['name']: collection = searchCollec break # Rien d'interessant, on prend le premier if not collection: collection = meta['results'][0] meta = collection tmdb_id = collection['id'] meta['tmdb_id'] = tmdb_id # recherche de toutes les infos meta = self.search_collection_id(tmdb_id) else: meta = {} return meta # Search for TV shows by title. def search_tvshow_name(self, name, year='', page=1, genre=''): if year: term = QuotePlus(name) + '&year=' + year else: term = QuotePlus(name) meta = self._call('search/tv', 'query=' + term + '&page=' + str(page)) if 'errors' not in meta and 'status_code' not in meta: # si pas de résultat avec l'année, on teste sans l'année if 'total_results' in meta and meta['total_results'] == 0 and year: meta = self.search_tvshow_name(name, '') # cherche 1 seul resultat if 'total_results' in meta and meta['total_results'] != 0: movie = '' # s'il n'y en a qu'un, c'est le bon if meta['total_results'] == 1: movie = meta['results'][0] else: # premiere boucle, recherche la correspondance parfaite sur le nom for searchMovie in meta['results']: if genre == '' or genre in searchMovie['genre_ids']: movieName = searchMovie['name'] if self._clean_title(movieName) == self._clean_title(name): movie = searchMovie break # sinon, hors documentaire et année proche if not movie: for searchMovie in meta['results']: if genre and genre in searchMovie['genre_ids']: # controle supplémentaire sur l'année meme si déjà dans la requete if year: if 'release_date' in searchMovie and searchMovie['release_date']: release_date = searchMovie['release_date'] yy = release_date[:4] if int(year)-int(yy) > 1 : continue # plus de deux ans d'écart, c'est pas bon movie = searchMovie break # Rien d'interessant, on prend le premier if not movie: movie = meta['results'][0] # recherche de toutes les infos tmdb_id = movie['id'] meta = self.search_tvshow_id(tmdb_id) else: meta = {} return meta # Search for person by name. def search_person_name(self, name): name = re.sub(" +", " ", name) # nettoyage du titre term = QuotePlus(name) meta = self._call('search/person', 'query=' + term) # si pas d'erreur if 'errors' not in meta and 'status_code' not in meta: # on prend le premier resultat if 'total_results' in meta and meta['total_results'] != 0: meta = meta['results'][0] # recherche de toutes les infos person_id = meta['id'] meta = self.search_person_id(person_id) else: meta = {} return meta # Get the basic movie information for a specific movie id. def search_movie_id(self, movie_id, append_to_response='append_to_response=trailers,credits'): result = self._call('movie/' + str(movie_id), append_to_response) result['tmdb_id'] = movie_id return result # obj(**self._call('movie/' + str(movie_id), append_to_response)) # Get the primary information about a TV series by id. def search_tvshow_id(self, show_id, append_to_response='append_to_response=external_ids,videos,credits'): result = self._call('tv/' + str(show_id), append_to_response) result['tmdb_id'] = show_id return result # Get the basic informations for a specific collection id. def search_collection_id(self, collection_id): result = self._call('collection/' + str(collection_id)) result['tmdb_id'] = collection_id return result # Get the basic person informations for a specific person id. def search_person_id(self, person_id): result = self._call('person/' + str(person_id)) result['tmdb_id'] = person_id return result # Get the informations for a specific network. def search_network_id(self, network_id): result = self._call('network/%s/images' % str(network_id)) if 'status_code' not in result and 'logos' in result: network = result['logos'][0] vote = -1 # On prend le logo qui a la meilleure note for logo in result['logos']: logoVote = float(logo['vote_average']) if logoVote>vote: network = logo vote = logoVote network['tmdb_id'] = network_id network.pop('vote_average') return network return {} def _format(self, meta, name): _meta = {} _meta['imdb_id'] = '' _meta['tmdb_id'] = '' _meta['tvdb_id'] = '' _meta['title'] = name _meta['media_type'] = '' _meta['rating'] = 0 _meta['votes'] = 0 _meta['duration'] = 0 _meta['plot'] = '' _meta['mpaa'] = '' _meta['premiered'] = '' _meta['year'] = '' _meta['trailer'] = '' _meta['tagline'] = '' _meta['genre'] = '' _meta['studio'] = '' _meta['status'] = '' _meta['credits'] = '' _meta['cast'] = [] _meta['director'] = '' _meta['writer'] = '' _meta['poster_path'] = '' _meta['cover_url'] = '' _meta['backdrop_path'] = '' _meta['backdrop_url'] = '' _meta['episode'] = 0 _meta['playcount'] = 0 if 'title' in meta and meta['title']: _meta['title'] = meta['title'] elif 'name' in meta and meta['name']: _meta['title'] = meta['name'] if 'id' in meta: _meta['tmdb_id'] = meta['id'] if 'tmdb_id' in meta: _meta['tmdb_id'] = meta['tmdb_id'] if 'imdb_id' in meta: _meta['imdb_id'] = meta['imdb_id'] elif 'external_ids' in meta: _meta['imdb_id'] = meta['external_ids']['imdb_id'] if 'mpaa' in meta: _meta['mpaa'] = meta['mpaa'] if 'media_type' in meta: _meta['media_type'] = meta['media_type'] if 'release_date' in meta: _meta['premiered'] = meta['release_date'] elif 'first_air_date' in meta: _meta['premiered'] = meta['first_air_date'] elif 'premiered' in meta and meta['premiered']: _meta['premiered'] = meta['premiered'] elif 's_premiered' in meta and meta['s_premiered']: _meta['premiered'] = meta['s_premiered'] elif 'air_date' in meta and meta['air_date']: _meta['premiered'] = meta['air_date'] if 'year' in meta: _meta['year'] = meta['year'] elif 's_year' in meta: _meta['year'] = meta['s_year'] else: try: if 'premiered' in _meta and _meta['premiered']: _meta['year'] = int(_meta['premiered'][:4]) except: pass if 'rating' in meta: _meta['rating'] = meta['rating'] elif 'vote_average' in meta: _meta['rating'] = meta['vote_average'] if 'votes' in meta: _meta['votes'] = meta['votes'] elif 'vote_count' in meta: _meta['votes'] = meta['vote_count'] try: duration = 0 if 'runtime' in meta and meta['runtime']: duration = int(meta['runtime']) elif 'episode_run_time' in meta and meta['episode_run_time']: duration = int(meta['episode_run_time'][0]) if duration < 300 : # en minutes duration *= 60 # Convertir les minutes TMDB en secondes pour KODI _meta['duration'] = duration except: _meta['duration'] = 0 if 'overview' in meta and meta['overview']: _meta['plot'] = meta['overview'] elif 'parts' in meta: # Il s'agit d'une collection, on récupere le plot du premier film _meta['plot'] = meta['parts'][0]['overview'] elif 'biography' in meta: # Il s'agit d'une personne, on récupere sa bio _meta['plot'] = meta['biography'] if 'studio' in meta: _meta['studio'] = meta['studio'] elif 'production_companies' in meta: _meta['studio'] = '' for studio in meta['production_companies']: if _meta['studio'] == '': _meta['studio'] += studio['name'] else: _meta['studio'] += ' / ' + studio['name'] if 'genre' in meta: listeGenre = meta['genre'] if '{' in listeGenre: meta['genres'] = eval(listeGenre) else: _meta['genre'] = listeGenre if 'genres' in meta: # _meta['genre'] = '' for genre in meta['genres']: if _meta['genre'] == '': _meta['genre'] += genre['name'] else: _meta['genre'] += ' / ' + genre['name'] elif 'genre_ids' in meta: genres = self.getGenresFromIDs(meta['genre_ids']) _meta['genre'] = '' for genre in genres: if _meta['genre'] == '': _meta['genre'] += genre else: _meta['genre'] += ' / ' + genre if not isMatrix: _meta['genre'] = unicode(_meta['genre'], 'utf-8') elif 'parts' in meta: # Il s'agit d'une collection, on récupere le genre du premier film genres = self.getGenresFromIDs(meta['parts'][0]['genre_ids']) _meta['genre'] = '' for genre in genres: if _meta['genre'] == '': _meta['genre'] += genre else: _meta['genre'] += ' / ' + genre if not isMatrix: _meta['genre'] = unicode(_meta['genre'], 'utf-8') trailer_id = '' if 'trailer' in meta and meta['trailer']: # Lecture du cache _meta['trailer'] = meta['trailer'] elif 'trailers' in meta: # Trailer d'un film retourné par TMDB try: # Recherche de la BA en français trailers = meta['trailers']['youtube'] for trailer in trailers: if trailer['type'] == 'Trailer': if 'VF' in trailer['name']: trailer_id = trailer['source'] break # pas de trailer français, on prend le premier if not trailer_id: trailer_id = meta['trailers']['youtube'][0]['source'] _meta['trailer'] = self.URL_TRAILER % trailer_id except: pass elif 'videos' in meta and meta['videos']: # Trailer d'une série retourné par TMDB try: # Recherche de la BA en français trailers = meta['videos'] if len(trailers['results']) >0: for trailer in trailers['results']: if trailer['type'] == 'Trailer' and trailer['site'] == 'YouTube': trailer_id = trailer['key'] # Au moins c'est un trailer, pas forcement français if 'fr' in trailer['iso_639_1']: trailer_id = trailer['key'] break # pas de trailer, on prend la premiere vidéo disponible if not trailer_id: trailer_id = meta['videos'][0]['key'] _meta['trailer'] = self.URL_TRAILER % trailer_id except: pass if 'backdrop_path' in meta and meta['backdrop_path']: _meta['backdrop_path'] = meta['backdrop_path'] _meta['backdrop_url'] = self.fanart + str(_meta['backdrop_path']) elif 'parts' in meta: # Il s'agit d'une collection, on récupere le backdrop du dernier film nbFilm = len(meta['parts']) _meta['backdrop_path'] = meta['parts'][nbFilm-1]['backdrop_path'] _meta['backdrop_url'] = self.fanart + str(_meta['backdrop_path']) if 'poster_path' in meta and meta['poster_path']: _meta['poster_path'] = meta['poster_path'] _meta['cover_url'] = self.poster + str(_meta['poster_path']) elif 'parts' in meta: # Il s'agit d'une collection, on récupere le poster du dernier film nbFilm = len(meta['parts']) _meta['poster_path'] = meta['parts'][nbFilm-1]['poster_path'] _meta['cover_url'] = self.fanart + str(_meta['poster_path']) elif 'profile_path' in meta: # il s'agit d'une personne _meta['poster_path'] = meta['profile_path'] _meta['cover_url'] = self.poster + str(_meta['poster_path']) elif 'file_path' in meta: # il s'agit d'un network _meta['poster_path'] = meta['file_path'] _meta['cover_url'] = self.poster + str(_meta['poster_path']) _meta['backdrop_path'] = _meta['poster_path'] _meta['backdrop_url'] = self.fanart + str(_meta['backdrop_path']) # special saisons if 's_poster_path' in meta and meta['s_poster_path']: _meta['poster_path'] = meta['s_poster_path'] _meta['cover_url'] = self.poster + str(meta['s_poster_path']) if 'playcount' in meta: _meta['playcount'] = meta['playcount'] if _meta['playcount'] == 6: # Anciennement 6 = unwatched _meta['playcount'] = 0 else: _meta['playcount'] = 0 if 'tagline' in meta and meta['tagline']: _meta['tagline'] = meta['tagline'] if 'status' in meta: _meta['status'] = meta['status'] if 'writer' in meta and meta['writer']: _meta['writer'] = meta['writer'] if 'director' in meta and meta['director']: _meta['director'] = meta['director'] if 'credits' in meta and meta['credits']: # Transformation compatible pour lecture depuis le cache et retour de TMDB strmeta = str(meta['credits']) listCredits = eval(strmeta) casts = listCredits['cast'] crews = [] if len(casts) > 0: #licast = [] if 'crew' in listCredits: crews = listCredits['crew'] if len(crews)>0: _meta['credits'] = "{u'cast': " + str(casts) + ", u'crew': "+str(crews) + "}" else: _meta['credits'] = "{u'cast': " + str(casts) + '}' # _meta['credits'] = "{u'cast': " + str(casts) + ", u'crew': "+str(crews) + "}" # _meta['credits'] = 'u\'cast\': ' + str(casts) + '' #for cast in casts: # licast.append((cast['name'], cast['character'], self.poster + str(cast['profile_path']), str(cast['id']))) #_meta['cast'] = licast #if 'crew' in listCredits: if len(crews) > 0: for crew in crews: if crew['job'] == 'Director': _meta['director'] = crew['name'] elif crew['department'] == 'Writing': if _meta['writer'] != '': _meta['writer'] += ' / ' _meta['writer'] += '%s (%s)' % (crew['job'], crew['name']) elif crew['department'] == 'Production' and 'Producer' in crew['job']: if _meta['writer'] != '': _meta['writer'] += ' / ' _meta['writer'] += '%s (%s)' % (crew['job'], crew['name']) return _meta def _clean_title(self, title): title = re.sub('[^%s]' % (string.ascii_lowercase + string.digits), '', title.lower()) return title def _cache_search(self, media_type, name, tmdb_id='', year='', season='', episode=''): if media_type == 'movie': sql_select = 'SELECT * FROM movie' if tmdb_id: sql_select = sql_select + ' WHERE tmdb_id = \'%s\'' % tmdb_id else: sql_select = sql_select + ' WHERE title = \'%s\'' % name if year: sql_select = sql_select + ' AND year = %s' % year elif media_type == 'collection': sql_select = 'SELECT * FROM movie' if tmdb_id: sql_select = sql_select + ' WHERE tmdb_id = \'%s\'' % tmdb_id else: if not name.endswith('saga'): name += 'saga' sql_select = sql_select + ' WHERE title = \'%s\'' % name elif media_type == 'tvshow' or media_type == 'anime': sql_select = 'SELECT * FROM tvshow' if season: sql_select = 'SELECT *, season.poster_path as s_poster_path, season.premiered as s_premiered, ' \ 'season.year as s_year FROM tvshow LEFT JOIN season ON tvshow.imdb_id = season.imdb_id ' if tmdb_id: sql_select = sql_select + ' WHERE tvshow.tmdb_id = \'%s\'' % tmdb_id else: sql_select = sql_select + ' WHERE tvshow.title = \'%s\'' % name if year: sql_select = sql_select + ' AND tvshow.year = %s' % year if season: sql_select = sql_select + ' AND season.season = \'%s\'' % season else: return None try: self.dbcur.execute(sql_select) matchedrow = self.dbcur.fetchone() except Exception as e: VSlog('************* Error selecting from cache db: %s' % e, 4) return None if matchedrow: # VSlog('Found meta information by name in cache table') return dict(matchedrow) else: # VSlog('No match in local DB') return None def _cache_save(self, meta, name, media_type, season, year): # Pas de cache pour les personnes ou les distributeurs if media_type in ('person', 'network'): return # cache des séries et animes if media_type == 'tvshow' or media_type == 'anime': return self._cache_save_tvshow(meta, name, 'tvshow', season, year) # cache des collections if media_type == 'collection': media_type = 'movie' # On utilise la même table que pour les films if not name.endswith('saga'): name += 'saga' # sauvegarde de la durée en minutes, pour le retrouver en minutes comme le fait TMDB runtime = 0 if 'duration' in meta and meta['duration']: runtime = int(meta['duration'])/60 if not year and 'year' in meta: year = meta['year'] # sauvegarde movie dans la BDD # year n'est pas forcement l'année du film mais l'année utilisée pour la recherche try: sql = 'INSERT INTO %s (imdb_id, tmdb_id, title, year, credits, writer, director, tagline, vote_average, vote_count, runtime, ' \ 'overview, mpaa, premiered, genre, studio, status, poster_path, trailer, backdrop_path, playcount) ' \ 'VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' % media_type self.dbcur.execute(sql, (meta['imdb_id'], meta['tmdb_id'], name, year, meta['credits'], meta['writer'], meta['director'], meta['tagline'], meta['rating'], meta['votes'], str(runtime), meta['plot'], meta['mpaa'], meta['premiered'], meta['genre'], meta['studio'], meta['status'], meta['poster_path'], meta['trailer'], meta['backdrop_path'], 0)) self.db.commit() # VSlog('SQL INSERT Successfully') except Exception as e: VSlog('SQL ERROR INSERT into table ' + media_type) pass # Cache pour les séries (et animes) def _cache_save_tvshow(self, meta, name, media_type, season, year): # ecrit les saisons dans la BDD if 'seasons' in meta: self._cache_save_season(meta, season) del meta['seasons'] if not year and 'year' in meta: year = meta['year'] # sauvegarde de la durée en minutes, pour le retrouver en minutes comme le fait TMDB runtime = 0 if 'duration' in meta and meta['duration']: runtime = int(meta['duration'])/60 # sauvegarde tvshow dans la BDD try: sql = 'INSERT INTO %s (imdb_id, tmdb_id, title, year, credits, writer, director, vote_average, vote_count, runtime, ' \ 'overview, mpaa, premiered, genre, studio, status, poster_path, trailer, backdrop_path, playcount) ' \ 'VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' % media_type self.dbcur.execute(sql, (meta['imdb_id'], meta['tmdb_id'], name, year, meta['credits'], meta['writer'], meta['director'], meta['rating'], meta['votes'], runtime, meta['plot'], meta['mpaa'], meta['premiered'], meta['genre'], meta['studio'], meta['status'], meta['poster_path'], meta['trailer'], meta['backdrop_path'], 0)) self.db.commit() # VSlog('SQL INSERT Successfully') except Exception as e: VSlog('SQL ERROR INSERT into table ' + media_type) pass def _cache_save_season(self, meta, season): for s in meta['seasons']: if s['season_number'] != None and ('%02d' % int(s['season_number'])) == season: meta['s_poster_path'] = s['poster_path'] meta['s_premiered'] = s['air_date'] meta['s_year'] = s['air_date'] try: sql = 'INSERT INTO season (imdb_id, tmdb_id, season, year, premiered, poster_path, playcount) VALUES ' \ '(?, ?, ?, ?, ?, ?, ?) ' self.dbcur.execute(sql, (meta['imdb_id'], s['id'], s['season_number'], s['air_date'], s['air_date'], s['poster_path'], 6)) self.db.commit() # VSlog('SQL INSERT Successfully') except Exception: VSlog('SQL ERROR INSERT into table season') pass def get_meta(self, media_type, name, imdb_id='', tmdb_id='', year='', season='', episode='', update=False): """ Main method to get meta data for movie or tvshow. Will lookup by name/year if no IMDB ID supplied. Args: media_type (str): 'movie' or 'tvshow' name (str): full name of movie/tvshow you are searching Kwargs: imdb_id (str): IMDB ID tmdb_id (str): TMDB ID year (str): 4 digit year of video, recommended to include the year whenever possible to maximize correct search results. season (int) episode (int) Returns: DICT of meta data or None if cannot be found. """ name = re.sub(" +", " ", name) # nettoyage du titre # VSlog('Attempting to retrieve meta data for %s: %s %s %s %s' % (media_type, name, year, imdb_id, tmdb_id)) # recherche dans la base de données if not update: meta = self._cache_search(media_type, self._clean_title(name), tmdb_id, year, season, episode) if meta: meta = self._format(meta, name) return meta # recherche online meta = {} if media_type == 'movie': if tmdb_id: meta = self.search_movie_id(tmdb_id) elif name: meta = self.search_movie_name(name, year) elif media_type == 'tvshow': if tmdb_id: meta = self.search_tvshow_id(tmdb_id) elif name: meta = self.search_tvshow_name(name, year) elif media_type == 'anime': if tmdb_id: meta = self.search_tvshow_id(tmdb_id) elif name: meta = self.search_tvshow_name(name, year, genre = 16) elif media_type == 'collection': if tmdb_id: meta = self.search_collection_id(tmdb_id) elif name: meta = self.search_collection_name(name) elif media_type == 'person': if tmdb_id: meta = self.search_person_id(tmdb_id) elif name: meta = self.search_person_name(name) elif media_type == 'network': if tmdb_id: meta = self.search_network_id(tmdb_id) # Mise en forme des metas si trouvé if meta and 'tmdb_id' in meta: meta = self._format(meta, name) # sauvegarde dans un cache self._cache_save(meta, self._clean_title(name), media_type, season, year) else: # initialise un meta vide meta = self._format(meta, name) return meta def getUrl(self, url, page=1, term=''): # return url api exemple 'movie/popular' page en cours try: if term: term = term + '&page=' + str(page) else: term = 'page=' + str(page) result = self._call(url, term) except: return False return result def _call(self, action, append_to_response=''): url = '%s%s?language=%s&api_key=%s' % (self.URL, action, self.lang, self.api_key) if append_to_response: url += '&%s' % append_to_response #On utilise requests car urllib n'arrive pas a certain moment a ouvrir le json. import requests data = requests.get(url).json() return data def getPostUrl(self, action, post): tmdb_session = self.ADDON.getSetting('tmdb_session') if not tmdb_session: return sUrl = '%s%s?api_key=%s&session_id=%s' % (self.URL, action, self.api_key, tmdb_session) try: sPost = json.dumps(post).encode('utf-8') except: sPost = json.dumps(post) headers = {'Content-Type': 'application/json'} req = urllib2.Request(sUrl, sPost, headers) response = urllib2.urlopen(req) data = json.loads(response.read()) return data # retourne la liste des genres en Texte, à partir des IDs def getGenresFromIDs(self, genresID): sGenres = [] for gid in genresID: genre = self.TMDB_GENRES.get(gid) if genre: sGenres.append(genre) return sGenres # Retourne le genre en Texte, à partir d'un ID def getGenreFromID(self, genreID): if not str(genreID).isdigit(): return genreID genre = self.TMDB_GENRES.get(genreID) if genre: return genre return genreID