Merge remote-tracking branch 'MediaBrowser/master' into develop
This commit is contained in:
commit
450437b812
18 changed files with 1428 additions and 1622 deletions
|
@ -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")
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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()'''
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue