494 lines
18 KiB
Python
494 lines
18 KiB
Python
# -*- coding: utf-8 -*-
|
|
# vStream https://github.com/Kodi-vStream/venom-xbmc-addons
|
|
from resources.lib.comaddon import addon, dialog, listitem, xbmc, xbmcgui
|
|
from resources.lib.tmdb import cTMDb
|
|
from datetime import date, datetime
|
|
|
|
import unicodedata
|
|
import xbmcvfs
|
|
import time
|
|
|
|
|
|
# -----------------------
|
|
# Cookies gestion
|
|
# ------------------------
|
|
|
|
|
|
class GestionCookie():
|
|
PathCache = 'special://userdata/addon_data/plugin.video.vstream'
|
|
|
|
def MakeListwithCookies(self,c):
|
|
t = {}
|
|
c = c.split(';')
|
|
for i in c:
|
|
j = i.split('=',1)
|
|
if len(j) > 1:
|
|
t[j[0]] = j[1]
|
|
|
|
return t
|
|
|
|
|
|
def DeleteCookie(self, Domain):
|
|
Name = '/'.join([self.PathCache, 'cookie_%s.txt']) % (Domain)
|
|
xbmcvfs.delete(Name)
|
|
|
|
def SaveCookie(self, Domain, data):
|
|
Name = '/'.join([self.PathCache, 'cookie_%s.txt']) % (Domain)
|
|
|
|
# save it
|
|
# file = open(Name, 'w')
|
|
# file.write(data)
|
|
# file.close()
|
|
|
|
f = xbmcvfs.File(Name, 'w')
|
|
f.write(data)
|
|
f.close()
|
|
|
|
def Readcookie(self, Domain):
|
|
Name = '/'.join([self.PathCache, 'cookie_%s.txt']) % (Domain)
|
|
|
|
# try:
|
|
# file = open(Name,'r')
|
|
# data = file.read()
|
|
# file.close()
|
|
# except:
|
|
# return ''
|
|
|
|
try:
|
|
f = xbmcvfs.File(Name)
|
|
data = f.read()
|
|
f.close()
|
|
except:
|
|
return ''
|
|
|
|
return data
|
|
|
|
def AddCookies(self):
|
|
cookies = self.Readcookie(self.__sHosterIdentifier)
|
|
return 'Cookie=' + cookies
|
|
|
|
def MixCookie(self,ancien_cookies, new_cookies):
|
|
t1 = self.MakeListwithCookies(ancien_cookies)
|
|
t2 = self.MakeListwithCookies(new_cookies)
|
|
#Les nouveaux doivent ecraser les anciens
|
|
for i in t2:
|
|
t1[i] = t2[i]
|
|
|
|
cookies = ''
|
|
for c in t1:
|
|
cookies = cookies + c + '=' + t1[c] + ';'
|
|
cookies = cookies[:-1]
|
|
return cookies
|
|
|
|
# -------------------------------
|
|
# Configuration gestion
|
|
# -------------------------------
|
|
|
|
class cConfig():
|
|
|
|
# def __init__(self):
|
|
|
|
# import xbmcaddon
|
|
# self.__oSettings = xbmcaddon.Addon(self.getPluginId())
|
|
# self.__aLanguage = self.__oSettings.getLocalizedString
|
|
# self.__setSetting = self.__oSettings.setSetting
|
|
# self.__getSetting = self.__oSettings.getSetting
|
|
# self.__oVersion = self.__oSettings.getAddonInfo('version')
|
|
# self.__oId = self.__oSettings.getAddonInfo('id')
|
|
# self.__oPath = self.__oSettings.getAddonInfo('path')
|
|
# self.__oName = self.__oSettings.getAddonInfo('name')
|
|
# self.__oCache = xbmc.translatePath(self.__oSettings.getAddonInfo('profile'))
|
|
# self.__sRootArt = os.path.join(self.__oPath, 'resources' , 'art', '')
|
|
# self.__sIcon = os.path.join(self.__oPath,'resources', 'art','icon.png')
|
|
# self.__sFanart = os.path.join(self.__oPath,'resources','art','fanart.jpg')
|
|
# self.__sFileFav = os.path.join(self.__oCache,'favourite.db').decode('utf-8')
|
|
# self.__sFileDB = os.path.join(self.__oCache,'vstream.db').decode('utf-8')
|
|
# self.__sFileCache = os.path.join(self.__oCache,'video_cache.db').decode('utf-8')
|
|
|
|
def isDharma(self):
|
|
return self.__bIsDharma
|
|
|
|
def getSettingCache(self):
|
|
return False
|
|
|
|
def getAddonPath(self):
|
|
return False
|
|
|
|
def getRootArt(self):
|
|
return False
|
|
|
|
def getFileFav(self):
|
|
return False
|
|
|
|
def getFileDB(self):
|
|
return False
|
|
|
|
def getFileCache(self):
|
|
return False
|
|
|
|
|
|
def WindowsBoxes(sTitle, sFileName, metaType, year=''):
|
|
|
|
ADDON = addon()
|
|
DIALOG = dialog()
|
|
|
|
# Presence de l'addon ExtendedInfo?
|
|
try:
|
|
if (addon('script.extendedinfo') and ADDON.getSetting('extendedinfo-view') == 'true'):
|
|
if metaType == '2':
|
|
DIALOG.VSinfo('Lancement de ExtendInfo')
|
|
xbmc.executebuiltin('RunScript(script.extendedinfo, info=extendedtvinfo, name=%s)' % sFileName)
|
|
return
|
|
elif metaType == '1':
|
|
DIALOG.VSinfo('Lancement de ExtendInfo')
|
|
xbmc.executebuiltin('RunScript(script.extendedinfo, info=extendedinfo, name=%s)' % sFileName)
|
|
return
|
|
except:
|
|
pass
|
|
|
|
|
|
# Sinon on gere par vStream via la lib TMDB
|
|
sType = str(metaType).replace('1', 'movie').replace('2', 'tvshow').replace('3', 'collection').replace('4', 'anime')
|
|
|
|
try:
|
|
meta = cTMDb().get_meta(sType, sFileName, tmdb_id = xbmc.getInfoLabel('ListItem.Property(TmdbId)'), year = year)
|
|
try:
|
|
meta['plot'] = str(meta['plot'].encode('latin-1'), 'utf-8')
|
|
except:
|
|
pass
|
|
except:
|
|
DIALOG.VSok("Veuillez vider le cache des métadonnées Paramètre - outils - 'vider le cache de vStream'")
|
|
pass
|
|
|
|
|
|
# si rien ne marche
|
|
if (not meta['imdb_id'] and not meta['tmdb_id'] and not meta['tvdb_id']):
|
|
# dialog par defaut
|
|
# xbmc.executebuiltin('Action(Info)')
|
|
# fenetre d'erreur
|
|
DIALOG.VSinfo(ADDON.VSlang(30204))
|
|
return
|
|
|
|
# convertion de la date au format JJ/MM/AAAA
|
|
if 'premiered' in meta and meta['premiered']:
|
|
releaseDate = datetime(*(time.strptime(meta['premiered'], '%Y-%m-%d')[0:6]))
|
|
meta['releaseDate'] = releaseDate.strftime('%d/%m/%Y')
|
|
else:
|
|
meta['releaseDate'] = '-'
|
|
|
|
# convertion de la durée en secondes -> heure:minutes
|
|
if 'duration' in meta and meta['duration']:
|
|
duration = meta['duration']/60 # En minutes
|
|
durationH = duration/60 # Nombre d'heures
|
|
meta['durationH'] = durationH
|
|
#Le resultat doit obligatoirement etre un int sous Py3.
|
|
meta['durationM'] = '{:02d}'.format(int(duration - 60*durationH))
|
|
else:
|
|
meta['durationH'] = 0
|
|
meta['durationM'] = 0
|
|
|
|
|
|
# affichage du dialog perso
|
|
class XMLDialog(xbmcgui.WindowXMLDialog):
|
|
|
|
ADDON = addon()
|
|
"""
|
|
Dialog class that asks user about rating of movie.
|
|
"""
|
|
def __init__(self, *args, **kwargs):
|
|
xbmcgui.WindowXMLDialog.__init__(self)
|
|
pass
|
|
|
|
# def message(self, message):
|
|
# """
|
|
# Shows xbmc dialog with OK and message.
|
|
# """
|
|
# dialog = xbmcgui.Dialog()
|
|
# dialog.ok(' My message title', message)
|
|
# self.close()
|
|
|
|
def onInit(self):
|
|
# par default le resumer#
|
|
color = ADDON.getSetting('deco_color')
|
|
self.setProperty('color', color)
|
|
self.poster = 'https://image.tmdb.org/t/p/%s' % self.ADDON.getSetting('poster_tmdb')
|
|
self.none_poster = 'https://eu.ui-avatars.com/api/?background=000&size=512&name=%s&color=FFF&font-size=0.33'
|
|
|
|
#self.getControl(50).setVisible(False)
|
|
#self.getControl(90).setVisible(False)
|
|
#self.getControl(5200).setVisible(False)
|
|
#self.getControl(52100).setVisible(False)
|
|
#self.getControl(52200).setVisible(False)
|
|
# synopsis_first
|
|
self.setFocusId(9000)
|
|
|
|
# self.getControl(50).reset()
|
|
|
|
if 'credits' in meta and meta['credits']:
|
|
cast = []
|
|
crew = []
|
|
|
|
#Decodage python 3
|
|
try:
|
|
data = eval(str(meta['credits'].encode('latin-1'), 'utf-8'))
|
|
except:
|
|
data = eval(str(meta['credits']))
|
|
|
|
try:
|
|
listitems = []
|
|
for i in data['cast']:
|
|
slabel = i['name']
|
|
slabel2 = i['character']
|
|
if i['profile_path']:
|
|
sicon = self.poster+str(i['profile_path'])
|
|
else :
|
|
sicon = self.none_poster % slabel
|
|
sid = i['id']
|
|
listitem_ = listitem(label=slabel, label2=slabel2)
|
|
listitem_.setProperty('id', str(sid))
|
|
listitem_.setArt({'icon':sicon})
|
|
listitems.append(listitem_)
|
|
cast.append(slabel.encode('ascii', 'ignore'))
|
|
self.getControl(50).addItems(listitems)
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
listitems2 = []
|
|
for i in data['crew']:
|
|
slabel = i['name']
|
|
slabel2 = i['job']
|
|
if i['profile_path']:
|
|
sicon = self.poster+str(i['profile_path'])
|
|
else :
|
|
sicon = self.none_poster % slabel
|
|
sid = i['id']
|
|
listitem_ = listitem(label=slabel, label2=slabel2)
|
|
listitem_.setProperty('id', str(sid))
|
|
listitem_.setArt({'icon':sicon})
|
|
listitems2.append(listitem_)
|
|
crew.append(slabel.encode('ascii', 'ignore'))
|
|
self.getControl(5200).addItems(listitems2)
|
|
except:
|
|
pass
|
|
|
|
# try:
|
|
# for slabel, slabel2, sicon, sid in meta['cast']:
|
|
# listitem_ = listitem(label=slabel, label2=slabel2, iconImage=sicon)
|
|
# listitem_.setProperty('id', str(sid))
|
|
# listitems.append(listitem_)
|
|
# cast.append(slabel.encode('ascii', 'ignore'))
|
|
# self.getControl(50).addItems(listitems)
|
|
# #self.setProperty('ListItem.casting', str(cast))
|
|
# except:
|
|
# pass
|
|
|
|
# title
|
|
# self.getControl(1).setLabel(meta['title'])
|
|
meta['title'] = sTitle
|
|
|
|
# self.getControl(49).setVisible(True)
|
|
# self.getControl(2).setImage(meta['cover_url'])
|
|
# self.getControl(3).setLabel(meta['rating'])
|
|
|
|
if 'rating' not in meta or meta['rating'] == 0:
|
|
meta['rating'] = '-'
|
|
if 'votes' not in meta or meta['votes'] == '0':
|
|
meta['votes'] = '-'
|
|
|
|
|
|
for prop in meta:
|
|
#Py3 unicode == str.
|
|
try:
|
|
if isinstance(meta[prop], unicode):
|
|
self.setProperty(prop, meta[prop].encode('utf-8'))
|
|
else:
|
|
self.setProperty(prop, str(meta[prop]))
|
|
except:
|
|
if isinstance(meta[prop], str):
|
|
self.setProperty(prop, meta[prop].encode('utf-8'))
|
|
else:
|
|
self.setProperty(prop, str(meta[prop]))
|
|
|
|
def credit(self, meta='', control=''):
|
|
#self.getControl(control).reset()
|
|
listitems = []
|
|
|
|
if not meta:
|
|
meta = [{u'id': 0, u'title': u'Aucune information', u'poster_path': u'', u'vote_average':0}]
|
|
|
|
try:
|
|
for i in meta:
|
|
try:
|
|
sTitle = unicodedata.normalize('NFKD', i['title']).encode('ascii', 'ignore')
|
|
except:
|
|
sTitle = 'Aucune information'
|
|
|
|
if i['poster_path']:
|
|
sThumbnail = self.poster+str(i['poster_path'])
|
|
else :
|
|
sThumbnail = self.none_poster % sTitle
|
|
|
|
# sId = i['id']
|
|
|
|
listitem_ = listitem(label=sTitle)
|
|
try:
|
|
listitem_.setInfo('video', {'rating': i['vote_average'].encode('utf-8') })
|
|
except:
|
|
listitem_.setInfo('video', {'rating': str(i['vote_average'])})
|
|
|
|
listitem_.setArt({'icon':sThumbnail})
|
|
listitems.append(listitem_)
|
|
self.getControl(control).addItems(listitems)
|
|
|
|
except:
|
|
pass
|
|
|
|
#self.getControl(52100).setVisible(False)
|
|
#self.getControl(52200).setVisible(True)
|
|
#self.setFocusId(5205)
|
|
# self.setFocus(self.getControl(5200))
|
|
|
|
def onClick(self, controlId):
|
|
|
|
if controlId == 11:
|
|
from resources.lib.ba import cShowBA
|
|
cBA = cShowBA()
|
|
cBA.SetSearch(sFileName)
|
|
cBA.SetYear(year)
|
|
cBA.SetTrailerUrl(self.getProperty('trailer'))
|
|
cBA.SearchBA(True)
|
|
return
|
|
|
|
elif controlId == 30:
|
|
self.close()
|
|
return
|
|
|
|
elif controlId == 50 or controlId == 5200 :
|
|
# print(self.getControl(50).ListItem.Property('id'))
|
|
item = self.getControl(controlId).getSelectedItem()
|
|
sid = item.getProperty('id')
|
|
|
|
|
|
grab = cTMDb()
|
|
sUrl = 'person/' + str(sid)
|
|
|
|
|
|
try:
|
|
meta = grab.getUrl(sUrl, '', "append_to_response=movie_credits,tv_credits")
|
|
meta_credits = meta['movie_credits']['cast']
|
|
self.credit(meta_credits, 5215)
|
|
|
|
|
|
try:
|
|
sTitle = unicodedata.normalize('NFKD', meta['name']).encode('ascii', 'ignore')
|
|
except:
|
|
sTitle = 'Aucune information'
|
|
|
|
if not meta['deathday']:
|
|
today = date.today()
|
|
try:
|
|
birthday = datetime(*(time.strptime(meta['birthday'], '%Y-%m-%d')[0:6]))
|
|
age = today.year - birthday.year - ((today.month, today.day) < (birthday.month, birthday.day))
|
|
age = '%s Ans' % age
|
|
except:
|
|
age = ''
|
|
else:
|
|
age = meta['deathday']
|
|
|
|
|
|
self.setProperty('Person_name', sTitle)
|
|
self.setProperty('Person_birthday', meta['birthday'])
|
|
self.setProperty('Person_place_of_birth', meta['place_of_birth'])
|
|
self.setProperty('Person_deathday', str(age))
|
|
self.setProperty('Person_biography', meta['biography'])
|
|
self.setFocusId(9000)
|
|
|
|
except:
|
|
return
|
|
# self.getControl(50).setVisible(True)
|
|
self.setProperty('vstream_menu', 'Person')
|
|
|
|
# click sur similaire
|
|
elif controlId == 9:
|
|
# print(self.getControl(9000).ListItem.tmdb_id)
|
|
sid = self.getProperty('tmdb_id')
|
|
|
|
grab = cTMDb()
|
|
sUrl_simil = 'movie/%s/similar' % str(sid)
|
|
sUrl_recom = 'movie/%s/recommendations' % str(sid)
|
|
|
|
try:
|
|
meta = grab.getUrl(sUrl_simil)
|
|
meta = meta['results']
|
|
self.credit(meta, 5205)
|
|
except:
|
|
pass
|
|
try:
|
|
meta = grab.getUrl(sUrl_recom)
|
|
meta = meta['results']
|
|
self.credit(meta, 5210)
|
|
except:
|
|
return
|
|
|
|
# click pour recherche
|
|
elif controlId == 5215 or controlId == 5205 or controlId == 5210:
|
|
|
|
import sys
|
|
from resources.lib.util import cUtil
|
|
item = self.getControl(controlId).getSelectedItem()
|
|
sTitle = item.getLabel()
|
|
|
|
try:
|
|
sTitle = sTitle.encode('utf-8')
|
|
sTitle = cUtil().CleanName(sTitle)
|
|
except:
|
|
return
|
|
|
|
self.close()
|
|
|
|
# Si lancé depuis la page Home de Kodi, il faut d'abord en sortir pour lancer la recherche
|
|
if xbmc.getCondVisibility('Window.IsVisible(home)'):
|
|
xbmc.executebuiltin('ActivateWindow(%d)' % (10028))
|
|
|
|
sTest = '%s?site=globalSearch&searchtext=%s&sCat=1' % (sys.argv[0], sTitle)
|
|
xbmc.executebuiltin('Container.Update(%s)' % sTest)
|
|
return
|
|
# elif controlId == 2:
|
|
# print("paseeeee")
|
|
# xbmc.executebuiltin('Dialog.Close(all, force)')
|
|
# xbmc.executebuiltin('ActivateWindow(12005)')
|
|
# return
|
|
|
|
def onFocus(self, controlId):
|
|
self.controlId = controlId
|
|
#fullscreen end return focus menu
|
|
if controlId == 40:
|
|
while xbmc.Player().isPlaying():
|
|
xbmc.sleep(500)
|
|
if not xbmc.Player().isPlaying():
|
|
self.setFocusId(9000)
|
|
|
|
#if controlId != 5200:
|
|
# self.getControl(5500).reset()
|
|
# self.getControl(5200).setVisible(False)
|
|
# if controlId == 50:
|
|
# item = self.getControl(50).getSelectedItem()
|
|
# sid = item.getProperty('id')
|
|
|
|
def _close_dialog(self):
|
|
self.close()
|
|
|
|
def onAction(self, action):
|
|
if action.getId() in (104, 105, 1, 2):
|
|
return
|
|
|
|
if action.getId() in (9, 10, 11, 30, 92, 216, 247, 257, 275, 61467, 61448):
|
|
self.close()
|
|
|
|
path = 'special://home/addons/plugin.video.vstream'
|
|
# self.__oPath.decode('utf-8')
|
|
wd = XMLDialog('DialogInfo4.xml', path, 'default', '720p')
|
|
wd.doModal()
|
|
del wd
|