Merge pull request #31 from Meta-Man/dev2

Dev2
This commit is contained in:
Ian Mclaughlin 2016-04-12 15:50:53 +01:00
commit bec455e8f7
24 changed files with 12471 additions and 12835 deletions

View file

@ -143,7 +143,7 @@ if __name__ == '__main__':
doUtils = downloadutils.DownloadUtils() doUtils = downloadutils.DownloadUtils()
url = "{server}/emby/Items/%s?format=json" % embyid url = "{server}/emby/Items/%s?format=json" % embyid
logMsg("Deleting request: %s" % embyid, 0) logMsg("Deleting request: %s" % embyid, 0)
doUtils.downloadUrl(url, type="DELETE") doUtils.downloadUrl(url, action_type="DELETE")
'''if utils.settings('skipContextMenu') != "true": '''if utils.settings('skipContextMenu') != "true":
if xbmcgui.Dialog().yesno( if xbmcgui.Dialog().yesno(
@ -152,8 +152,7 @@ if __name__ == '__main__':
"also delete the file(s) from disk!")): "also delete the file(s) from disk!")):
import downloadutils import downloadutils
doUtils = downloadutils.DownloadUtils() doUtils = downloadutils.DownloadUtils()
url = "{server}/emby/Items/%s?format=json" % embyid doUtils.downloadUrl("{server}/emby/Items/%s?format=json" % embyid, action_type="DELETE")'''
doUtils.downloadUrl(url, type="DELETE")'''
xbmc.sleep(500) xbmc.sleep(500)
xbmc.executebuiltin("Container.Update") xbmc.executebuiltin("Container.Update")

View file

@ -323,7 +323,7 @@
<string id="33020">Gathering tv shows from:</string> <string id="33020">Gathering tv shows from:</string>
<string id="33021">Gathering:</string> <string id="33021">Gathering:</string>
<string id="33022">Detected the database needs to be recreated for this version of Emby for Kodi. Proceed?</string> <string id="33022">Detected the database needs to be recreated for this version of Emby for Kodi. Proceed?</string>
<string id="33023">Emby for Kod may not work correctly until the database is reset.</string> <string id="33023">Emby for Kodi may not work correctly until the database is reset.</string>
<string id="33024">Cancelling the database syncing process. The current Kodi version is unsupported.</string> <string id="33024">Cancelling the database syncing process. The current Kodi version is unsupported.</string>
<string id="33025">completed in:</string> <string id="33025">completed in:</string>
<string id="33026">Comparing movies from:</string> <string id="33026">Comparing movies from:</string>

View file

@ -116,17 +116,16 @@ class API():
} }
def getMediaStreams(self): def getMediaStreams(self):
item = self.item
videotracks = [] videotracks = []
audiotracks = [] audiotracks = []
subtitlelanguages = [] subtitlelanguages = []
try: try:
media_streams = item['MediaSources'][0]['MediaStreams'] media_streams = self.item['MediaSources'][0]['MediaStreams']
except KeyError: except KeyError:
if not item.get("MediaStreams"): return None if not self.item.get("MediaStreams"): return None
media_streams = item['MediaStreams'] media_streams = self.item['MediaStreams']
for media_stream in media_streams: for media_stream in media_streams:
# Sort through Video, Audio, Subtitle # Sort through Video, Audio, Subtitle
@ -141,12 +140,12 @@ class API():
'codec': codec, 'codec': codec,
'height': media_stream.get('Height'), 'height': media_stream.get('Height'),
'width': media_stream.get('Width'), 'width': media_stream.get('Width'),
'video3DFormat': item.get('Video3DFormat'), 'video3DFormat': self.item.get('Video3DFormat'),
'aspect': 1.85 'aspect': 1.85
} }
try: try:
container = item['MediaSources'][0]['Container'].lower() container = self.item['MediaSources'][0]['Container'].lower()
except: except:
container = "" container = ""
@ -161,9 +160,9 @@ class API():
track['codec'] = "avc1" track['codec'] = "avc1"
# Aspect ratio # Aspect ratio
if item.get('AspectRatio'): if self.item.get('AspectRatio'):
# Metadata AR # Metadata AR
aspect = item['AspectRatio'] aspect = self.item['AspectRatio']
else: # File AR else: # File AR
aspect = media_stream.get('AspectRatio', "0") aspect = media_stream.get('AspectRatio', "0")
@ -180,8 +179,8 @@ class API():
else: else:
track['aspect'] = 1.85 track['aspect'] = 1.85
if item.get("RunTimeTicks"): if self.item.get("RunTimeTicks"):
track['duration'] = item.get("RunTimeTicks") / 10000000.0 track['duration'] = self.item.get("RunTimeTicks") / 10000000.0
videotracks.append(track) videotracks.append(track)
@ -211,12 +210,11 @@ class API():
} }
def getRuntime(self): def getRuntime(self):
item = self.item
try: try:
runtime = item['RunTimeTicks'] / 10000000.0 runtime = self.item['RunTimeTicks'] / 10000000.0
except KeyError: except KeyError:
runtime = item.get('CumulativeRunTimeTicks', 0) / 10000000.0 runtime = self.item.get('CumulativeRunTimeTicks', 0) / 10000000.0
return runtime return runtime
@ -234,15 +232,14 @@ class API():
def getStudios(self): def getStudios(self):
# Process Studios # Process Studios
item = self.item
studios = [] studios = []
try: try:
studio = item['SeriesStudio'] studio = self.item['SeriesStudio']
studios.append(self.verifyStudio(studio)) studios.append(self.verifyStudio(studio))
except KeyError: except KeyError:
studioList = item['Studios'] studioList = self.item['Studios']
for studio in studioList: for studio in studioList:
name = studio['Name'] name = studio['Name']
@ -265,12 +262,11 @@ class API():
def getChecksum(self): def getChecksum(self):
# Use the etags checksum and userdata # Use the etags checksum and userdata
item = self.item userdata = self.item['UserData']
userdata = item['UserData']
checksum = "%s%s%s%s%s%s%s" % ( checksum = "%s%s%s%s%s%s%s" % (
item['Etag'], self.item['Etag'],
userdata['Played'], userdata['Played'],
userdata['IsFavorite'], userdata['IsFavorite'],
userdata.get('Likes',''), userdata.get('Likes',''),
@ -282,9 +278,8 @@ class API():
return checksum return checksum
def getGenres(self): def getGenres(self):
item = self.item
all_genres = "" all_genres = ""
genres = item.get('Genres', item.get('SeriesGenres')) genres = self.item.get('Genres', self.item.get('SeriesGenres'))
if genres: if genres:
all_genres = " / ".join(genres) all_genres = " / ".join(genres)
@ -362,9 +357,8 @@ class API():
def getFilePath(self): def getFilePath(self):
item = self.item
try: try:
filepath = item['Path'] filepath = self.item['Path']
except KeyError: except KeyError:
filepath = "" filepath = ""
@ -375,8 +369,8 @@ class API():
filepath = filepath.replace("\\\\", "smb://") filepath = filepath.replace("\\\\", "smb://")
filepath = filepath.replace("\\", "/") filepath = filepath.replace("\\", "/")
if item.get('VideoType'): if self.item.get('VideoType'):
videotype = item['VideoType'] videotype = self.item['VideoType']
# Specific format modification # Specific format modification
if 'Dvd'in videotype: if 'Dvd'in videotype:
filepath = "%s/VIDEO_TS/VIDEO_TS.IFO" % filepath filepath = "%s/VIDEO_TS/VIDEO_TS.IFO" % filepath
@ -388,4 +382,3 @@ class API():
filepath = filepath.replace("/", "\\") filepath = filepath.replace("/", "\\")
return filepath return filepath

View file

@ -35,7 +35,7 @@ class Artwork():
self.enableTextureCache = utils.settings('enableTextureCache') == "true" self.enableTextureCache = utils.settings('enableTextureCache') == "true"
self.imageCacheLimitThreads = int(utils.settings("imageCacheLimit")) self.imageCacheLimitThreads = int(utils.settings("imageCacheLimit"))
self.imageCacheLimitThreads = int(self.imageCacheLimitThreads * 5); self.imageCacheLimitThreads = int(self.imageCacheLimitThreads * 5)
utils.logMsg("Using Image Cache Thread Count: " + str(self.imageCacheLimitThreads), 1) utils.logMsg("Using Image Cache Thread Count: " + str(self.imageCacheLimitThreads), 1)
if not self.xbmc_port and self.enableTextureCache: if not self.xbmc_port and self.enableTextureCache:
@ -509,8 +509,6 @@ class Artwork():
def getAllArtwork(self, item, parentInfo=False): def getAllArtwork(self, item, parentInfo=False):
server = self.server
itemid = item['Id'] itemid = item['Id']
artworks = item['ImageTags'] artworks = item['ImageTags']
backdrops = item.get('BackdropImageTags',[]) backdrops = item.get('BackdropImageTags',[])
@ -541,7 +539,7 @@ class Artwork():
artwork = ( artwork = (
"%s/emby/Items/%s/Images/Backdrop/%s?" "%s/emby/Items/%s/Images/Backdrop/%s?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s" "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, itemid, index, maxWidth, maxHeight, tag, customquery)) % (self.server, itemid, index, maxWidth, maxHeight, tag, customquery))
allartworks['Backdrop'].append(artwork) allartworks['Backdrop'].append(artwork)
# Process the rest of the artwork # Process the rest of the artwork
@ -552,7 +550,7 @@ class Artwork():
artwork = ( artwork = (
"%s/emby/Items/%s/Images/%s/0?" "%s/emby/Items/%s/Images/%s/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s" "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, itemid, art, maxWidth, maxHeight, tag, customquery)) % (self.server, itemid, art, maxWidth, maxHeight, tag, customquery))
allartworks[art] = artwork allartworks[art] = artwork
# Process parent items if the main item is missing artwork # Process parent items if the main item is missing artwork
@ -570,7 +568,7 @@ class Artwork():
artwork = ( artwork = (
"%s/emby/Items/%s/Images/Backdrop/%s?" "%s/emby/Items/%s/Images/Backdrop/%s?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s" "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, parentId, index, maxWidth, maxHeight, tag, customquery)) % (self.server, parentId, index, maxWidth, maxHeight, tag, customquery))
allartworks['Backdrop'].append(artwork) allartworks['Backdrop'].append(artwork)
# Process the rest of the artwork # Process the rest of the artwork
@ -586,7 +584,7 @@ class Artwork():
artwork = ( artwork = (
"%s/emby/Items/%s/Images/%s/0?" "%s/emby/Items/%s/Images/%s/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s" "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, parentId, parentart, % (self.server, parentId, parentart,
maxWidth, maxHeight, parentTag, customquery)) maxWidth, maxHeight, parentTag, customquery))
allartworks[parentart] = artwork allartworks[parentart] = artwork
@ -600,7 +598,7 @@ class Artwork():
artwork = ( artwork = (
"%s/emby/Items/%s/Images/Primary/0?" "%s/emby/Items/%s/Images/Primary/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s" "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, parentId, maxWidth, maxHeight, parentTag, customquery)) % (self.server, parentId, maxWidth, maxHeight, parentTag, customquery))
allartworks['Primary'] = artwork allartworks['Primary'] = artwork
return allartworks return allartworks

View file

@ -60,8 +60,6 @@ class ConnectUtils():
def startSession(self): def startSession(self):
log = self.logMsg
self.deviceId = self.clientInfo.getDeviceId() self.deviceId = self.clientInfo.getDeviceId()
# User is identified from this point # User is identified from this point
@ -75,7 +73,7 @@ class ConnectUtils():
if self.sslclient is not None: if self.sslclient is not None:
verify = self.sslclient verify = self.sslclient
except: except:
log("Could not load SSL settings.", 1) self.logMsg("Could not load SSL settings.", 1)
# Start session # Start session
self.c = requests.Session() self.c = requests.Session()
@ -85,7 +83,7 @@ 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))
log("Requests session started on: %s" % self.server, 1) self.logMsg("Requests session started on: %s" % self.server, 1)
def stopSession(self): def stopSession(self):
try: try:
@ -95,8 +93,7 @@ class ConnectUtils():
def getHeader(self, authenticate=True): def getHeader(self, authenticate=True):
clientInfo = self.clientInfo version = self.clientInfo.getVersion()
version = clientInfo.getVersion()
if not authenticate: if not authenticate:
# If user is not authenticated # If user is not authenticated
@ -125,10 +122,9 @@ class ConnectUtils():
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):
log = self.logMsg
window = utils.window 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
@ -213,25 +209,25 @@ class ConnectUtils():
verify=verifyssl) verify=verifyssl)
##### THE RESPONSE ##### ##### THE RESPONSE #####
log(r.url, 1) self.logMsg(r.url, 1)
log(r, 1) self.logMsg(r, 1)
if r.status_code == 204: if r.status_code == 204:
# No body in the response # No body in the response
log("====== 204 Success ======", 1) self.logMsg("====== 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()
log("====== 200 Success ======", 1) self.logMsg("====== 200 Success ======", 1)
log("Response: %s" % r, 1) self.logMsg("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":
log("Unable to convert the response for: %s" % url, 1) self.logMsg("Unable to convert the response for: %s" % url, 1)
else: else:
r.raise_for_status() r.raise_for_status()
@ -242,8 +238,8 @@ class ConnectUtils():
pass pass
except requests.exceptions.ConnectTimeout as e: except requests.exceptions.ConnectTimeout as e:
log("Server timeout at: %s" % url, 0) self.logMsg("Server timeout at: %s" % url, 0)
log(e, 1) self.logMsg(e, 1)
except requests.exceptions.HTTPError as e: except requests.exceptions.HTTPError as e:
@ -259,11 +255,11 @@ class ConnectUtils():
pass pass
except requests.exceptions.SSLError as e: except requests.exceptions.SSLError as e:
log("Invalid SSL certificate for: %s" % url, 0) self.logMsg("Invalid SSL certificate for: %s" % url, 0)
log(e, 1) self.logMsg(e, 1)
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
log("Unknown error connecting to: %s" % url, 0) self.logMsg("Unknown error connecting to: %s" % url, 0)
log(e, 1) self.logMsg(e, 1)
return default_link return default_link

View file

@ -97,7 +97,7 @@ class DownloadUtils():
self.logMsg("Capabilities URL: %s" % url, 2) self.logMsg("Capabilities URL: %s" % url, 2)
self.logMsg("Postdata: %s" % data, 2) self.logMsg("Postdata: %s" % data, 2)
self.downloadUrl(url, postBody=data, type="POST") self.downloadUrl(url, postBody=data, action_type="POST")
self.logMsg("Posted capabilities to %s" % self.server, 2) self.logMsg("Posted capabilities to %s" % self.server, 2)
# Attempt at getting sessionId # Attempt at getting sessionId
@ -140,13 +140,11 @@ class DownloadUtils():
"{server}/emby/Sessions/%s/Users/%s?format=json" "{server}/emby/Sessions/%s/Users/%s?format=json"
% (sessionId, userId) % (sessionId, userId)
) )
self.downloadUrl(url, postBody={}, type="POST") self.downloadUrl(url, postBody={}, action_type="POST")
def startSession(self): def startSession(self):
log = self.logMsg
self.deviceId = self.clientInfo.getDeviceId() self.deviceId = self.clientInfo.getDeviceId()
# User is identified from this point # User is identified from this point
@ -160,7 +158,7 @@ class DownloadUtils():
if self.sslclient is not None: if self.sslclient is not None:
verify = self.sslclient verify = self.sslclient
except: except:
log("Could not load SSL settings.", 1) self.logMsg("Could not load SSL settings.", 1)
# Start session # Start session
self.s = requests.Session() self.s = requests.Session()
@ -170,7 +168,7 @@ 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))
log("Requests session started on: %s" % self.server, 1) self.logMsg("Requests session started on: %s" % self.server, 1)
def stopSession(self): def stopSession(self):
try: try:
@ -180,12 +178,10 @@ class DownloadUtils():
def getHeader(self, authenticate=True): def getHeader(self, authenticate=True):
clientInfo = self.clientInfo deviceName = self.clientInfo.getDeviceName()
deviceName = clientInfo.getDeviceName()
deviceName = utils.normalize_string(deviceName.encode('utf-8')) deviceName = utils.normalize_string(deviceName.encode('utf-8'))
deviceId = clientInfo.getDeviceId() deviceId = self.clientInfo.getDeviceId()
version = clientInfo.getVersion() version = self.clientInfo.getVersion()
if not authenticate: if not authenticate:
# If user is not authenticated # If user is not authenticated
@ -220,11 +216,10 @@ class DownloadUtils():
return header return header
def downloadUrl(self, url, postBody=None, type="GET", parameters=None, authenticate=True): def downloadUrl(self, url, postBody=None, action_type="GET", parameters=None, authenticate=True):
self.logMsg("=== ENTER downloadUrl ===", 2) self.logMsg("=== ENTER downloadUrl ===", 2)
timeout = self.timeout
default_link = "" default_link = ""
try: try:
@ -238,12 +233,12 @@ class DownloadUtils():
url = url.replace("{UserId}", self.userId) url = url.replace("{UserId}", self.userId)
# Prepare request # Prepare request
if type == "GET": if action_type == "GET":
r = s.get(url, json=postBody, params=parameters, timeout=timeout) r = s.get(url, json=postBody, params=parameters, timeout=self.timeout)
elif type == "POST": elif action_type == "POST":
r = s.post(url, json=postBody, timeout=timeout) r = s.post(url, json=postBody, timeout=self.timeout)
elif type == "DELETE": elif action_type == "DELETE":
r = s.delete(url, json=postBody, timeout=timeout) r = s.delete(url, json=postBody, timeout=self.timeout)
except AttributeError: except AttributeError:
# request session does not exists # request session does not exists
@ -266,26 +261,26 @@ class DownloadUtils():
url = url.replace("{UserId}", self.userId) url = url.replace("{UserId}", self.userId)
# Prepare request # Prepare request
if type == "GET": if action_type == "GET":
r = requests.get(url, r = requests.get(url,
json=postBody, json=postBody,
params=parameters, params=parameters,
headers=header, headers=header,
timeout=timeout, timeout=self.timeout,
verify=verifyssl) verify=verifyssl)
elif type == "POST": elif action_type == "POST":
r = requests.post(url, r = requests.post(url,
json=postBody, json=postBody,
headers=header, headers=header,
timeout=timeout, timeout=self.timeout,
verify=verifyssl) verify=verifyssl)
elif type == "DELETE": elif action_type == "DELETE":
r = requests.delete(url, r = requests.delete(url,
json=postBody, json=postBody,
headers=header, headers=header,
timeout=timeout, timeout=self.timeout,
verify=verifyssl) verify=verifyssl)
# If user is not authenticated # If user is not authenticated
@ -303,19 +298,19 @@ class DownloadUtils():
pass pass
# Prepare request # Prepare request
if type == "GET": if action_type == "GET":
r = requests.get(url, r = requests.get(url,
json=postBody, json=postBody,
params=parameters, params=parameters,
headers=header, headers=header,
timeout=timeout, timeout=self.timeout,
verify=verifyssl) verify=verifyssl)
elif type == "POST": elif action_type == "POST":
r = requests.post(url, r = requests.post(url,
json=postBody, json=postBody,
headers=header, headers=header,
timeout=timeout, timeout=self.timeout,
verify=verifyssl) verify=verifyssl)
##### THE RESPONSE ##### ##### THE RESPONSE #####

View file

@ -25,7 +25,6 @@ class Embydb_Functions():
def getViews(self): def getViews(self):
embycursor = self.embycursor
views = [] views = []
query = ' '.join(( query = ' '.join((
@ -33,8 +32,8 @@ class Embydb_Functions():
"SELECT view_id", "SELECT view_id",
"FROM view" "FROM view"
)) ))
embycursor.execute(query) self.embycursor.execute(query)
rows = embycursor.fetchall() rows = self.embycursor.fetchall()
for row in rows: for row in rows:
views.append(row[0]) views.append(row[0])
@ -42,7 +41,6 @@ class Embydb_Functions():
def getView_byId(self, viewid): def getView_byId(self, viewid):
embycursor = self.embycursor
query = ' '.join(( query = ' '.join((
@ -50,14 +48,13 @@ class Embydb_Functions():
"FROM view", "FROM view",
"WHERE view_id = ?" "WHERE view_id = ?"
)) ))
embycursor.execute(query, (viewid,)) self.embycursor.execute(query, (viewid,))
view = embycursor.fetchone() view = self.embycursor.fetchone()
return view return view
def getView_byType(self, mediatype): def getView_byType(self, mediatype):
embycursor = self.embycursor
views = [] views = []
query = ' '.join(( query = ' '.join((
@ -66,8 +63,8 @@ class Embydb_Functions():
"FROM view", "FROM view",
"WHERE media_type = ?" "WHERE media_type = ?"
)) ))
embycursor.execute(query, (mediatype,)) self.embycursor.execute(query, (mediatype,))
rows = embycursor.fetchall() rows = self.embycursor.fetchall()
for row in rows: for row in rows:
views.append({ views.append({
@ -79,17 +76,15 @@ class Embydb_Functions():
def getView_byName(self, tagname): def getView_byName(self, tagname):
embycursor = self.embycursor
query = ' '.join(( query = ' '.join((
"SELECT view_id", "SELECT view_id",
"FROM view", "FROM view",
"WHERE view_name = ?" "WHERE view_name = ?"
)) ))
embycursor.execute(query, (tagname,)) self.embycursor.execute(query, (tagname,))
try: try:
view = embycursor.fetchone()[0] view = self.embycursor.fetchone()[0]
except TypeError: except TypeError:
view = None view = None
@ -129,8 +124,6 @@ class Embydb_Functions():
def getItem_byId(self, embyid): def getItem_byId(self, embyid):
embycursor = self.embycursor
query = ' '.join(( query = ' '.join((
"SELECT kodi_id, kodi_fileid, kodi_pathid, parent_id, media_type, emby_type", "SELECT kodi_id, kodi_fileid, kodi_pathid, parent_id, media_type, emby_type",
@ -138,45 +131,35 @@ class Embydb_Functions():
"WHERE emby_id = ?" "WHERE emby_id = ?"
)) ))
try: try:
embycursor.execute(query, (embyid,)) self.embycursor.execute(query, (embyid,))
item = embycursor.fetchone() item = self.embycursor.fetchone()
return item return item
except: return None except: return None
def getItem_byWildId(self, embyid): def getItem_byWildId(self, embyid):
embycursor = self.embycursor
query = ' '.join(( query = ' '.join((
"SELECT kodi_id, media_type", "SELECT kodi_id, media_type",
"FROM emby", "FROM emby",
"WHERE emby_id LIKE ?" "WHERE emby_id LIKE ?"
)) ))
embycursor.execute(query, (embyid+"%",)) self.embycursor.execute(query, (embyid+"%",))
items = embycursor.fetchall() return self.embycursor.fetchall()
return items
def getItem_byView(self, mediafolderid): def getItem_byView(self, mediafolderid):
embycursor = self.embycursor
query = ' '.join(( query = ' '.join((
"SELECT kodi_id", "SELECT kodi_id",
"FROM emby", "FROM emby",
"WHERE media_folder = ?" "WHERE media_folder = ?"
)) ))
embycursor.execute(query, (mediafolderid,)) self.embycursor.execute(query, (mediafolderid,))
items = embycursor.fetchall() return self.embycursor.fetchall()
return items
def getItem_byKodiId(self, kodiid, mediatype): def getItem_byKodiId(self, kodiid, mediatype):
embycursor = self.embycursor
query = ' '.join(( query = ' '.join((
"SELECT emby_id, parent_id", "SELECT emby_id, parent_id",
@ -184,15 +167,11 @@ class Embydb_Functions():
"WHERE kodi_id = ?", "WHERE kodi_id = ?",
"AND media_type = ?" "AND media_type = ?"
)) ))
embycursor.execute(query, (kodiid, mediatype,)) self.embycursor.execute(query, (kodiid, mediatype,))
item = embycursor.fetchone() return self.embycursor.fetchone()
return item
def getItem_byParentId(self, parentid, mediatype): def getItem_byParentId(self, parentid, mediatype):
embycursor = self.embycursor
query = ' '.join(( query = ' '.join((
"SELECT emby_id, kodi_id, kodi_fileid", "SELECT emby_id, kodi_id, kodi_fileid",
@ -200,15 +179,11 @@ class Embydb_Functions():
"WHERE parent_id = ?", "WHERE parent_id = ?",
"AND media_type = ?" "AND media_type = ?"
)) ))
embycursor.execute(query, (parentid, mediatype,)) self.embycursor.execute(query, (parentid, mediatype,))
items = embycursor.fetchall() return self.embycursor.fetchall()
return items
def getItemId_byParentId(self, parentid, mediatype): def getItemId_byParentId(self, parentid, mediatype):
embycursor = self.embycursor
query = ' '.join(( query = ' '.join((
"SELECT emby_id, kodi_id", "SELECT emby_id, kodi_id",
@ -216,39 +191,31 @@ class Embydb_Functions():
"WHERE parent_id = ?", "WHERE parent_id = ?",
"AND media_type = ?" "AND media_type = ?"
)) ))
embycursor.execute(query, (parentid, mediatype,)) self.embycursor.execute(query, (parentid, mediatype,))
items = embycursor.fetchall() return self.embycursor.fetchall()
return items
def getChecksum(self, mediatype): def getChecksum(self, mediatype):
embycursor = self.embycursor
query = ' '.join(( query = ' '.join((
"SELECT emby_id, checksum", "SELECT emby_id, checksum",
"FROM emby", "FROM emby",
"WHERE emby_type = ?" "WHERE emby_type = ?"
)) ))
embycursor.execute(query, (mediatype,)) self.embycursor.execute(query, (mediatype,))
items = embycursor.fetchall() return self.embycursor.fetchall()
return items
def getMediaType_byId(self, embyid): def getMediaType_byId(self, embyid):
embycursor = self.embycursor
query = ' '.join(( query = ' '.join((
"SELECT emby_type", "SELECT emby_type",
"FROM emby", "FROM emby",
"WHERE emby_id = ?" "WHERE emby_id = ?"
)) ))
embycursor.execute(query, (embyid,)) self.embycursor.execute(query, (embyid,))
try: try:
itemtype = embycursor.fetchone()[0] itemtype = self.embycursor.fetchone()[0]
except TypeError: except TypeError:
itemtype = None itemtype = None

View file

@ -67,12 +67,12 @@ def doMainListing():
if not path: if not path:
path = utils.window('Emby.nodes.%s.content' % i) path = utils.window('Emby.nodes.%s.content' % i)
label = utils.window('Emby.nodes.%s.title' % i) label = utils.window('Emby.nodes.%s.title' % i)
type = utils.window('Emby.nodes.%s.type' % i) node_type = utils.window('Emby.nodes.%s.type' % i)
#because we do not use seperate entrypoints for each content type, we need to figure out which items to show in each listing. #because we do not use seperate entrypoints for each content type, we need to figure out which items to show in each listing.
#for now we just only show picture nodes in the picture library video nodes in the video library and all nodes in any other window #for now we just only show picture nodes in the picture library video nodes in the video library and all nodes in any other window
if path and xbmc.getCondVisibility("Window.IsActive(Pictures)") and type == "photos": if path and xbmc.getCondVisibility("Window.IsActive(Pictures)") and node_type == "photos":
addDirectoryItem(label, path) addDirectoryItem(label, path)
elif path and xbmc.getCondVisibility("Window.IsActive(VideoLibrary)") and type != "photos": elif path and xbmc.getCondVisibility("Window.IsActive(VideoLibrary)") and node_type != "photos":
addDirectoryItem(label, path) addDirectoryItem(label, path)
elif path and not xbmc.getCondVisibility("Window.IsActive(VideoLibrary) | Window.IsActive(Pictures) | Window.IsActive(MusicLibrary)"): elif path and not xbmc.getCondVisibility("Window.IsActive(VideoLibrary) | Window.IsActive(Pictures) | Window.IsActive(MusicLibrary)"):
addDirectoryItem(label, path) addDirectoryItem(label, path)
@ -166,7 +166,7 @@ def deleteItem():
doUtils = downloadutils.DownloadUtils() doUtils = downloadutils.DownloadUtils()
url = "{server}/emby/Items/%s?format=json" % embyid url = "{server}/emby/Items/%s?format=json" % embyid
utils.logMsg("EMBY delete", "Deleting request: %s" % embyid, 0) utils.logMsg("EMBY delete", "Deleting request: %s" % embyid, 0)
doUtils.downloadUrl(url, type="DELETE") doUtils.downloadUrl(url, action_type="DELETE")
##### ADD ADDITIONAL USERS ##### ##### ADD ADDITIONAL USERS #####
def addUser(): def addUser():
@ -221,7 +221,7 @@ def addUser():
selected = additionalUsername[resp] selected = additionalUsername[resp]
selected_userId = additionalUserlist[selected] selected_userId = additionalUserlist[selected]
url = "{server}/emby/Sessions/%s/Users/%s" % (sessionId, selected_userId) url = "{server}/emby/Sessions/%s/Users/%s" % (sessionId, selected_userId)
doUtils.downloadUrl(url, postBody={}, type="DELETE") doUtils.downloadUrl(url, postBody={}, action_type="DELETE")
dialog.notification( dialog.notification(
heading="Success!", heading="Success!",
message="%s removed from viewing session" % selected, message="%s removed from viewing session" % selected,
@ -254,7 +254,7 @@ def addUser():
selected = users[resp] selected = users[resp]
selected_userId = userlist[selected] selected_userId = userlist[selected]
url = "{server}/emby/Sessions/%s/Users/%s" % (sessionId, selected_userId) url = "{server}/emby/Sessions/%s/Users/%s" % (sessionId, selected_userId)
doUtils.downloadUrl(url, postBody={}, type="POST") doUtils.downloadUrl(url, postBody={}, action_type="POST")
dialog.notification( dialog.notification(
heading="Success!", heading="Success!",
message="%s added to viewing session" % selected, message="%s added to viewing session" % selected,
@ -483,12 +483,11 @@ def GetSubFolders(nodeindex):
title = utils.window('Emby.nodes.%s%s.title' %(nodeindex,node)) title = utils.window('Emby.nodes.%s%s.title' %(nodeindex,node))
if title: if title:
path = utils.window('Emby.nodes.%s%s.content' %(nodeindex,node)) path = utils.window('Emby.nodes.%s%s.content' %(nodeindex,node))
type = utils.window('Emby.nodes.%s%s.type' %(nodeindex,node))
addDirectoryItem(title, path) addDirectoryItem(title, path)
xbmcplugin.endOfDirectory(int(sys.argv[1])) xbmcplugin.endOfDirectory(int(sys.argv[1]))
##### BROWSE EMBY NODES DIRECTLY ##### ##### BROWSE EMBY NODES DIRECTLY #####
def BrowseContent(viewname, type="", folderid=""): def BrowseContent(viewname, browse_type="", folderid=""):
emby = embyserver.Read_EmbyServer() emby = embyserver.Read_EmbyServer()
art = artwork.Artwork() art = artwork.Artwork()
@ -496,46 +495,47 @@ def BrowseContent(viewname, type="", folderid=""):
#folderid used as filter ? #folderid used as filter ?
if folderid in ["recent","recentepisodes","inprogress","inprogressepisodes","unwatched","nextepisodes","sets","genres","random","recommended"]: if folderid in ["recent","recentepisodes","inprogress","inprogressepisodes","unwatched","nextepisodes","sets","genres","random","recommended"]:
filter = folderid filter_type = folderid
folderid = "" folderid = ""
else: else:
filter = "" filter_type = ""
xbmcplugin.setPluginCategory(int(sys.argv[1]), viewname) xbmcplugin.setPluginCategory(int(sys.argv[1]), viewname)
#get views for root level #get views for root level
if not folderid: if not folderid:
views = emby.getViews(type) views = emby.getViews(browse_type)
for view in views: for view in views:
if view.get("name") == viewname.decode('utf-8'): if view.get("name") == viewname.decode('utf-8'):
folderid = view.get("id") folderid = view.get("id")
break
if viewname is not None: if viewname is not None:
utils.logMsg("BrowseContent","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname.decode('utf-8'), type.decode('utf-8'), folderid.decode('utf-8'), filter.decode('utf-8'))) utils.logMsg("BrowseContent","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname.decode('utf-8'), browse_type.decode('utf-8'), folderid.decode('utf-8'), filter_type.decode('utf-8')))
#set the correct params for the content type #set the correct params for the content type
#only proceed if we have a folderid #only proceed if we have a folderid
if folderid: if folderid:
if type.lower() == "homevideos": if browse_type.lower() == "homevideos":
xbmcplugin.setContent(int(sys.argv[1]), 'episodes') xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
itemtype = "Video,Folder,PhotoAlbum" itemtype = "Video,Folder,PhotoAlbum"
elif type.lower() == "photos": elif browse_type.lower() == "photos":
xbmcplugin.setContent(int(sys.argv[1]), 'files') xbmcplugin.setContent(int(sys.argv[1]), 'files')
itemtype = "Photo,PhotoAlbum,Folder" itemtype = "Photo,PhotoAlbum,Folder"
else: else:
itemtype = "" itemtype = ""
#get the actual listing #get the actual listing
if type == "recordings": if browse_type == "recordings":
listing = emby.getTvRecordings(folderid) listing = emby.getTvRecordings(folderid)
elif type == "tvchannels": elif browse_type == "tvchannels":
listing = emby.getTvChannels() listing = emby.getTvChannels()
elif filter == "recent": elif filter_type == "recent":
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="DateCreated", recursive=True, limit=25, sortorder="Descending") listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="DateCreated", recursive=True, limit=25, sortorder="Descending")
elif filter == "random": elif filter_type == "random":
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="Random", recursive=True, limit=150, sortorder="Descending") listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="Random", recursive=True, limit=150, sortorder="Descending")
elif filter == "recommended": elif filter_type == "recommended":
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter="IsFavorite") listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter_type="IsFavorite")
elif filter == "sets": elif filter_type == "sets":
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[1], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter="IsFavorite") listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[1], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter_type="IsFavorite")
else: else:
listing = emby.getFilteredSection(folderid, itemtype=itemtype, recursive=False) listing = emby.getFilteredSection(folderid, itemtype=itemtype, recursive=False)
@ -545,14 +545,14 @@ def BrowseContent(viewname, type="", folderid=""):
li = createListItemFromEmbyItem(item,art,doUtils) li = createListItemFromEmbyItem(item,art,doUtils)
if item.get("IsFolder") == True: if item.get("IsFolder") == True:
#for folders we add an additional browse request, passing the folderId #for folders we add an additional browse request, passing the folderId
path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" % (sys.argv[0].decode('utf-8'), viewname.decode('utf-8'), type.decode('utf-8'), item.get("Id").decode('utf-8')) path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" % (sys.argv[0].decode('utf-8'), viewname.decode('utf-8'), browse_type.decode('utf-8'), item.get("Id").decode('utf-8'))
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=True) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=True)
else: else:
#playable item, set plugin path and mediastreams #playable item, set plugin path and mediastreams
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=li.getProperty("path"), listitem=li) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=li.getProperty("path"), listitem=li)
if filter == "recent": if filter_type == "recent":
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE) xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE)
else: else:
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_TITLE) xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_TITLE)

View file

@ -176,8 +176,8 @@ 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); self.logMsg("MultiGroup : %s" % str(MULTI_GROUP), 2)
self.logMsg("Sending UDP Data: %s" % MESSAGE, 2); self.logMsg("Sending UDP Data: %s" % MESSAGE, 2)
sock.sendto(MESSAGE, MULTI_GROUP) sock.sendto(MESSAGE, MULTI_GROUP)
try: try:

View file

@ -249,10 +249,9 @@ class Movies(Items):
count = 0 count = 0
for boxset in items: for boxset in items:
title = boxset['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=boxset['Name'])
count += 1 count += 1
self.add_updateBoxset(boxset) self.add_updateBoxset(boxset)
@ -261,7 +260,6 @@ class Movies(Items):
# Process single movie # Process single movie
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
API = api.API(item) API = api.API(item)
@ -423,9 +421,9 @@ class Movies(Items):
self.logMsg("ADD movie itemid: %s - Title: %s" % (itemid, title), 1) self.logMsg("ADD movie itemid: %s - Title: %s" % (itemid, title), 1)
# Add path # Add path
pathid = kodi_db.addPath(path) pathid = self.kodi_db.addPath(path)
# Add the file # Add the file
fileid = kodi_db.addFile(filename, pathid) fileid = self.kodi_db.addFile(filename, pathid)
# Create the movie entry # Create the movie entry
query = ( query = (
@ -463,35 +461,34 @@ class Movies(Items):
kodicursor.execute(query, (pathid, filename, dateadded, fileid)) kodicursor.execute(query, (pathid, filename, dateadded, fileid))
# Process countries # Process countries
kodi_db.addCountries(movieid, item['ProductionLocations'], "movie") self.kodi_db.addCountries(movieid, item['ProductionLocations'], "movie")
# Process cast # Process cast
people = artwork.getPeopleArtwork(item['People']) people = artwork.getPeopleArtwork(item['People'])
kodi_db.addPeople(movieid, people, "movie") self.kodi_db.addPeople(movieid, people, "movie")
# Process genres # Process genres
kodi_db.addGenres(movieid, genres, "movie") self.kodi_db.addGenres(movieid, genres, "movie")
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), movieid, "movie", kodicursor) artwork.addArtwork(artwork.getAllArtwork(item), movieid, "movie", kodicursor)
# Process stream details # Process stream details
streams = API.getMediaStreams() streams = API.getMediaStreams()
kodi_db.addStreams(fileid, streams, runtime) self.kodi_db.addStreams(fileid, streams, runtime)
# Process studios # Process studios
kodi_db.addStudios(movieid, studios, "movie") self.kodi_db.addStudios(movieid, studios, "movie")
# Process tags: view, emby tags # Process tags: view, emby tags
tags = [viewtag] tags = [viewtag]
tags.extend(item['Tags']) tags.extend(item['Tags'])
if userdata['Favorite']: if userdata['Favorite']:
tags.append("Favorite movies") tags.append("Favorite movies")
kodi_db.addTags(movieid, tags, "movie") self.kodi_db.addTags(movieid, tags, "movie")
# Process playstates # Process playstates
resume = API.adjustResume(userdata['Resume']) resume = API.adjustResume(userdata['Resume'])
total = round(float(runtime), 6) total = round(float(runtime), 6)
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
def add_updateBoxset(self, boxset): def add_updateBoxset(self, boxset):
emby = self.emby emby = self.emby
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
boxsetid = boxset['Id'] boxsetid = boxset['Id']
@ -502,7 +499,7 @@ class Movies(Items):
setid = emby_dbitem[0] setid = emby_dbitem[0]
except TypeError: except TypeError:
setid = kodi_db.createBoxset(title) setid = self.kodi_db.createBoxset(title)
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(boxset), setid, "set", self.kodicursor) artwork.addArtwork(artwork.getAllArtwork(boxset), setid, "set", self.kodicursor)
@ -521,8 +518,7 @@ class Movies(Items):
process.append(current_movie) process.append(current_movie)
# New list to compare # New list to compare
boxsetMovies = emby.getMovies_byBoxset(boxsetid) for movie in emby.getMovies_byBoxset(boxsetid)['Items']:
for movie in boxsetMovies['Items']:
itemid = movie['Id'] itemid = movie['Id']
@ -536,7 +532,7 @@ class Movies(Items):
continue continue
self.logMsg("New addition to boxset %s: %s" % (title, movie['Name']), 1) self.logMsg("New addition to boxset %s: %s" % (title, movie['Name']), 1)
kodi_db.assignBoxset(setid, movieid) self.kodi_db.assignBoxset(setid, movieid)
# Update emby reference # Update emby reference
emby_db.updateParentId(itemid, setid) emby_db.updateParentId(itemid, setid)
else: else:
@ -547,7 +543,7 @@ class Movies(Items):
for movie in process: for movie in process:
movieid = current[movie] movieid = current[movie]
self.logMsg("Remove from boxset %s: %s" % (title, movieid)) self.logMsg("Remove from boxset %s: %s" % (title, movieid))
kodi_db.removefromBoxset(movieid) self.kodi_db.removefromBoxset(movieid)
# Update emby reference # Update emby reference
emby_db.updateParentId(movie, None) emby_db.updateParentId(movie, None)
@ -558,7 +554,6 @@ class Movies(Items):
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
# Poster with progress bar # Poster with progress bar
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
API = api.API(item) API = api.API(item)
# Get emby information # Get emby information
@ -580,9 +575,9 @@ class Movies(Items):
# Process favorite tags # Process favorite tags
if userdata['Favorite']: if userdata['Favorite']:
kodi_db.addTag(movieid, "Favorite movies", "movie") self.kodi_db.addTag(movieid, "Favorite movies", "movie")
else: else:
kodi_db.removeTag(movieid, "Favorite movies", "movie") self.kodi_db.removeTag(movieid, "Favorite movies", "movie")
# Process playstates # Process playstates
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
@ -592,7 +587,7 @@ class Movies(Items):
self.logMsg("%s New resume point: %s" % (itemid, resume)) self.logMsg("%s New resume point: %s" % (itemid, resume))
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
emby_db.updateReference(itemid, checksum) emby_db.updateReference(itemid, checksum)
def remove(self, itemid): def remove(self, itemid):
@ -660,7 +655,6 @@ class MusicVideos(Items):
# Process single music video # Process single music video
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
API = api.API(item) API = api.API(item)
@ -851,32 +845,31 @@ class MusicVideos(Items):
artist['Type'] = "Artist" artist['Type'] = "Artist"
people.extend(artists) people.extend(artists)
people = artwork.getPeopleArtwork(people) people = artwork.getPeopleArtwork(people)
kodi_db.addPeople(mvideoid, people, "musicvideo") self.kodi_db.addPeople(mvideoid, people, "musicvideo")
# Process genres # Process genres
kodi_db.addGenres(mvideoid, genres, "musicvideo") self.kodi_db.addGenres(mvideoid, genres, "musicvideo")
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), mvideoid, "musicvideo", kodicursor) artwork.addArtwork(artwork.getAllArtwork(item), mvideoid, "musicvideo", kodicursor)
# Process stream details # Process stream details
streams = API.getMediaStreams() streams = API.getMediaStreams()
kodi_db.addStreams(fileid, streams, runtime) self.kodi_db.addStreams(fileid, streams, runtime)
# Process studios # Process studios
kodi_db.addStudios(mvideoid, studios, "musicvideo") self.kodi_db.addStudios(mvideoid, studios, "musicvideo")
# Process tags: view, emby tags # Process tags: view, emby tags
tags = [viewtag] tags = [viewtag]
tags.extend(item['Tags']) tags.extend(item['Tags'])
if userdata['Favorite']: if userdata['Favorite']:
tags.append("Favorite musicvideos") tags.append("Favorite musicvideos")
kodi_db.addTags(mvideoid, tags, "musicvideo") self.kodi_db.addTags(mvideoid, tags, "musicvideo")
# Process playstates # Process playstates
resume = API.adjustResume(userdata['Resume']) resume = API.adjustResume(userdata['Resume'])
total = round(float(runtime), 6) total = round(float(runtime), 6)
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
def updateUserdata(self, item): def updateUserdata(self, item):
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
# Poster with progress bar # Poster with progress bar
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
API = api.API(item) API = api.API(item)
# Get emby information # Get emby information
@ -898,9 +891,9 @@ class MusicVideos(Items):
# Process favorite tags # Process favorite tags
if userdata['Favorite']: if userdata['Favorite']:
kodi_db.addTag(mvideoid, "Favorite musicvideos", "musicvideo") self.kodi_db.addTag(mvideoid, "Favorite musicvideos", "musicvideo")
else: else:
kodi_db.removeTag(mvideoid, "Favorite musicvideos", "musicvideo") self.kodi_db.removeTag(mvideoid, "Favorite musicvideos", "musicvideo")
# Process playstates # Process playstates
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
@ -908,7 +901,7 @@ class MusicVideos(Items):
resume = API.adjustResume(userdata['Resume']) resume = API.adjustResume(userdata['Resume'])
total = round(float(runtime), 6) total = round(float(runtime), 6)
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
emby_db.updateReference(itemid, checksum) emby_db.updateReference(itemid, checksum)
def remove(self, itemid): def remove(self, itemid):
@ -935,8 +928,7 @@ class MusicVideos(Items):
"AND media_type = 'musicvideo'" "AND media_type = 'musicvideo'"
)) ))
kodicursor.execute(query, (mvideoid,)) kodicursor.execute(query, (mvideoid,))
rows = kodicursor.fetchall() for row in kodicursor.fetchall():
for row in rows:
url = row[0] url = row[0]
imagetype = row[1] imagetype = row[1]
@ -1009,7 +1001,6 @@ class TVShows(Items):
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby = self.emby emby = self.emby
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
API = api.API(item) API = api.API(item)
@ -1131,7 +1122,7 @@ class TVShows(Items):
self.logMsg("ADD tvshow itemid: %s - Title: %s" % (itemid, title), 1) self.logMsg("ADD tvshow itemid: %s - Title: %s" % (itemid, title), 1)
# Add top path # Add top path
toppathid = kodi_db.addPath(toplevelpath) toppathid = self.kodi_db.addPath(toplevelpath)
query = ' '.join(( query = ' '.join((
"UPDATE path", "UPDATE path",
@ -1141,7 +1132,7 @@ class TVShows(Items):
kodicursor.execute(query, (toplevelpath, "tvshows", "metadata.local", 1, toppathid)) kodicursor.execute(query, (toplevelpath, "tvshows", "metadata.local", 1, toppathid))
# Add path # Add path
pathid = kodi_db.addPath(path) pathid = self.kodi_db.addPath(path)
# Create the tvshow entry # Create the tvshow entry
query = ( query = (
@ -1174,26 +1165,26 @@ class TVShows(Items):
# Process cast # Process cast
people = artwork.getPeopleArtwork(item['People']) people = artwork.getPeopleArtwork(item['People'])
kodi_db.addPeople(showid, people, "tvshow") self.kodi_db.addPeople(showid, people, "tvshow")
# Process genres # Process genres
kodi_db.addGenres(showid, genres, "tvshow") self.kodi_db.addGenres(showid, genres, "tvshow")
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), showid, "tvshow", kodicursor) artwork.addArtwork(artwork.getAllArtwork(item), showid, "tvshow", kodicursor)
# Process studios # Process studios
kodi_db.addStudios(showid, studios, "tvshow") self.kodi_db.addStudios(showid, studios, "tvshow")
# Process tags: view, emby tags # Process tags: view, emby tags
tags = [viewtag] tags = [viewtag]
tags.extend(item['Tags']) tags.extend(item['Tags'])
if userdata['Favorite']: if userdata['Favorite']:
tags.append("Favorite tvshows") tags.append("Favorite tvshows")
kodi_db.addTags(showid, tags, "tvshow") self.kodi_db.addTags(showid, tags, "tvshow")
# Process seasons # Process seasons
all_seasons = emby.getSeasons(itemid) all_seasons = emby.getSeasons(itemid)
for season in all_seasons['Items']: for season in all_seasons['Items']:
self.add_updateSeason(season, showid=showid) self.add_updateSeason(season, showid=showid)
else: else:
# Finally, refresh the all season entry # Finally, refresh the all season entry
seasonid = kodi_db.addSeason(showid, -1) seasonid = self.kodi_db.addSeason(showid, -1)
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor) artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor)
@ -1207,11 +1198,9 @@ class TVShows(Items):
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
seasonnum = item.get('IndexNumber', 1) seasonnum = item.get('IndexNumber', 1)
itemid = item['Id']
if showid is None: if showid is None:
try: try:
@ -1225,21 +1214,19 @@ class TVShows(Items):
self.add_update(show) self.add_update(show)
return return
seasonid = kodi_db.addSeason(showid, seasonnum) seasonid = self.kodi_db.addSeason(showid, seasonnum)
if item['LocationType'] != "Virtual": if item['LocationType'] != "Virtual":
# Create the reference in emby table # Create the reference in emby table
emby_db.addReference(itemid, seasonid, "Season", "season", parentid=showid) emby_db.addReference(item['Id'], seasonid, "Season", "season", parentid=showid)
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor) artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor)
def add_updateEpisode(self, item): def add_updateEpisode(self, item):
# Process single episode # Process single episode
kodiversion = self.kodiversion
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
API = api.API(item) API = api.API(item)
@ -1336,7 +1323,7 @@ class TVShows(Items):
self.logMsg("Skipping: %s. Unable to add series: %s." % (itemid, seriesId)) self.logMsg("Skipping: %s. Unable to add series: %s." % (itemid, seriesId))
return False return False
seasonid = kodi_db.addSeason(showid, season) seasonid = self.kodi_db.addSeason(showid, season)
##### GET THE FILE AND PATH ##### ##### GET THE FILE AND PATH #####
@ -1384,7 +1371,7 @@ class TVShows(Items):
self.logMsg("UPDATE episode itemid: %s - Title: %s" % (itemid, title), 1) self.logMsg("UPDATE episode itemid: %s - Title: %s" % (itemid, title), 1)
# Update the movie entry # Update the movie entry
if kodiversion in (16, 17): if self.kodiversion in (16, 17):
# Kodi Jarvis, Krypton # Kodi Jarvis, Krypton
query = ' '.join(( query = ' '.join((
@ -1418,12 +1405,12 @@ class TVShows(Items):
self.logMsg("ADD episode itemid: %s - Title: %s" % (itemid, title), 1) self.logMsg("ADD episode itemid: %s - Title: %s" % (itemid, title), 1)
# Add path # Add path
pathid = kodi_db.addPath(path) pathid = self.kodi_db.addPath(path)
# Add the file # Add the file
fileid = kodi_db.addFile(filename, pathid) fileid = self.kodi_db.addFile(filename, pathid)
# Create the episode entry # Create the episode entry
if kodiversion in (16, 17): if self.kodiversion in (16, 17):
# Kodi Jarvis, Krypton # Kodi Jarvis, Krypton
query = ( query = (
''' '''
@ -1475,21 +1462,21 @@ class TVShows(Items):
# Process cast # Process cast
people = artwork.getPeopleArtwork(item['People']) people = artwork.getPeopleArtwork(item['People'])
kodi_db.addPeople(episodeid, people, "episode") self.kodi_db.addPeople(episodeid, people, "episode")
# Process artwork # Process artwork
artworks = artwork.getAllArtwork(item) artworks = artwork.getAllArtwork(item)
artwork.addOrUpdateArt(artworks['Primary'], episodeid, "episode", "thumb", kodicursor) artwork.addOrUpdateArt(artworks['Primary'], episodeid, "episode", "thumb", kodicursor)
# Process stream details # Process stream details
streams = API.getMediaStreams() streams = API.getMediaStreams()
kodi_db.addStreams(fileid, streams, runtime) self.kodi_db.addStreams(fileid, streams, runtime)
# Process playstates # Process playstates
resume = API.adjustResume(userdata['Resume']) resume = API.adjustResume(userdata['Resume'])
total = round(float(runtime), 6) total = round(float(runtime), 6)
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
if not self.directpath and resume: if not self.directpath and resume:
# Create additional entry for widgets. This is only required for plugin/episode. # Create additional entry for widgets. This is only required for plugin/episode.
temppathid = kodi_db.getPath("plugin://plugin.video.emby.tvshows/") temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
tempfileid = kodi_db.addFile(filename, temppathid) tempfileid = self.kodi_db.addFile(filename, temppathid)
query = ' '.join(( query = ' '.join((
"UPDATE files", "UPDATE files",
@ -1497,13 +1484,12 @@ class TVShows(Items):
"WHERE idFile = ?" "WHERE idFile = ?"
)) ))
kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid)) kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
def updateUserdata(self, item): def updateUserdata(self, item):
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
# Poster with progress bar # Poster with progress bar
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
API = api.API(item) API = api.API(item)
# Get emby information # Get emby information
@ -1528,12 +1514,11 @@ class TVShows(Items):
# Process favorite tags # Process favorite tags
if mediatype == "tvshow": if mediatype == "tvshow":
if userdata['Favorite']: if userdata['Favorite']:
kodi_db.addTag(kodiid, "Favorite tvshows", "tvshow") self.kodi_db.addTag(kodiid, "Favorite tvshows", "tvshow")
else: else:
kodi_db.removeTag(kodiid, "Favorite tvshows", "tvshow") self.kodi_db.removeTag(kodiid, "Favorite tvshows", "tvshow")
elif mediatype == "episode":
# Process playstates # Process playstates
if mediatype == "episode":
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate'] dateplayed = userdata['LastPlayedDate']
resume = API.adjustResume(userdata['Resume']) resume = API.adjustResume(userdata['Resume'])
@ -1541,17 +1526,17 @@ class TVShows(Items):
self.logMsg("%s New resume point: %s" % (itemid, resume)) self.logMsg("%s New resume point: %s" % (itemid, resume))
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
if not self.directpath and not resume: if not self.directpath and not resume:
# Make sure there's no other bookmarks created by widget. # Make sure there's no other bookmarks created by widget.
filename = kodi_db.getFile(fileid) filename = self.kodi_db.getFile(fileid)
kodi_db.removeFile("plugin://plugin.video.emby.tvshows/", filename) self.kodi_db.removeFile("plugin://plugin.video.emby.tvshows/", filename)
if not self.directpath and resume: if not self.directpath and resume:
# Create additional entry for widgets. This is only required for plugin/episode. # Create additional entry for widgets. This is only required for plugin/episode.
filename = kodi_db.getFile(fileid) filename = self.kodi_db.getFile(fileid)
temppathid = kodi_db.getPath("plugin://plugin.video.emby.tvshows/") temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
tempfileid = kodi_db.addFile(filename, temppathid) tempfileid = self.kodi_db.addFile(filename, temppathid)
query = ' '.join(( query = ' '.join((
"UPDATE files", "UPDATE files",
@ -1559,7 +1544,7 @@ class TVShows(Items):
"WHERE idFile = ?" "WHERE idFile = ?"
)) ))
self.kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid)) self.kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
emby_db.updateReference(itemid, checksum) emby_db.updateReference(itemid, checksum)
@ -1672,27 +1657,23 @@ class TVShows(Items):
def removeShow(self, kodiid): def removeShow(self, kodiid):
kodicursor = self.kodicursor kodicursor = self.kodicursor
artwork = self.artwork self.artwork.deleteArtwork(kodiid, "tvshow", kodicursor)
artwork.deleteArtwork(kodiid, "tvshow", kodicursor)
kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodiid,)) kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodiid,))
self.logMsg("Removed tvshow: %s." % kodiid, 2) self.logMsg("Removed tvshow: %s." % kodiid, 2)
def removeSeason(self, kodiid): def removeSeason(self, kodiid):
kodicursor = self.kodicursor kodicursor = self.kodicursor
artwork = self.artwork
artwork.deleteArtwork(kodiid, "season", kodicursor) self.artwork.deleteArtwork(kodiid, "season", kodicursor)
kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?", (kodiid,)) kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?", (kodiid,))
self.logMsg("Removed season: %s." % kodiid, 2) self.logMsg("Removed season: %s." % kodiid, 2)
def removeEpisode(self, kodiid, fileid): def removeEpisode(self, kodiid, fileid):
kodicursor = self.kodicursor kodicursor = self.kodicursor
artwork = self.artwork
artwork.deleteArtwork(kodiid, "episode", kodicursor) self.artwork.deleteArtwork(kodiid, "episode", kodicursor)
kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodiid,)) kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodiid,))
kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,)) kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
self.logMsg("Removed episode: %s." % kodiid, 2) self.logMsg("Removed episode: %s." % kodiid, 2)
@ -1717,10 +1698,9 @@ class Music(Items):
count = 0 count = 0
for artist in items: for artist in items:
title = artist['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=artist['Name'])
count += 1 count += 1
self.add_updateArtist(artist) self.add_updateArtist(artist)
# Add albums # Add albums
@ -1733,10 +1713,9 @@ class Music(Items):
count = 0 count = 0
for album in items: for album in items:
title = album['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=album['Name'])
count += 1 count += 1
self.add_updateAlbum(album) self.add_updateAlbum(album)
# Add songs # Add songs
@ -1749,21 +1728,18 @@ class Music(Items):
count = 0 count = 0
for song in items: for song in items:
title = song['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=song['Name'])
count += 1 count += 1
self.add_updateSong(song) self.add_updateSong(song)
if not pdialog and self.contentmsg: if not pdialog and self.contentmsg:
self.contentPop(title, self.newmusic_time) self.contentPop(song['Name'], self.newmusic_time)
def add_updateArtist(self, item, artisttype="MusicArtist"): def add_updateArtist(self, item, artisttype="MusicArtist"):
# Process a single artist # Process a single artist
kodiversion = self.kodiversion
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
API = api.API(item) API = api.API(item)
@ -1810,7 +1786,7 @@ class Music(Items):
self.logMsg("ADD artist itemid: %s - Name: %s" % (itemid, name), 1) self.logMsg("ADD artist itemid: %s - Name: %s" % (itemid, name), 1)
# safety checks: It looks like Emby supports the same artist multiple times. # safety checks: It looks like Emby supports the same artist multiple times.
# Kodi doesn't allow that. In case that happens we just merge the artist entries. # Kodi doesn't allow that. In case that happens we just merge the artist entries.
artistid = kodi_db.addArtist(name, musicBrainzId) artistid = self.kodi_db.addArtist(name, musicBrainzId)
# Create the reference in emby table # Create the reference in emby table
emby_db.addReference(itemid, artistid, artisttype, "artist", checksum=checksum) emby_db.addReference(itemid, artistid, artisttype, "artist", checksum=checksum)
@ -1843,10 +1819,8 @@ class Music(Items):
def add_updateAlbum(self, item): def add_updateAlbum(self, item):
# Process a single artist # Process a single artist
emby = self.emby emby = self.emby
kodiversion = self.kodiversion
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
API = api.API(item) API = api.API(item)
@ -1897,13 +1871,13 @@ class Music(Items):
self.logMsg("ADD album itemid: %s - Name: %s" % (itemid, name), 1) self.logMsg("ADD album itemid: %s - Name: %s" % (itemid, name), 1)
# safety checks: It looks like Emby supports the same artist multiple times. # safety checks: It looks like Emby supports the same artist multiple times.
# Kodi doesn't allow that. In case that happens we just merge the artist entries. # Kodi doesn't allow that. In case that happens we just merge the artist entries.
albumid = kodi_db.addAlbum(name, musicBrainzId) albumid = self.kodi_db.addAlbum(name, musicBrainzId)
# Create the reference in emby table # Create the reference in emby table
emby_db.addReference(itemid, albumid, "MusicAlbum", "album", checksum=checksum) emby_db.addReference(itemid, albumid, "MusicAlbum", "album", checksum=checksum)
# Process the album info # Process the album info
if kodiversion == 17: if self.kodiversion == 17:
# Kodi Krypton # Kodi Krypton
query = ' '.join(( query = ' '.join((
@ -1914,7 +1888,7 @@ class Music(Items):
)) ))
kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped, kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
"album", albumid)) "album", albumid))
elif kodiversion == 16: elif self.kodiversion == 16:
# Kodi Jarvis # Kodi Jarvis
query = ' '.join(( query = ' '.join((
@ -1925,7 +1899,7 @@ class Music(Items):
)) ))
kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped, kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
"album", albumid)) "album", albumid))
elif kodiversion == 15: elif self.kodiversion == 15:
# Kodi Isengard # Kodi Isengard
query = ' '.join(( query = ' '.join((
@ -2006,17 +1980,15 @@ class Music(Items):
emby_db.updateParentId(artistId, albumid) emby_db.updateParentId(artistId, albumid)
# Add genres # Add genres
kodi_db.addMusicGenres(albumid, genres, "album") self.kodi_db.addMusicGenres(albumid, genres, "album")
# Update artwork # Update artwork
artwork.addArtwork(artworks, albumid, "album", kodicursor) artwork.addArtwork(artworks, albumid, "album", kodicursor)
def add_updateSong(self, item): def add_updateSong(self, item):
# Process single song # Process single song
kodiversion = self.kodiversion
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby = self.emby emby = self.emby
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
API = api.API(item) API = api.API(item)
@ -2122,7 +2094,7 @@ class Music(Items):
self.logMsg("ADD song itemid: %s - Title: %s" % (itemid, title), 1) self.logMsg("ADD song itemid: %s - Title: %s" % (itemid, title), 1)
# Add path # Add path
pathid = kodi_db.addPath(path) pathid = self.kodi_db.addPath(path)
try: try:
# Get the album # Get the album
@ -2133,7 +2105,7 @@ class Music(Items):
album_name = item.get('Album') album_name = item.get('Album')
if album_name: if album_name:
self.logMsg("Creating virtual music album for song: %s." % itemid, 1) self.logMsg("Creating virtual music album for song: %s." % itemid, 1)
albumid = kodi_db.addAlbum(album_name, API.getProvider('MusicBrainzAlbum')) albumid = self.kodi_db.addAlbum(album_name, API.getProvider('MusicBrainzAlbum'))
emby_db.addReference("%salbum%s" % (itemid, albumid), albumid, "MusicAlbum_", "album") emby_db.addReference("%salbum%s" % (itemid, albumid), albumid, "MusicAlbum_", "album")
else: else:
# No album Id associated to the song. # No album Id associated to the song.
@ -2155,7 +2127,7 @@ class Music(Items):
self.logMsg("Failed to add album. Creating singles.", 1) self.logMsg("Failed to add album. Creating singles.", 1)
kodicursor.execute("select coalesce(max(idAlbum),0) from album") kodicursor.execute("select coalesce(max(idAlbum),0) from album")
albumid = kodicursor.fetchone()[0] + 1 albumid = kodicursor.fetchone()[0] + 1
if kodiversion == 16: if self.kodiversion == 16:
# Kodi Jarvis # Kodi Jarvis
query = ( query = (
''' '''
@ -2165,7 +2137,7 @@ class Music(Items):
''' '''
) )
kodicursor.execute(query, (albumid, genre, year, "single")) kodicursor.execute(query, (albumid, genre, year, "single"))
elif kodiversion == 15: elif self.kodiversion == 15:
# Kodi Isengard # Kodi Isengard
query = ( query = (
''' '''
@ -2289,11 +2261,11 @@ class Music(Items):
result = kodicursor.fetchone() result = kodicursor.fetchone()
if result and result[0] != album_artists: if result and result[0] != album_artists:
# Field is empty # Field is empty
if kodiversion in (16, 17): if self.kodiversion in (16, 17):
# Kodi Jarvis, Krypton # Kodi Jarvis, Krypton
query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?" query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
kodicursor.execute(query, (album_artists, albumid)) kodicursor.execute(query, (album_artists, albumid))
elif kodiversion == 15: elif self.kodiversion == 15:
# Kodi Isengard # Kodi Isengard
query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?" query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
kodicursor.execute(query, (album_artists, albumid)) kodicursor.execute(query, (album_artists, albumid))
@ -2303,7 +2275,7 @@ class Music(Items):
kodicursor.execute(query, (album_artists, albumid)) kodicursor.execute(query, (album_artists, albumid))
# Add genres # Add genres
kodi_db.addMusicGenres(songid, genres, "song") self.kodi_db.addMusicGenres(songid, genres, "song")
# Update artwork # Update artwork
allart = artwork.getAllArtwork(item, parentInfo=True) allart = artwork.getAllArtwork(item, parentInfo=True)
@ -2320,7 +2292,6 @@ class Music(Items):
# Poster with progress bar # Poster with progress bar
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db
API = api.API(item) API = api.API(item)
# Get emby information # Get emby information
@ -2391,10 +2362,9 @@ class Music(Items):
self.removeSong(kodiid) self.removeSong(kodiid)
# This should only address single song scenario, where server doesn't actually # This should only address single song scenario, where server doesn't actually
# create an album for the song. # create an album for the song.
customitems = emby_db.getItem_byWildId(itemid)
emby_db.removeWildItem(itemid) emby_db.removeWildItem(itemid)
for item in customitems: for item in emby_db.getItem_byWildId(itemid):
item_kid = item[0] item_kid = item[0]
item_mediatype = item[1] item_mediatype = item[1]
@ -2448,23 +2418,16 @@ class Music(Items):
def removeSong(self, kodiid): def removeSong(self, kodiid):
kodicursor = self.kodicursor kodicursor = self.kodicursor
artwork = self.artwork
artwork.deleteArtwork(kodiid, "song", kodicursor) self.artwork.deleteArtwork(kodiid, "song", self.kodicursor)
kodicursor.execute("DELETE FROM song WHERE idSong = ?", (kodiid,)) self.kodicursor.execute("DELETE FROM song WHERE idSong = ?", (kodiid,))
def removeAlbum(self, kodiid): def removeAlbum(self, kodiid):
kodicursor = self.kodicursor self.artwork.deleteArtwork(kodiid, "album", self.kodicursor)
artwork = self.artwork self.kodicursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodiid,))
artwork.deleteArtwork(kodiid, "album", kodicursor)
kodicursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodiid,))
def removeArtist(self, kodiid): def removeArtist(self, kodiid):
kodicursor = self.kodicursor self.artwork.deleteArtwork(kodiid, "artist", self.kodicursor)
artwork = self.artwork self.kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiid,))
artwork.deleteArtwork(kodiid, "artist", kodicursor)
kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiid,))

