· 9 years ago · Jan 15, 2017, 01:18 PM
1# -*- coding: utf-8 -*-
2#Code de depart par AnthonyBloomer
3#Modif pour vStream
4
5from resources.lib.config import cConfig
6
7import json, os, copy
8import pprint
9from urllib import quote_plus, urlopen, urlencode
10import xbmc
11import threading
12
13try:
14 from sqlite3 import dbapi2 as sqlite
15 cConfig().log('SQLITE 3 as DB engine')
16except:
17 from pysqlite2 import dbapi2 as sqlite
18 cConfig().log('SQLITE 2 as DB engine')
19
20
21# http://docs.themoviedb.apiary.io
22class cTMDb(threading.Thread):
23 URL = "http://api.themoviedb.org/3/"
24
25 def __init__(self, api_key, debug=False, lang='en'):
26 self.api_key = api_key
27 self.debug = debug
28 self.lang = lang
29 self.poster = 'https://image.tmdb.org/t/p/w396'
30 self.fanart = 'https://image.tmdb.org/t/p/w1280'
31 self.cache = os.path.join(cConfig().getSettingCache(),'video_cache.db')
32 threading.Thread.__init__(self)
33
34 try:
35 if not os.path.exists(self.cache):
36 f = open(self.cache,'w')
37 f.close()
38 self.db = sqlite.connect(self.cache)
39 self.db.row_factory = sqlite.Row
40 self.dbcur = self.db.cursor()
41 self.__createdb()
42 except:
43 pass
44
45 try:
46 self.db = sqlite.connect(self.cache)
47 self.db.row_factory = sqlite.Row
48 self.dbcur = self.db.cursor()
49 except:
50 pass
51
52 def run(self):
53 xbmc.log('passe')
54
55 def __createdb(self):
56
57 sql_create = "CREATE TABLE IF NOT EXISTS movie ("\
58 "imdb_id TEXT, "\
59 "tmdb_id TEXT, "\
60 "title TEXT, "\
61 "year INTEGER,"\
62 "director TEXT, "\
63 "writer TEXT, "\
64 "tagline TEXT, "\
65 "cast TEXT,"\
66 "rating FLOAT, "\
67 "votes TEXT, "\
68 "duration TEXT, "\
69 "plot TEXT,"\
70 "mpaa TEXT, "\
71 "premiered TEXT, "\
72 "genre TEXT, "\
73 "studio TEXT,"\
74 "thumb_url TEXT, "\
75 "cover_url TEXT, "\
76 "trailer TEXT, "\
77 "backdrop_url TEXT,"\
78 "imgs_prepacked TEXT,"\
79 "playcount INTEGER,"\
80 "UNIQUE(imdb_id, tmdb_id, title, year)"\
81 ");"
82 try:
83 self.dbcur.execute(sql_create)
84 except:
85 xbmc.log("non")
86
87 sql_create = "CREATE TABLE IF NOT EXISTS tvshow ("\
88 "imdb_id VARCHAR(10), "\
89 "tvdb_id VARCHAR(10), "\
90 "title TEXT, "\
91 "year INTEGER,"\
92 "cast TEXT,"\
93 "rating FLOAT, "\
94 "duration TEXT, "\
95 "plot TEXT,"\
96 "mpaa TEXT, "\
97 "premiered TEXT, "\
98 "genre TEXT, "\
99 "studio TEXT,"\
100 "status TEXT,"\
101 "banner_url TEXT, "\
102 "cover_url TEXT,"\
103 "trailer TEXT, "\
104 "backdrop_url TEXT,"\
105 "imgs_prepacked TEXT,"\
106 "playcount INTEGER,"\
107 "UNIQUE(imdb_id, tvdb_id, title)"\
108 ");"
109
110 self.dbcur.execute(sql_create)
111
112 sql_create = "CREATE TABLE IF NOT EXISTS season ("\
113 "imdb_id VARCHAR(10), "\
114 "tvdb_id VARCHAR(10), " \
115 "season INTEGER, "\
116 "cover_url TEXT,"\
117 "playcount INTEGER,"\
118 "UNIQUE(imdb_id, tvdb_id, season)"\
119 ");"
120
121 self.dbcur.execute(sql_create)
122
123 sql_create = "CREATE TABLE IF NOT EXISTS episode ("\
124 "imdb_id VARCHAR(10), "\
125 "tvdb_id VARCHAR(10), "\
126 "episode_id VARCHAR(10), "\
127 "season INTEGER, "\
128 "episode INTEGER, "\
129 "title TEXT, "\
130 "director TEXT, "\
131 "writer TEXT, "\
132 "plot TEXT, "\
133 "rating FLOAT, "\
134 "premiered TEXT, "\
135 "poster TEXT, "\
136 "playcount INTEGER, "\
137 "UNIQUE(imdb_id, tvdb_id, episode_id, title)"\
138 ");"
139
140 self.dbcur.execute(sql_create)
141 xbmc.log("table creer")
142
143 def __del__(self):
144 ''' Cleanup db when object destroyed '''
145 try:
146 self.dbcur.close()
147 self.dbcon.close()
148 except: pass
149
150 # Get the basic movie information for a specific movie id.
151 def search_movie_id(self, movie_id, append_to_response="append_to_response=trailers,images,casts,translations"):
152 result = self._call('movie/'+ str(movie_id), append_to_response)
153 return result #obj(**self._call('movie/' + str(movie_id), append_to_response))
154
155 # Get the user reviews for a movie
156 def get_movie_reviews(self, id, page=1):
157 arr = []
158 result = self._call('movie/%s/reviews' % id, 'page=' + str(page))
159 [arr.append(obj(**res)) for res in result['results']]
160 return arr
161
162 def get_movie_lists(self, id, page=1):
163 arr = []
164 result = self._call('movie/%s/lists' % id, 'page=' + str(page))
165 [arr.append(obj(**res)) for res in result['results']]
166 return arr
167
168 def get_movie_videos(self, id, page=1):
169 arr = []
170 result = self._call('movie/%s/videos' % id, 'page=' + str(page))
171 [arr.append(obj(**res)) for res in result['results']]
172 return arr
173
174 def get_movie_recommendations(self, movie_id, page=1):
175 arr = []
176 result = self._call('movie/%s/recommendations' % movie_id, 'page=' + str(page))
177 [arr.append(obj(**res)) for res in result['results']]
178 return arr
179
180 def discover_movies(self, params):
181 arr = []
182 result = self._call('discover/movie/', urlencode(params))
183 [arr.append(obj(**res)) for res in result['results']]
184 return arr
185
186 def discover_tv_shows(self, params):
187 arr = []
188 result = self._call('discover/tv/', urlencode(params))
189 [arr.append(obj(**res)) for res in result['results']]
190 return arr
191
192 # Get the latest movie id.
193 def get_latest_movie(self):
194 return obj(**self._call('movie/latest', ''))
195
196 # Get the list of movies playing that have been, or are being released this week. This list refreshes every day.
197 def now_playing(self, page=1):
198 arr = []
199 result = self._call('movie/now_playing', 'page=' + str(page))
200 [arr.append(obj(**res)) for res in result['results']]
201 return arr
202
203 # Get the list of top rated movies. By default, this list will only include movies that have 50 or more votes.
204 # This list refreshes every day.
205 def top_rated(self, page=1):
206 arr = []
207 result = self._call('movie/top_rated', 'page=' + str(page))
208 [arr.append(obj(**res)) for res in result['results']]
209 return arr
210
211 # Get the list of upcoming movies by release date. This list refreshes every day.
212 def upcoming(self, page=1):
213 arr = []
214 result = self._call('movie/upcoming', 'page=' + str(page))
215 [arr.append(obj(**res)) for res in result['results']]
216 return arr
217
218 # Get the list of popular movies on The Movie Database. This list refreshes every day.
219 def popular(self, page=1):
220 arr = []
221 result = self._call('movie/popular', 'page=' + str(page))
222 [arr.append(obj(**res)) for res in result['results']]
223 return arr
224
225 # Search for movies by title.
226 def search_movie_name(self, name, year='', page=1):
227
228 meta = {}
229
230 if year:
231 term = name + '&year=' + year
232 else:
233 term = name
234
235 meta = self._call('search/movie', 'query=' + quote_plus(term) + '&page=' + str(page))
236 #teste sans l'année
237 if meta and meta['total_results'] == 0 and year:
238 meta = self.search_movie_name(name,'')
239
240 #cherche 1 seul resultat
241 if meta and meta['total_results'] != 0 and meta['results']:
242 tmdb_id = meta['results'][0]['id']
243 #cherche toutes les infos
244 meta = self.search_movie_id(tmdb_id)
245 else:
246 meta = {}
247
248 return meta
249
250 # Search for TV shows by title.
251 def search_tvshow_name(self, term, page=1):
252 arr = []
253 result = self._call('search/tv', 'query=' + quote_plus(term) + '&page=' + str(page))
254 [arr.append(obj(**res)) for res in result['results']]
255 return arr
256
257 # Get the similar movies for a specific movie id.
258 def similar(self, id, page=1):
259 arr = []
260 result = self._call('movie/' + str(id) + '/similar', 'page=' + str(page))
261 [arr.append(obj(**res)) for res in result['results']]
262 return arr
263
264 # Get the primary information about a TV series by id.
265 def search_tvshow_id(self, show_id, append_to_response="append_to_response=trailers,images,casts,translations"):
266 return obj(**self._call('tv/' + str(show_id), append_to_response))
267
268 # Get the latest TV show id.
269 def get_latest_tv_show(self):
270 return obj(**self._call('tv/latest', ''))
271
272 # Get the similar TV shows for a specific tv id.
273 def similar_shows(self, id, page=1):
274 arr = []
275 result = self._call('tv/' + str(id) + '/similar', 'page=' + str(page))
276 [arr.append(obj(**res)) for res in result['results']]
277 return arr
278
279 # Get the list of popular TV shows. This list refreshes every day.
280 def popular_shows(self, page=1):
281 arr = []
282 result = self._call('tv/popular', 'page=' + str(page))
283 [arr.append(obj(**res)) for res in result['results']]
284 return arr
285
286 # Get the list of top rated TV shows.
287 # By default, this list will only include TV shows that have 2 or more votes.
288 # This list refreshes every day.
289
290 def top_rated_shows(self, page=1):
291 arr = []
292 result = self._call('tv/top_rated', 'page=' + str(page))
293 [arr.append(obj(**res)) for res in result['results']]
294 return arr
295
296 # Get the general person information for a specific id.
297 def get_person(self, id):
298 return obj(**self._call('person/' + str(id), ''))
299
300 # Search for people by name.
301 def search_person(self, term, page=1):
302 arr = []
303 result = self._call('search/person', 'query=' + quote_plus(term) + '&page=' + str(page))
304 [arr.append(obj(**res)) for res in result['results']]
305 return arr
306
307 def __set_playcount(self, overlay):
308 if int(overlay) == 7:
309 return 1
310 else:
311 return 0
312
313 def _cache_format(self, meta):
314
315 if 'cast' in meta:
316 meta['cast'] = eval(str(meta['cast']))
317 return meta
318
319 def _format(self, meta, name):
320 _meta = {}
321
322 if not 'title' in meta:
323 _meta['title'] = name
324 else:
325 _meta['title'] = meta['title']
326 if 'id' in meta:
327 _meta['tmdb_id'] = meta['id']
328 if 'imdb_id' in meta:
329 _meta['imdb_id'] = meta['imdb_id']
330 if 'runtime' in meta:
331 if meta['runtime'] > 0:
332 _meta['duration'] = int(meta['runtime']) *60
333 else:
334 _meta['duration'] = 0
335 _meta['plot'] = meta['overview']
336 if 'certification' in meta:
337 _meta['mpaa'] = meta['certification']
338 if 'release_date' in meta:
339 _meta['year'] = int(meta['release_date'][:4])
340 # if not 'year' in meta and 'premiered' in _meta:
341 # _meta['year'] = _meta['premiered']
342
343 if 'genres' in meta:
344 _meta['genre'] = ""
345 for genre in meta['genres']:
346 if _meta['genre'] == "":
347 _meta['genre'] += genre['name']
348 else:
349 _meta['genre'] += '/'+genre['name']
350
351 if 'backdrop_path' in meta:
352 _meta['backdrop_url'] = self.fanart+str(meta['backdrop_path'])
353 if 'poster_path' in meta:
354 _meta['cover_url'] = self.poster+str(meta['poster_path'])
355
356 if not 'playcount' in meta:
357 _meta['playcount'] = self.__set_playcount(6)
358
359 if 'cast' in meta:
360 xbmc.log("passeeeeeeeeeeeeeeeeeee")
361 _meta['cast'] = json.loads(_meta['cast'])
362
363 if 'casts' in meta:
364 #meta['cast'] = str(meta['casts']['cast'])
365 licast = []
366 for cast in meta['casts']['cast']:
367 licast.append((cast['name'], cast['character']))
368 _meta['cast'] = licast
369
370
371 #ont prend juste le premier
372 try:
373 _meta['trailer'] = 'plugin://plugin.video.youtube/?action=play_video&videoid=%s' % meta['trailers']['youtube'][0]['source']
374 except:
375 _meta['trailer'] = ''
376
377
378 return _meta
379
380 def _clean_title(self, title):
381 title= title.replace(' ', '')
382 title = title.lower()
383 return title
384
385
386 def _cache_search(self, media_type, name, tmdb_id='', year=''):
387 if media_type == 'movie':
388 sql_select = "SELECT * FROM movie"
389 if tmdb_id:
390 sql_select = sql_select + " WHERE tmdb_id = '%s'" % tmdb_id
391 else:
392 sql_select = sql_select + " WHERE title = '%s'" % name
393
394 if year:
395 sql_select = sql_select + " AND year = %s" % year
396 xbmc.log(sql_select)
397 try:
398 self.dbcur.execute(sql_select)
399 matchedrow = self.dbcur.fetchone()
400 except Exception, e:
401 xbmc.log('************* Error selecting from cache db: %s' % e, 4)
402 return None
403
404 if matchedrow:
405 xbmc.log('Found meta information by name in cache table')
406 return self._cache_format(dict(matchedrow))
407 else:
408 xbmc.log('No match in local DB', 0)
409 return None
410
411 def _cache_save(self, meta, name, media_type, overlay):
412
413 metadb = copy.copy(meta)
414 metadb['title'] = name
415 #list en str
416 metadb['cast'] = str(metadb['cast'])
417 #news_meta['CastAndRole'] = str(news_meta['CastAndRole'])
418
419 columns = ', '.join(metadb.keys())
420 placeholders = ':'+', :'.join(metadb.keys())
421 sql = 'INSERT INTO movie (%s) VALUES (%s)' % (columns, placeholders)
422 self.dbcur.execute(sql, metadb)
423 try:
424 self.db.commit()
425 cConfig().log('SQL INSERT Successfully')
426 except Exception, e:
427 #print ('************* Error attempting to insert into %s cache table: %s ' % (table, e))
428 cConfig().log('SQL ERROR INSERT')
429 pass
430 self.db.close()
431
432 def get_meta(self, media_type, name, imdb_id='', tmdb_id='', year='', overlay=6, update=False):
433 '''
434 Main method to get meta data for movie or tvshow. Will lookup by name/year
435 if no IMDB ID supplied.
436
437 Args:
438 media_type (str): 'movie' or 'tvshow'
439 name (str): full name of movie/tvshow you are searching
440 Kwargs:
441 imdb_id (str): IMDB ID
442 tmdb_id (str): TMDB ID
443 year (str): 4 digit year of video, recommended to include the year whenever possible
444 to maximize correct search results.
445 overlay (int): To set the default watched status (6=unwatched, 7=watched) on new videos
446
447 Returns:
448 DICT of meta data or None if cannot be found.
449 '''
450
451 xbmc.log('vstream Meta', 0)
452 xbmc.log('Attempting to retrieve meta data for %s: %s %s %s %s' % (media_type, name, year, imdb_id, tmdb_id), 0)
453 #recherche dans la base de donner
454 if not update:
455 meta = self._cache_search(media_type, self._clean_title(name), tmdb_id, year)
456 else:
457 meta = {}
458
459 xbmc.log("meta chacheeeee")
460 #xbmc.log(str(meta))
461
462 #recherche online
463
464 if not meta:
465
466 if media_type=='movie':
467 if tmdb_id:
468 meta = self.search_movie_id(tmdb_id)
469 else:
470 #meta = self.search_movie_name(name, year)
471 meta = threading.Thread(target=self.search_movie_name, args=(name,year)).start()
472 #meta.start()
473 elif media_type=='tvshow':
474 if tmdb_id:
475 meta = self.search_tvshow_id(tmdb_id)
476 else:
477 meta = self.search_tvshow_name(name, year)
478 #meta = self.__format_meta(media_type, meta, name)
479 #transforme les metas
480 if meta:
481 meta = self._format(meta, name)
482 #ecrit dans le cache
483 self._cache_save(meta, self._clean_title(name), media_type, overlay)
484
485 else:
486 #utiliser par l'addon donc plante si y a vraiment pas de reponse.
487 meta['title'] = name
488 meta['imdb_id'] = ''
489 meta['tmdb_id'] = ''
490 meta['tvdb_id'] = ''
491 meta['backdrop_url'] = ''
492 meta['cover_url'] = ''
493
494 return meta
495
496
497 def _call(self, action, append_to_response):
498 url = '%s%s?api_key=%s&%s&language=%s' % (self.URL, action, self.api_key, append_to_response, self.lang)
499 response = urlopen(url)
500 xbmc.log(url)
501 data = json.loads(response.read())
502 if self.debug:
503 pprint.pprint(data)
504 print 'URL: ' + url
505 return data