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

This commit is contained in:
tomkat83 2016-03-01 10:10:11 +01:00
commit 4704d8e983
16 changed files with 195 additions and 90 deletions

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.plexkodiconnect" <addon id="plugin.video.plexkodiconnect"
name="PlexKodiConnect" name="PlexKodiConnect"
version="2.2.1" version="2.2.4"
provider-name="croneter"> provider-name="croneter">
<requires> <requires>
<import addon="xbmc.python" version="2.1.0"/> <import addon="xbmc.python" version="2.1.0"/>

View file

@ -1,3 +1,14 @@
version 2.2.4
- Fix external subs being appended to direct play (via add-on playback)
- First attempt at keeping Kodi awake during the initial sync
version 2.2.3
- Fix resume
version 2.2.2
- Fix dialog crash in the manual sync
- Fix view duplicate views appearing via launching the emby add-on, when grouping views in emby
version 2.2.1 version 2.2.1
- Fix artist/album link for music videos - Fix artist/album link for music videos
- Fix progress dialog when the manual sync runs at start up - Fix progress dialog when the manual sync runs at start up

View file

@ -65,7 +65,8 @@ class Main:
'recentepisodes': entrypoint.getRecentEpisodes, 'recentepisodes': entrypoint.getRecentEpisodes,
'refreshplaylist': entrypoint.refreshPlaylist, 'refreshplaylist': entrypoint.refreshPlaylist,
'companion': entrypoint.plexCompanion, 'companion': entrypoint.plexCompanion,
'switchuser': entrypoint.switchPlexUser 'switchuser': entrypoint.switchPlexUser,
'deviceid': entrypoint.resetDeviceId
} }
if "extrafanart" in sys.argv[0]: if "extrafanart" in sys.argv[0]:

View file

@ -297,6 +297,7 @@
<string id="30532">Duration of the video library pop up (in seconds)</string> <string id="30532">Duration of the video library pop up (in seconds)</string>
<string id="30533">Duration of the music library pop up (in seconds)</string> <string id="30533">Duration of the music library pop up (in seconds)</string>
<string id="30534">Server messages</string> <string id="30534">Server messages</string>
<string id="30535">Generate a new device Id</string>
<!-- service add-on --> <!-- service add-on -->
<string id="33000">Welcome</string> <string id="33000">Welcome</string>
@ -331,5 +332,7 @@
<string id="33029">Comparing tv shows from:</string> <string id="33029">Comparing tv shows from:</string>
<string id="33030">Comparing episodes from:</string> <string id="33030">Comparing episodes from:</string>
<string id="33031">Comparing:</string> <string id="33031">Comparing:</string>
<string id="33032">Failed to generate a new device Id. See your logs for more information.</string>
<string id="33033">A new device Id has been generated. Kodi will now restart.</string>
</strings> </strings>

View file

@ -6,6 +6,7 @@ import json
import requests import requests
import os import os
import urllib import urllib
from sqlite3 import OperationalError
import xbmc import xbmc
import xbmcgui import xbmcgui
@ -442,13 +443,16 @@ class Artwork():
connection = utils.kodiSQL('texture') connection = utils.kodiSQL('texture')
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute("SELECT cachedurl FROM texture WHERE url = ?", (url,))
try: try:
cursor.execute("SELECT cachedurl FROM texture WHERE url = ?", (url,))
cachedurl = cursor.fetchone()[0] cachedurl = cursor.fetchone()[0]
except TypeError: except TypeError:
self.logMsg("Could not find cached url.", 1) 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 else: # Delete thumbnail as well as the entry
thumbnails = xbmc.translatePath("special://thumbnails/%s" % cachedurl).decode('utf-8') thumbnails = xbmc.translatePath("special://thumbnails/%s" % cachedurl).decode('utf-8')
self.logMsg("Deleting cached thumbnail: %s" % thumbnails, 1) self.logMsg("Deleting cached thumbnail: %s" % thumbnails, 1)
@ -457,7 +461,7 @@ class Artwork():
try: try:
cursor.execute("DELETE FROM texture WHERE url = ?", (url,)) cursor.execute("DELETE FROM texture WHERE url = ?", (url,))
connection.commit() connection.commit()
except: except OperationalError:
self.logMsg("Issue deleting url from cache. Skipping.", 2) self.logMsg("Issue deleting url from cache. Skipping.", 2)
finally: finally:

