Centralized logging

This commit is contained in:
angelblue05 2016-06-17 22:03:28 -05:00
parent 02e7c2946b
commit 5658801f72
10 changed files with 336 additions and 373 deletions

View file

@ -6,8 +6,8 @@ import json
import requests import requests
import logging import logging
import utils
import clientinfo import clientinfo
from utils import Logging, window
################################################################################################## ##################################################################################################
@ -34,28 +34,26 @@ class ConnectUtils():
def __init__(self): def __init__(self):
global log
log = Logging(self.__class__.__name__).log
self.__dict__ = self._shared_state self.__dict__ = self._shared_state
def logMsg(self, msg, lvl=1):
className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
def setUserId(self, userId): def setUserId(self, userId):
# Reserved for userclient only # Reserved for userclient only
self.userId = userId self.userId = userId
self.logMsg("Set connect userId: %s" % userId, 2) log("Set connect userId: %s" % userId, 2)
def setServer(self, server): def setServer(self, server):
# Reserved for userclient only # Reserved for userclient only
self.server = server self.server = server
self.logMsg("Set connect server: %s" % server, 2) log("Set connect server: %s" % server, 2)
def setToken(self, token): def setToken(self, token):
# Reserved for userclient only # Reserved for userclient only
self.token = token self.token = token
self.logMsg("Set connect token: %s" % token, 2) log("Set connect token: %s" % token, 2)
def startSession(self): def startSession(self):
@ -73,7 +71,7 @@ class ConnectUtils():
if self.sslclient is not None: if self.sslclient is not None:
verify = self.sslclient verify = self.sslclient
except: except:
self.logMsg("Could not load SSL settings.", 1) log("Could not load SSL settings.", 1)
# Start session # Start session
self.c = requests.Session() self.c = requests.Session()
@ -83,13 +81,13 @@ class ConnectUtils():
self.c.mount("http://", requests.adapters.HTTPAdapter(max_retries=1)) self.c.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
self.c.mount("https://", requests.adapters.HTTPAdapter(max_retries=1)) self.c.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
self.logMsg("Requests session started on: %s" % self.server, 1) log("Requests session started on: %s" % self.server, 1)
def stopSession(self): def stopSession(self):
try: try:
self.c.close() self.c.close()
except Exception as e: except Exception as e:
self.logMsg("Requests session could not be terminated: %s" % e, 1) log("Requests session could not be terminated: %s" % e, 1)
def getHeader(self, authenticate=True): def getHeader(self, authenticate=True):
@ -103,7 +101,7 @@ class ConnectUtils():
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': "application/json" 'Accept': "application/json"
} }
self.logMsg("Header: %s" % header, 1) log("Header: %s" % header, 1)
else: else:
token = self.token token = self.token
@ -115,17 +113,17 @@ class ConnectUtils():
'X-Application': "Kodi/%s" % version, 'X-Application': "Kodi/%s" % version,
'X-Connect-UserToken': token 'X-Connect-UserToken': token
} }
self.logMsg("Header: %s" % header, 1) log("Header: %s" % header, 1)
return header return header
def doUrl(self, url, data=None, postBody=None, rtype="GET", def doUrl(self, url, data=None, postBody=None, rtype="GET",
parameters=None, authenticate=True, timeout=None): parameters=None, authenticate=True, timeout=None):
window = utils.window log("=== ENTER connectUrl ===", 2)
self.logMsg("=== ENTER connectUrl ===", 2)
default_link = "" default_link = ""
if timeout is None: if timeout is None:
timeout = self.timeout timeout = self.timeout
@ -209,25 +207,25 @@ class ConnectUtils():
verify=verifyssl) verify=verifyssl)
##### THE RESPONSE ##### ##### THE RESPONSE #####
self.logMsg(r.url, 1) log(r.url, 1)
self.logMsg(r, 1) log(r, 1)
if r.status_code == 204: if r.status_code == 204:
# No body in the response # No body in the response
self.logMsg("====== 204 Success ======", 1) log("====== 204 Success ======", 1)
elif r.status_code == requests.codes.ok: elif r.status_code == requests.codes.ok:
try: try:
# UNICODE - JSON object # UNICODE - JSON object
r = r.json() r = r.json()
self.logMsg("====== 200 Success ======", 1) log("====== 200 Success ======", 1)
self.logMsg("Response: %s" % r, 1) log("Response: %s" % r, 1)
return r return r
except: except:
if r.headers.get('content-type') != "text/html": if r.headers.get('content-type') != "text/html":
self.logMsg("Unable to convert the response for: %s" % url, 1) log("Unable to convert the response for: %s" % url, 1)
else: else:
r.raise_for_status() r.raise_for_status()
@ -238,8 +236,8 @@ class ConnectUtils():
pass pass
except requests.exceptions.ConnectTimeout as e: except requests.exceptions.ConnectTimeout as e:
self.logMsg("Server timeout at: %s" % url, 0) log("Server timeout at: %s" % url, 0)
self.logMsg(e, 1) log(e, 1)
except requests.exceptions.HTTPError as e: except requests.exceptions.HTTPError as e:
@ -255,11 +253,11 @@ class ConnectUtils():
pass pass
except requests.exceptions.SSLError as e: except requests.exceptions.SSLError as e:
self.logMsg("Invalid SSL certificate for: %s" % url, 0) log("Invalid SSL certificate for: %s" % url, 0)
self.logMsg(e, 1) log(e, 1)
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
self.logMsg("Unknown error connecting to: %s" % url, 0) log("Unknown error connecting to: %s" % url, 0)
self.logMsg(e, 1) log(e, 1)
return default_link return default_link

View file

