Updated kodi settings on Lenovo
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
310
Kodi/Lenovo/addons/script.embuary.info/resources/lib/helper.py
Normal file
310
Kodi/Lenovo/addons/script.embuary.info/resources/lib/helper.py
Normal file
@@ -0,0 +1,310 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
import xbmcplugin
|
||||
import json
|
||||
import time
|
||||
import datetime
|
||||
import os
|
||||
import operator
|
||||
import arrow
|
||||
import sys
|
||||
import simplecache
|
||||
import hashlib
|
||||
|
||||
########################
|
||||
|
||||
ADDON = xbmcaddon.Addon()
|
||||
ADDON_ID = ADDON.getAddonInfo('id')
|
||||
ADDON_VERSION = ADDON.getAddonInfo('version')
|
||||
ADDON_PATH = ADDON.getAddonInfo('path')
|
||||
|
||||
INFO = xbmc.LOGINFO
|
||||
WARNING = xbmc.LOGWARNING
|
||||
DEBUG = xbmc.LOGDEBUG
|
||||
ERROR = xbmc.LOGERROR
|
||||
|
||||
DIALOG = xbmcgui.Dialog()
|
||||
|
||||
COUNTRY_CODE = ADDON.getSettingString('country_code')
|
||||
DEFAULT_LANGUAGE = ADDON.getSettingString('language_code')
|
||||
FALLBACK_LANGUAGE = 'en'
|
||||
|
||||
CACHE = simplecache.SimpleCache()
|
||||
CACHE.enable_mem_cache = False
|
||||
CACHE.data_is_json = True
|
||||
CACHE_ENABLED = ADDON.getSettingBool('cache_enabled')
|
||||
CACHE_PREFIX = ADDON_ID + '_' + ADDON_VERSION + '_' + DEFAULT_LANGUAGE + COUNTRY_CODE + '_'
|
||||
|
||||
#TIMEZONE = 'US/Alaska'
|
||||
TIMEZONE = 'local'
|
||||
|
||||
########################
|
||||
|
||||
def log(txt,loglevel=DEBUG,json=False,force=False):
|
||||
if force:
|
||||
loglevel = INFO
|
||||
|
||||
if json:
|
||||
txt = json_prettyprint(txt)
|
||||
|
||||
message = u'[ %s ] %s' % (ADDON_ID,txt)
|
||||
xbmc.log(msg=message, level=loglevel)
|
||||
|
||||
|
||||
def get_cache(key):
|
||||
if CACHE_ENABLED:
|
||||
return CACHE.get(CACHE_PREFIX + key)
|
||||
|
||||
|
||||
def write_cache(key,data,cache_time=336):
|
||||
if data:
|
||||
CACHE.set(CACHE_PREFIX + key, data, expiration=datetime.timedelta(hours=cache_time))
|
||||
|
||||
|
||||
def format_currency(integer):
|
||||
try:
|
||||
integer = int(integer)
|
||||
if integer < 1:
|
||||
raise Exception
|
||||
|
||||
return '{:,.0f}'.format(integer)
|
||||
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
|
||||
def sort_dict(items,key,reverse=False):
|
||||
''' Dummy date to always add planned or rumored items at the end of the list
|
||||
if no release date is available yet.
|
||||
'''
|
||||
for item in items:
|
||||
if not item.get(key):
|
||||
if not reverse:
|
||||
item[key] = '2999-01-01'
|
||||
else:
|
||||
item[key] = '1900-01-01'
|
||||
|
||||
return sorted(items, key=operator.itemgetter(key),reverse=reverse)
|
||||
|
||||
|
||||
def remove_quotes(label):
|
||||
if not label:
|
||||
return ''
|
||||
|
||||
if label.startswith("'") and label.endswith("'") and len(label) > 2:
|
||||
label = label[1:-1]
|
||||
if label.startswith('"') and label.endswith('"') and len(label) > 2:
|
||||
label = label[1:-1]
|
||||
|
||||
return label
|
||||
|
||||
|
||||
def get_date(date_time):
|
||||
date_time_obj = datetime.datetime.strptime(date_time, '%Y-%m-%d %H:%M:%S')
|
||||
date_obj = date_time_obj.date()
|
||||
|
||||
return date_obj
|
||||
|
||||
|
||||
def execute(cmd):
|
||||
xbmc.executebuiltin(cmd)
|
||||
|
||||
|
||||
def condition(condition):
|
||||
return xbmc.getCondVisibility(condition)
|
||||
|
||||
|
||||
def busydialog(close=False):
|
||||
if not close and not condition('Window.IsVisible(busydialognocancel)'):
|
||||
execute('ActivateWindow(busydialognocancel)')
|
||||
elif close:
|
||||
execute('Dialog.Close(busydialognocancel)')
|
||||
|
||||
|
||||
def textviewer(params):
|
||||
DIALOG.textviewer(remove_quotes(params.get('header', '')), remove_quotes(params.get('message', '')))
|
||||
|
||||
|
||||
def winprop(key,value=None,clear=False,window_id=10000):
|
||||
window = xbmcgui.Window(window_id)
|
||||
|
||||
if clear:
|
||||
window.clearProperty(key.replace('.json', '').replace('.bool', ''))
|
||||
|
||||
elif value is not None:
|
||||
|
||||
if key.endswith('.json'):
|
||||
key = key.replace('.json', '')
|
||||
value = json.dumps(value)
|
||||
|
||||
elif key.endswith('.bool'):
|
||||
key = key.replace('.bool', '')
|
||||
value = 'true' if value else 'false'
|
||||
|
||||
window.setProperty(key, value)
|
||||
|
||||
else:
|
||||
result = window.getProperty(key.replace('.json', '').replace('.bool', ''))
|
||||
|
||||
if result:
|
||||
if key.endswith('.json'):
|
||||
result = json.loads(result)
|
||||
elif key.endswith('.bool'):
|
||||
result = result in ('true', '1')
|
||||
|
||||
return result
|
||||
|
||||
def date_year(value):
|
||||
if not value:
|
||||
return value
|
||||
|
||||
try:
|
||||
year = str(arrow.get(value).year)
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return year
|
||||
|
||||
def date_format(value,date='short'):
|
||||
if not value:
|
||||
return value
|
||||
|
||||
try:
|
||||
date_time = arrow.get(value)
|
||||
value = date_time.strftime(xbmc.getRegion('date%s' % date))
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def date_delta(date):
|
||||
date = arrow.get(date, 'YYYY-MM-DD').date()
|
||||
return date - datetime.date.today()
|
||||
|
||||
|
||||
def date_weekday(date=None):
|
||||
if not date:
|
||||
utc = arrow.utcnow()
|
||||
date = utc.to(TIMEZONE).date()
|
||||
|
||||
try:
|
||||
weekdays = (xbmc.getLocalizedString(11), xbmc.getLocalizedString(12), xbmc.getLocalizedString(13), xbmc.getLocalizedString(14), xbmc.getLocalizedString(15), xbmc.getLocalizedString(16), xbmc.getLocalizedString(17))
|
||||
date = arrow.get(date).date()
|
||||
weekday = date.weekday()
|
||||
return weekdays[weekday], weekday
|
||||
|
||||
except Exception:
|
||||
return '', ''
|
||||
|
||||
|
||||
def utc_to_local(value):
|
||||
conv_date = arrow.get(value).to(TIMEZONE)
|
||||
conv_date_str = conv_date.strftime('%Y-%m-%d')
|
||||
|
||||
if xbmc.getRegion('time').startswith('%I'):
|
||||
conv_time_str = conv_date.strftime('%I:%M %p')
|
||||
else:
|
||||
conv_time_str = conv_date.strftime('%H:%M')
|
||||
|
||||
return conv_date_str, conv_time_str
|
||||
|
||||
|
||||
def get_bool(value,string='true'):
|
||||
try:
|
||||
if value.lower() == string:
|
||||
return True
|
||||
raise Exception
|
||||
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def get_joined_items(item):
|
||||
if len(item) > 0:
|
||||
item = ' / '.join(item)
|
||||
else:
|
||||
item = ''
|
||||
return item
|
||||
|
||||
|
||||
def get_first_item(item):
|
||||
if len(item) > 0:
|
||||
item = item[0]
|
||||
else:
|
||||
item = ''
|
||||
|
||||
return item
|
||||
|
||||
|
||||
def json_call(method,properties=None,sort=None,query_filter=None,limit=None,params=None,item=None,options=None,limits=None):
|
||||
json_string = {'jsonrpc': '2.0', 'id': 1, 'method': method, 'params': {}}
|
||||
|
||||
if properties is not None:
|
||||
json_string['params']['properties'] = properties
|
||||
|
||||
if limit is not None:
|
||||
json_string['params']['limits'] = {'start': 0, 'end': int(limit)}
|
||||
|
||||
if sort is not None:
|
||||
json_string['params']['sort'] = sort
|
||||
|
||||
if query_filter is not None:
|
||||
json_string['params']['filter'] = query_filter
|
||||
|
||||
if options is not None:
|
||||
json_string['params']['options'] = options
|
||||
|
||||
if limits is not None:
|
||||
json_string['params']['limits'] = limits
|
||||
|
||||
if item is not None:
|
||||
json_string['params']['item'] = item
|
||||
|
||||
if params is not None:
|
||||
json_string['params'].update(params)
|
||||
|
||||
json_string = json.dumps(json_string)
|
||||
|
||||
result = xbmc.executeJSONRPC(json_string)
|
||||
|
||||
''' Python 2 compatibility
|
||||
'''
|
||||
try:
|
||||
result = unicode(result, 'utf-8', errors='ignore')
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
return json.loads(result)
|
||||
|
||||
|
||||
def set_plugincontent(content=None,category=None):
|
||||
if category:
|
||||
xbmcplugin.setPluginCategory(int(sys.argv[1]), category)
|
||||
if content:
|
||||
xbmcplugin.setContent(int(sys.argv[1]), content)
|
||||
|
||||
|
||||
def json_prettyprint(string):
|
||||
return json.dumps(string, sort_keys=True, indent=4, separators=(',', ': '))
|
||||
|
||||
|
||||
def urljoin(*args):
|
||||
''' Joins given arguments into an url. Trailing but not leading slashes are
|
||||
stripped for each argument.
|
||||
'''
|
||||
arglist = [arg for arg in args if arg is not None]
|
||||
return '/'.join(map(lambda x: str(x).rstrip('/'), arglist))
|
||||
|
||||
|
||||
def md5hash(value):
|
||||
value = str(value).encode()
|
||||
return hashlib.md5(value).hexdigest()
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import json
|
||||
import sys
|
||||
import requests
|
||||
|
||||
from resources.lib.helper import *
|
||||
|
||||
########################
|
||||
|
||||
def get_local_media(force=False):
|
||||
local_media = get_cache('local_db')
|
||||
|
||||
if not local_media or force:
|
||||
local_media = {}
|
||||
local_media['shows'] = query_local_media('tvshow',
|
||||
get='VideoLibrary.GetTVShows',
|
||||
properties=['title', 'originaltitle', 'year', 'playcount', 'episode', 'watchedepisodes', 'uniqueid', 'art']
|
||||
)
|
||||
local_media['movies'] = query_local_media('movie',
|
||||
get='VideoLibrary.GetMovies',
|
||||
properties=['title', 'originaltitle', 'year', 'uniqueid', 'playcount', 'file', 'art']
|
||||
)
|
||||
|
||||
if local_media:
|
||||
write_cache('local_db', local_media, 24)
|
||||
|
||||
return local_media
|
||||
|
||||
|
||||
def query_local_media(dbtype,get,properties):
|
||||
items = json_call(get,properties,sort={'order': 'descending', 'method': 'year'})
|
||||
|
||||
try:
|
||||
items = items['result']['%ss' % dbtype]
|
||||
except Exception:
|
||||
return
|
||||
|
||||
local_items = []
|
||||
for item in items:
|
||||
local_items.append({'title': item.get('title', ''),
|
||||
'originaltitle': item.get('originaltitle', ''),
|
||||
'imdbnumber': item.get('uniqueid', {}).get('imdb', ''),
|
||||
'tmdbid': item.get('uniqueid', {}).get('tmdb', ''),
|
||||
'tvdbid': item.get('uniqueid', {}).get('tvdb', ''),
|
||||
'year': item.get('year', ''),
|
||||
'dbid': item.get('%sid' % dbtype, ''),
|
||||
'playcount': item.get('playcount', ''),
|
||||
'episodes': item.get('episode', ''),
|
||||
'watchedepisodes': item.get('watchedepisodes', ''),
|
||||
'file': item.get('file', ''),
|
||||
'art': item.get('art', {})}
|
||||
)
|
||||
|
||||
return local_items
|
||||
563
Kodi/Lenovo/addons/script.embuary.info/resources/lib/main.py
Normal file
563
Kodi/Lenovo/addons/script.embuary.info/resources/lib/main.py
Normal file
@@ -0,0 +1,563 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import sys
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
from resources.lib.helper import *
|
||||
from resources.lib.tmdb import *
|
||||
from resources.lib.person import *
|
||||
from resources.lib.video import *
|
||||
from resources.lib.season import *
|
||||
from resources.lib.localdb import *
|
||||
|
||||
########################
|
||||
|
||||
class TheMovieDB(object):
|
||||
def __init__(self,call,params):
|
||||
self.monitor = xbmc.Monitor()
|
||||
self.window_stack = []
|
||||
self.dialog_cache = {}
|
||||
self.call = call
|
||||
self.tmdb_id = params.get('tmdb_id')
|
||||
self.season = params.get('season')
|
||||
self.query = remove_quotes(params.get('query'))
|
||||
self.query_year = params.get('year')
|
||||
self.exact_search = True if params.get('exact') == 'true' else False
|
||||
self.external_id = params.get('external_id')
|
||||
self.dbid = params.get('dbid')
|
||||
|
||||
if self.call == 'tv':
|
||||
self.dbtype = 'tvshow'
|
||||
elif self.call == 'movie':
|
||||
self.dbtype = 'movie'
|
||||
|
||||
winprop('script.embuary.info-language_code', DEFAULT_LANGUAGE)
|
||||
winprop('script.embuary.info-country_code', COUNTRY_CODE)
|
||||
|
||||
busydialog()
|
||||
|
||||
if self.dbid and self.dbtype:
|
||||
self.tmdb_id = self.find_id(method='dbid')
|
||||
elif self.external_id:
|
||||
self.tmdb_id = self.find_id(method='external_id')
|
||||
elif self.query:
|
||||
self.tmdb_id = self.find_id(method='query')
|
||||
|
||||
if self.tmdb_id:
|
||||
self.call_params = {}
|
||||
|
||||
local_media = get_local_media()
|
||||
self.call_params['local_shows'] = local_media['shows']
|
||||
self.call_params['local_movies'] = local_media['movies']
|
||||
|
||||
self.entry_point()
|
||||
|
||||
busydialog(close=True)
|
||||
|
||||
|
||||
''' Search for tmdb_id based one a query string or external ID (IMDb or TVDb)
|
||||
'''
|
||||
def find_id(self,method):
|
||||
if method == 'dbid':
|
||||
method_details = 'VideoLibrary.Get%sDetails' % self.dbtype
|
||||
param = '%sid' % self.dbtype
|
||||
key_details = '%sdetails' % self.dbtype
|
||||
|
||||
dbinfo = json_call(method_details,
|
||||
properties=['uniqueid', 'year', 'title'],
|
||||
params={param: int(self.dbid)}
|
||||
)
|
||||
try:
|
||||
dbinfo = dbinfo['result'][key_details]
|
||||
except KeyError:
|
||||
return
|
||||
|
||||
uniqueid = dbinfo.get('uniqueid', {})
|
||||
|
||||
result = None
|
||||
for item in uniqueid:
|
||||
if uniqueid[item].startswith('tt'):
|
||||
result = tmdb_find(self.call, uniqueid[item])
|
||||
break
|
||||
|
||||
elif self.dbtype == 'tvshow' and item.lower() == 'tvdb' and uniqueid[item]:
|
||||
result = tmdb_find(self.call, uniqueid[item])
|
||||
break
|
||||
|
||||
if not result:
|
||||
self.query = dbinfo.get('title')
|
||||
self.query_year = dbinfo.get('year', '')
|
||||
|
||||
tmdb_id = self.find_id(method='query')
|
||||
return tmdb_id
|
||||
|
||||
elif method == 'external_id':
|
||||
result = tmdb_find(self.call, self.external_id)
|
||||
|
||||
if not result and self.query:
|
||||
self.find_id(method='query')
|
||||
|
||||
elif method == 'query':
|
||||
if ' / ' in self.query:
|
||||
query_values = self.query.split(' / ')
|
||||
position = tmdb_select_dialog_small(query_values)
|
||||
if position < 0:
|
||||
return ''
|
||||
else:
|
||||
self.query = query_values[position]
|
||||
|
||||
result = tmdb_search(self.call, self.query, self.query_year)
|
||||
|
||||
if self.exact_search:
|
||||
exact_results = []
|
||||
|
||||
for item in result:
|
||||
title = item.get('title') or item.get('name') or ''
|
||||
original_title = item.get('original_title') or item.get('original_name') or ''
|
||||
|
||||
if title.lower() == self.query.lower() or original_title.lower() == self.query.lower():
|
||||
if self.query_year:
|
||||
premiered = item.get('first_air_date', '') if self.call == 'tv' else item.get('release_date', '')
|
||||
if self.query_year == premiered[:-6]:
|
||||
exact_results.append(item)
|
||||
else:
|
||||
exact_results.append(item)
|
||||
|
||||
if exact_results:
|
||||
result = exact_results
|
||||
else:
|
||||
return ''
|
||||
|
||||
try:
|
||||
if len(result) > 1:
|
||||
position = tmdb_select_dialog(result, self.call)
|
||||
if position < 0:
|
||||
raise Exception
|
||||
else:
|
||||
position = 0
|
||||
|
||||
tmdb_id = result[position]['id']
|
||||
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
return tmdb_id
|
||||
|
||||
|
||||
''' Collect all data by the tmdb_id and build the dialogs.
|
||||
'''
|
||||
def entry_point(self):
|
||||
self.call_params['call'] = self.call
|
||||
self.call_params['tmdb_id'] = self.tmdb_id
|
||||
self.call_params['season'] = self.season
|
||||
self.request = self.call + str(self.tmdb_id)
|
||||
|
||||
busydialog()
|
||||
|
||||
if self.call == 'person':
|
||||
dialog = self.fetch_person()
|
||||
elif self.call == 'tv' and self.season:
|
||||
dialog = self.fetch_season()
|
||||
elif self.call == 'movie' or self.call == 'tv':
|
||||
dialog = self.fetch_video()
|
||||
|
||||
busydialog(close=True)
|
||||
|
||||
''' Open next dialog if information has been found. If not open the previous dialog again.
|
||||
'''
|
||||
if dialog:
|
||||
self.dialog_cache[self.request] = dialog
|
||||
self.dialog_manager(dialog)
|
||||
|
||||
elif self.window_stack:
|
||||
self.dialog_history()
|
||||
|
||||
else:
|
||||
self.quit()
|
||||
|
||||
def fetch_person(self):
|
||||
data = TMDBPersons(self.call_params)
|
||||
if not data['person']:
|
||||
return
|
||||
|
||||
dialog = DialogPerson('script-embuary-person.xml', ADDON_PATH, 'default', '1080i',
|
||||
person=data['person'],
|
||||
movies=data['movies'],
|
||||
tvshows=data['tvshows'],
|
||||
combined=data['combined'],
|
||||
images=data['images'],
|
||||
tmdb_id=self.tmdb_id
|
||||
)
|
||||
return dialog
|
||||
|
||||
def fetch_video(self):
|
||||
data = TMDBVideos(self.call_params)
|
||||
if not data['details']:
|
||||
return
|
||||
|
||||
dialog = DialogVideo('script-embuary-video.xml', ADDON_PATH, 'default', '1080i',
|
||||
details=data['details'],
|
||||
cast=data['cast'],
|
||||
crew=data['crew'],
|
||||
similar=data['similar'],
|
||||
youtube=data['youtube'],
|
||||
backdrops=data['backdrops'],
|
||||
posters=data['posters'],
|
||||
collection=data['collection'],
|
||||
seasons=data['seasons'],
|
||||
tmdb_id=self.tmdb_id
|
||||
)
|
||||
return dialog
|
||||
|
||||
def fetch_season(self):
|
||||
data = TMDBSeasons(self.call_params)
|
||||
if not data['details']:
|
||||
return
|
||||
|
||||
dialog = DialogSeason('script-embuary-video.xml', ADDON_PATH, 'default', '1080i',
|
||||
details=data['details'],
|
||||
cast=data['cast'],
|
||||
gueststars=data['gueststars'],
|
||||
posters=data['posters'],
|
||||
tmdb_id=self.tmdb_id
|
||||
)
|
||||
return dialog
|
||||
|
||||
|
||||
''' Dialog handler. Creates the window history, reopens dialogs from a stack
|
||||
or cache and is responsible for keeping the script alive.
|
||||
'''
|
||||
def dialog_manager(self,dialog):
|
||||
dialog.doModal()
|
||||
|
||||
try:
|
||||
next_id = dialog['id']
|
||||
next_call = dialog['call']
|
||||
next_season = dialog['season']
|
||||
|
||||
if next_call == 'youtube':
|
||||
while condition('Player.HasMedia | Window.IsVisible(busydialog) | Window.IsVisible(busydialognocancel) | Window.IsVisible(okdialog)') and not self.monitor.abortRequested():
|
||||
self.monitor.waitForAbort(1)
|
||||
|
||||
# reopen dialog after playback ended
|
||||
self.dialog_manager(dialog)
|
||||
|
||||
if next_call == 'back':
|
||||
self.dialog_history()
|
||||
|
||||
if next_call == 'close':
|
||||
raise Exception
|
||||
|
||||
if not next_id or not next_call:
|
||||
raise Exception
|
||||
|
||||
self.window_stack.append(dialog)
|
||||
self.tmdb_id = next_id
|
||||
self.call = next_call
|
||||
self.season = next_season
|
||||
self.request = next_call + str(next_id) + str(next_season)
|
||||
|
||||
if self.dialog_cache.get(self.request):
|
||||
dialog = self.dialog_cache[self.request]
|
||||
self.dialog_manager(dialog)
|
||||
else:
|
||||
self.entry_point()
|
||||
|
||||
except Exception:
|
||||
self.quit()
|
||||
|
||||
def dialog_history(self):
|
||||
if self.window_stack:
|
||||
dialog = self.window_stack.pop()
|
||||
self.dialog_manager(dialog)
|
||||
else:
|
||||
self.quit()
|
||||
|
||||
def quit(self):
|
||||
del self.call_params
|
||||
del self.window_stack
|
||||
del self.dialog_cache
|
||||
quit()
|
||||
|
||||
|
||||
''' Person dialog
|
||||
'''
|
||||
class DialogPerson(xbmcgui.WindowXMLDialog):
|
||||
def __init__(self,*args,**kwargs):
|
||||
self.first_load = True
|
||||
self.action = {}
|
||||
|
||||
self.tmdb_id = kwargs['tmdb_id']
|
||||
self.person = kwargs['person']
|
||||
self.movies = kwargs['movies']
|
||||
self.tvshows = kwargs['tvshows']
|
||||
self.combined = kwargs['combined']
|
||||
self.images = kwargs['images']
|
||||
|
||||
def __getitem__(self,key):
|
||||
return self.action[key]
|
||||
|
||||
def __setitem__(self,key,value):
|
||||
self.action[key] = value
|
||||
|
||||
def onInit(self):
|
||||
execute('ClearProperty(script.embuary.info-nextcall,home)')
|
||||
|
||||
if self.first_load:
|
||||
self.add_items()
|
||||
|
||||
def add_items(self):
|
||||
self.first_load = False
|
||||
|
||||
index = 10051
|
||||
li = [self.person, self.movies, self.tvshows, self.images, self.combined]
|
||||
|
||||
for items in li:
|
||||
try:
|
||||
clist = self.getControl(index)
|
||||
clist.addItems(items)
|
||||
except RuntimeError as error:
|
||||
log('Control with id %s cannot be filled. Error --> %s' % (str(index), error), DEBUG)
|
||||
pass
|
||||
index += 1
|
||||
|
||||
def onAction(self,action):
|
||||
if action.getId() in [92,10]:
|
||||
self.action['id'] = ''
|
||||
self.action['season'] = ''
|
||||
self.action['call'] = 'back' if action.getId() == 92 else 'close'
|
||||
self.quit()
|
||||
|
||||
def onClick(self,controlId):
|
||||
next_id = xbmc.getInfoLabel('Container(%s).ListItem.Property(id)' % controlId)
|
||||
next_call = xbmc.getInfoLabel('Container(%s).ListItem.Property(call)' % controlId)
|
||||
|
||||
if next_call in ['person','movie','tv'] and next_id:
|
||||
self.action['id'] = next_id
|
||||
self.action['call'] = next_call
|
||||
self.action['season'] = ''
|
||||
self.quit()
|
||||
|
||||
elif next_call == 'image':
|
||||
FullScreenImage(controlId)
|
||||
|
||||
def quit(self):
|
||||
close_action = self.getProperty('onclose')
|
||||
onnext_action = self.getProperty('onnext')
|
||||
onback_action = self.getProperty('onback_%s' % self.getFocusId())
|
||||
|
||||
if self.action.get('call') and self.action.get('id'):
|
||||
execute('SetProperty(tmdb_next_call,true,home)')
|
||||
if onnext_action:
|
||||
execute(onnext_action)
|
||||
|
||||
if self.action.get('call') == 'back' and onback_action:
|
||||
execute(onback_action)
|
||||
|
||||
else:
|
||||
if close_action:
|
||||
execute(close_action)
|
||||
self.close()
|
||||
|
||||
|
||||
''' Show & movie dialog
|
||||
'''
|
||||
class DialogVideo(xbmcgui.WindowXMLDialog):
|
||||
def __init__(self,*args,**kwargs):
|
||||
self.first_load = True
|
||||
self.action = {}
|
||||
|
||||
self.tmdb_id = kwargs['tmdb_id']
|
||||
self.details = kwargs['details']
|
||||
self.cast = kwargs['cast']
|
||||
self.crew = kwargs['crew']
|
||||
self.similar = kwargs['similar']
|
||||
self.youtube = kwargs['youtube']
|
||||
self.backdrops = kwargs['backdrops']
|
||||
self.posters = kwargs['posters']
|
||||
self.seasons = kwargs['seasons']
|
||||
self.collection = kwargs['collection']
|
||||
|
||||
def __getitem__(self,key):
|
||||
return self.action[key]
|
||||
|
||||
def __setitem__(self,key,value):
|
||||
self.action[key] = value
|
||||
|
||||
def onInit(self):
|
||||
execute('ClearProperty(script.embuary.info-nextcall,home)')
|
||||
|
||||
if self.first_load:
|
||||
self.add_items()
|
||||
|
||||
def add_items(self):
|
||||
self.first_load = False
|
||||
|
||||
index = 10051
|
||||
li = [self.details, self.cast, self.similar, self.youtube, self.backdrops, self.crew, self.collection, self.seasons, self.posters]
|
||||
|
||||
for items in li:
|
||||
try:
|
||||
clist = self.getControl(index)
|
||||
clist.addItems(items)
|
||||
except RuntimeError as error:
|
||||
log('Control with id %s cannot be filled. Error --> %s' % (str(index), error), DEBUG)
|
||||
pass
|
||||
index += 1
|
||||
|
||||
def onAction(self,action):
|
||||
if action.getId() in [92,10]:
|
||||
self.action['id'] = ''
|
||||
self.action['season'] = ''
|
||||
self.action['call'] = 'back' if action.getId() == 92 else 'close'
|
||||
self.quit()
|
||||
|
||||
def onClick(self,controlId):
|
||||
next_id = xbmc.getInfoLabel('Container(%s).ListItem.Property(id)' % controlId)
|
||||
next_call = xbmc.getInfoLabel('Container(%s).ListItem.Property(call)' % controlId)
|
||||
next_season = xbmc.getInfoLabel('Container(%s).ListItem.Property(call_season)' % controlId)
|
||||
|
||||
if next_call in ['person','movie','tv'] and next_id:
|
||||
if next_id != str(self.tmdb_id) or next_season:
|
||||
self.action['id'] = next_id
|
||||
self.action['call'] = next_call
|
||||
self.action['season'] = next_season
|
||||
self.quit()
|
||||
|
||||
elif next_call == 'image':
|
||||
FullScreenImage(controlId)
|
||||
|
||||
elif next_call == 'youtube':
|
||||
self.action['id'] = ''
|
||||
self.action['season'] = ''
|
||||
self.action['call'] = 'youtube'
|
||||
xbmc.Player().play('plugin://plugin.video.youtube/play/?video_id=%s' % xbmc.getInfoLabel('Container(%s).ListItem.Property(ytid)' % controlId))
|
||||
self.quit()
|
||||
|
||||
def quit(self):
|
||||
close_action = self.getProperty('onclose')
|
||||
onnext_action = self.getProperty('onnext')
|
||||
onback_action = self.getProperty('onback_%s' % self.getFocusId())
|
||||
|
||||
if self.action.get('call') and self.action.get('id'):
|
||||
execute('SetProperty(script.embuary.info-nextcall,true,home)')
|
||||
if onnext_action:
|
||||
execute(onnext_action)
|
||||
|
||||
if self.action.get('call') == 'back' and onback_action:
|
||||
execute(onback_action)
|
||||
|
||||
else:
|
||||
if close_action:
|
||||
execute(close_action)
|
||||
self.close()
|
||||
|
||||
|
||||
''' Season dialog
|
||||
'''
|
||||
class DialogSeason(xbmcgui.WindowXMLDialog):
|
||||
def __init__(self,*args,**kwargs):
|
||||
self.first_load = True
|
||||
self.action = {}
|
||||
|
||||
self.tmdb_id = kwargs['tmdb_id']
|
||||
self.details = kwargs['details']
|
||||
self.cast = kwargs['cast']
|
||||
self.gueststars = kwargs['gueststars']
|
||||
self.posters = kwargs['posters']
|
||||
|
||||
def __getitem__(self,key):
|
||||
return self.action[key]
|
||||
|
||||
def __setitem__(self,key,value):
|
||||
self.action[key] = value
|
||||
|
||||
def onInit(self):
|
||||
execute('ClearProperty(script.embuary.info-nextcall,home)')
|
||||
|
||||
if self.first_load:
|
||||
self.add_items()
|
||||
|
||||
def add_items(self):
|
||||
self.first_load = False
|
||||
|
||||
index = [10051, 10052, 10056, 10059]
|
||||
li = [self.details, self.cast, self.gueststars, self.posters]
|
||||
|
||||
for items in li:
|
||||
try:
|
||||
clist = self.getControl(index[li.index(items)])
|
||||
clist.addItems(items)
|
||||
except RuntimeError as error:
|
||||
log('Control with id %s cannot be filled. Error --> %s' % (str(index[li.index(items)]), error), DEBUG)
|
||||
pass
|
||||
|
||||
def onAction(self,action):
|
||||
if action.getId() in [92,10]:
|
||||
self.action['id'] = ''
|
||||
self.action['season'] = ''
|
||||
self.action['call'] = 'back' if action.getId() == 92 else 'close'
|
||||
self.quit()
|
||||
|
||||
def onClick(self,controlId):
|
||||
next_id = xbmc.getInfoLabel('Container(%s).ListItem.Property(id)' % controlId)
|
||||
next_call = xbmc.getInfoLabel('Container(%s).ListItem.Property(call)' % controlId)
|
||||
|
||||
if next_call in ['person'] and next_id:
|
||||
self.action['id'] = next_id
|
||||
self.action['call'] = next_call
|
||||
self.action['season'] = ''
|
||||
self.quit()
|
||||
|
||||
elif next_call == 'image':
|
||||
FullScreenImage(controlId)
|
||||
|
||||
def quit(self):
|
||||
close_action = self.getProperty('onclose')
|
||||
onnext_action = self.getProperty('onnext')
|
||||
onback_action = self.getProperty('onback_%s' % self.getFocusId())
|
||||
|
||||
if self.action.get('call') and self.action.get('id'):
|
||||
execute('SetProperty(script.embuary.info-nextcall,true,home)')
|
||||
if onnext_action:
|
||||
execute(onnext_action)
|
||||
|
||||
if self.action.get('call') == 'back' and onback_action:
|
||||
execute(onback_action)
|
||||
|
||||
else:
|
||||
if close_action:
|
||||
execute(close_action)
|
||||
self.close()
|
||||
|
||||
|
||||
''' Slideshow dialog
|
||||
'''
|
||||
class FullScreenImage(object):
|
||||
def __init__(self,controlId):
|
||||
slideshow = []
|
||||
for i in range(int(xbmc.getInfoLabel('Container(%s).NumItems' % controlId))):
|
||||
slideshow.append(xbmc.getInfoLabel('Container(%s).ListItemAbsolute(%s).Art(thumb)' % (controlId,i)))
|
||||
|
||||
dialog = self.ShowImage('script-embuary-image.xml', ADDON_PATH, 'default', '1080i', slideshow=slideshow, position=xbmc.getInfoLabel('Container(%s).CurrentItem' % controlId))
|
||||
dialog.doModal()
|
||||
del dialog
|
||||
|
||||
class ShowImage(xbmcgui.WindowXMLDialog):
|
||||
def __init__(self,*args,**kwargs):
|
||||
self.position = int(kwargs['position']) - 1
|
||||
self.slideshow = list()
|
||||
for item in kwargs['slideshow']:
|
||||
list_item = xbmcgui.ListItem(label='')
|
||||
list_item.setArt({'icon': item})
|
||||
self.slideshow.append(list_item)
|
||||
|
||||
def onInit(self):
|
||||
self.cont = self.getControl(1)
|
||||
self.cont.addItems(self.slideshow)
|
||||
self.cont.selectItem(self.position)
|
||||
self.setFocusId(2)
|
||||
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import requests
|
||||
|
||||
from resources.lib.helper import *
|
||||
from resources.lib.tmdb import *
|
||||
from resources.lib.trakt import *
|
||||
from resources.lib.localdb import *
|
||||
|
||||
########################
|
||||
|
||||
class NextAired():
|
||||
def __init__(self):
|
||||
utc_date = arrow.utcnow()
|
||||
local_date = utc_date.to(TIMEZONE)
|
||||
self.date_today = utc_date.strftime('%Y-%m-%d')
|
||||
|
||||
local_media = get_local_media()
|
||||
self.local_media = local_media['shows']
|
||||
|
||||
if self.local_media:
|
||||
for item in self.local_media:
|
||||
del item['playcount']
|
||||
del item['watchedepisodes']
|
||||
|
||||
cache_key = 'nextaired_' + self.date_today + '_' + md5hash(self.local_media)
|
||||
self.airing_items = get_cache(cache_key)
|
||||
|
||||
if not self.airing_items:
|
||||
self.valid_days = []
|
||||
tmp_day = local_date
|
||||
for i in range(7):
|
||||
self.valid_days.append(tmp_day.strftime('%Y-%m-%d'))
|
||||
tmp_day = tmp_day.shift(days=1)
|
||||
|
||||
airing_items = {}
|
||||
airing_items['week'] = []
|
||||
airing_items['0'] = []
|
||||
airing_items['1'] = []
|
||||
airing_items['2'] = []
|
||||
airing_items['3'] = []
|
||||
airing_items['4'] = []
|
||||
airing_items['5'] = []
|
||||
airing_items['6'] = []
|
||||
|
||||
self.airing_items = airing_items
|
||||
self.getdata()
|
||||
|
||||
if self.airing_items:
|
||||
write_cache(cache_key, self.airing_items, 24)
|
||||
|
||||
def get(self,day=None):
|
||||
if day is not None and day in self.airing_items:
|
||||
return self.airing_items[day]
|
||||
else:
|
||||
return self.airing_items['week']
|
||||
|
||||
def getdata(self):
|
||||
if not self.local_media:
|
||||
return
|
||||
|
||||
local_media_data = []
|
||||
for item in self.local_media:
|
||||
local_media_data.append([item.get('tmdbid'), item.get('tvdbid'), item.get('imdbnumber'), item.get('art'), item.get('title'), item.get('originaltitle'), item.get('year')])
|
||||
|
||||
trakt_results = trakt_api('/calendars/all/shows/' + self.date_today + '/8?extended=full&countries=' + COUNTRY_CODE.lower() + '%2Cus')
|
||||
|
||||
if trakt_results:
|
||||
for item in trakt_results:
|
||||
airing_date, airing_time = utc_to_local(item.get('first_aired'))
|
||||
weekday, weekday_code = date_weekday(airing_date)
|
||||
|
||||
''' Because Trakt is using UTC dates it's possible that the airing item is already in the past
|
||||
for some timezones. Let's compare the converted airing date and only pick the ones for the
|
||||
users timezone.
|
||||
'''
|
||||
if airing_date not in self.valid_days:
|
||||
continue
|
||||
|
||||
show = item.get('show', {})
|
||||
episode = item.get('episode', {})
|
||||
|
||||
tvshowtitle = show.get('title')
|
||||
network = show.get('network')
|
||||
country = show.get('country')
|
||||
status = show.get('status')
|
||||
runtime = episode.get('runtime') * 60 if episode.get('runtime') else 0
|
||||
year = show.get('year')
|
||||
tmdb_id = show.get('ids', {}).get('tmdb')
|
||||
tvdb_id = show.get('ids', {}).get('tvdb')
|
||||
imdb_id = show.get('ids', {}).get('imdb')
|
||||
tvdb_id_episode = episode.get('ids', {}).get('tvdb')
|
||||
tmdb_id_episode = episode.get('ids', {}).get('tmdb')
|
||||
season_nr = episode.get('season')
|
||||
episode_nr = episode.get('number')
|
||||
|
||||
for i in local_media_data:
|
||||
if str(tmdb_id) == i[0] or str(tvdb_id) == i[1] or str(imdb_id) == i[2] or (tvshowtitle in [i[4], i[5]] and year == i[6]):
|
||||
episode_cache_key = 'nextaired_tmdb_episode_' + COUNTRY_CODE + '_' + str(tmdb_id_episode)
|
||||
episode_query = get_cache(episode_cache_key)
|
||||
|
||||
if not episode_query:
|
||||
episode_query = tmdb_query(action='tv',
|
||||
call=tmdb_id,
|
||||
get='season',
|
||||
get2=season_nr,
|
||||
get3='episode',
|
||||
get4=episode_nr,
|
||||
params={'append_to_response': 'translations'}
|
||||
)
|
||||
|
||||
if episode_query:
|
||||
write_cache(episode_cache_key, episode_query, 48)
|
||||
|
||||
if episode_query:
|
||||
episode_query['localart'] = i[3]
|
||||
episode_query['showtitle'] = i[4] or i[5]
|
||||
episode_query['airing'] = airing_date
|
||||
episode_query['airing_time'] = airing_time
|
||||
episode_query['weekday'] = weekday
|
||||
episode_query['weekday_code'] = weekday_code
|
||||
episode_query['network'] = network
|
||||
episode_query['country'] = country
|
||||
episode_query['status'] = status
|
||||
episode_query['runtime'] = runtime
|
||||
episode_query['show_id'] = tmdb_id
|
||||
episode_query['overview'] = tmdb_fallback_info(episode_query, 'overview')
|
||||
episode_query['name'] = tmdb_fallback_info(episode_query, 'name')
|
||||
|
||||
self.airing_items['week'].append(episode_query)
|
||||
self.airing_items[str(weekday_code)].append(episode_query)
|
||||
|
||||
break
|
||||
84
Kodi/Lenovo/addons/script.embuary.info/resources/lib/omdb.py
Normal file
84
Kodi/Lenovo/addons/script.embuary.info/resources/lib/omdb.py
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import json
|
||||
import sys
|
||||
import requests
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from resources.lib.helper import *
|
||||
|
||||
########################
|
||||
|
||||
OMDB_API_KEY = ADDON.getSettingString('omdb_api_key')
|
||||
|
||||
########################
|
||||
|
||||
def omdb_api(imdbnumber=None,title=None,year=None,content_type=None):
|
||||
if imdbnumber:
|
||||
url = 'http://www.omdbapi.com/?apikey=%s&i=%s&plot=short&r=xml&tomatoes=true' % (OMDB_API_KEY, imdbnumber)
|
||||
|
||||
elif title and year and content_type:
|
||||
# urllib has issues with some asian letters
|
||||
try:
|
||||
title = urllib.quote(title)
|
||||
except KeyError:
|
||||
return
|
||||
|
||||
url = 'http://www.omdbapi.com/?apikey=%s&t=%s&year=%s&plot=short&r=xml&tomatoes=true' % (OMDB_API_KEY, title, year)
|
||||
|
||||
else:
|
||||
return
|
||||
|
||||
omdb = get_cache(url)
|
||||
if omdb:
|
||||
return omdb
|
||||
|
||||
elif OMDB_API_KEY:
|
||||
omdb = {}
|
||||
|
||||
for i in range(1,4): # loop if heavy server load
|
||||
try:
|
||||
request = requests.get(url, timeout=5)
|
||||
|
||||
if not request.ok:
|
||||
raise Exception(str(request.status_code))
|
||||
|
||||
result = request.text
|
||||
|
||||
tree = ET.ElementTree(ET.fromstring(result))
|
||||
root = tree.getroot()
|
||||
|
||||
for child in root:
|
||||
# imdb ratings
|
||||
omdb['imdbRating'] = child.get('imdbRating', '').replace('N/A', '')
|
||||
omdb['imdbVotes'] = child.get('imdbVotes', '0').replace('N/A', '0').replace(',', '')
|
||||
|
||||
# regular rotten rating
|
||||
omdb['tomatometerallcritics'] = child.get('tomatoMeter', '').replace('N/A', '')
|
||||
omdb['tomatometerallcritics_avg'] = child.get('tomatoRating', '').replace('N/A', '')
|
||||
omdb['tomatometerallcritics_votes'] = child.get('tomatoReviews', '0').replace('N/A', '0').replace(',', '')
|
||||
|
||||
# user rotten rating
|
||||
omdb['tomatometerallaudience'] = child.get('tomatoUserMeter', '').replace('N/A', '')
|
||||
omdb['tomatometerallaudience_avg'] = child.get('tomatoUserRating', '').replace('N/A', '')
|
||||
omdb['tomatometerallaudience_votes'] = child.get('tomatoUserReviews', '0').replace('N/A', '0').replace(',', '')
|
||||
|
||||
# metacritic
|
||||
omdb['metacritic'] = child.get('metascore', '').replace('N/A', '')
|
||||
|
||||
# other
|
||||
omdb['awards'] = child.get('awards', '').replace('N/A', '')
|
||||
omdb['DVD'] = date_format(child.get('DVD', '').replace('N/A', ''), scheme='DD MMM YYYY')
|
||||
|
||||
except Exception as error:
|
||||
log('OMDB Error: %s' % error)
|
||||
pass
|
||||
|
||||
else:
|
||||
write_cache(url,omdb)
|
||||
break
|
||||
|
||||
return omdb
|
||||
172
Kodi/Lenovo/addons/script.embuary.info/resources/lib/person.py
Normal file
172
Kodi/Lenovo/addons/script.embuary.info/resources/lib/person.py
Normal file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import sys
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
from resources.lib.helper import *
|
||||
from resources.lib.tmdb import *
|
||||
|
||||
########################
|
||||
|
||||
FILTER_MOVIES = ADDON.getSettingBool('filter_movies')
|
||||
FILTER_SHOWS = ADDON.getSettingBool('filter_shows')
|
||||
FILTER_SHOWS_BLACKLIST = [10763, 10764, 10767]
|
||||
FILTER_UPCOMING = ADDON.getSettingBool('filter_upcoming')
|
||||
FILTER_DAYDELTA = int(ADDON.getSetting('filter_daydelta'))
|
||||
|
||||
########################
|
||||
|
||||
class TMDBPersons(object):
|
||||
def __init__(self,call_request):
|
||||
self.tmdb_id = call_request['tmdb_id']
|
||||
self.local_movies = call_request['local_movies']
|
||||
self.local_shows = call_request['local_shows']
|
||||
self.result = {}
|
||||
|
||||
if self.tmdb_id:
|
||||
cache_key = 'person' + str(self.tmdb_id)
|
||||
self.details = get_cache(cache_key)
|
||||
|
||||
if not self.details:
|
||||
self.details = tmdb_query(action='person',
|
||||
call=self.tmdb_id,
|
||||
params={'append_to_response': 'translations,movie_credits,tv_credits,images'},
|
||||
show_error=True
|
||||
)
|
||||
|
||||
write_cache(cache_key, self.details)
|
||||
|
||||
if not self.details:
|
||||
return
|
||||
|
||||
self.local_movie_count = 0
|
||||
self.local_tv_count = 0
|
||||
self.all_credits = list()
|
||||
|
||||
self.result['movies'] = self.get_movie_list()
|
||||
self.result['tvshows'] = self.get_tvshow_list()
|
||||
self.result['combined'] = self.get_combined_list()
|
||||
self.result['person'] = self.get_person_details()
|
||||
self.result['images'] = self.get_person_images()
|
||||
|
||||
def __getitem__(self,key):
|
||||
return self.result.get(key, '')
|
||||
|
||||
def get_person_details(self):
|
||||
li = list()
|
||||
|
||||
list_item = tmdb_handle_person(self.details)
|
||||
list_item.setProperty('LocalMovies', str(self.local_movie_count))
|
||||
list_item.setProperty('LocalTVShows', str(self.local_tv_count))
|
||||
list_item.setProperty('LocalMedia', str(self.local_movie_count + self.local_tv_count))
|
||||
li.append(list_item)
|
||||
|
||||
return li
|
||||
|
||||
def get_combined_list(self):
|
||||
combined = sort_dict(self.all_credits, 'release_date', True)
|
||||
li = list()
|
||||
|
||||
for item in combined:
|
||||
if item['type'] == 'movie':
|
||||
list_item, is_local = tmdb_handle_movie(item, self.local_movies)
|
||||
|
||||
elif item['type'] =='tvshow':
|
||||
list_item, is_local = tmdb_handle_tvshow(item, self.local_shows)
|
||||
|
||||
li.append(list_item)
|
||||
|
||||
return li
|
||||
|
||||
def get_movie_list(self):
|
||||
movies = self.details['movie_credits']['cast']
|
||||
movies = sort_dict(movies, 'release_date', True)
|
||||
li = list()
|
||||
duplicate_handler = list()
|
||||
|
||||
for item in movies:
|
||||
skip_movie = False
|
||||
|
||||
''' Filter to only show real movies and to skip documentaries / behind the scenes / etc
|
||||
'''
|
||||
if FILTER_MOVIES:
|
||||
character = item.get('character')
|
||||
if character:
|
||||
for genre in item['genre_ids']:
|
||||
if genre == 99 and ('himself' in character.lower() or 'herself' in character.lower()):
|
||||
skip_movie = True
|
||||
break
|
||||
|
||||
''' Filter to hide in production or rumored future movies
|
||||
'''
|
||||
if FILTER_UPCOMING:
|
||||
diff = date_delta(item.get('release_date', '2900-01-01'))
|
||||
if diff.days > FILTER_DAYDELTA:
|
||||
skip_movie = True
|
||||
|
||||
if not skip_movie and item['id'] not in duplicate_handler:
|
||||
list_item, is_local = tmdb_handle_movie(item, self.local_movies)
|
||||
li.append(list_item)
|
||||
duplicate_handler.append(item['id'])
|
||||
item['type'] = 'movie'
|
||||
|
||||
if is_local:
|
||||
self.local_movie_count += 1
|
||||
|
||||
self.all_credits.append(item)
|
||||
|
||||
return li
|
||||
|
||||
def get_tvshow_list(self):
|
||||
tvshows = self.details['tv_credits']['cast']
|
||||
tvshows = sort_dict(tvshows, 'first_air_date', True)
|
||||
li = list()
|
||||
duplicate_handler = list()
|
||||
|
||||
for item in tvshows:
|
||||
skip_show = False
|
||||
|
||||
''' Filter to only show real TV series and to skip talk, reality or news shows
|
||||
'''
|
||||
if FILTER_SHOWS:
|
||||
if not item['genre_ids']:
|
||||
skip_show = True
|
||||
else:
|
||||
for genre in item['genre_ids']:
|
||||
if genre in FILTER_SHOWS_BLACKLIST:
|
||||
skip_show = True
|
||||
break
|
||||
|
||||
''' Filter to hide in production or rumored future shows
|
||||
'''
|
||||
if FILTER_UPCOMING:
|
||||
diff = date_delta(item.get('first_air_date', '2900-01-01'))
|
||||
if diff.days > FILTER_DAYDELTA:
|
||||
skip_show = True
|
||||
|
||||
if not skip_show and item['id'] not in duplicate_handler:
|
||||
list_item, is_local = tmdb_handle_tvshow(item, self.local_shows)
|
||||
li.append(list_item)
|
||||
duplicate_handler.append(item['id'])
|
||||
item['type'] = 'tvshow'
|
||||
item['release_date'] = item['first_air_date']
|
||||
|
||||
if is_local:
|
||||
self.local_tv_count += 1
|
||||
|
||||
self.all_credits.append(item)
|
||||
|
||||
return li
|
||||
|
||||
def get_person_images(self):
|
||||
li = list()
|
||||
|
||||
for item in self.details['images']['profiles']:
|
||||
list_item = tmdb_handle_images(item)
|
||||
li.append(list_item)
|
||||
|
||||
return li
|
||||
128
Kodi/Lenovo/addons/script.embuary.info/resources/lib/season.py
Normal file
128
Kodi/Lenovo/addons/script.embuary.info/resources/lib/season.py
Normal file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import sys
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import requests
|
||||
|
||||
from resources.lib.helper import *
|
||||
from resources.lib.tmdb import *
|
||||
|
||||
########################
|
||||
|
||||
class TMDBSeasons(object):
|
||||
def __init__(self,call_request):
|
||||
self.result = {}
|
||||
self.tmdb_id = call_request['tmdb_id']
|
||||
self.season = call_request['season']
|
||||
|
||||
if self.tmdb_id:
|
||||
cache_key = 'season' + str(self.season) + str(self.tmdb_id)
|
||||
self.details = get_cache(cache_key)
|
||||
|
||||
if not self.details:
|
||||
self.details = tmdb_query(action='tv',
|
||||
call=self.tmdb_id,
|
||||
get='season',
|
||||
get2=self.season,
|
||||
params={'append_to_response': 'credits'},
|
||||
show_error=True
|
||||
)
|
||||
|
||||
if not self.details:
|
||||
return
|
||||
|
||||
if DEFAULT_LANGUAGE != FALLBACK_LANGUAGE and not self.details['overview']:
|
||||
fallback_details = tmdb_query(action='tv',
|
||||
call=self.tmdb_id,
|
||||
get='season',
|
||||
get2=self.season,
|
||||
use_language=False
|
||||
)
|
||||
|
||||
self.details['overview'] = fallback_details.get('overview')
|
||||
|
||||
write_cache(cache_key,self.details)
|
||||
|
||||
self.tvshow_details = self.get_tvshow_details()
|
||||
self.person_duplicate_handler = list()
|
||||
|
||||
self.result['details'] = self.get_details()
|
||||
self.result['cast'] = self.get_cast()
|
||||
self.result['gueststars'] = self.get_gueststars()
|
||||
self.result['posters'] = self.get_images()
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.result.get(key,'')
|
||||
|
||||
def get_tvshow_details(self):
|
||||
tvshow_cache_key = 'tv' + str(self.tmdb_id)
|
||||
tvshow_details = get_cache(tvshow_cache_key)
|
||||
|
||||
if not tvshow_details:
|
||||
tvshow_details = tmdb_query(action='tv',
|
||||
call=self.tmdb_id,
|
||||
params={'append_to_response': 'release_dates,content_ratings,external_ids,credits,videos,translations,similar'}
|
||||
)
|
||||
|
||||
write_cache(tvshow_cache_key,tvshow_details)
|
||||
|
||||
return tvshow_details
|
||||
|
||||
def get_details(self):
|
||||
li = list()
|
||||
|
||||
list_item = tmdb_handle_season(self.details,self.tvshow_details,full_info=True)
|
||||
li.append(list_item)
|
||||
|
||||
return li
|
||||
|
||||
def get_cast(self):
|
||||
li = list()
|
||||
|
||||
for item in self.details['credits']['cast']:
|
||||
item['label2'] = item.get('character','')
|
||||
list_item = tmdb_handle_credits(item)
|
||||
li.append(list_item)
|
||||
self.person_duplicate_handler.append(item['id'])
|
||||
|
||||
return li
|
||||
|
||||
def get_gueststars(self):
|
||||
li = list()
|
||||
|
||||
for episode in self.details['episodes']:
|
||||
for item in episode['guest_stars']:
|
||||
|
||||
if item['id'] not in self.person_duplicate_handler and item['character']:
|
||||
item['label2'] = item['character']
|
||||
list_item = tmdb_handle_credits(item)
|
||||
li.append(list_item)
|
||||
self.person_duplicate_handler.append(item['id'])
|
||||
|
||||
return li
|
||||
|
||||
def get_images(self):
|
||||
cache_key = 'images' + str(self.tmdb_id) + 'season' + str(self.season)
|
||||
images = get_cache(cache_key)
|
||||
li = list()
|
||||
|
||||
if not images:
|
||||
images = tmdb_query(action='tv',
|
||||
call=self.tmdb_id,
|
||||
get='season',
|
||||
get2=self.season,
|
||||
get3='images',
|
||||
params={'include_image_language': '%s,en,null' % DEFAULT_LANGUAGE}
|
||||
)
|
||||
|
||||
write_cache(cache_key,images)
|
||||
|
||||
for item in images['posters']:
|
||||
list_item = tmdb_handle_images(item)
|
||||
li.append(list_item)
|
||||
|
||||
return li
|
||||
646
Kodi/Lenovo/addons/script.embuary.info/resources/lib/tmdb.py
Normal file
646
Kodi/Lenovo/addons/script.embuary.info/resources/lib/tmdb.py
Normal file
@@ -0,0 +1,646 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import requests
|
||||
import datetime
|
||||
import urllib.request as urllib
|
||||
from urllib.parse import urlencode
|
||||
|
||||
|
||||
from resources.lib.helper import *
|
||||
from resources.lib.omdb import *
|
||||
from resources.lib.localdb import *
|
||||
|
||||
########################
|
||||
|
||||
API_KEY = ADDON.getSettingString('tmdb_api_key')
|
||||
API_URL = 'https://api.themoviedb.org/3/'
|
||||
IMAGEPATH = 'https://image.tmdb.org/t/p/original'
|
||||
|
||||
########################
|
||||
|
||||
def tmdb_query(action,call=None,get=None,get2=None,get3=None,get4=None,params=None,use_language=True,language=DEFAULT_LANGUAGE,show_error=False):
|
||||
urlargs = {}
|
||||
urlargs['api_key'] = API_KEY
|
||||
|
||||
if use_language:
|
||||
urlargs['language'] = language
|
||||
|
||||
if params:
|
||||
urlargs.update(params)
|
||||
|
||||
url = urljoin(API_URL ,action, call, get, get2, get3, get4)
|
||||
url = '{0}?{1}'.format(url, urlencode(urlargs))
|
||||
|
||||
try:
|
||||
request = None
|
||||
|
||||
for i in range(1,4): # loop if heavy server load
|
||||
try:
|
||||
request = requests.get(url, timeout=5)
|
||||
|
||||
if str(request.status_code).startswith('5'):
|
||||
raise Exception(str(request.status_code))
|
||||
else:
|
||||
break
|
||||
|
||||
except Exception:
|
||||
xbmc.sleep(500)
|
||||
|
||||
if not request or request.status_code == 404:
|
||||
error = ADDON.getLocalizedString(32019)
|
||||
raise Exception(error)
|
||||
|
||||
elif request.status_code == 401:
|
||||
error = ADDON.getLocalizedString(32022)
|
||||
raise Exception(error)
|
||||
|
||||
elif not request.ok:
|
||||
raise Exception('Code ' + str(request.status_code))
|
||||
|
||||
result = request.json()
|
||||
|
||||
if show_error:
|
||||
if len(result) == 0 or ('results' in result and not len(result['results']) == 0):
|
||||
error = ADDON.getLocalizedString(32019)
|
||||
raise Exception(error)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as error:
|
||||
log('%s --> %s' % (error, url), ERROR)
|
||||
if show_error:
|
||||
tmdb_error(error)
|
||||
|
||||
|
||||
def tmdb_search(call,query,year=None,include_adult='false'):
|
||||
if call == 'person':
|
||||
params = {'query': query, 'include_adult': include_adult}
|
||||
|
||||
elif call == 'movie':
|
||||
params = {'query': query, 'year': year, 'include_adult': include_adult}
|
||||
|
||||
elif call == 'tv':
|
||||
params = {'query': query, 'first_air_date_year': year}
|
||||
|
||||
else:
|
||||
return ''
|
||||
|
||||
result = tmdb_query(action='search',
|
||||
call=call,
|
||||
params=params)
|
||||
|
||||
try:
|
||||
result = result.get('results')
|
||||
|
||||
if not result:
|
||||
raise Exception
|
||||
|
||||
return result
|
||||
|
||||
except Exception:
|
||||
tmdb_error(ADDON.getLocalizedString(32019))
|
||||
|
||||
|
||||
def tmdb_find(call,external_id,error_check=True):
|
||||
if external_id.startswith('tt'):
|
||||
external_source = 'imdb_id'
|
||||
else:
|
||||
external_source = 'tvdb_id'
|
||||
|
||||
result = tmdb_query(action='find',
|
||||
call=str(external_id),
|
||||
params={'external_source': external_source},
|
||||
use_language=False,
|
||||
show_error=True
|
||||
)
|
||||
try:
|
||||
if call == 'movie':
|
||||
return result.get('movie_results')
|
||||
else:
|
||||
return result.get('tv_results')
|
||||
|
||||
except AttributeError:
|
||||
return
|
||||
|
||||
def tmdb_select_dialog(list,call):
|
||||
indexlist = []
|
||||
selectionlist = []
|
||||
|
||||
if call == 'person':
|
||||
default_img = 'DefaultActor.png'
|
||||
img = 'profile_path'
|
||||
label = 'name'
|
||||
label2 = ''
|
||||
|
||||
elif call == 'movie':
|
||||
default_img = 'DefaultVideo.png'
|
||||
img = 'poster_path'
|
||||
label = 'title'
|
||||
label2 = 'tmdb_get_year(item.get("release_date", ""))'
|
||||
|
||||
elif call == 'tv':
|
||||
default_img = 'DefaultVideo.png'
|
||||
img = 'poster_path'
|
||||
label = 'name'
|
||||
label2 = 'first_air_date'
|
||||
label2 = 'tmdb_get_year(item.get("first_air_date", ""))'
|
||||
|
||||
else:
|
||||
return
|
||||
|
||||
index = 0
|
||||
for item in list:
|
||||
icon = IMAGEPATH + item[img] if item[img] is not None else ''
|
||||
list_item = xbmcgui.ListItem(item[label])
|
||||
list_item.setArt({'icon': default_img, 'thumb': icon})
|
||||
|
||||
try:
|
||||
list_item.setLabel2(str(eval(label2)))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
selectionlist.append(list_item)
|
||||
indexlist.append(index)
|
||||
index += 1
|
||||
|
||||
busydialog(close=True)
|
||||
|
||||
selected = DIALOG.select(xbmc.getLocalizedString(424), selectionlist, useDetails=True)
|
||||
|
||||
if selected == -1:
|
||||
return -1
|
||||
|
||||
busydialog()
|
||||
|
||||
return indexlist[selected]
|
||||
|
||||
|
||||
def tmdb_select_dialog_small(list):
|
||||
indexlist = []
|
||||
selectionlist = []
|
||||
|
||||
index = 0
|
||||
for item in list:
|
||||
list_item = xbmcgui.ListItem(item)
|
||||
selectionlist.append(list_item)
|
||||
indexlist.append(index)
|
||||
index += 1
|
||||
|
||||
busydialog(close=True)
|
||||
|
||||
selected = DIALOG.select(xbmc.getLocalizedString(424), selectionlist, useDetails=False)
|
||||
|
||||
if selected == -1:
|
||||
return -1
|
||||
|
||||
busydialog()
|
||||
|
||||
return indexlist[selected]
|
||||
|
||||
|
||||
def tmdb_calc_age(birthday,deathday=None):
|
||||
if deathday is not None:
|
||||
ref_day = deathday.split("-")
|
||||
|
||||
elif birthday:
|
||||
date = datetime.date.today()
|
||||
ref_day = [date.year, date.month, date.day]
|
||||
|
||||
else:
|
||||
return ''
|
||||
|
||||
born = birthday.split('-')
|
||||
age = int(ref_day[0]) - int(born[0])
|
||||
|
||||
if len(born) > 1:
|
||||
diff_months = int(ref_day[1]) - int(born[1])
|
||||
diff_days = int(ref_day[2]) - int(born[2])
|
||||
|
||||
if diff_months < 0 or (diff_months == 0 and diff_days < 0):
|
||||
age -= 1
|
||||
|
||||
return age
|
||||
|
||||
|
||||
def tmdb_error(message=ADDON.getLocalizedString(32019)):
|
||||
busydialog(close=True)
|
||||
DIALOG.ok(ADDON.getLocalizedString(32000), str(message))
|
||||
|
||||
|
||||
def tmdb_studios(list_item,item,key):
|
||||
if key == 'production':
|
||||
key_name = 'production_companies'
|
||||
prop_name = 'studio'
|
||||
elif key == 'network':
|
||||
key_name = 'networks'
|
||||
prop_name = 'network'
|
||||
else:
|
||||
return
|
||||
|
||||
i = 0
|
||||
for studio in item[key_name]:
|
||||
icon = IMAGEPATH + studio['logo_path'] if studio['logo_path'] is not None else ''
|
||||
if icon:
|
||||
list_item.setProperty(prop_name + '.' + str(i), studio['name'])
|
||||
list_item.setProperty(prop_name + '.icon.' + str(i), icon)
|
||||
i += 1
|
||||
|
||||
|
||||
def tmdb_check_localdb(local_items,title,originaltitle,year,imdbnumber=False):
|
||||
found_local = False
|
||||
local = {'dbid': -1, 'playcount': 0, 'watchedepisodes': '', 'episodes': '', 'unwatchedepisodes': '', 'file': ''}
|
||||
|
||||
if local_items:
|
||||
for item in local_items:
|
||||
dbid = item['dbid']
|
||||
playcount = item['playcount']
|
||||
episodes = item.get('episodes', '')
|
||||
watchedepisodes = item.get('watchedepisodes', '')
|
||||
file = item.get('file', '')
|
||||
|
||||
if imdbnumber and item['imdbnumber'] == imdbnumber:
|
||||
found_local = True
|
||||
break
|
||||
|
||||
try:
|
||||
tmdb_year = int(tmdb_get_year(year))
|
||||
item_year = int(item['year'])
|
||||
|
||||
if item_year == tmdb_year:
|
||||
if item['originaltitle'] == originaltitle or item['title'] == originaltitle or item['title'] == title:
|
||||
found_local = True
|
||||
break
|
||||
elif tmdb_year in [item_year-2, item_year-1, item_year+1, item_year+2]:
|
||||
if item['title'] == title and item['originaltitle'] == originaltitle:
|
||||
found_local = True
|
||||
break
|
||||
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if found_local:
|
||||
local['dbid'] = dbid
|
||||
local['file'] = file
|
||||
local['playcount'] = playcount
|
||||
local['episodes'] = episodes
|
||||
local['watchedepisodes'] = watchedepisodes
|
||||
local['unwatchedepisodes'] = episodes - watchedepisodes if episodes else ''
|
||||
|
||||
return local
|
||||
|
||||
|
||||
def tmdb_handle_person(item):
|
||||
if item.get('gender') == 2:
|
||||
gender = 'male'
|
||||
elif item.get('gender') == 1:
|
||||
gender = 'female'
|
||||
else:
|
||||
gender = ''
|
||||
|
||||
icon = IMAGEPATH + item['profile_path'] if item['profile_path'] is not None else ''
|
||||
list_item = xbmcgui.ListItem(label=item['name'])
|
||||
list_item.setProperty('birthyear', date_year(item.get('birthday', '')))
|
||||
list_item.setProperty('birthday', date_format(item.get('birthday', '')))
|
||||
list_item.setProperty('deathday', date_format(item.get('deathday', '')))
|
||||
list_item.setProperty('age', str(tmdb_calc_age(item.get('birthday', ''), item.get('deathday'))))
|
||||
list_item.setProperty('biography', tmdb_fallback_info(item, 'biography'))
|
||||
list_item.setProperty('place_of_birth', item.get('place_of_birth').strip() if item.get('place_of_birth') else '')
|
||||
list_item.setProperty('known_for_department', item.get('known_for_department', ''))
|
||||
list_item.setProperty('gender', gender)
|
||||
list_item.setProperty('id', str(item.get('id', '')))
|
||||
list_item.setProperty('call', 'person')
|
||||
list_item.setArt({'icon': 'DefaultActor.png', 'thumb': icon, 'poster': icon})
|
||||
|
||||
return list_item
|
||||
|
||||
|
||||
def tmdb_handle_movie(item,local_items=None,full_info=False,mediatype='movie'):
|
||||
icon = IMAGEPATH + item['poster_path'] if item['poster_path'] is not None else ''
|
||||
backdrop = IMAGEPATH + item['backdrop_path'] if item['backdrop_path'] is not None else ''
|
||||
|
||||
label = item['title'] or item['original_title']
|
||||
originaltitle = item.get('original_title', '')
|
||||
imdbnumber = item.get('imdb_id', '')
|
||||
collection = item.get('belongs_to_collection', '')
|
||||
duration = item.get('runtime') * 60 if item.get('runtime', 0) > 0 else ''
|
||||
|
||||
premiered = item.get('release_date')
|
||||
if premiered in ['2999-01-01', '1900-01-01']:
|
||||
premiered = ''
|
||||
|
||||
local_info = tmdb_check_localdb(local_items, label, originaltitle, premiered, imdbnumber)
|
||||
dbid = local_info['dbid']
|
||||
is_local = True if dbid > 0 else False
|
||||
|
||||
list_item = xbmcgui.ListItem(label=label)
|
||||
list_item.setInfo('video', {'title': label,
|
||||
'originaltitle': originaltitle,
|
||||
'dbid': dbid,
|
||||
'playcount': local_info['playcount'],
|
||||
'imdbnumber': imdbnumber,
|
||||
'rating': item.get('vote_average', ''),
|
||||
'votes': item.get('vote_count', ''),
|
||||
'premiered': premiered,
|
||||
'mpaa': tmdb_get_cert(item),
|
||||
'tagline': item.get('tagline', ''),
|
||||
'duration': duration,
|
||||
'status': item.get('status', ''),
|
||||
'plot': tmdb_fallback_info(item, 'overview'),
|
||||
'director': tmdb_join_items_by(item.get('crew', ''), key_is='job', value_is='Director'),
|
||||
'writer': tmdb_join_items_by(item.get('crew', ''), key_is='department', value_is='Writing'),
|
||||
'country': tmdb_join_items(item.get('production_countries', '')),
|
||||
'genre': tmdb_join_items(item.get('genres', '')),
|
||||
'studio': tmdb_join_items(item.get('production_companies', '')),
|
||||
'mediatype': mediatype}
|
||||
)
|
||||
list_item.setArt({'icon': 'DefaultVideo.png', 'thumb': icon, 'poster': icon, 'fanart': backdrop})
|
||||
list_item.setProperty('role', item.get('character', ''))
|
||||
list_item.setProperty('budget', format_currency(item.get('budget')))
|
||||
list_item.setProperty('revenue', format_currency(item.get('revenue')))
|
||||
list_item.setProperty('homepage', item.get('homepage', ''))
|
||||
list_item.setProperty('file', local_info.get('file', ''))
|
||||
list_item.setProperty('id', str(item.get('id', '')))
|
||||
list_item.setProperty('call', 'movie')
|
||||
|
||||
if full_info:
|
||||
tmdb_studios(list_item, item, 'production')
|
||||
omdb_properties(list_item, imdbnumber)
|
||||
|
||||
region_release = tmdb_get_region_release(item)
|
||||
if premiered != region_release:
|
||||
list_item.setProperty('region_release', date_format(region_release))
|
||||
|
||||
if collection:
|
||||
list_item.setProperty('collection', collection['name'])
|
||||
list_item.setProperty('collection_id', str(collection['id']))
|
||||
list_item.setProperty('collection_poster', IMAGEPATH + collection['poster_path'] if collection['poster_path'] is not None else '')
|
||||
list_item.setProperty('collection_fanart', IMAGEPATH + collection['backdrop_path'] if collection['backdrop_path'] is not None else '')
|
||||
|
||||
return list_item, is_local
|
||||
|
||||
|
||||
def tmdb_handle_tvshow(item,local_items=None,full_info=False,mediatype='tvshow'):
|
||||
icon = IMAGEPATH + item['poster_path'] if item['poster_path'] is not None else ''
|
||||
backdrop = IMAGEPATH + item['backdrop_path'] if item['backdrop_path'] is not None else ''
|
||||
|
||||
label = item['name'] or item['original_name']
|
||||
originaltitle = item.get('original_name', '')
|
||||
imdbnumber = item['external_ids']['imdb_id'] if item.get('external_ids') else ''
|
||||
next_episode = item.get('next_episode_to_air', '')
|
||||
last_episode = item.get('last_episode_to_air', '')
|
||||
tvdb_id = item['external_ids']['tvdb_id'] if item.get('external_ids') else ''
|
||||
|
||||
premiered = item.get('first_air_date')
|
||||
if premiered in ['2999-01-01', '1900-01-01']:
|
||||
premiered = ''
|
||||
|
||||
local_info = tmdb_check_localdb(local_items, label, originaltitle, premiered, tvdb_id)
|
||||
dbid = local_info['dbid']
|
||||
is_local = True if dbid > 0 else False
|
||||
|
||||
list_item = xbmcgui.ListItem(label=label)
|
||||
list_item.setInfo('video', {'title': label,
|
||||
'originaltitle': originaltitle,
|
||||
'dbid': dbid,
|
||||
'playcount': local_info['playcount'],
|
||||
'status': item.get('status', ''),
|
||||
'rating': item.get('vote_average', ''),
|
||||
'votes': item.get('vote_count', ''),
|
||||
'imdbnumber': imdbnumber,
|
||||
'premiered': premiered,
|
||||
'mpaa': tmdb_get_cert(item),
|
||||
'season': str(item.get('number_of_seasons', '')),
|
||||
'episode': str(item.get('number_of_episodes', '')),
|
||||
'plot': tmdb_fallback_info(item, 'overview'),
|
||||
'director': tmdb_join_items(item.get('created_by', '')),
|
||||
'genre': tmdb_join_items(item.get('genres', '')),
|
||||
'studio': tmdb_join_items(item.get('networks', '')),
|
||||
'mediatype': mediatype}
|
||||
)
|
||||
list_item.setArt({'icon': 'DefaultVideo.png', 'thumb': icon, 'poster': icon, 'fanart': backdrop})
|
||||
list_item.setProperty('TotalEpisodes', str(local_info['episodes']))
|
||||
list_item.setProperty('WatchedEpisodes', str(local_info['watchedepisodes']))
|
||||
list_item.setProperty('UnWatchedEpisodes', str(local_info['unwatchedepisodes']))
|
||||
list_item.setProperty('homepage', item.get('homepage', ''))
|
||||
list_item.setProperty('role', item.get('character', ''))
|
||||
list_item.setProperty('tvdb_id', str(tvdb_id))
|
||||
list_item.setProperty('id', str(item.get('id', '')))
|
||||
list_item.setProperty('call', 'tv')
|
||||
|
||||
if full_info:
|
||||
tmdb_studios(list_item,item, 'production')
|
||||
tmdb_studios(list_item,item, 'network')
|
||||
omdb_properties(list_item, imdbnumber)
|
||||
|
||||
if last_episode:
|
||||
list_item.setProperty('lastepisode', last_episode.get('name'))
|
||||
list_item.setProperty('lastepisode_plot', last_episode.get('overview'))
|
||||
list_item.setProperty('lastepisode_number', str(last_episode.get('episode_number')))
|
||||
list_item.setProperty('lastepisode_season', str(last_episode.get('season_number')))
|
||||
list_item.setProperty('lastepisode_date', date_format(last_episode.get('air_date')))
|
||||
list_item.setProperty('lastepisode_thumb', IMAGEPATH + last_episode['still_path'] if last_episode['still_path'] is not None else '')
|
||||
|
||||
if next_episode:
|
||||
list_item.setProperty('nextepisode', next_episode.get('name'))
|
||||
list_item.setProperty('nextepisode_plot', next_episode.get('overview'))
|
||||
list_item.setProperty('nextepisode_number', str(next_episode.get('episode_number')))
|
||||
list_item.setProperty('nextepisode_season', str(next_episode.get('season_number')))
|
||||
list_item.setProperty('nextepisode_date', date_format(next_episode.get('air_date')))
|
||||
list_item.setProperty('nextepisode_thumb', IMAGEPATH + next_episode['still_path'] if next_episode['still_path'] is not None else '')
|
||||
|
||||
return list_item, is_local
|
||||
|
||||
|
||||
def tmdb_handle_season(item,tvshow_details,full_info=False):
|
||||
backdrop = IMAGEPATH + tvshow_details['backdrop_path'] if tvshow_details['backdrop_path'] is not None else ''
|
||||
icon = IMAGEPATH + item['poster_path'] if item['poster_path'] is not None else ''
|
||||
if not icon and tvshow_details['poster_path']:
|
||||
icon = IMAGEPATH + tvshow_details['poster_path']
|
||||
|
||||
imdbnumber = tvshow_details['external_ids']['imdb_id'] if tvshow_details.get('external_ids') else ''
|
||||
season_nr = str(item.get('season_number', ''))
|
||||
tvshow_label = tvshow_details['name'] or tvshow_details['original_name']
|
||||
|
||||
episodes_count = 0
|
||||
for episode in item.get('episodes', ''):
|
||||
episodes_count += 1
|
||||
|
||||
list_item = xbmcgui.ListItem(label=tvshow_label)
|
||||
list_item.setInfo('video', {'title': item['name'],
|
||||
'tvshowtitle': tvshow_label,
|
||||
'premiered': item.get('air_date', ''),
|
||||
'episode': episodes_count,
|
||||
'season': season_nr,
|
||||
'plot': item.get('overview', ''),
|
||||
'genre': tmdb_join_items(tvshow_details.get('genres', '')),
|
||||
'rating': tvshow_details.get('vote_average', ''),
|
||||
'votes': tvshow_details.get('vote_count', ''),
|
||||
'mpaa': tmdb_get_cert(tvshow_details),
|
||||
'mediatype': 'season'}
|
||||
)
|
||||
list_item.setArt({'icon': 'DefaultVideo.png', 'thumb': icon, 'poster': icon, 'fanart': backdrop})
|
||||
list_item.setProperty('TotalEpisodes', str(episodes_count))
|
||||
list_item.setProperty('id', str(tvshow_details['id']))
|
||||
list_item.setProperty('call', 'tv')
|
||||
list_item.setProperty('call_season', season_nr)
|
||||
|
||||
if full_info:
|
||||
tmdb_studios(list_item,tvshow_details, 'production')
|
||||
tmdb_studios(list_item,tvshow_details, 'network')
|
||||
omdb_properties(list_item, imdbnumber)
|
||||
|
||||
return list_item
|
||||
|
||||
|
||||
def tmdb_fallback_info(item,key):
|
||||
if FALLBACK_LANGUAGE == DEFAULT_LANGUAGE:
|
||||
try:
|
||||
key_value = item.get(key, '').replace('&', '&').strip()
|
||||
except Exception:
|
||||
key_value = ''
|
||||
|
||||
else:
|
||||
key_value = tmdb_get_translation(item, key, DEFAULT_LANGUAGE)
|
||||
|
||||
# Default language is empty in the translations dict? Fall back to EN
|
||||
if not key_value:
|
||||
key_value = tmdb_get_translation(item, key, FALLBACK_LANGUAGE)
|
||||
|
||||
return key_value
|
||||
|
||||
|
||||
def tmdb_get_translation(item,key,language):
|
||||
key_value_iso_639_1 = ""
|
||||
try:
|
||||
language_iso_639_1 = language[:2]
|
||||
language_iso_3166_1 = language[3:] if len(language)>3 else None
|
||||
|
||||
for translation in item['translations']['translations']:
|
||||
if translation.get('iso_639_1') == language_iso_639_1 and translation['data'][key]:
|
||||
key_value = translation['data'][key]
|
||||
if key_value:
|
||||
key_value = key_value.replace('&', '&').strip()
|
||||
if not language_iso_3166_1 or language_iso_3166_1 == translation.get('iso_3166_1'):
|
||||
return key_value
|
||||
else:
|
||||
key_value_iso_639_1 = key_value
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return key_value_iso_639_1
|
||||
|
||||
|
||||
def tmdb_handle_images(item):
|
||||
icon = IMAGEPATH + item['file_path'] if item['file_path'] is not None else ''
|
||||
list_item = xbmcgui.ListItem(label=str(item['width']) + 'x' + str(item['height']) + 'px')
|
||||
list_item.setArt({'icon': 'DefaultPicture.png', 'thumb': icon})
|
||||
list_item.setProperty('call', 'image')
|
||||
|
||||
return list_item
|
||||
|
||||
|
||||
def tmdb_handle_credits(item):
|
||||
icon = IMAGEPATH + item['profile_path'] if item['profile_path'] is not None else ''
|
||||
list_item = xbmcgui.ListItem(label=item['name'])
|
||||
list_item.setLabel2(item['label2'])
|
||||
list_item.setArt({'icon': 'DefaultActor.png', 'thumb': icon, 'poster': icon})
|
||||
list_item.setProperty('id', str(item.get('id', '')))
|
||||
list_item.setProperty('call', 'person')
|
||||
|
||||
return list_item
|
||||
|
||||
|
||||
def tmdb_handle_yt_videos(item):
|
||||
icon = 'https://img.youtube.com/vi/%s/0.jpg' % str(item['key'])
|
||||
list_item = xbmcgui.ListItem(label=item['name'])
|
||||
list_item.setLabel2(item.get('type', ''))
|
||||
list_item.setArt({'icon': 'DefaultVideo.png', 'thumb': icon, 'landscape': icon})
|
||||
list_item.setProperty('ytid', str(item['key']))
|
||||
list_item.setProperty('call', 'youtube')
|
||||
|
||||
return list_item
|
||||
|
||||
|
||||
def tmdb_join_items_by(item,key_is,value_is,key='name'):
|
||||
values = []
|
||||
for value in item:
|
||||
if value[key_is] == value_is:
|
||||
values.append(value[key])
|
||||
|
||||
return get_joined_items(values)
|
||||
|
||||
|
||||
def tmdb_join_items(item,key='name'):
|
||||
values = []
|
||||
for value in item:
|
||||
values.append(value[key])
|
||||
|
||||
return get_joined_items(values)
|
||||
|
||||
|
||||
def tmdb_get_year(item):
|
||||
try:
|
||||
year = str(item)[:-6]
|
||||
return year
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
|
||||
def tmdb_get_region_release(item):
|
||||
try:
|
||||
for release in item['release_dates']['results']:
|
||||
if release['iso_3166_1'] == COUNTRY_CODE:
|
||||
date = release['release_dates'][0]['release_date']
|
||||
return date[:-14]
|
||||
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
|
||||
def tmdb_get_cert(item):
|
||||
prefix = 'FSK ' if COUNTRY_CODE == 'DE' else ''
|
||||
mpaa = ''
|
||||
mpaa_fallback = ''
|
||||
|
||||
if item.get('content_ratings'):
|
||||
for cert in item['content_ratings']['results']:
|
||||
if cert['iso_3166_1'] == COUNTRY_CODE:
|
||||
mpaa = cert['rating']
|
||||
break
|
||||
elif cert['iso_3166_1'] == 'US':
|
||||
mpaa_fallback = cert['rating']
|
||||
|
||||
elif item.get('release_dates'):
|
||||
for cert in item['release_dates']['results']:
|
||||
if cert['iso_3166_1'] == COUNTRY_CODE:
|
||||
mpaa = cert['release_dates'][0]['certification']
|
||||
break
|
||||
elif cert['iso_3166_1'] == 'US':
|
||||
mpaa_fallback = cert['release_dates'][0]['certification']
|
||||
|
||||
if mpaa:
|
||||
return prefix + mpaa
|
||||
|
||||
return mpaa_fallback
|
||||
|
||||
|
||||
def omdb_properties(list_item,imdbnumber):
|
||||
if OMDB_API_KEY and imdbnumber:
|
||||
omdb = omdb_api(imdbnumber)
|
||||
if omdb:
|
||||
list_item.setProperty('rating.metacritic', omdb.get('metacritic', ''))
|
||||
list_item.setProperty('rating.rotten', omdb.get('tomatometerallcritics', ''))
|
||||
list_item.setProperty('rating.rotten_avg', omdb.get('tomatometerallcritics_avg', ''))
|
||||
list_item.setProperty('votes.rotten', omdb.get('tomatometerallcritics_votes', ''))
|
||||
list_item.setProperty('rating.rotten_user', omdb.get('tomatometerallaudience', ''))
|
||||
list_item.setProperty('rating.rotten_user_avg', omdb.get('tomatometerallaudience_avg', ''))
|
||||
list_item.setProperty('votes.rotten_user', omdb.get('tomatometerallaudience_votes', ''))
|
||||
list_item.setProperty('rating.imdb', omdb.get('imdbRating', ''))
|
||||
list_item.setProperty('votes.imdb', omdb.get('imdbVotes', ''))
|
||||
list_item.setProperty('awards', omdb.get('awards', ''))
|
||||
list_item.setProperty('release', omdb.get('DVD', ''))
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import xbmc
|
||||
import requests
|
||||
|
||||
from resources.lib.helper import *
|
||||
|
||||
########################
|
||||
|
||||
TRAKT_API_KEY = ADDON.getSettingString('trakt_api_key')
|
||||
|
||||
########################
|
||||
|
||||
def trakt_api(call=None):
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'trakt-api-version': '2',
|
||||
'trakt-api-key': TRAKT_API_KEY
|
||||
}
|
||||
|
||||
request_url = 'https://api.trakt.tv' + call
|
||||
|
||||
for i in range(1,4): # loop if heavy server load
|
||||
try:
|
||||
request = requests.get(request_url, timeout=5, headers=headers)
|
||||
|
||||
if not request.ok:
|
||||
raise Exception(str(request.status_code))
|
||||
|
||||
except Exception as error:
|
||||
log('Trakt server error: Code ' + str(error), ERROR)
|
||||
xbmc.sleep(500)
|
||||
|
||||
else:
|
||||
return request.json()
|
||||
297
Kodi/Lenovo/addons/script.embuary.info/resources/lib/video.py
Normal file
297
Kodi/Lenovo/addons/script.embuary.info/resources/lib/video.py
Normal file
@@ -0,0 +1,297 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import sys
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import requests
|
||||
|
||||
from resources.lib.helper import *
|
||||
from resources.lib.tmdb import *
|
||||
|
||||
########################
|
||||
|
||||
SIMILAR_FILTER = ADDON.getSettingBool('similar_movies_filter')
|
||||
FILTER_UPCOMING = ADDON.getSettingBool('filter_upcoming')
|
||||
FILTER_DAYDELTA = int(ADDON.getSetting('filter_daydelta'))
|
||||
|
||||
########################
|
||||
|
||||
class TMDBVideos(object):
|
||||
def __init__(self,call_request):
|
||||
self.result = {}
|
||||
self.call = call_request['call']
|
||||
self.tmdb_id = call_request['tmdb_id']
|
||||
self.local_movies = call_request['local_movies']
|
||||
self.local_shows = call_request['local_shows']
|
||||
self.movie = get_bool(self.call, 'movie')
|
||||
self.tvshow = get_bool(self.call, 'tv')
|
||||
|
||||
if self.tmdb_id:
|
||||
cache_key = self.call + str(self.tmdb_id)
|
||||
self.details = get_cache(cache_key)
|
||||
|
||||
if not self.details:
|
||||
self.details = tmdb_query(action=self.call,
|
||||
call=self.tmdb_id,
|
||||
params={'append_to_response': 'release_dates,content_ratings,external_ids,credits,videos,translations,similar'},
|
||||
show_error=True
|
||||
)
|
||||
|
||||
write_cache(cache_key, self.details)
|
||||
|
||||
if not self.details:
|
||||
return
|
||||
|
||||
self.created_by = self.details['created_by'] if self.details.get('created_by') else ''
|
||||
self.crew = self.details['credits']['crew']
|
||||
self.details['crew'] = self.crew
|
||||
self.similar_duplicate_handler = list()
|
||||
|
||||
self.result['details'] = self.get_details()
|
||||
self.result['cast'] = self.get_cast()
|
||||
self.result['crew'] = self.get_crew()
|
||||
self.result['collection'] = self.get_collection()
|
||||
self.result['similar'] = self.get_similar()
|
||||
self.result['youtube'] = self.get_yt_videos()
|
||||
self.result['backdrops'], self.result['posters'] = self.get_images()
|
||||
self.result['seasons'] = self.get_seasons()
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.result.get(key, '')
|
||||
|
||||
def get_details(self):
|
||||
li = list()
|
||||
|
||||
if self.movie:
|
||||
list_item, is_local = tmdb_handle_movie(self.details, self.local_movies,full_info=True)
|
||||
elif self.tvshow:
|
||||
list_item, is_local = tmdb_handle_tvshow(self.details, self.local_shows,full_info=True)
|
||||
|
||||
li.append(list_item)
|
||||
return li
|
||||
|
||||
def get_cast(self):
|
||||
li = list()
|
||||
|
||||
for item in self.details['credits']['cast']:
|
||||
item['label2'] = item.get('character', '')
|
||||
list_item = tmdb_handle_credits(item)
|
||||
li.append(list_item)
|
||||
|
||||
return li
|
||||
|
||||
def get_crew(self):
|
||||
li_clean_crew = list()
|
||||
li_crew_duplicate_handler_id = list()
|
||||
li = list()
|
||||
|
||||
''' Add creators to crew
|
||||
'''
|
||||
for item in self.created_by:
|
||||
item['job'] = 'Creator'
|
||||
item['department'] = 'Directing'
|
||||
li_clean_crew.append(item)
|
||||
li_crew_duplicate_handler_id.append(item['id'])
|
||||
|
||||
''' Filter crew and merge duplicate crew members if they were responsible for different jobs
|
||||
'''
|
||||
for item in self.crew:
|
||||
if item['job'] in ['Creator', 'Director', 'Producer', 'Screenplay', 'Writer', 'Original Music Composer', 'Novel', 'Storyboard', 'Executive Producer', 'Comic Book']:
|
||||
if item['id'] not in li_crew_duplicate_handler_id:
|
||||
li_clean_crew.append(item)
|
||||
li_crew_duplicate_handler_id.append(item['id'])
|
||||
else:
|
||||
for duplicate in li_clean_crew:
|
||||
if duplicate['id'] == item['id']:
|
||||
duplicate['job'] = duplicate['job'] + ' / ' + item['job']
|
||||
|
||||
''' Sort crew output based on department
|
||||
'''
|
||||
for item in li_clean_crew:
|
||||
if item['department'] == 'Directing':
|
||||
item['label2'] = item.get('job', '')
|
||||
list_item = tmdb_handle_credits(item)
|
||||
li.append(list_item)
|
||||
|
||||
for item in li_clean_crew:
|
||||
if item['department'] == 'Writing':
|
||||
item['label2'] = item.get('job', '')
|
||||
list_item = tmdb_handle_credits(item)
|
||||
li.append(list_item)
|
||||
|
||||
for item in li_clean_crew:
|
||||
if item['department'] == 'Production':
|
||||
item['label2'] = item.get('job', '')
|
||||
list_item = tmdb_handle_credits(item)
|
||||
li.append(list_item)
|
||||
|
||||
for item in li_clean_crew:
|
||||
if item['department'] == 'Sound':
|
||||
item['job'] = 'Music Composer' if item['job'] == 'Original Music Composer' else item['job']
|
||||
item['label2'] = item.get('job', '')
|
||||
list_item = tmdb_handle_credits(item)
|
||||
li.append(list_item)
|
||||
|
||||
return li
|
||||
|
||||
def get_seasons(self):
|
||||
seasons = self.details.get('seasons')
|
||||
li = list()
|
||||
|
||||
if seasons:
|
||||
for item in seasons:
|
||||
if item['season_number'] == 0:
|
||||
continue
|
||||
list_item = tmdb_handle_season(item, self.details)
|
||||
li.append(list_item)
|
||||
|
||||
return li
|
||||
|
||||
def get_collection(self):
|
||||
collection = self.details.get('belongs_to_collection')
|
||||
li = list()
|
||||
|
||||
if collection:
|
||||
collection_id = collection['id']
|
||||
|
||||
cache_key = 'collection' + str(collection_id)
|
||||
collection_data = get_cache(cache_key)
|
||||
|
||||
if not collection_data:
|
||||
collection_data = tmdb_query(action='collection',
|
||||
call=collection_id
|
||||
)
|
||||
|
||||
write_cache(cache_key, collection_data)
|
||||
|
||||
if collection_data['parts']:
|
||||
set_items = sort_dict(collection_data['parts'], 'release_date')
|
||||
|
||||
for item in set_items:
|
||||
''' Filter to hide in production or rumored future movies
|
||||
'''
|
||||
if FILTER_UPCOMING:
|
||||
diff = date_delta(item.get('release_date', '2900-01-01'))
|
||||
if diff.days > FILTER_DAYDELTA:
|
||||
continue
|
||||
|
||||
list_item, is_local = tmdb_handle_movie(item, self.local_movies)
|
||||
li.append(list_item)
|
||||
|
||||
if SIMILAR_FILTER:
|
||||
self.similar_duplicate_handler.append(item['id'])
|
||||
|
||||
''' Don't show sets with only 1 item
|
||||
'''
|
||||
if len(li) == 1:
|
||||
self.similar_duplicate_handler = list()
|
||||
li = list()
|
||||
|
||||
return li
|
||||
|
||||
def get_similar(self):
|
||||
similar = self.details['similar']['results']
|
||||
li = list()
|
||||
|
||||
if self.movie:
|
||||
similar = sort_dict(similar, 'release_date',True)
|
||||
|
||||
for item in similar:
|
||||
''' Filter to hide item if it's part of the collection
|
||||
'''
|
||||
if SIMILAR_FILTER and item['id'] in self.similar_duplicate_handler:
|
||||
continue
|
||||
|
||||
''' Filter to hide in production or rumored future movies
|
||||
'''
|
||||
if FILTER_UPCOMING:
|
||||
diff = date_delta(item.get('release_date', '2900-01-01'))
|
||||
if diff.days > FILTER_DAYDELTA:
|
||||
continue
|
||||
|
||||
list_item, is_local = tmdb_handle_movie(item, self.local_movies)
|
||||
li.append(list_item)
|
||||
|
||||
elif self.tvshow:
|
||||
similar = sort_dict(similar, 'first_air_date', True)
|
||||
|
||||
for item in similar:
|
||||
''' Filter to hide in production or rumored future shows
|
||||
'''
|
||||
if FILTER_UPCOMING:
|
||||
diff = date_delta(item.get('first_air_date', '2900-01-01'))
|
||||
if diff.days > FILTER_DAYDELTA:
|
||||
continue
|
||||
|
||||
list_item, is_local = tmdb_handle_tvshow(item, self.local_shows)
|
||||
li.append(list_item)
|
||||
|
||||
return li
|
||||
|
||||
def get_images(self):
|
||||
cache_key = 'images' + str(self.tmdb_id)
|
||||
images = get_cache(cache_key)
|
||||
li_backdrops = list()
|
||||
li_poster = list()
|
||||
|
||||
if not images:
|
||||
images = tmdb_query(action=self.call,
|
||||
call=self.tmdb_id,
|
||||
get='images',
|
||||
params={'include_image_language': '%s,en,null' % DEFAULT_LANGUAGE}
|
||||
)
|
||||
|
||||
write_cache(cache_key, images)
|
||||
|
||||
for item in images['backdrops']:
|
||||
list_item = tmdb_handle_images(item)
|
||||
li_backdrops.append(list_item)
|
||||
|
||||
for item in images['posters']:
|
||||
list_item = tmdb_handle_images(item)
|
||||
li_poster.append(list_item)
|
||||
|
||||
return li_backdrops, li_poster
|
||||
|
||||
def get_yt_videos(self):
|
||||
cache_key = 'ytvideos' + str(self.tmdb_id)
|
||||
videos = get_cache(cache_key)
|
||||
li = list()
|
||||
|
||||
if not videos:
|
||||
videos = self.details['videos']['results']
|
||||
|
||||
''' Add EN videos next to the user configured language
|
||||
'''
|
||||
if DEFAULT_LANGUAGE != FALLBACK_LANGUAGE:
|
||||
videos_en = tmdb_query(action=self.call,
|
||||
call=self.tmdb_id,
|
||||
get='videos',
|
||||
use_language=False
|
||||
)
|
||||
|
||||
videos_en = videos_en.get('results')
|
||||
videos = videos + videos_en
|
||||
|
||||
''' Check online status of all videos to prevent dead links
|
||||
'''
|
||||
online_videos = []
|
||||
for item in videos:
|
||||
request = requests.head('https://img.youtube.com/vi/%s/0.jpg' % str(item['key']))
|
||||
if request.status_code == requests.codes.ok:
|
||||
online_videos.append(item)
|
||||
|
||||
videos = online_videos
|
||||
write_cache(cache_key, videos)
|
||||
|
||||
for item in videos:
|
||||
if item['site'] == 'YouTube':
|
||||
list_item = tmdb_handle_yt_videos(item)
|
||||
if not list_item == 404:
|
||||
li.append(list_item)
|
||||
|
||||
return li
|
||||
487
Kodi/Lenovo/addons/script.embuary.info/resources/lib/widgets.py
Normal file
487
Kodi/Lenovo/addons/script.embuary.info/resources/lib/widgets.py
Normal file
@@ -0,0 +1,487 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
########################
|
||||
|
||||
import routing
|
||||
from xbmcgui import ListItem
|
||||
from xbmcplugin import *
|
||||
from datetime import date
|
||||
|
||||
from resources.lib.helper import *
|
||||
from resources.lib.tmdb import *
|
||||
from resources.lib.trakt import *
|
||||
from resources.lib.localdb import *
|
||||
from resources.lib.nextaired import *
|
||||
|
||||
########################
|
||||
|
||||
INDEX_MENU = {
|
||||
'discover': {
|
||||
'name': 'The Movie DB - ' + ADDON.getLocalizedString(32049),
|
||||
'route': 'discover',
|
||||
'folder': True,
|
||||
'menu': [
|
||||
{ 'name': ADDON.getLocalizedString(32050), 'call': 'movie'},
|
||||
{ 'name': ADDON.getLocalizedString(32051), 'call': 'tv' },
|
||||
{ 'name': ADDON.getLocalizedString(32057), 'call': 'person' }
|
||||
]
|
||||
},
|
||||
'movie': {
|
||||
'name': 'The Movie DB - ' + xbmc.getLocalizedString(342),
|
||||
'route': 'movie_listing',
|
||||
'folder': True,
|
||||
'menu': [
|
||||
{ 'name': ADDON.getLocalizedString(32042), 'call': 'trending' },
|
||||
{ 'name': ADDON.getLocalizedString(32029), 'call': 'top_rated' },
|
||||
{ 'name': ADDON.getLocalizedString(32030), 'call': 'now_playing' },
|
||||
{ 'name': ADDON.getLocalizedString(32031), 'call': 'upcoming' },
|
||||
{ 'name': ADDON.getLocalizedString(32032), 'call': 'popular' },
|
||||
]
|
||||
},
|
||||
'tv': {
|
||||
'name': 'The Movie DB - ' + xbmc.getLocalizedString(20343),
|
||||
'route': 'tv_listing',
|
||||
'folder': True,
|
||||
'menu': [
|
||||
{ 'name': ADDON.getLocalizedString(32043), 'call': 'trending' },
|
||||
{ 'name': ADDON.getLocalizedString(32033), 'call': 'top_rated' },
|
||||
{ 'name': ADDON.getLocalizedString(32034), 'call': 'popular' },
|
||||
{ 'name': ADDON.getLocalizedString(32035), 'call': 'airing_today' },
|
||||
{ 'name': ADDON.getLocalizedString(32036), 'call': 'on_the_air' }
|
||||
]
|
||||
},
|
||||
'nextaired': {
|
||||
'name': 'Trakt.tv - ' + ADDON.getLocalizedString(32059),
|
||||
'route': 'nextaired',
|
||||
'folder': True,
|
||||
'menu': [
|
||||
{ 'name': ADDON.getLocalizedString(32058), 'day': 'week' },
|
||||
{ 'name': xbmc.getLocalizedString(33006), 'day': 'today' },
|
||||
],
|
||||
'days': [
|
||||
xbmc.getLocalizedString(11),
|
||||
xbmc.getLocalizedString(12),
|
||||
xbmc.getLocalizedString(13),
|
||||
xbmc.getLocalizedString(14),
|
||||
xbmc.getLocalizedString(15),
|
||||
xbmc.getLocalizedString(16),
|
||||
xbmc.getLocalizedString(17)
|
||||
]
|
||||
},
|
||||
'search': {
|
||||
'name': xbmc.getLocalizedString(137),
|
||||
'route': 'search',
|
||||
'folder': False
|
||||
}
|
||||
}
|
||||
|
||||
DISCOVER_INDEX = {
|
||||
'movie': [
|
||||
{ 'name': ADDON.getLocalizedString(32050), 'option': 'all' },
|
||||
{ 'name': ADDON.getLocalizedString(32052), 'option': 'year', 'param': 'year' },
|
||||
{ 'name': ADDON.getLocalizedString(32053), 'option': 'genre', 'param': 'with_genres' },
|
||||
],
|
||||
'tv': [
|
||||
{ 'name': ADDON.getLocalizedString(32051), 'option': 'all' },
|
||||
{ 'name': ADDON.getLocalizedString(32054), 'option': 'year', 'parmam': 'first_air_date_year' },
|
||||
{ 'name': ADDON.getLocalizedString(32055), 'option': 'genre', 'param': 'with_genres' }
|
||||
]
|
||||
}
|
||||
|
||||
DEFAULT_ART = {
|
||||
'icon': 'DefaultFolder.png',
|
||||
'thumb': 'special://home/addons/script.embuary.info/resources/icon.png'
|
||||
}
|
||||
|
||||
########################
|
||||
|
||||
plugin = routing.Plugin()
|
||||
|
||||
# entrypoint
|
||||
@plugin.route('/')
|
||||
def index():
|
||||
for i in ['discover', 'movie', 'tv', 'nextaired', 'search']:
|
||||
item = INDEX_MENU[i]
|
||||
li_item = ListItem(item['name'])
|
||||
li_item.setArt(DEFAULT_ART)
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(eval(item['route'])),
|
||||
li_item, item['folder'])
|
||||
|
||||
_sortmethods()
|
||||
xbmcplugin.endOfDirectory(plugin.handle)
|
||||
|
||||
|
||||
# actions
|
||||
@plugin.route('/info/<call>/<idtype>/<tmdbid>')
|
||||
def dialog(call,idtype,tmdbid):
|
||||
if idtype == 'tmdb':
|
||||
execute('RunScript(script.embuary.info,call=%s,tmdb_id=%s)' % (call, tmdbid))
|
||||
elif idtype == 'external':
|
||||
execute('RunScript(script.embuary.info,call=%s,external_id=%s)' % (call, tmdbid))
|
||||
|
||||
|
||||
@plugin.route('/search')
|
||||
def search():
|
||||
execute('RunScript(script.embuary.info)')
|
||||
|
||||
|
||||
# next aired
|
||||
@plugin.route('/nextaired')
|
||||
@plugin.route('/nextaired/<day>')
|
||||
def nextaired(day=None):
|
||||
if not day:
|
||||
for i in INDEX_MENU['nextaired'].get('menu'):
|
||||
li_item = ListItem(i.get('name'))
|
||||
li_item.setArt(DEFAULT_ART)
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(nextaired, i.get('day')),
|
||||
li_item, True)
|
||||
|
||||
utc = arrow.utcnow()
|
||||
local_date = utc.to(TIMEZONE)
|
||||
|
||||
kodi_locale = json_call('Settings.GetSettingValue', params={'setting': 'locale.language'})
|
||||
kodi_locale = kodi_locale['result']['value'][-5:]
|
||||
|
||||
for i in range(6):
|
||||
local_date = local_date.shift(days=1)
|
||||
translated_date = local_date.format(fmt='dddd, D. MMMM YYYY', locale=kodi_locale)
|
||||
tmp_day_str, tmp_day = date_weekday(local_date)
|
||||
|
||||
li_item = ListItem(translated_date)
|
||||
li_item.setArt(DEFAULT_ART)
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(nextaired, tmp_day),
|
||||
li_item, True)
|
||||
|
||||
_category(category=INDEX_MENU['nextaired']['name'])
|
||||
|
||||
else:
|
||||
_nextaired(day)
|
||||
|
||||
_sortmethods()
|
||||
xbmcplugin.endOfDirectory(plugin.handle)
|
||||
|
||||
def _nextaired(day):
|
||||
if day == 'today':
|
||||
day_str, day = date_weekday()
|
||||
|
||||
next_aired = NextAired()
|
||||
next_aired_results = next_aired.get(str(day))
|
||||
|
||||
if day == 'week':
|
||||
next_aired_results = sort_dict(next_aired_results, 'airing')
|
||||
|
||||
#log(next_aired_results,force=True,json=True)
|
||||
|
||||
for i in next_aired_results:
|
||||
try:
|
||||
|
||||
if day != 'week' and day is not None:
|
||||
label = '%s %sx%s. %s' % (i['showtitle'], i['season_number'], i['episode_number'], i['name'])
|
||||
else:
|
||||
kodi_date = date_format(i['airing'])
|
||||
label = '%s, %s: %s %sx%s. %s' % (i['weekday'], kodi_date, i['showtitle'], i['season_number'], i['episode_number'], i['name'])
|
||||
|
||||
season = str(i.get('season_number', ''))
|
||||
episode = str(i.get('episode_number', ''))
|
||||
airing_date = i.get('airing', '')
|
||||
airing_time = i.get('airing_time', '')
|
||||
plot = i.get('overview') or xbmc.getLocalizedString(19055)
|
||||
|
||||
overview = [date_format(airing_date) + ' ' + airing_time, plot]
|
||||
overview ='[CR]'.join(filter(None, overview))
|
||||
|
||||
thumb = IMAGEPATH + i.get('still_path') if i.get('still_path') else ''
|
||||
if not thumb:
|
||||
thumb = i['localart'].get('landscape') or i['localart'].get('fanart') or ''
|
||||
|
||||
li_item = ListItem(label)
|
||||
li_item.setArt(i.get('localart'))
|
||||
li_item.setArt({'icon': 'DefaultVideo.png', 'thumb': thumb})
|
||||
li_item.setInfo('video', {'title': i.get('name') or xbmc.getLocalizedString(13205),
|
||||
'tvshowtitle': i.get('showtitle') or xbmc.getLocalizedString(13205),
|
||||
'plot': overview,
|
||||
'premiered': airing_date,
|
||||
'season': season,
|
||||
'episode': episode,
|
||||
'status': i.get('status', ''),
|
||||
'country': i.get('country', ''),
|
||||
'studio': i.get('network', ''),
|
||||
'duration': i.get('runtime', 0),
|
||||
'mediatype': 'episode'}
|
||||
)
|
||||
li_item.setProperty('AirDay', i['weekday'])
|
||||
li_item.setProperty('AirTime', airing_time)
|
||||
li_item.setProperty('IsPlayable', 'false')
|
||||
|
||||
xbmcplugin.addDirectoryItem(plugin.handle, plugin.url_for(dialog, 'tv', 'tmdb', i['show_id']), li_item)
|
||||
|
||||
except Exception as error:
|
||||
pass
|
||||
|
||||
if day == 'week':
|
||||
category = INDEX_MENU['nextaired']['menu'][0]['name']
|
||||
else:
|
||||
category = INDEX_MENU['nextaired']['days'][int(day)]
|
||||
|
||||
_category(content='videos', category=category)
|
||||
|
||||
|
||||
# discover
|
||||
@plugin.route('/discover')
|
||||
@plugin.route('/discover/<directory>')
|
||||
@plugin.route('/discover/<directory>/<option>')
|
||||
@plugin.route('/discover/<directory>/<option>/<filterby>')
|
||||
@plugin.route('/discover/<directory>/<option>/<filterby>/<page>')
|
||||
def discover(directory=None,option=None,filterby=None,page=1,pages=1):
|
||||
if not directory:
|
||||
for i in INDEX_MENU['discover'].get('menu'):
|
||||
li_item = ListItem(i.get('name'))
|
||||
li_item.setArt(DEFAULT_ART)
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(discover, i.get('call')),
|
||||
li_item, True)
|
||||
|
||||
_category(category=INDEX_MENU['discover']['name'])
|
||||
|
||||
else:
|
||||
category = _dict_match('name', INDEX_MENU['discover']['menu'], 'call', directory)
|
||||
|
||||
if _previouspage(page):
|
||||
li_item = ListItem(ADDON.getLocalizedString(32056))
|
||||
li_item.setArt(DEFAULT_ART)
|
||||
li_item.setProperty('SpecialSort', 'top')
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(discover, directory, option, filterby, int(page)-1),
|
||||
li_item, True)
|
||||
|
||||
if directory == 'person':
|
||||
result, pages = _query('person', 'popular', params={'page': page})
|
||||
|
||||
if result:
|
||||
_add(result, 'person')
|
||||
|
||||
_category(directory, category)
|
||||
|
||||
elif not option:
|
||||
for i in DISCOVER_INDEX[directory]:
|
||||
li_item = ListItem(i.get('name'))
|
||||
li_item.setArt(DEFAULT_ART)
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(discover, directory, i.get('option')),
|
||||
li_item, True)
|
||||
|
||||
_category(category=category)
|
||||
|
||||
elif option == 'all':
|
||||
result, pages = _query('discover', directory, params={'page': page})
|
||||
|
||||
if result:
|
||||
_add(result, directory)
|
||||
|
||||
_category(directory, category)
|
||||
|
||||
elif option in ['genre', 'year'] and not filterby:
|
||||
option_results, filter_value, icon = _discover_option(directory, option)
|
||||
|
||||
for i in option_results:
|
||||
li_item = ListItem(i.get('name'))
|
||||
li_item.setArt({'icon': icon})
|
||||
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(discover, directory, option, i.get(filter_value)),
|
||||
li_item, True)
|
||||
|
||||
_category(directory, category)
|
||||
|
||||
else:
|
||||
filter_param = _dict_match('param', DISCOVER_INDEX[directory], 'option', option)
|
||||
result, pages = _query('discover', directory, params={filter_param: filterby, 'page': page})
|
||||
|
||||
if result:
|
||||
_add(result, directory)
|
||||
|
||||
_category(directory, category + ' (' + filterby + ')')
|
||||
|
||||
if _nextpage(page, pages):
|
||||
li_item = ListItem(xbmc.getLocalizedString(33078))
|
||||
li_item.setArt(DEFAULT_ART)
|
||||
li_item.setProperty('SpecialSort', 'bottom')
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(discover, directory, option, filterby, int(page)+1),
|
||||
li_item, True)
|
||||
|
||||
_sortmethods()
|
||||
xbmcplugin.endOfDirectory(plugin.handle)
|
||||
|
||||
|
||||
def _discover_option(call,option):
|
||||
if option == 'genre':
|
||||
tmdb = tmdb_query(action='genre',
|
||||
call=call,
|
||||
get='list'
|
||||
)
|
||||
|
||||
return tmdb['genres'], 'id', 'DefaultGenre.png'
|
||||
|
||||
elif option == 'year':
|
||||
cur_year = date.today().year
|
||||
index = cur_year
|
||||
years = []
|
||||
|
||||
for i in range(cur_year - 1900 + 1):
|
||||
years.append({'name': str(index)})
|
||||
index -= 1
|
||||
|
||||
return years, 'name', 'DefaultYear.png'
|
||||
|
||||
elif option == 'keyword':
|
||||
keyboard = xbmc.Keyboard()
|
||||
keyboard.doModal()
|
||||
|
||||
if keyboard.isConfirmed():
|
||||
return keyboard.getText(),
|
||||
|
||||
|
||||
# common
|
||||
@plugin.route('/movie')
|
||||
@plugin.route('/movie/<call>')
|
||||
@plugin.route('/movie/<call>/<page>')
|
||||
def movie_listing(call=None,page=1,pages=1):
|
||||
_listing('movie', call, page, pages)
|
||||
|
||||
@plugin.route('/tv')
|
||||
@plugin.route('/tv/<call>')
|
||||
@plugin.route('/tv/<call>/<page>')
|
||||
def tv_listing(call=None,page=1,pages=1):
|
||||
_listing('tv', call, page, pages)
|
||||
|
||||
def _listing(directory, call, page, pages):
|
||||
route = '%s_listing' % directory
|
||||
category = _dict_match('name', INDEX_MENU[directory]['menu'], 'call', call)
|
||||
|
||||
if _previouspage(page):
|
||||
li_item = ListItem(ADDON.getLocalizedString(32056))
|
||||
li_item.setArt(DEFAULT_ART)
|
||||
li_item.setProperty('SpecialSort', 'top')
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(eval(route), call, int(page)-1),
|
||||
li_item, True)
|
||||
|
||||
if not call:
|
||||
result = None
|
||||
for i in INDEX_MENU[directory].get('menu'):
|
||||
li_item = ListItem(i.get('name'))
|
||||
li_item.setArt(DEFAULT_ART)
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(eval(route), i.get('call')),
|
||||
li_item, True)
|
||||
|
||||
_category(category=INDEX_MENU[directory]['name'])
|
||||
|
||||
elif call == 'trending':
|
||||
result, pages = _query('trending', directory, 'week', params={'page': page})
|
||||
|
||||
else:
|
||||
result, pages = _query(directory, call, params={'page': page})
|
||||
|
||||
if result:
|
||||
_add(result, directory)
|
||||
_category(directory, category)
|
||||
|
||||
if _nextpage(page, pages):
|
||||
li_item = ListItem(xbmc.getLocalizedString(33078))
|
||||
li_item.setArt(DEFAULT_ART)
|
||||
li_item.setProperty('SpecialSort', 'bottom')
|
||||
xbmcplugin.addDirectoryItem(plugin.handle,
|
||||
plugin.url_for(eval(route), call, int(page)+1),
|
||||
li_item, True)
|
||||
|
||||
_sortmethods()
|
||||
xbmcplugin.endOfDirectory(plugin.handle)
|
||||
|
||||
#helpers
|
||||
def _dict_match(get,source,key,value):
|
||||
result = [i.get(get) for i in source if i.get(key) == value]
|
||||
if result:
|
||||
return result[0]
|
||||
|
||||
|
||||
def _add(items,call):
|
||||
local_items = get_local_media()
|
||||
|
||||
if call == 'tv':
|
||||
for item in items:
|
||||
list_item, is_local = tmdb_handle_tvshow(item, local_items=local_items.get('shows', []))
|
||||
xbmcplugin.addDirectoryItem(plugin.handle, plugin.url_for(dialog, 'tv', 'tmdb', item['id']), list_item)
|
||||
|
||||
elif call == 'movie':
|
||||
for item in items:
|
||||
list_item, is_local = tmdb_handle_movie(item, local_items=local_items.get('movies', []))
|
||||
xbmcplugin.addDirectoryItem(plugin.handle, plugin.url_for(dialog, 'movie', 'tmdb', item['id']), list_item)
|
||||
|
||||
elif call == 'person':
|
||||
for item in items:
|
||||
list_item = tmdb_handle_person(item)
|
||||
xbmcplugin.addDirectoryItem(plugin.handle, plugin.url_for(dialog, 'person', 'tmdb', item['id']), list_item)
|
||||
|
||||
def _category(content='',category='',call=None,info=None):
|
||||
if content == 'tv':
|
||||
plugincontent = 'tvshows'
|
||||
elif content == 'movie':
|
||||
plugincontent = 'movies'
|
||||
elif content == 'person':
|
||||
plugincontent = 'actors'
|
||||
elif content:
|
||||
plugincontent = content
|
||||
else:
|
||||
plugincontent = ''
|
||||
|
||||
set_plugincontent(content=plugincontent, category=category)
|
||||
|
||||
|
||||
def _query(content_type,call,get=None,params=None,get_details=False):
|
||||
args = {'region': COUNTRY_CODE}
|
||||
if params:
|
||||
args.update(params)
|
||||
|
||||
cache_key = 'widget' + content_type + str(call) + str(get) + str(args)
|
||||
tmdb = get_cache(cache_key)
|
||||
|
||||
if not tmdb:
|
||||
tmdb = tmdb_query(action=content_type,
|
||||
call=call,
|
||||
get=get,
|
||||
params=args
|
||||
)
|
||||
|
||||
if tmdb:
|
||||
write_cache(cache_key,tmdb,3)
|
||||
|
||||
if not get_details:
|
||||
try:
|
||||
return tmdb.get('results'), tmdb.get('total_pages')
|
||||
except Exception:
|
||||
return [], 1
|
||||
|
||||
else:
|
||||
return tmdb
|
||||
|
||||
|
||||
def _nextpage(page,pages):
|
||||
if int(page) < int(pages) and condition('Window.IsVisible(MyVideoNav.xml)'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _previouspage(page):
|
||||
if int(page) > 1 and condition('Window.IsVisible(MyVideoNav.xml) + !Container.HasParent'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _sortmethods():
|
||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_TITLE)
|
||||
Reference in New Issue
Block a user