diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 7610558c..a33f1dbe 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -85,6 +85,12 @@ class LibrarySync(threading.Thread): ### BUILD VIDEO NODES LISTING ### VideoNodes().buildVideoNodesListing() + ### CREATE SOURCES ### + if addon.getSetting("Sources") != "true": + # Only create sources once + self.logMsg("Sources.xml created.", 0) + utils.createSources() + addon.setSetting("Sources", "true") ### PROCESS VIDEO LIBRARY ### diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index 026ebeaa..c841c37c 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -117,27 +117,6 @@ class PlaybackUtils(): WINDOW.setProperty(playurl+"positionurl", positionurl) WINDOW.setProperty(playurl+"deleteurl", "") WINDOW.setProperty(playurl+"deleteurl", deleteurl) - - #show the additional resume dialog if launched from a widget - if xbmc.getCondVisibility("Window.IsActive(home)"): - if userData.get("PlaybackPositionTicks") != 0: - reasonableTicks = int(userData.get("PlaybackPositionTicks")) / 1000 - seekTime = reasonableTicks / 10000 - if seekTime != 0: - displayTime = str(datetime.timedelta(seconds=seekTime)) - display_list = [ self.language(30106) + ' ' + displayTime, self.language(30107)] - resumeScreen = xbmcgui.Dialog() - resume_result = resumeScreen.select(self.language(30105), display_list) - if resume_result == 0: - WINDOW.setProperty(playurl+"seektime", str(seekTime)) - elif resume_result < 0: - # User cancelled dialog - xbmc.log("Emby player -> User cancelled resume dialog.") - return - else: - WINDOW.clearProperty(playurl+"seektime") - else: - WINDOW.clearProperty(playurl+"seektime") if result.get("Type")=="Episode": WINDOW.setProperty(playurl+"refresh_id", result.get("SeriesId")) @@ -169,12 +148,7 @@ class PlaybackUtils(): self.setListItemProps(server, id, listItem, result) xbmc.Player().play(playurl,listItem) elif setup == "default": - #artwork only works from widgets (home screen) with player command as there is no listitem selected - if xbmc.getCondVisibility("Window.IsActive(home)"): - self.setListItemProps(server, id, listItem, result) - xbmc.Player().play(playurl,listItem) - else: - xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) + xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) def setArt(self, list,name,path): if name=='thumb' or name=='fanart_image' or name=='small_poster' or name=='tiny_poster' or name == "medium_landscape" or name=='medium_poster' or name=='small_fanartimage' or name=='medium_fanartimage' or name=='fanart_noindicators': @@ -255,7 +229,7 @@ class PlaybackUtils(): xbmc.sleep(500) #Jump to resume point - jumpBackSec = 10#int(self.settings.getSetting("resumeJumpBack")) + jumpBackSec = int(addon.getSetting("resumeJumpBack")) seekToTime = seekTo - jumpBackSec count = 0 while xbmc.Player().getTime() < (seekToTime - 5) and count < 11: # only try 10 times @@ -382,7 +356,7 @@ class PlaybackUtils(): if item.get("Type") == "Episode" and addon.getSetting("offerDeleteTV")=="true": WINDOW.setProperty(playurl + "deleteurl", deleteurl) if item.get("Type") == "Movie" and addon.getSetting("offerDeleteMovies")=="true": - WINDOW.setProperty(playurl + "deleteurl", deleteurl) + WINDOW.setProperty(playurl + "deleteurl", deleteurl) WINDOW.setProperty(playurl + "runtimeticks", str(item.get("RunTimeTicks"))) WINDOW.setProperty(playurl+"type", item.get("Type")) diff --git a/resources/lib/Player.py b/resources/lib/Player.py index 3e5fd9cd..9e59e789 100644 --- a/resources/lib/Player.py +++ b/resources/lib/Player.py @@ -239,121 +239,6 @@ class Player( xbmc.Player ): currentFile = xbmcplayer.getPlayingFile() except: pass self.logMsg("onPlayBackStarted: %s" % currentFile, 0) - - playMethod = WINDOW.getProperty(currentFile + "playmethod") - - # Set audio and subtitles automatically - # Following Emby user preference. - '''if self.audioPref == "default" and self.subsPref == "default": - self.logMsg("No Emby user preferences found.", 2) - # Emby user preferences are not set. - pass - elif playMethod == "DirectPlay" or playMethod == "DirectStream": - # Only currently compatible with DirectPlay. - # Tested on plugin://, unsure about direct paths. - self.logMsg("Audio Pref: %s Subtitles Pref: %s" % (self.audioPref, self.subsPref), 1) - audiotracks = xbmcplayer.getAvailableAudioStreams() - subs = xbmcplayer.getAvailableSubtitleStreams() - self.logMsg("%s %s" % (audiotracks, subs), 1) - defaultsubs = WINDOW.getProperty("%ssubs" % currentFile) - - codecs = [ - # Possible codecs - 'und','Stereo','AC3','DTS', '5.1' - #'Stereo - Stereo','AC3 5.1', 'DTS 5.1', 'DTS-HD MA 5.1' - ] - - if len(audiotracks) == 1 and len(subs) == 0: - # There's only one audio track and no subtitles - xbmcplayer.showSubtitles(False) - - else: - # More complex cases - codec_intrack = False - for codec in codecs: - if codec in '\n'.join(audiotracks): - codec_intrack = True - - if self.audioPref in audiotracks: - self.logMsg("Door 1", 1) - # Audio pref is available - index = audiotracks.index(self.audioPref) - xbmcplayer.setAudioStream(index) - - if addon.getSetting('subsoverride') == "true": - if self.subsPref in subs: - self.logMsg("Door 1.1", 1) - # Subs are forced. - index = subs.index(self.subsPref) - xbmcplayer.setSubtitleStream(index) - else: - # Use default subs - if defaultsubs == "ssa" or defaultsubs == "srt": - # For some reason, Kodi sees SSA as '' - self.logMsg("Door 1.2", 1) - index = subs.index('') - xbmcplayer.setSubtitleStream(index) - elif defaultsubs: - self.logMsg("Door 1.3", 1) - index = subs.index(defaultsubs) - xbmcplayer.setSubtitleStream(index) - else: - xbmcplayer.showSubtitles(False) - - elif (len(audiotracks) == 1) and not codec_intrack: - self.logMsg("Door 2", 1) - # 1. There's one audio track. - # 2. The audio is defined as a language. - # 3. Audio pref is not available, guaranteed. - if self.subsPref in subs: - self.logMsg("Door 2.1", 1) - # Subs pref is available. - index = subs.index(self.subsPref) - xbmcplayer.setSubtitleStream(index) - else: - # Use default subs - if defaultsubs == "ssa" or defaultsubs == "srt": - # For some reason, Kodi sees SSA as '' - self.logMsg("Door 2.2", 1) - index = subs.index('') - xbmcplayer.setSubtitleStream(index) - elif defaultsubs: - self.logMsg("Door 2.3", 1) - index = subs.index(defaultsubs) - xbmcplayer.setSubtitleStream(index) - - elif len(audiotracks) == 1 and codec_intrack: - self.logMsg("Door 3", 1) - # 1. There one audio track. - # 2. The audio is undefined or a codec. - # 3. Audio track is mislabeled. - if self.subsPref in subs: - # If the subtitle is available, only display - # if the setting is enabled. - if addon.getSetting('subsoverride') == "true": - # Subs are forced. - self.logMsg("Door 3.2", 1) - index = subs.index(self.subsPref) - xbmcplayer.setSubtitleStream(index) - else: - # Let the user decide, since track is mislabeled. - self.logMsg("Door 3.3") - xbmcplayer.showSubtitles(False) - else: - # Use default subs - if defaultsubs == "ssa" or defaultsubs == "srt": - # For some reason, Kodi sees SSA as '' - self.logMsg("Door 3.4", 1) - index = subs.index('') - xbmcplayer.setSubtitleStream(index) - elif defaultsubs: - self.logMsg("Door 3.5", 1) - index = subs.index(defaultsubs) - xbmcplayer.setSubtitleStream(index) - else: - # Nothing matches, let the user decide. - self.logMsg("Door 3.6", 1) - xbmcplayer.showSubtitles(False)''' # we may need to wait until the info is available item_id = WINDOW.getProperty(currentFile + "item_id") @@ -374,7 +259,6 @@ class Player( xbmc.Player ): subtitleindex = WINDOW.getProperty(currentFile + "SubtitleStreamIndex") playMethod = WINDOW.getProperty(currentFile + "playmethod") itemType = WINDOW.getProperty(currentFile + "type") - seekTime = WINDOW.getProperty(currentFile + "seektime") # Get playback volume volume_query = '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume","muted"]}, "id": 1}' @@ -382,11 +266,8 @@ class Player( xbmc.Player ): result = json.loads(result) volume = result.get(u'result').get(u'volume') muted = result.get(u'result').get(u'muted') - - if seekTime: - PlaybackUtils().seekToPosition(int(seekTime)) - else: - seekTime = 0 + + seekTime = xbmc.Player().getTime() url = "{server}/mediabrowser/Sessions/Playing" postdata = { diff --git a/resources/lib/UserClient.py b/resources/lib/UserClient.py index f5915164..104bc337 100644 --- a/resources/lib/UserClient.py +++ b/resources/lib/UserClient.py @@ -239,7 +239,7 @@ class UserClient(threading.Thread): url = "%s/mediabrowser/Users/%s" % (self.currServer, self.currUserId) WINDOW.setProperty("currUser", username) WINDOW.setProperty("accessToken%s" % username, self.currToken) - result = doUtils.downloadUrl(url, type="POST") + result = doUtils.downloadUrl(url) if result == 401: # Token is no longer valid self.resetClient() diff --git a/resources/lib/Utils.py b/resources/lib/Utils.py index 5ea5bcfa..eec80d54 100644 --- a/resources/lib/Utils.py +++ b/resources/lib/Utils.py @@ -157,6 +157,43 @@ def stopProfiling(pr, profileName): f.write(str(ncalls) + "\t" + "{0}".format(total_time) + "\t" + "{0}".format(cumulative_time) + "\t" + func_name + "\t" + filename + "\r\n") f.close() +def createSources(): + # To make Master lock compatible + path = xbmc.translatePath("special://profile/").decode("utf-8") + xmlpath = "%ssources.xml" % path + + sources = open(xmlpath, 'w') + sources.write( + + '\n\t' + '\n\t\t' + '\n\t' + '\n\t' + '\n\t' + '\n\t\t' + '\n\t' + '\n\t' + '\n\t\t' + '\n\t' + '\n\t' + '\n\t\t' + '\n\t' + '\n' + '' + ) + def CleanName(filename): validFilenameChars = "-_.() %s%s" % (string.ascii_letters, string.digits) cleanedFilename = unicodedata.normalize('NFKD', filename).encode('ASCII', 'ignore') diff --git a/resources/lib/WriteKodiVideoDB.py b/resources/lib/WriteKodiVideoDB.py index f4327ab9..be023ba3 100644 --- a/resources/lib/WriteKodiVideoDB.py +++ b/resources/lib/WriteKodiVideoDB.py @@ -62,9 +62,9 @@ class WriteKodiVideoDB(): # Found the Emby Id, let Emby server know of new playcount watchedurl = "{server}/mediabrowser/Users/{UserId}/PlayedItems/%s" % emby_id if playcount != 0: - doUtils.downloadUtils(watchedurl, type = "POST") + doUtils.downloadUrl(watchedurl, type = "POST") else: - doUtils.downloadUtils(watchedurl, type = "DELETE") + doUtils.downloadUrl(watchedurl, type = "DELETE") # Erase any resume point associated self.setKodiResumePoint(id, 0, 0, cursor) finally: @@ -252,6 +252,39 @@ class WriteKodiVideoDB(): # To avoid negative bookmark resume = resume - jumpback self.setKodiResumePoint(fileid, resume, total, cursor) + + # Create a dummy bookmark for homescreen - widgets + if not self.directpath: + plugindummy = "plugin://plugin.video.emby/" + cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?", (plugindummy,)) + try: + pathid = cursor.fetchone()[0] + except: + # Top level path does not exist yet + cursor.execute("select coalesce(max(idPath),0) as tlpathid from path") + pathid = cursor.fetchone()[0] + 1 + query = "INSERT INTO path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" + cursor.execute(query, (pathid, plugindummy, "tvshows", "metadata.local", 1)) + + # Validate the file in database + cursor.execute("SELECT idFile as fileid FROM files WHERE strFilename = ? and idPath = ?", (filename, pathid,)) + try: + fileid = cursor.fetchone()[0] + except: + # File does not exist yet + if resume: + cursor.execute("select coalesce(max(idFile),0) as fileid from files") + fileid = cursor.fetchone()[0] + 1 + query = "INSERT INTO files(idFile, idPath, strFilename, playCount, lastPlayed, dateAdded) values(?, ?, ?, ?, ?, ?)" + cursor.execute(query, (fileid, pathid, filename, playcount, dateplayed, dateadded)) + self.setKodiResumePoint(fileid, resume, total, cursor) + else: # File exists + if not resume: + cursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,)) + else: + query = "UPDATE files SET playCount = ?, lastPlayed = ? WHERE idFile = ?" + cursor.execute(query, (playcount, dateplayed, fileid)) + self.setKodiResumePoint(fileid, resume, total, cursor) def addOrUpdateMusicVideoToKodiLibrary(self, embyId ,connection, cursor): @@ -652,6 +685,12 @@ class WriteKodiVideoDB(): # Update or insert actors self.AddPeopleToMedia(episodeid, MBitem.get('People'), "episode", connection, cursor) + # Add streamdetails + self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) + + # Update artwork + self.addOrUpdateArt(API().getArtwork(MBitem, "Primary", mediaType = "episode"), episodeid, "episode", "thumb", cursor) + # Set resume point and round to 6th decimal resume = round(float(timeInfo.get('ResumeTime')), 6) total = round(float(timeInfo.get('TotalTime')), 6) @@ -660,12 +699,40 @@ class WriteKodiVideoDB(): # To avoid negative bookmark resume = resume - jumpback self.setKodiResumePoint(fileid, resume, total, cursor) - - # Add streamdetails - self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) - - # Update artwork - self.addOrUpdateArt(API().getArtwork(MBitem, "Primary", mediaType = "episode"), episodeid, "episode", "thumb", cursor) + + if not self.directpath: + # Create a dummy bookmark for homescreen - widgets + plugindummy = "plugin://plugin.video.emby/" + cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?", (plugindummy,)) + try: + pathid = cursor.fetchone()[0] + except: + # Top level path does not exist yet + cursor.execute("select coalesce(max(idPath),0) as tlpathid from path") + pathid = cursor.fetchone()[0] + 1 + query = "INSERT INTO path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" + cursor.execute(query, (pathid, plugindummy, "tvshows", "metadata.local", 1)) + + # Validate the file in database + cursor.execute("SELECT idFile as fileid FROM files WHERE strFilename = ? and idPath = ?", (filename, pathid,)) + try: + fileid = cursor.fetchone()[0] + except: + # File does not exist yet + if resume: + cursor.execute("select coalesce(max(idFile),0) as fileid from files") + fileid = cursor.fetchone()[0] + 1 + query = "INSERT INTO files(idFile, idPath, strFilename, playCount, lastPlayed, dateAdded) values(?, ?, ?, ?, ?, ?)" + cursor.execute(query, (fileid, pathid, filename, playcount, dateplayed, dateadded)) + self.setKodiResumePoint(fileid, resume, total, cursor) + else: # File exists + if not resume: + cursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,)) + else: + query = "UPDATE files SET playCount = ?, lastPlayed = ? WHERE idFile = ?" + cursor.execute(query, (playcount, dateplayed, fileid)) + self.setKodiResumePoint(fileid, resume, total, cursor) + def deleteItemFromKodiLibrary(self, id, connection, cursor ): diff --git a/resources/settings.xml b/resources/settings.xml index 83ea2959..4e168207 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -25,6 +25,7 @@ +