View file

@ -144,31 +144,32 @@ class DownloadUtils():
def startSession(self): def startSession(self):
log = self.logMsg
self.deviceId = self.clientInfo.getDeviceId() self.deviceId = self.clientInfo.getDeviceId()
# User is identified from this point # User is identified from this point
# Attach authenticated header to the session # Attach authenticated header to the session
verify = None verify = False
cert = None
header = self.getHeader() header = self.getHeader()
# If user enabled host certificate verification # If user enabled host certificate verification
try: try:
verify = self.sslverify verify = self.sslverify
cert = self.sslclient if self.sslclient is not None:
verify = self.sslclient
except: except:
self.logMsg("Could not load SSL settings.", 1) log("Could not load SSL settings.", 1)
# Start session # Start session
self.s = requests.Session() self.s = requests.Session()
self.s.headers = header self.s.headers = header
self.s.verify = verify self.s.verify = verify
self.s.cert = cert
# Retry connections to the server # Retry connections to the server
self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1)) self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1)) self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
self.logMsg("Requests session started on: %s" % self.server, 1) log("Requests session started on: %s" % self.server, 1)
def stopSession(self): def stopSession(self):
try: try:
@ -232,7 +233,7 @@ class DownloadUtils():
if utils.settings('sslverify') == "true": if utils.settings('sslverify') == "true":
verifyssl = True verifyssl = True
if utils.settings('sslcert') != "None": if utils.settings('sslcert') != "None":
cert = utils.settings('sslcert') verifyssl = utils.settings('sslcert')
# Replace for the real values # Replace for the real values
url = url.replace("{server}", self.server) url = url.replace("{server}", self.server)
@ -245,7 +246,6 @@ class DownloadUtils():
params=parameters, params=parameters,
headers=header, headers=header,
timeout=timeout, timeout=timeout,
cert=cert,
verify=verifyssl) verify=verifyssl)
elif type == "POST": elif type == "POST":
@ -253,7 +253,6 @@ class DownloadUtils():
json=postBody, json=postBody,
headers=header, headers=header,
timeout=timeout, timeout=timeout,
cert=cert,
verify=verifyssl) verify=verifyssl)
elif type == "DELETE": elif type == "DELETE":
@ -261,7 +260,6 @@ class DownloadUtils():
json=postBody, json=postBody,
headers=header, headers=header,
timeout=timeout, timeout=timeout,
cert=cert,
verify=verifyssl) verify=verifyssl)
elif type == "OPTIONS": elif type == "OPTIONS":
@ -287,6 +285,8 @@ class DownloadUtils():
# If user enables ssl verification # If user enables ssl verification
try: try:
verifyssl = self.sslverify verifyssl = self.sslverify
if self.sslclient is not None:
verifyssl = self.sslclient
except AttributeError: except AttributeError:
if utils.settings('sslverify') == "true": if utils.settings('sslverify') == "true":
verifyssl = True verifyssl = True

View file

@ -143,6 +143,15 @@ class Embydb_Functions():
)) ))
self.embycursor.execute(query, (name, tagid, mediafolderid)) self.embycursor.execute(query, (name, tagid, mediafolderid))
def removeView(self, viewid):
query = ' '.join((
"DELETE FROM view",
"WHERE view_id = ?"
))
self.embycursor.execute(query, (viewid,))
def getItem_byId(self, embyid): def getItem_byId(self, embyid):
embycursor = self.embycursor embycursor = self.embycursor

View file

