Merge remote-tracking branch 'MediaBrowser/master' into develop

This commit is contained in:
tomkat83 2016-04-26 13:53:19 +02:00
commit 450437b812
18 changed files with 1428 additions and 1622 deletions

View File

@ -147,7 +147,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(
@ -156,8 +156,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

@ -328,7 +328,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

@ -28,7 +28,7 @@ class Artwork():
xbmc_port = None
xbmc_username = None
xbmc_password = None
imageCacheThreads = []
imageCacheLimitThreads = 0
@ -36,9 +36,9 @@ 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:
self.setKodiWebServerDetails()
@ -48,11 +48,11 @@ class Artwork():
def double_urlencode(self, text):
text = self.single_urlencode(text)
text = self.single_urlencode(text)
return text
def single_urlencode(self, text):
text = urllib.urlencode({'blahblahblah':text.encode("utf-8")}) #urlencode needs a utf- string
text = text[13:]
@ -74,9 +74,9 @@ class Artwork():
result = json.loads(result)
try:
xbmc_webserver_enabled = result['result']['value']
except KeyError, TypeError:
except (KeyError, TypeError):
xbmc_webserver_enabled = False
if not xbmc_webserver_enabled:
# Enable the webserver, it is disabled
web_port = {
@ -159,7 +159,7 @@ class Artwork():
self.xbmc_password = result['result']['value']
except TypeError:
pass
def FullTextureCacheSync(self):
# This method will sync all Kodi artwork to textures13.db
# and cache them locally. This takes diskspace!
@ -169,12 +169,12 @@ class Artwork():
if not xbmcgui.Dialog().yesno(
"Image Texture Cache", string(39250).encode('utf-8')):
return
self.logMsg("Doing Image Cache Sync", 1)
dialog = xbmcgui.DialogProgress()
dialog.create("Emby for Kodi", "Image Cache Sync")
# ask to rest all existing or not
if xbmcgui.Dialog().yesno(
"Image Texture Cache", string(39251).encode('utf-8'), ""):
@ -190,7 +190,7 @@ class Artwork():
xbmcvfs.delete(os.path.join(path+dir.decode('utf-8'),file.decode('utf-8')))
else:
xbmcvfs.delete(os.path.join(path.encode('utf-8')+dir,file))
# remove all existing data from texture DB
textureconnection = utils.kodiSQL('texture')
texturecursor = textureconnection.cursor()
@ -209,8 +209,8 @@ class Artwork():
cursor.execute("SELECT url FROM art WHERE media_type != 'actor'") # dont include actors
result = cursor.fetchall()
total = len(result)
count = 1
percentage = 0
count = 1
percentage = 0
self.logMsg("Image cache sync about to process " + str(total) + " images", 1)
for url in result:
if dialog.iscanceled():
@ -221,26 +221,26 @@ class Artwork():
self.CacheTexture(url[0])
count += 1
cursor.close()
# Cache all entries in music DB
connection = utils.kodiSQL('music')
cursor = connection.cursor()
cursor.execute("SELECT url FROM art")
result = cursor.fetchall()
total = len(result)
count = 1
count = 1
percentage = 0
self.logMsg("Image cache sync about to process " + str(total) + " images", 1)
for url in result:
if dialog.iscanceled():
break
break
percentage = int((float(count) / float(total))*100)
textMessage = str(count) + " of " + str(total)
dialog.update(percentage, "Updating Image Cache: " + textMessage)
self.CacheTexture(url[0])
count += 1
cursor.close()
dialog.update(100, "Waiting for all threads to exit: " + str(len(self.imageCacheThreads)))
self.logMsg("Waiting for all threads to exit", 1)
while len(self.imageCacheThreads) > 0:
@ -250,16 +250,16 @@ class Artwork():
dialog.update(100, "Waiting for all threads to exit: " + str(len(self.imageCacheThreads)))
self.logMsg("Waiting for all threads to exit: " + str(len(self.imageCacheThreads)), 1)
xbmc.sleep(500)
dialog.close()
def addWorkerImageCacheThread(self, urlToAdd):
while(True):
# removed finished
for thread in self.imageCacheThreads:
if thread.isFinished:
self.imageCacheThreads.remove(thread)
self.imageCacheThreads.remove(thread)
# add a new thread or wait and retry if we hit our limit
if(len(self.imageCacheThreads) < self.imageCacheLimitThreads):
@ -273,14 +273,14 @@ class Artwork():
else:
self.logMsg("Waiting for empty queue spot: " + str(len(self.imageCacheThreads)), 2)
xbmc.sleep(50)
def CacheTexture(self, url):
# Cache a single image url to the texture cache
if url and self.enableTextureCache:
if(self.imageCacheLimitThreads == 0 or self.imageCacheLimitThreads == None):
#Add image to texture cache by simply calling it at the http endpoint
url = self.double_urlencode(url)
try: # Extreme short timeouts so we will have a exception.
response = requests.head(
@ -291,7 +291,7 @@ class Artwork():
timeout=(0.01, 0.01))
# We don't need the result
except: pass
else:
self.addWorkerImageCacheThread(url)
@ -349,13 +349,13 @@ class Artwork():
mediaType=mediaType,
imageType="%s%s" % ("fanart", index),
cursor=cursor)
if backdropsNumber > 1:
try: # Will only fail on the first try, str to int.
index += 1
except TypeError:
index = 1
elif art == "Primary":
# Primary art is processed as thumb and poster for Kodi.
for artType in kodiart[art]:
@ -365,7 +365,7 @@ class Artwork():
mediaType=mediaType,
imageType=artType,
cursor=cursor)
elif kodiart.get(art):
# Process the rest artwork type that Kodi can use
self.addOrUpdateArt(
@ -391,9 +391,11 @@ class Artwork():
cursor.execute(query, (kodiId, mediaType, imageType,))
try: # Update the artwork
url = cursor.fetchone()[0]
except TypeError: # Add the artwork
cacheimage = True
self.logMsg("Adding Art Link for kodiId: %s (%s)" % (kodiId, imageUrl), 2)
query = (
'''
INSERT INTO art(media_id, media_type, type, url)
@ -402,17 +404,21 @@ class Artwork():
'''
)
cursor.execute(query, (kodiId, mediaType, imageType, imageUrl))
else: # Only cache artwork if it changed
if url != imageUrl:
cacheimage = True
# Only for the main backdrop, poster
if (utils.window('emby_initialScan') != "true" and
imageType in ("fanart", "poster")):
# Delete current entry before updating with the new one
self.deleteCachedArtwork(url)
self.logMsg(
"Updating Art url for %s kodiId: %s (%s) -> (%s)"
% (imageType, kodiId, url, imageUrl), 1)
query = ' '.join((
"UPDATE art",
@ -422,7 +428,7 @@ class Artwork():
"AND type = ?"
))
cursor.execute(query, (imageUrl, kodiId, mediaType, imageType))
# Cache fanart and poster in Kodi texture cache
if cacheimage and imageType in ("fanart", "poster", "thumb"):
self.CacheTexture(imageUrl)
@ -453,24 +459,24 @@ class Artwork():
try:
cursor.execute("SELECT cachedurl FROM texture WHERE url = ?", (url,))
cachedurl = cursor.fetchone()[0]
except TypeError:
self.logMsg("Could not find cached url.", 1)
except OperationalError:
self.logMsg("Database is locked. Skip deletion process.", 1)
else: # Delete thumbnail as well as the entry
thumbnails = xbmc.translatePath("special://thumbnails/%s" % cachedurl).decode('utf-8')
self.logMsg("Deleting cached thumbnail: %s" % thumbnails, 1)
xbmcvfs.delete(thumbnails)
try:
cursor.execute("DELETE FROM texture WHERE url = ?", (url,))
connection.commit()
except OperationalError:
self.logMsg("Issue deleting url from cache. Skipping.", 2)
finally:
cursor.close()
@ -487,7 +493,7 @@ class Artwork():
"%s/emby/Items/%s/Images/Primary?"
"MaxWidth=400&MaxHeight=400&Index=0&Tag=%s"
% (self.server, personId, tag))
person['imageurl'] = image
return people
@ -501,8 +507,6 @@ class Artwork():
def getAllArtwork(self, item, parentInfo=False):
server = self.server
itemid = item['Id']
artworks = item['ImageTags']
backdrops = item.get('BackdropImageTags',[])
@ -527,13 +531,13 @@ def getAllArtwork(self, item, parentInfo=False):
'Disc': "",
'Backdrop': []
}
# Process backdrops
for index, tag in enumerate(backdrops):
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
@ -544,15 +548,15 @@ def getAllArtwork(self, item, parentInfo=False):
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
if parentInfo:
# Process parent backdrops
if not allartworks['Backdrop']:
parentId = item.get('ParentBackdropItemId')
if parentId:
# If there is a parentId, go through the parent backdrop list
@ -562,7 +566,7 @@ def getAllArtwork(self, item, parentInfo=False):
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
@ -570,15 +574,15 @@ def getAllArtwork(self, item, parentInfo=False):
for parentart in parentartwork:
if not allartworks[parentart]:
parentId = item.get('Parent%sItemId' % parentart)
if parentId:
parentTag = item['Parent%sImageTag' % parentart]
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
@ -587,12 +591,12 @@ def getAllArtwork(self, item, parentInfo=False):
parentId = item.get('AlbumId')
if parentId and item.get('AlbumPrimaryImageTag'):
parentTag = item['AlbumPrimaryImageTag']
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
return allartworks

