Files
addon/platformcode/infoplus.py
marco 8a8d1e4f5e KoD 1.4
- completato il supporto al futuro Kodi 19\n- ridisegnato infoplus\n- fix vari ed eventuali\n
2020-09-29 21:08:25 +02:00

549 lines
24 KiB
Python

# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# infoplus window with item information
# ------------------------------------------------------------
import xbmc, xbmcgui, sys, requests, re
from core import support, tmdb, filetools, channeltools, servertools
from core.item import Item
from platformcode import config, platformtools
from platformcode.logger import log
from core.scrapertools import decodeHtmlentities, htmlclean
PY3 = False
if sys.version_info[0] >= 3: PY3 = True
if PY3: from concurrent import futures
else: from concurrent_py2 import futures
info_list = []
SearchWindows = []
api = 'k_0tdb8a8y'
# Control ID
FANART = 30000
NUMBER = 30001
TITLE = 30002
TAGLINE = 30003
PLOT = 30004
RATING_ICON = 30005
RATING = 30006
TRAILER = 30007
SEARCH = 30008
NEXT = 30009
PREVIOUS = 30010
LOADING = 30011
COMMANDS = 30012
RECOMANDED = TRAILERS = 30500
ACTORS = 30501
CAST = 30502
# Actions
LEFT = 1
RIGHT = 2
UP = 3
DOWN = 4
EXIT = 10
BACKSPACE = 92
def Main(item):
if type(item) == Item:
item.channel = item.from_channel
global ITEM
ITEM = item
Info = xbmcgui.ListItem(item.infoLabels['title'])
for key, value in item.infoLabels.items():
Info.setProperty(key, str(value))
else:
Info = item
main = MainWindow('InfoPlus.xml', config.get_runtime_path())
add({'class':main, 'info':Info, 'id':RECOMANDED, RECOMANDED:0, ACTORS:0})
modal()
class MainWindow(xbmcgui.WindowXMLDialog):
def __init__(self, *args, **kwargs):
self.items = []
self.cast = []
self.actors = []
self.ids = {}
def onInit(self):
#### Compatibility with Kodi 18 ####
if config.get_platform(True)['num_version'] < 18:
self.setCoordinateResolution(2)
if Info.getProperty('id'):self.items = get_movies(Info)
else: self.items = get_recomendations(Info)
self.cast, self.actors = get_cast(Info)
self.getControl(LOADING).setVisible(False)
self.getControl(RECOMANDED).addItems(self.items)
self.getControl(FANART).setImage(Info.getProperty('fanart'))
self.getControl(ACTORS).addItems(self.actors)
if self.cast:
self.getControl(CAST).setVisible(True)
self.getControl(CAST).addItems(self.cast)
else:
self.getControl(CAST).setVisible(False)
if Info.getProperty('rating'): rating = str(Info.getProperty('rating'))
else: rating = 'N/A'
self.getControl(RATING).setText(rating)
getFocus(self)
def onClick(self, control_id):
setFocus(self)
if control_id in [SEARCH]:
title = self.getControl(RECOMANDED).getSelectedItem().getProperty('title')
mode = self.getControl(RECOMANDED).getSelectedItem().getProperty('mediatype')
self.close()
if self.getControl(RECOMANDED).getSelectedPosition() > 0:
Search(ITEM.clone(action='search', search_text=title))
else:
Search(ITEM.clone(channel='search', action='new_search', search_text=title, mode=mode))
elif control_id in [TRAILER]:
info = self.getControl(RECOMANDED).getSelectedItem()
self.close()
Trailer(info)
elif control_id in [ACTORS, CAST]:
self.close()
Main(self.getControl(self.getFocusId()).getSelectedItem())
elif control_id in [RECOMANDED] and self.getControl(RECOMANDED).getSelectedPosition() > 0:
self.close()
Main(self.getControl(RECOMANDED).getSelectedItem())
def onAction(self, action):
if self.getFocusId() in [ACTORS, RECOMANDED]:
self.ids[self.getFocusId()] = self.getControl(self.getFocusId()).getSelectedPosition()
if self.getFocusId() in [ACTORS, CAST] and action not in [BACKSPACE, EXIT]:
actors_more_info(self.getControl(self.getFocusId()).getSelectedItem())
if self.getFocusId() in [RECOMANDED]:
fanart = self.getControl(self.getFocusId()).getSelectedItem().getProperty('fanart')
rating = self.getControl(self.getFocusId()).getSelectedItem().getProperty('rating')
if not rating: rating = 'N/A'
self.getControl(FANART).setImage(fanart)
self.getControl(RATING).setText(rating)
cast, actors = get_cast(self.getControl(self.getFocusId()).getSelectedItem())
self.getControl(ACTORS).reset()
self.getControl(ACTORS).addItems(actors)
self.getControl(CAST).reset()
self.getControl(CAST).addItems(cast)
action = action.getId()
if action in [BACKSPACE]:
self.close()
remove()
modal()
elif action in [EXIT]:
self.close()
def Search(item):
if item.action == 'findvideos': XML = 'ServersWindow.xml'
else: XML = 'SearchWindow.xml'
global Info
Info = item
main = SearchWindow(XML, config.get_runtime_path())
add({'class':main, 'info':item, 'id':RECOMANDED})
modal()
class SearchWindow(xbmcgui.WindowXMLDialog):
def __init__(self, *args, **kwargs):
self.items = []
self.itemlist = []
self.commands = []
self.ids = {}
self.channel = None
def onInit(self):
#### Compatibility with Kodi 18 ####
if config.get_platform(True)['num_version'] < 18:
self.setCoordinateResolution(2)
if len(self.items) == 0:
if Info.action == 'new_search' and Info.mode:
from specials.search import new_search
itemlist = new_search(Info)
elif Info.action == 'channel_search':
from specials.search import channel_search
itemlist = channel_search(Info)
else:
self.channel = __import__('channels.%s' % Info.channel, fromlist=["channels.%s" % Info.channel])
if Info.action == 'search': itemlist = getattr(self.channel, 'search')(Info, Info.search_text)
else: itemlist = getattr(self.channel, Info.action)(Info)
if not itemlist:
if platformtools.dialog_yesno(config.get_localized_string(60473), config.get_localized_string(70820) % Info.channel):
remove()
self.close()
return Search(Info.clone(mode=Info.infoLabels['mediatype']))
else:
remove()
self.close()
modal()
for item in itemlist:
if item.action not in ['save_download', 'add_pelicula_to_library', 'add_serie_to_library', ''] and item.infoLabels['title']:
if item.action == 'findvideos' and item.contentType in ['episode', 'tvshow']:
it = xbmcgui.ListItem(re.sub(r'\[[^\]]+\]', '', item.title))
self.getControl(NUMBER).setText(support.typo(config.get_localized_string(70362),'uppercase bold'))
else:
it = xbmcgui.ListItem(item.infoLabels['title'])
it.setProperty('channel', channeltools.get_channel_parameters(item.channel).get('title',''))
it.setProperty('action', item.action)
it.setProperty('server', servertools.get_server_parameters(item.server.lower()).get('name',item.server))
it.setProperty('url', item.url)
for key, value in item.infoLabels.items():
it.setProperty(key, str(value))
if item.action == 'play':
it.setProperty('thumbnail', "https://raw.githubusercontent.com/kodiondemand/media/master/resources/servers/%s.png" % item.server.lower())
self.items.append(it)
self.itemlist.append(item)
if itemlist[0].contentType == 'movie':
if not itemlist[0].server:
self.commands.append(itemlist[0].clone(action='add_pelicula_to_library', thumbnail=support.thumb('add_to_videolibrary')))
self.commands.append(itemlist[0].clone(channel='downloads', action='save_download', from_channel=itemlist[0].channel, from_action=itemlist[0].action, thumbnail=support.thumb('downloads')))
else:
self.commands.append(Info.clone(channel='downloads', action='save_download', from_channel=Info.channel, from_action=Info.action, thumbnail=support.thumb('downloads')))
if itemlist[0].contentType in ['tvshow', 'episode']:
if not itemlist[0].server:
self.commands.append(itemlist[0].clone(action='add_serie_to_library', thumbnail=support.thumb('add_to_videolibrary')))
self.commands.append(itemlist[0].clone(channel='downloads', action='save_download', from_channel=itemlist[0].channel, from_action=itemlist[0].action, thumbnail=support.thumb('downloads')))
else:
self.commands.append(Info.clone(channel='downloads', action='save_download', from_channel=Info.channel, from_action=Info.action, thumbnail=support.thumb('downloads')))
if self.commands:
commands = []
for command in self.commands:
it = xbmcgui.ListItem(command.title)
path = filetools.join(config.get_runtime_path(),'resources','skins','Default','media','Infoplus',command.thumbnail.split('/')[-1].replace('thumb_',''))
it.setProperty('thumbnail',path)
commands.append(it)
self.getControl(COMMANDS).addItems(commands)
if self.items:
self.getControl(FANART).setImage(self.items[0].getProperty('fanart'))
self.getControl(RECOMANDED).addItems(self.items)
self.getControl(LOADING).setVisible(False)
getFocus(self)
def onClick(self, control_id):
setFocus(self)
if control_id == COMMANDS:
from platformcode.launcher import run
pos = self.getControl(COMMANDS).getSelectedPosition()
if self.commands[pos].action =='save_download' and self.commands[pos].contentType == 'tvshow':
actions = [self.commands[-1].clone(), self.commands[-1].clone(download='season')]
options = [config.get_localized_string(60355),config.get_localized_string(60357)]
run(actions[platformtools.dialog_select(config.get_localized_string(60498),options)])
else:
run(self.commands[pos])
else:
action = self.getControl(RECOMANDED).getSelectedItem().getProperty('action')
channel = self.getControl(RECOMANDED).getSelectedItem().getProperty('channel')
url = self.getControl(RECOMANDED).getSelectedItem().getProperty('url')
item = Item(channel=channel, action=action, url=url)
if action == 'play':
item.server = self.getControl(RECOMANDED).getSelectedItem().getProperty('server')
self.close()
platformtools.play_video(item)
xbmc.sleep(500)
while xbmc.Player().isPlaying():
xbmc.sleep(500)
modal()
elif config.get_setting('autoplay'):
item.quality = self.getControl(RECOMANDED).getSelectedItem().getProperty('quality')
getattr(self.channel, item.action)(item)
self.close()
xbmc.sleep(500)
while xbmc.Player().isPlaying():
xbmc.sleep(500)
modal()
else:
pos = self.getControl(RECOMANDED).getSelectedPosition()
self.close()
if self.itemlist[pos].mode: remove()
Search(self.itemlist[pos])
def onAction(self, action):
if self.getFocusId() in [RECOMANDED]:
fanart = self.getControl(self.getFocusId()).getSelectedItem().getProperty('fanart')
self.getControl(FANART).setImage(fanart)
action = action.getId()
if action in [BACKSPACE]:
self.close()
remove()
modal()
elif action in [EXIT]:
self.close()
def Trailer(info):
global info_list, trailers
trailers = []
trailers_list = []
Type = info.getProperty('mediatype')
if Type != "movie": Type = "tv"
trailers_list = tmdb.Tmdb(id_Tmdb=info.getProperty('tmdb_id'), tipo=Type).get_videos()
if trailers_list:
for i, trailer in enumerate(trailers_list):
item = xbmcgui.ListItem(trailer['name'])
item.setProperties({'tile':trailer['name'],
'url': trailer['url'],
'thumbnail': 'http://img.youtube.com/vi/' + trailer['url'].split('=')[-1] + '/0.jpg',
'fanart':info.getProperty('fanart'),
'position':'%s/%s' % (i + 1, len(trailers_list))})
trailers.append(item)
else: # TRY youtube search
patron = r'thumbnails":\[\{"url":"(https://i.ytimg.com/vi[^"]+).*?'
patron += r'text":"([^"]+).*?'
patron += r'simpleText":"[^"]+.*?simpleText":"([^"]+).*?'
patron += r'url":"([^"]+)'
matches = support.match('https://www.youtube.com/results?search_query=' + info.getProperty('title').replace(' ','+') + '+trailer+ita', patron = patron).matches
i = 0
for thumb, title, text, url in matches:
i += 1
item = xbmcgui.ListItem(title + ' - '+ text)
item.setProperties({'tile':title + ' - '+ text, 'url': url, 'thumbnail': thumb, 'fanart':info.getProperty('fanart'), 'position':'%s/%s' % (i, len(matches))})
trailers.append(item)
main = TrailerWindow('TrailerWindow.xml', config.get_runtime_path())
add({'class':main, 'info':trailers, 'id':RECOMANDED, TRAILERS:0})
modal()
class TrailerWindow(xbmcgui.WindowXMLDialog):
def __init__(self, *args, **kwargs):
self.ids = {}
def onInit(self):
#### Compatibility with Kodi 18 ####
if config.get_platform(True)['num_version'] < 18:
self.setCoordinateResolution(2)
self.getControl(FANART).setImage(trailers[0].getProperty('fanart'))
self.getControl(NUMBER).setText(trailers[0].getProperty('position'))
self.getControl(TRAILERS).addItems(trailers)
self.setFocusId(TRAILERS)
getFocus(self)
def onClick(self, control_id):
setFocus(self)
if control_id in [TRAILERS]:
selected = self.getControl(TRAILERS).getSelectedItem()
platformtools.play_video(Item(title=selected.getProperty('title'), action='play', url=selected.getProperty('url'), server='youtube'))
while not xbmc.Player().isPlaying():
xbmc.sleep(100)
self.close()
while xbmc.Player().isPlaying():
xbmc.sleep(100)
modal()
def onAction(self, action):
if self.getFocusId() in [TRAILERS]:
self.ids[self.getFocusId()] = self.getControl(self.getFocusId()).getSelectedPosition()
fanart = self.getControl(TRAILERS).getSelectedItem().getProperty('fanart')
position = self.getControl(TRAILERS).getSelectedItem().getProperty('position')
self.getControl(FANART).setImage(fanart)
self.getControl(NUMBER).setText(position)
action = action.getId()
global info_list
if action in [BACKSPACE]:
self.close()
remove()
modal()
elif action in [EXIT]:
self.close()
class images(xbmcgui.WindowDialog):
def __init__(self, *args, **kwargs):
self.tmdb = kwargs.get("tmdb", {})
self.imdb = kwargs.get("imdb", {})
self.mal = kwargs.get("mal", {})
self.fanartv = kwargs.get("fanartv", {})
self.image_list = []
for key, value in self.tmdb.items():
for detail in value: self.image_list.append('http://image.tmdb.org/t/p/original' + detail["file_path"])
for image in self.imdb: self.image_list.append(image["src"])
for image, title in self.mal: self.image_list.append(image)
for key, value in self.fanartv.items():
for image in value: self.image_list.append(image["url"])
#### Kodi 18 Compatibility ####
if config.get_platform(True)['num_version'] < 18: self.setCoordinateResolution(2)
log
self.background = xbmcgui.ControlImage(0, 0, 1280, 720, imagepath('white'), colorDiffuse='FF232323')
self.addControl(self.background)
main_image = self.image_list[0] if self.image_list else ''
self.main_image = xbmcgui.ControlImage(0, 0, 1280, 720, main_image, 2)
self.addControl(self.main_image)
self.close_btn = xbmcgui.ControlButton(0, 0, 1280, 720, '' ,'', '')
self.addControl(self.close_btn)
# BUTTON LEFT
self.btn_left = xbmcgui.ControlButton(0, 330, 60, 60, '', imagepath('previous_focus'), imagepath('previous_nofocus'))
self.addControl(self.btn_left)
self.btn_left.setAnimations([('WindowOpen', 'effect=slide start=-60,0 end=0,0 delay=100 time=200'),('WindowClose', 'effect=slide start=0,0 end=-60,0 delay=100 time=200')])
# BUTTON RIGHT
self.btn_right = xbmcgui.ControlButton(1220, 330, 60, 60, '', imagepath('next_focus'), imagepath('next_nofocus'))
self.addControl(self.btn_right)
self.btn_right.setAnimations([('WindowOpen', 'effect=slide start=60,0 end=0,0 delay=100 time=200'),('WindowClose', 'effect=slide start=0,0 end=60,0 delay=100 time=200')])
self.count = 0
def onAction(self, action):
if action in [BACKSPACE, EXIT]:
self.close()
if action in [RIGHT, DOWN]:
self.count += 1
if self.count > len(self.image_list) -1: self.count = 0
self.main_image.setImage(self.image_list[self.count])
if action in [LEFT, UP]:
self.count -= 1
if self.count < 0: self.count = len(self.image_list) -1
self.main_image.setImage(self.image_list[self.count])
def onControl(self, control):
if control.getId() == self.btn_right.getId():
self.count += 1
if self.count > len(self.image_list) -1: self.count = 0
self.main_image.setImage(self.image_list[self.count])
elif control.getId() == self.btn_left.getId():
self.count -= 1
if self.count < 0: self.count = len(self.image_list) -1
self.main_image.setImage(self.image_list[self.count])
else:
self.close()
def get_recomendations(info):
recommendations = [info]
Type = info.getProperty('mediatype')
if Type != "movie": Type = "tv"
search = {'url': '%s/%s/recommendations' % (Type, info.getProperty('tmdb_id')), 'language': 'it', 'page': 1}
tmdb_res = tmdb.Tmdb(discover=search, tipo=Type, idioma_Search='it').results
for result in tmdb_res:
if Type == 'movie':
title = result.get("title", '')
original_title = result.get("original_title", "")
else:
title = result.get("name", '')
original_title = result.get("original_name", '')
thumbnail ='http://image.tmdb.org/t/p/w342' + result.get("poster_path", "") if result.get("poster_path", "") else ''
fanart = 'http://image.tmdb.org/t/p/original' + result.get("backdrop_path", "") if result.get("backdrop_path", "") else ''
item = xbmcgui.ListItem(title)
item.setProperties({'title': title,
'original_title': original_title,
'mediatype': info.getProperty('mediatype'),
'tmdb_id': result.get('id', 0),
'imdb_id': info.getProperty('imdb_id'),
'rating': result.get('vote_average', 0),
'plot': result.get('overview', ''),
'year': result.get('release_date', '').split('-')[0],
'thumbnail': thumbnail,
'fanart': fanart})
recommendations.append(item)
return recommendations
def get_cast(info):
cast_list = []
actors_list = []
Type = "movie" if info.getProperty('mediatype') == 'movie' else 'tv'
otmdb = tmdb.Tmdb(id_Tmdb=info.getProperty('tmdb_id'), tipo=Type)
actors = otmdb.result.get("credits", {}).get("cast", [])
cast = otmdb.result.get("credits", {}).get("crew", []) if Type == 'movie' else otmdb.result.get("created_by", [])
for i, crew in enumerate(cast):
if crew.get('job', '') == 'Director' or Type!= "movie":
actors.insert(0, crew)
else:
res = xbmcgui.ListItem(crew.get('name', ''))
res.setProperties({'title': crew.get('name', ''),
'job': crew.get('job', '') if crew.get('job', '') else crew.get('character',''),
'thumbnail': "https://image.tmdb.org/t/p/w342" + crew.get('profile_path', '') if crew.get('profile_path', '') else '',
'department': crew.get('department', ''),
'type': Type,
'id': crew.get('id', ''),
'mediatype': info.getProperty('mediatype')})
cast_list.append(res)
for actor in actors:
res = xbmcgui.ListItem(actor.get('name', ''))
res.setProperties({'title': actor.get('name', ''),
'job': actor.get('job', '') if actor.get('job', '') else actor.get('character',''),
'thumbnail': "https://image.tmdb.org/t/p/w342" + actor.get('profile_path', '') if actor.get('profile_path', '') else imagepath('no_photo'),
'type': Type,
'id': actor.get('id', ''),
'mediatype': info.getProperty('mediatype')})
actors_list.append(res)
return cast_list, actors_list
def imagepath(image):
if len(image.split('.')) == 1: image += '.png'
path = filetools.join(config.get_runtime_path(), 'resources', 'skins' , 'Default', 'media', 'Infoplus', image)
return path
def actors_more_info(ListItem):
Type = ListItem.getProperty('type')
actor_id = ListItem.getProperty('id')
more = tmdb.Tmdb(discover={'url': 'person/' + str(actor_id), 'language': 'en'}).results
if more['biography']: ListItem.setProperty('bio', more['biography'])
def get_movies(info):
Type = info.getProperty('mediatype') if info.getProperty('mediatype') == 'movie' else 'tv'
more = tmdb.Tmdb(discover={'url': 'person/' + str(info.getProperty('id')), 'language': 'it', 'append_to_response': Type + '_credits'}).results
movies = []
for movie in more.get(Type + '_credits', {}).get('cast',[]) + more.get(Type + '_credits', {}).get('crew',[]):
ret = {}
ret['mediatype'] = info.getProperty('mediatype')
thumbnail = movie.get('poster_path','')
ret['thumbnail'] = "https://image.tmdb.org/t/p/w342" + thumbnail if thumbnail else imagepath(Type)
ret['title'] = movie.get('title','') if Type == 'movie' else movie.get('name','')
ret['original_title'] = movie.get('original_title','') if Type == 'movie' else movie.get("original_name", '')
ret['tmdb_id'] = movie.get('id',0)
if ret not in movies: movies.append(ret)
itemlist = []
with futures.ThreadPoolExecutor() as executor:
List = [executor.submit(add_infoLabels, movie) for movie in movies]
for res in futures.as_completed(List):
if res.result():
itemlist.append(res.result())
itemlist = sorted(itemlist, key=lambda it: (it.getProperty('year'),it.getProperty('title')))
return itemlist
def add_infoLabels(movie):
it = Item(title=movie['title'], infoLabels=movie, contentType=movie['mediatype'])
tmdb.set_infoLabels_item(it, True)
movie=it.infoLabels
item = xbmcgui.ListItem(movie['title'])
for key, value in movie.items():
item.setProperty(key, str(value))
return item
def add(Dict):
global info_list
info_list.append(Dict)
def remove():
global info_list
info_list = info_list[:-1]
def modal():
global Info
global info_list
if info_list:
Info = info_list[-1]['info']
info_list[-1]['class'].doModal()
def getFocus(self):
global info_list
for key, value in info_list[-1].items():
if key not in ['class', 'info', 'id']:
self.getControl(int(key)).selectItem(value)
self.setFocusId(info_list[-1]['id'])
def setFocus(self):
global info_list
info_list[-1]['id'] = self.getFocusId()
for key, values in self.ids.items():
info_list[-1][key] = values