@ -203,6 +203,30 @@ def doMainListing():
xbmcplugin.endOfDirectory(int(sys.argv[1])) xbmcplugin.endOfDirectory(int(sys.argv[1]))
##### Generate a new deviceId
def resetDeviceId():
dialog = xbmcgui.Dialog()
language = utils.language
deviceId_old = utils.window('emby_deviceId')
try:
utils.window('emby_deviceId', clear=True)
deviceId = clientinfo.ClientInfo().getDeviceId(reset=True)
except Exception as e:
utils.logMsg("EMBY", "Failed to generate a new device Id: %s" % e, 1)
dialog.ok(
heading="Emby for Kodi",
line1=language(33032))
else:
utils.logMsg("EMBY", "Successfully removed old deviceId: %s New deviceId: %s"
% (deviceId_old, deviceId), 1)
dialog.ok(
heading="Emby for Kodi",
line1=language(33033))
xbmc.executebuiltin('RestartApp')
##### ADD ADDITIONAL USERS ##### ##### ADD ADDITIONAL USERS #####
def addUser(): def addUser():

View file

@ -1191,12 +1191,12 @@ class TVShows(Items):
season = -1 season = -1
# Specials ordering within season # Specials ordering within season
# if item.get('AirsAfterSeasonNumber'): if item.get('AirsAfterSeasonNumber'):
# airsBeforeSeason = item['AirsAfterSeasonNumber'] airsBeforeSeason = item['AirsAfterSeasonNumber']
# airsBeforeEpisode = 4096 # Kodi default number for afterseason ordering airsBeforeEpisode = 4096 # Kodi default number for afterseason ordering
# else: else:
# airsBeforeSeason = item.get('AirsBeforeSeasonNumber', "-1") airsBeforeSeason = item.get('AirsBeforeSeasonNumber')
# airsBeforeEpisode = item.get('AirsBeforeEpisodeNumber', "-1") airsBeforeEpisode = item.get('AirsBeforeEpisodeNumber')
airsBeforeSeason = "-1" airsBeforeSeason = "-1"
airsBeforeEpisode = "-1" airsBeforeEpisode = "-1"

View file

@ -38,7 +38,9 @@ class KodiMonitor(xbmc.Monitor):
def onSettingsChanged(self): def onSettingsChanged(self):
# Monitor emby settings # Monitor emby settings
currentPath = utils.settings('useDirectPaths') # Review reset setting at a later time, need to be adjusted to account for initial setup
# changes.
'''currentPath = utils.settings('useDirectPaths')
if utils.window('emby_pluginpath') != currentPath: if utils.window('emby_pluginpath') != currentPath:
# Plugin path value changed. Offer to reset # Plugin path value changed. Offer to reset
self.logMsg("Changed to playback mode detected", 1) self.logMsg("Changed to playback mode detected", 1)
@ -50,7 +52,7 @@ class KodiMonitor(xbmc.Monitor):
"needs to be recreated for the change to be applied. " "needs to be recreated for the change to be applied. "
"Proceed?")) "Proceed?"))
if resp: if resp:
utils.reset() utils.reset()'''
currentLog = utils.settings('logLevel') currentLog = utils.settings('logLevel')
if utils.window('emby_logLevel') != currentLog: if utils.window('emby_logLevel') != currentLog:

View file