View File

@ -21,7 +21,7 @@ requests.packages.urllib3.disable_warnings(InsecurePlatformWarning)
class ConnectUtils():
# Borg - multiple instances, shared state
_shared_state = {}
clientInfo = clientinfo.ClientInfo()
@ -60,8 +60,6 @@ class ConnectUtils():
def startSession(self):
log = self.logMsg
self.deviceId = self.clientInfo.getDeviceId()
# User is identified from this point
@ -75,8 +73,8 @@ 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()
self.c.headers = header
@ -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
@ -105,9 +102,9 @@ class ConnectUtils():
'X-Application': "Kodi/%s" % version,
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': "application/json"
}
}
self.logMsg("Header: %s" % header, 1)
else:
token = self.token
# Attached to the requests session
@ -117,18 +114,17 @@ class ConnectUtils():
'Accept': "application/json",
'X-Application': "Kodi/%s" % version,
'X-Connect-UserToken': token
}
}
self.logMsg("Header: %s" % header, 1)
return header
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
@ -137,7 +133,7 @@ class ConnectUtils():
try:
# If connect user is authenticated
if authenticate:
try:
try:
c = self.c
# Replace for the real values
url = url.replace("{server}", self.server)
@ -167,7 +163,7 @@ class ConnectUtils():
verifyssl = self.sslclient
except AttributeError:
pass
# Prepare request
if rtype == "GET":
r = requests.get(url,
@ -195,7 +191,7 @@ class ConnectUtils():
verifyssl = self.sslclient
except AttributeError:
pass
# Prepare request
if rtype == "GET":
r = requests.get(url,
@ -213,28 +209,28 @@ 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:
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()
##### EXCEPTIONS #####
except requests.exceptions.ConnectionError as e:
@ -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

@ -34,7 +34,6 @@ class Embydb_Functions():
def getViews(self):
embycursor = self.embycursor
views = []
query = ' '.join((
@ -42,8 +41,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])
return views
@ -68,7 +67,6 @@ class Embydb_Functions():
def getView_byId(self, viewid):
embycursor = self.embycursor
query = ' '.join((
@ -76,13 +74,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((
@ -91,8 +89,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({
@ -105,17 +103,16 @@ 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
@ -190,8 +187,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",
@ -199,40 +194,32 @@ 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 getPlexId(self, kodiid, mediatype):
"""
@ -253,8 +240,6 @@ class Embydb_Functions():
def getItem_byKodiId(self, kodiid, mediatype):
embycursor = self.embycursor
query = ' '.join((
"SELECT emby_id, parent_id",
@ -262,15 +247,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",
@ -278,15 +259,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",
@ -294,39 +271,32 @@ 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

@ -328,12 +328,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)
@ -431,7 +431,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():
@ -486,7 +486,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,
@ -519,7 +519,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,
@ -759,22 +759,22 @@ 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()
doUtils = downloadutils.DownloadUtils()
#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
@ -783,33 +783,35 @@ def BrowseContent(viewname, type="", folderid=""):
for view in views:
if view.get("name") == viewname.decode('utf-8'):
folderid = view.get("id")
break
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')))
if viewname is not None:
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)
@ -819,14 +821,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

@ -309,10 +309,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)
@ -333,7 +332,6 @@ class Movies(Items):
# Process single movie
kodicursor = self.kodicursor
emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork
API = PlexAPI.API(item)
@ -517,23 +515,23 @@ class Movies(Items):
kodi_db.addCountries(movieid, countries, "movie")
# Process cast
people = API.getPeopleList()
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
allartworks = API.getAllArtwork()
artwork.addArtwork(allartworks, 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, Plex collection tags
tags = [viewtag]
tags.extend(collections)
if userdata['Favorite']:
tags.append("Favorite movies")
kodi_db.addTags(movieid, tags, "movie")
self.kodi_db.addTags(movieid, tags, "movie")
# Process playstates
kodi_db.addPlaystate(fileid, resume, runtime, playcount, dateplayed)
@ -603,7 +601,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)
@ -794,32 +791,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
@ -841,9 +837,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']
@ -851,7 +847,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):
@ -878,8 +874,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]
@ -959,7 +954,6 @@ class TVShows(Items):
# Process single tvshow
kodicursor = self.kodicursor
emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork
API = PlexAPI.API(item)
@ -1079,7 +1073,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 = (
@ -1112,18 +1106,18 @@ class TVShows(Items):
# Process cast
people = API.getPeopleList()
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
allartworks = API.getAllArtwork()
artwork.addArtwork(allartworks, showid, "tvshow", kodicursor)
# Process studios
kodi_db.addStudios(showid, studios, "tvshow")
self.kodi_db.addStudios(showid, studios, "tvshow")
# Process tags: view, PMS collection tags
tags = [viewtag]
tags.extend(collections)
kodi_db.addTags(showid, tags, "tvshow")
self.kodi_db.addTags(showid, tags, "tvshow")
if force_episodes:
# We needed to recreate the show entry. Re-add episodes now.
@ -1154,7 +1148,6 @@ class TVShows(Items):
return
kodicursor = self.kodicursor
emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork
seasonnum = API.getIndex()
# Get parent tv show Plex id
@ -1210,10 +1203,8 @@ class TVShows(Items):
viewtag and viewid are irrelevant!
"""
# Process single episode
kodiversion = self.kodiversion
kodicursor = self.kodicursor
emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork
API = PlexAPI.API(item)
@ -1310,7 +1301,7 @@ class TVShows(Items):
# self.logMsg("Skipping: %s. Unable to add series: %s." % (itemid, seriesId), -1)
self.logMsg("Parent tvshow now found, skip item", 2)
return False
seasonid = kodi_db.addSeason(showid, season)
seasonid = self.kodi_db.addSeason(showid, season)
# GET THE FILE AND PATH #####
doIndirect = not self.directpath
@ -1368,7 +1359,7 @@ class TVShows(Items):
self.logMsg("UPDATE episode itemid: %s" % (itemid), 1)
# Update the movie entry
if kodiversion in (16, 17):
if self.kodiversion in (16, 17):
# Kodi Jarvis, Krypton
query = ' '.join((
@ -1400,10 +1391,9 @@ class TVShows(Items):
##### OR ADD THE EPISODE #####
else:
self.logMsg("ADD episode itemid: %s" % (itemid), 1)
self.logMsg("ADD episode itemid: %s - Title: %s" % (itemid, title), 1)
# Create the episode entry
if kodiversion in (16, 17):
if self.kodiversion in (16, 17):
# Kodi Jarvis, Krypton
query = (
'''
@ -1454,7 +1444,7 @@ class TVShows(Items):
kodicursor.execute(query, (pathid, filename, dateadded, fileid))
# Process cast
people = API.getPeopleList()
kodi_db.addPeople(episodeid, people, "episode")
self.kodi_db.addPeople(episodeid, people, "episode")
# Process artwork
# Wide "screenshot" of particular episode
poster = item.attrib.get('thumb')
@ -1473,13 +1463,13 @@ class TVShows(Items):
# Process stream details
streams = API.getMediaStreams()
kodi_db.addStreams(fileid, streams, runtime)
self.kodi_db.addStreams(fileid, streams, runtime)
# Process playstates
kodi_db.addPlaystate(fileid, resume, runtime, playcount, dateplayed)
self.kodi_db.addPlaystate(fileid, resume, runtime, 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.plexkodiconnect.tvshows/")
tempfileid = kodi_db.addFile(filename, temppathid)
temppathid = self.kodi_db.getPath("plugin://plugin.video.plexkodiconnect.tvshows/")
tempfileid = self.kodi_db.addFile(filename, temppathid)
query = ' '.join((
"UPDATE files",
@ -1487,7 +1477,7 @@ class TVShows(Items):
"WHERE idFile = ?"
))
kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
kodi_db.addPlaystate(tempfileid, resume, runtime, playcount, dateplayed)
self.kodi_db.addPlaystate(tempfileid, resume, runtime, playcount, dateplayed)
self.kodiconn.commit()
self.embyconn.commit()
@ -1600,27 +1590,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)
@ -1656,10 +1642,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
@ -1672,10 +1657,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
@ -1688,14 +1672,13 @@ 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, viewtag=None, viewid=None, artisttype="MusicArtist"):
try:
@ -1715,7 +1698,6 @@ class Music(Items):
artisttype="MusicArtist"):
kodicursor = self.kodicursor
emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork
API = PlexAPI.API(item)
@ -1764,7 +1746,7 @@ class Music(Items):
# 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)
@ -1811,10 +1793,8 @@ class Music(Items):
return
def run_add_updateAlbum(self, item, viewtag=None, viewid=None):
kodiversion = self.kodiversion
kodicursor = self.kodicursor
emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork
API = PlexAPI.API(item)
@ -1875,13 +1855,13 @@ class Music(Items):
# 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((
@ -1894,7 +1874,7 @@ class Music(Items):
kodicursor.execute(query, (artistname, year, genre, bio, thumb,
rating, lastScraped, "album", studio,
albumid))
elif kodiversion == 16:
elif self.kodiversion == 16:
# Kodi Jarvis
query = ' '.join((
@ -1907,7 +1887,7 @@ class Music(Items):
kodicursor.execute(query, (artistname, year, genre, bio, thumb,
rating, lastScraped, "album", studio,
albumid))
elif kodiversion == 15:
elif self.kodiversion == 15:
# Kodi Isengard
query = ' '.join((
@ -1998,7 +1978,7 @@ class Music(Items):
# Update emby reference with parentid
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)
self.embyconn.commit()
@ -2020,11 +2000,9 @@ class Music(Items):
def run_add_updateSong(self, item, viewtag=None, viewid=None):
# 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 = PlexAPI.API(item)
@ -2136,7 +2114,7 @@ class Music(Items):
self.logMsg("ADD song itemid: %s - Title: %s" % (itemid, title), 1)
# Add path
pathid = kodi_db.addPath(path, strHash="123")
pathid = self.kodi_db.addPath(path, strHash="123")
try:
# Get the album
@ -2148,7 +2126,7 @@ class Music(Items):
album_name = item.get('parentTitle')
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.
@ -2173,7 +2151,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 = (
'''
@ -2183,7 +2161,7 @@ class Music(Items):
'''
)
kodicursor.execute(query, (albumid, genre, year, "single"))
elif kodiversion == 15:
elif self.kodiversion == 15:
# Kodi Isengard
query = (
'''
@ -2316,11 +2294,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))
@ -2330,7 +2308,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 = API.getAllArtwork(parentInfo=True)
@ -2372,10 +2350,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]
@ -2431,23 +2408,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,))

File diff suppressed because it is too large Load Diff

View File

@ -82,13 +82,13 @@ 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:
# Send notification to the server.
with embydb.GetEmbyDB() as emby_db:
emby_dbitem = emby_db.getItem_byKodiId(kodiid, type)
emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
try:
itemid = emby_dbitem[0]
except TypeError:
@ -137,7 +137,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

@ -193,6 +193,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

@ -44,7 +44,6 @@ class PlaybackUtils():
def play(self, itemid, dbid=None):
log = self.logMsg
window = utils.window
settings = utils.settings
@ -56,7 +55,7 @@ class PlaybackUtils():
listitem = xbmcgui.ListItem()
playutils = putils.PlayUtils(item[0])
log("Play called.", 1)
self.logMsg("Play called.", 1)
playurl = playutils.getPlayUrl()
if not playurl:
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
@ -101,9 +100,9 @@ class PlaybackUtils():
introsPlaylist = False
dummyPlaylist = False
log("Playlist start position: %s" % startPos, 1)
log("Playlist plugin position: %s" % self.currentPosition, 1)
log("Playlist size: %s" % sizePlaylist, 1)
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 ################
@ -114,11 +113,11 @@ class PlaybackUtils():
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
@ -181,13 +180,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()
@ -206,18 +205,18 @@ 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)
API.CreateListItemFromPlexItem(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 AddTrailers(self, xml):

View File

@ -51,15 +51,13 @@ class Player(xbmc.Player):
"""
Window values need to have been set in Kodimonitor.py
"""
log = self.logMsg
window = utils.window
# Will be called when xbmc starts playing a file
xbmcplayer = self.xbmcplayer
self.stopAll()
# Get current file (in utf-8!)
try:
currentFile = xbmcplayer.getPlayingFile()
currentFile = self.xbmcplayer.getPlayingFile()
xbmc.sleep(300)
except:
currentFile = ""
@ -67,11 +65,11 @@ class Player(xbmc.Player):
while not currentFile:
xbmc.sleep(100)
try:
currentFile = xbmcplayer.getPlayingFile()
currentFile = self.xbmcplayer.getPlayingFile()
except:
pass
if count == 20:
log("Cancelling playback report...", 1)
self.logMsg("Cancelling playback report...", 1)
break
else:
count += 1
@ -220,6 +218,8 @@ class Player(xbmc.Player):
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)
playQueueVersion = window('playQueueVersion')
playQueueID = window('playQueueID')
@ -263,7 +263,7 @@ class Player(xbmc.Player):
if not self.doNotify:
return
log = self.logMsg
self.logMsg("reportPlayback Called", 2)
log("reportPlayback Called", 2)
@ -382,7 +382,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)):
@ -404,7 +404,7 @@ class Player(xbmc.Player):
# postdata = json.dumps(postdata)
# self.ws.sendProgressUpdate(postdata)
self.doUtils(
"{server}/:/timeline?" + urlencode(postdata), type="GET")
"{server}/:/timeline?" + urlencode(postdata), action_type="GET")
def onPlayBackPaused(self):
@ -440,7 +440,6 @@ class Player(xbmc.Player):
def onPlayBackStopped(self):
# Will be called when user stops xbmc playing a file
log = self.logMsg
window = utils.window
log("ONPLAYBACK_STOPPED", 1)
@ -459,31 +458,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
@ -497,15 +493,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":
@ -520,7 +516,7 @@ class Player(xbmc.Player):
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
@ -567,4 +563,4 @@ class Player(xbmc.Player):
'duration': int(duration)
}
url = url + urlencode(args)
self.doUtils(url, type="GET")
self.doUtils(url, action_type="GET")

View File

@ -27,7 +27,6 @@ class Playlist():
self.emby = embyserver.Read_EmbyServer()
def playAll(self, itemids, startat):
log = self.logMsg
window = utils.window
embyconn = utils.kodiSQL('emby')
@ -38,8 +37,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")
@ -76,14 +75,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)
@ -101,7 +98,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()
@ -124,8 +121,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 addtoPlaylist_xbmc(self, playlist, item):
path = "plugin://plugin.video.plexkodiconnect.movies/"
@ -160,8 +156,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):
@ -176,8 +171,7 @@ class Playlist():
'properties': ['title', 'file']
}
}
result = xbmc.executeJSONRPC(json.dumps(pl))
self.logMsg(result, 2)
self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
def removefromPlaylist(self, position):
@ -192,5 +186,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