@ -9,14 +9,15 @@ import logging
import xbmc import xbmc
import xbmcgui import xbmcgui
import utils
import clientinfo import clientinfo
from utils import Logging, window, settings
################################################################################################## ##################################################################################################
# Disable requests logging # Disable requests logging
from requests.packages.urllib3.exceptions import InsecureRequestWarning from requests.packages.urllib3.exceptions import InsecureRequestWarning, InsecurePlatformWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
requests.packages.urllib3.disable_warnings(InsecurePlatformWarning)
#logging.getLogger('requests').setLevel(logging.WARNING) #logging.getLogger('requests').setLevel(logging.WARNING)
################################################################################################## ##################################################################################################
@ -36,40 +37,38 @@ class DownloadUtils():
def __init__(self): def __init__(self):
global log
log = Logging(self.__class__.__name__).log
self.__dict__ = self._shared_state self.__dict__ = self._shared_state
def logMsg(self, msg, lvl=1):
className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
def setUsername(self, username): def setUsername(self, username):
# Reserved for userclient only # Reserved for userclient only
self.username = username self.username = username
self.logMsg("Set username: %s" % username, 2) log("Set username: %s" % username, 2)
def setUserId(self, userId): def setUserId(self, userId):
# Reserved for userclient only # Reserved for userclient only
self.userId = userId self.userId = userId
self.logMsg("Set userId: %s" % userId, 2) log("Set userId: %s" % userId, 2)
def setServer(self, server): def setServer(self, server):
# Reserved for userclient only # Reserved for userclient only
self.server = server self.server = server
self.logMsg("Set server: %s" % server, 2) log("Set server: %s" % server, 2)
def setToken(self, token): def setToken(self, token):
# Reserved for userclient only # Reserved for userclient only
self.token = token self.token = token
self.logMsg("Set token: %s" % token, 2) log("Set token: %s" % token, 2)
def setSSL(self, ssl, sslclient): def setSSL(self, ssl, sslclient):
# Reserved for userclient only # Reserved for userclient only
self.sslverify = ssl self.sslverify = ssl
self.sslclient = sslclient self.sslclient = sslclient
self.logMsg("Verify SSL host certificate: %s" % ssl, 2) log("Verify SSL host certificate: %s" % ssl, 2)
self.logMsg("SSL client side certificate: %s" % sslclient, 2) log("SSL client side certificate: %s" % sslclient, 2)
def postCapabilities(self, deviceId): def postCapabilities(self, deviceId):
@ -94,11 +93,11 @@ class DownloadUtils():
) )
} }
self.logMsg("Capabilities URL: %s" % url, 2) log("Capabilities URL: %s" % url, 2)
self.logMsg("Postdata: %s" % data, 2) log("Postdata: %s" % data, 2)
self.downloadUrl(url, postBody=data, action_type="POST") self.downloadUrl(url, postBody=data, action_type="POST")
self.logMsg("Posted capabilities to %s" % self.server, 2) log("Posted capabilities to %s" % self.server, 2)
# Attempt at getting sessionId # Attempt at getting sessionId
url = "{server}/emby/Sessions?DeviceId=%s&format=json" % deviceId url = "{server}/emby/Sessions?DeviceId=%s&format=json" % deviceId
@ -107,20 +106,19 @@ class DownloadUtils():
sessionId = result[0]['Id'] sessionId = result[0]['Id']
except (KeyError, TypeError): except (KeyError, TypeError):
self.logMsg("Failed to retrieve sessionId.", 1) log("Failed to retrieve sessionId.", 1)
else: else:
self.logMsg("Session: %s" % result, 2) log("Session: %s" % result, 2)
self.logMsg("SessionId: %s" % sessionId, 1) log("SessionId: %s" % sessionId, 1)
utils.window('emby_sessionId', value=sessionId) window('emby_sessionId', value=sessionId)
# Post any permanent additional users # Post any permanent additional users
additionalUsers = utils.settings('additionalUsers') additionalUsers = settings('additionalUsers')
if additionalUsers: if additionalUsers:
additionalUsers = additionalUsers.split(',') additionalUsers = additionalUsers.split(',')
self.logMsg( log("List of permanent users added to the session: %s"
"List of permanent users added to the session: %s"
% additionalUsers, 1) % additionalUsers, 1)
# Get the user list from server to get the userId # Get the user list from server to get the userId
@ -158,7 +156,7 @@ class DownloadUtils():
if self.sslclient is not None: if self.sslclient is not None:
verify = self.sslclient verify = self.sslclient
except: except:
self.logMsg("Could not load SSL settings.", 1) log("Could not load SSL settings.", 1)
# Start session # Start session
self.s = requests.Session() self.s = requests.Session()
@ -168,18 +166,18 @@ class DownloadUtils():
self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1)) self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1)) self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
self.logMsg("Requests session started on: %s" % self.server, 1) log("Requests session started on: %s" % self.server, 1)
def stopSession(self): def stopSession(self):
try: try:
self.s.close() self.s.close()
except: except:
self.logMsg("Requests session could not be terminated.", 1) log("Requests session could not be terminated.", 1)
def getHeader(self, authenticate=True): def getHeader(self, authenticate=True):
deviceName = self.clientInfo.getDeviceName() deviceName = self.clientInfo.getDeviceName()
deviceName = utils.normalize_string(deviceName.encode('utf-8')) deviceName = deviceName.encode('utf-8')
deviceId = self.clientInfo.getDeviceId() deviceId = self.clientInfo.getDeviceId()
version = self.clientInfo.getVersion() version = self.clientInfo.getVersion()
@ -195,7 +193,7 @@ class DownloadUtils():
'Accept-Charset': 'UTF-8,*', 'Accept-Charset': 'UTF-8,*',
'Authorization': auth 'Authorization': auth
} }
self.logMsg("Header: %s" % header, 2) log("Header: %s" % header, 2)
else: else:
userId = self.userId userId = self.userId
@ -212,19 +210,20 @@ class DownloadUtils():
'Authorization': auth, 'Authorization': auth,
'X-MediaBrowser-Token': token 'X-MediaBrowser-Token': token
} }
self.logMsg("Header: %s" % header, 2) log("Header: %s" % header, 2)
return header return header
def downloadUrl(self, url, postBody=None, action_type="GET", parameters=None, authenticate=True): def downloadUrl(self, url, postBody=None, action_type="GET", parameters=None,
authenticate=True):
self.logMsg("=== ENTER downloadUrl ===", 2) log("=== ENTER downloadUrl ===", 2)
default_link = "" default_link = ""
try: try:
# If user is authenticated # If user is authenticated
if (authenticate): if authenticate:
# Get requests session # Get requests session
try: try:
s = self.s s = self.s
@ -243,18 +242,18 @@ class DownloadUtils():
except AttributeError: except AttributeError:
# request session does not exists # request session does not exists
# Get user information # Get user information
self.userId = utils.window('emby_currUser') self.userId = window('emby_currUser')
self.server = utils.window('emby_server%s' % self.userId) self.server = window('emby_server%s' % self.userId)
self.token = utils.window('emby_accessToken%s' % self.userId) self.token = window('emby_accessToken%s' % self.userId)
header = self.getHeader() header = self.getHeader()
verifyssl = False verifyssl = False
cert = None cert = None
# IF user enables ssl verification # IF user enables ssl verification
if utils.settings('sslverify') == "true": if settings('sslverify') == "true":
verifyssl = True verifyssl = True
if utils.settings('sslcert') != "None": if settings('sslcert') != "None":
verifyssl = utils.settings('sslcert') verifyssl = settings('sslcert')
# Replace for the real values # Replace for the real values
url = url.replace("{server}", self.server) url = url.replace("{server}", self.server)
@ -314,23 +313,23 @@ class DownloadUtils():
verify=verifyssl) verify=verifyssl)
##### THE RESPONSE ##### ##### THE RESPONSE #####
self.logMsg(r.url, 2) log(r.url, 2)
if r.status_code == 204: if r.status_code == 204:
# No body in the response # No body in the response
self.logMsg("====== 204 Success ======", 2) log("====== 204 Success ======", 2)
elif r.status_code == requests.codes.ok: elif r.status_code == requests.codes.ok:
try: try:
# UNICODE - JSON object # UNICODE - JSON object
r = r.json() r = r.json()
self.logMsg("====== 200 Success ======", 2) log("====== 200 Success ======", 2)
self.logMsg("Response: %s" % r, 2) log("Response: %s" % r, 2)
return r return r
except: except:
if r.headers.get('content-type') != "text/html": if r.headers.get('content-type') != "text/html":
self.logMsg("Unable to convert the response for: %s" % url, 1) log("Unable to convert the response for: %s" % url, 1)
else: else:
r.raise_for_status() r.raise_for_status()
@ -338,26 +337,26 @@ class DownloadUtils():
except requests.exceptions.ConnectionError as e: except requests.exceptions.ConnectionError as e:
# Make the addon aware of status # Make the addon aware of status
if utils.window('emby_online') != "false": if window('emby_online') != "false":
self.logMsg("Server unreachable at: %s" % url, 0) log("Server unreachable at: %s" % url, 0)
self.logMsg(e, 2) log(e, 2)
utils.window('emby_online', value="false") window('emby_online', value="false")
except requests.exceptions.ConnectTimeout as e: except requests.exceptions.ConnectTimeout as e:
self.logMsg("Server timeout at: %s" % url, 0) log("Server timeout at: %s" % url, 0)
self.logMsg(e, 1) log(e, 1)
except requests.exceptions.HTTPError as e: except requests.exceptions.HTTPError as e:
if r.status_code == 401: if r.status_code == 401:
# Unauthorized # Unauthorized
status = utils.window('emby_serverStatus') status = window('emby_serverStatus')
if 'X-Application-Error-Code' in r.headers: if 'X-Application-Error-Code' in r.headers:
# Emby server errors # Emby server errors
if r.headers['X-Application-Error-Code'] == "ParentalControl": if r.headers['X-Application-Error-Code'] == "ParentalControl":
# Parental control - access restricted # Parental control - access restricted
utils.window('emby_serverStatus', value="restricted") window('emby_serverStatus', value="restricted")
xbmcgui.Dialog().notification( xbmcgui.Dialog().notification(
heading="Emby server", heading="Emby server",
message="Access restricted.", message="Access restricted.",
@ -371,8 +370,8 @@ class DownloadUtils():
elif status not in ("401", "Auth"): elif status not in ("401", "Auth"):
# Tell userclient token has been revoked. # Tell userclient token has been revoked.
utils.window('emby_serverStatus', value="401") window('emby_serverStatus', value="401")
self.logMsg("HTTP Error: %s" % e, 0) log("HTTP Error: %s" % e, 0)
xbmcgui.Dialog().notification( xbmcgui.Dialog().notification(
heading="Error connecting", heading="Error connecting",
message="Unauthorized.", message="Unauthorized.",
@ -387,11 +386,11 @@ class DownloadUtils():
pass pass
except requests.exceptions.SSLError as e: except requests.exceptions.SSLError as e:
self.logMsg("Invalid SSL certificate for: %s" % url, 0) log("Invalid SSL certificate for: %s" % url, 0)
self.logMsg(e, 1) log(e, 1)
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
self.logMsg("Unknown error connecting to: %s" % url, 0) log("Unknown error connecting to: %s" % url, 0)
self.logMsg(e, 1) log(e, 1)
return default_link return default_link

View file

@ -1,8 +1,14 @@
# -*- coding: utf-8 -*-
#################################################################################################
import threading import threading
import utils
import xbmc
import requests import requests
from utils import Logging
#################################################################################################
class image_cache_thread(threading.Thread): class image_cache_thread(threading.Thread):
urlToProcess = None urlToProcess = None
@ -13,28 +19,32 @@ class image_cache_thread(threading.Thread):
xbmc_username = "" xbmc_username = ""
xbmc_password = "" xbmc_password = ""
def __init__(self): def __init__(self):
self.monitor = xbmc.Monitor()
global log
log = Logging(self.__class__.__name__).log
threading.Thread.__init__(self) threading.Thread.__init__(self)
def logMsg(self, msg, lvl=1):
className = self.__class__.__name__
utils.logMsg("%s" % className, msg, lvl)
def setUrl(self, url): def setUrl(self, url):
self.urlToProcess = url self.urlToProcess = url
def setHost(self, host, port): def setHost(self, host, port):
self.xbmc_host = host self.xbmc_host = host
self.xbmc_port = port self.xbmc_port = port
def setAuth(self, user, pwd): def setAuth(self, user, pwd):
self.xbmc_username = user self.xbmc_username = user
self.xbmc_password = pwd self.xbmc_password = pwd
def run(self): def run(self):
self.logMsg("Image Caching Thread Processing : " + self.urlToProcess, 2) log("Image Caching Thread Processing: %s" % self.urlToProcess, 2)
try: try:
response = requests.head( response = requests.head(
@ -46,7 +56,5 @@ class image_cache_thread(threading.Thread):
# We don't need the result # We don't need the result
except: pass except: pass
self.logMsg("Image Caching Thread Exited", 2) log("Image Caching Thread Exited", 2)
self.isFinished = True
self.isFinished = True

View file

@ -9,10 +9,10 @@ import xbmc
import xbmcgui import xbmcgui
import xbmcaddon import xbmcaddon
import utils
import clientinfo import clientinfo
import downloadutils import downloadutils
import userclient import userclient
from utils import Logging, settings, language as lang, passwordsXML
################################################################################################# #################################################################################################
@ -22,74 +22,67 @@ class InitialSetup():
def __init__(self): def __init__(self):
self.addon = xbmcaddon.Addon() global log
self.__language__ = self.addon.getLocalizedString log = Logging(self.__class__.__name__).log
self.clientInfo = clientinfo.ClientInfo() self.clientInfo = clientinfo.ClientInfo()
self.addonName = self.clientInfo.getAddonName()
self.addonId = self.clientInfo.getAddonId() self.addonId = self.clientInfo.getAddonId()
self.doUtils = downloadutils.DownloadUtils() self.doUtils = downloadutils.DownloadUtils()
self.userClient = userclient.UserClient() self.userClient = userclient.UserClient()
def logMsg(self, msg, lvl=1):
className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
def setup(self): def setup(self):
# Check server, user, direct paths, music, direct stream if not direct path. # Check server, user, direct paths, music, direct stream if not direct path.
string = self.__language__
addonId = self.addonId addonId = self.addonId
##### SERVER INFO ##### ##### SERVER INFO #####
self.logMsg("Initial setup called.", 2) log("Initial setup called.", 2)
server = self.userClient.getServer() server = self.userClient.getServer()
if server: if server:
self.logMsg("Server is already set.", 2) log("Server is already set.", 2)
return return
self.logMsg("Looking for server...", 2) log("Looking for server...", 2)
server = self.getServerDetails() server = self.getServerDetails()
self.logMsg("Found: %s" % server, 2) log("Found: %s" % server, 2)
try: try:
prefix, ip, port = server.replace("/", "").split(":") prefix, ip, port = server.replace("/", "").split(":")
except: # Failed to retrieve server information except: # Failed to retrieve server information
self.logMsg("getServerDetails failed.", 1) log("getServerDetails failed.", 1)
xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId) xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId)
return return
else: else:
server_confirm = xbmcgui.Dialog().yesno( server_confirm = xbmcgui.Dialog().yesno(
heading="Emby for Kodi", heading="Emby for Kodi",
line1="Proceed with the following server?", line1="Proceed with the following server?",
line2="%s %s" % (string(30169), server)) line2="%s %s" % (lang(30169), server))
if server_confirm: if server_confirm:
# Correct server found # Correct server found
self.logMsg("Server is selected. Saving the information.", 1) log("Server is selected. Saving the information.", 1)
utils.settings('ipaddress', value=ip) settings('ipaddress', value=ip)
utils.settings('port', value=port) settings('port', value=port)
if prefix == "https": if prefix == "https":
utils.settings('https', value="true") settings('https', value="true")
else: else:
# User selected no or cancelled the dialog # User selected no or cancelled the dialog
self.logMsg("No server selected.", 1) log("No server selected.", 1)
xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId) xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId)
return return
##### USER INFO ##### ##### USER INFO #####
self.logMsg("Getting user list.", 1) log("Getting user list.", 1)
url = "%s/emby/Users/Public?format=json" % server url = "%s/emby/Users/Public?format=json" % server
result = self.doUtils.downloadUrl(url, authenticate=False) result = self.doUtils.downloadUrl(url, authenticate=False)
if result == "": if result == "":
self.logMsg("Unable to connect to %s" % server, 1) log("Unable to connect to %s" % server, 1)
return return
self.logMsg("Response: %s" % result, 2) log("Response: %s" % result, 2)
# Process the list of users # Process the list of users
usernames = [] usernames = []
users_hasPassword = [] users_hasPassword = []
@ -103,14 +96,14 @@ class InitialSetup():
name = "%s (secure)" % name name = "%s (secure)" % name
users_hasPassword.append(name) users_hasPassword.append(name)
self.logMsg("Presenting user list: %s" % users_hasPassword, 1) log("Presenting user list: %s" % users_hasPassword, 1)
user_select = xbmcgui.Dialog().select(string(30200), users_hasPassword) user_select = xbmcgui.Dialog().select(lang(30200), users_hasPassword)
if user_select > -1: if user_select > -1:
selected_user = usernames[user_select] selected_user = usernames[user_select]
self.logMsg("Selected user: %s" % selected_user, 1) log("Selected user: %s" % selected_user, 1)
utils.settings('username', value=selected_user) settings('username', value=selected_user)
else: else:
self.logMsg("No user selected.", 1) log("No user selected.", 1)
xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId) xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId)
##### ADDITIONAL PROMPTS ##### ##### ADDITIONAL PROMPTS #####
@ -126,8 +119,8 @@ class InitialSetup():
nolabel="Addon (Default)", nolabel="Addon (Default)",
yeslabel="Native (Direct Paths)") yeslabel="Native (Direct Paths)")
if directPaths: if directPaths:
self.logMsg("User opted to use direct paths.", 1) log("User opted to use direct paths.", 1)
utils.settings('useDirectPaths', value="1") settings('useDirectPaths', value="1")
# ask for credentials # ask for credentials
credentials = dialog.yesno( credentials = dialog.yesno(
@ -138,15 +131,15 @@ class InitialSetup():
"during the initial scan of your content if Kodi can't " "during the initial scan of your content if Kodi can't "
"locate your content.")) "locate your content."))
if credentials: if credentials:
self.logMsg("Presenting network credentials dialog.", 1) log("Presenting network credentials dialog.", 1)
utils.passwordsXML() passwordsXML()
musicDisabled = dialog.yesno( musicDisabled = dialog.yesno(
heading="Music Library", heading="Music Library",
line1="Disable Emby music library?") line1="Disable Emby music library?")
if musicDisabled: if musicDisabled:
self.logMsg("User opted to disable Emby music library.", 1) log("User opted to disable Emby music library.", 1)
utils.settings('enableMusic', value="false") settings('enableMusic', value="false")
else: else:
# Only prompt if the user didn't select direct paths for videos # Only prompt if the user didn't select direct paths for videos
if not directPaths: if not directPaths:
@ -157,12 +150,12 @@ class InitialSetup():
"this option only if you plan on listening " "this option only if you plan on listening "
"to music outside of your network.")) "to music outside of your network."))
if musicAccess: if musicAccess:
self.logMsg("User opted to direct stream music.", 1) log("User opted to direct stream music.", 1)
utils.settings('streamMusic', value="true") settings('streamMusic', value="true")
def getServerDetails(self): def getServerDetails(self):
self.logMsg("Getting Server Details from Network", 1) log("Getting Server Details from Network", 1)
MULTI_GROUP = ("<broadcast>", 7359) MULTI_GROUP = ("<broadcast>", 7359)
MESSAGE = "who is EmbyServer?" MESSAGE = "who is EmbyServer?"
@ -176,15 +169,15 @@ class InitialSetup():
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1) sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
sock.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1) sock.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1)
self.logMsg("MultiGroup : %s" % str(MULTI_GROUP), 2) log("MultiGroup : %s" % str(MULTI_GROUP), 2)
self.logMsg("Sending UDP Data: %s" % MESSAGE, 2) log("Sending UDP Data: %s" % MESSAGE, 2)
sock.sendto(MESSAGE, MULTI_GROUP) sock.sendto(MESSAGE, MULTI_GROUP)
try: try:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
self.logMsg("Received Response: %s" % data) log("Received Response: %s" % data)
except: except:
self.logMsg("No UDP Response") log("No UDP Response")
return None return None
else: else:
# Get the address # Get the address

