diff --git a/addon.xml b/addon.xml index 92bcd889..6e393108 100644 --- a/addon.xml +++ b/addon.xml @@ -1,7 +1,7 @@ diff --git a/changelog.txt b/changelog.txt index 4633cc2c..6ce7cf99 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +version 1.0.12 +- Possibility to use direct paths (you need to reset!) +- Replicate Plex views in video nodes + version 1.0.11 - Hotfix DB comparison. Sorry for that :-) diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml index 3f8554c0..04e7e9d5 100644 --- a/resources/language/English/strings.xml +++ b/resources/language/English/strings.xml @@ -273,7 +273,7 @@ Sync empty TV Shows Enable Music Library (restart Kodi!) Direct stream music library - Playback Mode + Playback Mode (resync!) Force artwork caching Limit artwork cache threads (recommended for rpi) Enable fast startup (requires server plugin) @@ -366,6 +366,14 @@ [COLOR yellow]Reset PMS and plex.tv connections to re-login[/COLOR] Automatically log into plex.tv on startup Enable constant background sync (restart Kodi!) + Playback Mode + CAUTION! If you choose "Native" mode , you might loose access to certain Plex features such as: Plex trailers and transcoding options. ALL Plex shares need to use direct paths (e.g. smb://myNAS/mymovie.mkv or \\myNAS/mymovie.mkv)! + Network credentials + Add network credentials to allow Kodi access to your content? Note: Skipping this step may generate a message during the initial scan of your content if Kodi can't locate your content. + Kodi can't locate file: + Please verify the path. You may need to verify your network credentials in the add-on settings or use different Plex paths. Stop syncing? + Shall we transform Plex paths from e.g. \\myNas\mymovie.mkv to smb://myNas/mymovie.mkv? (recommended) + Replace Plex paths \\myNas with SMB paths smb://myNas (resync!) diff --git a/resources/language/German/strings.xml b/resources/language/German/strings.xml index 7da49118..3358b9f5 100644 --- a/resources/language/German/strings.xml +++ b/resources/language/German/strings.xml @@ -302,6 +302,14 @@ [COLOR yellow]PMS und plex.tv Verbindungen zurücksetzen für erneuten Login[/COLOR] Automatisch beim Starten bei plex.tv einloggen Laufende Synchronisierung im Hintergrund aktivieren (Neustart!) + Playback Modus + WARNUNG! Mit dem "Native" Modus verlieren Sie Zugang zu Plex Funktionen wie z.B. Trailer und Transkodieren. ALLE Plex Bibliotheken müssen über direkte Plex Pfade für Kodi zugänglich sein (z.B. via \\meinNas\MeinFilm.mkv oder smb://meinNas/MeinFilm.mkv)! + Netzwerk Zugangsdaten + Möchten Sie nun Netzwerk Zugangsdaten eingeben? Wenn Sie diesen Schritt überspringen, wird möglicherweise die Synchronisierung Ihrer Bibliothek fehlschlagen, wenn Kodi nicht auf Ihre Medien zugreifen kann. + Kodi kann die folgende Datei nicht finden: + Bitte verifizieren Sie den Pfad. Möglichweise müssen Sie in den Addon Einstellungen die Netzwerk Zugangsdaten korrekt eingeben, oder Plex muss andere Pfade nutzen. Soll Sync gestoppt werden? + Sollen alle Plex Pfade \\meinNAS\meinFilm.mkv durch smb://meinNAS/meinFilm.mkv ersetzt werden? (empfohlen) + Plex Pfade \\meinNAS durch SMB Pfade smb://meinNAS ersetzen (neu synchen!) Plex Home Benutzer wechseln diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index b5d6111b..e1ac6719 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -53,7 +53,7 @@ import requests import re import json -from urllib import urlencode, quote_plus +from urllib import urlencode, quote_plus, unquote from PlexFunctions import PlexToKodiTimefactor, PMSHttpsEnabled @@ -1478,7 +1478,7 @@ class API(): """ Returns the type of media, e.g. 'movie' or 'clip' for trailers """ - return self.item.attrib.get('type', None) + return self.item.attrib.get('type') def getChecksum(self): """ @@ -1493,19 +1493,43 @@ class API(): """ Returns the Plex key such as '246922' as a string """ - return self.item.attrib.get('ratingKey', None) + return self.item.attrib.get('ratingKey') def getKey(self): """ Returns the Plex key such as '/library/metadata/246922' """ - return self.item.attrib.get('key', None) + return self.item.attrib.get('key') + + def getFilePath(self): + """ + Returns the direct path to this item, e.g. '\\NAS\movies\movie.mkv' + or None + """ + try: + res = self.item[0][0].attrib.get('file') + except: + res = None + if res: + res = unquote(res).decode('utf-8') + return res + + def getTVShowPath(self): + """ + Returns the direct path to the TV show, e.g. '\\NAS\tv\series' + or None + """ + res = None + for child in self.item: + if child.tag == 'Location': + res = child.attrib.get('path') + return res def getIndex(self): """ Returns the 'index' of an PMS XML reply. Depicts e.g. season number. """ - return self.item.attrib.get('index', None) + return self.item.attrib.get('index') def getDateCreated(self): """ diff --git a/resources/lib/initialsetup.py b/resources/lib/initialsetup.py index b1fb8dcb..29270369 100644 --- a/resources/lib/initialsetup.py +++ b/resources/lib/initialsetup.py @@ -234,6 +234,26 @@ class InitialSetup(): if forcePlexTV: return + # Direct paths (\\NAS\mymovie.mkv) or addon (http)? + if dialog.yesno(heading=self.addonName, + line1=string(39027), + line2=string(39028), + nolabel="Addon (Default)", + yeslabel="Native (Direct Paths)"): + self.logMsg("User opted to use direct paths.", 1) + utils.settings('useDirectPaths', value="1") + # Are you on a system where you would like to replace paths + # \\NAS\mymovie.mkv with smb://NAS/mymovie.mkv? (e.g. Windows) + if dialog.yesno(heading=self.addonName, + line1=string(39033)): + self.logMsg("User chose to replace paths with smb", 1) + + # Go to network credentials? + if dialog.yesno(heading=self.addonName, + line1=string(39029), + line2=string(39030)): + self.logMsg("Presenting network credentials dialog.", 1) + utils.passwordsXML() # Disable Plex music? if dialog.yesno(heading=self.addonName, line1=string(39016)): diff --git a/resources/lib/itemtypes.py b/resources/lib/itemtypes.py index e75913b8..cce00347 100644 --- a/resources/lib/itemtypes.py +++ b/resources/lib/itemtypes.py @@ -37,7 +37,10 @@ class Items(object): self.doUtils = downloadutils.DownloadUtils() self.kodiversion = int(xbmc.getInfoLabel("System.BuildVersion")[:2]) # self.directpath = utils.settings('useDirectPaths') == "1" - self.directpath = False + self.directpath = True if utils.window('useDirectPaths') == 'true' \ + else False + self.replaceSMB = True if utils.window('replaceSMB') == 'true' \ + else False # self.music_enabled = utils.settings('enableMusic') == "true" # self.contentmsg = utils.settings('newContent') == "true" @@ -68,6 +71,23 @@ class Items(object): self.kodiconn.close() return self + def askToValidate(self, url): + """ + Displays a YESNO dialog box: + Kodi can't locate file: . Please verify the path. + You may need to verify your network credentials in the + add-on settings or use different Plex paths. Stop syncing? + + Returns True if sync should stop, else False + """ + import xbmcaddon + string = xbmcaddon.Addon().getLocalizedString + resp = xbmcgui.Dialog().yesno( + heading=self.addonName, + line1=string(39031) + url, + line2=string(39032)) + return resp + def itemsbyId(self, items, process, pdialog=None): # Process items by itemid. Process can be added, update, userdata, remove emby = self.emby @@ -394,44 +414,45 @@ class Movies(Items): "id=%s&mode=play") % extra['key'] break - ##### GET THE FILE AND PATH ##### - playurl = API.getKey() - filename = playurl - # if "\\" in playurl: - # # Local path - # filename = playurl.rsplit("\\", 1)[1] - # else: # Network share - # filename = playurl.rsplit("/", 1)[1] - + # GET THE FILE AND PATH ##### + doIndirect = not self.directpath if self.directpath: # Direct paths is set the Kodi way - if utils.window('emby_pathverified') != "true" and not xbmcvfs.exists(playurl): - # Validate the path is correct with user intervention - resp = xbmcgui.Dialog().yesno( - heading="Can't validate path", - line1=( - "Kodi can't locate file: %s. Verify the path. " - "You may to verify your network credentials in the " - "add-on settings or use the emby path substitution " - "to format your path correctly. Stop syncing?" - % playurl)) - if resp: - utils.window('emby_shouldStop', value="true") - return False - - path = playurl.replace(filename, "") - utils.window('emby_pathverified', value="true") - else: + playurl = API.getFilePath() + if playurl is None: + # Something went wrong, trying to use non-direct paths + doIndirect = True + else: + if self.replaceSMB: + if playurl.startswith('\\\\'): + playurl = playurl.replace('\\', '/') + playurl = 'smb:' + playurl + if (utils.window('emby_pathverified') != "true" and + not xbmcvfs.exists(playurl.encode('utf-8'))): + # Validate the path is correct with user intervention + if self.askToValidate(playurl): + utils.window('emby_shouldStop', value="true") + return False + if "\\" in playurl: + # Local path + filename = playurl.rsplit("\\", 1)[1] + else: + # Network share + filename = playurl.rsplit("/", 1)[1] + path = playurl.replace(filename, "") + utils.window('emby_pathverified', value="true") + if doIndirect: # Set plugin path and media flags using real filename path = "plugin://plugin.video.plexkodiconnect.movies/" params = { - 'filename': filename.encode('utf-8'), + 'filename': API.getKey().encode('utf-8'), 'id': itemid, 'dbid': movieid, 'mode': "play" } filename = "%s?%s" % (path, urllib.urlencode(params)) - ##### UPDATE THE MOVIE ##### + + # UPDATE THE MOVIE ##### if update_item: self.logMsg("UPDATE movie itemid: %s - Title: %s" % (itemid, title), 1) @@ -1008,38 +1029,38 @@ class TVShows(Items): studio = None # GET THE FILE AND PATH ##### - playurl = API.getKey() - + doIndirect = not self.directpath if self.directpath: # Direct paths is set the Kodi way - if "\\" in playurl: - # Local path - path = "%s\\" % playurl - toplevelpath = "%s\\" % dirname(dirname(path)) + playurl = API.getTVShowPath() + if playurl is None: + # Something went wrong, trying to use non-direct paths + doIndirect = True else: - # Network path - path = "%s/" % playurl - toplevelpath = "%s/" % dirname(dirname(path)) - - if utils.window('emby_pathverified') != "true" and not xbmcvfs.exists(path): - # Validate the path is correct with user intervention - resp = xbmcgui.Dialog().yesno( - heading="Can't validate path", - line1=( - "Kodi can't locate file: %s. Verify the path. " - "You may to verify your network credentials in the " - "add-on settings or use the emby path substitution " - "to format your path correctly. Stop syncing?" - % playurl)) - if resp: - utils.window('emby_shouldStop', value="true") - return False - - utils.window('emby_pathverified', value="true") - else: + if self.replaceSMB: + if playurl.startswith('\\\\'): + playurl = playurl.replace('\\', '/') + playurl = 'smb:' + playurl + if "\\" in playurl: + # Local path + path = "%s\\" % playurl + toplevelpath = "%s\\" % dirname(dirname(path)) + else: + # Network path + path = "%s/" % playurl + toplevelpath = "%s/" % dirname(dirname(path)) + if (utils.window('emby_pathverified') != "true" and + not xbmcvfs.exists(path.encode('utf-8'))): + # Validate the path is correct with user intervention + if self.askToValidate(playurl): + utils.window('emby_shouldStop', value="true") + return False + utils.window('emby_pathverified', value="true") + if doIndirect: # Set plugin path toplevelpath = "plugin://plugin.video.plexkodiconnect.tvshows/" path = "%s%s/" % (toplevelpath, itemid) + # UPDATE THE TVSHOW ##### if update_item: self.logMsg("UPDATE tvshow itemid: %s - Title: %s" % (itemid, title), 1) @@ -1312,40 +1333,37 @@ class TVShows(Items): seasonid = kodi_db.addSeason(showid, season) # GET THE FILE AND PATH ##### - playurl = API.getKey() - filename = playurl - - # if "\\" in playurl: - # # Local path - # filename = playurl.rsplit("\\", 1)[1] - # else: # Network share - # filename = playurl.rsplit("/", 1)[1] - + doIndirect = not self.directpath if self.directpath: # Direct paths is set the Kodi way - if utils.window('emby_pathverified') != "true" and not xbmcvfs.exists(playurl): - # Validate the path is correct with user intervention - resp = xbmcgui.Dialog().yesno( - heading="Can't validate path", - line1=( - "Kodi can't locate file: %s. Verify the path. " - "You may to verify your network credentials in the " - "add-on settings or use the emby path substitution " - "to format your path correctly. Stop syncing?" - % playurl)) - if resp: - utils.window('emby_shouldStop', value="true") - return False - - path = playurl.replace(filename, "") - utils.window('emby_pathverified', value="true") - else: + playurl = API.getFilePath() + if playurl is None: + # Something went wrong, trying to use non-direct paths + doIndirect = True + else: + if self.replaceSMB: + if playurl.startswith('\\\\'): + playurl = playurl.replace('\\', '/') + playurl = 'smb:' + playurl + if (utils.window('emby_pathverified') != "true" and + not xbmcvfs.exists(playurl.encode('utf-8'))): + # Validate the path is correct with user intervention + if self.askToValidate(playurl): + utils.window('emby_shouldStop', value="true") + return False + if "\\" in playurl: + # Local path + filename = playurl.rsplit("\\", 1)[1] + else: + # Network share + filename = playurl.rsplit("/", 1)[1] + path = playurl.replace(filename, "") + utils.window('emby_pathverified', value="true") + if doIndirect: # Set plugin path and media flags using real filename - path = "plugin://plugin.video.plexkodiconnect.tvshows/%s/" % seriesId + path = "plugin://plugin.video.plexkodiconnect.movies/" params = { - - #'filename': filename.encode('utf-8'), - 'filename': filename.encode('utf-8'), + 'filename': API.getKey().encode('utf-8'), 'id': itemid, 'dbid': episodeid, 'mode': "play" @@ -2063,24 +2081,48 @@ class Music(Items): resume, duration = API.getRuntime() rating = userdata['UserRating'] + #if enabled, try to get the rating from file and/or emby + # if not self.directstream: + # rating, comment, hasEmbeddedCover = musicutils.getAdditionalSongTags(itemid, rating, API, kodicursor, emby_db, self.enableimportsongrating, self.enableexportsongrating, self.enableupdatesongrating) + # else: + # hasEmbeddedCover = False + # comment = API.getOverview() + + hasEmbeddedCover = False comment = None - # Plex works a bit differently - # if self.directstream: - path = "%s%s" % (self.server, item[0][0].attrib.get('key')) - filename = API.addPlexCredentialsToUrl(path) - # Keep path empty to not let Kodi scan it - path = None - # else: - # path = "plugin://plugin.audio.plexkodiconnect.music/" - # filename = API.getKey() - # params = { - # 'filename': filename, - # 'id': itemid, - # 'dbid': songid, - # 'mode': "play" - # } - # filename = "%s?%s" % (path, urllib.urlencode(params)) + # GET THE FILE AND PATH ##### + doIndirect = not self.directpath + if self.directpath: + # Direct paths is set the Kodi way + playurl = API.getFilePath() + if playurl is None: + # Something went wrong, trying to use non-direct paths + doIndirect = True + else: + if self.replaceSMB: + playurl = playurl.replace('\\', '/') + playurl = 'smb:' + playurl + if (utils.window('emby_pathverified') != "true" and + not xbmcvfs.exists(playurl.encode('utf-8'))): + # Validate the path is correct with user intervention + if self.askToValidate(playurl): + utils.window('emby_shouldStop', value="true") + return False + if "\\" in playurl: + # Local path + filename = playurl.rsplit("\\", 1)[1] + else: + # Network share + filename = playurl.rsplit("/", 1)[1] + path = playurl.replace(filename, "") + utils.window('emby_pathverified', value="true") + if doIndirect: + # Plex works a bit differently + path = "%s%s" % (self.server, item[0][0].attrib.get('key')) + filename = API.addPlexCredentialsToUrl(path) + # Keep path empty to not let Kodi scan it + path = None # UPDATE THE SONG ##### if update_item: diff --git a/resources/lib/userclient.py b/resources/lib/userclient.py index d8ca1cfa..19731fe6 100644 --- a/resources/lib/userclient.py +++ b/resources/lib/userclient.py @@ -203,6 +203,11 @@ class UserClient(threading.Thread): window('plex_machineIdentifier', value=self.machineIdentifier) window('plex_servername', value=self.servername) window('plex_authenticated', value='true') + # self.directpath + window('useDirectPaths', value='true' + if utils.settings('useDirectPaths') == "1" else 'false') + window('replaceSMB', value='true' + if utils.settings('replaceSMB') == "true" else 'false') # Set DownloadUtils values doUtils.setUsername(username) diff --git a/resources/lib/utils.py b/resources/lib/utils.py index 343efd05..f74f9128 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -687,6 +687,7 @@ def passwordsXML(): # To add network credentials path = xbmc.translatePath("special://userdata/").decode('utf-8') xmlpath = "%spasswords.xml" % path + logMsg('Path to passwords.xml: %s' % xmlpath, 1) try: xmlparse = etree.parse(xmlpath) @@ -751,13 +752,15 @@ def passwordsXML(): return # Network password password = dialog.input( - heading="Enter the network password", - option=xbmcgui.ALPHANUM_HIDE_INPUT) - if not password: - return + heading="Enter the network password", + default='', + type=xbmcgui.INPUT_ALPHANUM, + option=xbmcgui.ALPHANUM_HIDE_INPUT) + logMsg('Done asking for user credentials', 1) # Add elements for path in root.findall('.//path'): + logMsg('Running in loop', 1) if path.find('.//from').text.lower() == "smb://%s/" % server.lower(): # Found the server, rewrite credentials path.find('.//to').text = "smb://%s:%s@%s/" % (user, password, server) @@ -773,19 +776,19 @@ def passwordsXML(): # Add credentials settings('networkCreds', value="%s" % server) - logMsg("EMBY", "Added server: %s to passwords.xml" % server, 1) + logMsg("PLEX", "Added server: %s to passwords.xml" % server, 1) # Prettify and write to file try: indent(root) except: pass etree.ElementTree(root).write(xmlpath) - dialog.notification( - heading="PlexKodiConnect", - message="%s added to passwords.xml" % server, - icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", - time=1000, - sound=False) + # dialog.notification( + # heading="PlexKodiConnect", + # message="Added to passwords.xml", + # icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", + # time=5000, + # sound=False) def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False): """ diff --git a/resources/settings.xml b/resources/settings.xml index 502f1e72..c7e0c96f 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -54,7 +54,8 @@ - + +