@ -56,7 +56,7 @@ class PlayUtils():
utils.window('emby_%s.playmethod' % playurl, "DirectStream")
elif self.isTranscoding():
log("File is transcoding.", 1)
self.logMsg("File is transcoding.", 1)
quality = {
'maxVideoBitrate': self.getBitrate(),
'videoResolution': self.getResolution(),
@ -73,16 +73,14 @@ 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
@ -117,20 +115,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
@ -146,26 +140,24 @@ 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 h265enabled(self):
@ -197,6 +189,8 @@ class PlayUtils():
if utils.settings('playType') == "2":
# User forcing to play via HTTP
self.logMsg("User chose to transcode", 1)
self.logMsg("Resolution is: %sP, transcode for resolution: %sP+"
canDirectStream = self.item['MediaSources'][0]['SupportsDirectStream']
return False
if self.h265enabled():
return False
@ -244,26 +238,19 @@ class PlayUtils():
return True
def isTranscoding(self):
# I hope Plex transcodes everything
return True
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"

View File

@ -31,8 +31,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}/emby/Users/{UserId}/Items/%s?format=json" % itemid)
if result:
item = result
@ -45,13 +44,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'])
@ -64,7 +62,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),
@ -75,10 +72,10 @@ class Read_EmbyServer():
"Metascore,AirTime,DateCreated,MediaStreams,People,Overview,"
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers,"
"MediaSources"
"MediaSources,VoteCount"
)
}
result = self.doUtils(url, parameters=params)
result = self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
if result:
items.extend(result['Items'])
@ -87,13 +84,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']
@ -120,8 +114,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,
@ -140,11 +132,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,
@ -154,11 +144,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 = {
@ -170,13 +158,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': [],
@ -195,13 +180,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
@ -234,36 +219,36 @@ class Read_EmbyServer():
"Metascore,AirTime,DateCreated,MediaStreams,People,Overview,"
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers,"
"MediaSources"
"MediaSources,VoteCount"
)
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
@ -291,12 +276,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()
@ -305,7 +289,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:
@ -313,11 +297,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
@ -328,20 +309,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
@ -349,9 +330,9 @@ class Read_EmbyServer():
views.append({
'name': name,
'name': item['Name'],
'type': itemtype,
'id': itemId
'id': item['Id']
})
return views
@ -359,8 +340,6 @@ class Read_EmbyServer():
def verifyView(self, parentid, itemid):
belongs = False
url = "{server}/emby/Users/{UserId}/Items?format=json"
params = {
'ParentId': parentid,
@ -370,7 +349,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:
@ -383,40 +362,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):
@ -426,13 +388,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
@ -440,25 +401,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': [],
@ -472,7 +427,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
@ -502,7 +457,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
@ -512,28 +467,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):
@ -543,8 +487,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
@ -566,25 +509,21 @@ 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")
else:
self.logMsg("Error processing user rating.", 1)
self.logMsg("Update user rating to emby for itemid: %s "
"| like: %s | favourite: %s | deletelike: %s"
% (itemid, like, favourite, deletelike), 1)
% (itemid, like, favourite, deletelike), 1)

View File

@ -299,7 +299,7 @@ def window(property, value=None, clear=False, windowid=10000):
Property needs to be string; value may be string or unicode
"""
WINDOW = xbmcgui.Window(windowid)
#setproperty accepts both string and unicode but utf-8 strings are adviced by kodi devs because some unicode can give issues
'''if isinstance(property, unicode):
property = property.encode("utf-8")
@ -334,23 +334,22 @@ def language(stringid):
string = addon.getLocalizedString(stringid) #returns unicode object
return string
def kodiSQL(type="video"):
if type == "emby":
def kodiSQL(media_type="video"):
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()
connection = sqlite3.connect(dbPath)
return connection
def getKodiVideoDBPath():
kodibuild = xbmc.getInfoLabel('System.BuildVersion')[:2]
dbVersion = {
"13": 78, # Gotham
@ -358,16 +357,16 @@ def getKodiVideoDBPath():
"15": 93, # Isengard
"16": 99, # Jarvis
"17":104 # Krypton
"17": 104 # Krypton
}
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
@ -379,7 +378,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():
@ -394,11 +393,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
@ -413,15 +408,13 @@ def setScreensaver(value):
'value': value
}
}
result = xbmc.executeJSONRPC(json.dumps(query))
logMsg("PLEX", "Toggling screensaver: %s %s" % (value, result), 1)
logMsg("PLEX", "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
@ -483,7 +476,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
@ -497,7 +490,7 @@ def reset():
xbmcvfs.delete(os.path.join(path+dir.decode('utf-8'),file.decode('utf-8')))
else:
xbmcvfs.delete(os.path.join(path.encode('utf-8')+dir,file))
# remove all existing data from texture DB
connection = kodiSQL('texture')
cursor = connection.cursor()
@ -509,8 +502,8 @@ def reset():
cursor.execute("DELETE FROM " + tableName)
connection.commit()
cursor.close()
# reset the install run flag
# reset the install run flag
settings('SyncInstallRunDone', value="false")
# Remove emby info
@ -532,7 +525,7 @@ def profiling(sortby="cumulative"):
# Will print results to Kodi log
def decorator(func):
def wrapper(*args, **kwargs):
pr = cProfile.Profile()
pr.enable()
@ -576,7 +569,7 @@ def normalize_nodes(text):
# with dots at the end
text = text.rstrip('.')
text = unicodedata.normalize('NFKD', unicode(text, 'utf-8')).encode('ascii', 'ignore')
return text
def normalize_string(text):
@ -717,7 +710,7 @@ def sourcesXML():
root = etree.Element('sources')
else:
root = xmlparse.getroot()
video = root.find('video')
if video is None:
@ -729,7 +722,7 @@ def sourcesXML():
for source in root.findall('.//path'):
if source.text == "smb://":
count -= 1
if count == 0:
# sources already set
break
@ -775,9 +768,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)
@ -788,7 +779,7 @@ def passwordsXML():
break
else:
logMsg("EMBY", "Failed to find saved server: %s in passwords.xml" % credentials, 1)
settings('networkCreds', value="")
xbmcgui.Dialog().notification(
heading='PlexKodiConnect',
@ -842,7 +833,7 @@ def passwordsXML():
# Force Kodi to see the credentials without restarting
xbmcvfs.exists(topath)
# Add credentials
# Add credentials
settings('networkCreds', value="%s" % server)
logMsg("PLEX", "Added server: %s to passwords.xml" % server, 1)
# Prettify and write to file
@ -850,7 +841,7 @@ def passwordsXML():
indent(root)
except: pass
etree.ElementTree(root).write(xmlpath)
# dialog.notification(
# heading="PlexKodiConnect",
# message="Added to passwords.xml",
@ -881,7 +872,7 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
if delete:
xbmcvfs.delete(xsppath.encode('utf-8'))
logMsg("PLEX", "Successfully removed playlist: %s." % tagname, 1)
return
# Using write process since there's no guarantee the xml declaration works with etree
@ -949,4 +940,4 @@ def try_decode(text, encoding="utf-8"):
try:
return text.decode(encoding,"ignore")
except:
return text
return text

View File

@ -54,7 +54,6 @@ class VideoNodes(object):
mediatype = mediatypes[mediatype]
window = utils.window
kodiversion = self.kodiversion
if viewtype == "mixed":
dirname = "%s-%s" % (viewid, mediatype)
@ -231,7 +230,7 @@ class VideoNodes(object):
# Custom query
path = ("plugin://plugin.video.plexkodiconnect/?id=%s&mode=recentepisodes&type=%s&tagname=%s&limit=%s"
% (viewid, mediatype, tagname, limit))
elif kodiversion == 14 and nodetype == "inprogressepisodes":
elif self.kodiversion == 14 and nodetype == "inprogressepisodes":
# Custom query
path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=inprogressepisodes&limit=%s" % (tagname, limit)
elif nodetype == 'ondeck':

File diff suppressed because it is too large Load Diff