@ -398,7 +398,6 @@ class LibrarySync(Thread):
xbmc.executebuiltin('UpdateLibrary(video)') xbmc.executebuiltin('UpdateLibrary(video)')
if self.enableMusic: if self.enableMusic:
xbmc.executebuiltin('UpdateLibrary(music)') xbmc.executebuiltin('UpdateLibrary(music)')
elapsedtotal = datetime.now() - starttotal elapsedtotal = datetime.now() - starttotal
utils.window('emby_initialScan', clear=True) utils.window('emby_initialScan', clear=True)
self.showKodiNote("%s completed in: %s" self.showKodiNote("%s completed in: %s"
@ -522,29 +521,6 @@ class LibrarySync(Thread):
vnodes.clearProperties() vnodes.clearProperties()
totalnodes = 0 totalnodes = 0
with embydb.GetEmbyDB() as emby_db:
with kodidb.GetKodiDB('video') as kodi_db:
for folderItem in result:
self.processView(folderItem, kodi_db, emby_db, totalnodes)
else:
# Add video nodes listings
vnodes.singleNode(totalnodes,
"Favorite movies",
"movies",
"favourites")
totalnodes += 1
vnodes.singleNode(totalnodes,
"Favorite tvshows",
"tvshows",
"favourites")
totalnodes += 1
vnodes.singleNode(totalnodes,
"channels",
"movies",
"channels")
totalnodes += 1
# Save total
utils.window('Emby.nodes.total', str(totalnodes))
# update views for all: # update views for all:
self.views = emby_db.getAllViewInfo() self.views = emby_db.getAllViewInfo()
@ -558,6 +534,8 @@ class LibrarySync(Thread):
'itemtype': 'artist' 'itemtype': 'artist'
} }
self.views.append(entry) self.views.append(entry)
nodes = [] # Prevent duplicate for nodes of the same type
playlists = [] # Prevent duplicate for playlists of the same type
self.logMsg("views saved: %s" % self.views, 1) self.logMsg("views saved: %s" % self.views, 1)
@ -645,6 +623,17 @@ class LibrarySync(Thread):
itemNumber = len(self.updatelist) itemNumber = len(self.updatelist)
if itemNumber == 0: if itemNumber == 0:
return True return True
# Validate the playlist exists or recreate it
if (foldername not in playlists and
mediatype in ('movies', 'tvshows', 'musicvideos')):
utils.playlistXSP(mediatype, foldername, folderid, viewtype)
playlists.append(foldername)
if foldername not in nodes and mediatype != "musicvideos":
vnodes.viewNode(sorted_views.index(foldername), foldername,
mediatype, viewtype, folderid)
if viewtype == "mixed": # Change the value
sorted_views[sorted_views.index(foldername)] = "%ss" % foldername
nodes.append(foldername)
# Run through self.updatelist, get XML metadata per item # Run through self.updatelist, get XML metadata per item
# Initiate threads # Initiate threads
@ -693,6 +682,10 @@ class LibrarySync(Thread):
thread.start() thread.start()
threads.append(thread) threads.append(thread)
self.logMsg("Kodi Infobox thread spawned", 1) self.logMsg("Kodi Infobox thread spawned", 1)
# Remove any old referenced views
log("Removing views: %s" % current_views, 1)
for view in current_views:
emby_db.removeView(view)
# Wait until finished # Wait until finished
getMetadataQueue.join() getMetadataQueue.join()

View file

@ -274,6 +274,16 @@ class PlaybackUtils():
else: else:
window('%s.refreshid' % embyitem, value=itemid) window('%s.refreshid' % embyitem, value=itemid)
# Append external subtitles to stream
playmethod = utils.window('%s.playmethod' % embyitem)
# Only for direct stream
if playmethod in ("DirectStream"):
# Direct play automatically appends external
subtitles = self.externalSubs(playurl)
listitem.setSubtitles(subtitles)
self.setArtwork(listitem)
def externalSubs(self, playurl): def externalSubs(self, playurl):
externalsubs = [] externalsubs = []

View file