View file

@ -33,20 +33,18 @@ class Kodidb_Functions():
def addPath(self, path): def addPath(self, path):
cursor = self.cursor
query = ' '.join(( query = ' '.join((
"SELECT idPath", "SELECT idPath",
"FROM path", "FROM path",
"WHERE strPath = ?" "WHERE strPath = ?"
)) ))
cursor.execute(query, (path,)) self.cursor.execute(query, (path,))
try: try:
pathid = cursor.fetchone()[0] pathid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
cursor.execute("select coalesce(max(idPath),0) from path") self.cursor.execute("select coalesce(max(idPath),0) from path")
pathid = cursor.fetchone()[0] + 1 pathid = self.cursor.fetchone()[0] + 1
query = ( query = (
''' '''
INSERT INTO path( INSERT INTO path(
@ -55,23 +53,21 @@ class Kodidb_Functions():
VALUES (?, ?) VALUES (?, ?)
''' '''
) )
cursor.execute(query, (pathid, path)) self.cursor.execute(query, (pathid, path))
return pathid return pathid
def getPath(self, path): def getPath(self, path):
cursor = self.cursor
query = ' '.join(( query = ' '.join((
"SELECT idPath", "SELECT idPath",
"FROM path", "FROM path",
"WHERE strPath = ?" "WHERE strPath = ?"
)) ))
cursor.execute(query, (path,)) self.cursor.execute(query, (path,))
try: try:
pathid = cursor.fetchone()[0] pathid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
pathid = None pathid = None
@ -79,8 +75,6 @@ class Kodidb_Functions():
def addFile(self, filename, pathid): def addFile(self, filename, pathid):
cursor = self.cursor
query = ' '.join(( query = ' '.join((
"SELECT idFile", "SELECT idFile",
@ -88,12 +82,12 @@ class Kodidb_Functions():
"WHERE strFilename = ?", "WHERE strFilename = ?",
"AND idPath = ?" "AND idPath = ?"
)) ))
cursor.execute(query, (filename, pathid,)) self.cursor.execute(query, (filename, pathid,))
try: try:
fileid = cursor.fetchone()[0] fileid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
cursor.execute("select coalesce(max(idFile),0) from files") self.cursor.execute("select coalesce(max(idFile),0) from files")
fileid = cursor.fetchone()[0] + 1 fileid = self.cursor.fetchone()[0] + 1
query = ( query = (
''' '''
INSERT INTO files( INSERT INTO files(
@ -102,23 +96,21 @@ class Kodidb_Functions():
VALUES (?, ?) VALUES (?, ?)
''' '''
) )
cursor.execute(query, (fileid, filename)) self.cursor.execute(query, (fileid, filename))
return fileid return fileid
def getFile(self, fileid): def getFile(self, fileid):
cursor = self.cursor
query = ' '.join(( query = ' '.join((
"SELECT strFilename", "SELECT strFilename",
"FROM files", "FROM files",
"WHERE idFile = ?" "WHERE idFile = ?"
)) ))
cursor.execute(query, (fileid,)) self.cursor.execute(query, (fileid,))
try: try:
filename = cursor.fetchone()[0] filename = self.cursor.fetchone()[0]
except TypeError: except TypeError:
filename = "" filename = ""
@ -139,8 +131,6 @@ class Kodidb_Functions():
def addCountries(self, kodiid, countries, mediatype): def addCountries(self, kodiid, countries, mediatype):
cursor = self.cursor
if self.kodiversion in (15, 16, 17): if self.kodiversion in (15, 16, 17):
# Kodi Isengard, Jarvis, Krypton # Kodi Isengard, Jarvis, Krypton
for country in countries: for country in countries:
@ -151,18 +141,18 @@ class Kodidb_Functions():
"WHERE name = ?", "WHERE name = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (country,)) self.cursor.execute(query, (country,))
try: try:
country_id = cursor.fetchone()[0] country_id = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Country entry does not exists # Country entry does not exists
cursor.execute("select coalesce(max(country_id),0) from country") self.cursor.execute("select coalesce(max(country_id),0) from country")
country_id = cursor.fetchone()[0] + 1 country_id = self.cursor.fetchone()[0] + 1
query = "INSERT INTO country(country_id, name) values(?, ?)" query = "INSERT INTO country(country_id, name) values(?, ?)"
cursor.execute(query, (country_id, country)) self.cursor.execute(query, (country_id, country))
self.logMsg("Add country to media, processing: %s" % country, 2) self.logMsg("Add country to media, processing: %s" % country, 2)
finally: # Assign country to content finally: # Assign country to content
@ -174,7 +164,7 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''' '''
) )
cursor.execute(query, (country_id, kodiid, mediatype)) self.cursor.execute(query, (country_id, kodiid, mediatype))
else: else:
# Kodi Helix # Kodi Helix
for country in countries: for country in countries:
@ -185,18 +175,18 @@ class Kodidb_Functions():
"WHERE strCountry = ?", "WHERE strCountry = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (country,)) self.cursor.execute(query, (country,))
try: try:
idCountry = cursor.fetchone()[0] idCountry = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Country entry does not exists # Country entry does not exists
cursor.execute("select coalesce(max(idCountry),0) from country") self.cursor.execute("select coalesce(max(idCountry),0) from country")
idCountry = cursor.fetchone()[0] + 1 idCountry = self.cursor.fetchone()[0] + 1
query = "INSERT INTO country(idCountry, strCountry) values(?, ?)" query = "INSERT INTO country(idCountry, strCountry) values(?, ?)"
cursor.execute(query, (idCountry, country)) self.cursor.execute(query, (idCountry, country))
self.logMsg("Add country to media, processing: %s" % country, 2) self.logMsg("Add country to media, processing: %s" % country, 2)
finally: finally:
@ -210,23 +200,19 @@ class Kodidb_Functions():
VALUES (?, ?) VALUES (?, ?)
''' '''
) )
cursor.execute(query, (idCountry, kodiid)) self.cursor.execute(query, (idCountry, kodiid))
def addPeople(self, kodiid, people, mediatype): def addPeople(self, kodiid, people, mediatype):
cursor = self.cursor
artwork = self.artwork
kodiversion = self.kodiversion
castorder = 1 castorder = 1
for person in people: for person in people:
name = person['Name'] name = person['Name']
type = person['Type'] person_type = person['Type']
thumb = person['imageurl'] thumb = person['imageurl']
# Kodi Isengard, Jarvis, Krypton # Kodi Isengard, Jarvis, Krypton
if kodiversion in (15, 16, 17): if self.kodiversion in (15, 16, 17):
query = ' '.join(( query = ' '.join((
"SELECT actor_id", "SELECT actor_id",
@ -234,23 +220,23 @@ class Kodidb_Functions():
"WHERE name = ?", "WHERE name = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (name,)) self.cursor.execute(query, (name,))
try: try:
actorid = cursor.fetchone()[0] actorid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Cast entry does not exists # Cast entry does not exists
cursor.execute("select coalesce(max(actor_id),0) from actor") self.cursor.execute("select coalesce(max(actor_id),0) from actor")
actorid = cursor.fetchone()[0] + 1 actorid = self.cursor.fetchone()[0] + 1
query = "INSERT INTO actor(actor_id, name) values(?, ?)" query = "INSERT INTO actor(actor_id, name) values(?, ?)"
cursor.execute(query, (actorid, name)) self.cursor.execute(query, (actorid, name))
self.logMsg("Add people to media, processing: %s" % name, 2) self.logMsg("Add people to media, processing: %s" % name, 2)
finally: finally:
# Link person to content # Link person to content
if "Actor" in type: if "Actor" in person_type:
role = person.get('Role') role = person.get('Role')
query = ( query = (
''' '''
@ -260,10 +246,10 @@ class Kodidb_Functions():
VALUES (?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?)
''' '''
) )
cursor.execute(query, (actorid, kodiid, mediatype, role, castorder)) self.cursor.execute(query, (actorid, kodiid, mediatype, role, castorder))
castorder += 1 castorder += 1
elif "Director" in type: elif "Director" in person_type:
query = ( query = (
''' '''
INSERT OR REPLACE INTO director_link( INSERT OR REPLACE INTO director_link(
@ -272,9 +258,9 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''' '''
) )
cursor.execute(query, (actorid, kodiid, mediatype)) self.cursor.execute(query, (actorid, kodiid, mediatype))
elif type in ("Writing", "Writer"): elif person_type in ("Writing", "Writer"):
query = ( query = (
''' '''
INSERT OR REPLACE INTO writer_link( INSERT OR REPLACE INTO writer_link(
@ -283,9 +269,9 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''' '''
) )
cursor.execute(query, (actorid, kodiid, mediatype)) self.cursor.execute(query, (actorid, kodiid, mediatype))
elif "Artist" in type: elif "Artist" in person_type:
query = ( query = (
''' '''
INSERT OR REPLACE INTO actor_link( INSERT OR REPLACE INTO actor_link(
@ -294,7 +280,7 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''' '''
) )
cursor.execute(query, (actorid, kodiid, mediatype)) self.cursor.execute(query, (actorid, kodiid, mediatype))
# Kodi Helix # Kodi Helix
else: else:
query = ' '.join(( query = ' '.join((
@ -304,23 +290,23 @@ class Kodidb_Functions():
"WHERE strActor = ?", "WHERE strActor = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (name,)) self.cursor.execute(query, (name,))
try: try:
actorid = cursor.fetchone()[0] actorid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Cast entry does not exists # Cast entry does not exists
cursor.execute("select coalesce(max(idActor),0) from actors") self.cursor.execute("select coalesce(max(idActor),0) from actors")
actorid = cursor.fetchone()[0] + 1 actorid = self.cursor.fetchone()[0] + 1
query = "INSERT INTO actors(idActor, strActor) values(?, ?)" query = "INSERT INTO actors(idActor, strActor) values(?, ?)"
cursor.execute(query, (actorid, name)) self.cursor.execute(query, (actorid, name))
self.logMsg("Add people to media, processing: %s" % name, 2) self.logMsg("Add people to media, processing: %s" % name, 2)
finally: finally:
# Link person to content # Link person to content
if "Actor" in type: if "Actor" in person_type:
role = person.get('Role') role = person.get('Role')
if "movie" in mediatype: if "movie" in mediatype:
@ -352,10 +338,10 @@ class Kodidb_Functions():
) )
else: return # Item is invalid else: return # Item is invalid
cursor.execute(query, (actorid, kodiid, role, castorder)) self.cursor.execute(query, (actorid, kodiid, role, castorder))
castorder += 1 castorder += 1
elif "Director" in type: elif "Director" in person_type:
if "movie" in mediatype: if "movie" in mediatype:
query = ( query = (
''' '''
@ -395,9 +381,9 @@ class Kodidb_Functions():
) )
else: return # Item is invalid else: return # Item is invalid
cursor.execute(query, (actorid, kodiid)) self.cursor.execute(query, (actorid, kodiid))
elif type in ("Writing", "Writer"): elif person_type in ("Writing", "Writer"):
if "movie" in mediatype: if "movie" in mediatype:
query = ( query = (
''' '''
@ -418,9 +404,9 @@ class Kodidb_Functions():
) )
else: return # Item is invalid else: return # Item is invalid
cursor.execute(query, (actorid, kodiid)) self.cursor.execute(query, (actorid, kodiid))
elif "Artist" in type: elif "Artist" in person_type:
query = ( query = (
''' '''
INSERT OR REPLACE INTO artistlinkmusicvideo( INSERT OR REPLACE INTO artistlinkmusicvideo(
@ -429,20 +415,19 @@ class Kodidb_Functions():
VALUES (?, ?) VALUES (?, ?)
''' '''
) )
cursor.execute(query, (actorid, kodiid)) self.cursor.execute(query, (actorid, kodiid))
# Add person image to art table # Add person image to art table
if thumb: if thumb:
arttype = type.lower() arttype = person_type.lower()
if "writing" in arttype: if "writing" in arttype:
arttype = "writer" arttype = "writer"
artwork.addOrUpdateArt(thumb, actorid, arttype, "thumb", cursor) self.artwork.addOrUpdateArt(thumb, actorid, arttype, "thumb", self.cursor)
def addGenres(self, kodiid, genres, mediatype): def addGenres(self, kodiid, genres, mediatype):
cursor = self.cursor
# Kodi Isengard, Jarvis, Krypton # Kodi Isengard, Jarvis, Krypton
if self.kodiversion in (15, 16, 17): if self.kodiversion in (15, 16, 17):
@ -453,7 +438,7 @@ class Kodidb_Functions():
"WHERE media_id = ?", "WHERE media_id = ?",
"AND media_type = ?" "AND media_type = ?"
)) ))
cursor.execute(query, (kodiid, mediatype,)) self.cursor.execute(query, (kodiid, mediatype,))
# Add genres # Add genres
for genre in genres: for genre in genres:
@ -465,18 +450,18 @@ class Kodidb_Functions():
"WHERE name = ?", "WHERE name = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (genre,)) self.cursor.execute(query, (genre,))
try: try:
genre_id = cursor.fetchone()[0] genre_id = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Create genre in database # Create genre in database
cursor.execute("select coalesce(max(genre_id),0) from genre") self.cursor.execute("select coalesce(max(genre_id),0) from genre")
genre_id = cursor.fetchone()[0] + 1 genre_id = self.cursor.fetchone()[0] + 1
query = "INSERT INTO genre(genre_id, name) values(?, ?)" query = "INSERT INTO genre(genre_id, name) values(?, ?)"
cursor.execute(query, (genre_id, genre)) self.cursor.execute(query, (genre_id, genre))
self.logMsg("Add Genres to media, processing: %s" % genre, 2) self.logMsg("Add Genres to media, processing: %s" % genre, 2)
finally: finally:
@ -489,16 +474,16 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''' '''
) )
cursor.execute(query, (genre_id, kodiid, mediatype)) self.cursor.execute(query, (genre_id, kodiid, mediatype))
else: else:
# Kodi Helix # Kodi Helix
# Delete current genres for clean slate # Delete current genres for clean slate
if "movie" in mediatype: if "movie" in mediatype:
cursor.execute("DELETE FROM genrelinkmovie WHERE idMovie = ?", (kodiid,)) self.cursor.execute("DELETE FROM genrelinkmovie WHERE idMovie = ?", (kodiid,))
elif "tvshow" in mediatype: elif "tvshow" in mediatype:
cursor.execute("DELETE FROM genrelinktvshow WHERE idShow = ?", (kodiid,)) self.cursor.execute("DELETE FROM genrelinktvshow WHERE idShow = ?", (kodiid,))
elif "musicvideo" in mediatype: elif "musicvideo" in mediatype:
cursor.execute("DELETE FROM genrelinkmusicvideo WHERE idMVideo = ?", (kodiid,)) self.cursor.execute("DELETE FROM genrelinkmusicvideo WHERE idMVideo = ?", (kodiid,))
# Add genres # Add genres
for genre in genres: for genre in genres:
@ -510,18 +495,18 @@ class Kodidb_Functions():
"WHERE strGenre = ?", "WHERE strGenre = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (genre,)) self.cursor.execute(query, (genre,))
try: try:
idGenre = cursor.fetchone()[0] idGenre = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Create genre in database # Create genre in database
cursor.execute("select coalesce(max(idGenre),0) from genre") self.cursor.execute("select coalesce(max(idGenre),0) from genre")
idGenre = cursor.fetchone()[0] + 1 idGenre = self.cursor.fetchone()[0] + 1
query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)" query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)"
cursor.execute(query, (idGenre, genre)) self.cursor.execute(query, (idGenre, genre))
self.logMsg("Add Genres to media, processing: %s" % genre, 2) self.logMsg("Add Genres to media, processing: %s" % genre, 2)
finally: finally:
@ -555,16 +540,13 @@ class Kodidb_Functions():
) )
else: return # Item is invalid else: return # Item is invalid
cursor.execute(query, (idGenre, kodiid)) self.cursor.execute(query, (idGenre, kodiid))
def addStudios(self, kodiid, studios, mediatype): def addStudios(self, kodiid, studios, mediatype):
cursor = self.cursor
kodiversion = self.kodiversion
for studio in studios: for studio in studios:
if kodiversion in (15, 16, 17): if self.kodiversion in (15, 16, 17):
# Kodi Isengard, Jarvis, Krypton # Kodi Isengard, Jarvis, Krypton
query = ' '.join(( query = ' '.join((
@ -573,17 +555,17 @@ class Kodidb_Functions():
"WHERE name = ?", "WHERE name = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (studio,)) self.cursor.execute(query, (studio,))
try: try:
studioid = cursor.fetchone()[0] studioid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Studio does not exists. # Studio does not exists.
cursor.execute("select coalesce(max(studio_id),0) from studio") self.cursor.execute("select coalesce(max(studio_id),0) from studio")
studioid = cursor.fetchone()[0] + 1 studioid = self.cursor.fetchone()[0] + 1
query = "INSERT INTO studio(studio_id, name) values(?, ?)" query = "INSERT INTO studio(studio_id, name) values(?, ?)"
cursor.execute(query, (studioid, studio)) self.cursor.execute(query, (studioid, studio))
self.logMsg("Add Studios to media, processing: %s" % studio, 2) self.logMsg("Add Studios to media, processing: %s" % studio, 2)
finally: # Assign studio to item finally: # Assign studio to item
@ -594,7 +576,7 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''') ''')
cursor.execute(query, (studioid, kodiid, mediatype)) self.cursor.execute(query, (studioid, kodiid, mediatype))
else: else:
# Kodi Helix # Kodi Helix
query = ' '.join(( query = ' '.join((
@ -604,17 +586,17 @@ class Kodidb_Functions():
"WHERE strstudio = ?", "WHERE strstudio = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (studio,)) self.cursor.execute(query, (studio,))
try: try:
studioid = cursor.fetchone()[0] studioid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Studio does not exists. # Studio does not exists.
cursor.execute("select coalesce(max(idstudio),0) from studio") self.cursor.execute("select coalesce(max(idstudio),0) from studio")
studioid = cursor.fetchone()[0] + 1 studioid = self.cursor.fetchone()[0] + 1
query = "INSERT INTO studio(idstudio, strstudio) values(?, ?)" query = "INSERT INTO studio(idstudio, strstudio) values(?, ?)"
cursor.execute(query, (studioid, studio)) self.cursor.execute(query, (studioid, studio))
self.logMsg("Add Studios to media, processing: %s" % studio, 2) self.logMsg("Add Studios to media, processing: %s" % studio, 2)
finally: # Assign studio to item finally: # Assign studio to item
@ -642,14 +624,12 @@ class Kodidb_Functions():
INSERT OR REPLACE INTO studiolinkepisode(idstudio, idEpisode) INSERT OR REPLACE INTO studiolinkepisode(idstudio, idEpisode)
VALUES (?, ?) VALUES (?, ?)
''') ''')
cursor.execute(query, (studioid, kodiid)) self.cursor.execute(query, (studioid, kodiid))
def addStreams(self, fileid, streamdetails, runtime): def addStreams(self, fileid, streamdetails, runtime):
cursor = self.cursor
# First remove any existing entries # First remove any existing entries
cursor.execute("DELETE FROM streamdetails WHERE idFile = ?", (fileid,)) self.cursor.execute("DELETE FROM streamdetails WHERE idFile = ?", (fileid,))
if streamdetails: if streamdetails:
# Video details # Video details
for videotrack in streamdetails['video']: for videotrack in streamdetails['video']:
@ -662,7 +642,7 @@ class Kodidb_Functions():
VALUES (?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
''' '''
) )
cursor.execute(query, (fileid, 0, videotrack['codec'], self.cursor.execute(query, (fileid, 0, videotrack['codec'],
videotrack['aspect'], videotrack['width'], videotrack['height'], videotrack['aspect'], videotrack['width'], videotrack['height'],
runtime ,videotrack['video3DFormat'])) runtime ,videotrack['video3DFormat']))
@ -676,7 +656,7 @@ class Kodidb_Functions():
VALUES (?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?)
''' '''
) )
cursor.execute(query, (fileid, 1, audiotrack['codec'], self.cursor.execute(query, (fileid, 1, audiotrack['codec'],
audiotrack['channels'], audiotrack['language'])) audiotrack['channels'], audiotrack['language']))
# Subtitles details # Subtitles details
@ -689,19 +669,17 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''' '''
) )
cursor.execute(query, (fileid, 2, subtitletrack)) self.cursor.execute(query, (fileid, 2, subtitletrack))
def addPlaystate(self, fileid, resume_seconds, total_seconds, playcount, dateplayed): def addPlaystate(self, fileid, resume_seconds, total_seconds, playcount, dateplayed):
cursor = self.cursor
# Delete existing resume point # Delete existing resume point
query = ' '.join(( query = ' '.join((
"DELETE FROM bookmark", "DELETE FROM bookmark",
"WHERE idFile = ?" "WHERE idFile = ?"
)) ))
cursor.execute(query, (fileid,)) self.cursor.execute(query, (fileid,))
# Set watched count # Set watched count
query = ' '.join(( query = ' '.join((
@ -710,12 +688,12 @@ class Kodidb_Functions():
"SET playCount = ?, lastPlayed = ?", "SET playCount = ?, lastPlayed = ?",
"WHERE idFile = ?" "WHERE idFile = ?"
)) ))
cursor.execute(query, (playcount, dateplayed, fileid)) self.cursor.execute(query, (playcount, dateplayed, fileid))
# Set the resume bookmark # Set the resume bookmark
if resume_seconds: if resume_seconds:
cursor.execute("select coalesce(max(idBookmark),0) from bookmark") self.cursor.execute("select coalesce(max(idBookmark),0) from bookmark")
bookmarkId = cursor.fetchone()[0] + 1 bookmarkId = self.cursor.fetchone()[0] + 1
query = ( query = (
''' '''
INSERT INTO bookmark( INSERT INTO bookmark(
@ -724,13 +702,11 @@ class Kodidb_Functions():
VALUES (?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?)
''' '''
) )
cursor.execute(query, (bookmarkId, fileid, resume_seconds, total_seconds, self.cursor.execute(query, (bookmarkId, fileid, resume_seconds, total_seconds,
"DVDPlayer", 1)) "DVDPlayer", 1))
def addTags(self, kodiid, tags, mediatype): def addTags(self, kodiid, tags, mediatype):
cursor = self.cursor
# First, delete any existing tags associated to the id # First, delete any existing tags associated to the id
if self.kodiversion in (15, 16, 17): if self.kodiversion in (15, 16, 17):
# Kodi Isengard, Jarvis, Krypton # Kodi Isengard, Jarvis, Krypton
@ -740,7 +716,7 @@ class Kodidb_Functions():
"WHERE media_id = ?", "WHERE media_id = ?",
"AND media_type = ?" "AND media_type = ?"
)) ))
cursor.execute(query, (kodiid, mediatype)) self.cursor.execute(query, (kodiid, mediatype))
else: else:
# Kodi Helix # Kodi Helix
query = ' '.join(( query = ' '.join((
@ -749,7 +725,7 @@ class Kodidb_Functions():
"WHERE idMedia = ?", "WHERE idMedia = ?",
"AND media_type = ?" "AND media_type = ?"
)) ))
cursor.execute(query, (kodiid, mediatype)) self.cursor.execute(query, (kodiid, mediatype))
# Add tags # Add tags
self.logMsg("Adding Tags: %s" % tags, 2) self.logMsg("Adding Tags: %s" % tags, 2)
@ -758,8 +734,6 @@ class Kodidb_Functions():
def addTag(self, kodiid, tag, mediatype): def addTag(self, kodiid, tag, mediatype):
cursor = self.cursor
if self.kodiversion in (15, 16, 17): if self.kodiversion in (15, 16, 17):
# Kodi Isengard, Jarvis, Krypton # Kodi Isengard, Jarvis, Krypton
query = ' '.join(( query = ' '.join((
@ -769,9 +743,9 @@ class Kodidb_Functions():
"WHERE name = ?", "WHERE name = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (tag,)) self.cursor.execute(query, (tag,))
try: try:
tag_id = cursor.fetchone()[0] tag_id = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Create the tag, because it does not exist # Create the tag, because it does not exist
@ -788,7 +762,7 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''' '''
) )
cursor.execute(query, (tag_id, kodiid, mediatype)) self.cursor.execute(query, (tag_id, kodiid, mediatype))
else: else:
# Kodi Helix # Kodi Helix
query = ' '.join(( query = ' '.join((
@ -798,9 +772,9 @@ class Kodidb_Functions():
"WHERE strTag = ?", "WHERE strTag = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (tag,)) self.cursor.execute(query, (tag,))
try: try:
tag_id = cursor.fetchone()[0] tag_id = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Create the tag # Create the tag
@ -817,12 +791,10 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''' '''
) )
cursor.execute(query, (tag_id, kodiid, mediatype)) self.cursor.execute(query, (tag_id, kodiid, mediatype))
def createTag(self, name): def createTag(self, name):
cursor = self.cursor
# This will create and return the tag_id # This will create and return the tag_id
if self.kodiversion in (15, 16, 17): if self.kodiversion in (15, 16, 17):
# Kodi Isengard, Jarvis, Krypton # Kodi Isengard, Jarvis, Krypton
@ -833,16 +805,16 @@ class Kodidb_Functions():
"WHERE name = ?", "WHERE name = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (name,)) self.cursor.execute(query, (name,))
try: try:
tag_id = cursor.fetchone()[0] tag_id = self.cursor.fetchone()[0]
except TypeError: except TypeError:
cursor.execute("select coalesce(max(tag_id),0) from tag") self.cursor.execute("select coalesce(max(tag_id),0) from tag")
tag_id = cursor.fetchone()[0] + 1 tag_id = self.cursor.fetchone()[0] + 1
query = "INSERT INTO tag(tag_id, name) values(?, ?)" query = "INSERT INTO tag(tag_id, name) values(?, ?)"
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) self.logMsg("Create tag_id: %s name: %s" % (tag_id, name), 2)
else: else:
# Kodi Helix # Kodi Helix
@ -853,23 +825,22 @@ class Kodidb_Functions():
"WHERE strTag = ?", "WHERE strTag = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (name,)) self.cursor.execute(query, (name,))
try: try:
tag_id = cursor.fetchone()[0] tag_id = self.cursor.fetchone()[0]
except TypeError: except TypeError:
cursor.execute("select coalesce(max(idTag),0) from tag") self.cursor.execute("select coalesce(max(idTag),0) from tag")
tag_id = cursor.fetchone()[0] + 1 tag_id = self.cursor.fetchone()[0] + 1
query = "INSERT INTO tag(idTag, strTag) values(?, ?)" query = "INSERT INTO tag(idTag, strTag) values(?, ?)"
cursor.execute(query, (tag_id, name)) self.cursor.execute(query, (tag_id, name))
self.logMsg("Create idTag: %s name: %s" % (tag_id, name), 2) self.logMsg("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):
cursor = self.cursor
self.logMsg("Updating: %s with %s for %s: %s" % (oldtag, newtag, mediatype, kodiid), 2) self.logMsg("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):
@ -883,7 +854,7 @@ class Kodidb_Functions():
"AND media_type = ?", "AND media_type = ?",
"AND tag_id = ?" "AND tag_id = ?"
)) ))
cursor.execute(query, (newtag, kodiid, mediatype, oldtag,)) self.cursor.execute(query, (newtag, kodiid, mediatype, oldtag,))
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
@ -895,7 +866,7 @@ class Kodidb_Functions():
"AND media_type = ?", "AND media_type = ?",
"AND tag_id = ?" "AND tag_id = ?"
)) ))
cursor.execute(query, (kodiid, mediatype, oldtag,)) self.cursor.execute(query, (kodiid, mediatype, oldtag,))
else: else:
# Kodi Helix # Kodi Helix
try: try:
@ -907,7 +878,7 @@ class Kodidb_Functions():
"AND media_type = ?", "AND media_type = ?",
"AND idTag = ?" "AND idTag = ?"
)) ))
cursor.execute(query, (newtag, kodiid, mediatype, oldtag,)) self.cursor.execute(query, (newtag, kodiid, mediatype, oldtag,))
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
@ -919,12 +890,10 @@ class Kodidb_Functions():
"AND media_type = ?", "AND media_type = ?",
"AND idTag = ?" "AND idTag = ?"
)) ))
cursor.execute(query, (kodiid, mediatype, oldtag,)) self.cursor.execute(query, (kodiid, mediatype, oldtag,))
def removeTag(self, kodiid, tagname, mediatype): def removeTag(self, kodiid, tagname, mediatype):
cursor = self.cursor
if self.kodiversion in (15, 16, 17): if self.kodiversion in (15, 16, 17):
# Kodi Isengard, Jarvis, Krypton # Kodi Isengard, Jarvis, Krypton
query = ' '.join(( query = ' '.join((
@ -934,9 +903,9 @@ class Kodidb_Functions():
"WHERE name = ?", "WHERE name = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (tagname,)) self.cursor.execute(query, (tagname,))
try: try:
tag_id = cursor.fetchone()[0] tag_id = self.cursor.fetchone()[0]
except TypeError: except TypeError:
return return
else: else:
@ -947,7 +916,7 @@ class Kodidb_Functions():
"AND media_type = ?", "AND media_type = ?",
"AND tag_id = ?" "AND tag_id = ?"
)) ))
cursor.execute(query, (kodiid, mediatype, tag_id,)) self.cursor.execute(query, (kodiid, mediatype, tag_id,))
else: else:
# Kodi Helix # Kodi Helix
query = ' '.join(( query = ' '.join((
@ -957,9 +926,9 @@ class Kodidb_Functions():
"WHERE strTag = ?", "WHERE strTag = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (tagname,)) self.cursor.execute(query, (tagname,))
try: try:
tag_id = cursor.fetchone()[0] tag_id = self.cursor.fetchone()[0]
except TypeError: except TypeError:
return return
else: else:
@ -970,11 +939,10 @@ class Kodidb_Functions():
"AND media_type = ?", "AND media_type = ?",
"AND idTag = ?" "AND idTag = ?"
)) ))
cursor.execute(query, (kodiid, mediatype, tag_id,)) self.cursor.execute(query, (kodiid, mediatype, tag_id,))
def createBoxset(self, boxsetname): def createBoxset(self, boxsetname):
cursor = self.cursor
self.logMsg("Adding boxset: %s" % boxsetname, 2) self.logMsg("Adding boxset: %s" % boxsetname, 2)
query = ' '.join(( query = ' '.join((
@ -983,16 +951,16 @@ class Kodidb_Functions():
"WHERE strSet = ?", "WHERE strSet = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (boxsetname,)) self.cursor.execute(query, (boxsetname,))
try: try:
setid = cursor.fetchone()[0] setid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
cursor.execute("select coalesce(max(idSet),0) from sets") self.cursor.execute("select coalesce(max(idSet),0) from sets")
setid = cursor.fetchone()[0] + 1 setid = self.cursor.fetchone()[0] + 1
query = "INSERT INTO sets(idSet, strSet) values(?, ?)" query = "INSERT INTO sets(idSet, strSet) values(?, ?)"
cursor.execute(query, (setid, boxsetname)) self.cursor.execute(query, (setid, boxsetname))
return setid return setid
@ -1018,8 +986,6 @@ class Kodidb_Functions():
def addSeason(self, showid, seasonnumber): def addSeason(self, showid, seasonnumber):
cursor = self.cursor
query = ' '.join(( query = ' '.join((
"SELECT idSeason", "SELECT idSeason",
@ -1027,30 +993,28 @@ class Kodidb_Functions():
"WHERE idShow = ?", "WHERE idShow = ?",
"AND season = ?" "AND season = ?"
)) ))
cursor.execute(query, (showid, seasonnumber,)) self.cursor.execute(query, (showid, seasonnumber,))
try: try:
seasonid = cursor.fetchone()[0] seasonid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
cursor.execute("select coalesce(max(idSeason),0) from seasons") self.cursor.execute("select coalesce(max(idSeason),0) from seasons")
seasonid = cursor.fetchone()[0] + 1 seasonid = self.cursor.fetchone()[0] + 1
query = "INSERT INTO seasons(idSeason, idShow, season) values(?, ?, ?)" query = "INSERT INTO seasons(idSeason, idShow, season) values(?, ?, ?)"
cursor.execute(query, (seasonid, showid, seasonnumber)) self.cursor.execute(query, (seasonid, showid, seasonnumber))
return seasonid return seasonid
def addArtist(self, name, musicbrainz): def addArtist(self, name, musicbrainz):
cursor = self.cursor
query = ' '.join(( query = ' '.join((
"SELECT idArtist, strArtist", "SELECT idArtist, strArtist",
"FROM artist", "FROM artist",
"WHERE strMusicBrainzArtistID = ?" "WHERE strMusicBrainzArtistID = ?"
)) ))
cursor.execute(query, (musicbrainz,)) self.cursor.execute(query, (musicbrainz,))
try: try:
result = cursor.fetchone() result = self.cursor.fetchone()
artistid = result[0] artistid = result[0]
artistname = result[1] artistname = result[1]
@ -1063,12 +1027,12 @@ class Kodidb_Functions():
"WHERE strArtist = ?", "WHERE strArtist = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (name,)) self.cursor.execute(query, (name,))
try: try:
artistid = cursor.fetchone()[0] artistid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
cursor.execute("select coalesce(max(idArtist),0) from artist") self.cursor.execute("select coalesce(max(idArtist),0) from artist")
artistid = cursor.fetchone()[0] + 1 artistid = self.cursor.fetchone()[0] + 1
query = ( query = (
''' '''
INSERT INTO artist(idArtist, strArtist, strMusicBrainzArtistID) INSERT INTO artist(idArtist, strArtist, strMusicBrainzArtistID)
@ -1076,33 +1040,30 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''' '''
) )
cursor.execute(query, (artistid, name, musicbrainz)) self.cursor.execute(query, (artistid, name, musicbrainz))
else: else:
if artistname != name: if artistname != name:
query = "UPDATE artist SET strArtist = ? WHERE idArtist = ?" query = "UPDATE artist SET strArtist = ? WHERE idArtist = ?"
cursor.execute(query, (name, artistid,)) self.cursor.execute(query, (name, artistid,))
return artistid return artistid
def addAlbum(self, name, musicbrainz): def addAlbum(self, name, musicbrainz):
kodiversion = self.kodiversion
cursor = self.cursor
query = ' '.join(( query = ' '.join((
"SELECT idAlbum", "SELECT idAlbum",
"FROM album", "FROM album",
"WHERE strMusicBrainzAlbumID = ?" "WHERE strMusicBrainzAlbumID = ?"
)) ))
cursor.execute(query, (musicbrainz,)) self.cursor.execute(query, (musicbrainz,))
try: try:
albumid = cursor.fetchone()[0] albumid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Create the album # Create the album
cursor.execute("select coalesce(max(idAlbum),0) from album") self.cursor.execute("select coalesce(max(idAlbum),0) from album")
albumid = cursor.fetchone()[0] + 1 albumid = self.cursor.fetchone()[0] + 1
if kodiversion in (15, 16, 17): if self.kodiversion in (15, 16, 17):
query = ( query = (
''' '''
INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID, strReleaseType) INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID, strReleaseType)
@ -1110,7 +1071,7 @@ class Kodidb_Functions():
VALUES (?, ?, ?, ?) VALUES (?, ?, ?, ?)
''' '''
) )
cursor.execute(query, (albumid, name, musicbrainz, "album")) self.cursor.execute(query, (albumid, name, musicbrainz, "album"))
else: # Helix else: # Helix
query = ( query = (
''' '''
@ -1119,14 +1080,12 @@ class Kodidb_Functions():
VALUES (?, ?, ?) VALUES (?, ?, ?)
''' '''
) )
cursor.execute(query, (albumid, name, musicbrainz)) self.cursor.execute(query, (albumid, name, musicbrainz))
return albumid return albumid
def addMusicGenres(self, kodiid, genres, mediatype): def addMusicGenres(self, kodiid, genres, mediatype):
cursor = self.cursor
if mediatype == "album": if mediatype == "album":
# Delete current genres for clean slate # Delete current genres for clean slate
@ -1135,7 +1094,7 @@ class Kodidb_Functions():
"DELETE FROM album_genre", "DELETE FROM album_genre",
"WHERE idAlbum = ?" "WHERE idAlbum = ?"
)) ))
cursor.execute(query, (kodiid,)) self.cursor.execute(query, (kodiid,))
for genre in genres: for genre in genres:
query = ' '.join(( query = ' '.join((
@ -1145,18 +1104,18 @@ class Kodidb_Functions():
"WHERE strGenre = ?", "WHERE strGenre = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (genre,)) self.cursor.execute(query, (genre,))
try: try:
genreid = cursor.fetchone()[0] genreid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Create the genre # Create the genre
cursor.execute("select coalesce(max(idGenre),0) from genre") self.cursor.execute("select coalesce(max(idGenre),0) from genre")
genreid = cursor.fetchone()[0] + 1 genreid = self.cursor.fetchone()[0] + 1
query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)" query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)"
cursor.execute(query, (genreid, genre)) self.cursor.execute(query, (genreid, genre))
query = "INSERT OR REPLACE INTO album_genre(idGenre, idAlbum) values(?, ?)" query = "INSERT OR REPLACE INTO album_genre(idGenre, idAlbum) values(?, ?)"
cursor.execute(query, (genreid, kodiid)) self.cursor.execute(query, (genreid, kodiid))
elif mediatype == "song": elif mediatype == "song":
@ -1166,7 +1125,7 @@ class Kodidb_Functions():
"DELETE FROM song_genre", "DELETE FROM song_genre",
"WHERE idSong = ?" "WHERE idSong = ?"
)) ))
cursor.execute(query, (kodiid,)) self.cursor.execute(query, (kodiid,))
for genre in genres: for genre in genres:
query = ' '.join(( query = ' '.join((
@ -1176,15 +1135,15 @@ class Kodidb_Functions():
"WHERE strGenre = ?", "WHERE strGenre = ?",
"COLLATE NOCASE" "COLLATE NOCASE"
)) ))
cursor.execute(query, (genre,)) self.cursor.execute(query, (genre,))
try: try:
genreid = cursor.fetchone()[0] genreid = self.cursor.fetchone()[0]
except TypeError: except TypeError:
# Create the genre # Create the genre
cursor.execute("select coalesce(max(idGenre),0) from genre") self.cursor.execute("select coalesce(max(idGenre),0) from genre")
genreid = cursor.fetchone()[0] + 1 genreid = self.cursor.fetchone()[0] + 1
query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)" query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)"
cursor.execute(query, (genreid, genre)) self.cursor.execute(query, (genreid, genre))
query = "INSERT OR REPLACE INTO song_genre(idGenre, idSong) values(?, ?)" query = "INSERT OR REPLACE INTO song_genre(idGenre, idSong) values(?, ?)"
cursor.execute(query, (genreid, kodiid)) self.cursor.execute(query, (genreid, kodiid))

