################################################################################################# # utils ################################################################################################# import xbmc import xbmcgui import xbmcaddon import xbmcvfs import json import os import cProfile import pstats import time import inspect from xml.etree.ElementTree import Element, SubElement, Comment, tostring from xml.etree import ElementTree from xml.dom import minidom import xml.etree.cElementTree as ET from API import API from PlayUtils import PlayUtils from DownloadUtils import DownloadUtils downloadUtils = DownloadUtils() addonSettings = xbmcaddon.Addon(id='plugin.video.emby') language = addonSettings.getLocalizedString def logMsg(title, msg, level = 1): logLevel = int(addonSettings.getSetting("logLevel")) if(logLevel >= level): if(logLevel == 2): # inspect.stack() is expensive try: xbmc.log(title + " -> " + inspect.stack()[1][3] + " : " + str(msg)) except UnicodeEncodeError: xbmc.log(title + " -> " + inspect.stack()[1][3] + " : " + str(msg.encode('utf-8'))) else: try: xbmc.log(title + " -> " + str(msg)) except UnicodeEncodeError: xbmc.log(title + " -> " + str(msg.encode('utf-8'))) def convertEncoding(data): #nasty hack to make sure we have a unicode string try: return data.decode('utf-8') except: return data def checkKodiSources(): addon = xbmcaddon.Addon(id='plugin.video.emby') addondir = xbmc.translatePath( addon.getAddonInfo('profile') ) dataPath = os.path.join(addondir,"library") movieLibrary = os.path.join(dataPath,'movies') tvLibrary = os.path.join(dataPath,'tvshows') musicvideoLibrary = os.path.join(dataPath,'musicvideos') rebootRequired = False if not xbmcvfs.exists(dataPath + os.sep): xbmcvfs.mkdir(dataPath) if not xbmcvfs.exists(movieLibrary + os.sep): xbmcvfs.mkdir(movieLibrary) rebootRequired = True addKodiSource("mediabrowser_movies",movieLibrary,"movies") if not xbmcvfs.exists(tvLibrary + os.sep): xbmcvfs.mkdir(tvLibrary) rebootRequired = True addKodiSource("mediabrowser_tvshows",tvLibrary,"tvshows") if not xbmcvfs.exists(musicvideoLibrary + os.sep): xbmcvfs.mkdir(musicvideoLibrary) rebootRequired = True addKodiSource("mediabrowser_musicvideos",musicvideoLibrary,"musicvideos") rebootRequired = KodiAdvancedSettingsCheck() if rebootRequired: ret = xbmcgui.Dialog().yesno(heading="Emby Sync service", line1="A restart of Kodi is needed to apply changes.", line2="Synchronisation will not start before the restart.", line3="Do you want to restart now?") if ret: xbmc.executebuiltin("RestartApp") else: return False return True def KodiSQL(): if xbmc.getInfoLabel("System.BuildVersion").startswith("13"): #gotham dbVersion = "78" if xbmc.getInfoLabel("System.BuildVersion").startswith("15"): #isengard dbVersion = "91" else: #helix dbVersion = "90" #find out if we should use MySQL useMySQL = False settingsFile = xbmc.translatePath( "special://profile/advancedsettings.xml" ) if xbmcvfs.exists(settingsFile): tree = ET.ElementTree(file=settingsFile) root = tree.getroot() video = root.find("videodatabase") if video != None: mysql = video.find("type") if mysql != None: useMySQL = True db_port = video.find("port").text db_host = video.find("host").text db_user = video.find("user").text db_pass = video.find("pass").text if video.find("name") != None: db_name = video.find("name").text else: db_name = "MyVideos" if useMySQL: import local.mysql.connector as database connection = database.connect(dbPath) connection = database.connect(db = db_name, user = db_user, passwd = db_pass, host = db_host, port = db_port) connection.set_charset('utf8') connection.set_unicode(True) else: import sqlite3 as database dbPath = xbmc.translatePath("special://userdata/Database/MyVideos" + dbVersion + ".db") connection = database.connect(dbPath) return connection def addKodiSource(name, path, type): #add new source to database, common way is to add it directly to the Kodi DB. Fallback to adding it to the sources.xml #return boolean wether a manual reboot is required. #todo: Do feature request with Kodi team to get support for adding a source by the json API error = False if xbmcvfs.exists(dbPath): try: connection = KodiSQL() cursor = connection.cursor( ) cursor.execute("select coalesce(max(idPath),0) as pathId from path") pathId = cursor.fetchone()[0] pathId = pathId + 1 pathsql="insert into path(idPath, strPath, strContent, strScraper, strHash, scanRecursive) values(?, ?, ?, ?, ?, ?)" cursor.execute(pathsql, (pathId,path + os.sep,type,"metadata.local",None,2147483647)) connection.commit() cursor.close() except: error = True else: error = True # add it to sources.xml sourcesFile = xbmc.translatePath( "special://profile/sources.xml" ) # add an empty sources file to work with if xbmcvfs.exists(sourcesFile) == False: sources = Element("sources") video = SubElement(sources, "video") ET.ElementTree(sources).write(sourcesFile) if xbmcvfs.exists(sourcesFile): tree = ET.ElementTree(file=sourcesFile) root = tree.getroot() videosources = root.find("video") #remove any existing entries for this path allsources = videosources.findall("source") if allsources != None: for source in allsources: if source.find("name").text == name: videosources.remove(source) # add the new source source = SubElement(videosources,'source') SubElement(source, "name").text = name SubElement(source, "path").text = path tree.write(sourcesFile) def KodiAdvancedSettingsCheck(): #setting that kodi should import watched state and resume points from the nfo files settingsFile = xbmc.translatePath( "special://profile/advancedsettings.xml" ) # add an empty sources file to work with if xbmcvfs.exists(settingsFile) == False: sources = Element("advancedsettings") video = SubElement(sources, "videolibrary") ET.ElementTree(sources).write(settingsFile) writeNeeded = False if xbmcvfs.exists(settingsFile): tree = ET.ElementTree(file=settingsFile) root = tree.getroot() video = root.find("videolibrary") if video == None: video = SubElement(sources, "videolibrary") # add the settings if video.find("importwatchedstate") == None: writeNeeded = True SubElement(video, "importwatchedstate").text = "true" if video.find("importresumepoint") == None: writeNeeded = True SubElement(video, "importresumepoint").text = "true" if writeNeeded: tree.write(settingsFile) return True else: return False def checkAuthentication(): #check authentication if addonSettings.getSetting('username') != "" and addonSettings.getSetting('ipaddress') != "": try: downloadUtils.authenticate() except Exception, e: logMsg("MB3 Syncer authentication failed",e) pass def prettifyXml(elem): rough_string = etree.tostring(elem, "utf-8") reparsed = minidom.parseString(rough_string) return reparsed.toprettyxml(indent="\t") def get_params( paramstring ): xbmc.log("Parameter string: " + paramstring) param={} if len(paramstring)>=2: params=paramstring if params[0] == "?": cleanedparams=params[1:] else: cleanedparams=params if (params[len(params)-1]=='/'): params=params[0:len(params)-2] pairsofparams=cleanedparams.split('&') for i in range(len(pairsofparams)): splitparams={} splitparams=pairsofparams[i].split('=') if (len(splitparams))==2: param[splitparams[0]]=splitparams[1] elif (len(splitparams))==3: param[splitparams[0]]=splitparams[1]+"="+splitparams[2] return param def startProfiling(): pr = cProfile.Profile() pr.enable() return pr def stopProfiling(pr, profileName): pr.disable() ps = pstats.Stats(pr) addondir = xbmc.translatePath(xbmcaddon.Addon(id='plugin.video.emby').getAddonInfo('profile')) fileTimeStamp = time.strftime("%Y-%m-%d %H-%M-%S") tabFileNamepath = os.path.join(addondir, "profiles") tabFileName = os.path.join(addondir, "profiles" , profileName + "_profile_(" + fileTimeStamp + ").tab") if not xbmcvfs.exists(tabFileNamepath): xbmcvfs.mkdir(tabFileNamepath) f = open(tabFileName, 'wb') f.write("NumbCalls\tTotalTime\tCumulativeTime\tFunctionName\tFileName\r\n") for (key, value) in ps.stats.items(): (filename, count, func_name) = key (ccalls, ncalls, total_time, cumulative_time, callers) = value try: f.write(str(ncalls) + "\t" + "{:10.4f}".format(total_time) + "\t" + "{:10.4f}".format(cumulative_time) + "\t" + func_name + "\t" + filename + "\r\n") except ValueError: f.write(str(ncalls) + "\t" + "{0}".format(total_time) + "\t" + "{0}".format(cumulative_time) + "\t" + func_name + "\t" + filename + "\r\n") f.close()