@ -414,7 +414,7 @@ class Player(xbmc.Player):
self.doUtils( self.doUtils(
"{server}/:/timeline?" + urlencode(postdata), type="GET") "{server}/:/timeline?" + urlencode(postdata), type="GET")
def onPlayBackPaused( self ): def onPlayBackPaused(self):
currentFile = self.currentFile currentFile = self.currentFile
self.logMsg("PLAYBACK_PAUSED: %s" % currentFile, 2) self.logMsg("PLAYBACK_PAUSED: %s" % currentFile, 2)
@ -424,7 +424,7 @@ class Player(xbmc.Player):
self.reportPlayback() self.reportPlayback()
def onPlayBackResumed( self ): def onPlayBackResumed(self):
currentFile = self.currentFile currentFile = self.currentFile
self.logMsg("PLAYBACK_RESUMED: %s" % currentFile, 2) self.logMsg("PLAYBACK_RESUMED: %s" % currentFile, 2)
@ -434,7 +434,7 @@ class Player(xbmc.Player):
self.reportPlayback() self.reportPlayback()
def onPlayBackSeek( self, time, seekOffset ): def onPlayBackSeek(self, time, seekOffset):
# Make position when seeking a bit more accurate # Make position when seeking a bit more accurate
currentFile = self.currentFile currentFile = self.currentFile
self.logMsg("PLAYBACK_SEEK: %s" % currentFile, 2) self.logMsg("PLAYBACK_SEEK: %s" % currentFile, 2)
@ -445,7 +445,7 @@ class Player(xbmc.Player):
self.reportPlayback() self.reportPlayback()
def onPlayBackStopped( self ): def onPlayBackStopped(self):
log = self.logMsg log = self.logMsg
window = utils.window window = utils.window
@ -458,7 +458,7 @@ class Player(xbmc.Player):
log("Clear playlist properties.", 1) log("Clear playlist properties.", 1)
self.stopAll() self.stopAll()
def onPlayBackEnded( self ): def onPlayBackEnded(self):
# Will be called when xbmc stops playing a file # Will be called when xbmc stops playing a file
self.logMsg("ONPLAYBACK_ENDED", 2) self.logMsg("ONPLAYBACK_ENDED", 2)
utils.window('emby_customPlaylist.seektime', clear=True) utils.window('emby_customPlaylist.seektime', clear=True)
@ -494,6 +494,9 @@ class Player(xbmc.Player):
type = data['Type'] type = data['Type']
playMethod = data['playmethod'] playMethod = data['playmethod']
# Prevent manually mark as watched in Kodi monitor
utils.window('emby_skipWatched%s' % itemid, value="true")
if currentPosition and runtime: if currentPosition and runtime:
try: try:
percentComplete = currentPosition / int(runtime) percentComplete = currentPosition / int(runtime)
@ -505,16 +508,6 @@ class Player(xbmc.Player):
log("Percent complete: %s Mark played at: %s" log("Percent complete: %s Mark played at: %s"
% (percentComplete, markPlayedAt), 1) % (percentComplete, markPlayedAt), 1)
# Prevent manually mark as watched in Kodi monitor
utils.window('emby_skipWatched%s' % itemid, value="true")
self.stopPlayback(data)
# Stop transcoding
if playMethod == "Transcode":
log("Transcoding for %s terminated." % itemid, 1)
url = "{server}/video/:/transcode/universal/stop?session=%s" % self.clientInfo.getDeviceId()
doUtils(url, type="GET")
# Send the delete action to the server. # Send the delete action to the server.
offerDelete = False offerDelete = False
@ -553,6 +546,14 @@ class Player(xbmc.Player):
) )
for item in cleanup: for item in cleanup:
utils.window(item, clear=True) utils.window(item, clear=True)
self.stopPlayback(data)
# Stop transcoding
if playMethod == "Transcode":
log("Transcoding for %s terminated." % itemid, 1)
deviceId = self.clientInfo.getDeviceId()
url = "{server}/emby/Videos/ActiveEncodings?DeviceId=%s" % deviceId
doUtils(url, type="DELETE")
self.played_info.clear() self.played_info.clear()

View file

@ -294,11 +294,11 @@ class Read_EmbyServer():
log("Increase jump limit to: %s" % jump, 1) log("Increase jump limit to: %s" % jump, 1)
return items return items
def getViews(self, type, root=False): def getViews(self, mediatype="", root=False, sortedlist=False):
# Build a list of user views # Build a list of user views
doUtils = self.doUtils doUtils = self.doUtils
views = [] views = []
type = type.lower() mediatype = mediatype.lower()
if not root: if not root:
url = "{server}/emby/Users/{UserId}/Views?format=json" url = "{server}/emby/Users/{UserId}/Views?format=json"
@ -308,10 +308,8 @@ class Read_EmbyServer():
result = doUtils(url) result = doUtils(url)
try: try:
items = result['Items'] items = result['Items']
except TypeError: except TypeError:
self.logMsg("Error retrieving views for type: %s" % type, 2) self.logMsg("Error retrieving views for type: %s" % mediatype, 2)
else: else:
for item in items: for item in items:
@ -336,15 +334,25 @@ class Read_EmbyServer():
if itemId == folder['Id']: if itemId == folder['Id']:
itemtype = folder.get('CollectionType', "mixed") itemtype = folder.get('CollectionType', "mixed")
if (name not in ('Collections', 'Trailers') and (itemtype == type or if name not in ('Collections', 'Trailers'):
(itemtype == "mixed" and type in ("movies", "tvshows")))):
views.append({ if sortedlist:
views.append({
'name': name, 'name': name,
'type': itemtype, 'type': itemtype,
'id': itemId 'id': itemId
}) })
elif (itemtype == mediatype or
(itemtype == "mixed" and mediatype in ("movies", "tvshows"))):
views.append({
'name': name,
'type': itemtype,
'id': itemId
})
return views return views

View file

@ -296,7 +296,7 @@ def reset():
deleteNodes() deleteNodes()
# Wipe the kodi databases # Wipe the kodi databases
logMsg("EMBY", "Resetting the Kodi video database.") logMsg("EMBY", "Resetting the Kodi video database.", 0)
connection = kodiSQL('video') connection = kodiSQL('video')
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"') cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
@ -322,7 +322,7 @@ def reset():
cursor.close() cursor.close()
# Wipe the emby database # Wipe the emby database
logMsg("EMBY", "Resetting the Emby database.") logMsg("EMBY", "Resetting the Emby database.", 0)
connection = kodiSQL('emby') connection = kodiSQL('emby')
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"') cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
@ -331,15 +331,45 @@ def reset():
tablename = row[0] tablename = row[0]
if tablename != "version": if tablename != "version":
cursor.execute("DELETE FROM " + tablename) cursor.execute("DELETE FROM " + tablename)
cursor.execute('DROP table IF EXISTS emby')
cursor.execute('DROP table IF EXISTS view')
connection.commit() connection.commit()
cursor.close() cursor.close()
# Offer to wipe cached thumbnails
resp = dialog.yesno("Warning", "Removed all cached artwork?")
if resp:
logMsg("EMBY", "Resetting all cached artwork.", 0)
# Remove all existing textures first
path = xbmc.translatePath("special://thumbnails/").decode('utf-8')
if xbmcvfs.exists(path):
allDirs, allFiles = xbmcvfs.listdir(path)
for dir in allDirs:
allDirs, allFiles = xbmcvfs.listdir(path+dir)
for file in allFiles:
if os.path.supports_unicode_filenames:
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()
cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
rows = cursor.fetchall()
for row in rows:
tableName = row[0]
if(tableName != "version"):
cursor.execute("DELETE FROM " + tableName)
connection.commit()
cursor.close()
# reset the install run flag # reset the install run flag
settings('SyncInstallRunDone', value="false") settings('SyncInstallRunDone', value="false")
# Remove emby info # Remove emby info
resp = dialog.yesno("Warning", "Reset all Emby Addon settings?") resp = dialog.yesno("Warning", "Reset all Emby Addon settings?")
if resp == 1: if resp:
# Delete the settings # Delete the settings
addon = xbmcaddon.Addon() addon = xbmcaddon.Addon()
addondir = xbmc.translatePath(addon.getAddonInfo('profile')).decode('utf-8') addondir = xbmc.translatePath(addon.getAddonInfo('profile')).decode('utf-8')
@ -601,17 +631,17 @@ def passwordsXML():
time=1000, time=1000,
sound=False) sound=False)
def playlistXSP(mediatype, tagname, viewtype="", delete=False): def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
# Tagname is in unicode - actions: add or delete # Tagname is in unicode - actions: add or delete
tagname = tagname.encode('utf-8') tagname = tagname.encode('utf-8')
cleantagname = normalize_nodes(tagname)
path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8') path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8')
if viewtype == "mixed": if viewtype == "mixed":
plname = "%s - %s" % (tagname, mediatype) plname = "%s - %s" % (tagname, mediatype)
xsppath = "%sEmby %s - %s.xsp" % (path, cleantagname, mediatype) xsppath = "%sEmby %s - %s.xsp" % (path, viewid, mediatype)
else: else:
plname = tagname plname = tagname
xsppath = "%sEmby %s.xsp" % (path, cleantagname) xsppath = "%sEmby %s.xsp" % (path, viewid)
# Create the playlist directory # Create the playlist directory
if not xbmcvfs.exists(path): if not xbmcvfs.exists(path):
@ -668,7 +698,13 @@ def deleteNodes():
dirs, files = xbmcvfs.listdir(path) dirs, files = xbmcvfs.listdir(path)
for dir in dirs: for dir in dirs:
if dir.decode('utf-8').startswith('Emby'): if dir.decode('utf-8').startswith('Emby'):
shutil.rmtree("%s%s" % (path, dir.decode('utf-8'))) try:
shutil.rmtree("%s%s" % (path, dir.decode('utf-8')))
except:
logMsg("EMBY", "Failed to delete directory: %s" % dir.decode('utf-8'))
for file in files: for file in files:
if file.decode('utf-8').startswith('emby'): if file.decode('utf-8').startswith('emby'):
xbmcvfs.delete("%s%s" % (path, file.decode('utf-8'))) try:
xbmcvfs.delete("%s%s" % (path, file.decode('utf-8')))
except:
logMsg("EMBY", "Failed to file: %s" % file.decode('utf-8'))

View file

@ -40,16 +40,15 @@ class VideoNodes(object):
return root return root
def viewNode(self, indexnumber, tagname, mediatype, viewtype, delete=False): def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False):
window = utils.window window = utils.window
kodiversion = self.kodiversion kodiversion = self.kodiversion
cleantagname = utils.normalize_nodes(tagname.encode('utf-8'))
if viewtype == "mixed": if viewtype == "mixed":
dirname = "%s - %s" % (cleantagname, mediatype) dirname = "%s - %s" % (viewid, mediatype)
else: else:
dirname = cleantagname dirname = viewid
path = xbmc.translatePath("special://profile/library/video/").decode('utf-8') path = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
nodepath = xbmc.translatePath( nodepath = xbmc.translatePath(
@ -91,7 +90,11 @@ class VideoNodes(object):
# Root # Root
if not mediatype == "photos": if not mediatype == "photos":
root = self.commonRoot(order=0, label=tagname, tagname=tagname, roottype=0) if viewtype == "mixed":
specialtag = "%s - %s" % (tagname, mediatype)
root = self.commonRoot(order=0, label=specialtag, tagname=tagname, roottype=0)
else:
root = self.commonRoot(order=0, label=tagname, tagname=tagname, roottype=0)
try: try:
utils.indent(root) utils.indent(root)
except: pass except: pass
@ -166,7 +169,7 @@ class VideoNodes(object):
for node in nodes: for node in nodes:
nodetype = nodetypes[node] nodetype = nodetypes[node]
nodeXML = "%s%s_%s.xml" % (nodepath, cleantagname, nodetype) nodeXML = "%s%s_%s.xml" % (nodepath, viewid, nodetype)
# Get label # Get label
stringid = nodes[node] stringid = nodes[node]
if node != "1": if node != "1":
@ -193,7 +196,7 @@ class VideoNodes(object):
# Custom query # Custom query
path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=inprogressepisodes&limit=25"% tagname path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=inprogressepisodes&limit=25"% tagname
else: else:
path = "library://video/plex%s/%s_%s.xml" % (dirname, cleantagname, nodetype) path = "library://video/plex%s/%s_%s.xml" % (dirname, viewid, nodetype)
if mediatype == "photos": if mediatype == "photos":
windowpath = "ActivateWindow(Pictures,%s,return)" % path windowpath = "ActivateWindow(Pictures,%s,return)" % path
@ -203,7 +206,7 @@ class VideoNodes(object):
if nodetype == "all": if nodetype == "all":
if viewtype == "mixed": if viewtype == "mixed":
templabel = dirname templabel = "%s - %s" % (tagname, mediatype)
else: else:
templabel = label templabel = label