2015-03-13 21:24:59 +00:00
#################################################################################################
# utils
#################################################################################################
import xbmc
import xbmcgui
import xbmcaddon
import xbmcvfs
import json
import os
2015-03-19 23:48:59 +00:00
import cProfile
import pstats
import time
2015-03-13 22:39:35 +00:00
import sqlite3
2015-03-13 21:24:59 +00:00
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.mb3sync ' )
language = addonSettings . getLocalizedString
def logMsg ( title , msg , level = 1 ) :
2015-03-18 20:34:52 +00:00
logLevel = int ( addonSettings . getSetting ( " logLevel " ) )
2015-03-13 21:24:59 +00:00
if ( logLevel > = level ) :
2015-03-19 23:48:59 +00:00
if ( logLevel == 2 ) : # inspect.stack() is expensive
2015-03-13 21:24:59 +00:00
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 ' ) ) )
2015-03-16 21:31:32 +00:00
def convertEncoding ( data ) :
#nasty hack to make sure we have a unicode string
try :
return data . decode ( ' utf-8 ' )
except :
return data
2015-03-13 21:24:59 +00:00
def checkKodiSources ( ) :
addon = xbmcaddon . Addon ( id = ' plugin.video.mb3sync ' )
addondir = xbmc . translatePath ( addon . getAddonInfo ( ' profile ' ) )
2015-03-14 18:55:04 +00:00
dataPath = os . path . join ( addondir , " library " )
2015-03-14 18:37:52 +00:00
movieLibrary = os . path . join ( dataPath , ' movies ' )
tvLibrary = os . path . join ( dataPath , ' tvshows ' )
2015-03-13 21:24:59 +00:00
2015-03-14 17:23:45 +00:00
rebootRequired = False
2015-03-19 12:43:02 +00:00
2015-03-14 20:48:09 +00:00
if not xbmcvfs . exists ( dataPath + os . sep ) :
2015-03-13 21:24:59 +00:00
xbmcvfs . mkdir ( dataPath )
2015-03-14 20:48:09 +00:00
if not xbmcvfs . exists ( movieLibrary + os . sep ) :
2015-03-14 17:23:45 +00:00
xbmcvfs . mkdir ( movieLibrary )
2015-03-19 12:43:02 +00:00
rebootRequired = True
addKodiSource ( " mediabrowser_movies " , movieLibrary , " movies " )
2015-03-14 20:48:09 +00:00
if not xbmcvfs . exists ( tvLibrary + os . sep ) :
2015-03-14 17:23:45 +00:00
xbmcvfs . mkdir ( tvLibrary )
2015-03-19 12:43:02 +00:00
rebootRequired = True
addKodiSource ( " mediabrowser_tvshows " , tvLibrary , " tvshows " )
rebootRequired = KodiAdvancedSettingsCheck ( )
2015-03-13 21:24:59 +00:00
if rebootRequired :
2015-03-21 03:15:34 +00:00
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? " )
2015-03-13 21:24:59 +00:00
if ret :
xbmc . executebuiltin ( " RestartApp " )
2015-03-19 12:43:02 +00:00
else :
return False
return True
2015-03-13 21:24:59 +00:00
2015-03-13 22:39:35 +00:00
def addKodiSource ( name , path , type ) :
2015-03-14 11:28:11 +00:00
#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
2015-03-13 22:39:35 +00:00
dbPath = xbmc . translatePath ( " special://userdata/Database/MyVideos90.db " )
2015-03-14 17:23:45 +00:00
error = False
2015-03-14 11:28:11 +00:00
if xbmcvfs . exists ( dbPath ) :
2015-03-14 17:23:45 +00:00
try :
connection = sqlite3 . connect ( dbPath )
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(?, ?, ?, ?, ?, ?) "
2015-03-14 20:48:09 +00:00
cursor . execute ( pathsql , ( pathId , path + os . sep , type , " metadata.local " , None , 2147483647 ) )
2015-03-14 17:23:45 +00:00
connection . commit ( )
cursor . close ( )
except :
error = True
2015-03-14 11:28:11 +00:00
else :
2015-03-14 17:23:45 +00:00
error = True
2015-03-15 04:18:34 +00:00
# add it to sources.xml
sourcesFile = xbmc . translatePath ( " special://profile/sources.xml " )
# add an emply 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 )
2015-03-16 22:37:31 +00:00
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 )
2015-03-19 12:43:02 +00:00
writeNeeded = False
2015-03-16 22:37:31 +00:00
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
2015-03-19 12:43:02 +00:00
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
2015-03-15 04:18:34 +00:00
2015-03-13 21:24:59 +00:00
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
2015-03-19 23:48:59 +00:00
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.mb3sync ' ) . 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 \t TotalTime \t CumulativeTime \t FunctionName \t FileName \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 ( )
2015-03-17 18:41:26 +00:00
2015-03-13 21:24:59 +00:00