View file

@ -82,17 +82,17 @@ class KodiMonitor(xbmc.Monitor):
item = data.get('item') item = data.get('item')
try: try:
kodiid = item['id'] kodiid = item['id']
type = item['type'] item_type = item['type']
except (KeyError, TypeError): except (KeyError, TypeError):
self.logMsg("Item is invalid for playstate update.", 1) self.logMsg("Item is invalid for playstate update.", 1)
else: else:
if ((utils.settings('useDirectPaths') == "1" and not type == "song") or if ((utils.settings('useDirectPaths') == "1" and not item_type == "song") or
(type == "song" and utils.settings('enableMusic') == "true")): (item_type == "song" and utils.settings('enableMusic') == "true")):
# Set up properties for player # Set up properties for player
embyconn = utils.kodiSQL('emby') embyconn = utils.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, type) emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
try: try:
itemid = emby_dbitem[0] itemid = emby_dbitem[0]
except TypeError: except TypeError:
@ -114,7 +114,7 @@ class KodiMonitor(xbmc.Monitor):
listItem = xbmcgui.ListItem() listItem = xbmcgui.ListItem()
playback = pbutils.PlaybackUtils(result) playback = pbutils.PlaybackUtils(result)
if type == "song" and utils.settings('streamMusic') == "true": if item_type == "song" and utils.settings('streamMusic') == "true":
utils.window('emby_%s.playmethod' % playurl, utils.window('emby_%s.playmethod' % playurl,
value="DirectStream") value="DirectStream")
else: else:
@ -132,7 +132,7 @@ class KodiMonitor(xbmc.Monitor):
item = data.get('item') item = data.get('item')
try: try:
kodiid = item['id'] kodiid = item['id']
type = item['type'] item_type = item['type']
except (KeyError, TypeError): except (KeyError, TypeError):
self.logMsg("Item is invalid for playstate update.", 1) self.logMsg("Item is invalid for playstate update.", 1)
else: else:
@ -140,7 +140,7 @@ class KodiMonitor(xbmc.Monitor):
embyconn = utils.kodiSQL('emby') embyconn = utils.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, type) emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
try: try:
itemid = emby_dbitem[0] itemid = emby_dbitem[0]
except TypeError: except TypeError:
@ -154,10 +154,10 @@ class KodiMonitor(xbmc.Monitor):
# 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, type="POST") doUtils.downloadUrl(url, action_type="POST")
self.logMsg("Mark as watched for itemid: %s" % itemid, 1) self.logMsg("Mark as watched for itemid: %s" % itemid, 1)
else: else:
doUtils.downloadUrl(url, type="DELETE") doUtils.downloadUrl(url, action_type="DELETE")
self.logMsg("Mark as unwatched for itemid: %s" % itemid, 1) self.logMsg("Mark as unwatched for itemid: %s" % itemid, 1)
finally: finally:
embycursor.close() embycursor.close()
@ -195,7 +195,7 @@ class KodiMonitor(xbmc.Monitor):
url = "{server}/emby/Items/%s?format=json" % itemid url = "{server}/emby/Items/%s?format=json" % itemid
self.logMsg("Deleting request: %s" % itemid) self.logMsg("Deleting request: %s" % itemid)
doUtils.downloadUrl(url, type="DELETE") doUtils.downloadUrl(url, action_type="DELETE")
finally: finally:
embycursor.close()''' embycursor.close()'''

View file

@ -90,6 +90,7 @@ class LibrarySync(threading.Thread):
if plugin['Name'] == "Emby.Kodi Sync Queue": if plugin['Name'] == "Emby.Kodi Sync Queue":
self.logMsg("Found server plugin.", 2) self.logMsg("Found server plugin.", 2)
completed = self.fastSync() completed = self.fastSync()
break
if not completed: if not completed:
# Fast sync failed or server plugin is not found # Fast sync failed or server plugin is not found
@ -102,20 +103,15 @@ class LibrarySync(threading.Thread):
def fastSync(self): def fastSync(self):
log = self.logMsg
doUtils = self.doUtils
lastSync = utils.settings('LastIncrementalSync') lastSync = utils.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)
log("Last sync run: %s" % lastSyncTime, 1) self.logMsg("Last sync run: %s" % lastSyncTime, 1)
# get server RetentionDateTime # get server RetentionDateTime
url = "{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json" result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json")
result = doUtils(url)
retention_time = "2010-01-01T00:00:00Z" retention_time = "2010-01-01T00:00:00Z"
if result and result.get('RetentionDateTime'): if result and result.get('RetentionDateTime'):
retention_time = result['RetentionDateTime'] retention_time = result['RetentionDateTime']
@ -129,16 +125,15 @@ class LibrarySync(threading.Thread):
''' '''
retention_time = utils.convertdate(retention_time) retention_time = utils.convertdate(retention_time)
log("RetentionDateTime: %s" % retention_time, 1) self.logMsg("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:
log("Fast sync server retention insufficient, fall back to full sync", 1) self.logMsg("Fast sync server retention insufficient, fall back to full sync", 1)
return False return False
url = "{server}/emby/Emby.Kodi.SyncQueue/{UserId}/GetItems?format=json"
params = {'LastUpdateDT': lastSync} params = {'LastUpdateDT': lastSync}
result = doUtils(url, parameters=params) result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/{UserId}/GetItems?format=json", parameters=params)
try: try:
processlist = { processlist = {
@ -150,11 +145,11 @@ class LibrarySync(threading.Thread):
} }
except (KeyError, TypeError): except (KeyError, TypeError):
log("Failed to retrieve latest updates using fast sync.", 1) self.logMsg("Failed to retrieve latest updates using fast sync.", 1)
return False return False
else: else:
log("Fast sync changes: %s" % result, 1) self.logMsg("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])
@ -162,26 +157,24 @@ class LibrarySync(threading.Thread):
def saveLastSync(self): def saveLastSync(self):
log = self.logMsg
# Save last sync time # Save last sync time
overlap = 2 overlap = 2
url = "{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json" result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json")
result = self.doUtils(url)
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.
log("An exception occurred: %s" % e, 1) self.logMsg("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')
log("New sync time: client time -%s min: %s" % (overlap, lastSync), 1) self.logMsg("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')
log("New sync time: server time -%s min: %s" % (overlap, lastSync), 1) self.logMsg("New sync time: server time -%s min: %s" % (overlap, lastSync), 1)
finally: finally:
utils.settings('LastIncrementalSync', value=lastSync) utils.settings('LastIncrementalSync', value=lastSync)
@ -197,35 +190,32 @@ class LibrarySync(threading.Thread):
def dbCommit(self, connection): def dbCommit(self, connection):
log = self.logMsg
window = utils.window 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:
log("Kodi scan is running. Waiting...", 1) self.logMsg("Kodi scan is running. Waiting...", 1)
kodidb_scan = window('emby_kodiScan') == "true" kodidb_scan = window('emby_kodiScan') == "true"
if self.shouldStop(): if self.shouldStop():
log("Commit unsuccessful. Sync terminated.", 1) self.logMsg("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
log("Commit unsuccessful.", 1) self.logMsg("Commit unsuccessful.", 1)
break break
else: else:
connection.commit() connection.commit()
log("Commit successful.", 1) self.logMsg("Commit successful.", 1)
def fullSync(self, manualrun=False, repair=False, forceddialog=False): def fullSync(self, manualrun=False, repair=False, forceddialog=False):
log = self.logMsg
window = utils.window window = utils.window
settings = utils.settings 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.
emby = self.emby
music_enabled = utils.settings('enableMusic') == "true" music_enabled = utils.settings('enableMusic') == "true"
xbmc.executebuiltin('InhibitIdleShutdown(true)') xbmc.executebuiltin('InhibitIdleShutdown(true)')
@ -294,7 +284,7 @@ class LibrarySync(threading.Thread):
self.dbCommit(kodiconn) self.dbCommit(kodiconn)
embyconn.commit() embyconn.commit()
elapsedTime = datetime.now() - startTime elapsedTime = datetime.now() - startTime
log("SyncDatabase (finished %s in: %s)" self.logMsg("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
@ -322,7 +312,7 @@ class LibrarySync(threading.Thread):
musicconn.commit() musicconn.commit()
embyconn.commit() embyconn.commit()
elapsedTime = datetime.now() - startTime elapsedTime = datetime.now() - startTime
log("SyncDatabase (finished music in: %s)" self.logMsg("SyncDatabase (finished music in: %s)"
% (str(elapsedTime).split('.')[0]), 1) % (str(elapsedTime).split('.')[0]), 1)
musiccursor.close() musiccursor.close()
@ -369,19 +359,15 @@ class LibrarySync(threading.Thread):
def maintainViews(self, embycursor, kodicursor): def maintainViews(self, embycursor, kodicursor):
log = self.logMsg
# Compare the views to emby # Compare the views to emby
emby = self.emby emby = self.emby
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
kodi_db = kodidb.Kodidb_Functions(kodicursor) kodi_db = kodidb.Kodidb_Functions(kodicursor)
doUtils = self.doUtils
vnodes = self.vnodes
# Get views # Get views
url = "{server}/emby/Users/{UserId}/Views?format=json" result = self.doUtils("{server}/emby/Users/{UserId}/Views?format=json")
result = doUtils(url)
grouped_views = result['Items'] grouped_views = result['Items']
ordered_views = emby.getViews(sortedlist=True) ordered_views = self.emby.getViews(sortedlist=True)
all_views = [] all_views = []
sorted_views = [] sorted_views = []
for view in ordered_views: for view in ordered_views:
@ -392,10 +378,10 @@ 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'])
log("Sorted views: %s" % sorted_views, 1) self.logMsg("Sorted views: %s" % sorted_views, 1)
# total nodes for window properties # total nodes for window properties
vnodes.clearProperties() self.vnodes.clearProperties()
totalnodes = len(sorted_views) + 0 totalnodes = len(sorted_views) + 0
current_views = emby_db.getViews() current_views = emby_db.getViews()
@ -409,13 +395,12 @@ class LibrarySync(threading.Thread):
'music': "Audio", 'music': "Audio",
'photos': "Photo" 'photos': "Photo"
} }
mediatypes = ['movies', 'tvshows', 'musicvideos', 'homevideos', 'music', 'photos'] for mediatype in ['movies', 'tvshows', 'musicvideos', 'homevideos', 'music', 'photos']:
for mediatype in mediatypes:
nodes = [] # Prevent duplicate for nodes of the same type nodes = [] # Prevent duplicate for nodes of the same type
playlists = [] # Prevent duplicate for playlists of the same type playlists = [] # Prevent duplicate for playlists of the same type
# Get media folders from server # Get media folders from server
folders = emby.getViews(mediatype, root=True) folders = self.emby.getViews(mediatype, root=True)
for folder in folders: for folder in folders:
folderid = folder['id'] folderid = folder['id']
@ -424,14 +409,13 @@ class LibrarySync(threading.Thread):
if foldername not in all_views: if foldername not in all_views:
# Media folders are grouped into userview # Media folders are grouped into userview
url = "{server}/emby/Users/{UserId}/Items?format=json"
params = { params = {
'ParentId': folderid, 'ParentId': folderid,
'Recursive': True, 'Recursive': True,
'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 = doUtils(url, parameters=params) result = self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
try: try:
verifyitem = result['Items'][0]['Id'] verifyitem = result['Items'][0]['Id']
except (TypeError, IndexError): except (TypeError, IndexError):
@ -444,16 +428,16 @@ class LibrarySync(threading.Thread):
if (grouped_view['Type'] == "UserView" and if (grouped_view['Type'] == "UserView" and
grouped_view.get('CollectionType') == mediatype): grouped_view.get('CollectionType') == mediatype):
# Take the userview, and validate the item belong to the view # Take the userview, and validate the item belong to the view
if 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
log("Found corresponding view: %s %s" self.logMsg("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)
log("Couldn't find corresponding grouped view: %s" % sorted_views, 1) self.logMsg("Couldn't find corresponding grouped view: %s" % sorted_views, 1)
# Failsafe # Failsafe
try: try:
@ -469,7 +453,7 @@ class LibrarySync(threading.Thread):
current_tagid = view[2] current_tagid = view[2]
except TypeError: except TypeError:
log("Creating viewid: %s in Emby database." % folderid, 1) self.logMsg("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
@ -478,7 +462,7 @@ class LibrarySync(threading.Thread):
playlists.append(foldername) playlists.append(foldername)
# Create the video node # Create the video node
if foldername not in nodes and mediatype not in ("musicvideos", "music"): if foldername not in nodes and mediatype not in ("musicvideos", "music"):
vnodes.viewNode(sorted_views.index(foldername), foldername, mediatype, self.vnodes.viewNode(sorted_views.index(foldername), foldername, mediatype,
viewtype, folderid) viewtype, folderid)
if viewtype == "mixed": # Change the value if viewtype == "mixed": # Change the value
sorted_views[sorted_views.index(foldername)] = "%ss" % foldername sorted_views[sorted_views.index(foldername)] = "%ss" % foldername
@ -488,7 +472,7 @@ class LibrarySync(threading.Thread):
emby_db.addView(folderid, foldername, viewtype, tagid) emby_db.addView(folderid, foldername, viewtype, tagid)
else: else:
log(' '.join(( self.logMsg(' '.join((
"Found viewid: %s" % folderid, "Found viewid: %s" % folderid,
"viewname: %s" % current_viewname, "viewname: %s" % current_viewname,
@ -504,7 +488,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:
log("viewid: %s new viewname: %s" % (folderid, foldername), 1) self.logMsg("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
@ -518,7 +502,7 @@ class LibrarySync(threading.Thread):
mediatype, current_viewname, folderid, current_viewtype, True) mediatype, current_viewname, folderid, current_viewtype, True)
# Delete video node # Delete video node
if mediatype != "musicvideos": if mediatype != "musicvideos":
vnodes.viewNode( self.vnodes.viewNode(
indexnumber=None, indexnumber=None,
tagname=current_viewname, tagname=current_viewname,
mediatype=mediatype, mediatype=mediatype,
@ -532,7 +516,7 @@ class LibrarySync(threading.Thread):
playlists.append(foldername) playlists.append(foldername)
# Add new video node # Add new video node
if foldername not in nodes and mediatype != "musicvideos": if foldername not in nodes and mediatype != "musicvideos":
vnodes.viewNode(sorted_views.index(foldername), foldername, self.vnodes.viewNode(sorted_views.index(foldername), foldername,
mediatype, viewtype, folderid) mediatype, viewtype, folderid)
if viewtype == "mixed": # Change the value if viewtype == "mixed": # Change the value
sorted_views[sorted_views.index(foldername)] = "%ss" % foldername sorted_views[sorted_views.index(foldername)] = "%ss" % foldername
@ -554,7 +538,7 @@ class LibrarySync(threading.Thread):
playlists.append(foldername) playlists.append(foldername)
# Create the video node if not already exists # Create the video node if not already exists
if foldername not in nodes and mediatype != "musicvideos": if foldername not in nodes and mediatype != "musicvideos":
vnodes.viewNode(sorted_views.index(foldername), foldername, self.vnodes.viewNode(sorted_views.index(foldername), foldername,
mediatype, viewtype, folderid) mediatype, viewtype, folderid)
if viewtype == "mixed": # Change the value if viewtype == "mixed": # Change the value
sorted_views[sorted_views.index(foldername)] = "%ss" % foldername sorted_views[sorted_views.index(foldername)] = "%ss" % foldername
@ -562,32 +546,30 @@ class LibrarySync(threading.Thread):
totalnodes += 1 totalnodes += 1
else: else:
# Add video nodes listings # Add video nodes listings
vnodes.singleNode(totalnodes, "Favorite movies", "movies", "favourites") self.vnodes.singleNode(totalnodes, "Favorite movies", "movies", "favourites")
totalnodes += 1 totalnodes += 1
vnodes.singleNode(totalnodes, "Favorite tvshows", "tvshows", "favourites") self.vnodes.singleNode(totalnodes, "Favorite tvshows", "tvshows", "favourites")
totalnodes += 1 totalnodes += 1
vnodes.singleNode(totalnodes, "channels", "movies", "channels") self.vnodes.singleNode(totalnodes, "channels", "movies", "channels")
totalnodes += 1 totalnodes += 1
# Save total # Save total
utils.window('Emby.nodes.total', str(totalnodes)) utils.window('Emby.nodes.total', str(totalnodes))
# Remove any old referenced views # Remove any old referenced views
log("Removing views: %s" % current_views, 1) self.logMsg("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):
log = self.logMsg
lang = utils.language lang = utils.language
# Get movies from emby # Get movies from emby
emby = self.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')
log("Media folders: %s" % views, 1) self.logMsg("Media folders: %s" % views, 1)
##### PROCESS MOVIES ##### ##### PROCESS MOVIES #####
for view in views: for view in views:
@ -596,21 +578,18 @@ class LibrarySync(threading.Thread):
return False return False
# Get items per view # Get items per view
viewId = view['id']
viewName = view['name']
if pdialog: if pdialog:
pdialog.update( pdialog.update(
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (lang(33017), viewName)) message="%s %s..." % (lang(33017), view['name']))
# Initial or repair sync # Initial or repair sync
all_embymovies = emby.getMovies(viewId, dialog=pdialog) all_embymovies = self.emby.getMovies(view['id'], dialog=pdialog)
total = all_embymovies['TotalRecordCount'] total = all_embymovies['TotalRecordCount']
embymovies = all_embymovies['Items'] embymovies = all_embymovies['Items']
if pdialog: if pdialog:
pdialog.update(heading="Processing %s / %s items" % (viewName, total)) pdialog.update(heading="Processing %s / %s items" % (view['name'], total))
count = 0 count = 0
for embymovie in embymovies: for embymovie in embymovies:
@ -623,16 +602,16 @@ class LibrarySync(threading.Thread):
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=title)
count += 1 count += 1
movies.add_update(embymovie, viewName, viewId) movies.add_update(embymovie, view['name'], view['id'])
else: else:
log("Movies finished.", 2) self.logMsg("Movies finished.", 2)
##### PROCESS BOXSETS ##### ##### PROCESS BOXSETS #####
if pdialog: if pdialog:
pdialog.update(heading="Emby for Kodi", message=lang(33018)) pdialog.update(heading="Emby for Kodi", message=lang(33018))
boxsets = emby.getBoxset(dialog=pdialog) boxsets = self.emby.getBoxset(dialog=pdialog)
total = boxsets['TotalRecordCount'] total = boxsets['TotalRecordCount']
embyboxsets = boxsets['Items'] embyboxsets = boxsets['Items']
@ -652,20 +631,18 @@ class LibrarySync(threading.Thread):
count += 1 count += 1
movies.add_updateBoxset(boxset) movies.add_updateBoxset(boxset)
else: else:
log("Boxsets finished.", 2) self.logMsg("Boxsets finished.", 2)
return True return True
def musicvideos(self, embycursor, kodicursor, pdialog): def musicvideos(self, embycursor, kodicursor, pdialog):
log = self.logMsg
# Get musicvideos from emby # Get musicvideos from emby
emby = self.emby
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
mvideos = itemtypes.MusicVideos(embycursor, kodicursor) mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
views = emby_db.getView_byType('musicvideos') views = emby_db.getView_byType('musicvideos')
log("Media folders: %s" % views, 1) self.logMsg("Media folders: %s" % views, 1)
for view in views: for view in views:
@ -682,7 +659,7 @@ class LibrarySync(threading.Thread):
message="%s %s..." % (utils.language(33019), viewName)) message="%s %s..." % (utils.language(33019), viewName))
# Initial or repair sync # Initial or repair sync
all_embymvideos = emby.getMusicVideos(viewId, dialog=pdialog) all_embymvideos = self.emby.getMusicVideos(viewId, dialog=pdialog)
total = all_embymvideos['TotalRecordCount'] total = all_embymvideos['TotalRecordCount']
embymvideos = all_embymvideos['Items'] embymvideos = all_embymvideos['Items']
@ -702,21 +679,19 @@ class LibrarySync(threading.Thread):
count += 1 count += 1
mvideos.add_update(embymvideo, viewName, viewId) mvideos.add_update(embymvideo, viewName, viewId)
else: else:
log("MusicVideos finished.", 2) self.logMsg("MusicVideos finished.", 2)
return True return True
def tvshows(self, embycursor, kodicursor, pdialog): def tvshows(self, embycursor, kodicursor, pdialog):
log = self.logMsg
# Get shows from emby # Get shows from emby
emby = self.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')
log("Media folders: %s" % views, 1) self.logMsg("Media folders: %s" % views, 1)
for view in views: for view in views:
@ -724,20 +699,17 @@ class LibrarySync(threading.Thread):
return False return False
# Get items per view # Get items per view
viewId = view['id']
viewName = view['name']
if pdialog: if pdialog:
pdialog.update( pdialog.update(
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (utils.language(33020), viewName)) message="%s %s..." % (utils.language(33020), view['name']))
all_embytvshows = emby.getShows(viewId, dialog=pdialog) all_embytvshows = self.emby.getShows(view['id'], dialog=pdialog)
total = all_embytvshows['TotalRecordCount'] total = all_embytvshows['TotalRecordCount']
embytvshows = all_embytvshows['Items'] embytvshows = all_embytvshows['Items']
if pdialog: if pdialog:
pdialog.update(heading="Processing %s / %s items" % (viewName, total)) pdialog.update(heading="Processing %s / %s items" % (view['name'], total))
count = 0 count = 0
for embytvshow in embytvshows: for embytvshow in embytvshows:
@ -745,16 +717,15 @@ class LibrarySync(threading.Thread):
if self.shouldStop(): if self.shouldStop():
return False return False
itemid = embytvshow['Id']
title = embytvshow['Name'] title = embytvshow['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=title)
count += 1 count += 1
tvshows.add_update(embytvshow, viewName, viewId) tvshows.add_update(embytvshow, view['name'], view['id'])
# Process episodes # Process episodes
all_episodes = emby.getEpisodesbyShow(itemid) all_episodes = self.emby.getEpisodesbyShow(embytvshow['Id'])
for episode in all_episodes['Items']: for episode in all_episodes['Items']:
# Process individual show # Process individual show
@ -766,24 +737,22 @@ 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:
log("TVShows finished.", 2) self.logMsg("TVShows finished.", 2)
return True return True
def music(self, embycursor, kodicursor, pdialog): def music(self, embycursor, kodicursor, pdialog):
# Get music from emby # Get music from emby
emby = self.emby
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
music = itemtypes.Music(embycursor, kodicursor) music = itemtypes.Music(embycursor, kodicursor)
process = { process = {
'artists': [emby.getArtists, music.add_updateArtist], 'artists': [self.emby.getArtists, music.add_updateArtist],
'albums': [emby.getAlbums, music.add_updateAlbum], 'albums': [self.emby.getAlbums, music.add_updateAlbum],
'songs': [emby.getSongs, music.add_updateSong] 'songs': [self.emby.getSongs, music.add_updateSong]
} }
types = ['artists', 'albums', 'songs'] for itemtype in ['artists', 'albums', 'songs']:
for itemtype in types:
if pdialog: if pdialog:
pdialog.update( pdialog.update(
@ -802,11 +771,9 @@ class LibrarySync(threading.Thread):
# Process individual item # Process individual item
if self.shouldStop(): if self.shouldStop():
return False return False
title = embyitem['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=embyitem['Name'])
count += 1 count += 1
process[itemtype][1](embyitem) process[itemtype][1](embyitem)
@ -837,13 +804,10 @@ class LibrarySync(threading.Thread):
def incrementalSync(self): def incrementalSync(self):
log = self.logMsg
embyconn = utils.kodiSQL('emby') embyconn = utils.kodiSQL('emby')
embycursor = embyconn.cursor() embycursor = embyconn.cursor()
kodiconn = utils.kodiSQL('video') kodiconn = utils.kodiSQL('video')
kodicursor = kodiconn.cursor() kodicursor = kodiconn.cursor()
emby = self.emby
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
pDialog = None pDialog = None
update_embydb = False update_embydb = False
@ -867,28 +831,27 @@ class LibrarySync(threading.Thread):
'userdata': self.userdataItems, 'userdata': self.userdataItems,
'remove': self.removeItems 'remove': self.removeItems
} }
types = ['added', 'update', 'userdata', 'remove'] for process_type in ['added', 'update', 'userdata', 'remove']:
for type in types:
if process[type] and utils.window('emby_kodiScan') != "true": if process[process_type] and utils.window('emby_kodiScan') != "true":
listItems = list(process[type]) listItems = list(process[process_type])
del process[type][:] # Reset class list del process[process_type][:] # Reset class list
items_process = itemtypes.Items(embycursor, kodicursor) items_process = itemtypes.Items(embycursor, kodicursor)
update = False update = False
# Prepare items according to process type # Prepare items according to process process_type
if type == "added": if process_type == "added":
items = emby.sortby_mediatype(listItems) items = self.emby.sortby_mediatype(listItems)
elif type in ("userdata", "remove"): elif process_type in ("userdata", "remove"):
items = emby_db.sortby_mediaType(listItems, unsorted=False) items = emby_db.sortby_mediaType(listItems, unsorted=False)
else: else:
items = emby_db.sortby_mediaType(listItems) items = emby_db.sortby_mediaType(listItems)
if items.get('Unsorted'): if items.get('Unsorted'):
sorted_items = emby.sortby_mediatype(items['Unsorted']) sorted_items = self.emby.sortby_mediatype(items['Unsorted'])
doupdate = items_process.itemsbyId(sorted_items, "added", pDialog) doupdate = items_process.itemsbyId(sorted_items, "added", pDialog)
if doupdate: if doupdate:
embyupdate, kodiupdate_video = doupdate embyupdate, kodiupdate_video = doupdate
@ -898,7 +861,7 @@ class LibrarySync(threading.Thread):
self.forceLibraryUpdate = True self.forceLibraryUpdate = True
del items['Unsorted'] del items['Unsorted']
doupdate = items_process.itemsbyId(items, type, pDialog) doupdate = items_process.itemsbyId(items, process_type, pDialog)
if doupdate: if doupdate:
embyupdate, kodiupdate_video = doupdate embyupdate, kodiupdate_video = doupdate
if embyupdate: if embyupdate:
@ -908,7 +871,7 @@ class LibrarySync(threading.Thread):
if update_embydb: if update_embydb:
update_embydb = False update_embydb = False
log("Updating emby database.", 1) self.logMsg("Updating emby database.", 1)
embyconn.commit() embyconn.commit()
self.saveLastSync() self.saveLastSync()
@ -917,7 +880,7 @@ class LibrarySync(threading.Thread):
self.forceLibraryUpdate = False self.forceLibraryUpdate = False
self.dbCommit(kodiconn) self.dbCommit(kodiconn)
log("Updating video library.", 1) self.logMsg("Updating video library.", 1)
utils.window('emby_kodiScan', value="true") utils.window('emby_kodiScan', value="true")
xbmc.executebuiltin('UpdateLibrary(video)') xbmc.executebuiltin('UpdateLibrary(video)')
@ -959,23 +922,21 @@ class LibrarySync(threading.Thread):
def run_internal(self): def run_internal(self):
log = self.logMsg
lang = utils.language lang = utils.language
window = utils.window window = utils.window
settings = utils.settings settings = utils.settings
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
startupComplete = False startupComplete = False
monitor = self.monitor
log("---===### Starting LibrarySync ###===---", 0) self.logMsg("---===### Starting LibrarySync ###===---", 0)
while not monitor.abortRequested(): while not self.monitor.abortRequested():
# In the event the server goes offline # In the event the server goes offline
while self.suspend_thread: while self.suspend_thread:
# Set in service.py # Set in service.py
if monitor.waitForAbort(5): if self.monitor.waitForAbort(5):
# Abort was requested while waiting. We should exit # Abort was requested while waiting. We should exit
break break
@ -986,12 +947,12 @@ class LibrarySync(threading.Thread):
uptoDate = self.compareDBVersion(currentVersion, minVersion) uptoDate = self.compareDBVersion(currentVersion, minVersion)
if not uptoDate: if not uptoDate:
log("Database version out of date: %s minimum version required: %s" self.logMsg("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:
log("Database version is out of date! USER IGNORED!", 0) self.logMsg("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()
@ -1006,7 +967,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
log( self.logMsg(
"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 "
@ -1018,12 +979,12 @@ class LibrarySync(threading.Thread):
break break
# Run start up sync # Run start up sync
log("Database version: %s" % settings('dbCreatedWithVersion'), 0) self.logMsg("Database version: %s" % settings('dbCreatedWithVersion'), 0)
log("SyncDatabase (started)", 1) self.logMsg("SyncDatabase (started)", 1)
startTime = datetime.now() startTime = datetime.now()
librarySync = self.startSync() librarySync = self.startSync()
elapsedTime = datetime.now() - startTime elapsedTime = datetime.now() - startTime
log("SyncDatabase (finished in: %s) %s" self.logMsg("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.
@ -1038,20 +999,20 @@ 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":
log("SyncDatabase onWake (started)", 0) self.logMsg("SyncDatabase onWake (started)", 0)
librarySync = self.startSync() librarySync = self.startSync()
log("SyncDatabase onWake (finished) %s" % librarySync, 0) self.logMsg("SyncDatabase onWake (finished) %s" % librarySync, 0)
if self.stop_thread: if self.stop_thread:
# Set in service.py # Set in service.py
log("Service terminated thread.", 2) self.logMsg("Service terminated thread.", 2)
break break
if 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
log("###===--- LibrarySync Stopped ---===###", 0) self.logMsg("###===--- LibrarySync Stopped ---===###", 0)
def stopThread(self): def stopThread(self):
self.stop_thread = True self.stop_thread = True
@ -1080,16 +1041,14 @@ class ManualSync(LibrarySync):
def movies(self, embycursor, kodicursor, pdialog): def movies(self, embycursor, kodicursor, pdialog):
log = self.logMsg
lang = utils.language lang = utils.language
# Get movies from emby # Get movies from emby
emby = self.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')
log("Media folders: %s" % views, 1) self.logMsg("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:
@ -1121,7 +1080,7 @@ class ManualSync(LibrarySync):
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (lang(33026), viewName)) message="%s %s..." % (lang(33026), viewName))
all_embymovies = emby.getMovies(viewId, basic=True, dialog=pdialog) all_embymovies = self.emby.getMovies(viewId, basic=True, dialog=pdialog)
for embymovie in all_embymovies['Items']: for embymovie in all_embymovies['Items']:
if self.shouldStop(): if self.shouldStop():
@ -1136,8 +1095,8 @@ 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)
log("Movies to update for %s: %s" % (viewName, updatelist), 1) self.logMsg("Movies to update for %s: %s" % (viewName, updatelist), 1)
embymovies = emby.getFullItems(updatelist) embymovies = self.emby.getFullItems(updatelist)
total = len(updatelist) total = len(updatelist)
del updatelist[:] del updatelist[:]
@ -1150,16 +1109,15 @@ class ManualSync(LibrarySync):
if self.shouldStop(): if self.shouldStop():
return False return False
title = embymovie['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=embymovie['Name'])
count += 1 count += 1
movies.add_update(embymovie, viewName, viewId) movies.add_update(embymovie, viewName, viewId)
##### PROCESS BOXSETS ##### ##### PROCESS BOXSETS #####
boxsets = emby.getBoxset(dialog=pdialog) boxsets = self.emby.getBoxset(dialog=pdialog)
embyboxsets = [] embyboxsets = []
if pdialog: if pdialog:
@ -1171,16 +1129,15 @@ class ManualSync(LibrarySync):
return False return False
# Boxset has no real userdata, so using etag to compare # Boxset has no real userdata, so using etag to compare
checksum = boxset['Etag']
itemid = boxset['Id'] itemid = boxset['Id']
all_embyboxsetsIds.add(itemid) all_embyboxsetsIds.add(itemid)
if all_kodisets.get(itemid) != checksum: if all_kodisets.get(itemid) != boxset['Etag']:
# Only update if boxset is not in Kodi or checksum is different # Only update if boxset is not in Kodi or boxset['Etag'] is different
updatelist.append(itemid) updatelist.append(itemid)
embyboxsets.append(boxset) embyboxsets.append(boxset)
log("Boxsets to update: %s" % updatelist, 1) self.logMsg("Boxsets to update: %s" % updatelist, 1)
total = len(updatelist) total = len(updatelist)
if pdialog: if pdialog:
@ -1192,10 +1149,9 @@ class ManualSync(LibrarySync):
if self.shouldStop(): if self.shouldStop():
return False return False
title = boxset['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=boxset['Name'])
count += 1 count += 1
movies.add_updateBoxset(boxset) movies.add_updateBoxset(boxset)
@ -1205,26 +1161,24 @@ class ManualSync(LibrarySync):
if kodimovie not in all_embymoviesIds: if kodimovie not in all_embymoviesIds:
movies.remove(kodimovie) movies.remove(kodimovie)
else: else:
log("Movies compare finished.", 1) self.logMsg("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:
log("Boxsets compare finished.", 1) self.logMsg("Boxsets compare finished.", 1)
return True return True
def musicvideos(self, embycursor, kodicursor, pdialog): def musicvideos(self, embycursor, kodicursor, pdialog):
log = self.logMsg
# Get musicvideos from emby # Get musicvideos from emby
emby = self.emby
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
mvideos = itemtypes.MusicVideos(embycursor, kodicursor) mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
views = emby_db.getView_byType('musicvideos') views = emby_db.getView_byType('musicvideos')
log("Media folders: %s" % views, 1) self.logMsg("Media folders: %s" % views, 1)
# Pull the list of musicvideos in Kodi # Pull the list of musicvideos in Kodi
try: try:
@ -1249,7 +1203,7 @@ class ManualSync(LibrarySync):
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (utils.language(33028), viewName)) message="%s %s..." % (utils.language(33028), viewName))
all_embymvideos = 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']:
if self.shouldStop(): if self.shouldStop():
@ -1264,8 +1218,8 @@ 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)
log("MusicVideos to update for %s: %s" % (viewName, updatelist), 1) self.logMsg("MusicVideos to update for %s: %s" % (viewName, updatelist), 1)
embymvideos = emby.getFullItems(updatelist) embymvideos = self.emby.getFullItems(updatelist)
total = len(updatelist) total = len(updatelist)
del updatelist[:] del updatelist[:]
@ -1279,10 +1233,9 @@ class ManualSync(LibrarySync):
if self.shouldStop(): if self.shouldStop():
return False return False
title = embymvideo['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=embymvideo['Name'])
count += 1 count += 1
mvideos.add_update(embymvideo, viewName, viewId) mvideos.add_update(embymvideo, viewName, viewId)
@ -1292,22 +1245,20 @@ class ManualSync(LibrarySync):
if kodimvideo not in all_embymvideosIds: if kodimvideo not in all_embymvideosIds:
mvideos.remove(kodimvideo) mvideos.remove(kodimvideo)
else: else:
log("MusicVideos compare finished.", 1) self.logMsg("MusicVideos compare finished.", 1)
return True return True
def tvshows(self, embycursor, kodicursor, pdialog): def tvshows(self, embycursor, kodicursor, pdialog):
log = self.logMsg
lang = utils.language lang = utils.language
# Get shows from emby # Get shows from emby
emby = self.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')
log("Media folders: %s" % views, 1) self.logMsg("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:
@ -1339,7 +1290,7 @@ class ManualSync(LibrarySync):
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (lang(33029), viewName)) message="%s %s..." % (lang(33029), viewName))
all_embytvshows = emby.getShows(viewId, basic=True, dialog=pdialog) all_embytvshows = self.emby.getShows(viewId, basic=True, dialog=pdialog)
for embytvshow in all_embytvshows['Items']: for embytvshow in all_embytvshows['Items']:
if self.shouldStop(): if self.shouldStop():
@ -1354,8 +1305,8 @@ 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)
log("TVShows to update for %s: %s" % (viewName, updatelist), 1) self.logMsg("TVShows to update for %s: %s" % (viewName, updatelist), 1)
embytvshows = emby.getFullItems(updatelist) embytvshows = self.emby.getFullItems(updatelist)
total = len(updatelist) total = len(updatelist)
del updatelist[:] del updatelist[:]
@ -1384,7 +1335,7 @@ class ManualSync(LibrarySync):
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (lang(33030), viewName)) message="%s %s..." % (lang(33030), viewName))
all_embyepisodes = emby.getEpisodes(viewId, basic=True, dialog=pdialog) all_embyepisodes = self.emby.getEpisodes(viewId, basic=True, dialog=pdialog)
for embyepisode in all_embyepisodes['Items']: for embyepisode in all_embyepisodes['Items']:
if self.shouldStop(): if self.shouldStop():
@ -1398,8 +1349,8 @@ 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)
log("Episodes to update for %s: %s" % (viewName, updatelist), 1) self.logMsg("Episodes to update for %s: %s" % (viewName, updatelist), 1)
embyepisodes = emby.getFullItems(updatelist) embyepisodes = self.emby.getFullItems(updatelist)
total = len(updatelist) total = len(updatelist)
del updatelist[:] del updatelist[:]
@ -1410,11 +1361,9 @@ class ManualSync(LibrarySync):
if self.shouldStop(): if self.shouldStop():
return False return False
title = episode['SeriesName']
episodetitle = episode['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message="%s - %s" % (title, episodetitle)) pdialog.update(percentage, message="%s - %s" % (episode['SeriesName'], episode['Name']))
count += 1 count += 1
tvshows.add_updateEpisode(episode) tvshows.add_updateEpisode(episode)
@ -1424,21 +1373,19 @@ class ManualSync(LibrarySync):
if koditvshow not in all_embytvshowsIds: if koditvshow not in all_embytvshowsIds:
tvshows.remove(koditvshow) tvshows.remove(koditvshow)
else: else:
log("TVShows compare finished.", 1) self.logMsg("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:
log("Episodes compare finished.", 1) self.logMsg("Episodes compare finished.", 1)
return True return True
def music(self, embycursor, kodicursor, pdialog): def music(self, embycursor, kodicursor, pdialog):
log = self.logMsg
# Get music from emby # Get music from emby
emby = self.emby
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
music = itemtypes.Music(embycursor, kodicursor) music = itemtypes.Music(embycursor, kodicursor)
@ -1465,35 +1412,30 @@ class ManualSync(LibrarySync):
process = { process = {
'artists': [emby.getArtists, music.add_updateArtist], 'artists': [self.emby.getArtists, music.add_updateArtist],
'albums': [emby.getAlbums, music.add_updateAlbum], 'albums': [self.emby.getAlbums, music.add_updateAlbum],
'songs': [emby.getSongs, music.add_updateSong] 'songs': [self.emby.getSongs, music.add_updateSong]
} }
types = ['artists', 'albums', 'songs'] for data_type in ['artists', 'albums', 'songs']:
for type in types:
if pdialog: if pdialog:
pdialog.update( pdialog.update(
heading="Emby for Kodi", heading="Emby for Kodi",
message="%s %s..." % (utils.language(33031), type)) message="%s %s..." % (utils.language(33031), data_type))
if data_type != "artists":
if type != "artists": all_embyitems = process[data_type][0](basic=True, dialog=pdialog)
all_embyitems = process[type][0](basic=True, dialog=pdialog)
else: else:
all_embyitems = process[type][0](dialog=pdialog) all_embyitems = process[data_type][0](dialog=pdialog)
for embyitem in all_embyitems['Items']: for embyitem in all_embyitems['Items']:
if self.shouldStop(): if self.shouldStop():
return False return False
API = api.API(embyitem) API = api.API(embyitem)
itemid = embyitem['Id'] itemid = embyitem['Id']
if type == "artists": if data_type == "artists":
all_embyartistsIds.add(itemid) all_embyartistsIds.add(itemid)
if all_kodiartists.get(itemid) != API.getChecksum(): if all_kodiartists.get(itemid) != API.getChecksum():
# Only update if artist is not in Kodi or checksum is different # Only update if artist is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
elif type == "albums": elif data_type == "albums":
all_embyalbumsIds.add(itemid) all_embyalbumsIds.add(itemid)
if all_kodialbums.get(itemid) != API.getChecksum(): if all_kodialbums.get(itemid) != API.getChecksum():
# Only update if album is not in Kodi or checksum is different # Only update if album is not in Kodi or checksum is different
@ -1503,47 +1445,36 @@ 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" % (type, updatelist), 1) embyitems = self.emby.getFullItems(updatelist)
embyitems = emby.getFullItems(updatelist)
total = len(updatelist) total = len(updatelist)
del updatelist[:] del updatelist[:]
if pdialog: if pdialog:
pdialog.update(heading="Processing %s / %s items" % (type, total)) pdialog.update(heading="Processing %s / %s items" % (data_type, total))
count = 0 count = 0
for embyitem in embyitems: for embyitem in embyitems:
# Process individual item # Process individual item
if self.shouldStop(): if self.shouldStop():
return False return False
title = embyitem['Name']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=embyitem['Name'])
count += 1 count += 1
process[data_type][1](embyitem)
process[type][1](embyitem)
##### PROCESS DELETES ##### ##### PROCESS DELETES #####
for kodiartist in all_kodiartists: for kodiartist in all_kodiartists:
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:
log("Artist compare finished.", 1) self.logMsg("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:
log("Albums compare finished.", 1) self.logMsg("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:
log("Songs compare finished.", 1) self.logMsg("Songs compare finished.", 1)
return True return True

View file

@ -195,6 +195,7 @@ def getSongTags(file):
if pic.type == 3 and pic.data: if pic.type == 3 and pic.data:
#the file has an embedded cover #the file has an embedded cover
hasEmbeddedCover = True hasEmbeddedCover = True
break
if audio.get("rating"): if audio.get("rating"):
rating = float(audio.get("rating")[0]) rating = float(audio.get("rating")[0])
#flac rating is 0-100 and needs to be converted to 0-5 range #flac rating is 0-100 and needs to be converted to 0-5 range

View file

@ -48,17 +48,13 @@ class PlaybackUtils():
def play(self, itemid, dbid=None): def play(self, itemid, dbid=None):
log = self.logMsg
window = utils.window window = utils.window
settings = utils.settings settings = utils.settings
doUtils = self.doUtils
item = self.item
API = self.API
listitem = xbmcgui.ListItem() listitem = xbmcgui.ListItem()
playutils = putils.PlayUtils(item) playutils = putils.PlayUtils(self.item)
log("Play called.", 1) self.logMsg("Play called.", 1)
playurl = playutils.getPlayUrl() playurl = playutils.getPlayUrl()
if not playurl: if not playurl:
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem) return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
@ -81,32 +77,32 @@ class PlaybackUtils():
introsPlaylist = False introsPlaylist = False
dummyPlaylist = False dummyPlaylist = False
log("Playlist start position: %s" % startPos, 2) self.logMsg("Playlist start position: %s" % startPos, 2)
log("Playlist plugin position: %s" % currentPosition, 2) self.logMsg("Playlist plugin position: %s" % currentPosition, 2)
log("Playlist size: %s" % sizePlaylist, 2) self.logMsg("Playlist size: %s" % sizePlaylist, 2)
############### RESUME POINT ################ ############### RESUME POINT ################
userdata = API.getUserData() userdata = self.API.getUserData()
seektime = API.adjustResume(userdata['Resume']) seektime = self.API.adjustResume(userdata['Resume'])
# We need to ensure we add the intro and additional parts only once. # We need to ensure we add the intro and additional parts only once.
# Otherwise we get a loop. # Otherwise we get a loop.
if not propertiesPlayback: if not propertiesPlayback:
window('emby_playbackProps', value="true") window('emby_playbackProps', value="true")
log("Setting up properties in playlist.", 1) self.logMsg("Setting up properties in playlist.", 1)
if (not homeScreen and not seektime and if (not homeScreen and not seektime and
window('emby_customPlaylist') != "true"): window('emby_customPlaylist') != "true"):
log("Adding dummy file to playlist.", 2) self.logMsg("Adding dummy file to playlist.", 2)
dummyPlaylist = True dummyPlaylist = True
playlist.add(playurl, listitem, index=startPos) playlist.add(playurl, listitem, index=startPos)
# Remove the original item from playlist # Remove the original item from playlist
self.pl.removefromPlaylist(startPos+1) self.pl.removefromPlaylist(startPos+1)
# Readd the original item to playlist - via jsonrpc so we have full metadata # Readd the original item to playlist - via jsonrpc so we have full metadata
self.pl.insertintoPlaylist(currentPosition+1, dbid, item['Type'].lower()) self.pl.insertintoPlaylist(currentPosition+1, dbid, self.item['Type'].lower())
currentPosition += 1 currentPosition += 1
############### -- CHECK FOR INTROS ################ ############### -- CHECK FOR INTROS ################
@ -114,7 +110,7 @@ class PlaybackUtils():
if settings('enableCinema') == "true" and not seektime: if settings('enableCinema') == "true" and not seektime:
# if we have any play them when the movie/show is not being resumed # if we have any play them when the movie/show is not being resumed
url = "{server}/emby/Users/{UserId}/Items/%s/Intros?format=json" % itemid url = "{server}/emby/Users/{UserId}/Items/%s/Intros?format=json" % itemid
intros = doUtils(url) intros = self.doUtils(url)
if intros['TotalRecordCount'] != 0: if intros['TotalRecordCount'] != 0:
getTrailers = True getTrailers = True
@ -124,14 +120,14 @@ class PlaybackUtils():
if not resp: if not resp:
# User selected to not play trailers # User selected to not play trailers
getTrailers = False getTrailers = False
log("Skip trailers.", 1) self.logMsg("Skip trailers.", 1)
if getTrailers: if getTrailers:
for intro in intros['Items']: for intro in intros['Items']:
# The server randomly returns intros, process them. # The server randomly returns intros, process them.
introListItem = xbmcgui.ListItem() introListItem = xbmcgui.ListItem()
introPlayurl = putils.PlayUtils(intro).getPlayUrl() introPlayurl = putils.PlayUtils(intro).getPlayUrl()
log("Adding Intro: %s" % introPlayurl, 1) self.logMsg("Adding Intro: %s" % introPlayurl, 1)
# Set listitem and properties for intros # Set listitem and properties for intros
pbutils = PlaybackUtils(intro) pbutils = PlaybackUtils(intro)
@ -147,24 +143,24 @@ class PlaybackUtils():
if homeScreen and not seektime and not sizePlaylist: if homeScreen and not seektime and not sizePlaylist:
# Extend our current playlist with the actual item to play # Extend our current playlist with the actual item to play
# only if there's no playlist first # only if there's no playlist first
log("Adding main item to playlist.", 1) self.logMsg("Adding main item to playlist.", 1)
self.pl.addtoPlaylist(dbid, item['Type'].lower()) self.pl.addtoPlaylist(dbid, self.item['Type'].lower())
# Ensure that additional parts are played after the main item # Ensure that additional parts are played after the main item
currentPosition += 1 currentPosition += 1
############### -- CHECK FOR ADDITIONAL PARTS ################ ############### -- CHECK FOR ADDITIONAL PARTS ################
if item.get('PartCount'): if self.item.get('PartCount'):
# Only add to the playlist after intros have played # Only add to the playlist after intros have played
partcount = item['PartCount'] partcount = self.item['PartCount']
url = "{server}/emby/Videos/%s/AdditionalParts?format=json" % itemid url = "{server}/emby/Videos/%s/AdditionalParts?format=json" % itemid
parts = doUtils(url) parts = self.doUtils(url)
for part in parts['Items']: for part in parts['Items']:
additionalListItem = xbmcgui.ListItem() additionalListItem = xbmcgui.ListItem()
additionalPlayurl = putils.PlayUtils(part).getPlayUrl() additionalPlayurl = putils.PlayUtils(part).getPlayUrl()
log("Adding additional part: %s" % partcount, 1) self.logMsg("Adding additional part: %s" % partcount, 1)
# Set listitem and properties for each additional parts # Set listitem and properties for each additional parts
pbutils = PlaybackUtils(part) pbutils = PlaybackUtils(part)
@ -178,13 +174,13 @@ class PlaybackUtils():
if dummyPlaylist: if dummyPlaylist:
# Added a dummy file to the playlist, # Added a dummy file to the playlist,
# because the first item is going to fail automatically. # because the first item is going to fail automatically.
log("Processed as a playlist. First item is skipped.", 1) self.logMsg("Processed as a playlist. First item is skipped.", 1)
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem) return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
# We just skipped adding properties. Reset flag for next time. # We just skipped adding properties. Reset flag for next time.
elif propertiesPlayback: elif propertiesPlayback:
log("Resetting properties playback flag.", 2) self.logMsg("Resetting properties playback flag.", 2)
window('emby_playbackProps', clear=True) window('emby_playbackProps', clear=True)
#self.pl.verifyPlaylist() #self.pl.verifyPlaylist()
@ -201,35 +197,34 @@ class PlaybackUtils():
############### PLAYBACK ################ ############### PLAYBACK ################
if homeScreen and seektime and window('emby_customPlaylist') != "true": if homeScreen and seektime and window('emby_customPlaylist') != "true":
log("Play as a widget item.", 1) self.logMsg("Play as a widget item.", 1)
self.setListItem(listitem) self.setListItem(listitem)
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
elif ((introsPlaylist and window('emby_customPlaylist') == "true") or elif ((introsPlaylist and window('emby_customPlaylist') == "true") or
(homeScreen and not sizePlaylist)): (homeScreen and not sizePlaylist)):
# Playlist was created just now, play it. # Playlist was created just now, play it.
log("Play playlist.", 1) self.logMsg("Play playlist.", 1)
xbmc.Player().play(playlist, startpos=startPos) xbmc.Player().play(playlist, startpos=startPos)
else: else:
log("Play as a regular item.", 1) self.logMsg("Play as a regular item.", 1)
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
def setProperties(self, playurl, listitem): def setProperties(self, playurl, listitem):
window = utils.window window = utils.window
# Set all properties necessary for plugin path playback # Set all properties necessary for plugin path playback
item = self.item itemid = self.item['Id']
itemid = item['Id'] itemtype = self.item['Type']
itemtype = item['Type']
embyitem = "emby_%s" % playurl embyitem = "emby_%s" % playurl
window('%s.runtime' % embyitem, value=str(item.get('RunTimeTicks'))) window('%s.runtime' % embyitem, value=str(self.item.get('RunTimeTicks')))
window('%s.type' % embyitem, value=itemtype) window('%s.type' % embyitem, value=itemtype)
window('%s.itemid' % embyitem, value=itemid) window('%s.itemid' % embyitem, value=itemid)
if itemtype == "Episode": if itemtype == "Episode":
window('%s.refreshid' % embyitem, value=item.get('SeriesId')) window('%s.refreshid' % embyitem, value=self.item.get('SeriesId'))
else: else:
window('%s.refreshid' % embyitem, value=itemid) window('%s.refreshid' % embyitem, value=itemid)
@ -248,10 +243,9 @@ class PlaybackUtils():
externalsubs = [] externalsubs = []
mapping = {} mapping = {}
item = self.item itemid = self.item['Id']
itemid = item['Id']
try: try:
mediastreams = item['MediaSources'][0]['MediaStreams'] mediastreams = self.item['MediaSources'][0]['MediaStreams']
except (TypeError, KeyError, IndexError): except (TypeError, KeyError, IndexError):
return return
@ -280,10 +274,7 @@ class PlaybackUtils():
def setArtwork(self, listItem): def setArtwork(self, listItem):
# Set up item and item info # Set up item and item info
item = self.item allartwork = self.artwork.getAllArtwork(self.item, parentInfo=True)
artwork = self.artwork
allartwork = artwork.getAllArtwork(item, parentInfo=True)
# Set artwork for listitem # Set artwork for listitem
arttypes = { arttypes = {
@ -320,33 +311,30 @@ class PlaybackUtils():
def setListItem(self, listItem): def setListItem(self, listItem):
item = self.item people = self.API.getPeople()
itemtype = item['Type'] studios = self.API.getStudios()
API = self.API
people = API.getPeople()
studios = API.getStudios()
metadata = { metadata = {
'title': item.get('Name', "Missing name"), 'title': self.item.get('Name', "Missing name"),
'year': item.get('ProductionYear'), 'year': self.item.get('ProductionYear'),
'plot': API.getOverview(), 'plot': self.API.getOverview(),
'director': people.get('Director'), 'director': people.get('Director'),
'writer': people.get('Writer'), 'writer': people.get('Writer'),
'mpaa': API.getMpaa(), 'mpaa': self.API.getMpaa(),
'genre': " / ".join(item['Genres']), 'genre': " / ".join(self.item['Genres']),
'studio': " / ".join(studios), 'studio': " / ".join(studios),
'aired': API.getPremiereDate(), 'aired': self.API.getPremiereDate(),
'rating': item.get('CommunityRating'), 'rating': self.item.get('CommunityRating'),
'votes': item.get('VoteCount') 'votes': self.item.get('VoteCount')
} }
if "Episode" in itemtype: if "Episode" in self.item['Type']:
# Only for tv shows # Only for tv shows
thumbId = item.get('SeriesId') thumbId = self.item.get('SeriesId')
season = item.get('ParentIndexNumber', -1) season = self.item.get('ParentIndexNumber', -1)
episode = item.get('IndexNumber', -1) episode = self.item.get('IndexNumber', -1)
show = item.get('SeriesName', "") show = self.item.get('SeriesName', "")
metadata['TVShowTitle'] = show metadata['TVShowTitle'] = show
metadata['season'] = season metadata['season'] = season

View file

@ -49,15 +49,13 @@ class Player(xbmc.Player):
def onPlayBackStarted(self): def onPlayBackStarted(self):
log = self.logMsg
window = utils.window window = utils.window
# Will be called when xbmc starts playing a file # Will be called when xbmc starts playing a file
xbmcplayer = self.xbmcplayer
self.stopAll() self.stopAll()
# Get current file # Get current file
try: try:
currentFile = xbmcplayer.getPlayingFile() currentFile = self.xbmcplayer.getPlayingFile()
xbmc.sleep(300) xbmc.sleep(300)
except: except:
currentFile = "" currentFile = ""
@ -65,11 +63,11 @@ class Player(xbmc.Player):
while not currentFile: while not currentFile:
xbmc.sleep(100) xbmc.sleep(100)
try: try:
currentFile = xbmcplayer.getPlayingFile() currentFile = self.xbmcplayer.getPlayingFile()
except: pass except: pass
if count == 5: # try 5 times if count == 5: # try 5 times
log("Cancelling playback report...", 1) self.logMsg("Cancelling playback report...", 1)
break break
else: count += 1 else: count += 1
@ -86,12 +84,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
log("Could not find itemId, cancelling playback report...", 1) self.logMsg("Could not find itemId, cancelling playback report...", 1)
break break
else: tryCount += 1 else: tryCount += 1
else: else:
log("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId), 0) self.logMsg("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
@ -104,11 +102,11 @@ 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)
log("Seeking to: %s" % customseek, 1) self.logMsg("Seeking to: %s" % customseek, 1)
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)
seekTime = xbmcplayer.getTime() seekTime = self.xbmcplayer.getTime()
# Get playback volume # Get playback volume
volume_query = { volume_query = {
@ -191,7 +189,7 @@ class Player(xbmc.Player):
if mapping: # Set in playbackutils.py if mapping: # Set in playbackutils.py
log("Mapping for external subtitles index: %s" % mapping, 2) self.logMsg("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)):
@ -209,15 +207,15 @@ class Player(xbmc.Player):
# Post playback to server # Post playback to server
log("Sending POST play started: %s." % postdata, 2) self.logMsg("Sending POST play started: %s." % postdata, 2)
self.doUtils(url, postBody=postdata, type="POST") self.doUtils(url, postBody=postdata, action_type="POST")
# Ensure we do have a runtime # Ensure we do have a runtime
try: try:
runtime = int(runtime) runtime = int(runtime)
except ValueError: except ValueError:
runtime = xbmcplayer.getTotalTime() runtime = self.xbmcplayer.getTotalTime()
log("Runtime is missing, Kodi runtime: %s" % runtime, 1) self.logMsg("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 = {
@ -234,7 +232,7 @@ class Player(xbmc.Player):
} }
self.played_info[currentFile] = data self.played_info[currentFile] = data
log("ADDING_FILE: %s" % self.played_info, 1) self.logMsg("ADDING_FILE: %s" % self.played_info, 1)
# log some playback stats # log some playback stats
'''if(itemType != None): '''if(itemType != None):
@ -253,10 +251,7 @@ class Player(xbmc.Player):
def reportPlayback(self): def reportPlayback(self):
log = self.logMsg self.logMsg("reportPlayback Called", 2)
log("reportPlayback Called", 2)
xbmcplayer = self.xbmcplayer
# Get current file # Get current file
currentFile = self.currentFile currentFile = self.currentFile
@ -354,7 +349,7 @@ class Player(xbmc.Player):
if mapping: # Set in PlaybackUtils.py if mapping: # Set in PlaybackUtils.py
log("Mapping for external subtitles index: %s" % mapping, 2) self.logMsg("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)):
@ -374,7 +369,7 @@ class Player(xbmc.Player):
# Report progress via websocketclient # Report progress via websocketclient
postdata = json.dumps(postdata) postdata = json.dumps(postdata)
log("Report: %s" % postdata, 2) self.logMsg("Report: %s" % postdata, 2)
self.ws.sendProgressUpdate(postdata) self.ws.sendProgressUpdate(postdata)
def onPlayBackPaused(self): def onPlayBackPaused(self):
@ -410,14 +405,13 @@ class Player(xbmc.Player):
def onPlayBackStopped(self): def onPlayBackStopped(self):
log = self.logMsg
window = utils.window window = utils.window
# Will be called when user stops xbmc playing a file # Will be called when user stops xbmc playing a file
log("ONPLAYBACK_STOPPED", 2) self.logMsg("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)
log("Clear playlist properties.", 1) self.logMsg("Clear playlist properties.", 1)
self.stopAll() self.stopAll()
def onPlayBackEnded(self): def onPlayBackEnded(self):
@ -428,31 +422,28 @@ class Player(xbmc.Player):
def stopAll(self): def stopAll(self):
log = self.logMsg
lang = utils.language lang = utils.language
settings = utils.settings settings = utils.settings
doUtils = self.doUtils
if not self.played_info: if not self.played_info:
return return
log("Played_information: %s" % self.played_info, 1) self.logMsg("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:
log("Item path: %s" % item, 2) self.logMsg("Item path: %s" % item, 2)
log("Item data: %s" % data, 2) self.logMsg("Item data: %s" % data, 2)
runtime = data['runtime'] runtime = data['runtime']
currentPosition = data['currentPosition'] currentPosition = data['currentPosition']
itemid = data['item_id'] itemid = data['item_id']
refresh_id = data['refresh_id'] refresh_id = data['refresh_id']
currentFile = data['currentfile'] currentFile = data['currentfile']
type = data['Type'] media_type = data['Type']
playMethod = data['playmethod'] playMethod = data['playmethod']
# Prevent manually mark as watched in Kodi monitor # Prevent manually mark as watched in Kodi monitor
@ -466,15 +457,15 @@ class Player(xbmc.Player):
percentComplete = 0 percentComplete = 0
markPlayedAt = float(settings('markPlayed')) / 100 markPlayedAt = float(settings('markPlayed')) / 100
log("Percent complete: %s Mark played at: %s" self.logMsg("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.
offerDelete = False offerDelete = False
if type == "Episode" and settings('deleteTV') == "true": if media_type == "Episode" and settings('deleteTV') == "true":
offerDelete = True offerDelete = True
elif type == "Movie" and settings('deleteMovies') == "true": elif media_type == "Movie" and settings('deleteMovies') == "true":
offerDelete = True offerDelete = True
if settings('offerDelete') != "true": if settings('offerDelete') != "true":
@ -484,21 +475,21 @@ 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:
log("User skipped deletion.", 1) self.logMsg("User skipped deletion.", 1)
continue continue
url = "{server}/emby/Items/%s?format=json" % itemid url = "{server}/emby/Items/%s?format=json" % itemid
log("Deleting request: %s" % itemid, 1) self.logMsg("Deleting request: %s" % itemid, 1)
doUtils(url, type="DELETE") self.doUtils(url, action_type="DELETE")
self.stopPlayback(data) self.stopPlayback(data)
# Stop transcoding # Stop transcoding
if playMethod == "Transcode": if playMethod == "Transcode":
log("Transcoding for %s terminated." % itemid, 1) self.logMsg("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
doUtils(url, type="DELETE") self.doUtils(url, action_type="DELETE")
self.played_info.clear() self.played_info.clear()
@ -517,4 +508,4 @@ class Player(xbmc.Player):
'MediaSourceId': itemId, 'MediaSourceId': itemId,
'PositionTicks': positionTicks 'PositionTicks': positionTicks
} }
self.doUtils(url, postBody=postdata, type="POST") self.doUtils(url, postBody=postdata, action_type="POST")

View file

@ -39,7 +39,6 @@ class Playlist():
def playAll(self, itemids, startat): def playAll(self, itemids, startat):
log = self.logMsg
window = utils.window window = utils.window
embyconn = utils.kodiSQL('emby') embyconn = utils.kodiSQL('emby')
@ -50,8 +49,8 @@ class Playlist():
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
playlist.clear() playlist.clear()
log("---*** PLAY ALL ***---", 1) self.logMsg("---*** PLAY ALL ***---", 1)
log("Items: %s and start at: %s" % (itemids, startat), 1) self.logMsg("Items: %s and start at: %s" % (itemids, startat), 1)
started = False started = False
window('emby_customplaylist', value="true") window('emby_customplaylist', value="true")
@ -67,14 +66,14 @@ class Playlist():
mediatype = embydb_item[4] mediatype = embydb_item[4]
except TypeError: except TypeError:
# Item is not found in our database, add item manually # Item is not found in our database, add item manually
log("Item was not found in the database, manually adding item.", 1) self.logMsg("Item was not found in the database, manually adding item.", 1)
item = self.emby.getItem(itemid) item = self.emby.getItem(itemid)
self.addtoPlaylist_xbmc(playlist, item) self.addtoPlaylist_xbmc(playlist, item)
else: else:
# Add to playlist # Add to playlist
self.addtoPlaylist(dbid, mediatype) self.addtoPlaylist(dbid, mediatype)
log("Adding %s to playlist." % itemid, 1) self.logMsg("Adding %s to playlist." % itemid, 1)
if not started: if not started:
started = True started = True
@ -85,14 +84,12 @@ class Playlist():
def modifyPlaylist(self, itemids): def modifyPlaylist(self, itemids):
log = self.logMsg
embyconn = utils.kodiSQL('emby') embyconn = utils.kodiSQL('emby')
embycursor = embyconn.cursor() embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
log("---*** ADD TO PLAYLIST ***---", 1) self.logMsg("---*** ADD TO PLAYLIST ***---", 1)
log("Items: %s" % itemids, 1) self.logMsg("Items: %s" % itemids, 1)
player = xbmc.Player() player = xbmc.Player()
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
@ -110,7 +107,7 @@ class Playlist():
# Add to playlist # Add to playlist
self.addtoPlaylist(dbid, mediatype) self.addtoPlaylist(dbid, mediatype)
log("Adding %s to playlist." % itemid, 1) self.logMsg("Adding %s to playlist." % itemid, 1)
self.verifyPlaylist() self.verifyPlaylist()
embycursor.close() embycursor.close()
@ -133,12 +130,10 @@ class Playlist():
else: else:
pl['params']['item'] = {'file': url} pl['params']['item'] = {'file': url}
result = xbmc.executeJSONRPC(json.dumps(pl)) self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
self.logMsg(result, 2)
def addtoPlaylist_xbmc(self, playlist, item): def addtoPlaylist_xbmc(self, playlist, item):
itemid = item['Id']
playurl = playutils.PlayUtils(item).getPlayUrl() playurl = playutils.PlayUtils(item).getPlayUrl()
if not playurl: if not playurl:
# Playurl failed # Playurl failed
@ -169,8 +164,7 @@ class Playlist():
else: else:
pl['params']['item'] = {'file': url} pl['params']['item'] = {'file': url}
result = xbmc.executeJSONRPC(json.dumps(pl)) self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
self.logMsg(result, 2)
def verifyPlaylist(self): def verifyPlaylist(self):
@ -184,8 +178,7 @@ class Playlist():
'playlistid': 1 'playlistid': 1
} }
} }
result = xbmc.executeJSONRPC(json.dumps(pl)) self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
self.logMsg(result, 2)
def removefromPlaylist(self, position): def removefromPlaylist(self, position):
@ -200,5 +193,4 @@ class Playlist():
'position': position 'position': position
} }
} }
result = xbmc.executeJSONRPC(json.dumps(pl)) self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
self.logMsg(result, 2)

View file

@ -33,28 +33,26 @@ class PlayUtils():
def getPlayUrl(self): def getPlayUrl(self):
log = self.logMsg
window = utils.window window = utils.window
item = self.item
playurl = None playurl = None
if (item.get('Type') in ("Recording", "TvChannel") and if (self.item.get('Type') in ("Recording", "TvChannel") and
item.get('MediaSources') and item['MediaSources'][0]['Protocol'] == "Http"): self.item.get('MediaSources') and self.item['MediaSources'][0]['Protocol'] == "Http"):
# Play LiveTV or recordings # Play LiveTV or recordings
log("File protocol is http (livetv).", 1) self.logMsg("File protocol is http (livetv).", 1)
playurl = "%s/emby/Videos/%s/live.m3u8?static=true" % (self.server, item['Id']) playurl = "%s/emby/Videos/%s/live.m3u8?static=true" % (self.server, self.item['Id'])
window('emby_%s.playmethod' % playurl, value="Transcode") window('emby_%s.playmethod' % playurl, value="Transcode")
elif item.get('MediaSources') and item['MediaSources'][0]['Protocol'] == "Http": elif self.item.get('MediaSources') and self.item['MediaSources'][0]['Protocol'] == "Http":
# Only play as http, used for channels, or online hosting of content # Only play as http, used for channels, or online hosting of content
log("File protocol is http.", 1) self.logMsg("File protocol is http.", 1)
playurl = self.httpPlay() playurl = self.httpPlay()
window('emby_%s.playmethod' % playurl, value="DirectStream") window('emby_%s.playmethod' % playurl, value="DirectStream")
elif self.isDirectPlay(): elif self.isDirectPlay():
log("File is direct playing.", 1) self.logMsg("File is direct playing.", 1)
playurl = self.directPlay() playurl = self.directPlay()
playurl = playurl.encode('utf-8') playurl = playurl.encode('utf-8')
# Set playmethod property # Set playmethod property
@ -62,14 +60,14 @@ class PlayUtils():
elif self.isDirectStream(): elif self.isDirectStream():
log("File is direct streaming.", 1) self.logMsg("File is direct streaming.", 1)
playurl = self.directStream() playurl = self.directStream()
# Set playmethod property # Set playmethod property
window('emby_%s.playmethod' % playurl, value="DirectStream") window('emby_%s.playmethod' % playurl, value="DirectStream")
elif self.isTranscoding(): elif self.isTranscoding():
log("File is transcoding.", 1) self.logMsg("File is transcoding.", 1)
playurl = self.transcoding() playurl = self.transcoding()
# Set playmethod property # Set playmethod property
window('emby_%s.playmethod' % playurl, value="Transcode") window('emby_%s.playmethod' % playurl, value="Transcode")
@ -78,35 +76,31 @@ class PlayUtils():
def httpPlay(self): def httpPlay(self):
# Audio, Video, Photo # Audio, Video, Photo
item = self.item
server = self.server
itemid = item['Id'] itemid = self.item['Id']
mediatype = item['MediaType'] mediatype = self.item['MediaType']
if mediatype == "Audio": if mediatype == "Audio":
playurl = "%s/emby/Audio/%s/stream" % (server, itemid) playurl = "%s/emby/Audio/%s/stream" % (self.server, itemid)
else: else:
playurl = "%s/emby/Videos/%s/stream?static=true" % (server, itemid) playurl = "%s/emby/Videos/%s/stream?static=true" % (self.server, itemid)
return playurl return playurl
def isDirectPlay(self): def isDirectPlay(self):
log = self.logMsg
lang = utils.language lang = utils.language
settings = utils.settings settings = utils.settings
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
item = self.item
# Requirement: Filesystem, Accessible path # Requirement: Filesystem, Accessible path
if settings('playFromStream') == "true": if settings('playFromStream') == "true":
# User forcing to play via HTTP # User forcing to play via HTTP
log("Can't direct play, play from HTTP enabled.", 1) self.logMsg("Can't direct play, play from HTTP enabled.", 1)
return False return False
videotrack = item['MediaSources'][0]['Name'] videotrack = self.item['MediaSources'][0]['Name']
transcodeH265 = settings('transcodeH265') transcodeH265 = settings('transcodeH265')
if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack): if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack):
@ -118,27 +112,27 @@ class PlayUtils():
'2': 720, '2': 720,
'3': 1080 '3': 1080
} }
log("Resolution is: %sP, transcode for resolution: %sP+" self.logMsg("Resolution is: %sP, transcode for resolution: %sP+"
% (resolution, res[transcodeH265]), 1) % (resolution, res[transcodeH265]), 1)
if res[transcodeH265] <= resolution: if res[transcodeH265] <= resolution:
return False return False
canDirectPlay = item['MediaSources'][0]['SupportsDirectPlay'] canDirectPlay = self.item['MediaSources'][0]['SupportsDirectPlay']
# Make sure direct play is supported by the server # Make sure direct play is supported by the server
if not canDirectPlay: if not canDirectPlay:
log("Can't direct play, server doesn't allow/support it.", 1) self.logMsg("Can't direct play, server doesn't allow/support it.", 1)
return False return False
location = item['LocationType'] location = self.item['LocationType']
if location == "FileSystem": if location == "FileSystem":
# Verify the path # Verify the path
if not self.fileExists(): if not self.fileExists():
log("Unable to direct play.") self.logMsg("Unable to direct play.")
try: try:
count = int(settings('failCount')) count = int(settings('failCount'))
except ValueError: except ValueError:
count = 0 count = 0
log("Direct play failed: %s times." % count, 1) self.logMsg("Direct play failed: %s times." % count, 1)
if count < 2: if count < 2:
# Let the user know that direct play failed # Let the user know that direct play failed
@ -163,20 +157,16 @@ class PlayUtils():
def directPlay(self): def directPlay(self):
item = self.item
try: try:
playurl = item['MediaSources'][0]['Path'] playurl = self.item['MediaSources'][0]['Path']
except (IndexError, KeyError): except (IndexError, KeyError):
playurl = item['Path'] playurl = self.item['Path']
if item.get('VideoType'): if self.item.get('VideoType'):
# Specific format modification # Specific format modification
type = item['VideoType'] if self.item['VideoType'] == "Dvd":
if type == "Dvd":
playurl = "%s/VIDEO_TS/VIDEO_TS.IFO" % playurl playurl = "%s/VIDEO_TS/VIDEO_TS.IFO" % playurl
elif type == "BluRay": elif self.item['VideoType'] == "BluRay":
playurl = "%s/BDMV/index.bdmv" % playurl playurl = "%s/BDMV/index.bdmv" % playurl
# Assign network protocol # Assign network protocol
@ -192,35 +182,30 @@ class PlayUtils():
def fileExists(self): def fileExists(self):
log = self.logMsg
if 'Path' not in self.item: if 'Path' not in self.item:
# File has no path defined in server # File has no path defined in server
return False return False
# Convert path to direct play # Convert path to direct play
path = self.directPlay() path = self.directPlay()
log("Verifying path: %s" % path, 1) self.logMsg("Verifying path: %s" % path, 1)
if xbmcvfs.exists(path): if xbmcvfs.exists(path):
log("Path exists.", 1) self.logMsg("Path exists.", 1)
return True return True
elif ":" not in path: elif ":" not in path:
log("Can't verify path, assumed linux. Still try to direct play.", 1) self.logMsg("Can't verify path, assumed linux. Still try to direct play.", 1)
return True return True
else: else:
log("Failed to find file.", 1) self.logMsg("Failed to find file.", 1)
return False return False
def isDirectStream(self): def isDirectStream(self):
log = self.logMsg
item = self.item videotrack = self.item['MediaSources'][0]['Name']
videotrack = item['MediaSources'][0]['Name']
transcodeH265 = utils.settings('transcodeH265') transcodeH265 = utils.settings('transcodeH265')
if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack): if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack):
@ -232,54 +217,47 @@ class PlayUtils():
'2': 720, '2': 720,
'3': 1080 '3': 1080
} }
log("Resolution is: %sP, transcode for resolution: %sP+" self.logMsg("Resolution is: %sP, transcode for resolution: %sP+"
% (resolution, res[transcodeH265]), 1) % (resolution, res[transcodeH265]), 1)
if res[transcodeH265] <= resolution: if res[transcodeH265] <= resolution:
return False return False
# Requirement: BitRate, supported encoding # Requirement: BitRate, supported encoding
canDirectStream = item['MediaSources'][0]['SupportsDirectStream'] canDirectStream = self.item['MediaSources'][0]['SupportsDirectStream']
# Make sure the server supports it # Make sure the server supports it
if not canDirectStream: if not canDirectStream:
return False return False
# Verify the bitrate # Verify the bitrate
if not self.isNetworkSufficient(): if not self.isNetworkSufficient():
log("The network speed is insufficient to direct stream file.", 1) self.logMsg("The network speed is insufficient to direct stream file.", 1)
return False return False
return True return True
def directStream(self): def directStream(self):
item = self.item if 'Path' in self.item and self.item['Path'].endswith('.strm'):
server = self.server
itemid = item['Id']
itemtype = item['Type']
if 'Path' in item and item['Path'].endswith('.strm'):
# Allow strm loading when direct streaming # Allow strm loading when direct streaming
playurl = self.directPlay() playurl = self.directPlay()
elif itemtype == "Audio": elif self.item['Type'] == "Audio":
playurl = "%s/emby/Audio/%s/stream.mp3" % (server, itemid) playurl = "%s/emby/Audio/%s/stream.mp3" % (self.server, self.item['Id'])
else: else:
playurl = "%s/emby/Videos/%s/stream?static=true" % (server, itemid) playurl = "%s/emby/Videos/%s/stream?static=true" % (self.server, self.item['Id'])
return playurl return playurl
def isNetworkSufficient(self): def isNetworkSufficient(self):
log = self.logMsg
settings = self.getBitrate()*1000 settings = self.getBitrate()*1000
try: try:
sourceBitrate = int(self.item['MediaSources'][0]['Bitrate']) sourceBitrate = int(self.item['MediaSources'][0]['Bitrate'])
except (KeyError, TypeError): except (KeyError, TypeError):
log("Bitrate value is missing.", 1) self.logMsg("Bitrate value is missing.", 1)
else: else:
log("The add-on settings bitrate is: %s, the video bitrate required is: %s" self.logMsg("The add-on settings bitrate is: %s, the video bitrate required is: %s"
% (settings, sourceBitrate), 1) % (settings, sourceBitrate), 1)
if settings < sourceBitrate: if settings < sourceBitrate:
return False return False
@ -287,25 +265,19 @@ class PlayUtils():
return True return True
def isTranscoding(self): def isTranscoding(self):
item = self.item
canTranscode = item['MediaSources'][0]['SupportsTranscoding']
# Make sure the server supports it # Make sure the server supports it
if not canTranscode: if not self.item['MediaSources'][0]['SupportsTranscoding']:
return False return False
return True return True
def transcoding(self): def transcoding(self):
item = self.item if 'Path' in self.item and self.item['Path'].endswith('.strm'):
if 'Path' in item and item['Path'].endswith('.strm'):
# Allow strm loading when transcoding # Allow strm loading when transcoding
playurl = self.directPlay() playurl = self.directPlay()
else: else:
itemid = item['Id'] itemid = self.item['Id']
deviceId = self.clientInfo.getDeviceId() deviceId = self.clientInfo.getDeviceId()
playurl = ( playurl = (
"%s/emby/Videos/%s/master.m3u8?MediaSourceId=%s" "%s/emby/Videos/%s/master.m3u8?MediaSourceId=%s"
@ -320,7 +292,6 @@ class PlayUtils():
def getBitrate(self): def getBitrate(self):
# get the addon video quality # get the addon video quality
videoQuality = utils.settings('videoBitrate')
bitrate = { bitrate = {
'0': 664, '0': 664,
@ -345,11 +316,10 @@ class PlayUtils():
} }
# max bit rate supported by server (max signed 32bit integer) # max bit rate supported by server (max signed 32bit integer)
return bitrate.get(videoQuality, 2147483) return bitrate.get(utils.settings('videoBitrate'), 2147483)
def audioSubsPref(self, url, listitem): def audioSubsPref(self, url, listitem):
log = self.logMsg
lang = utils.language lang = utils.language
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
# For transcoding only # For transcoding only
@ -364,9 +334,8 @@ class PlayUtils():
selectSubsIndex = "" selectSubsIndex = ""
playurlprefs = "%s" % url playurlprefs = "%s" % url
item = self.item
try: try:
mediasources = item['MediaSources'][0] mediasources = self.item['MediaSources'][0]
mediastreams = mediasources['MediaStreams'] mediastreams = mediasources['MediaStreams']
except (TypeError, KeyError, IndexError): except (TypeError, KeyError, IndexError):
return return
@ -374,9 +343,8 @@ class PlayUtils():
for stream in mediastreams: for stream in mediastreams:
# Since Emby returns all possible tracks together, have to sort them. # Since Emby returns all possible tracks together, have to sort them.
index = stream['Index'] index = stream['Index']
type = stream['Type']
if 'Audio' in type: if 'Audio' in stream['Type']:
codec = stream['Codec'] codec = stream['Codec']
channelLayout = stream.get('ChannelLayout', "") channelLayout = stream.get('ChannelLayout', "")
@ -389,7 +357,7 @@ class PlayUtils():
audioStreamsList[track] = index audioStreamsList[track] = index
audioStreams.append(track) audioStreams.append(track)
elif 'Subtitle' in type: elif 'Subtitle' in stream['Type']:
try: try:
track = "%s - %s" % (index, stream['Language']) track = "%s - %s" % (index, stream['Language'])
except: except:
@ -436,10 +404,10 @@ class PlayUtils():
# Load subtitles in the listitem if downloadable # Load subtitles in the listitem if downloadable
if selectSubsIndex in downloadableStreams: if selectSubsIndex in downloadableStreams:
itemid = item['Id'] itemid = self.item['Id']
url = [("%s/Videos/%s/%s/Subtitles/%s/Stream.srt" url = [("%s/Videos/%s/%s/Subtitles/%s/Stream.srt"
% (self.server, itemid, itemid, selectSubsIndex))] % (self.server, itemid, itemid, selectSubsIndex))]
log("Set up subtitles: %s %s" % (selectSubsIndex, url), 1) self.logMsg("Set up subtitles: %s %s" % (selectSubsIndex, url), 1)
listitem.setSubtitles(url) listitem.setSubtitles(url)
else: else:
# Burn subtitles # Burn subtitles

View file

@ -42,8 +42,7 @@ class Read_EmbyServer():
# This will return the full item # This will return the full item
item = {} item = {}
url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid result = self.doUtils("{server}/metaman/Users/{UserId}/Items/%s?format=json" % itemid)
result = self.doUtils(url)
if result: if result:
item = result item = result
@ -56,13 +55,12 @@ class Read_EmbyServer():
itemlists = self.split_list(itemlist, 50) itemlists = self.split_list(itemlist, 50)
for itemlist in itemlists: for itemlist in itemlists:
# Will return basic information # Will return basic information
url = "{server}/emby/Users/{UserId}/Items?&format=json"
params = { params = {
'Ids': ",".join(itemlist), 'Ids': ",".join(itemlist),
'Fields': "Etag" 'Fields': "Etag"
} }
result = self.doUtils(url, parameters=params) result = self.doUtils("{server}/emby/Users/{UserId}/Items?&format=json", parameters=params)
if result: if result:
items.extend(result['Items']) items.extend(result['Items'])
@ -75,7 +73,6 @@ class Read_EmbyServer():
itemlists = self.split_list(itemlist, 50) itemlists = self.split_list(itemlist, 50)
for itemlist in itemlists: for itemlist in itemlists:
url = "{server}/emby/Users/{UserId}/Items?format=json"
params = { params = {
"Ids": ",".join(itemlist), "Ids": ",".join(itemlist),
@ -89,7 +86,7 @@ class Read_EmbyServer():
"MediaSources" "MediaSources"
) )
} }
result = self.doUtils(url, parameters=params) result = self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
if result: if result:
items.extend(result['Items']) items.extend(result['Items'])
@ -98,13 +95,10 @@ class Read_EmbyServer():
def getView_embyId(self, itemid): def getView_embyId(self, itemid):
# Returns ancestors using embyId # Returns ancestors using embyId
viewId = None viewId = None
url = "{server}/emby/Items/%s/Ancestors?UserId={UserId}&format=json" % itemid
result = self.doUtils(url)
for view in result: for view in self.doUtils("{server}/emby/Items/%s/Ancestors?UserId={UserId}&format=json" % itemid):
viewtype = view['Type'] if view['Type'] == "CollectionFolder":
if viewtype == "CollectionFolder":
# Found view # Found view
viewId = view['Id'] viewId = view['Id']
@ -131,8 +125,6 @@ class Read_EmbyServer():
return [viewName, viewId, mediatype] return [viewName, viewId, mediatype]
def getFilteredSection(self, parentid, itemtype=None, sortby="SortName", recursive=True, limit=None, sortorder="Ascending", filter=""): def getFilteredSection(self, parentid, itemtype=None, sortby="SortName", recursive=True, limit=None, sortorder="Ascending", filter=""):
doUtils = self.doUtils
url = "{server}/emby/Users/{UserId}/Items?format=json"
params = { params = {
'ParentId': parentid, 'ParentId': parentid,
@ -151,11 +143,9 @@ class Read_EmbyServer():
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers") "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
} }
return doUtils(url, parameters=params) return self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
def getTvChannels(self): def getTvChannels(self):
doUtils = self.doUtils
url = "{server}/emby/LiveTv/Channels/?userid={UserId}&format=json"
params = { params = {
'EnableImages': True, 'EnableImages': True,
@ -165,11 +155,9 @@ class Read_EmbyServer():
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers") "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
} }
return doUtils(url, parameters=params) return self.doUtils("{server}/emby/LiveTv/Channels/?userid={UserId}&format=json", parameters=params)
def getTvRecordings(self, groupid): def getTvRecordings(self, groupid):
doUtils = self.doUtils
url = "{server}/emby/LiveTv/Recordings/?userid={UserId}&format=json"
if groupid == "root": groupid = "" if groupid == "root": groupid = ""
params = { params = {
@ -181,13 +169,10 @@ class Read_EmbyServer():
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers") "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
} }
return doUtils(url, parameters=params) return self.doUtils("{server}/emby/LiveTv/Recordings/?userid={UserId}&format=json", parameters=params)
def getSection(self, parentid, itemtype=None, sortby="SortName", basic=False, dialog=None): def getSection(self, parentid, itemtype=None, sortby="SortName", basic=False, dialog=None):
log = self.logMsg
doUtils = self.doUtils
items = { items = {
'Items': [], 'Items': [],
@ -206,13 +191,13 @@ class Read_EmbyServer():
'Recursive': True, 'Recursive': True,
'Limit': 1 'Limit': 1
} }
result = doUtils(url, parameters=params) result = self.doUtils(url, parameters=params)
try: try:
total = result['TotalRecordCount'] total = result['TotalRecordCount']
items['TotalRecordCount'] = total items['TotalRecordCount'] = total
except TypeError: # Failed to retrieve except TypeError: # Failed to retrieve
log("%s:%s Failed to retrieve the server response." % (url, params), 2) self.logMsg("%s:%s Failed to retrieve the server response." % (url, params), 2)
else: else:
index = 0 index = 0
@ -247,34 +232,34 @@ class Read_EmbyServer():
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers," "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers,"
"MediaSources" "MediaSources"
) )
result = doUtils(url, parameters=params) result = self.doUtils(url, parameters=params)
try: try:
items['Items'].extend(result['Items']) items['Items'].extend(result['Items'])
except TypeError: except TypeError:
# Something happened to the connection # Something happened to the connection
if not throttled: if not throttled:
throttled = True throttled = True
log("Throttle activated.", 1) self.logMsg("Throttle activated.", 1)
if jump == highestjump: if jump == highestjump:
# We already tried with the highestjump, but it failed. Reset value. # We already tried with the highestjump, but it failed. Reset value.
log("Reset highest value.", 1) self.logMsg("Reset highest value.", 1)
highestjump = 0 highestjump = 0
# Lower the number by half # Lower the number by half
if highestjump: if highestjump:
throttled = False throttled = False
jump = highestjump jump = highestjump
log("Throttle deactivated.", 1) self.logMsg("Throttle deactivated.", 1)
else: else:
jump = int(jump/4) jump = int(jump/4)
log("Set jump limit to recover: %s" % jump, 2) self.logMsg("Set jump limit to recover: %s" % jump, 2)
retry = 0 retry = 0
while utils.window('emby_online') != "true": while utils.window('emby_online') != "true":
# Wait server to come back online # Wait server to come back online
if retry == 5: if retry == 5:
log("Unable to reconnect to server. Abort process.", 1) self.logMsg("Unable to reconnect to server. Abort process.", 1)
return items return items
retry += 1 retry += 1
@ -302,12 +287,11 @@ class Read_EmbyServer():
increment = 10 increment = 10
jump += increment jump += increment
log("Increase jump limit to: %s" % jump, 1) self.logMsg("Increase jump limit to: %s" % jump, 1)
return items return items
def getViews(self, mediatype="", root=False, sortedlist=False): def getViews(self, mediatype="", root=False, sortedlist=False):
# Build a list of user views # Build a list of user views
doUtils = self.doUtils
views = [] views = []
mediatype = mediatype.lower() mediatype = mediatype.lower()
@ -316,7 +300,7 @@ class Read_EmbyServer():
else: # Views ungrouped else: # Views ungrouped
url = "{server}/emby/Users/{UserId}/Items?Sortby=SortName&format=json" url = "{server}/emby/Users/{UserId}/Items?Sortby=SortName&format=json"
result = doUtils(url) result = self.doUtils(url)
try: try:
items = result['Items'] items = result['Items']
except TypeError: except TypeError:
@ -324,11 +308,8 @@ class Read_EmbyServer():
else: else:
for item in items: for item in items:
name = item['Name'] item['Name'] = item['Name']
itemId = item['Id'] if item['Type'] == "Channel":
viewtype = item['Type']
if viewtype == "Channel":
# Filter view types # Filter view types
continue continue
@ -339,20 +320,20 @@ class Read_EmbyServer():
# Assumed missing is mixed then. # Assumed missing is mixed then.
'''if itemtype is None: '''if itemtype is None:
url = "{server}/emby/Library/MediaFolders?format=json" url = "{server}/emby/Library/MediaFolders?format=json"
result = doUtils(url) result = self.doUtils(url)
for folder in result['Items']: for folder in result['Items']:
if itemId == folder['Id']: if item['Id'] == folder['Id']:
itemtype = folder.get('CollectionType', "mixed")''' itemtype = folder.get('CollectionType', "mixed")'''
if name not in ('Collections', 'Trailers'): if item['Name'] not in ('Collections', 'Trailers'):
if sortedlist: if sortedlist:
views.append({ views.append({
'name': name, 'name': item['Name'],
'type': itemtype, 'type': itemtype,
'id': itemId 'id': item['Id']
}) })
elif (itemtype == mediatype or elif (itemtype == mediatype or
@ -360,9 +341,9 @@ class Read_EmbyServer():
views.append({ views.append({
'name': name, 'name': item['Name'],
'type': itemtype, 'type': itemtype,
'id': itemId 'id': item['Id']
}) })
return views return views
@ -370,8 +351,6 @@ class Read_EmbyServer():
def verifyView(self, parentid, itemid): def verifyView(self, parentid, itemid):
belongs = False belongs = False
url = "{server}/emby/Users/{UserId}/Items?format=json"
params = { params = {
'ParentId': parentid, 'ParentId': parentid,
@ -381,7 +360,7 @@ class Read_EmbyServer():
'Recursive': True, 'Recursive': True,
'Ids': itemid 'Ids': itemid
} }
result = self.doUtils(url, parameters=params) result = self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
try: try:
total = result['TotalRecordCount'] total = result['TotalRecordCount']
except TypeError: except TypeError:
@ -394,40 +373,23 @@ class Read_EmbyServer():
return belongs return belongs
def getMovies(self, parentId, basic=False, dialog=None): def getMovies(self, parentId, basic=False, dialog=None):
return self.getSection(parentId, "Movie", basic=basic, dialog=dialog)
items = self.getSection(parentId, "Movie", basic=basic, dialog=dialog)
return items
def getBoxset(self, dialog=None): def getBoxset(self, dialog=None):
return self.getSection(None, "BoxSet", dialog=dialog)
items = self.getSection(None, "BoxSet", dialog=dialog)
return items
def getMovies_byBoxset(self, boxsetid): def getMovies_byBoxset(self, boxsetid):
return self.getSection(boxsetid, "Movie")
items = self.getSection(boxsetid, "Movie")
return items
def getMusicVideos(self, parentId, basic=False, dialog=None): def getMusicVideos(self, parentId, basic=False, dialog=None):
return self.getSection(parentId, "MusicVideo", basic=basic, dialog=dialog)
items = self.getSection(parentId, "MusicVideo", basic=basic, dialog=dialog)
return items
def getHomeVideos(self, parentId): def getHomeVideos(self, parentId):
items = self.getSection(parentId, "Video") return self.getSection(parentId, "Video")
return items
def getShows(self, parentId, basic=False, dialog=None): def getShows(self, parentId, basic=False, dialog=None):
return self.getSection(parentId, "Series", basic=basic, dialog=dialog)
items = self.getSection(parentId, "Series", basic=basic, dialog=dialog)
return items
def getSeasons(self, showId): def getSeasons(self, showId):
@ -437,13 +399,12 @@ class Read_EmbyServer():
'TotalRecordCount': 0 'TotalRecordCount': 0
} }
url = "{server}/emby/Shows/%s/Seasons?UserId={UserId}&format=json" % showId
params = { params = {
'IsVirtualUnaired': False, 'IsVirtualUnaired': False,
'Fields': "Etag" 'Fields': "Etag"
} }
result = self.doUtils(url, parameters=params) result = self.doUtils("{server}/emby/Shows/%s/Seasons?UserId={UserId}&format=json" % showId, parameters=params)
if result: if result:
items = result items = result
@ -451,25 +412,19 @@ class Read_EmbyServer():
def getEpisodes(self, parentId, basic=False, dialog=None): def getEpisodes(self, parentId, basic=False, dialog=None):
items = self.getSection(parentId, "Episode", basic=basic, dialog=dialog) return self.getSection(parentId, "Episode", basic=basic, dialog=dialog)
return items
def getEpisodesbyShow(self, showId): def getEpisodesbyShow(self, showId):
items = self.getSection(showId, "Episode") return self.getSection(showId, "Episode")
return items
def getEpisodesbySeason(self, seasonId): def getEpisodesbySeason(self, seasonId):
items = self.getSection(seasonId, "Episode") return self.getSection(seasonId, "Episode")
return items
def getArtists(self, dialog=None): def getArtists(self, dialog=None):
doUtils = self.doUtils
items = { items = {
'Items': [], 'Items': [],
@ -483,7 +438,7 @@ class Read_EmbyServer():
'Recursive': True, 'Recursive': True,
'Limit': 1 'Limit': 1
} }
result = doUtils(url, parameters=params) result = self.doUtils(url, parameters=params)
try: try:
total = result['TotalRecordCount'] total = result['TotalRecordCount']
items['TotalRecordCount'] = total items['TotalRecordCount'] = total
@ -513,7 +468,7 @@ class Read_EmbyServer():
"AirTime,DateCreated,MediaStreams,People,ProviderIds,Overview" "AirTime,DateCreated,MediaStreams,People,ProviderIds,Overview"
) )
} }
result = doUtils(url, parameters=params) result = self.doUtils(url, parameters=params)
items['Items'].extend(result['Items']) items['Items'].extend(result['Items'])
index += jump index += jump
@ -523,28 +478,17 @@ class Read_EmbyServer():
return items return items
def getAlbums(self, basic=False, dialog=None): def getAlbums(self, basic=False, dialog=None):
return self.getSection(None, "MusicAlbum", sortby="DateCreated", basic=basic, dialog=dialog)
items = self.getSection(None, "MusicAlbum", sortby="DateCreated", basic=basic, dialog=dialog)
return items
def getAlbumsbyArtist(self, artistId): def getAlbumsbyArtist(self, artistId):
return self.getSection(artistId, "MusicAlbum", sortby="DateCreated")
items = self.getSection(artistId, "MusicAlbum", sortby="DateCreated")
return items
def getSongs(self, basic=False, dialog=None): def getSongs(self, basic=False, dialog=None):
return self.getSection(None, "Audio", basic=basic, dialog=dialog)
items = self.getSection(None, "Audio", basic=basic, dialog=dialog)
return items
def getSongsbyAlbum(self, albumId): def getSongsbyAlbum(self, albumId):
return self.getSection(albumId, "Audio")
items = self.getSection(albumId, "Audio")
return items
def getAdditionalParts(self, itemId): def getAdditionalParts(self, itemId):
@ -554,8 +498,7 @@ class Read_EmbyServer():
'TotalRecordCount': 0 'TotalRecordCount': 0
} }
url = "{server}/emby/Videos/%s/AdditionalParts?UserId={UserId}&format=json" % itemId result = self.doUtils("{server}/emby/Videos/%s/AdditionalParts?UserId={UserId}&format=json" % itemId)
result = self.doUtils(url)
if result: if result:
items = result items = result
@ -577,24 +520,18 @@ class Read_EmbyServer():
def updateUserRating(self, itemid, like=None, favourite=None, deletelike=False): def updateUserRating(self, itemid, like=None, favourite=None, deletelike=False):
# Updates the user rating to Emby # Updates the user rating to Emby
doUtils = self.doUtils
if favourite: if favourite:
url = "{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid self.doUtils("{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid, action_type="POST")
doUtils(url, type="POST")
elif favourite == False: elif favourite == False:
url = "{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid self.doUtils("{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid, action_type="DELETE")
doUtils(url, type="DELETE")
if not deletelike and like: if not deletelike and like:
url = "{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=true&format=json" % itemid self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=true&format=json" % itemid, action_type="POST")
doUtils(url, type="POST") elif not deletelike and like is False:
elif not deletelike and like == False: self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=false&format=json" % itemid, action_type="POST")
url = "{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=false&format=json" % itemid
doUtil(url, type="POST")
elif deletelike: elif deletelike:
url = "{server}/emby/Users/{UserId}/Items/%s/Rating?format=json" % itemid self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?format=json" % itemid, action_type="DELETE")
doUtils(url, type="DELETE")
self.logMsg("Update user rating to emby for itemid: %s " self.logMsg("Update user rating to emby for itemid: %s "
"| like: %s | favourite: %s | deletelike: %s" "| like: %s | favourite: %s | deletelike: %s"

View file

@ -81,7 +81,6 @@ class UserClient(threading.Thread):
def getUserId(self): def getUserId(self):
log = self.logMsg
window = utils.window window = utils.window
settings = utils.settings settings = utils.settings
@ -94,17 +93,17 @@ class UserClient(threading.Thread):
if not s_userId: if not s_userId:
# Save access token if it's missing from settings # Save access token if it's missing from settings
settings('userId%s' % username, value=w_userId) settings('userId%s' % username, value=w_userId)
log("Returning userId from WINDOW for username: %s UserId: %s" self.logMsg("Returning userId from WINDOW for username: %s UserId: %s"
% (username, w_userId), 2) % (username, w_userId), 2)
return w_userId return w_userId
# Verify the settings # Verify the settings
elif s_userId: elif s_userId:
log("Returning userId from SETTINGS for username: %s userId: %s" self.logMsg("Returning userId from SETTINGS for username: %s userId: %s"
% (username, s_userId), 2) % (username, s_userId), 2)
return s_userId return s_userId
# No userId found # No userId found
else: else:
log("No userId saved for username: %s." % username, 1) self.logMsg("No userId saved for username: %s." % username, 1)
def getServer(self, prefix=True): def getServer(self, prefix=True):
@ -142,7 +141,6 @@ class UserClient(threading.Thread):
def getToken(self): def getToken(self):
log = self.logMsg
window = utils.window window = utils.window
settings = utils.settings settings = utils.settings
@ -156,17 +154,17 @@ class UserClient(threading.Thread):
if not s_token: if not s_token:
# Save access token if it's missing from settings # Save access token if it's missing from settings
settings('accessToken', value=w_token) settings('accessToken', value=w_token)
log("Returning accessToken from WINDOW for username: %s accessToken: %s" self.logMsg("Returning accessToken from WINDOW for username: %s accessToken: %s"
% (username, w_token), 2) % (username, w_token), 2)
return w_token return w_token
# Verify the settings # Verify the settings
elif s_token: elif s_token:
log("Returning accessToken from SETTINGS for username: %s accessToken: %s" self.logMsg("Returning accessToken from SETTINGS for username: %s accessToken: %s"
% (username, s_token), 2) % (username, s_token), 2)
window('emby_accessToken%s' % username, value=s_token) window('emby_accessToken%s' % username, value=s_token)
return s_token return s_token
else: else:
log("No token found.", 1) self.logMsg("No token found.", 1)
return "" return ""
def getSSLverify(self): def getSSLverify(self):
@ -198,46 +196,37 @@ class UserClient(threading.Thread):
def setUserPref(self): def setUserPref(self):
doUtils = self.doUtils.downloadUrl doUtils = self.doUtils.downloadUrl
art = artwork.Artwork()
url = "{server}/emby/Users/{UserId}?format=json" result = doUtils("{server}/emby/Users/{UserId}?format=json")
result = doUtils(url)
self.userSettings = result self.userSettings = result
# Set user image for skin display # Set user image for skin display
if result.get('PrimaryImageTag'): if result.get('PrimaryImageTag'):
utils.window('EmbyUserImage', value=art.getUserArtwork(result['Id'], 'Primary')) utils.window('EmbyUserImage', value=artwork.Artwork().getUserArtwork(result['Id'], 'Primary'))
# Set resume point max # Set resume point max
url = "{server}/emby/System/Configuration?format=json" result = doUtils("{server}/emby/System/Configuration?format=json")
result = doUtils(url)
utils.settings('markPlayed', value=str(result['MaxResumePct'])) utils.settings('markPlayed', value=str(result['MaxResumePct']))
def getPublicUsers(self): def getPublicUsers(self):
server = self.getServer()
# Get public Users # Get public Users
url = "%s/emby/Users/Public?format=json" % server result = self.doUtils.downloadUrl("%s/emby/Users/Public?format=json" % self.getServer(), authenticate=False)
result = self.doUtils.downloadUrl(url, authenticate=False)
if result != "": if result != "":
return result return result
else: else:
# Server connection failed # Server connection failed
return False return False
def hasAccess(self): def hasAccess(self):
# hasAccess is verified in service.py # hasAccess is verified in service.py
log = self.logMsg
window = utils.window window = utils.window
url = "{server}/emby/Users?format=json" result = self.doUtils.downloadUrl("{server}/emby/Users?format=json")
result = self.doUtils.downloadUrl(url)
if result == False: if result == False:
# Access is restricted, set in downloadutils.py via exception # Access is restricted, set in downloadutils.py via exception
log("Access is restricted.", 1) self.logMsg("Access is restricted.", 1)
self.HasAccess = False self.HasAccess = False
elif window('emby_online') != "true": elif window('emby_online') != "true":
@ -245,7 +234,7 @@ class UserClient(threading.Thread):
pass pass
elif window('emby_serverStatus') == "restricted": elif window('emby_serverStatus') == "restricted":
log("Access is granted.", 1) self.logMsg("Access is granted.", 1)
self.HasAccess = True self.HasAccess = True
window('emby_serverStatus', clear=True) window('emby_serverStatus', clear=True)
xbmcgui.Dialog().notification("Emby for Kodi", utils.language(33007)) xbmcgui.Dialog().notification("Emby for Kodi", utils.language(33007))
@ -301,7 +290,6 @@ class UserClient(threading.Thread):
def authenticate(self): def authenticate(self):
log = self.logMsg
lang = utils.language lang = utils.language
window = utils.window window = utils.window
settings = utils.settings settings = utils.settings
@ -316,24 +304,24 @@ class UserClient(threading.Thread):
# If there's no settings.xml # If there's no settings.xml
if not hasSettings: if not hasSettings:
log("No settings.xml found.", 1) self.logMsg("No settings.xml found.", 1)
self.auth = False self.auth = False
return return
# If no user information # If no user information
elif not server or not username: elif not server or not username:
log("Missing server information.", 1) self.logMsg("Missing server information.", 1)
self.auth = False self.auth = False
return return
# If there's a token, load the user # If there's a token, load the user
elif self.getToken(): elif self.getToken():
result = self.loadCurrUser() result = self.loadCurrUser()
if result == False: if result is False:
pass pass
else: else:
log("Current user: %s" % self.currUser, 1) self.logMsg("Current user: %s" % self.currUser, 1)
log("Current userId: %s" % self.currUserId, 1) self.logMsg("Current userId: %s" % self.currUserId, 1)
log("Current accessToken: %s" % self.currToken, 2) self.logMsg("Current accessToken: %s" % self.currToken, 2)
return return
##### AUTHENTICATE USER ##### ##### AUTHENTICATE USER #####
@ -353,7 +341,7 @@ class UserClient(threading.Thread):
option=xbmcgui.ALPHANUM_HIDE_INPUT) option=xbmcgui.ALPHANUM_HIDE_INPUT)
# If password dialog is cancelled # If password dialog is cancelled
if not password: if not password:
log("No password entered.", 0) self.logMsg("No password entered.", 0)
window('emby_serverStatus', value="Stop") window('emby_serverStatus', value="Stop")
self.auth = False self.auth = False
return return
@ -367,40 +355,38 @@ class UserClient(threading.Thread):
sha1 = sha1.hexdigest() sha1 = sha1.hexdigest()
# Authenticate username and password # Authenticate username and password
url = "%s/emby/Users/AuthenticateByName?format=json" % server
data = {'username': username, 'password': sha1} data = {'username': username, 'password': sha1}
log(data, 2) self.logMsg(data, 2)
result = self.doUtils.downloadUrl(url, postBody=data, type="POST", authenticate=False) result = self.doUtils.downloadUrl("%s/emby/Users/AuthenticateByName?format=json" % server, postBody=data, action_type="POST", authenticate=False)
try: try:
log("Auth response: %s" % result, 1) self.logMsg("Auth response: %s" % result, 1)
accessToken = result['AccessToken'] accessToken = result['AccessToken']
except (KeyError, TypeError): except (KeyError, TypeError):
log("Failed to retrieve the api key.", 1) self.logMsg("Failed to retrieve the api key.", 1)
accessToken = None accessToken = None
if accessToken is not None: if accessToken is not None:
self.currUser = username self.currUser = username
dialog.notification("Emby for Kodi", dialog.notification("Emby for Kodi",
"%s %s!" % (lang(33000), self.currUser.decode('utf-8'))) "%s %s!" % (lang(33000), self.currUser.decode('utf-8')))
userId = result['User']['Id']
settings('accessToken', value=accessToken) settings('accessToken', value=accessToken)
settings('userId%s' % username, value=userId) settings('userId%s' % username, value=result['User']['Id'])
log("User Authenticated: %s" % accessToken, 1) self.logMsg("User Authenticated: %s" % accessToken, 1)
self.loadCurrUser(authenticated=True) self.loadCurrUser(authenticated=True)
window('emby_serverStatus', clear=True) window('emby_serverStatus', clear=True)
self.retry = 0 self.retry = 0
else: else:
log("User authentication failed.", 1) self.logMsg("User authentication failed.", 1)
settings('accessToken', value="") settings('accessToken', value="")
settings('userId%s' % username, value="") settings('userId%s' % username, value="")
dialog.ok(lang(33001), lang(33009)) dialog.ok(lang(33001), lang(33009))
# Give two attempts at entering password # Give two attempts at entering password
if self.retry == 2: if self.retry == 2:
log("Too many retries. " self.logMsg("Too many retries. "
"You can retry by resetting attempts in the addon settings.", 1) "You can retry by resetting attempts in the addon settings.", 1)
window('emby_serverStatus', value="Stop") window('emby_serverStatus', value="Stop")
dialog.ok(lang(33001), lang(33010)) dialog.ok(lang(33001), lang(33010))
@ -410,28 +396,23 @@ class UserClient(threading.Thread):
def resetClient(self): def resetClient(self):
log = self.logMsg self.logMsg("Reset UserClient authentication.", 1)
log("Reset UserClient authentication.", 1)
userId = self.getUserId()
if self.currToken is not None: if self.currToken is not None:
# In case of 401, removed saved token # In case of 401, removed saved token
utils.settings('accessToken', value="") utils.settings('accessToken', value="")
utils.window('emby_accessToken%s' % userId, clear=True) utils.window('emby_accessToken%s' % self.getUserId(), clear=True)
self.currToken = None self.currToken = None
log("User token has been removed.", 1) self.logMsg("User token has been removed.", 1)
self.auth = True self.auth = True
self.currUser = None self.currUser = None
def run(self): def run(self):
log = self.logMsg
window = utils.window window = utils.window
monitor = xbmc.Monitor() monitor = xbmc.Monitor()
log("----===## Starting UserClient ##===----", 0) self.logMsg("----===## Starting UserClient ##===----", 0)
while not monitor.abortRequested(): while not monitor.abortRequested():
@ -466,8 +447,8 @@ class UserClient(threading.Thread):
# The status Stop is for when user cancelled password dialog. # The status Stop is for when user cancelled password dialog.
if server and username and status != "Stop": if server and username and status != "Stop":
# Only if there's information found to login # Only if there's information found to login
log("Server found: %s" % server, 2) self.logMsg("Server found: %s" % server, 2)
log("Username found: %s" % username, 2) self.logMsg("Username found: %s" % username, 2)
self.auth = True self.auth = True
@ -480,7 +461,7 @@ class UserClient(threading.Thread):
break break
self.doUtils.stopSession() self.doUtils.stopSession()
log("##===---- UserClient Stopped ----===##", 0) self.logMsg("##===---- UserClient Stopped ----===##", 0)
def stopClient(self): def stopClient(self):
# When emby for kodi terminates # When emby for kodi terminates

View file

@ -62,26 +62,23 @@ def window(property, value=None, clear=False, windowid=10000):
def settings(setting, value=None): def settings(setting, value=None):
# Get or add addon setting # Get or add addon setting
addon = xbmcaddon.Addon(id='plugin.video.emby')
if value is not None: if value is not None:
addon.setSetting(setting, value) xbmcaddon.Addon(id='plugin.video.metaman').setSetting(setting, value)
else: else:
return addon.getSetting(setting) #returns unicode object return xbmcaddon.Addon(id='plugin.video.metaman').getSetting(setting) #returns unicode object
def language(stringid): def language(stringid):
# Central string retrieval # Central string retrieval
addon = xbmcaddon.Addon(id='plugin.video.emby') string = xbmcaddon.Addon(id='plugin.video.emby').getLocalizedString(stringid) #returns unicode object
string = addon.getLocalizedString(stringid) #returns unicode object
return string return string
def kodiSQL(type="video"): def kodiSQL(media_type="video"):
if type == "emby": if media_type == "emby":
dbPath = xbmc.translatePath("special://database/emby.db").decode('utf-8') dbPath = xbmc.translatePath("special://database/emby.db").decode('utf-8')
elif type == "music": elif media_type == "music":
dbPath = getKodiMusicDBPath() dbPath = getKodiMusicDBPath()
elif type == "texture": elif media_type == "texture":
dbPath = xbmc.translatePath("special://database/Textures13.db").decode('utf-8') dbPath = xbmc.translatePath("special://database/Textures13.db").decode('utf-8')
else: else:
dbPath = getKodiVideoDBPath() dbPath = getKodiVideoDBPath()
@ -91,7 +88,6 @@ def kodiSQL(type="video"):
def getKodiVideoDBPath(): def getKodiVideoDBPath():
kodibuild = xbmc.getInfoLabel('System.BuildVersion')[:2]
dbVersion = { dbVersion = {
"13": 78, # Gotham "13": 78, # Gotham
@ -102,12 +98,11 @@ def getKodiVideoDBPath():
dbPath = xbmc.translatePath( dbPath = xbmc.translatePath(
"special://database/MyVideos%s.db" "special://database/MyVideos%s.db"
% dbVersion.get(kodibuild, "")).decode('utf-8') % dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8')
return dbPath return dbPath
def getKodiMusicDBPath(): def getKodiMusicDBPath():
kodibuild = xbmc.getInfoLabel('System.BuildVersion')[:2]
dbVersion = { dbVersion = {
"13": 46, # Gotham "13": 46, # Gotham
@ -118,7 +113,7 @@ def getKodiMusicDBPath():
dbPath = xbmc.translatePath( dbPath = xbmc.translatePath(
"special://database/MyMusic%s.db" "special://database/MyMusic%s.db"
% dbVersion.get(kodibuild, "")).decode('utf-8') % dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8')
return dbPath return dbPath
def getScreensaver(): def getScreensaver():
@ -133,11 +128,7 @@ def getScreensaver():
'setting': "screensaver.mode" 'setting': "screensaver.mode"
} }
} }
result = xbmc.executeJSONRPC(json.dumps(query)) return json.loads(xbmc.executeJSONRPC(json.dumps(query)))['result']['value']
result = json.loads(result)
screensaver = result['result']['value']
return screensaver
def setScreensaver(value): def setScreensaver(value):
# Toggle the screensaver # Toggle the screensaver
@ -152,15 +143,13 @@ def setScreensaver(value):
'value': value 'value': value
} }
} }
result = xbmc.executeJSONRPC(json.dumps(query)) logMsg("EMBY", "Toggling screensaver: %s %s" % (value, xbmc.executeJSONRPC(json.dumps(query))), 1)
logMsg("EMBY", "Toggling screensaver: %s %s" % (value, result), 1)
def reset(): def reset():
dialog = xbmcgui.Dialog() dialog = xbmcgui.Dialog()
resp = dialog.yesno("Warning", "Are you sure you want to reset your local Kodi database?") if dialog.yesno("Warning", "Are you sure you want to reset your local Kodi database?") == 0:
if resp == 0:
return return
# first stop any db sync # first stop any db sync
@ -222,7 +211,7 @@ def reset():
cursor.close() cursor.close()
# Offer to wipe cached thumbnails # Offer to wipe cached thumbnails
resp = dialog.yesno("Warning", "Removed all cached artwork?") resp = dialog.yesno("Warning", "Remove all cached artwork?")
if resp: if resp:
logMsg("EMBY", "Resetting all cached artwork.", 0) logMsg("EMBY", "Resetting all cached artwork.", 0)
# Remove all existing textures first # Remove all existing textures first
@ -418,9 +407,7 @@ def passwordsXML():
elif option == 1: elif option == 1:
# User selected remove # User selected remove
iterator = root.getiterator('passwords') for paths in root.getiterator('passwords'):
for paths in iterator:
for path in paths: for path in paths:
if path.find('.//from').text == "smb://%s/" % credentials: if path.find('.//from').text == "smb://%s/" % credentials:
paths.remove(path) paths.remove(path)

View file

@ -55,7 +55,6 @@ class VideoNodes(object):
def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False): def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False):
window = utils.window window = utils.window
kodiversion = self.kodiversion
if viewtype == "mixed": if viewtype == "mixed":
dirname = "%s - %s" % (viewid, mediatype) dirname = "%s - %s" % (viewid, mediatype)
@ -203,10 +202,10 @@ class VideoNodes(object):
elif nodetype == "nextepisodes": elif nodetype == "nextepisodes":
# Custom query # Custom query
path = "plugin://plugin.video.emby/?id=%s&mode=nextup&limit=25" % tagname path = "plugin://plugin.video.emby/?id=%s&mode=nextup&limit=25" % tagname
elif kodiversion == 14 and nodetype == "recentepisodes": elif self.kodiversion == 14 and nodetype == "recentepisodes":
# Custom query # Custom query
path = "plugin://plugin.video.emby/?id=%s&mode=recentepisodes&limit=25" % tagname path = "plugin://plugin.video.emby/?id=%s&mode=recentepisodes&limit=25" % tagname
elif kodiversion == 14 and nodetype == "inprogressepisodes": elif self.kodiversion == 14 and nodetype == "inprogressepisodes":
# Custom query # Custom query
path = "plugin://plugin.video.emby/?id=%s&mode=inprogressepisodes&limit=25"% tagname path = "plugin://plugin.video.emby/?id=%s&mode=inprogressepisodes&limit=25"% tagname
else: else:
@ -247,7 +246,7 @@ class VideoNodes(object):
# Create the root # Create the root
if (nodetype == "nextepisodes" or mediatype == "homevideos" or if (nodetype == "nextepisodes" or mediatype == "homevideos" or
(kodiversion == 14 and nodetype in ('recentepisodes', 'inprogressepisodes'))): (self.kodiversion == 14 and nodetype in ('recentepisodes', 'inprogressepisodes'))):
# Folder type with plugin path # Folder type with plugin path
root = self.commonRoot(order=node, label=label, tagname=tagname, roottype=2) root = self.commonRoot(order=node, label=label, tagname=tagname, roottype=2)
etree.SubElement(root, 'path').text = path etree.SubElement(root, 'path').text = path

View file

@ -455,7 +455,6 @@ class WebSocket(object):
self._handshake(hostname, port, resource, **options) self._handshake(hostname, port, resource, **options)
def _handshake(self, host, port, resource, **options): def _handshake(self, host, port, resource, **options):
sock = self.sock
headers = [] headers = []
headers.append("GET %s HTTP/1.1" % resource) headers.append("GET %s HTTP/1.1" % resource)
headers.append("Upgrade: websocket") headers.append("Upgrade: websocket")

View file

@ -51,9 +51,7 @@ class WebSocket_Client(threading.Thread):
def sendProgressUpdate(self, data): def sendProgressUpdate(self, data):
log = self.logMsg self.logMsg("sendProgressUpdate", 2)
log("sendProgressUpdate", 2)
try: try:
messageData = { messageData = {
@ -62,14 +60,13 @@ class WebSocket_Client(threading.Thread):
} }
messageString = json.dumps(messageData) messageString = json.dumps(messageData)
self.client.send(messageString) self.client.send(messageString)
log("Message data: %s" % messageString, 2) self.logMsg("Message data: %s" % messageString, 2)
except Exception as e: except Exception as e:
log("Exception: %s" % e, 1) self.logMsg("Exception: %s" % e, 1)
def on_message(self, ws, message): def on_message(self, ws, message):
log = self.logMsg
window = utils.window window = utils.window
lang = utils.language lang = utils.language
@ -79,7 +76,7 @@ class WebSocket_Client(threading.Thread):
if messageType not in ('SessionEnded'): if messageType not in ('SessionEnded'):
# Mute certain events # Mute certain events
log("Message: %s" % message, 1) self.logMsg("Message: %s" % message, 1)
if messageType == "Play": if messageType == "Play":
# A remote control play command has been sent from the server. # A remote control play command has been sent from the server.
@ -129,10 +126,10 @@ class WebSocket_Client(threading.Thread):
seekto = data['SeekPositionTicks'] seekto = data['SeekPositionTicks']
seektime = seekto / 10000000.0 seektime = seekto / 10000000.0
action(seektime) action(seektime)
log("Seek to %s." % seektime, 1) self.logMsg("Seek to %s." % seektime, 1)
else: else:
action() action()
log("Command: %s completed." % command, 1) self.logMsg("Command: %s completed." % command, 1)
window('emby_command', value="true") window('emby_command', value="true")
@ -279,26 +276,21 @@ class WebSocket_Client(threading.Thread):
def run(self): def run(self):
log = self.logMsg
window = utils.window window = utils.window
monitor = self.monitor
loglevel = int(window('emby_logLevel')) loglevel = int(window('emby_logLevel'))
# websocket.enableTrace(True) # websocket.enableTrace(True)
userId = window('emby_currUser') userId = window('emby_currUser')
server = window('emby_server%s' % userId) server = window('emby_server%s' % userId)
token = window('emby_accessToken%s' % userId) token = window('emby_accessToken%s' % userId)
deviceId = self.deviceId
# Get the appropriate prefix for the websocket # Get the appropriate prefix for the websocket
if "https" in server: if "https" in server:
server = server.replace('https', "wss") server = server.replace('https', "wss")
else: else:
server = server.replace('http', "ws") server = server.replace('http', "ws")
websocket_url = "%s?api_key=%s&deviceId=%s" % (server, token, deviceId) websocket_url = "%s?api_key=%s&deviceId=%s" % (server, token, self.deviceId)
log("websocket url: %s" % websocket_url, 1) self.logMsg("websocket url: %s" % websocket_url, 1)
self.client = websocket.WebSocketApp(websocket_url, self.client = websocket.WebSocketApp(websocket_url,
on_message=self.on_message, on_message=self.on_message,
@ -306,19 +298,19 @@ class WebSocket_Client(threading.Thread):
on_close=self.on_close) on_close=self.on_close)
self.client.on_open = self.on_open self.client.on_open = self.on_open
log("----===## Starting WebSocketClient ##===----", 0) self.logMsg("----===## Starting WebSocketClient ##===----", 0)
while not monitor.abortRequested(): while not self.monitor.abortRequested():
self.client.run_forever(ping_interval=10) self.client.run_forever(ping_interval=10)
if self.stopWebsocket: if self.stopWebsocket:
break break
if monitor.waitForAbort(5): if self.monitor.waitForAbort(5):
# Abort was requested, exit # Abort was requested, exit
break break
log("##===---- WebSocketClient Stopped ----===##", 0) self.logMsg("##===---- WebSocketClient Stopped ----===##", 0)
def stopClient(self): def stopClient(self):