View file

@ -7,7 +7,7 @@ import xbmc
import api import api
import artwork import artwork
import clientinfo import clientinfo
import utils from utils import Logging
################################################################################################## ##################################################################################################
@ -19,16 +19,14 @@ class Kodidb_Functions():
def __init__(self, cursor): def __init__(self, cursor):
global log
log = Logging(self.__class__.__name__).log
self.cursor = cursor self.cursor = cursor
self.clientInfo = clientinfo.ClientInfo() self.clientInfo = clientinfo.ClientInfo()
self.addonName = self.clientInfo.getAddonName() self.addonName = self.clientInfo.getAddonName()
self.artwork = artwork.Artwork() self.artwork = artwork.Artwork()
def logMsg(self, msg, lvl=1):
className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
def addPath(self, path): def addPath(self, path):
@ -153,7 +151,7 @@ class Kodidb_Functions():
query = "INSERT INTO country(country_id, name) values(?, ?)" query = "INSERT INTO country(country_id, name) values(?, ?)"
self.cursor.execute(query, (country_id, country)) self.cursor.execute(query, (country_id, country))
self.logMsg("Add country to media, processing: %s" % country, 2) log("Add country to media, processing: %s" % country, 2)
finally: # Assign country to content finally: # Assign country to content
query = ( query = (
@ -187,7 +185,7 @@ class Kodidb_Functions():
query = "INSERT INTO country(idCountry, strCountry) values(?, ?)" query = "INSERT INTO country(idCountry, strCountry) values(?, ?)"
self.cursor.execute(query, (idCountry, country)) self.cursor.execute(query, (idCountry, country))
self.logMsg("Add country to media, processing: %s" % country, 2) log("Add country to media, processing: %s" % country, 2)
finally: finally:
# Only movies have a country field # Only movies have a country field
@ -232,7 +230,7 @@ class Kodidb_Functions():
query = "INSERT INTO actor(actor_id, name) values(?, ?)" query = "INSERT INTO actor(actor_id, name) values(?, ?)"
self.cursor.execute(query, (actorid, name)) self.cursor.execute(query, (actorid, name))
self.logMsg("Add people to media, processing: %s" % name, 2) log("Add people to media, processing: %s" % name, 2)
finally: finally:
# Link person to content # Link person to content
@ -302,7 +300,7 @@ class Kodidb_Functions():
query = "INSERT INTO actors(idActor, strActor) values(?, ?)" query = "INSERT INTO actors(idActor, strActor) values(?, ?)"
self.cursor.execute(query, (actorid, name)) self.cursor.execute(query, (actorid, name))
self.logMsg("Add people to media, processing: %s" % name, 2) log("Add people to media, processing: %s" % name, 2)
finally: finally:
# Link person to content # Link person to content
@ -462,7 +460,7 @@ class Kodidb_Functions():
query = "INSERT INTO genre(genre_id, name) values(?, ?)" query = "INSERT INTO genre(genre_id, name) values(?, ?)"
self.cursor.execute(query, (genre_id, genre)) self.cursor.execute(query, (genre_id, genre))
self.logMsg("Add Genres to media, processing: %s" % genre, 2) log("Add Genres to media, processing: %s" % genre, 2)
finally: finally:
# Assign genre to item # Assign genre to item
@ -507,7 +505,7 @@ class Kodidb_Functions():
query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)" query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)"
self.cursor.execute(query, (idGenre, genre)) self.cursor.execute(query, (idGenre, genre))
self.logMsg("Add Genres to media, processing: %s" % genre, 2) log("Add Genres to media, processing: %s" % genre, 2)
finally: finally:
# Assign genre to item # Assign genre to item
@ -566,7 +564,7 @@ class Kodidb_Functions():
query = "INSERT INTO studio(studio_id, name) values(?, ?)" query = "INSERT INTO studio(studio_id, name) values(?, ?)"
self.cursor.execute(query, (studioid, studio)) self.cursor.execute(query, (studioid, studio))
self.logMsg("Add Studios to media, processing: %s" % studio, 2) log("Add Studios to media, processing: %s" % studio, 2)
finally: # Assign studio to item finally: # Assign studio to item
query = ( query = (
@ -597,7 +595,7 @@ class Kodidb_Functions():
query = "INSERT INTO studio(idstudio, strstudio) values(?, ?)" query = "INSERT INTO studio(idstudio, strstudio) values(?, ?)"
self.cursor.execute(query, (studioid, studio)) self.cursor.execute(query, (studioid, studio))
self.logMsg("Add Studios to media, processing: %s" % studio, 2) log("Add Studios to media, processing: %s" % studio, 2)
finally: # Assign studio to item finally: # Assign studio to item
if "movie" in mediatype: if "movie" in mediatype:
@ -728,7 +726,7 @@ class Kodidb_Functions():
self.cursor.execute(query, (kodiid, mediatype)) self.cursor.execute(query, (kodiid, mediatype))
# Add tags # Add tags
self.logMsg("Adding Tags: %s" % tags, 2) log("Adding Tags: %s" % tags, 2)
for tag in tags: for tag in tags:
self.addTag(kodiid, tag, mediatype) self.addTag(kodiid, tag, mediatype)
@ -750,7 +748,7 @@ class Kodidb_Functions():
except TypeError: except TypeError:
# Create the tag, because it does not exist # Create the tag, because it does not exist
tag_id = self.createTag(tag) tag_id = self.createTag(tag)
self.logMsg("Adding tag: %s" % tag, 2) log("Adding tag: %s" % tag, 2)
finally: finally:
# Assign tag to item # Assign tag to item
@ -779,7 +777,7 @@ class Kodidb_Functions():
except TypeError: except TypeError:
# Create the tag # Create the tag
tag_id = self.createTag(tag) tag_id = self.createTag(tag)
self.logMsg("Adding tag: %s" % tag, 2) log("Adding tag: %s" % tag, 2)
finally: finally:
# Assign tag to item # Assign tag to item
@ -815,7 +813,7 @@ class Kodidb_Functions():
query = "INSERT INTO tag(tag_id, name) values(?, ?)" query = "INSERT INTO tag(tag_id, name) values(?, ?)"
self.cursor.execute(query, (tag_id, name)) self.cursor.execute(query, (tag_id, name))
self.logMsg("Create tag_id: %s name: %s" % (tag_id, name), 2) log("Create tag_id: %s name: %s" % (tag_id, name), 2)
else: else:
# Kodi Helix # Kodi Helix
query = ' '.join(( query = ' '.join((
@ -835,13 +833,13 @@ class Kodidb_Functions():
query = "INSERT INTO tag(idTag, strTag) values(?, ?)" query = "INSERT INTO tag(idTag, strTag) values(?, ?)"
self.cursor.execute(query, (tag_id, name)) self.cursor.execute(query, (tag_id, name))
self.logMsg("Create idTag: %s name: %s" % (tag_id, name), 2) log("Create idTag: %s name: %s" % (tag_id, name), 2)
return tag_id return tag_id
def updateTag(self, oldtag, newtag, kodiid, mediatype): def updateTag(self, oldtag, newtag, kodiid, mediatype):
self.logMsg("Updating: %s with %s for %s: %s" % (oldtag, newtag, mediatype, kodiid), 2) log("Updating: %s with %s for %s: %s" % (oldtag, newtag, mediatype, kodiid), 2)
if self.kodiversion in (15, 16, 17): if self.kodiversion in (15, 16, 17):
# Kodi Isengard, Jarvis, Krypton # Kodi Isengard, Jarvis, Krypton
@ -858,7 +856,7 @@ class Kodidb_Functions():
except Exception as e: except Exception as e:
# The new tag we are going to apply already exists for this item # The new tag we are going to apply already exists for this item
# delete current tag instead # delete current tag instead
self.logMsg("Exception: %s" % e, 1) log("Exception: %s" % e, 1)
query = ' '.join(( query = ' '.join((
"DELETE FROM tag_link", "DELETE FROM tag_link",
@ -882,7 +880,7 @@ class Kodidb_Functions():
except Exception as e: except Exception as e:
# The new tag we are going to apply already exists for this item # The new tag we are going to apply already exists for this item
# delete current tag instead # delete current tag instead
self.logMsg("Exception: %s" % e, 1) log("Exception: %s" % e, 1)
query = ' '.join(( query = ' '.join((
"DELETE FROM taglinks", "DELETE FROM taglinks",
@ -943,7 +941,7 @@ class Kodidb_Functions():
def createBoxset(self, boxsetname): def createBoxset(self, boxsetname):
self.logMsg("Adding boxset: %s" % boxsetname, 2) log("Adding boxset: %s" % boxsetname, 2)
query = ' '.join(( query = ' '.join((
"SELECT idSet", "SELECT idSet",

View file

@ -11,7 +11,7 @@ import clientinfo
import downloadutils import downloadutils
import embydb_functions as embydb import embydb_functions as embydb
import playbackutils as pbutils import playbackutils as pbutils
import utils from utils import Logging, window, settings, kodiSQL
################################################################################################# #################################################################################################
@ -21,27 +21,25 @@ class KodiMonitor(xbmc.Monitor):
def __init__(self): def __init__(self):
global log
log = Logging(self.__class__.__name__).log
self.clientInfo = clientinfo.ClientInfo() self.clientInfo = clientinfo.ClientInfo()
self.addonName = self.clientInfo.getAddonName() self.addonName = self.clientInfo.getAddonName()
self.doUtils = downloadutils.DownloadUtils() self.doUtils = downloadutils.DownloadUtils()
self.logMsg("Kodi monitor started.", 1) log("Kodi monitor started.", 1)
def logMsg(self, msg, lvl=1):
self.className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
def onScanStarted(self, library): def onScanStarted(self, library):
self.logMsg("Kodi library scan %s running." % library, 2) log("Kodi library scan %s running." % library, 2)
if library == "video": if library == "video":
utils.window('emby_kodiScan', value="true") window('emby_kodiScan', value="true")
def onScanFinished(self, library): def onScanFinished(self, library):
self.logMsg("Kodi library scan %s finished." % library, 2) log("Kodi library scan %s finished." % library, 2)
if library == "video": if library == "video":
utils.window('emby_kodiScan', clear=True) window('emby_kodiScan', clear=True)
def onSettingsChanged(self): def onSettingsChanged(self):
# Monitor emby settings # Monitor emby settings
@ -50,7 +48,7 @@ class KodiMonitor(xbmc.Monitor):
'''currentPath = utils.settings('useDirectPaths') '''currentPath = utils.settings('useDirectPaths')
if utils.window('emby_pluginpath') != currentPath: if utils.window('emby_pluginpath') != currentPath:
# Plugin path value changed. Offer to reset # Plugin path value changed. Offer to reset
self.logMsg("Changed to playback mode detected", 1) log("Changed to playback mode detected", 1)
utils.window('emby_pluginpath', value=currentPath) utils.window('emby_pluginpath', value=currentPath)
resp = xbmcgui.Dialog().yesno( resp = xbmcgui.Dialog().yesno(
heading="Playback mode change detected", heading="Playback mode change detected",
@ -61,17 +59,17 @@ class KodiMonitor(xbmc.Monitor):
if resp: if resp:
utils.reset()''' utils.reset()'''
currentLog = utils.settings('logLevel') currentLog = settings('logLevel')
if utils.window('emby_logLevel') != currentLog: if window('emby_logLevel') != currentLog:
# The log level changed, set new prop # The log level changed, set new prop
self.logMsg("New log level: %s" % currentLog, 1) log("New log level: %s" % currentLog, 1)
utils.window('emby_logLevel', value=currentLog) window('emby_logLevel', value=currentLog)
def onNotification(self, sender, method, data): def onNotification(self, sender, method, data):
doUtils = self.doUtils doUtils = self.doUtils
if method not in ("Playlist.OnAdd"): if method not in ("Playlist.OnAdd"):
self.logMsg("Method: %s Data: %s" % (method, data), 1) log("Method: %s Data: %s" % (method, data), 1)
if data: if data:
data = json.loads(data,'utf-8') data = json.loads(data,'utf-8')
@ -84,23 +82,23 @@ class KodiMonitor(xbmc.Monitor):
kodiid = item['id'] kodiid = item['id']
item_type = item['type'] item_type = item['type']
except (KeyError, TypeError): except (KeyError, TypeError):
self.logMsg("Item is invalid for playstate update.", 1) log("Item is invalid for playstate update.", 1)
else: else:
if ((utils.settings('useDirectPaths') == "1" and not item_type == "song") or if ((settings('useDirectPaths') == "1" and not item_type == "song") or
(item_type == "song" and utils.settings('enableMusic') == "true")): (item_type == "song" and settings('enableMusic') == "true")):
# Set up properties for player # Set up properties for player
embyconn = utils.kodiSQL('emby') embyconn = kodiSQL('emby')
embycursor = embyconn.cursor() embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type) emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
try: try:
itemid = emby_dbitem[0] itemid = emby_dbitem[0]
except TypeError: except TypeError:
self.logMsg("No kodiid returned.", 1) log("No kodiid returned.", 1)
else: else:
url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid
result = doUtils.downloadUrl(url) result = doUtils.downloadUrl(url)
self.logMsg("Item: %s" % result, 2) log("Item: %s" % result, 2)
playurl = None playurl = None
count = 0 count = 0
@ -114,12 +112,10 @@ class KodiMonitor(xbmc.Monitor):
listItem = xbmcgui.ListItem() listItem = xbmcgui.ListItem()
playback = pbutils.PlaybackUtils(result) playback = pbutils.PlaybackUtils(result)
if item_type == "song" and utils.settings('streamMusic') == "true": if item_type == "song" and settings('streamMusic') == "true":
utils.window('emby_%s.playmethod' % playurl, window('emby_%s.playmethod' % playurl, value="DirectStream")
value="DirectStream")
else: else:
utils.window('emby_%s.playmethod' % playurl, window('emby_%s.playmethod' % playurl, value="DirectPlay")
value="DirectPlay")
# Set properties for player.py # Set properties for player.py
playback.setProperties(playurl, listItem) playback.setProperties(playurl, listItem)
finally: finally:
@ -134,31 +130,31 @@ class KodiMonitor(xbmc.Monitor):
kodiid = item['id'] kodiid = item['id']
item_type = item['type'] item_type = item['type']
except (KeyError, TypeError): except (KeyError, TypeError):
self.logMsg("Item is invalid for playstate update.", 1) log("Item is invalid for playstate update.", 1)
else: else:
# Send notification to the server. # Send notification to the server.
embyconn = utils.kodiSQL('emby') embyconn = kodiSQL('emby')
embycursor = embyconn.cursor() embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type) emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
try: try:
itemid = emby_dbitem[0] itemid = emby_dbitem[0]
except TypeError: except TypeError:
self.logMsg("Could not find itemid in emby database.", 1) log("Could not find itemid in emby database.", 1)
else: else:
# Stop from manually marking as watched unwatched, with actual playback. # Stop from manually marking as watched unwatched, with actual playback.
if utils.window('emby_skipWatched%s' % itemid) == "true": if window('emby_skipWatched%s' % itemid) == "true":
# property is set in player.py # property is set in player.py
utils.window('emby_skipWatched%s' % itemid, clear=True) window('emby_skipWatched%s' % itemid, clear=True)
else: else:
# notify the server # notify the server
url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % itemid url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % itemid
if playcount != 0: if playcount != 0:
doUtils.downloadUrl(url, action_type="POST") doUtils.downloadUrl(url, action_type="POST")
self.logMsg("Mark as watched for itemid: %s" % itemid, 1) log("Mark as watched for itemid: %s" % itemid, 1)
else: else:
doUtils.downloadUrl(url, action_type="DELETE") doUtils.downloadUrl(url, action_type="DELETE")
self.logMsg("Mark as unwatched for itemid: %s" % itemid, 1) log("Mark as unwatched for itemid: %s" % itemid, 1)
finally: finally:
embycursor.close() embycursor.close()
@ -172,7 +168,7 @@ class KodiMonitor(xbmc.Monitor):
kodiid = data['id'] kodiid = data['id']
type = data['type'] type = data['type']
except (KeyError, TypeError): except (KeyError, TypeError):
self.logMsg("Item is invalid for emby deletion.", 1) log("Item is invalid for emby deletion.", 1)
else: else:
# Send the delete action to the server. # Send the delete action to the server.
embyconn = utils.kodiSQL('emby') embyconn = utils.kodiSQL('emby')
@ -182,19 +178,19 @@ class KodiMonitor(xbmc.Monitor):
try: try:
itemid = emby_dbitem[0] itemid = emby_dbitem[0]
except TypeError: except TypeError:
self.logMsg("Could not find itemid in emby database.", 1) log("Could not find itemid in emby database.", 1)
else: else:
if utils.settings('skipContextMenu') != "true": if utils.settings('skipContextMenu') != "true":
resp = xbmcgui.Dialog().yesno( resp = xbmcgui.Dialog().yesno(
heading="Confirm delete", heading="Confirm delete",
line1="Delete file on Emby Server?") line1="Delete file on Emby Server?")
if not resp: if not resp:
self.logMsg("User skipped deletion.", 1) log("User skipped deletion.", 1)
embycursor.close() embycursor.close()
return return
url = "{server}/emby/Items/%s?format=json" % itemid url = "{server}/emby/Items/%s?format=json" % itemid
self.logMsg("Deleting request: %s" % itemid) log("Deleting request: %s" % itemid)
doUtils.downloadUrl(url, action_type="DELETE") doUtils.downloadUrl(url, action_type="DELETE")
finally: finally:
embycursor.close()''' embycursor.close()'''
@ -203,13 +199,13 @@ class KodiMonitor(xbmc.Monitor):
elif method == "System.OnWake": elif method == "System.OnWake":
# Allow network to wake up # Allow network to wake up
xbmc.sleep(10000) xbmc.sleep(10000)
utils.window('emby_onWake', value="true") window('emby_onWake', value="true")
elif method == "GUI.OnScreensaverDeactivated": elif method == "GUI.OnScreensaverDeactivated":
if utils.settings('dbSyncScreensaver') == "true": if settings('dbSyncScreensaver') == "true":
xbmc.sleep(5000); xbmc.sleep(5000);
utils.window('emby_onWake', value="true") window('emby_onWake', value="true")
elif method == "Playlist.OnClear": elif method == "Playlist.OnClear":

View file

@ -20,6 +20,7 @@ import kodidb_functions as kodidb
import read_embyserver as embyserver import read_embyserver as embyserver
import userclient import userclient
import videonodes import videonodes
from utils import Logging, window, settings, language as lang
################################################################################################## ##################################################################################################
@ -42,6 +43,9 @@ class LibrarySync(threading.Thread):
def __init__(self): def __init__(self):
global log
log = Logging(self.__class__.__name__).log
self.__dict__ = self._shared_state self.__dict__ = self._shared_state
self.monitor = xbmc.Monitor() self.monitor = xbmc.Monitor()
@ -54,26 +58,20 @@ class LibrarySync(threading.Thread):
threading.Thread.__init__(self) threading.Thread.__init__(self)
def logMsg(self, msg, lvl=1):
className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
def progressDialog(self, title, forced=False): def progressDialog(self, title, forced=False):
dialog = None dialog = None
if utils.settings('dbSyncIndicator') == "true" or forced: if settings('dbSyncIndicator') == "true" or forced:
dialog = xbmcgui.DialogProgressBG() dialog = xbmcgui.DialogProgressBG()
dialog.create("Emby for Kodi", title) dialog.create("Emby for Kodi", title)
self.logMsg("Show progress dialog: %s" % title, 2) log("Show progress dialog: %s" % title, 2)
return dialog return dialog
def startSync(self): def startSync(self):
settings = utils.settings
# Run at start up - optional to use the server plugin # Run at start up - optional to use the server plugin
if settings('SyncInstallRunDone') == "true": if settings('SyncInstallRunDone') == "true":
@ -88,7 +86,7 @@ class LibrarySync(threading.Thread):
for plugin in result: for plugin in result:
if plugin['Name'] == "Emby.Kodi Sync Queue": if plugin['Name'] == "Emby.Kodi Sync Queue":
self.logMsg("Found server plugin.", 2) log("Found server plugin.", 2)
completed = self.fastSync() completed = self.fastSync()
break break
@ -103,37 +101,31 @@ class LibrarySync(threading.Thread):
def fastSync(self): def fastSync(self):
lastSync = utils.settings('LastIncrementalSync') lastSync = settings('LastIncrementalSync')
if not lastSync: if not lastSync:
lastSync = "2010-01-01T00:00:00Z" lastSync = "2010-01-01T00:00:00Z"
lastSyncTime = utils.convertdate(lastSync) lastSyncTime = utils.convertDate(lastSync)
self.logMsg("Last sync run: %s" % lastSyncTime, 1) log("Last sync run: %s" % lastSyncTime, 1)
# get server RetentionDateTime # get server RetentionDateTime
result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json") result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json")
retention_time = "2010-01-01T00:00:00Z"
if result and result.get('RetentionDateTime'):
retention_time = result['RetentionDateTime']
#Try/except equivalent
'''
try: try:
retention_time = result['RetentionDateTime'] retention_time = result['RetentionDateTime']
except (TypeError, KeyError): except (TypeError, KeyError):
retention_time = "2010-01-01T00:00:00Z" retention_time = "2010-01-01T00:00:00Z"
'''
retention_time = utils.convertdate(retention_time) retention_time = utils.convertDate(retention_time)
self.logMsg("RetentionDateTime: %s" % retention_time, 1) log("RetentionDateTime: %s" % retention_time, 1)
# if last sync before retention time do a full sync # if last sync before retention time do a full sync
if retention_time > lastSyncTime: if retention_time > lastSyncTime:
self.logMsg("Fast sync server retention insufficient, fall back to full sync", 1) log("Fast sync server retention insufficient, fall back to full sync", 1)
return False return False
params = {'LastUpdateDT': lastSync} params = {'LastUpdateDT': lastSync}
result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/{UserId}/GetItems?format=json", parameters=params) url = "{server}/emby/Emby.Kodi.SyncQueue/{UserId}/GetItems?format=json"
result = self.doUtils(url, parameters=params)
try: try:
processlist = { processlist = {
@ -145,11 +137,11 @@ class LibrarySync(threading.Thread):
} }
except (KeyError, TypeError): except (KeyError, TypeError):
self.logMsg("Failed to retrieve latest updates using fast sync.", 1) log("Failed to retrieve latest updates using fast sync.", 1)
return False return False
else: else:
self.logMsg("Fast sync changes: %s" % result, 1) log("Fast sync changes: %s" % result, 1)
for action in processlist: for action in processlist:
self.triage_items(action, processlist[action]) self.triage_items(action, processlist[action])
@ -163,60 +155,55 @@ class LibrarySync(threading.Thread):
result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json") result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json")
try: # datetime fails when used more than once, TypeError try: # datetime fails when used more than once, TypeError
server_time = result['ServerDateTime'] server_time = result['ServerDateTime']
server_time = utils.convertdate(server_time) server_time = utils.convertDate(server_time)
except Exception as e: except Exception as e:
# If the server plugin is not installed or an error happened. # If the server plugin is not installed or an error happened.
self.logMsg("An exception occurred: %s" % e, 1) log("An exception occurred: %s" % e, 1)
time_now = datetime.utcnow()-timedelta(minutes=overlap) time_now = datetime.utcnow()-timedelta(minutes=overlap)
lastSync = time_now.strftime('%Y-%m-%dT%H:%M:%SZ') lastSync = time_now.strftime('%Y-%m-%dT%H:%M:%SZ')
self.logMsg("New sync time: client time -%s min: %s" % (overlap, lastSync), 1) log("New sync time: client time -%s min: %s" % (overlap, lastSync), 1)
else: else:
lastSync = (server_time - timedelta(minutes=overlap)).strftime('%Y-%m-%dT%H:%M:%SZ') lastSync = (server_time - timedelta(minutes=overlap)).strftime('%Y-%m-%dT%H:%M:%SZ')
self.logMsg("New sync time: server time -%s min: %s" % (overlap, lastSync), 1) log("New sync time: server time -%s min: %s" % (overlap, lastSync), 1)
finally: finally:
utils.settings('LastIncrementalSync', value=lastSync) settings('LastIncrementalSync', value=lastSync)
def shouldStop(self): def shouldStop(self):
# Checkpoint during the syncing process # Checkpoint during the syncing process
if self.monitor.abortRequested(): if self.monitor.abortRequested():
return True return True
elif utils.window('emby_shouldStop') == "true": elif window('emby_shouldStop') == "true":
return True return True
else: # Keep going else: # Keep going
return False return False
def dbCommit(self, connection): def dbCommit(self, connection):
window = utils.window
# Central commit, verifies if Kodi database update is running # Central commit, verifies if Kodi database update is running
kodidb_scan = window('emby_kodiScan') == "true" kodidb_scan = window('emby_kodiScan') == "true"
while kodidb_scan: while kodidb_scan:
self.logMsg("Kodi scan is running. Waiting...", 1) log("Kodi scan is running. Waiting...", 1)
kodidb_scan = window('emby_kodiScan') == "true" kodidb_scan = window('emby_kodiScan') == "true"
if self.shouldStop(): if self.shouldStop():
self.logMsg("Commit unsuccessful. Sync terminated.", 1) log("Commit unsuccessful. Sync terminated.", 1)
break break
if self.monitor.waitForAbort(1): if self.monitor.waitForAbort(1):
# Abort was requested while waiting. We should exit # Abort was requested while waiting. We should exit
self.logMsg("Commit unsuccessful.", 1) log("Commit unsuccessful.", 1)
break break
else: else:
connection.commit() connection.commit()
self.logMsg("Commit successful.", 1) log("Commit successful.", 1)
def fullSync(self, manualrun=False, repair=False, forceddialog=False): def fullSync(self, manualrun=False, repair=False, forceddialog=False):
window = utils.window
settings = utils.settings
# Only run once when first setting up. Can be run manually. # Only run once when first setting up. Can be run manually.
music_enabled = utils.settings('enableMusic') == "true" music_enabled = settings('enableMusic') == "true"
xbmc.executebuiltin('InhibitIdleShutdown(true)') xbmc.executebuiltin('InhibitIdleShutdown(true)')
screensaver = utils.getScreensaver() screensaver = utils.getScreensaver()
@ -284,7 +271,7 @@ class LibrarySync(threading.Thread):
self.dbCommit(kodiconn) self.dbCommit(kodiconn)
embyconn.commit() embyconn.commit()
elapsedTime = datetime.now() - startTime elapsedTime = datetime.now() - startTime
self.logMsg("SyncDatabase (finished %s in: %s)" log("SyncDatabase (finished %s in: %s)"
% (itemtype, str(elapsedTime).split('.')[0]), 1) % (itemtype, str(elapsedTime).split('.')[0]), 1)
else: else:
# Close the Kodi cursor # Close the Kodi cursor
@ -312,7 +299,7 @@ class LibrarySync(threading.Thread):
musicconn.commit() musicconn.commit()
embyconn.commit() embyconn.commit()
elapsedTime = datetime.now() - startTime elapsedTime = datetime.now() - startTime
self.logMsg("SyncDatabase (finished music in: %s)" log("SyncDatabase (finished music in: %s)"
% (str(elapsedTime).split('.')[0]), 1) % (str(elapsedTime).split('.')[0]), 1)
musiccursor.close() musiccursor.close()
@ -335,7 +322,7 @@ class LibrarySync(threading.Thread):
xbmcgui.Dialog().notification( xbmcgui.Dialog().notification(
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s %s" % message="%s %s %s" %
(message, utils.language(33025), str(elapsedtotal).split('.')[0]), (message, lang(33025), str(elapsedtotal).split('.')[0]),
icon="special://home/addons/plugin.video.emby/icon.png", icon="special://home/addons/plugin.video.emby/icon.png",
sound=False) sound=False)
return True return True
@ -378,7 +365,7 @@ class LibrarySync(threading.Thread):
if view['type'] == "mixed": if view['type'] == "mixed":
sorted_views.append(view['name']) sorted_views.append(view['name'])
sorted_views.append(view['name']) sorted_views.append(view['name'])
self.logMsg("Sorted views: %s" % sorted_views, 1) log("Sorted views: %s" % sorted_views, 1)
# total nodes for window properties # total nodes for window properties
self.vnodes.clearProperties() self.vnodes.clearProperties()
@ -415,7 +402,8 @@ class LibrarySync(threading.Thread):
'Limit': 1, 'Limit': 1,
'IncludeItemTypes': emby_mediatypes[mediatype] 'IncludeItemTypes': emby_mediatypes[mediatype]
} # Get one item from server using the folderid } # Get one item from server using the folderid
result = self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params) url = "{server}/emby/Users/{UserId}/Items?format=json"
result = self.doUtils(url, parameters=params)
try: try:
verifyitem = result['Items'][0]['Id'] verifyitem = result['Items'][0]['Id']
except (TypeError, IndexError): except (TypeError, IndexError):
@ -430,14 +418,14 @@ class LibrarySync(threading.Thread):
# Take the userview, and validate the item belong to the view # Take the userview, and validate the item belong to the view
if self.emby.verifyView(grouped_view['Id'], verifyitem): if self.emby.verifyView(grouped_view['Id'], verifyitem):
# Take the name of the userview # Take the name of the userview
self.logMsg("Found corresponding view: %s %s" log("Found corresponding view: %s %s"
% (grouped_view['Name'], grouped_view['Id']), 1) % (grouped_view['Name'], grouped_view['Id']), 1)
foldername = grouped_view['Name'] foldername = grouped_view['Name']
break break
else: else:
# Unable to find a match, add the name to our sorted_view list # Unable to find a match, add the name to our sorted_view list
sorted_views.append(foldername) sorted_views.append(foldername)
self.logMsg("Couldn't find corresponding grouped view: %s" % sorted_views, 1) log("Couldn't find corresponding grouped view: %s" % sorted_views, 1)
# Failsafe # Failsafe
try: try:
@ -453,7 +441,7 @@ class LibrarySync(threading.Thread):
current_tagid = view[2] current_tagid = view[2]
except TypeError: except TypeError:
self.logMsg("Creating viewid: %s in Emby database." % folderid, 1) log("Creating viewid: %s in Emby database." % folderid, 1)
tagid = kodi_db.createTag(foldername) tagid = kodi_db.createTag(foldername)
# Create playlist for the video library # Create playlist for the video library
if (foldername not in playlists and if (foldername not in playlists and
@ -472,7 +460,7 @@ class LibrarySync(threading.Thread):
emby_db.addView(folderid, foldername, viewtype, tagid) emby_db.addView(folderid, foldername, viewtype, tagid)
else: else:
self.logMsg(' '.join(( log(' '.join((
"Found viewid: %s" % folderid, "Found viewid: %s" % folderid,
"viewname: %s" % current_viewname, "viewname: %s" % current_viewname,
@ -488,7 +476,7 @@ class LibrarySync(threading.Thread):
# View was modified, update with latest info # View was modified, update with latest info
if current_viewname != foldername: if current_viewname != foldername:
self.logMsg("viewid: %s new viewname: %s" % (folderid, foldername), 1) log("viewid: %s new viewname: %s" % (folderid, foldername), 1)
tagid = kodi_db.createTag(foldername) tagid = kodi_db.createTag(foldername)
# Update view with new info # Update view with new info
@ -556,20 +544,19 @@ class LibrarySync(threading.Thread):
utils.window('Emby.nodes.total', str(totalnodes)) utils.window('Emby.nodes.total', str(totalnodes))
# Remove any old referenced views # Remove any old referenced views
self.logMsg("Removing views: %s" % current_views, 1) log("Removing views: %s" % current_views, 1)
for view in current_views: for view in current_views:
emby_db.removeView(view) emby_db.removeView(view)
def movies(self, embycursor, kodicursor, pdialog): def movies(self, embycursor, kodicursor, pdialog):
lang = utils.language
# Get movies from emby # Get movies from emby
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
movies = itemtypes.Movies(embycursor, kodicursor) movies = itemtypes.Movies(embycursor, kodicursor)
views = emby_db.getView_byType('movies') views = emby_db.getView_byType('movies')
views += emby_db.getView_byType('mixed') views += emby_db.getView_byType('mixed')
self.logMsg("Media folders: %s" % views, 1) log("Media folders: %s" % views, 1)
##### PROCESS MOVIES ##### ##### PROCESS MOVIES #####
for view in views: for view in views:
@ -604,7 +591,7 @@ class LibrarySync(threading.Thread):
count += 1 count += 1
movies.add_update(embymovie, view['name'], view['id']) movies.add_update(embymovie, view['name'], view['id'])
else: else:
self.logMsg("Movies finished.", 2) log("Movies finished.", 2)
##### PROCESS BOXSETS ##### ##### PROCESS BOXSETS #####
@ -631,7 +618,7 @@ class LibrarySync(threading.Thread):
count += 1 count += 1
movies.add_updateBoxset(boxset) movies.add_updateBoxset(boxset)
else: else:
self.logMsg("Boxsets finished.", 2) log("Boxsets finished.", 2)
return True return True
@ -642,7 +629,7 @@ class LibrarySync(threading.Thread):
mvideos = itemtypes.MusicVideos(embycursor, kodicursor) mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
views = emby_db.getView_byType('musicvideos') views = emby_db.getView_byType('musicvideos')
self.logMsg("Media folders: %s" % views, 1) log("Media folders: %s" % views, 1)
for view in views: for view in views:
@ -656,7 +643,7 @@ class LibrarySync(threading.Thread):
if pdialog: if pdialog:
pdialog.update( pdialog.update(
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (utils.language(33019), viewName)) message="%s %s..." % (lang(33019), viewName))
# Initial or repair sync # Initial or repair sync
all_embymvideos = self.emby.getMusicVideos(viewId, dialog=pdialog) all_embymvideos = self.emby.getMusicVideos(viewId, dialog=pdialog)
@ -679,7 +666,7 @@ class LibrarySync(threading.Thread):
count += 1 count += 1
mvideos.add_update(embymvideo, viewName, viewId) mvideos.add_update(embymvideo, viewName, viewId)
else: else:
self.logMsg("MusicVideos finished.", 2) log("MusicVideos finished.", 2)
return True return True
@ -691,7 +678,7 @@ class LibrarySync(threading.Thread):
views = emby_db.getView_byType('tvshows') views = emby_db.getView_byType('tvshows')
views += emby_db.getView_byType('mixed') views += emby_db.getView_byType('mixed')
self.logMsg("Media folders: %s" % views, 1) log("Media folders: %s" % views, 1)
for view in views: for view in views:
@ -702,7 +689,7 @@ class LibrarySync(threading.Thread):
if pdialog: if pdialog:
pdialog.update( pdialog.update(
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (utils.language(33020), view['name'])) message="%s %s..." % (lang(33020), view['name']))
all_embytvshows = self.emby.getShows(view['id'], dialog=pdialog) all_embytvshows = self.emby.getShows(view['id'], dialog=pdialog)
total = all_embytvshows['TotalRecordCount'] total = all_embytvshows['TotalRecordCount']
@ -737,7 +724,7 @@ class LibrarySync(threading.Thread):
pdialog.update(percentage, message="%s - %s" % (title, episodetitle)) pdialog.update(percentage, message="%s - %s" % (title, episodetitle))
tvshows.add_updateEpisode(episode) tvshows.add_updateEpisode(episode)
else: else:
self.logMsg("TVShows finished.", 2) log("TVShows finished.", 2)
return True return True
@ -757,7 +744,7 @@ class LibrarySync(threading.Thread):
if pdialog: if pdialog:
pdialog.update( pdialog.update(
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (utils.language(33021), itemtype)) message="%s %s..." % (lang(33021), itemtype))
all_embyitems = process[itemtype][0](dialog=pdialog) all_embyitems = process[itemtype][0](dialog=pdialog)
total = all_embyitems['TotalRecordCount'] total = all_embyitems['TotalRecordCount']
@ -778,7 +765,7 @@ class LibrarySync(threading.Thread):
process[itemtype][1](embyitem) process[itemtype][1](embyitem)
else: else:
self.logMsg("%s finished." % itemtype, 2) log("%s finished." % itemtype, 2)
return True return True
@ -799,7 +786,7 @@ class LibrarySync(threading.Thread):
itemids.append(item['ItemId']) itemids.append(item['ItemId'])
items = itemids items = itemids
self.logMsg("Queue %s: %s" % (process, items), 1) log("Queue %s: %s" % (process, items), 1)
processlist[process].extend(items) processlist[process].extend(items)
def incrementalSync(self): def incrementalSync(self):
@ -833,7 +820,7 @@ class LibrarySync(threading.Thread):
} }
for process_type in ['added', 'update', 'userdata', 'remove']: for process_type in ['added', 'update', 'userdata', 'remove']:
if process[process_type] and utils.window('emby_kodiScan') != "true": if process[process_type] and window('emby_kodiScan') != "true":
listItems = list(process[process_type]) listItems = list(process[process_type])
del process[process_type][:] # Reset class list del process[process_type][:] # Reset class list
@ -871,7 +858,7 @@ class LibrarySync(threading.Thread):
if update_embydb: if update_embydb:
update_embydb = False update_embydb = False
self.logMsg("Updating emby database.", 1) log("Updating emby database.", 1)
embyconn.commit() embyconn.commit()
self.saveLastSync() self.saveLastSync()
@ -880,8 +867,8 @@ class LibrarySync(threading.Thread):
self.forceLibraryUpdate = False self.forceLibraryUpdate = False
self.dbCommit(kodiconn) self.dbCommit(kodiconn)
self.logMsg("Updating video library.", 1) log("Updating video library.", 1)
utils.window('emby_kodiScan', value="true") window('emby_kodiScan', value="true")
xbmc.executebuiltin('UpdateLibrary(video)') xbmc.executebuiltin('UpdateLibrary(video)')
if pDialog: if pDialog:
@ -893,7 +880,7 @@ class LibrarySync(threading.Thread):
def compareDBVersion(self, current, minimum): def compareDBVersion(self, current, minimum):
# It returns True is database is up to date. False otherwise. # It returns True is database is up to date. False otherwise.
self.logMsg("current: %s minimum: %s" % (current, minimum), 1) log("current: %s minimum: %s" % (current, minimum), 1)
currMajor, currMinor, currPatch = current.split(".") currMajor, currMinor, currPatch = current.split(".")
minMajor, minMinor, minPatch = minimum.split(".") minMajor, minMinor, minPatch = minimum.split(".")
@ -911,7 +898,7 @@ class LibrarySync(threading.Thread):
try: try:
self.run_internal() self.run_internal()
except Exception as e: except Exception as e:
utils.window('emby_dbScan', clear=True) window('emby_dbScan', clear=True)
xbmcgui.Dialog().ok( xbmcgui.Dialog().ok(
heading="Emby for Kodi", heading="Emby for Kodi",
line1=( line1=(
@ -922,14 +909,11 @@ class LibrarySync(threading.Thread):
def run_internal(self): def run_internal(self):
lang = utils.language
window = utils.window
settings = utils.settings
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
startupComplete = False startupComplete = False
self.logMsg("---===### Starting LibrarySync ###===---", 0) log("---===### Starting LibrarySync ###===---", 0)
while not self.monitor.abortRequested(): while not self.monitor.abortRequested():
@ -947,12 +931,12 @@ class LibrarySync(threading.Thread):
uptoDate = self.compareDBVersion(currentVersion, minVersion) uptoDate = self.compareDBVersion(currentVersion, minVersion)
if not uptoDate: if not uptoDate:
self.logMsg("Database version out of date: %s minimum version required: %s" log("Database version out of date: %s minimum version required: %s"
% (currentVersion, minVersion), 0) % (currentVersion, minVersion), 0)
resp = dialog.yesno("Emby for Kodi", lang(33022)) resp = dialog.yesno("Emby for Kodi", lang(33022))
if not resp: if not resp:
self.logMsg("Database version is out of date! USER IGNORED!", 0) log("Database version is out of date! USER IGNORED!", 0)
dialog.ok("Emby for Kodi", lang(33023)) dialog.ok("Emby for Kodi", lang(33023))
else: else:
utils.reset() utils.reset()
@ -967,7 +951,7 @@ class LibrarySync(threading.Thread):
videoDb = utils.getKodiVideoDBPath() videoDb = utils.getKodiVideoDBPath()
if not xbmcvfs.exists(videoDb): if not xbmcvfs.exists(videoDb):
# Database does not exists # Database does not exists
self.logMsg( log(
"The current Kodi version is incompatible " "The current Kodi version is incompatible "
"with the Emby for Kodi add-on. Please visit " "with the Emby for Kodi add-on. Please visit "
"https://github.com/MediaBrowser/Emby.Kodi/wiki " "https://github.com/MediaBrowser/Emby.Kodi/wiki "
@ -979,12 +963,12 @@ class LibrarySync(threading.Thread):
break break
# Run start up sync # Run start up sync
self.logMsg("Database version: %s" % settings('dbCreatedWithVersion'), 0) log("Database version: %s" % settings('dbCreatedWithVersion'), 0)
self.logMsg("SyncDatabase (started)", 1) log("SyncDatabase (started)", 1)
startTime = datetime.now() startTime = datetime.now()
librarySync = self.startSync() librarySync = self.startSync()
elapsedTime = datetime.now() - startTime elapsedTime = datetime.now() - startTime
self.logMsg("SyncDatabase (finished in: %s) %s" log("SyncDatabase (finished in: %s) %s"
% (str(elapsedTime).split('.')[0], librarySync), 1) % (str(elapsedTime).split('.')[0], librarySync), 1)
# Only try the initial sync once per kodi session regardless # Only try the initial sync once per kodi session regardless
# This will prevent an infinite loop in case something goes wrong. # This will prevent an infinite loop in case something goes wrong.
@ -999,32 +983,32 @@ class LibrarySync(threading.Thread):
# Set in kodimonitor.py # Set in kodimonitor.py
window('emby_onWake', clear=True) window('emby_onWake', clear=True)
if window('emby_syncRunning') != "true": if window('emby_syncRunning') != "true":
self.logMsg("SyncDatabase onWake (started)", 0) log("SyncDatabase onWake (started)", 0)
librarySync = self.startSync() librarySync = self.startSync()
self.logMsg("SyncDatabase onWake (finished) %s" % librarySync, 0) log("SyncDatabase onWake (finished) %s" % librarySync, 0)
if self.stop_thread: if self.stop_thread:
# Set in service.py # Set in service.py
self.logMsg("Service terminated thread.", 2) log("Service terminated thread.", 2)
break break
if self.monitor.waitForAbort(1): if self.monitor.waitForAbort(1):
# Abort was requested while waiting. We should exit # Abort was requested while waiting. We should exit
break break
self.logMsg("###===--- LibrarySync Stopped ---===###", 0) log("###===--- LibrarySync Stopped ---===###", 0)
def stopThread(self): def stopThread(self):
self.stop_thread = True self.stop_thread = True
self.logMsg("Ending thread...", 2) log("Ending thread...", 2)
def suspendThread(self): def suspendThread(self):
self.suspend_thread = True self.suspend_thread = True
self.logMsg("Pausing thread...", 0) log("Pausing thread...", 0)
def resumeThread(self): def resumeThread(self):
self.suspend_thread = False self.suspend_thread = False
self.logMsg("Resuming thread...", 0) log("Resuming thread...", 0)
class ManualSync(LibrarySync): class ManualSync(LibrarySync):
@ -1041,14 +1025,13 @@ class ManualSync(LibrarySync):
def movies(self, embycursor, kodicursor, pdialog): def movies(self, embycursor, kodicursor, pdialog):
lang = utils.language
# Get movies from emby # Get movies from emby
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
movies = itemtypes.Movies(embycursor, kodicursor) movies = itemtypes.Movies(embycursor, kodicursor)
views = emby_db.getView_byType('movies') views = emby_db.getView_byType('movies')
views += emby_db.getView_byType('mixed') views += emby_db.getView_byType('mixed')
self.logMsg("Media folders: %s" % views, 1) log("Media folders: %s" % views, 1)
# Pull the list of movies and boxsets in Kodi # Pull the list of movies and boxsets in Kodi
try: try:
@ -1095,7 +1078,7 @@ class ManualSync(LibrarySync):
# Only update if movie is not in Kodi or checksum is different # Only update if movie is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
self.logMsg("Movies to update for %s: %s" % (viewName, updatelist), 1) log("Movies to update for %s: %s" % (viewName, updatelist), 1)
embymovies = self.emby.getFullItems(updatelist) embymovies = self.emby.getFullItems(updatelist)
total = len(updatelist) total = len(updatelist)
del updatelist[:] del updatelist[:]
@ -1137,7 +1120,7 @@ class ManualSync(LibrarySync):
updatelist.append(itemid) updatelist.append(itemid)
embyboxsets.append(boxset) embyboxsets.append(boxset)
self.logMsg("Boxsets to update: %s" % updatelist, 1) log("Boxsets to update: %s" % updatelist, 1)
total = len(updatelist) total = len(updatelist)
if pdialog: if pdialog:
@ -1161,13 +1144,13 @@ class ManualSync(LibrarySync):
if kodimovie not in all_embymoviesIds: if kodimovie not in all_embymoviesIds:
movies.remove(kodimovie) movies.remove(kodimovie)
else: else:
self.logMsg("Movies compare finished.", 1) log("Movies compare finished.", 1)
for boxset in all_kodisets: for boxset in all_kodisets:
if boxset not in all_embyboxsetsIds: if boxset not in all_embyboxsetsIds:
movies.remove(boxset) movies.remove(boxset)
else: else:
self.logMsg("Boxsets compare finished.", 1) log("Boxsets compare finished.", 1)
return True return True
@ -1178,7 +1161,7 @@ class ManualSync(LibrarySync):
mvideos = itemtypes.MusicVideos(embycursor, kodicursor) mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
views = emby_db.getView_byType('musicvideos') views = emby_db.getView_byType('musicvideos')
self.logMsg("Media folders: %s" % views, 1) log("Media folders: %s" % views, 1)
# Pull the list of musicvideos in Kodi # Pull the list of musicvideos in Kodi
try: try:
@ -1201,7 +1184,7 @@ class ManualSync(LibrarySync):
if pdialog: if pdialog:
pdialog.update( pdialog.update(
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (utils.language(33028), viewName)) message="%s %s..." % (lang(33028), viewName))
all_embymvideos = self.emby.getMusicVideos(viewId, basic=True, dialog=pdialog) all_embymvideos = self.emby.getMusicVideos(viewId, basic=True, dialog=pdialog)
for embymvideo in all_embymvideos['Items']: for embymvideo in all_embymvideos['Items']:
@ -1218,7 +1201,7 @@ class ManualSync(LibrarySync):
# Only update if musicvideo is not in Kodi or checksum is different # Only update if musicvideo is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
self.logMsg("MusicVideos to update for %s: %s" % (viewName, updatelist), 1) log("MusicVideos to update for %s: %s" % (viewName, updatelist), 1)
embymvideos = self.emby.getFullItems(updatelist) embymvideos = self.emby.getFullItems(updatelist)
total = len(updatelist) total = len(updatelist)
del updatelist[:] del updatelist[:]
@ -1245,20 +1228,19 @@ class ManualSync(LibrarySync):
if kodimvideo not in all_embymvideosIds: if kodimvideo not in all_embymvideosIds:
mvideos.remove(kodimvideo) mvideos.remove(kodimvideo)
else: else:
self.logMsg("MusicVideos compare finished.", 1) log("MusicVideos compare finished.", 1)
return True return True
def tvshows(self, embycursor, kodicursor, pdialog): def tvshows(self, embycursor, kodicursor, pdialog):
lang = utils.language
# Get shows from emby # Get shows from emby
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
tvshows = itemtypes.TVShows(embycursor, kodicursor) tvshows = itemtypes.TVShows(embycursor, kodicursor)
views = emby_db.getView_byType('tvshows') views = emby_db.getView_byType('tvshows')
views += emby_db.getView_byType('mixed') views += emby_db.getView_byType('mixed')
self.logMsg("Media folders: %s" % views, 1) log("Media folders: %s" % views, 1)
# Pull the list of tvshows and episodes in Kodi # Pull the list of tvshows and episodes in Kodi
try: try:
@ -1305,7 +1287,7 @@ class ManualSync(LibrarySync):
# Only update if movie is not in Kodi or checksum is different # Only update if movie is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
self.logMsg("TVShows to update for %s: %s" % (viewName, updatelist), 1) log("TVShows to update for %s: %s" % (viewName, updatelist), 1)
embytvshows = self.emby.getFullItems(updatelist) embytvshows = self.emby.getFullItems(updatelist)
total = len(updatelist) total = len(updatelist)
del updatelist[:] del updatelist[:]
@ -1349,7 +1331,7 @@ class ManualSync(LibrarySync):
# Only update if movie is not in Kodi or checksum is different # Only update if movie is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
self.logMsg("Episodes to update for %s: %s" % (viewName, updatelist), 1) log("Episodes to update for %s: %s" % (viewName, updatelist), 1)
embyepisodes = self.emby.getFullItems(updatelist) embyepisodes = self.emby.getFullItems(updatelist)
total = len(updatelist) total = len(updatelist)
del updatelist[:] del updatelist[:]
@ -1374,13 +1356,13 @@ class ManualSync(LibrarySync):
if koditvshow not in all_embytvshowsIds: if koditvshow not in all_embytvshowsIds:
tvshows.remove(koditvshow) tvshows.remove(koditvshow)
else: else:
self.logMsg("TVShows compare finished.", 1) log("TVShows compare finished.", 1)
for kodiepisode in all_kodiepisodes: for kodiepisode in all_kodiepisodes:
if kodiepisode not in all_embyepisodesIds: if kodiepisode not in all_embyepisodesIds:
tvshows.remove(kodiepisode) tvshows.remove(kodiepisode)
else: else:
self.logMsg("Episodes compare finished.", 1) log("Episodes compare finished.", 1)
return True return True
@ -1421,7 +1403,7 @@ class ManualSync(LibrarySync):
if pdialog: if pdialog:
pdialog.update( pdialog.update(
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (utils.language(33031), data_type)) message="%s %s..." % (lang(33031), data_type))
if data_type != "artists": if data_type != "artists":
all_embyitems = process[data_type][0](basic=True, dialog=pdialog) all_embyitems = process[data_type][0](basic=True, dialog=pdialog)
else: else:
@ -1446,7 +1428,7 @@ class ManualSync(LibrarySync):
if all_kodisongs.get(itemid) != API.getChecksum(): if all_kodisongs.get(itemid) != API.getChecksum():
# Only update if songs is not in Kodi or checksum is different # Only update if songs is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
self.logMsg("%s to update: %s" % (data_type, updatelist), 1) log("%s to update: %s" % (data_type, updatelist), 1)
embyitems = self.emby.getFullItems(updatelist) embyitems = self.emby.getFullItems(updatelist)
total = len(updatelist) total = len(updatelist)
del updatelist[:] del updatelist[:]
@ -1467,15 +1449,15 @@ class ManualSync(LibrarySync):
if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None: if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None:
music.remove(kodiartist) music.remove(kodiartist)
else: else:
self.logMsg("Artist compare finished.", 1) log("Artist compare finished.", 1)
for kodialbum in all_kodialbums: for kodialbum in all_kodialbums:
if kodialbum not in all_embyalbumsIds: if kodialbum not in all_embyalbumsIds:
music.remove(kodialbum) music.remove(kodialbum)
else: else:
self.logMsg("Albums compare finished.", 1) log("Albums compare finished.", 1)
for kodisong in all_kodisongs: for kodisong in all_kodisongs:
if kodisong not in all_embysongsIds: if kodisong not in all_embysongsIds:
music.remove(kodisong) music.remove(kodisong)
else: else:
self.logMsg("Songs compare finished.", 1) log("Songs compare finished.", 1)
return True return True

View file

@ -14,20 +14,18 @@ from mutagen import id3
import base64 import base64
import read_embyserver as embyserver import read_embyserver as embyserver
import utils from utils import Logging, window
################################################################################################# #################################################################################################
# Helper for the music library, intended to fix missing song ID3 tags on Emby # Helper for the music library, intended to fix missing song ID3 tags on Emby
log = Logging('MusicTools').log
def logMsg(msg, lvl=1):
utils.logMsg("%s %s" % ("Emby", "musictools"), msg, lvl)
def getRealFileName(filename, isTemp=False): def getRealFileName(filename, isTemp=False):
#get the filename path accessible by python if possible... #get the filename path accessible by python if possible...
if not xbmcvfs.exists(filename): if not xbmcvfs.exists(filename):
logMsg( "File does not exist! %s" %(filename), 0) log("File does not exist! %s" % filename, 0)
return (False, "") return (False, "")
#if we use os.path method on older python versions (sunch as some android builds), we need to pass arguments as string #if we use os.path method on older python versions (sunch as some android builds), we need to pass arguments as string
@ -104,7 +102,7 @@ def getAdditionalSongTags(embyid, emby_rating, API, kodicursor, emby_db, enablei
elif file_rating is None and not currentvalue: elif file_rating is None and not currentvalue:
return (emby_rating, comment, False) return (emby_rating, comment, False)
logMsg("getAdditionalSongTags --> embyid: %s - emby_rating: %s - file_rating: %s - current rating in kodidb: %s" %(embyid, emby_rating, file_rating, currentvalue)) log("getAdditionalSongTags --> embyid: %s - emby_rating: %s - file_rating: %s - current rating in kodidb: %s" %(embyid, emby_rating, file_rating, currentvalue))
updateFileRating = False updateFileRating = False
updateEmbyRating = False updateEmbyRating = False
@ -171,7 +169,7 @@ def getAdditionalSongTags(embyid, emby_rating, API, kodicursor, emby_db, enablei
if updateEmbyRating and enableexportsongrating: if updateEmbyRating and enableexportsongrating:
# sync details to emby server. Translation needed between ID3 rating and emby likes/favourites: # sync details to emby server. Translation needed between ID3 rating and emby likes/favourites:
like, favourite, deletelike = getEmbyRatingFromKodiRating(rating) like, favourite, deletelike = getEmbyRatingFromKodiRating(rating)
utils.window("ignore-update-%s" %embyid, "true") #set temp windows prop to ignore the update from webclient update window("ignore-update-%s" %embyid, "true") #set temp windows prop to ignore the update from webclient update
emby.updateUserRating(embyid, like, favourite, deletelike) emby.updateUserRating(embyid, like, favourite, deletelike)
return (rating, comment, hasEmbeddedCover) return (rating, comment, hasEmbeddedCover)
@ -183,7 +181,7 @@ def getSongTags(file):
hasEmbeddedCover = False hasEmbeddedCover = False
isTemp,filename = getRealFileName(file) isTemp,filename = getRealFileName(file)
logMsg( "getting song ID3 tags for " + filename) log( "getting song ID3 tags for " + filename)
try: try:
###### FLAC FILES ############# ###### FLAC FILES #############
@ -217,14 +215,14 @@ def getSongTags(file):
#POPM rating is 0-255 and needs to be converted to 0-5 range #POPM rating is 0-255 and needs to be converted to 0-5 range
if rating > 5: rating = (rating / 255) * 5 if rating > 5: rating = (rating / 255) * 5
else: else:
logMsg( "Not supported fileformat or unable to access file: %s" %(filename)) log( "Not supported fileformat or unable to access file: %s" %(filename))
#the rating must be a round value #the rating must be a round value
rating = int(round(rating,0)) rating = int(round(rating,0))
except Exception as e: except Exception as e:
#file in use ? #file in use ?
utils.logMsg("Exception in getSongTags", str(e),0) log("Exception in getSongTags", str(e),0)
rating = None rating = None
#remove tempfile if needed.... #remove tempfile if needed....
@ -246,7 +244,7 @@ def updateRatingToFile(rating, file):
xbmcvfs.copy(file, tempfile) xbmcvfs.copy(file, tempfile)
tempfile = xbmc.translatePath(tempfile).decode("utf-8") tempfile = xbmc.translatePath(tempfile).decode("utf-8")
logMsg( "setting song rating: %s for filename: %s - using tempfile: %s" %(rating,file,tempfile)) log( "setting song rating: %s for filename: %s - using tempfile: %s" %(rating,file,tempfile))
if not tempfile: if not tempfile:
return return
@ -263,7 +261,7 @@ def updateRatingToFile(rating, file):
audio.add(id3.POPM(email="Windows Media Player 9 Series", rating=calcrating, count=1)) audio.add(id3.POPM(email="Windows Media Player 9 Series", rating=calcrating, count=1))
audio.save() audio.save()
else: else:
logMsg( "Not supported fileformat: %s" %(tempfile)) log( "Not supported fileformat: %s" %(tempfile))
#once we have succesfully written the flags we move the temp file to destination, otherwise not proceeding and just delete the temp #once we have succesfully written the flags we move the temp file to destination, otherwise not proceeding and just delete the temp
#safety check: we check the file size of the temp file before proceeding with overwite of original file #safety check: we check the file size of the temp file before proceeding with overwite of original file
@ -274,14 +272,14 @@ def updateRatingToFile(rating, file):
xbmcvfs.delete(file) xbmcvfs.delete(file)
xbmcvfs.copy(tempfile,file) xbmcvfs.copy(tempfile,file)
else: else:
logMsg( "Checksum mismatch for filename: %s - using tempfile: %s - not proceeding with file overwite!" %(rating,file,tempfile)) log( "Checksum mismatch for filename: %s - using tempfile: %s - not proceeding with file overwite!" %(rating,file,tempfile))
#always delete the tempfile #always delete the tempfile
xbmcvfs.delete(tempfile) xbmcvfs.delete(tempfile)
except Exception as e: except Exception as e:
#file in use ? #file in use ?
logMsg("Exception in updateRatingToFile %s" %e,0) log("Exception in updateRatingToFile %s" %e,0)

View file

@ -7,11 +7,11 @@ import json
import xbmc import xbmc
import xbmcgui import xbmcgui
import utils
import clientinfo import clientinfo
import downloadutils import downloadutils
import kodidb_functions as kodidb import kodidb_functions as kodidb
import websocket_client as wsc import websocket_client as wsc
from utils import Logging, window, settings, language as lang
################################################################################################# #################################################################################################
@ -28,6 +28,9 @@ class Player(xbmc.Player):
def __init__(self): def __init__(self):
global log
log = Logging(self.__class__.__name__).log
self.__dict__ = self._shared_state self.__dict__ = self._shared_state
self.clientInfo = clientinfo.ClientInfo() self.clientInfo = clientinfo.ClientInfo()
@ -36,20 +39,13 @@ class Player(xbmc.Player):
self.ws = wsc.WebSocket_Client() self.ws = wsc.WebSocket_Client()
self.xbmcplayer = xbmc.Player() self.xbmcplayer = xbmc.Player()
self.logMsg("Starting playback monitor.", 2) log("Starting playback monitor.", 2)
def logMsg(self, msg, lvl=1):
self.className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
def GetPlayStats(self): def GetPlayStats(self):
return self.playStats return self.playStats
def onPlayBackStarted(self): def onPlayBackStarted(self):
window = utils.window
# Will be called when xbmc starts playing a file # Will be called when xbmc starts playing a file
self.stopAll() self.stopAll()
@ -67,7 +63,7 @@ class Player(xbmc.Player):
except: pass except: pass
if count == 5: # try 5 times if count == 5: # try 5 times
self.logMsg("Cancelling playback report...", 1) log("Cancelling playback report...", 1)
break break
else: count += 1 else: count += 1
@ -84,12 +80,12 @@ class Player(xbmc.Player):
xbmc.sleep(200) xbmc.sleep(200)
itemId = window("emby_%s.itemid" % currentFile) itemId = window("emby_%s.itemid" % currentFile)
if tryCount == 20: # try 20 times or about 10 seconds if tryCount == 20: # try 20 times or about 10 seconds
self.logMsg("Could not find itemId, cancelling playback report...", 1) log("Could not find itemId, cancelling playback report...", 1)
break break
else: tryCount += 1 else: tryCount += 1
else: else:
self.logMsg("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId), 0) log("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId), 0)
# Only proceed if an itemId was found. # Only proceed if an itemId was found.
embyitem = "emby_%s" % currentFile embyitem = "emby_%s" % currentFile
@ -102,7 +98,7 @@ class Player(xbmc.Player):
customseek = window('emby_customPlaylist.seektime') customseek = window('emby_customPlaylist.seektime')
if window('emby_customPlaylist') == "true" and customseek: if window('emby_customPlaylist') == "true" and customseek:
# Start at, when using custom playlist (play to Kodi from webclient) # Start at, when using custom playlist (play to Kodi from webclient)
self.logMsg("Seeking to: %s" % customseek, 1) log("Seeking to: %s" % customseek, 1)
self.xbmcplayer.seekTime(int(customseek)/10000000.0) self.xbmcplayer.seekTime(int(customseek)/10000000.0)
window('emby_customPlaylist.seektime', clear=True) window('emby_customPlaylist.seektime', clear=True)
@ -189,7 +185,7 @@ class Player(xbmc.Player):
if mapping: # Set in playbackutils.py if mapping: # Set in playbackutils.py
self.logMsg("Mapping for external subtitles index: %s" % mapping, 2) log("Mapping for external subtitles index: %s" % mapping, 2)
externalIndex = json.loads(mapping) externalIndex = json.loads(mapping)
if externalIndex.get(str(indexSubs)): if externalIndex.get(str(indexSubs)):
@ -207,7 +203,7 @@ class Player(xbmc.Player):
# Post playback to server # Post playback to server
self.logMsg("Sending POST play started: %s." % postdata, 2) log("Sending POST play started: %s." % postdata, 2)
self.doUtils(url, postBody=postdata, action_type="POST") self.doUtils(url, postBody=postdata, action_type="POST")
# Ensure we do have a runtime # Ensure we do have a runtime
@ -215,7 +211,7 @@ class Player(xbmc.Player):
runtime = int(runtime) runtime = int(runtime)
except ValueError: except ValueError:
runtime = self.xbmcplayer.getTotalTime() runtime = self.xbmcplayer.getTotalTime()
self.logMsg("Runtime is missing, Kodi runtime: %s" % runtime, 1) log("Runtime is missing, Kodi runtime: %s" % runtime, 1)
# Save data map for updates and position calls # Save data map for updates and position calls
data = { data = {
@ -232,7 +228,7 @@ class Player(xbmc.Player):
} }
self.played_info[currentFile] = data self.played_info[currentFile] = data
self.logMsg("ADDING_FILE: %s" % self.played_info, 1) log("ADDING_FILE: %s" % self.played_info, 1)
# log some playback stats # log some playback stats
'''if(itemType != None): '''if(itemType != None):
@ -251,7 +247,7 @@ class Player(xbmc.Player):
def reportPlayback(self): def reportPlayback(self):
self.logMsg("reportPlayback Called", 2) log("reportPlayback Called", 2)
# Get current file # Get current file
currentFile = self.currentFile currentFile = self.currentFile
@ -345,11 +341,11 @@ class Player(xbmc.Player):
# Number of audiotracks to help get Emby Index # Number of audiotracks to help get Emby Index
audioTracks = len(xbmc.Player().getAvailableAudioStreams()) audioTracks = len(xbmc.Player().getAvailableAudioStreams())
mapping = utils.window("emby_%s.indexMapping" % currentFile) mapping = window("emby_%s.indexMapping" % currentFile)
if mapping: # Set in PlaybackUtils.py if mapping: # Set in PlaybackUtils.py
self.logMsg("Mapping for external subtitles index: %s" % mapping, 2) log("Mapping for external subtitles index: %s" % mapping, 2)
externalIndex = json.loads(mapping) externalIndex = json.loads(mapping)
if externalIndex.get(str(indexSubs)): if externalIndex.get(str(indexSubs)):
@ -369,13 +365,13 @@ class Player(xbmc.Player):
# Report progress via websocketclient # Report progress via websocketclient
postdata = json.dumps(postdata) postdata = json.dumps(postdata)
self.logMsg("Report: %s" % postdata, 2) log("Report: %s" % postdata, 2)
self.ws.sendProgressUpdate(postdata) self.ws.sendProgressUpdate(postdata)
def onPlayBackPaused(self): def onPlayBackPaused(self):
currentFile = self.currentFile currentFile = self.currentFile
self.logMsg("PLAYBACK_PAUSED: %s" % currentFile, 2) log("PLAYBACK_PAUSED: %s" % currentFile, 2)
if self.played_info.get(currentFile): if self.played_info.get(currentFile):
self.played_info[currentFile]['paused'] = True self.played_info[currentFile]['paused'] = True
@ -385,7 +381,7 @@ class Player(xbmc.Player):
def onPlayBackResumed(self): def onPlayBackResumed(self):
currentFile = self.currentFile currentFile = self.currentFile
self.logMsg("PLAYBACK_RESUMED: %s" % currentFile, 2) log("PLAYBACK_RESUMED: %s" % currentFile, 2)
if self.played_info.get(currentFile): if self.played_info.get(currentFile):
self.played_info[currentFile]['paused'] = False self.played_info[currentFile]['paused'] = False
@ -395,7 +391,7 @@ class Player(xbmc.Player):
def onPlayBackSeek(self, time, seekOffset): def onPlayBackSeek(self, time, seekOffset):
# Make position when seeking a bit more accurate # Make position when seeking a bit more accurate
currentFile = self.currentFile currentFile = self.currentFile
self.logMsg("PLAYBACK_SEEK: %s" % currentFile, 2) log("PLAYBACK_SEEK: %s" % currentFile, 2)
if self.played_info.get(currentFile): if self.played_info.get(currentFile):
position = self.xbmcplayer.getTime() position = self.xbmcplayer.getTime()
@ -404,39 +400,34 @@ class Player(xbmc.Player):
self.reportPlayback() self.reportPlayback()
def onPlayBackStopped(self): def onPlayBackStopped(self):
window = utils.window
# Will be called when user stops xbmc playing a file # Will be called when user stops xbmc playing a file
self.logMsg("ONPLAYBACK_STOPPED", 2) log("ONPLAYBACK_STOPPED", 2)
window('emby_customPlaylist', clear=True) window('emby_customPlaylist', clear=True)
window('emby_customPlaylist.seektime', clear=True) window('emby_customPlaylist.seektime', clear=True)
window('emby_playbackProps', clear=True) window('emby_playbackProps', clear=True)
self.logMsg("Clear playlist properties.", 1) log("Clear playlist properties.", 1)
self.stopAll() self.stopAll()
def onPlayBackEnded(self): def onPlayBackEnded(self):
# Will be called when xbmc stops playing a file # Will be called when xbmc stops playing a file
self.logMsg("ONPLAYBACK_ENDED", 2) log("ONPLAYBACK_ENDED", 2)
utils.window('emby_customPlaylist.seektime', clear=True) window('emby_customPlaylist.seektime', clear=True)
self.stopAll() self.stopAll()
def stopAll(self): def stopAll(self):
lang = utils.language
settings = utils.settings
if not self.played_info: if not self.played_info:
return return
self.logMsg("Played_information: %s" % self.played_info, 1) log("Played_information: %s" % self.played_info, 1)
# Process each items # Process each items
for item in self.played_info: for item in self.played_info:
data = self.played_info.get(item) data = self.played_info.get(item)
if data: if data:
self.logMsg("Item path: %s" % item, 2) log("Item path: %s" % item, 2)
self.logMsg("Item data: %s" % data, 2) log("Item data: %s" % data, 2)
runtime = data['runtime'] runtime = data['runtime']
currentPosition = data['currentPosition'] currentPosition = data['currentPosition']
@ -447,7 +438,7 @@ class Player(xbmc.Player):
playMethod = data['playmethod'] playMethod = data['playmethod']
# Prevent manually mark as watched in Kodi monitor # Prevent manually mark as watched in Kodi monitor
utils.window('emby_skipWatched%s' % itemid, value="true") window('emby_skipWatched%s' % itemid, value="true")
if currentPosition and runtime: if currentPosition and runtime:
try: try:
@ -457,7 +448,7 @@ class Player(xbmc.Player):
percentComplete = 0 percentComplete = 0
markPlayedAt = float(settings('markPlayed')) / 100 markPlayedAt = float(settings('markPlayed')) / 100
self.logMsg("Percent complete: %s Mark played at: %s" log("Percent complete: %s Mark played at: %s"
% (percentComplete, markPlayedAt), 1) % (percentComplete, markPlayedAt), 1)
# Send the delete action to the server. # Send the delete action to the server.
@ -475,18 +466,18 @@ class Player(xbmc.Player):
if percentComplete >= markPlayedAt and offerDelete: if percentComplete >= markPlayedAt and offerDelete:
resp = xbmcgui.Dialog().yesno(lang(30091), lang(33015), autoclose=120000) resp = xbmcgui.Dialog().yesno(lang(30091), lang(33015), autoclose=120000)
if not resp: if not resp:
self.logMsg("User skipped deletion.", 1) log("User skipped deletion.", 1)
continue continue
url = "{server}/emby/Items/%s?format=json" % itemid url = "{server}/emby/Items/%s?format=json" % itemid
self.logMsg("Deleting request: %s" % itemid, 1) log("Deleting request: %s" % itemid, 1)
self.doUtils(url, action_type="DELETE") self.doUtils(url, action_type="DELETE")
self.stopPlayback(data) self.stopPlayback(data)
# Stop transcoding # Stop transcoding
if playMethod == "Transcode": if playMethod == "Transcode":
self.logMsg("Transcoding for %s terminated." % itemid, 1) log("Transcoding for %s terminated." % itemid, 1)
deviceId = self.clientInfo.getDeviceId() deviceId = self.clientInfo.getDeviceId()
url = "{server}/emby/Videos/ActiveEncodings?DeviceId=%s" % deviceId url = "{server}/emby/Videos/ActiveEncodings?DeviceId=%s" % deviceId
self.doUtils(url, action_type="DELETE") self.doUtils(url, action_type="DELETE")
@ -495,7 +486,7 @@ class Player(xbmc.Player):
def stopPlayback(self, data): def stopPlayback(self, data):
self.logMsg("stopPlayback called", 2) log("stopPlayback called", 2)
itemId = data['item_id'] itemId = data['item_id']
currentPosition = data['currentPosition'] currentPosition = data['currentPosition']

View file

@ -188,7 +188,7 @@ def setScreensaver(value):
result = xbmc.executeJSONRPC(json.dumps(query)) result = xbmc.executeJSONRPC(json.dumps(query))
log("Toggling screensaver: %s %s" % (value, result), 1) log("Toggling screensaver: %s %s" % (value, result), 1)
def convertdate(date): def convertDate(date):
try: try:
date = datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ") date = datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ")
except TypeError: except TypeError: