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

View file

@ -323,7 +323,7 @@
<string id="33020">Gathering tv shows from:</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="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="33025">completed in:</string>
<string id="33026">Comparing movies from:</string>

View file

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

View file

@ -35,7 +35,7 @@ class Artwork():
self.enableTextureCache = utils.settings('enableTextureCache') == "true"
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)
if not self.xbmc_port and self.enableTextureCache:
@ -509,8 +509,6 @@ class Artwork():
def getAllArtwork(self, item, parentInfo=False):
server = self.server
itemid = item['Id']
artworks = item['ImageTags']
backdrops = item.get('BackdropImageTags',[])
@ -541,7 +539,7 @@ class Artwork():
artwork = (
"%s/emby/Items/%s/Images/Backdrop/%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)
# Process the rest of the artwork
@ -552,7 +550,7 @@ class Artwork():
artwork = (
"%s/emby/Items/%s/Images/%s/0?"
"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
# Process parent items if the main item is missing artwork
@ -570,7 +568,7 @@ class Artwork():
artwork = (
"%s/emby/Items/%s/Images/Backdrop/%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)
# Process the rest of the artwork
@ -586,7 +584,7 @@ class Artwork():
artwork = (
"%s/emby/Items/%s/Images/%s/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, parentId, parentart,
% (self.server, parentId, parentart,
maxWidth, maxHeight, parentTag, customquery))
allartworks[parentart] = artwork
@ -600,7 +598,7 @@ class Artwork():
artwork = (
"%s/emby/Items/%s/Images/Primary/0?"
"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
return allartworks

View file

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

View file

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

View file

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

View file

@ -67,12 +67,12 @@ def doMainListing():
if not path:
path = utils.window('Emby.nodes.%s.content' % 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.
#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)
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)
elif path and not xbmc.getCondVisibility("Window.IsActive(VideoLibrary) | Window.IsActive(Pictures) | Window.IsActive(MusicLibrary)"):
addDirectoryItem(label, path)
@ -166,7 +166,7 @@ def deleteItem():
doUtils = downloadutils.DownloadUtils()
url = "{server}/emby/Items/%s?format=json" % embyid
utils.logMsg("EMBY delete", "Deleting request: %s" % embyid, 0)
doUtils.downloadUrl(url, type="DELETE")
doUtils.downloadUrl(url, action_type="DELETE")
##### ADD ADDITIONAL USERS #####
def addUser():
@ -221,7 +221,7 @@ def addUser():
selected = additionalUsername[resp]
selected_userId = additionalUserlist[selected]
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(
heading="Success!",
message="%s removed from viewing session" % selected,
@ -254,7 +254,7 @@ def addUser():
selected = users[resp]
selected_userId = userlist[selected]
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(
heading="Success!",
message="%s added to viewing session" % selected,
@ -483,12 +483,11 @@ def GetSubFolders(nodeindex):
title = utils.window('Emby.nodes.%s%s.title' %(nodeindex,node))
if title:
path = utils.window('Emby.nodes.%s%s.content' %(nodeindex,node))
type = utils.window('Emby.nodes.%s%s.type' %(nodeindex,node))
addDirectoryItem(title, path)
xbmcplugin.endOfDirectory(int(sys.argv[1]))
##### BROWSE EMBY NODES DIRECTLY #####
def BrowseContent(viewname, type="", folderid=""):
def BrowseContent(viewname, browse_type="", folderid=""):
emby = embyserver.Read_EmbyServer()
art = artwork.Artwork()
@ -496,46 +495,47 @@ def BrowseContent(viewname, type="", folderid=""):
#folderid used as filter ?
if folderid in ["recent","recentepisodes","inprogress","inprogressepisodes","unwatched","nextepisodes","sets","genres","random","recommended"]:
filter = folderid
filter_type = folderid
folderid = ""
else:
filter = ""
filter_type = ""
xbmcplugin.setPluginCategory(int(sys.argv[1]), viewname)
#get views for root level
if not folderid:
views = emby.getViews(type)
views = emby.getViews(browse_type)
for view in views:
if view.get("name") == viewname.decode('utf-8'):
folderid = view.get("id")
break
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
#only proceed if we have a folderid
if folderid:
if type.lower() == "homevideos":
if browse_type.lower() == "homevideos":
xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
itemtype = "Video,Folder,PhotoAlbum"
elif type.lower() == "photos":
elif browse_type.lower() == "photos":
xbmcplugin.setContent(int(sys.argv[1]), 'files')
itemtype = "Photo,PhotoAlbum,Folder"
else:
itemtype = ""
#get the actual listing
if type == "recordings":
if browse_type == "recordings":
listing = emby.getTvRecordings(folderid)
elif type == "tvchannels":
elif browse_type == "tvchannels":
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")
elif filter == "random":
elif filter_type == "random":
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="Random", recursive=True, limit=150, sortorder="Descending")
elif filter == "recommended":
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter="IsFavorite")
elif filter == "sets":
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[1], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter="IsFavorite")
elif filter_type == "recommended":
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter_type="IsFavorite")
elif filter_type == "sets":
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[1], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter_type="IsFavorite")
else:
listing = emby.getFilteredSection(folderid, itemtype=itemtype, recursive=False)
@ -545,14 +545,14 @@ def BrowseContent(viewname, type="", folderid=""):
li = createListItemFromEmbyItem(item,art,doUtils)
if item.get("IsFolder") == True:
#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)
else:
#playable item, set plugin path and mediastreams
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)
else:
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.IPPROTO_IP, socket.SO_REUSEADDR, 1)
self.logMsg("MultiGroup : %s" % str(MULTI_GROUP), 2);
self.logMsg("Sending UDP Data: %s" % MESSAGE, 2);
self.logMsg("MultiGroup : %s" % str(MULTI_GROUP), 2)
self.logMsg("Sending UDP Data: %s" % MESSAGE, 2)
sock.sendto(MESSAGE, MULTI_GROUP)
try:

View file

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

View file

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

View file

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

View file

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

View file

@ -49,15 +49,13 @@ class Player(xbmc.Player):
def onPlayBackStarted(self):
log = self.logMsg
window = utils.window
# Will be called when xbmc starts playing a file
xbmcplayer = self.xbmcplayer
self.stopAll()
# Get current file
try:
currentFile = xbmcplayer.getPlayingFile()
currentFile = self.xbmcplayer.getPlayingFile()
xbmc.sleep(300)
except:
currentFile = ""
@ -65,11 +63,11 @@ class Player(xbmc.Player):
while not currentFile:
xbmc.sleep(100)
try:
currentFile = xbmcplayer.getPlayingFile()
currentFile = self.xbmcplayer.getPlayingFile()
except: pass
if count == 5: # try 5 times
log("Cancelling playback report...", 1)
self.logMsg("Cancelling playback report...", 1)
break
else: count += 1
@ -86,12 +84,12 @@ class Player(xbmc.Player):
xbmc.sleep(200)
itemId = window("emby_%s.itemid" % currentFile)
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
else: tryCount += 1
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.
embyitem = "emby_%s" % currentFile
@ -104,11 +102,11 @@ class Player(xbmc.Player):
customseek = window('emby_customPlaylist.seektime')
if window('emby_customPlaylist') == "true" and customseek:
# Start at, when using custom playlist (play to Kodi from webclient)
log("Seeking to: %s" % customseek, 1)
xbmcplayer.seekTime(int(customseek)/10000000.0)
self.logMsg("Seeking to: %s" % customseek, 1)
self.xbmcplayer.seekTime(int(customseek)/10000000.0)
window('emby_customPlaylist.seektime', clear=True)
seekTime = xbmcplayer.getTime()
seekTime = self.xbmcplayer.getTime()
# Get playback volume
volume_query = {
@ -191,7 +189,7 @@ class Player(xbmc.Player):
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)
if externalIndex.get(str(indexSubs)):
@ -209,15 +207,15 @@ class Player(xbmc.Player):
# Post playback to server
log("Sending POST play started: %s." % postdata, 2)
self.doUtils(url, postBody=postdata, type="POST")
self.logMsg("Sending POST play started: %s." % postdata, 2)
self.doUtils(url, postBody=postdata, action_type="POST")
# Ensure we do have a runtime
try:
runtime = int(runtime)
except ValueError:
runtime = xbmcplayer.getTotalTime()
log("Runtime is missing, Kodi runtime: %s" % runtime, 1)
runtime = self.xbmcplayer.getTotalTime()
self.logMsg("Runtime is missing, Kodi runtime: %s" % runtime, 1)
# Save data map for updates and position calls
data = {
@ -234,7 +232,7 @@ class Player(xbmc.Player):
}
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
'''if(itemType != None):
@ -253,10 +251,7 @@ class Player(xbmc.Player):
def reportPlayback(self):
log = self.logMsg
log("reportPlayback Called", 2)
xbmcplayer = self.xbmcplayer
self.logMsg("reportPlayback Called", 2)
# Get current file
currentFile = self.currentFile
@ -354,7 +349,7 @@ class Player(xbmc.Player):
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)
if externalIndex.get(str(indexSubs)):
@ -374,7 +369,7 @@ class Player(xbmc.Player):
# Report progress via websocketclient
postdata = json.dumps(postdata)
log("Report: %s" % postdata, 2)
self.logMsg("Report: %s" % postdata, 2)
self.ws.sendProgressUpdate(postdata)
def onPlayBackPaused(self):
@ -410,14 +405,13 @@ class Player(xbmc.Player):
def onPlayBackStopped(self):
log = self.logMsg
window = utils.window
# 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.seektime', clear=True)
window('emby_playbackProps', clear=True)
log("Clear playlist properties.", 1)
self.logMsg("Clear playlist properties.", 1)
self.stopAll()
def onPlayBackEnded(self):
@ -428,31 +422,28 @@ class Player(xbmc.Player):
def stopAll(self):
log = self.logMsg
lang = utils.language
settings = utils.settings
doUtils = self.doUtils
if not self.played_info:
return
log("Played_information: %s" % self.played_info, 1)
self.logMsg("Played_information: %s" % self.played_info, 1)
# Process each items
for item in self.played_info:
data = self.played_info.get(item)
if data:
log("Item path: %s" % item, 2)
log("Item data: %s" % data, 2)
self.logMsg("Item path: %s" % item, 2)
self.logMsg("Item data: %s" % data, 2)
runtime = data['runtime']
currentPosition = data['currentPosition']
itemid = data['item_id']
refresh_id = data['refresh_id']
currentFile = data['currentfile']
type = data['Type']
media_type = data['Type']
playMethod = data['playmethod']
# Prevent manually mark as watched in Kodi monitor
@ -466,15 +457,15 @@ class Player(xbmc.Player):
percentComplete = 0
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)
# Send the delete action to the server.
offerDelete = False
if type == "Episode" and settings('deleteTV') == "true":
if media_type == "Episode" and settings('deleteTV') == "true":
offerDelete = True
elif type == "Movie" and settings('deleteMovies') == "true":
elif media_type == "Movie" and settings('deleteMovies') == "true":
offerDelete = True
if settings('offerDelete') != "true":
@ -484,21 +475,21 @@ class Player(xbmc.Player):
if percentComplete >= markPlayedAt and offerDelete:
resp = xbmcgui.Dialog().yesno(lang(30091), lang(33015), autoclose=120000)
if not resp:
log("User skipped deletion.", 1)
self.logMsg("User skipped deletion.", 1)
continue
url = "{server}/emby/Items/%s?format=json" % itemid
log("Deleting request: %s" % itemid, 1)
doUtils(url, type="DELETE")
self.logMsg("Deleting request: %s" % itemid, 1)
self.doUtils(url, action_type="DELETE")
self.stopPlayback(data)
# Stop transcoding
if playMethod == "Transcode":
log("Transcoding for %s terminated." % itemid, 1)
self.logMsg("Transcoding for %s terminated." % itemid, 1)
deviceId = self.clientInfo.getDeviceId()
url = "{server}/emby/Videos/ActiveEncodings?DeviceId=%s" % deviceId
doUtils(url, type="DELETE")
self.doUtils(url, action_type="DELETE")
self.played_info.clear()
@ -517,4 +508,4 @@ class Player(xbmc.Player):
'MediaSourceId': itemId,
'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):
log = self.logMsg
window = utils.window
embyconn = utils.kodiSQL('emby')
@ -50,8 +49,8 @@ class Playlist():
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
playlist.clear()
log("---*** PLAY ALL ***---", 1)
log("Items: %s and start at: %s" % (itemids, startat), 1)
self.logMsg("---*** PLAY ALL ***---", 1)
self.logMsg("Items: %s and start at: %s" % (itemids, startat), 1)
started = False
window('emby_customplaylist', value="true")
@ -67,14 +66,14 @@ class Playlist():
mediatype = embydb_item[4]
except TypeError:
# 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)
self.addtoPlaylist_xbmc(playlist, item)
else:
# Add to playlist
self.addtoPlaylist(dbid, mediatype)
log("Adding %s to playlist." % itemid, 1)
self.logMsg("Adding %s to playlist." % itemid, 1)
if not started:
started = True
@ -85,14 +84,12 @@ class Playlist():
def modifyPlaylist(self, itemids):
log = self.logMsg
embyconn = utils.kodiSQL('emby')
embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor)
log("---*** ADD TO PLAYLIST ***---", 1)
log("Items: %s" % itemids, 1)
self.logMsg("---*** ADD TO PLAYLIST ***---", 1)
self.logMsg("Items: %s" % itemids, 1)
player = xbmc.Player()
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
@ -110,7 +107,7 @@ class Playlist():
# Add to playlist
self.addtoPlaylist(dbid, mediatype)
log("Adding %s to playlist." % itemid, 1)
self.logMsg("Adding %s to playlist." % itemid, 1)
self.verifyPlaylist()
embycursor.close()
@ -133,12 +130,10 @@ class Playlist():
else:
pl['params']['item'] = {'file': url}
result = xbmc.executeJSONRPC(json.dumps(pl))
self.logMsg(result, 2)
self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
def addtoPlaylist_xbmc(self, playlist, item):
itemid = item['Id']
playurl = playutils.PlayUtils(item).getPlayUrl()
if not playurl:
# Playurl failed
@ -169,8 +164,7 @@ class Playlist():
else:
pl['params']['item'] = {'file': url}
result = xbmc.executeJSONRPC(json.dumps(pl))
self.logMsg(result, 2)
self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
def verifyPlaylist(self):
@ -184,8 +178,7 @@ class Playlist():
'playlistid': 1
}
}
result = xbmc.executeJSONRPC(json.dumps(pl))
self.logMsg(result, 2)
self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
def removefromPlaylist(self, position):
@ -200,5 +193,4 @@ class Playlist():
'position': position
}
}
result = xbmc.executeJSONRPC(json.dumps(pl))
self.logMsg(result, 2)
self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)

View file

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

View file

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

View file

@ -81,7 +81,6 @@ class UserClient(threading.Thread):
def getUserId(self):
log = self.logMsg
window = utils.window
settings = utils.settings
@ -94,17 +93,17 @@ class UserClient(threading.Thread):
if not s_userId:
# Save access token if it's missing from settings
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)
return w_userId
# Verify the settings
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)
return s_userId
# No userId found
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):
@ -142,7 +141,6 @@ class UserClient(threading.Thread):
def getToken(self):
log = self.logMsg
window = utils.window
settings = utils.settings
@ -156,17 +154,17 @@ class UserClient(threading.Thread):
if not s_token:
# Save access token if it's missing from settings
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)
return w_token
# Verify the settings
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)
window('emby_accessToken%s' % username, value=s_token)
return s_token
else:
log("No token found.", 1)
self.logMsg("No token found.", 1)
return ""
def getSSLverify(self):
@ -198,46 +196,37 @@ class UserClient(threading.Thread):
def setUserPref(self):
doUtils = self.doUtils.downloadUrl
art = artwork.Artwork()
url = "{server}/emby/Users/{UserId}?format=json"
result = doUtils(url)
result = doUtils("{server}/emby/Users/{UserId}?format=json")
self.userSettings = result
# Set user image for skin display
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
url = "{server}/emby/System/Configuration?format=json"
result = doUtils(url)
result = doUtils("{server}/emby/System/Configuration?format=json")
utils.settings('markPlayed', value=str(result['MaxResumePct']))
def getPublicUsers(self):
server = self.getServer()
# Get public Users
url = "%s/emby/Users/Public?format=json" % server
result = self.doUtils.downloadUrl(url, authenticate=False)
result = self.doUtils.downloadUrl("%s/emby/Users/Public?format=json" % self.getServer(), authenticate=False)
if result != "":
return result
else:
# Server connection failed
return False
def hasAccess(self):
# hasAccess is verified in service.py
log = self.logMsg
window = utils.window
url = "{server}/emby/Users?format=json"
result = self.doUtils.downloadUrl(url)
result = self.doUtils.downloadUrl("{server}/emby/Users?format=json")
if result == False:
# Access is restricted, set in downloadutils.py via exception
log("Access is restricted.", 1)
self.logMsg("Access is restricted.", 1)
self.HasAccess = False
elif window('emby_online') != "true":
@ -245,7 +234,7 @@ class UserClient(threading.Thread):
pass
elif window('emby_serverStatus') == "restricted":
log("Access is granted.", 1)
self.logMsg("Access is granted.", 1)
self.HasAccess = True
window('emby_serverStatus', clear=True)
xbmcgui.Dialog().notification("Emby for Kodi", utils.language(33007))
@ -301,7 +290,6 @@ class UserClient(threading.Thread):
def authenticate(self):
log = self.logMsg
lang = utils.language
window = utils.window
settings = utils.settings
@ -316,24 +304,24 @@ class UserClient(threading.Thread):
# If there's no settings.xml
if not hasSettings:
log("No settings.xml found.", 1)
self.logMsg("No settings.xml found.", 1)
self.auth = False
return
# If no user information
elif not server or not username:
log("Missing server information.", 1)
self.logMsg("Missing server information.", 1)
self.auth = False
return
# If there's a token, load the user
elif self.getToken():
result = self.loadCurrUser()
if result == False:
if result is False:
pass
else:
log("Current user: %s" % self.currUser, 1)
log("Current userId: %s" % self.currUserId, 1)
log("Current accessToken: %s" % self.currToken, 2)
self.logMsg("Current user: %s" % self.currUser, 1)
self.logMsg("Current userId: %s" % self.currUserId, 1)
self.logMsg("Current accessToken: %s" % self.currToken, 2)
return
##### AUTHENTICATE USER #####
@ -353,7 +341,7 @@ class UserClient(threading.Thread):
option=xbmcgui.ALPHANUM_HIDE_INPUT)
# If password dialog is cancelled
if not password:
log("No password entered.", 0)
self.logMsg("No password entered.", 0)
window('emby_serverStatus', value="Stop")
self.auth = False
return
@ -367,40 +355,38 @@ class UserClient(threading.Thread):
sha1 = sha1.hexdigest()
# Authenticate username and password
url = "%s/emby/Users/AuthenticateByName?format=json" % server
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:
log("Auth response: %s" % result, 1)
self.logMsg("Auth response: %s" % result, 1)
accessToken = result['AccessToken']
except (KeyError, TypeError):
log("Failed to retrieve the api key.", 1)
self.logMsg("Failed to retrieve the api key.", 1)
accessToken = None
if accessToken is not None:
self.currUser = username
dialog.notification("Emby for Kodi",
"%s %s!" % (lang(33000), self.currUser.decode('utf-8')))
userId = result['User']['Id']
settings('accessToken', value=accessToken)
settings('userId%s' % username, value=userId)
log("User Authenticated: %s" % accessToken, 1)
settings('userId%s' % username, value=result['User']['Id'])
self.logMsg("User Authenticated: %s" % accessToken, 1)
self.loadCurrUser(authenticated=True)
window('emby_serverStatus', clear=True)
self.retry = 0
else:
log("User authentication failed.", 1)
self.logMsg("User authentication failed.", 1)
settings('accessToken', value="")
settings('userId%s' % username, value="")
dialog.ok(lang(33001), lang(33009))
# Give two attempts at entering password
if self.retry == 2:
log("Too many retries. "
self.logMsg("Too many retries. "
"You can retry by resetting attempts in the addon settings.", 1)
window('emby_serverStatus', value="Stop")
dialog.ok(lang(33001), lang(33010))
@ -410,28 +396,23 @@ class UserClient(threading.Thread):
def resetClient(self):
log = self.logMsg
log("Reset UserClient authentication.", 1)
userId = self.getUserId()
self.logMsg("Reset UserClient authentication.", 1)
if self.currToken is not None:
# In case of 401, removed saved token
utils.settings('accessToken', value="")
utils.window('emby_accessToken%s' % userId, clear=True)
utils.window('emby_accessToken%s' % self.getUserId(), clear=True)
self.currToken = None
log("User token has been removed.", 1)
self.logMsg("User token has been removed.", 1)
self.auth = True
self.currUser = None
def run(self):
log = self.logMsg
window = utils.window
monitor = xbmc.Monitor()
log("----===## Starting UserClient ##===----", 0)
self.logMsg("----===## Starting UserClient ##===----", 0)
while not monitor.abortRequested():
@ -466,8 +447,8 @@ class UserClient(threading.Thread):
# The status Stop is for when user cancelled password dialog.
if server and username and status != "Stop":
# Only if there's information found to login
log("Server found: %s" % server, 2)
log("Username found: %s" % username, 2)
self.logMsg("Server found: %s" % server, 2)
self.logMsg("Username found: %s" % username, 2)
self.auth = True
@ -480,7 +461,7 @@ class UserClient(threading.Thread):
break
self.doUtils.stopSession()
log("##===---- UserClient Stopped ----===##", 0)
self.logMsg("##===---- UserClient Stopped ----===##", 0)
def stopClient(self):
# 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):
# Get or add addon setting
addon = xbmcaddon.Addon(id='plugin.video.emby')
if value is not None:
addon.setSetting(setting, value)
xbmcaddon.Addon(id='plugin.video.metaman').setSetting(setting, value)
else:
return addon.getSetting(setting) #returns unicode object
return xbmcaddon.Addon(id='plugin.video.metaman').getSetting(setting) #returns unicode object
def language(stringid):
# Central string retrieval
addon = xbmcaddon.Addon(id='plugin.video.emby')
string = addon.getLocalizedString(stringid) #returns unicode object
string = xbmcaddon.Addon(id='plugin.video.emby').getLocalizedString(stringid) #returns unicode object
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')
elif type == "music":
elif media_type == "music":
dbPath = getKodiMusicDBPath()
elif type == "texture":
elif media_type == "texture":
dbPath = xbmc.translatePath("special://database/Textures13.db").decode('utf-8')
else:
dbPath = getKodiVideoDBPath()
@ -91,7 +88,6 @@ def kodiSQL(type="video"):
def getKodiVideoDBPath():
kodibuild = xbmc.getInfoLabel('System.BuildVersion')[:2]
dbVersion = {
"13": 78, # Gotham
@ -102,12 +98,11 @@ def getKodiVideoDBPath():
dbPath = xbmc.translatePath(
"special://database/MyVideos%s.db"
% dbVersion.get(kodibuild, "")).decode('utf-8')
% dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8')
return dbPath
def getKodiMusicDBPath():
kodibuild = xbmc.getInfoLabel('System.BuildVersion')[:2]
dbVersion = {
"13": 46, # Gotham
@ -118,7 +113,7 @@ def getKodiMusicDBPath():
dbPath = xbmc.translatePath(
"special://database/MyMusic%s.db"
% dbVersion.get(kodibuild, "")).decode('utf-8')
% dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8')
return dbPath
def getScreensaver():
@ -133,11 +128,7 @@ def getScreensaver():
'setting': "screensaver.mode"
}
}
result = xbmc.executeJSONRPC(json.dumps(query))
result = json.loads(result)
screensaver = result['result']['value']
return screensaver
return json.loads(xbmc.executeJSONRPC(json.dumps(query)))['result']['value']
def setScreensaver(value):
# Toggle the screensaver
@ -152,15 +143,13 @@ def setScreensaver(value):
'value': value
}
}
result = xbmc.executeJSONRPC(json.dumps(query))
logMsg("EMBY", "Toggling screensaver: %s %s" % (value, result), 1)
logMsg("EMBY", "Toggling screensaver: %s %s" % (value, xbmc.executeJSONRPC(json.dumps(query))), 1)
def reset():
dialog = xbmcgui.Dialog()
resp = dialog.yesno("Warning", "Are you sure you want to reset your local Kodi database?")
if resp == 0:
if dialog.yesno("Warning", "Are you sure you want to reset your local Kodi database?") == 0:
return
# first stop any db sync
@ -222,7 +211,7 @@ def reset():
cursor.close()
# Offer to wipe cached thumbnails
resp = dialog.yesno("Warning", "Removed all cached artwork?")
resp = dialog.yesno("Warning", "Remove all cached artwork?")
if resp:
logMsg("EMBY", "Resetting all cached artwork.", 0)
# Remove all existing textures first
@ -418,9 +407,7 @@ def passwordsXML():
elif option == 1:
# User selected remove
iterator = root.getiterator('passwords')
for paths in iterator:
for paths in root.getiterator('passwords'):
for path in paths:
if path.find('.//from').text == "smb://%s/" % credentials:
paths.remove(path)

View file

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

View file

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

View file

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