Updated kodi settings on Lenovo

This commit is contained in:
2026-03-22 22:28:43 +01:00
parent 725dfa7157
commit 32b5a81da6
10925 changed files with 575678 additions and 5511 deletions

View 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()

View File

@@ -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

View 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)

View File

@@ -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

View 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

View 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

View 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

View 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('&amp;', '&').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('&amp;', '&').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', ''))

View File

@@ -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()

View 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

View 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)