Centralized logging
This commit is contained in:
parent
02e7c2946b
commit
5658801f72
10 changed files with 336 additions and 373 deletions
|
@ -6,8 +6,8 @@ import json
|
|||
import requests
|
||||
import logging
|
||||
|
||||
import utils
|
||||
import clientinfo
|
||||
from utils import Logging, window
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
@ -34,28 +34,26 @@ class ConnectUtils():
|
|||
|
||||
def __init__(self):
|
||||
|
||||
global log
|
||||
log = Logging(self.__class__.__name__).log
|
||||
|
||||
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):
|
||||
# Reserved for userclient only
|
||||
self.userId = userId
|
||||
self.logMsg("Set connect userId: %s" % userId, 2)
|
||||
log("Set connect userId: %s" % userId, 2)
|
||||
|
||||
def setServer(self, server):
|
||||
# Reserved for userclient only
|
||||
self.server = server
|
||||
self.logMsg("Set connect server: %s" % server, 2)
|
||||
log("Set connect server: %s" % server, 2)
|
||||
|
||||
def setToken(self, token):
|
||||
# Reserved for userclient only
|
||||
self.token = token
|
||||
self.logMsg("Set connect token: %s" % token, 2)
|
||||
log("Set connect token: %s" % token, 2)
|
||||
|
||||
|
||||
def startSession(self):
|
||||
|
@ -73,7 +71,7 @@ class ConnectUtils():
|
|||
if self.sslclient is not None:
|
||||
verify = self.sslclient
|
||||
except:
|
||||
self.logMsg("Could not load SSL settings.", 1)
|
||||
log("Could not load SSL settings.", 1)
|
||||
|
||||
# Start session
|
||||
self.c = requests.Session()
|
||||
|
@ -83,13 +81,13 @@ class ConnectUtils():
|
|||
self.c.mount("http://", 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):
|
||||
try:
|
||||
self.c.close()
|
||||
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):
|
||||
|
||||
|
@ -103,7 +101,7 @@ class ConnectUtils():
|
|||
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'Accept': "application/json"
|
||||
}
|
||||
self.logMsg("Header: %s" % header, 1)
|
||||
log("Header: %s" % header, 1)
|
||||
|
||||
else:
|
||||
token = self.token
|
||||
|
@ -115,17 +113,17 @@ class ConnectUtils():
|
|||
'X-Application': "Kodi/%s" % version,
|
||||
'X-Connect-UserToken': token
|
||||
}
|
||||
self.logMsg("Header: %s" % header, 1)
|
||||
log("Header: %s" % header, 1)
|
||||
|
||||
return header
|
||||
|
||||
def doUrl(self, url, data=None, postBody=None, rtype="GET",
|
||||
parameters=None, authenticate=True, timeout=None):
|
||||
|
||||
window = utils.window
|
||||
|
||||
self.logMsg("=== ENTER connectUrl ===", 2)
|
||||
log("=== ENTER connectUrl ===", 2)
|
||||
|
||||
default_link = ""
|
||||
|
||||
if timeout is None:
|
||||
timeout = self.timeout
|
||||
|
||||
|
@ -209,25 +207,25 @@ class ConnectUtils():
|
|||
verify=verifyssl)
|
||||
|
||||
##### THE RESPONSE #####
|
||||
self.logMsg(r.url, 1)
|
||||
self.logMsg(r, 1)
|
||||
log(r.url, 1)
|
||||
log(r, 1)
|
||||
|
||||
if r.status_code == 204:
|
||||
# No body in the response
|
||||
self.logMsg("====== 204 Success ======", 1)
|
||||
log("====== 204 Success ======", 1)
|
||||
|
||||
elif r.status_code == requests.codes.ok:
|
||||
|
||||
try:
|
||||
# UNICODE - JSON object
|
||||
r = r.json()
|
||||
self.logMsg("====== 200 Success ======", 1)
|
||||
self.logMsg("Response: %s" % r, 1)
|
||||
log("====== 200 Success ======", 1)
|
||||
log("Response: %s" % r, 1)
|
||||
return r
|
||||
|
||||
except:
|
||||
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:
|
||||
r.raise_for_status()
|
||||
|
||||
|
@ -238,8 +236,8 @@ class ConnectUtils():
|
|||
pass
|
||||
|
||||
except requests.exceptions.ConnectTimeout as e:
|
||||
self.logMsg("Server timeout at: %s" % url, 0)
|
||||
self.logMsg(e, 1)
|
||||
log("Server timeout at: %s" % url, 0)
|
||||
log(e, 1)
|
||||
|
||||
except requests.exceptions.HTTPError as e:
|
||||
|
||||
|
@ -255,11 +253,11 @@ class ConnectUtils():
|
|||
pass
|
||||
|
||||
except requests.exceptions.SSLError as e:
|
||||
self.logMsg("Invalid SSL certificate for: %s" % url, 0)
|
||||
self.logMsg(e, 1)
|
||||
log("Invalid SSL certificate for: %s" % url, 0)
|
||||
log(e, 1)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
self.logMsg("Unknown error connecting to: %s" % url, 0)
|
||||
self.logMsg(e, 1)
|
||||
log("Unknown error connecting to: %s" % url, 0)
|
||||
log(e, 1)
|
||||
|
||||
return default_link
|
||||
return default_link
|
|
@ -9,14 +9,15 @@ import logging
|
|||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
import utils
|
||||
import clientinfo
|
||||
from utils import Logging, window, settings
|
||||
|
||||
##################################################################################################
|
||||
|
||||
# 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(InsecurePlatformWarning)
|
||||
#logging.getLogger('requests').setLevel(logging.WARNING)
|
||||
|
||||
##################################################################################################
|
||||
|
@ -36,40 +37,38 @@ class DownloadUtils():
|
|||
|
||||
def __init__(self):
|
||||
|
||||
global log
|
||||
log = Logging(self.__class__.__name__).log
|
||||
|
||||
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):
|
||||
# Reserved for userclient only
|
||||
self.username = username
|
||||
self.logMsg("Set username: %s" % username, 2)
|
||||
log("Set username: %s" % username, 2)
|
||||
|
||||
def setUserId(self, userId):
|
||||
# Reserved for userclient only
|
||||
self.userId = userId
|
||||
self.logMsg("Set userId: %s" % userId, 2)
|
||||
log("Set userId: %s" % userId, 2)
|
||||
|
||||
def setServer(self, server):
|
||||
# Reserved for userclient only
|
||||
self.server = server
|
||||
self.logMsg("Set server: %s" % server, 2)
|
||||
log("Set server: %s" % server, 2)
|
||||
|
||||
def setToken(self, token):
|
||||
# Reserved for userclient only
|
||||
self.token = token
|
||||
self.logMsg("Set token: %s" % token, 2)
|
||||
log("Set token: %s" % token, 2)
|
||||
|
||||
def setSSL(self, ssl, sslclient):
|
||||
# Reserved for userclient only
|
||||
self.sslverify = ssl
|
||||
self.sslclient = sslclient
|
||||
self.logMsg("Verify SSL host certificate: %s" % ssl, 2)
|
||||
self.logMsg("SSL client side certificate: %s" % sslclient, 2)
|
||||
log("Verify SSL host certificate: %s" % ssl, 2)
|
||||
log("SSL client side certificate: %s" % sslclient, 2)
|
||||
|
||||
|
||||
def postCapabilities(self, deviceId):
|
||||
|
@ -94,11 +93,11 @@ class DownloadUtils():
|
|||
)
|
||||
}
|
||||
|
||||
self.logMsg("Capabilities URL: %s" % url, 2)
|
||||
self.logMsg("Postdata: %s" % data, 2)
|
||||
log("Capabilities URL: %s" % url, 2)
|
||||
log("Postdata: %s" % data, 2)
|
||||
|
||||
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
|
||||
url = "{server}/emby/Sessions?DeviceId=%s&format=json" % deviceId
|
||||
|
@ -107,20 +106,19 @@ class DownloadUtils():
|
|||
sessionId = result[0]['Id']
|
||||
|
||||
except (KeyError, TypeError):
|
||||
self.logMsg("Failed to retrieve sessionId.", 1)
|
||||
log("Failed to retrieve sessionId.", 1)
|
||||
|
||||
else:
|
||||
self.logMsg("Session: %s" % result, 2)
|
||||
self.logMsg("SessionId: %s" % sessionId, 1)
|
||||
utils.window('emby_sessionId', value=sessionId)
|
||||
log("Session: %s" % result, 2)
|
||||
log("SessionId: %s" % sessionId, 1)
|
||||
window('emby_sessionId', value=sessionId)
|
||||
|
||||
# Post any permanent additional users
|
||||
additionalUsers = utils.settings('additionalUsers')
|
||||
additionalUsers = settings('additionalUsers')
|
||||
if additionalUsers:
|
||||
|
||||
additionalUsers = additionalUsers.split(',')
|
||||
self.logMsg(
|
||||
"List of permanent users added to the session: %s"
|
||||
log("List of permanent users added to the session: %s"
|
||||
% additionalUsers, 1)
|
||||
|
||||
# Get the user list from server to get the userId
|
||||
|
@ -158,7 +156,7 @@ class DownloadUtils():
|
|||
if self.sslclient is not None:
|
||||
verify = self.sslclient
|
||||
except:
|
||||
self.logMsg("Could not load SSL settings.", 1)
|
||||
log("Could not load SSL settings.", 1)
|
||||
|
||||
# Start session
|
||||
self.s = requests.Session()
|
||||
|
@ -168,18 +166,18 @@ class DownloadUtils():
|
|||
self.s.mount("http://", 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):
|
||||
try:
|
||||
self.s.close()
|
||||
except:
|
||||
self.logMsg("Requests session could not be terminated.", 1)
|
||||
log("Requests session could not be terminated.", 1)
|
||||
|
||||
def getHeader(self, authenticate=True):
|
||||
|
||||
deviceName = self.clientInfo.getDeviceName()
|
||||
deviceName = utils.normalize_string(deviceName.encode('utf-8'))
|
||||
deviceName = deviceName.encode('utf-8')
|
||||
deviceId = self.clientInfo.getDeviceId()
|
||||
version = self.clientInfo.getVersion()
|
||||
|
||||
|
@ -195,7 +193,7 @@ class DownloadUtils():
|
|||
'Accept-Charset': 'UTF-8,*',
|
||||
'Authorization': auth
|
||||
}
|
||||
self.logMsg("Header: %s" % header, 2)
|
||||
log("Header: %s" % header, 2)
|
||||
|
||||
else:
|
||||
userId = self.userId
|
||||
|
@ -212,19 +210,20 @@ class DownloadUtils():
|
|||
'Authorization': auth,
|
||||
'X-MediaBrowser-Token': token
|
||||
}
|
||||
self.logMsg("Header: %s" % header, 2)
|
||||
log("Header: %s" % header, 2)
|
||||
|
||||
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 = ""
|
||||
|
||||
try:
|
||||
# If user is authenticated
|
||||
if (authenticate):
|
||||
if authenticate:
|
||||
# Get requests session
|
||||
try:
|
||||
s = self.s
|
||||
|
@ -243,18 +242,18 @@ class DownloadUtils():
|
|||
except AttributeError:
|
||||
# request session does not exists
|
||||
# Get user information
|
||||
self.userId = utils.window('emby_currUser')
|
||||
self.server = utils.window('emby_server%s' % self.userId)
|
||||
self.token = utils.window('emby_accessToken%s' % self.userId)
|
||||
self.userId = window('emby_currUser')
|
||||
self.server = window('emby_server%s' % self.userId)
|
||||
self.token = window('emby_accessToken%s' % self.userId)
|
||||
header = self.getHeader()
|
||||
verifyssl = False
|
||||
cert = None
|
||||
|
||||
# IF user enables ssl verification
|
||||
if utils.settings('sslverify') == "true":
|
||||
if settings('sslverify') == "true":
|
||||
verifyssl = True
|
||||
if utils.settings('sslcert') != "None":
|
||||
verifyssl = utils.settings('sslcert')
|
||||
if settings('sslcert') != "None":
|
||||
verifyssl = settings('sslcert')
|
||||
|
||||
# Replace for the real values
|
||||
url = url.replace("{server}", self.server)
|
||||
|
@ -314,23 +313,23 @@ class DownloadUtils():
|
|||
verify=verifyssl)
|
||||
|
||||
##### THE RESPONSE #####
|
||||
self.logMsg(r.url, 2)
|
||||
log(r.url, 2)
|
||||
if r.status_code == 204:
|
||||
# No body in the response
|
||||
self.logMsg("====== 204 Success ======", 2)
|
||||
log("====== 204 Success ======", 2)
|
||||
|
||||
elif r.status_code == requests.codes.ok:
|
||||
|
||||
try:
|
||||
# UNICODE - JSON object
|
||||
r = r.json()
|
||||
self.logMsg("====== 200 Success ======", 2)
|
||||
self.logMsg("Response: %s" % r, 2)
|
||||
log("====== 200 Success ======", 2)
|
||||
log("Response: %s" % r, 2)
|
||||
return r
|
||||
|
||||
except:
|
||||
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:
|
||||
r.raise_for_status()
|
||||
|
||||
|
@ -338,26 +337,26 @@ class DownloadUtils():
|
|||
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
# Make the addon aware of status
|
||||
if utils.window('emby_online') != "false":
|
||||
self.logMsg("Server unreachable at: %s" % url, 0)
|
||||
self.logMsg(e, 2)
|
||||
utils.window('emby_online', value="false")
|
||||
if window('emby_online') != "false":
|
||||
log("Server unreachable at: %s" % url, 0)
|
||||
log(e, 2)
|
||||
window('emby_online', value="false")
|
||||
|
||||
except requests.exceptions.ConnectTimeout as e:
|
||||
self.logMsg("Server timeout at: %s" % url, 0)
|
||||
self.logMsg(e, 1)
|
||||
log("Server timeout at: %s" % url, 0)
|
||||
log(e, 1)
|
||||
|
||||
except requests.exceptions.HTTPError as e:
|
||||
|
||||
if r.status_code == 401:
|
||||
# Unauthorized
|
||||
status = utils.window('emby_serverStatus')
|
||||
status = window('emby_serverStatus')
|
||||
|
||||
if 'X-Application-Error-Code' in r.headers:
|
||||
# Emby server errors
|
||||
if r.headers['X-Application-Error-Code'] == "ParentalControl":
|
||||
# Parental control - access restricted
|
||||
utils.window('emby_serverStatus', value="restricted")
|
||||
window('emby_serverStatus', value="restricted")
|
||||
xbmcgui.Dialog().notification(
|
||||
heading="Emby server",
|
||||
message="Access restricted.",
|
||||
|
@ -371,8 +370,8 @@ class DownloadUtils():
|
|||
|
||||
elif status not in ("401", "Auth"):
|
||||
# Tell userclient token has been revoked.
|
||||
utils.window('emby_serverStatus', value="401")
|
||||
self.logMsg("HTTP Error: %s" % e, 0)
|
||||
window('emby_serverStatus', value="401")
|
||||
log("HTTP Error: %s" % e, 0)
|
||||
xbmcgui.Dialog().notification(
|
||||
heading="Error connecting",
|
||||
message="Unauthorized.",
|
||||
|
@ -387,11 +386,11 @@ class DownloadUtils():
|
|||
pass
|
||||
|
||||
except requests.exceptions.SSLError as e:
|
||||
self.logMsg("Invalid SSL certificate for: %s" % url, 0)
|
||||
self.logMsg(e, 1)
|
||||
log("Invalid SSL certificate for: %s" % url, 0)
|
||||
log(e, 1)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
self.logMsg("Unknown error connecting to: %s" % url, 0)
|
||||
self.logMsg(e, 1)
|
||||
log("Unknown error connecting to: %s" % url, 0)
|
||||
log(e, 1)
|
||||
|
||||
return default_link
|
|
@ -1,8 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#################################################################################################
|
||||
|
||||
import threading
|
||||
import utils
|
||||
import xbmc
|
||||
import requests
|
||||
|
||||
from utils import Logging
|
||||
|
||||
#################################################################################################
|
||||
|
||||
class image_cache_thread(threading.Thread):
|
||||
|
||||
urlToProcess = None
|
||||
|
@ -13,28 +19,32 @@ class image_cache_thread(threading.Thread):
|
|||
xbmc_username = ""
|
||||
xbmc_password = ""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.monitor = xbmc.Monitor()
|
||||
|
||||
global log
|
||||
log = Logging(self.__class__.__name__).log
|
||||
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def logMsg(self, msg, lvl=1):
|
||||
className = self.__class__.__name__
|
||||
utils.logMsg("%s" % className, msg, lvl)
|
||||
|
||||
|
||||
def setUrl(self, url):
|
||||
|
||||
self.urlToProcess = url
|
||||
|
||||
def setHost(self, host, port):
|
||||
|
||||
self.xbmc_host = host
|
||||
self.xbmc_port = port
|
||||
|
||||
def setAuth(self, user, pwd):
|
||||
|
||||
self.xbmc_username = user
|
||||
self.xbmc_password = pwd
|
||||
|
||||
def run(self):
|
||||
|
||||
self.logMsg("Image Caching Thread Processing : " + self.urlToProcess, 2)
|
||||
log("Image Caching Thread Processing: %s" % self.urlToProcess, 2)
|
||||
|
||||
try:
|
||||
response = requests.head(
|
||||
|
@ -46,7 +56,5 @@ class image_cache_thread(threading.Thread):
|
|||
# We don't need the result
|
||||
except: pass
|
||||
|
||||
self.logMsg("Image Caching Thread Exited", 2)
|
||||
|
||||
self.isFinished = True
|
||||
|
||||
log("Image Caching Thread Exited", 2)
|
||||
self.isFinished = True
|
|
@ -9,10 +9,10 @@ import xbmc
|
|||
import xbmcgui
|
||||
import xbmcaddon
|
||||
|
||||
import utils
|
||||
import clientinfo
|
||||
import downloadutils
|
||||
import userclient
|
||||
from utils import Logging, settings, language as lang, passwordsXML
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -22,74 +22,67 @@ class InitialSetup():
|
|||
|
||||
def __init__(self):
|
||||
|
||||
self.addon = xbmcaddon.Addon()
|
||||
self.__language__ = self.addon.getLocalizedString
|
||||
global log
|
||||
log = Logging(self.__class__.__name__).log
|
||||
|
||||
self.clientInfo = clientinfo.ClientInfo()
|
||||
self.addonName = self.clientInfo.getAddonName()
|
||||
self.addonId = self.clientInfo.getAddonId()
|
||||
self.doUtils = downloadutils.DownloadUtils()
|
||||
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):
|
||||
# Check server, user, direct paths, music, direct stream if not direct path.
|
||||
string = self.__language__
|
||||
addonId = self.addonId
|
||||
|
||||
##### SERVER INFO #####
|
||||
|
||||
self.logMsg("Initial setup called.", 2)
|
||||
log("Initial setup called.", 2)
|
||||
server = self.userClient.getServer()
|
||||
|
||||
if server:
|
||||
self.logMsg("Server is already set.", 2)
|
||||
log("Server is already set.", 2)
|
||||
return
|
||||
|
||||
self.logMsg("Looking for server...", 2)
|
||||
log("Looking for server...", 2)
|
||||
server = self.getServerDetails()
|
||||
self.logMsg("Found: %s" % server, 2)
|
||||
log("Found: %s" % server, 2)
|
||||
try:
|
||||
prefix, ip, port = server.replace("/", "").split(":")
|
||||
except: # Failed to retrieve server information
|
||||
self.logMsg("getServerDetails failed.", 1)
|
||||
log("getServerDetails failed.", 1)
|
||||
xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId)
|
||||
return
|
||||
else:
|
||||
server_confirm = xbmcgui.Dialog().yesno(
|
||||
heading="Emby for Kodi",
|
||||
line1="Proceed with the following server?",
|
||||
line2="%s %s" % (string(30169), server))
|
||||
line2="%s %s" % (lang(30169), server))
|
||||
if server_confirm:
|
||||
# Correct server found
|
||||
self.logMsg("Server is selected. Saving the information.", 1)
|
||||
utils.settings('ipaddress', value=ip)
|
||||
utils.settings('port', value=port)
|
||||
log("Server is selected. Saving the information.", 1)
|
||||
settings('ipaddress', value=ip)
|
||||
settings('port', value=port)
|
||||
|
||||
if prefix == "https":
|
||||
utils.settings('https', value="true")
|
||||
settings('https', value="true")
|
||||
else:
|
||||
# User selected no or cancelled the dialog
|
||||
self.logMsg("No server selected.", 1)
|
||||
log("No server selected.", 1)
|
||||
xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId)
|
||||
return
|
||||
|
||||
##### USER INFO #####
|
||||
|
||||
self.logMsg("Getting user list.", 1)
|
||||
log("Getting user list.", 1)
|
||||
|
||||
url = "%s/emby/Users/Public?format=json" % server
|
||||
result = self.doUtils.downloadUrl(url, authenticate=False)
|
||||
if result == "":
|
||||
self.logMsg("Unable to connect to %s" % server, 1)
|
||||
log("Unable to connect to %s" % server, 1)
|
||||
return
|
||||
|
||||
self.logMsg("Response: %s" % result, 2)
|
||||
log("Response: %s" % result, 2)
|
||||
# Process the list of users
|
||||
usernames = []
|
||||
users_hasPassword = []
|
||||
|
@ -103,14 +96,14 @@ class InitialSetup():
|
|||
name = "%s (secure)" % name
|
||||
users_hasPassword.append(name)
|
||||
|
||||
self.logMsg("Presenting user list: %s" % users_hasPassword, 1)
|
||||
user_select = xbmcgui.Dialog().select(string(30200), users_hasPassword)
|
||||
log("Presenting user list: %s" % users_hasPassword, 1)
|
||||
user_select = xbmcgui.Dialog().select(lang(30200), users_hasPassword)
|
||||
if user_select > -1:
|
||||
selected_user = usernames[user_select]
|
||||
self.logMsg("Selected user: %s" % selected_user, 1)
|
||||
utils.settings('username', value=selected_user)
|
||||
log("Selected user: %s" % selected_user, 1)
|
||||
settings('username', value=selected_user)
|
||||
else:
|
||||
self.logMsg("No user selected.", 1)
|
||||
log("No user selected.", 1)
|
||||
xbmc.executebuiltin('Addon.OpenSettings(%s)' % addonId)
|
||||
|
||||
##### ADDITIONAL PROMPTS #####
|
||||
|
@ -126,8 +119,8 @@ class InitialSetup():
|
|||
nolabel="Addon (Default)",
|
||||
yeslabel="Native (Direct Paths)")
|
||||
if directPaths:
|
||||
self.logMsg("User opted to use direct paths.", 1)
|
||||
utils.settings('useDirectPaths', value="1")
|
||||
log("User opted to use direct paths.", 1)
|
||||
settings('useDirectPaths', value="1")
|
||||
|
||||
# ask for credentials
|
||||
credentials = dialog.yesno(
|
||||
|
@ -138,15 +131,15 @@ class InitialSetup():
|
|||
"during the initial scan of your content if Kodi can't "
|
||||
"locate your content."))
|
||||
if credentials:
|
||||
self.logMsg("Presenting network credentials dialog.", 1)
|
||||
utils.passwordsXML()
|
||||
log("Presenting network credentials dialog.", 1)
|
||||
passwordsXML()
|
||||
|
||||
musicDisabled = dialog.yesno(
|
||||
heading="Music Library",
|
||||
line1="Disable Emby music library?")
|
||||
if musicDisabled:
|
||||
self.logMsg("User opted to disable Emby music library.", 1)
|
||||
utils.settings('enableMusic', value="false")
|
||||
log("User opted to disable Emby music library.", 1)
|
||||
settings('enableMusic', value="false")
|
||||
else:
|
||||
# Only prompt if the user didn't select direct paths for videos
|
||||
if not directPaths:
|
||||
|
@ -157,12 +150,12 @@ class InitialSetup():
|
|||
"this option only if you plan on listening "
|
||||
"to music outside of your network."))
|
||||
if musicAccess:
|
||||
self.logMsg("User opted to direct stream music.", 1)
|
||||
utils.settings('streamMusic', value="true")
|
||||
log("User opted to direct stream music.", 1)
|
||||
settings('streamMusic', value="true")
|
||||
|
||||
def getServerDetails(self):
|
||||
|
||||
self.logMsg("Getting Server Details from Network", 1)
|
||||
log("Getting Server Details from Network", 1)
|
||||
|
||||
MULTI_GROUP = ("<broadcast>", 7359)
|
||||
MESSAGE = "who is EmbyServer?"
|
||||
|
@ -176,15 +169,15 @@ class InitialSetup():
|
|||
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1)
|
||||
|
||||
self.logMsg("MultiGroup : %s" % str(MULTI_GROUP), 2)
|
||||
self.logMsg("Sending UDP Data: %s" % MESSAGE, 2)
|
||||
log("MultiGroup : %s" % str(MULTI_GROUP), 2)
|
||||
log("Sending UDP Data: %s" % MESSAGE, 2)
|
||||
sock.sendto(MESSAGE, MULTI_GROUP)
|
||||
|
||||
try:
|
||||
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
|
||||
self.logMsg("Received Response: %s" % data)
|
||||
log("Received Response: %s" % data)
|
||||
except:
|
||||
self.logMsg("No UDP Response")
|
||||
log("No UDP Response")
|
||||
return None
|
||||
else:
|
||||
# Get the address
|
||||
|
|
|
@ -7,7 +7,7 @@ import xbmc
|
|||
import api
|
||||
import artwork
|
||||
import clientinfo
|
||||
import utils
|
||||
from utils import Logging
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
@ -19,16 +19,14 @@ class Kodidb_Functions():
|
|||
|
||||
def __init__(self, cursor):
|
||||
|
||||
global log
|
||||
log = Logging(self.__class__.__name__).log
|
||||
|
||||
self.cursor = cursor
|
||||
|
||||
self.clientInfo = clientinfo.ClientInfo()
|
||||
self.addonName = self.clientInfo.getAddonName()
|
||||
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):
|
||||
|
@ -153,7 +151,7 @@ class Kodidb_Functions():
|
|||
|
||||
query = "INSERT INTO country(country_id, name) values(?, ?)"
|
||||
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
|
||||
query = (
|
||||
|
@ -187,7 +185,7 @@ class Kodidb_Functions():
|
|||
|
||||
query = "INSERT INTO country(idCountry, strCountry) values(?, ?)"
|
||||
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:
|
||||
# Only movies have a country field
|
||||
|
@ -232,7 +230,7 @@ class Kodidb_Functions():
|
|||
|
||||
query = "INSERT INTO actor(actor_id, name) values(?, ?)"
|
||||
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:
|
||||
# Link person to content
|
||||
|
@ -302,7 +300,7 @@ class Kodidb_Functions():
|
|||
|
||||
query = "INSERT INTO actors(idActor, strActor) values(?, ?)"
|
||||
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:
|
||||
# Link person to content
|
||||
|
@ -462,7 +460,7 @@ class Kodidb_Functions():
|
|||
|
||||
query = "INSERT INTO genre(genre_id, name) values(?, ?)"
|
||||
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:
|
||||
# Assign genre to item
|
||||
|
@ -507,7 +505,7 @@ class Kodidb_Functions():
|
|||
|
||||
query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)"
|
||||
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:
|
||||
# Assign genre to item
|
||||
|
@ -566,7 +564,7 @@ class Kodidb_Functions():
|
|||
|
||||
query = "INSERT INTO studio(studio_id, name) values(?, ?)"
|
||||
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
|
||||
query = (
|
||||
|
@ -597,7 +595,7 @@ class Kodidb_Functions():
|
|||
|
||||
query = "INSERT INTO studio(idstudio, strstudio) values(?, ?)"
|
||||
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
|
||||
if "movie" in mediatype:
|
||||
|
@ -728,7 +726,7 @@ class Kodidb_Functions():
|
|||
self.cursor.execute(query, (kodiid, mediatype))
|
||||
|
||||
# Add tags
|
||||
self.logMsg("Adding Tags: %s" % tags, 2)
|
||||
log("Adding Tags: %s" % tags, 2)
|
||||
for tag in tags:
|
||||
self.addTag(kodiid, tag, mediatype)
|
||||
|
||||
|
@ -750,7 +748,7 @@ class Kodidb_Functions():
|
|||
except TypeError:
|
||||
# Create the tag, because it does not exist
|
||||
tag_id = self.createTag(tag)
|
||||
self.logMsg("Adding tag: %s" % tag, 2)
|
||||
log("Adding tag: %s" % tag, 2)
|
||||
|
||||
finally:
|
||||
# Assign tag to item
|
||||
|
@ -779,7 +777,7 @@ class Kodidb_Functions():
|
|||
except TypeError:
|
||||
# Create the tag
|
||||
tag_id = self.createTag(tag)
|
||||
self.logMsg("Adding tag: %s" % tag, 2)
|
||||
log("Adding tag: %s" % tag, 2)
|
||||
|
||||
finally:
|
||||
# Assign tag to item
|
||||
|
@ -815,7 +813,7 @@ class Kodidb_Functions():
|
|||
|
||||
query = "INSERT INTO tag(tag_id, name) values(?, ?)"
|
||||
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:
|
||||
# Kodi Helix
|
||||
query = ' '.join((
|
||||
|
@ -835,13 +833,13 @@ class Kodidb_Functions():
|
|||
|
||||
query = "INSERT INTO tag(idTag, strTag) values(?, ?)"
|
||||
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
|
||||
|
||||
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):
|
||||
# Kodi Isengard, Jarvis, Krypton
|
||||
|
@ -858,7 +856,7 @@ class Kodidb_Functions():
|
|||
except Exception as e:
|
||||
# The new tag we are going to apply already exists for this item
|
||||
# delete current tag instead
|
||||
self.logMsg("Exception: %s" % e, 1)
|
||||
log("Exception: %s" % e, 1)
|
||||
query = ' '.join((
|
||||
|
||||
"DELETE FROM tag_link",
|
||||
|
@ -882,7 +880,7 @@ class Kodidb_Functions():
|
|||
except Exception as e:
|
||||
# The new tag we are going to apply already exists for this item
|
||||
# delete current tag instead
|
||||
self.logMsg("Exception: %s" % e, 1)
|
||||
log("Exception: %s" % e, 1)
|
||||
query = ' '.join((
|
||||
|
||||
"DELETE FROM taglinks",
|
||||
|
@ -943,7 +941,7 @@ class Kodidb_Functions():
|
|||
|
||||
def createBoxset(self, boxsetname):
|
||||
|
||||
self.logMsg("Adding boxset: %s" % boxsetname, 2)
|
||||
log("Adding boxset: %s" % boxsetname, 2)
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT idSet",
|
||||
|
|
|
@ -11,7 +11,7 @@ import clientinfo
|
|||
import downloadutils
|
||||
import embydb_functions as embydb
|
||||
import playbackutils as pbutils
|
||||
import utils
|
||||
from utils import Logging, window, settings, kodiSQL
|
||||
|
||||
#################################################################################################
|
||||
|
||||
|
@ -21,27 +21,25 @@ class KodiMonitor(xbmc.Monitor):
|
|||
|
||||
def __init__(self):
|
||||
|
||||
global log
|
||||
log = Logging(self.__class__.__name__).log
|
||||
|
||||
self.clientInfo = clientinfo.ClientInfo()
|
||||
self.addonName = self.clientInfo.getAddonName()
|
||||
self.doUtils = downloadutils.DownloadUtils()
|
||||
|
||||
self.logMsg("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)
|
||||
log("Kodi monitor started.", 1)
|
||||
|
||||
|
||||
def onScanStarted(self, library):
|
||||
self.logMsg("Kodi library scan %s running." % library, 2)
|
||||
log("Kodi library scan %s running." % library, 2)
|
||||
if library == "video":
|
||||
utils.window('emby_kodiScan', value="true")
|
||||
window('emby_kodiScan', value="true")
|
||||
|
||||
def onScanFinished(self, library):
|
||||
self.logMsg("Kodi library scan %s finished." % library, 2)
|
||||
log("Kodi library scan %s finished." % library, 2)
|
||||
if library == "video":
|
||||
utils.window('emby_kodiScan', clear=True)
|
||||
window('emby_kodiScan', clear=True)
|
||||
|
||||
def onSettingsChanged(self):
|
||||
# Monitor emby settings
|
||||
|
@ -50,7 +48,7 @@ class KodiMonitor(xbmc.Monitor):
|
|||
'''currentPath = utils.settings('useDirectPaths')
|
||||
if utils.window('emby_pluginpath') != currentPath:
|
||||
# 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)
|
||||
resp = xbmcgui.Dialog().yesno(
|
||||
heading="Playback mode change detected",
|
||||
|
@ -61,17 +59,17 @@ class KodiMonitor(xbmc.Monitor):
|
|||
if resp:
|
||||
utils.reset()'''
|
||||
|
||||
currentLog = utils.settings('logLevel')
|
||||
if utils.window('emby_logLevel') != currentLog:
|
||||
currentLog = settings('logLevel')
|
||||
if window('emby_logLevel') != currentLog:
|
||||
# The log level changed, set new prop
|
||||
self.logMsg("New log level: %s" % currentLog, 1)
|
||||
utils.window('emby_logLevel', value=currentLog)
|
||||
log("New log level: %s" % currentLog, 1)
|
||||
window('emby_logLevel', value=currentLog)
|
||||
|
||||
def onNotification(self, sender, method, data):
|
||||
|
||||
doUtils = self.doUtils
|
||||
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:
|
||||
data = json.loads(data,'utf-8')
|
||||
|
@ -84,23 +82,23 @@ class KodiMonitor(xbmc.Monitor):
|
|||
kodiid = item['id']
|
||||
item_type = item['type']
|
||||
except (KeyError, TypeError):
|
||||
self.logMsg("Item is invalid for playstate update.", 1)
|
||||
log("Item is invalid for playstate update.", 1)
|
||||
else:
|
||||
if ((utils.settings('useDirectPaths') == "1" and not item_type == "song") or
|
||||
(item_type == "song" and utils.settings('enableMusic') == "true")):
|
||||
if ((settings('useDirectPaths') == "1" and not item_type == "song") or
|
||||
(item_type == "song" and settings('enableMusic') == "true")):
|
||||
# Set up properties for player
|
||||
embyconn = utils.kodiSQL('emby')
|
||||
embyconn = kodiSQL('emby')
|
||||
embycursor = embyconn.cursor()
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
|
||||
try:
|
||||
itemid = emby_dbitem[0]
|
||||
except TypeError:
|
||||
self.logMsg("No kodiid returned.", 1)
|
||||
log("No kodiid returned.", 1)
|
||||
else:
|
||||
url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid
|
||||
result = doUtils.downloadUrl(url)
|
||||
self.logMsg("Item: %s" % result, 2)
|
||||
log("Item: %s" % result, 2)
|
||||
|
||||
playurl = None
|
||||
count = 0
|
||||
|
@ -114,12 +112,10 @@ class KodiMonitor(xbmc.Monitor):
|
|||
listItem = xbmcgui.ListItem()
|
||||
playback = pbutils.PlaybackUtils(result)
|
||||
|
||||
if item_type == "song" and utils.settings('streamMusic') == "true":
|
||||
utils.window('emby_%s.playmethod' % playurl,
|
||||
value="DirectStream")
|
||||
if item_type == "song" and settings('streamMusic') == "true":
|
||||
window('emby_%s.playmethod' % playurl, value="DirectStream")
|
||||
else:
|
||||
utils.window('emby_%s.playmethod' % playurl,
|
||||
value="DirectPlay")
|
||||
window('emby_%s.playmethod' % playurl, value="DirectPlay")
|
||||
# Set properties for player.py
|
||||
playback.setProperties(playurl, listItem)
|
||||
finally:
|
||||
|
@ -134,31 +130,31 @@ class KodiMonitor(xbmc.Monitor):
|
|||
kodiid = item['id']
|
||||
item_type = item['type']
|
||||
except (KeyError, TypeError):
|
||||
self.logMsg("Item is invalid for playstate update.", 1)
|
||||
log("Item is invalid for playstate update.", 1)
|
||||
else:
|
||||
# Send notification to the server.
|
||||
embyconn = utils.kodiSQL('emby')
|
||||
embyconn = kodiSQL('emby')
|
||||
embycursor = embyconn.cursor()
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
|
||||
try:
|
||||
itemid = emby_dbitem[0]
|
||||
except TypeError:
|
||||
self.logMsg("Could not find itemid in emby database.", 1)
|
||||
log("Could not find itemid in emby database.", 1)
|
||||
else:
|
||||
# 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
|
||||
utils.window('emby_skipWatched%s' % itemid, clear=True)
|
||||
window('emby_skipWatched%s' % itemid, clear=True)
|
||||
else:
|
||||
# notify the server
|
||||
url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % itemid
|
||||
if playcount != 0:
|
||||
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:
|
||||
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:
|
||||
embycursor.close()
|
||||
|
||||
|
@ -172,7 +168,7 @@ class KodiMonitor(xbmc.Monitor):
|
|||
kodiid = data['id']
|
||||
type = data['type']
|
||||
except (KeyError, TypeError):
|
||||
self.logMsg("Item is invalid for emby deletion.", 1)
|
||||
log("Item is invalid for emby deletion.", 1)
|
||||
else:
|
||||
# Send the delete action to the server.
|
||||
embyconn = utils.kodiSQL('emby')
|
||||
|
@ -182,19 +178,19 @@ class KodiMonitor(xbmc.Monitor):
|
|||
try:
|
||||
itemid = emby_dbitem[0]
|
||||
except TypeError:
|
||||
self.logMsg("Could not find itemid in emby database.", 1)
|
||||
log("Could not find itemid in emby database.", 1)
|
||||
else:
|
||||
if utils.settings('skipContextMenu') != "true":
|
||||
resp = xbmcgui.Dialog().yesno(
|
||||
heading="Confirm delete",
|
||||
line1="Delete file on Emby Server?")
|
||||
if not resp:
|
||||
self.logMsg("User skipped deletion.", 1)
|
||||
log("User skipped deletion.", 1)
|
||||
embycursor.close()
|
||||
return
|
||||
|
||||
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")
|
||||
finally:
|
||||
embycursor.close()'''
|
||||
|
@ -203,13 +199,13 @@ class KodiMonitor(xbmc.Monitor):
|
|||
elif method == "System.OnWake":
|
||||
# Allow network to wake up
|
||||
xbmc.sleep(10000)
|
||||
utils.window('emby_onWake', value="true")
|
||||
window('emby_onWake', value="true")
|
||||
|
||||
|
||||
elif method == "GUI.OnScreensaverDeactivated":
|
||||
if utils.settings('dbSyncScreensaver') == "true":
|
||||
if settings('dbSyncScreensaver') == "true":
|
||||
xbmc.sleep(5000);
|
||||
utils.window('emby_onWake', value="true")
|
||||
window('emby_onWake', value="true")
|
||||
|
||||
|
||||
elif method == "Playlist.OnClear":
|
||||
|
|
|
@ -20,6 +20,7 @@ import kodidb_functions as kodidb
|
|||
import read_embyserver as embyserver
|
||||
import userclient
|
||||
import videonodes
|
||||
from utils import Logging, window, settings, language as lang
|
||||
|
||||
##################################################################################################
|
||||
|
||||
|
@ -42,6 +43,9 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
def __init__(self):
|
||||
|
||||
global log
|
||||
log = Logging(self.__class__.__name__).log
|
||||
|
||||
self.__dict__ = self._shared_state
|
||||
self.monitor = xbmc.Monitor()
|
||||
|
||||
|
@ -54,26 +58,20 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
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):
|
||||
|
||||
dialog = None
|
||||
|
||||
if utils.settings('dbSyncIndicator') == "true" or forced:
|
||||
if settings('dbSyncIndicator') == "true" or forced:
|
||||
dialog = xbmcgui.DialogProgressBG()
|
||||
dialog.create("Emby for Kodi", title)
|
||||
self.logMsg("Show progress dialog: %s" % title, 2)
|
||||
log("Show progress dialog: %s" % title, 2)
|
||||
|
||||
return dialog
|
||||
|
||||
def startSync(self):
|
||||
|
||||
settings = utils.settings
|
||||
# Run at start up - optional to use the server plugin
|
||||
if settings('SyncInstallRunDone') == "true":
|
||||
|
||||
|
@ -88,7 +86,7 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
for plugin in result:
|
||||
if plugin['Name'] == "Emby.Kodi Sync Queue":
|
||||
self.logMsg("Found server plugin.", 2)
|
||||
log("Found server plugin.", 2)
|
||||
completed = self.fastSync()
|
||||
break
|
||||
|
||||
|
@ -103,37 +101,31 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
def fastSync(self):
|
||||
|
||||
lastSync = utils.settings('LastIncrementalSync')
|
||||
lastSync = settings('LastIncrementalSync')
|
||||
if not lastSync:
|
||||
lastSync = "2010-01-01T00:00:00Z"
|
||||
|
||||
lastSyncTime = utils.convertdate(lastSync)
|
||||
self.logMsg("Last sync run: %s" % lastSyncTime, 1)
|
||||
lastSyncTime = utils.convertDate(lastSync)
|
||||
log("Last sync run: %s" % lastSyncTime, 1)
|
||||
|
||||
# get server RetentionDateTime
|
||||
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:
|
||||
retention_time = result['RetentionDateTime']
|
||||
except (TypeError, KeyError):
|
||||
retention_time = "2010-01-01T00:00:00Z"
|
||||
'''
|
||||
|
||||
retention_time = utils.convertdate(retention_time)
|
||||
self.logMsg("RetentionDateTime: %s" % retention_time, 1)
|
||||
retention_time = utils.convertDate(retention_time)
|
||||
log("RetentionDateTime: %s" % retention_time, 1)
|
||||
|
||||
# if last sync before retention time do a full sync
|
||||
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
|
||||
|
||||
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:
|
||||
processlist = {
|
||||
|
@ -145,11 +137,11 @@ class LibrarySync(threading.Thread):
|
|||
}
|
||||
|
||||
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
|
||||
|
||||
else:
|
||||
self.logMsg("Fast sync changes: %s" % result, 1)
|
||||
log("Fast sync changes: %s" % result, 1)
|
||||
for action in processlist:
|
||||
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")
|
||||
try: # datetime fails when used more than once, TypeError
|
||||
server_time = result['ServerDateTime']
|
||||
server_time = utils.convertdate(server_time)
|
||||
server_time = utils.convertDate(server_time)
|
||||
|
||||
except Exception as e:
|
||||
# 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)
|
||||
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:
|
||||
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:
|
||||
utils.settings('LastIncrementalSync', value=lastSync)
|
||||
settings('LastIncrementalSync', value=lastSync)
|
||||
|
||||
def shouldStop(self):
|
||||
# Checkpoint during the syncing process
|
||||
if self.monitor.abortRequested():
|
||||
return True
|
||||
elif utils.window('emby_shouldStop') == "true":
|
||||
elif window('emby_shouldStop') == "true":
|
||||
return True
|
||||
else: # Keep going
|
||||
return False
|
||||
|
||||
def dbCommit(self, connection):
|
||||
|
||||
window = utils.window
|
||||
# Central commit, verifies if Kodi database update is running
|
||||
kodidb_scan = window('emby_kodiScan') == "true"
|
||||
|
||||
while kodidb_scan:
|
||||
|
||||
self.logMsg("Kodi scan is running. Waiting...", 1)
|
||||
log("Kodi scan is running. Waiting...", 1)
|
||||
kodidb_scan = window('emby_kodiScan') == "true"
|
||||
|
||||
if self.shouldStop():
|
||||
self.logMsg("Commit unsuccessful. Sync terminated.", 1)
|
||||
log("Commit unsuccessful. Sync terminated.", 1)
|
||||
break
|
||||
|
||||
if self.monitor.waitForAbort(1):
|
||||
# Abort was requested while waiting. We should exit
|
||||
self.logMsg("Commit unsuccessful.", 1)
|
||||
log("Commit unsuccessful.", 1)
|
||||
break
|
||||
else:
|
||||
connection.commit()
|
||||
self.logMsg("Commit successful.", 1)
|
||||
log("Commit successful.", 1)
|
||||
|
||||
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.
|
||||
music_enabled = utils.settings('enableMusic') == "true"
|
||||
music_enabled = settings('enableMusic') == "true"
|
||||
|
||||
xbmc.executebuiltin('InhibitIdleShutdown(true)')
|
||||
screensaver = utils.getScreensaver()
|
||||
|
@ -284,7 +271,7 @@ class LibrarySync(threading.Thread):
|
|||
self.dbCommit(kodiconn)
|
||||
embyconn.commit()
|
||||
elapsedTime = datetime.now() - startTime
|
||||
self.logMsg("SyncDatabase (finished %s in: %s)"
|
||||
log("SyncDatabase (finished %s in: %s)"
|
||||
% (itemtype, str(elapsedTime).split('.')[0]), 1)
|
||||
else:
|
||||
# Close the Kodi cursor
|
||||
|
@ -312,7 +299,7 @@ class LibrarySync(threading.Thread):
|
|||
musicconn.commit()
|
||||
embyconn.commit()
|
||||
elapsedTime = datetime.now() - startTime
|
||||
self.logMsg("SyncDatabase (finished music in: %s)"
|
||||
log("SyncDatabase (finished music in: %s)"
|
||||
% (str(elapsedTime).split('.')[0]), 1)
|
||||
musiccursor.close()
|
||||
|
||||
|
@ -335,7 +322,7 @@ class LibrarySync(threading.Thread):
|
|||
xbmcgui.Dialog().notification(
|
||||
heading="Emby for Kodi",
|
||||
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",
|
||||
sound=False)
|
||||
return True
|
||||
|
@ -378,7 +365,7 @@ class LibrarySync(threading.Thread):
|
|||
if view['type'] == "mixed":
|
||||
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
|
||||
self.vnodes.clearProperties()
|
||||
|
@ -415,7 +402,8 @@ class LibrarySync(threading.Thread):
|
|||
'Limit': 1,
|
||||
'IncludeItemTypes': emby_mediatypes[mediatype]
|
||||
} # 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:
|
||||
verifyitem = result['Items'][0]['Id']
|
||||
except (TypeError, IndexError):
|
||||
|
@ -430,14 +418,14 @@ class LibrarySync(threading.Thread):
|
|||
# Take the userview, and validate the item belong to the view
|
||||
if self.emby.verifyView(grouped_view['Id'], verifyitem):
|
||||
# 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)
|
||||
foldername = grouped_view['Name']
|
||||
break
|
||||
else:
|
||||
# Unable to find a match, add the name to our sorted_view list
|
||||
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
|
||||
try:
|
||||
|
@ -453,7 +441,7 @@ class LibrarySync(threading.Thread):
|
|||
current_tagid = view[2]
|
||||
|
||||
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)
|
||||
# Create playlist for the video library
|
||||
if (foldername not in playlists and
|
||||
|
@ -472,7 +460,7 @@ class LibrarySync(threading.Thread):
|
|||
emby_db.addView(folderid, foldername, viewtype, tagid)
|
||||
|
||||
else:
|
||||
self.logMsg(' '.join((
|
||||
log(' '.join((
|
||||
|
||||
"Found viewid: %s" % folderid,
|
||||
"viewname: %s" % current_viewname,
|
||||
|
@ -488,7 +476,7 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
# View was modified, update with latest info
|
||||
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)
|
||||
|
||||
# Update view with new info
|
||||
|
@ -556,20 +544,19 @@ class LibrarySync(threading.Thread):
|
|||
utils.window('Emby.nodes.total', str(totalnodes))
|
||||
|
||||
# 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:
|
||||
emby_db.removeView(view)
|
||||
|
||||
def movies(self, embycursor, kodicursor, pdialog):
|
||||
|
||||
lang = utils.language
|
||||
# Get movies from emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
movies = itemtypes.Movies(embycursor, kodicursor)
|
||||
|
||||
views = emby_db.getView_byType('movies')
|
||||
views += emby_db.getView_byType('mixed')
|
||||
self.logMsg("Media folders: %s" % views, 1)
|
||||
log("Media folders: %s" % views, 1)
|
||||
|
||||
##### PROCESS MOVIES #####
|
||||
for view in views:
|
||||
|
@ -604,7 +591,7 @@ class LibrarySync(threading.Thread):
|
|||
count += 1
|
||||
movies.add_update(embymovie, view['name'], view['id'])
|
||||
else:
|
||||
self.logMsg("Movies finished.", 2)
|
||||
log("Movies finished.", 2)
|
||||
|
||||
|
||||
##### PROCESS BOXSETS #####
|
||||
|
@ -631,7 +618,7 @@ class LibrarySync(threading.Thread):
|
|||
count += 1
|
||||
movies.add_updateBoxset(boxset)
|
||||
else:
|
||||
self.logMsg("Boxsets finished.", 2)
|
||||
log("Boxsets finished.", 2)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -642,7 +629,7 @@ class LibrarySync(threading.Thread):
|
|||
mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
|
||||
|
||||
views = emby_db.getView_byType('musicvideos')
|
||||
self.logMsg("Media folders: %s" % views, 1)
|
||||
log("Media folders: %s" % views, 1)
|
||||
|
||||
for view in views:
|
||||
|
||||
|
@ -656,7 +643,7 @@ class LibrarySync(threading.Thread):
|
|||
if pdialog:
|
||||
pdialog.update(
|
||||
heading="Emby for Kodi",
|
||||
message="%s %s..." % (utils.language(33019), viewName))
|
||||
message="%s %s..." % (lang(33019), viewName))
|
||||
|
||||
# Initial or repair sync
|
||||
all_embymvideos = self.emby.getMusicVideos(viewId, dialog=pdialog)
|
||||
|
@ -679,7 +666,7 @@ class LibrarySync(threading.Thread):
|
|||
count += 1
|
||||
mvideos.add_update(embymvideo, viewName, viewId)
|
||||
else:
|
||||
self.logMsg("MusicVideos finished.", 2)
|
||||
log("MusicVideos finished.", 2)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -691,7 +678,7 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
views = emby_db.getView_byType('tvshows')
|
||||
views += emby_db.getView_byType('mixed')
|
||||
self.logMsg("Media folders: %s" % views, 1)
|
||||
log("Media folders: %s" % views, 1)
|
||||
|
||||
for view in views:
|
||||
|
||||
|
@ -702,7 +689,7 @@ class LibrarySync(threading.Thread):
|
|||
if pdialog:
|
||||
pdialog.update(
|
||||
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)
|
||||
total = all_embytvshows['TotalRecordCount']
|
||||
|
@ -737,7 +724,7 @@ class LibrarySync(threading.Thread):
|
|||
pdialog.update(percentage, message="%s - %s" % (title, episodetitle))
|
||||
tvshows.add_updateEpisode(episode)
|
||||
else:
|
||||
self.logMsg("TVShows finished.", 2)
|
||||
log("TVShows finished.", 2)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -757,7 +744,7 @@ class LibrarySync(threading.Thread):
|
|||
if pdialog:
|
||||
pdialog.update(
|
||||
heading="Emby for Kodi",
|
||||
message="%s %s..." % (utils.language(33021), itemtype))
|
||||
message="%s %s..." % (lang(33021), itemtype))
|
||||
|
||||
all_embyitems = process[itemtype][0](dialog=pdialog)
|
||||
total = all_embyitems['TotalRecordCount']
|
||||
|
@ -778,7 +765,7 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
process[itemtype][1](embyitem)
|
||||
else:
|
||||
self.logMsg("%s finished." % itemtype, 2)
|
||||
log("%s finished." % itemtype, 2)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -799,7 +786,7 @@ class LibrarySync(threading.Thread):
|
|||
itemids.append(item['ItemId'])
|
||||
items = itemids
|
||||
|
||||
self.logMsg("Queue %s: %s" % (process, items), 1)
|
||||
log("Queue %s: %s" % (process, items), 1)
|
||||
processlist[process].extend(items)
|
||||
|
||||
def incrementalSync(self):
|
||||
|
@ -833,7 +820,7 @@ class LibrarySync(threading.Thread):
|
|||
}
|
||||
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])
|
||||
del process[process_type][:] # Reset class list
|
||||
|
@ -871,7 +858,7 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
if update_embydb:
|
||||
update_embydb = False
|
||||
self.logMsg("Updating emby database.", 1)
|
||||
log("Updating emby database.", 1)
|
||||
embyconn.commit()
|
||||
self.saveLastSync()
|
||||
|
||||
|
@ -880,8 +867,8 @@ class LibrarySync(threading.Thread):
|
|||
self.forceLibraryUpdate = False
|
||||
self.dbCommit(kodiconn)
|
||||
|
||||
self.logMsg("Updating video library.", 1)
|
||||
utils.window('emby_kodiScan', value="true")
|
||||
log("Updating video library.", 1)
|
||||
window('emby_kodiScan', value="true")
|
||||
xbmc.executebuiltin('UpdateLibrary(video)')
|
||||
|
||||
if pDialog:
|
||||
|
@ -893,7 +880,7 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
def compareDBVersion(self, current, minimum):
|
||||
# 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(".")
|
||||
minMajor, minMinor, minPatch = minimum.split(".")
|
||||
|
||||
|
@ -911,7 +898,7 @@ class LibrarySync(threading.Thread):
|
|||
try:
|
||||
self.run_internal()
|
||||
except Exception as e:
|
||||
utils.window('emby_dbScan', clear=True)
|
||||
window('emby_dbScan', clear=True)
|
||||
xbmcgui.Dialog().ok(
|
||||
heading="Emby for Kodi",
|
||||
line1=(
|
||||
|
@ -922,14 +909,11 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
def run_internal(self):
|
||||
|
||||
lang = utils.language
|
||||
window = utils.window
|
||||
settings = utils.settings
|
||||
dialog = xbmcgui.Dialog()
|
||||
|
||||
startupComplete = False
|
||||
|
||||
self.logMsg("---===### Starting LibrarySync ###===---", 0)
|
||||
log("---===### Starting LibrarySync ###===---", 0)
|
||||
|
||||
while not self.monitor.abortRequested():
|
||||
|
||||
|
@ -947,12 +931,12 @@ class LibrarySync(threading.Thread):
|
|||
uptoDate = self.compareDBVersion(currentVersion, minVersion)
|
||||
|
||||
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)
|
||||
|
||||
resp = dialog.yesno("Emby for Kodi", lang(33022))
|
||||
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))
|
||||
else:
|
||||
utils.reset()
|
||||
|
@ -967,7 +951,7 @@ class LibrarySync(threading.Thread):
|
|||
videoDb = utils.getKodiVideoDBPath()
|
||||
if not xbmcvfs.exists(videoDb):
|
||||
# Database does not exists
|
||||
self.logMsg(
|
||||
log(
|
||||
"The current Kodi version is incompatible "
|
||||
"with the Emby for Kodi add-on. Please visit "
|
||||
"https://github.com/MediaBrowser/Emby.Kodi/wiki "
|
||||
|
@ -979,12 +963,12 @@ class LibrarySync(threading.Thread):
|
|||
break
|
||||
|
||||
# Run start up sync
|
||||
self.logMsg("Database version: %s" % settings('dbCreatedWithVersion'), 0)
|
||||
self.logMsg("SyncDatabase (started)", 1)
|
||||
log("Database version: %s" % settings('dbCreatedWithVersion'), 0)
|
||||
log("SyncDatabase (started)", 1)
|
||||
startTime = datetime.now()
|
||||
librarySync = self.startSync()
|
||||
elapsedTime = datetime.now() - startTime
|
||||
self.logMsg("SyncDatabase (finished in: %s) %s"
|
||||
log("SyncDatabase (finished in: %s) %s"
|
||||
% (str(elapsedTime).split('.')[0], librarySync), 1)
|
||||
# Only try the initial sync once per kodi session regardless
|
||||
# This will prevent an infinite loop in case something goes wrong.
|
||||
|
@ -999,32 +983,32 @@ class LibrarySync(threading.Thread):
|
|||
# Set in kodimonitor.py
|
||||
window('emby_onWake', clear=True)
|
||||
if window('emby_syncRunning') != "true":
|
||||
self.logMsg("SyncDatabase onWake (started)", 0)
|
||||
log("SyncDatabase onWake (started)", 0)
|
||||
librarySync = self.startSync()
|
||||
self.logMsg("SyncDatabase onWake (finished) %s" % librarySync, 0)
|
||||
log("SyncDatabase onWake (finished) %s" % librarySync, 0)
|
||||
|
||||
if self.stop_thread:
|
||||
# Set in service.py
|
||||
self.logMsg("Service terminated thread.", 2)
|
||||
log("Service terminated thread.", 2)
|
||||
break
|
||||
|
||||
if self.monitor.waitForAbort(1):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
|
||||
self.logMsg("###===--- LibrarySync Stopped ---===###", 0)
|
||||
log("###===--- LibrarySync Stopped ---===###", 0)
|
||||
|
||||
def stopThread(self):
|
||||
self.stop_thread = True
|
||||
self.logMsg("Ending thread...", 2)
|
||||
log("Ending thread...", 2)
|
||||
|
||||
def suspendThread(self):
|
||||
self.suspend_thread = True
|
||||
self.logMsg("Pausing thread...", 0)
|
||||
log("Pausing thread...", 0)
|
||||
|
||||
def resumeThread(self):
|
||||
self.suspend_thread = False
|
||||
self.logMsg("Resuming thread...", 0)
|
||||
log("Resuming thread...", 0)
|
||||
|
||||
|
||||
class ManualSync(LibrarySync):
|
||||
|
@ -1041,14 +1025,13 @@ class ManualSync(LibrarySync):
|
|||
|
||||
def movies(self, embycursor, kodicursor, pdialog):
|
||||
|
||||
lang = utils.language
|
||||
# Get movies from emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
movies = itemtypes.Movies(embycursor, kodicursor)
|
||||
|
||||
views = emby_db.getView_byType('movies')
|
||||
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
|
||||
try:
|
||||
|
@ -1095,7 +1078,7 @@ class ManualSync(LibrarySync):
|
|||
# Only update if movie is not in Kodi or checksum is different
|
||||
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)
|
||||
total = len(updatelist)
|
||||
del updatelist[:]
|
||||
|
@ -1137,7 +1120,7 @@ class ManualSync(LibrarySync):
|
|||
updatelist.append(itemid)
|
||||
embyboxsets.append(boxset)
|
||||
|
||||
self.logMsg("Boxsets to update: %s" % updatelist, 1)
|
||||
log("Boxsets to update: %s" % updatelist, 1)
|
||||
total = len(updatelist)
|
||||
|
||||
if pdialog:
|
||||
|
@ -1161,13 +1144,13 @@ class ManualSync(LibrarySync):
|
|||
if kodimovie not in all_embymoviesIds:
|
||||
movies.remove(kodimovie)
|
||||
else:
|
||||
self.logMsg("Movies compare finished.", 1)
|
||||
log("Movies compare finished.", 1)
|
||||
|
||||
for boxset in all_kodisets:
|
||||
if boxset not in all_embyboxsetsIds:
|
||||
movies.remove(boxset)
|
||||
else:
|
||||
self.logMsg("Boxsets compare finished.", 1)
|
||||
log("Boxsets compare finished.", 1)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -1178,7 +1161,7 @@ class ManualSync(LibrarySync):
|
|||
mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
|
||||
|
||||
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
|
||||
try:
|
||||
|
@ -1201,7 +1184,7 @@ class ManualSync(LibrarySync):
|
|||
if pdialog:
|
||||
pdialog.update(
|
||||
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)
|
||||
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
|
||||
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)
|
||||
total = len(updatelist)
|
||||
del updatelist[:]
|
||||
|
@ -1245,20 +1228,19 @@ class ManualSync(LibrarySync):
|
|||
if kodimvideo not in all_embymvideosIds:
|
||||
mvideos.remove(kodimvideo)
|
||||
else:
|
||||
self.logMsg("MusicVideos compare finished.", 1)
|
||||
log("MusicVideos compare finished.", 1)
|
||||
|
||||
return True
|
||||
|
||||
def tvshows(self, embycursor, kodicursor, pdialog):
|
||||
|
||||
lang = utils.language
|
||||
# Get shows from emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
tvshows = itemtypes.TVShows(embycursor, kodicursor)
|
||||
|
||||
views = emby_db.getView_byType('tvshows')
|
||||
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
|
||||
try:
|
||||
|
@ -1305,7 +1287,7 @@ class ManualSync(LibrarySync):
|
|||
# Only update if movie is not in Kodi or checksum is different
|
||||
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)
|
||||
total = len(updatelist)
|
||||
del updatelist[:]
|
||||
|
@ -1349,7 +1331,7 @@ class ManualSync(LibrarySync):
|
|||
# Only update if movie is not in Kodi or checksum is different
|
||||
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)
|
||||
total = len(updatelist)
|
||||
del updatelist[:]
|
||||
|
@ -1374,13 +1356,13 @@ class ManualSync(LibrarySync):
|
|||
if koditvshow not in all_embytvshowsIds:
|
||||
tvshows.remove(koditvshow)
|
||||
else:
|
||||
self.logMsg("TVShows compare finished.", 1)
|
||||
log("TVShows compare finished.", 1)
|
||||
|
||||
for kodiepisode in all_kodiepisodes:
|
||||
if kodiepisode not in all_embyepisodesIds:
|
||||
tvshows.remove(kodiepisode)
|
||||
else:
|
||||
self.logMsg("Episodes compare finished.", 1)
|
||||
log("Episodes compare finished.", 1)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -1421,7 +1403,7 @@ class ManualSync(LibrarySync):
|
|||
if pdialog:
|
||||
pdialog.update(
|
||||
heading="Emby for Kodi",
|
||||
message="%s %s..." % (utils.language(33031), data_type))
|
||||
message="%s %s..." % (lang(33031), data_type))
|
||||
if data_type != "artists":
|
||||
all_embyitems = process[data_type][0](basic=True, dialog=pdialog)
|
||||
else:
|
||||
|
@ -1446,7 +1428,7 @@ class ManualSync(LibrarySync):
|
|||
if all_kodisongs.get(itemid) != API.getChecksum():
|
||||
# Only update if songs is not in Kodi or checksum is different
|
||||
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)
|
||||
total = len(updatelist)
|
||||
del updatelist[:]
|
||||
|
@ -1467,15 +1449,15 @@ class ManualSync(LibrarySync):
|
|||
if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None:
|
||||
music.remove(kodiartist)
|
||||
else:
|
||||
self.logMsg("Artist compare finished.", 1)
|
||||
log("Artist compare finished.", 1)
|
||||
for kodialbum in all_kodialbums:
|
||||
if kodialbum not in all_embyalbumsIds:
|
||||
music.remove(kodialbum)
|
||||
else:
|
||||
self.logMsg("Albums compare finished.", 1)
|
||||
log("Albums compare finished.", 1)
|
||||
for kodisong in all_kodisongs:
|
||||
if kodisong not in all_embysongsIds:
|
||||
music.remove(kodisong)
|
||||
else:
|
||||
self.logMsg("Songs compare finished.", 1)
|
||||
return True
|
||||
log("Songs compare finished.", 1)
|
||||
return True
|
|
@ -14,20 +14,18 @@ from mutagen import id3
|
|||
import base64
|
||||
|
||||
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
|
||||
|
||||
def logMsg(msg, lvl=1):
|
||||
utils.logMsg("%s %s" % ("Emby", "musictools"), msg, lvl)
|
||||
log = Logging('MusicTools').log
|
||||
|
||||
def getRealFileName(filename, isTemp=False):
|
||||
#get the filename path accessible by python if possible...
|
||||
|
||||
if not xbmcvfs.exists(filename):
|
||||
logMsg( "File does not exist! %s" %(filename), 0)
|
||||
log("File does not exist! %s" % filename, 0)
|
||||
return (False, "")
|
||||
|
||||
#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:
|
||||
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
|
||||
updateEmbyRating = False
|
||||
|
@ -171,7 +169,7 @@ def getAdditionalSongTags(embyid, emby_rating, API, kodicursor, emby_db, enablei
|
|||
if updateEmbyRating and enableexportsongrating:
|
||||
# sync details to emby server. Translation needed between ID3 rating and emby likes/favourites:
|
||||
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)
|
||||
|
||||
return (rating, comment, hasEmbeddedCover)
|
||||
|
@ -183,7 +181,7 @@ def getSongTags(file):
|
|||
hasEmbeddedCover = False
|
||||
|
||||
isTemp,filename = getRealFileName(file)
|
||||
logMsg( "getting song ID3 tags for " + filename)
|
||||
log( "getting song ID3 tags for " + filename)
|
||||
|
||||
try:
|
||||
###### FLAC FILES #############
|
||||
|
@ -217,14 +215,14 @@ def getSongTags(file):
|
|||
#POPM rating is 0-255 and needs to be converted to 0-5 range
|
||||
if rating > 5: rating = (rating / 255) * 5
|
||||
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
|
||||
rating = int(round(rating,0))
|
||||
|
||||
except Exception as e:
|
||||
#file in use ?
|
||||
utils.logMsg("Exception in getSongTags", str(e),0)
|
||||
log("Exception in getSongTags", str(e),0)
|
||||
rating = None
|
||||
|
||||
#remove tempfile if needed....
|
||||
|
@ -246,7 +244,7 @@ def updateRatingToFile(rating, file):
|
|||
xbmcvfs.copy(file, tempfile)
|
||||
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:
|
||||
return
|
||||
|
@ -263,7 +261,7 @@ def updateRatingToFile(rating, file):
|
|||
audio.add(id3.POPM(email="Windows Media Player 9 Series", rating=calcrating, count=1))
|
||||
audio.save()
|
||||
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
|
||||
#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.copy(tempfile,file)
|
||||
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
|
||||
xbmcvfs.delete(tempfile)
|
||||
|
||||
except Exception as e:
|
||||
#file in use ?
|
||||
logMsg("Exception in updateRatingToFile %s" %e,0)
|
||||
log("Exception in updateRatingToFile %s" %e,0)
|
||||
|
||||
|
||||
|
|
@ -7,11 +7,11 @@ import json
|
|||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
import utils
|
||||
import clientinfo
|
||||
import downloadutils
|
||||
import kodidb_functions as kodidb
|
||||
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):
|
||||
|
||||
global log
|
||||
log = Logging(self.__class__.__name__).log
|
||||
|
||||
self.__dict__ = self._shared_state
|
||||
|
||||
self.clientInfo = clientinfo.ClientInfo()
|
||||
|
@ -36,20 +39,13 @@ class Player(xbmc.Player):
|
|||
self.ws = wsc.WebSocket_Client()
|
||||
self.xbmcplayer = xbmc.Player()
|
||||
|
||||
self.logMsg("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)
|
||||
log("Starting playback monitor.", 2)
|
||||
|
||||
|
||||
def GetPlayStats(self):
|
||||
return self.playStats
|
||||
|
||||
def onPlayBackStarted(self):
|
||||
|
||||
window = utils.window
|
||||
# Will be called when xbmc starts playing a file
|
||||
self.stopAll()
|
||||
|
||||
|
@ -67,7 +63,7 @@ class Player(xbmc.Player):
|
|||
except: pass
|
||||
|
||||
if count == 5: # try 5 times
|
||||
self.logMsg("Cancelling playback report...", 1)
|
||||
log("Cancelling playback report...", 1)
|
||||
break
|
||||
else: count += 1
|
||||
|
||||
|
@ -84,12 +80,12 @@ class Player(xbmc.Player):
|
|||
xbmc.sleep(200)
|
||||
itemId = window("emby_%s.itemid" % currentFile)
|
||||
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
|
||||
else: tryCount += 1
|
||||
|
||||
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.
|
||||
embyitem = "emby_%s" % currentFile
|
||||
|
@ -102,7 +98,7 @@ class Player(xbmc.Player):
|
|||
customseek = window('emby_customPlaylist.seektime')
|
||||
if window('emby_customPlaylist') == "true" and customseek:
|
||||
# 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)
|
||||
window('emby_customPlaylist.seektime', clear=True)
|
||||
|
||||
|
@ -189,7 +185,7 @@ class Player(xbmc.Player):
|
|||
|
||||
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)
|
||||
|
||||
if externalIndex.get(str(indexSubs)):
|
||||
|
@ -207,7 +203,7 @@ class Player(xbmc.Player):
|
|||
|
||||
|
||||
# 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")
|
||||
|
||||
# Ensure we do have a runtime
|
||||
|
@ -215,7 +211,7 @@ class Player(xbmc.Player):
|
|||
runtime = int(runtime)
|
||||
except ValueError:
|
||||
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
|
||||
data = {
|
||||
|
@ -232,7 +228,7 @@ class Player(xbmc.Player):
|
|||
}
|
||||
|
||||
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
|
||||
'''if(itemType != None):
|
||||
|
@ -251,7 +247,7 @@ class Player(xbmc.Player):
|
|||
|
||||
def reportPlayback(self):
|
||||
|
||||
self.logMsg("reportPlayback Called", 2)
|
||||
log("reportPlayback Called", 2)
|
||||
|
||||
# Get current file
|
||||
currentFile = self.currentFile
|
||||
|
@ -345,11 +341,11 @@ class Player(xbmc.Player):
|
|||
|
||||
# Number of audiotracks to help get Emby Index
|
||||
audioTracks = len(xbmc.Player().getAvailableAudioStreams())
|
||||
mapping = utils.window("emby_%s.indexMapping" % currentFile)
|
||||
mapping = window("emby_%s.indexMapping" % currentFile)
|
||||
|
||||
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)
|
||||
|
||||
if externalIndex.get(str(indexSubs)):
|
||||
|
@ -369,13 +365,13 @@ class Player(xbmc.Player):
|
|||
|
||||
# Report progress via websocketclient
|
||||
postdata = json.dumps(postdata)
|
||||
self.logMsg("Report: %s" % postdata, 2)
|
||||
log("Report: %s" % postdata, 2)
|
||||
self.ws.sendProgressUpdate(postdata)
|
||||
|
||||
def onPlayBackPaused(self):
|
||||
|
||||
currentFile = self.currentFile
|
||||
self.logMsg("PLAYBACK_PAUSED: %s" % currentFile, 2)
|
||||
log("PLAYBACK_PAUSED: %s" % currentFile, 2)
|
||||
|
||||
if self.played_info.get(currentFile):
|
||||
self.played_info[currentFile]['paused'] = True
|
||||
|
@ -385,7 +381,7 @@ class Player(xbmc.Player):
|
|||
def onPlayBackResumed(self):
|
||||
|
||||
currentFile = self.currentFile
|
||||
self.logMsg("PLAYBACK_RESUMED: %s" % currentFile, 2)
|
||||
log("PLAYBACK_RESUMED: %s" % currentFile, 2)
|
||||
|
||||
if self.played_info.get(currentFile):
|
||||
self.played_info[currentFile]['paused'] = False
|
||||
|
@ -395,7 +391,7 @@ class Player(xbmc.Player):
|
|||
def onPlayBackSeek(self, time, seekOffset):
|
||||
# Make position when seeking a bit more accurate
|
||||
currentFile = self.currentFile
|
||||
self.logMsg("PLAYBACK_SEEK: %s" % currentFile, 2)
|
||||
log("PLAYBACK_SEEK: %s" % currentFile, 2)
|
||||
|
||||
if self.played_info.get(currentFile):
|
||||
position = self.xbmcplayer.getTime()
|
||||
|
@ -404,39 +400,34 @@ class Player(xbmc.Player):
|
|||
self.reportPlayback()
|
||||
|
||||
def onPlayBackStopped(self):
|
||||
|
||||
window = utils.window
|
||||
# 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.seektime', clear=True)
|
||||
window('emby_playbackProps', clear=True)
|
||||
self.logMsg("Clear playlist properties.", 1)
|
||||
log("Clear playlist properties.", 1)
|
||||
self.stopAll()
|
||||
|
||||
def onPlayBackEnded(self):
|
||||
# Will be called when xbmc stops playing a file
|
||||
self.logMsg("ONPLAYBACK_ENDED", 2)
|
||||
utils.window('emby_customPlaylist.seektime', clear=True)
|
||||
log("ONPLAYBACK_ENDED", 2)
|
||||
window('emby_customPlaylist.seektime', clear=True)
|
||||
self.stopAll()
|
||||
|
||||
def stopAll(self):
|
||||
|
||||
lang = utils.language
|
||||
settings = utils.settings
|
||||
|
||||
if not self.played_info:
|
||||
return
|
||||
|
||||
self.logMsg("Played_information: %s" % self.played_info, 1)
|
||||
log("Played_information: %s" % self.played_info, 1)
|
||||
# Process each items
|
||||
for item in self.played_info:
|
||||
|
||||
data = self.played_info.get(item)
|
||||
if data:
|
||||
|
||||
self.logMsg("Item path: %s" % item, 2)
|
||||
self.logMsg("Item data: %s" % data, 2)
|
||||
log("Item path: %s" % item, 2)
|
||||
log("Item data: %s" % data, 2)
|
||||
|
||||
runtime = data['runtime']
|
||||
currentPosition = data['currentPosition']
|
||||
|
@ -447,7 +438,7 @@ class Player(xbmc.Player):
|
|||
playMethod = data['playmethod']
|
||||
|
||||
# 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:
|
||||
try:
|
||||
|
@ -457,7 +448,7 @@ class Player(xbmc.Player):
|
|||
percentComplete = 0
|
||||
|
||||
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)
|
||||
|
||||
# Send the delete action to the server.
|
||||
|
@ -475,18 +466,18 @@ class Player(xbmc.Player):
|
|||
if percentComplete >= markPlayedAt and offerDelete:
|
||||
resp = xbmcgui.Dialog().yesno(lang(30091), lang(33015), autoclose=120000)
|
||||
if not resp:
|
||||
self.logMsg("User skipped deletion.", 1)
|
||||
log("User skipped deletion.", 1)
|
||||
continue
|
||||
|
||||
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.stopPlayback(data)
|
||||
|
||||
# Stop transcoding
|
||||
if playMethod == "Transcode":
|
||||
self.logMsg("Transcoding for %s terminated." % itemid, 1)
|
||||
log("Transcoding for %s terminated." % itemid, 1)
|
||||
deviceId = self.clientInfo.getDeviceId()
|
||||
url = "{server}/emby/Videos/ActiveEncodings?DeviceId=%s" % deviceId
|
||||
self.doUtils(url, action_type="DELETE")
|
||||
|
@ -495,7 +486,7 @@ class Player(xbmc.Player):
|
|||
|
||||
def stopPlayback(self, data):
|
||||
|
||||
self.logMsg("stopPlayback called", 2)
|
||||
log("stopPlayback called", 2)
|
||||
|
||||
itemId = data['item_id']
|
||||
currentPosition = data['currentPosition']
|
||||
|
|
|
@ -188,7 +188,7 @@ def setScreensaver(value):
|
|||
result = xbmc.executeJSONRPC(json.dumps(query))
|
||||
log("Toggling screensaver: %s %s" % (value, result), 1)
|
||||
|
||||
def convertdate(date):
|
||||
def convertDate(date):
|
||||
try:
|
||||
date = datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ")
|
||||
except TypeError:
|
||||
|
|
Loading…
Reference in a new issue