def _record_playstate(status, ended): with kodidb.GetKodiDB('video') as kodi_db: # Hack - remove any obsolete file entries Kodi made kodi_db.clean_file_table() if not status['plex_id']: LOG.debug('No Plex id found to record playstate for status %s', status) return with plexdb.Get_Plex_DB() as plex_db: kodi_db_item = plex_db.getItem_byId(status['plex_id']) if kodi_db_item is None: # Item not (yet) in Kodi library LOG.debug('No playstate update due to Plex id not found: %s', status) return totaltime = float(kodi_time_to_millis(status['totaltime'])) / 1000 if ended: progress = 0.99 time = v.IGNORE_SECONDS_AT_START + 1 else: time = float(kodi_time_to_millis(status['time'])) / 1000 try: progress = time / totaltime except ZeroDivisionError: progress = 0.0 LOG.debug('Playback progress %s (%s of %s seconds)', progress, time, totaltime) playcount = status['playcount'] last_played = unix_date_to_kodi(unix_timestamp()) if playcount is None: LOG.info('playcount not found, looking it up in the Kodi DB') with kodidb.GetKodiDB('video') as kodi_db: playcount = kodi_db.get_playcount(kodi_db_item[1]) playcount = 0 if playcount is None else playcount if time < v.IGNORE_SECONDS_AT_START: LOG.debug('Ignoring playback less than %s seconds', v.IGNORE_SECONDS_AT_START) # Annoying Plex bug - it'll reset an already watched video to unwatched playcount = 0 last_played = None time = 0 elif progress >= v.MARK_PLAYED_AT: LOG.debug('Recording entirely played video since progress > %s', v.MARK_PLAYED_AT) playcount += 1 time = 0 with kodidb.GetKodiDB('video') as kodi_db: kodi_db.addPlaystate(kodi_db_item[1], time, totaltime, playcount, last_played) # Hack to force "in progress" widget to appear if it wasn't visible before if (state.FORCE_RELOAD_SKIN and xbmc.getCondVisibility('Window.IsVisible(Home.xml)')): LOG.debug('Refreshing skin to update widgets') xbmc.executebuiltin('ReloadSkin()')
def conclude_playback(playqueue, pos): """ ONLY if actually being played (e.g. at 5th position of a playqueue). Decide on direct play, direct stream, transcoding path to direct paths: file itself PMS URL Web URL audiostream (e.g. let user choose) subtitle stream (e.g. let user choose) Init Kodi Playback (depending on situation): start playback return PKC listitem attached to result """ LOG.info('Concluding playback for playqueue position %s', pos) result = Playback_Successful() listitem = PKC_ListItem() item = playqueue.items[pos] if item.xml is not None: # Got a Plex element api = API(item.xml) api.setPartNumber(item.part) api.CreateListItemFromPlexItem(listitem) playutils = PlayUtils(api, item) playurl = playutils.getPlayUrl() else: playurl = item.file listitem.setPath(tryEncode(playurl)) if item.playmethod in ('DirectStream', 'DirectPlay'): listitem.setSubtitles(api.externalSubs()) else: playutils.audio_subtitle_prefs(listitem) if state.RESUME_PLAYBACK is True: state.RESUME_PLAYBACK = False if (item.offset is None and item.plex_type not in (v.PLEX_TYPE_SONG, v.PLEX_TYPE_CLIP)): with plexdb.Get_Plex_DB() as plex_db: plex_dbitem = plex_db.getItem_byId(item.plex_id) file_id = plex_dbitem[1] if plex_dbitem else None with kodidb.GetKodiDB('video') as kodi_db: item.offset = kodi_db.get_resume(file_id) LOG.info('Resuming playback at %s', item.offset) listitem.setProperty('StartOffset', str(item.offset)) listitem.setProperty('resumetime', str(item.offset)) # Reset the resumable flag state.RESUMABLE = False result.listitem = listitem pickle_me(result) LOG.info('Done concluding playback')
def stopAll(self): if not self.played_info: return log.info("Played_information: %s" % self.played_info) # Process each items for item in self.played_info: data = self.played_info.get(item) if data: log.debug("Item path: %s" % item) log.debug("Item data: %s" % data) runtime = data['runtime'] currentPosition = data['currentPosition'] itemid = data['item_id'] refresh_id = data['refresh_id'] currentFile = data['currentfile'] media_type = data['Type'] playMethod = data['playmethod'] # Prevent manually mark as watched in Kodi monitor window('plex_skipWatched%s' % itemid, value="true") if currentPosition and runtime: try: percentComplete = float(currentPosition) / float( runtime) except ZeroDivisionError: # Runtime is 0. percentComplete = 0 markPlayed = 0.90 log.info("Percent complete: %s Mark played at: %s" % (percentComplete, markPlayed)) if percentComplete >= markPlayed: # Tell Kodi that we've finished watching (Plex knows) if (data['fileid'] is not None and data['itemType'] in (v.KODI_TYPE_MOVIE, v.KODI_TYPE_EPISODE)): with kodidb.GetKodiDB('video') as kodi_db: kodi_db.addPlaystate( data['fileid'], None, None, data['playcount'] + 1, DateToKodi(getUnixTimestamp())) # Send the delete action to the server. offerDelete = False if media_type == "Episode" and settings( 'deleteTV') == "true": offerDelete = True elif media_type == "Movie" and settings( 'deleteMovies') == "true": offerDelete = True if settings('offerDelete') != "true": # Delete could be disabled, even if the subsetting is enabled. offerDelete = False # Plex: never delete offerDelete = False if percentComplete >= markPlayed and offerDelete: resp = xbmcgui.Dialog().yesno(lang(30091), lang(33015), autoclose=120000) if not resp: log.info("User skipped deletion.") continue url = "{server}/emby/Items/%s?format=json" % itemid log.info("Deleting request: %s" % itemid) self.doUtils(url, action_type="DELETE") # Clean the WINDOW properties for filename in self.played_info: plex_item = 'plex_%s' % tryEncode(filename) cleanup = ( '%s.itemid' % plex_item, '%s.runtime' % plex_item, '%s.refreshid' % plex_item, '%s.playmethod' % plex_item, '%s.type' % plex_item, '%s.runtime' % plex_item, '%s.playcount' % plex_item, '%s.playlistPosition' % plex_item, '%s.subtitle' % plex_item, ) for item in cleanup: window(item, clear=True) # Stop transcoding if playMethod == "Transcode": log.info("Transcoding for %s terminating" % itemid) self.doUtils("{server}/video/:/transcode/universal/stop", parameters={'session': window('plex_client_Id')}) self.played_info.clear()
def stopAll(self): if not self.played_info: return log.info("Played_information: %s" % self.played_info) # Process each items for item in self.played_info: data = self.played_info.get(item) if not data: continue log.debug("Item path: %s" % item) log.debug("Item data: %s" % data) runtime = data['runtime'] currentPosition = data['currentPosition'] itemid = data['item_id'] refresh_id = data['refresh_id'] currentFile = data['currentfile'] media_type = data['Type'] playMethod = data['playmethod'] # Prevent manually mark as watched in Kodi monitor window('plex_skipWatched%s' % itemid, value="true") if not currentPosition or not runtime: continue try: percentComplete = float(currentPosition) / float(runtime) except ZeroDivisionError: # Runtime is 0. percentComplete = 0 markPlayed = 0.90 log.info("Percent complete: %s Mark played at: %s" % (percentComplete, markPlayed)) if percentComplete >= markPlayed: # Tell Kodi that we've finished watching (Plex knows) if (data['fileid'] is not None and data['itemType'] in (v.KODI_TYPE_MOVIE, v.KODI_TYPE_EPISODE)): with kodidb.GetKodiDB('video') as kodi_db: kodi_db.addPlaystate(data['fileid'], None, None, data['playcount'] + 1, DateToKodi(getUnixTimestamp())) # Clean the WINDOW properties for filename in self.played_info: plex_item = 'plex_%s' % tryEncode(filename) cleanup = ( '%s.itemid' % plex_item, '%s.runtime' % plex_item, '%s.refreshid' % plex_item, '%s.playmethod' % plex_item, '%s.type' % plex_item, '%s.runtime' % plex_item, '%s.playcount' % plex_item, '%s.playlistPosition' % plex_item, '%s.subtitle' % plex_item, ) for item in cleanup: window(item, clear=True) # Stop transcoding if playMethod == "Transcode": log.info("Transcoding for %s terminating" % itemid) self.doUtils("{server}/video/:/transcode/universal/stop", parameters={'session': window('plex_client_Id')}) self.played_info.clear()
def PlayBackStart(self, data): """ Called whenever a playback is started """ log = self.logMsg window = utils.window # Get currently playing file - can take a while. Will be utf-8! try: currentFile = self.xbmcplayer.getPlayingFile() except: currentFile = None count = 0 while currentFile is None: xbmc.sleep(100) try: currentFile = self.xbmcplayer.getPlayingFile() except: pass if count == 50: log("No current File - Cancelling OnPlayBackStart...", -1) return else: count += 1 log("Currently playing file is: %s" % utils.tryDecode(currentFile), 1) # Try to get a Kodi ID item = data.get('item') try: type = item['type'] except: log("Item is invalid for PMS playstate update.", 0) return try: kodiid = item['id'] except (KeyError, TypeError): itemType = window("emby_%s.type" % currentFile) log("No kodi id passed. Playing itemtype is: %s" % itemType, 1) if itemType in ('movie', 'episode'): # Window was setup by PKC and is NOT a trailer ('clip') with kodidb.GetKodiDB('video') as kodi_db: kodiid = kodi_db.getIdFromTitle(data.get('item')) if kodiid is None: log( "Skip playstate update. No unique Kodi title found" " for %s" % data.get('item'), 0) return else: log("Item is invalid for PMS playstate update.", 0) return # Get Plex' item id with embydb.GetEmbyDB() as emby_db: emby_dbitem = emby_db.getItem_byKodiId(kodiid, type) try: plexid = emby_dbitem[0] except TypeError: log("No Plex id returned for kodiid %s" % kodiid, 0) return log("Found Plex id %s for Kodi id %s" % (plexid, kodiid), 1) # Set some stuff if Kodi initiated playback if ((utils.settings('useDirectPaths') == "1" and not type == "song") or (type == "song" and utils.settings('enableMusic') == "true")): if self.StartDirectPath(plexid, type, currentFile) is False: log('Could not initiate monitoring; aborting', -1) return # Save currentFile for cleanup later and to be able to access refs window('plex_lastPlayedFiled', value=utils.tryDecode(currentFile)) window('Plex_currently_playing_itemid', value=plexid) window("emby_%s.itemid" % currentFile, value=plexid) log('Finish playback startup', 1)
def PlayBackStart(self, data): """ Called whenever a playback is started """ # Get currently playing file - can take a while. Will be utf-8! try: currentFile = self.xbmcplayer.getPlayingFile() except: currentFile = None count = 0 while currentFile is None: xbmc.sleep(100) try: currentFile = self.xbmcplayer.getPlayingFile() except: pass if count == 50: log.info("No current File, cancel OnPlayBackStart...") return else: count += 1 # Just to be on the safe side currentFile = tryDecode(currentFile) log.debug("Currently playing file is: %s" % currentFile) # Get the type of media we're playing try: typus = data['item']['type'] except (TypeError, KeyError): log.info("Item is invalid for PMS playstate update.") return log.debug("Playing itemtype is (or appears to be): %s" % typus) # Try to get a Kodi ID # If PKC was used - native paths, not direct paths plexid = window('emby_%s.itemid' % tryEncode(currentFile)) # Get rid of the '' if the window property was not set plexid = None if not plexid else plexid kodiid = None if plexid is None: log.debug('Did not get Plex id from window properties') try: kodiid = data['item']['id'] except (TypeError, KeyError): log.debug('Did not get a Kodi id from Kodi, darn') # For direct paths, if we're not streaming something # When using Widgets, Kodi doesn't tell us shit so we need this hack if (kodiid is None and plexid is None and typus != 'song' and not currentFile.startswith('http')): try: filename = currentFile.rsplit('/', 1)[1] path = currentFile.rsplit('/', 1)[0] + '/' except IndexError: filename = currentFile.rsplit('\\', 1)[1] path = currentFile.rsplit('\\', 1)[0] + '\\' log.debug('Trying to figure out playing item from filename: %s ' 'and path: %s' % (filename, path)) with kodidb.GetKodiDB('video') as kodi_db: try: kodiid, typus = kodi_db.getIdFromFilename(filename, path) except TypeError: log.info('Abort playback report, could not id kodi item') return if plexid is None: # Get Plex' item id with embydb.GetEmbyDB() as emby_db: emby_dbitem = emby_db.getItem_byKodiId(kodiid, typus) try: plexid = emby_dbitem[0] except TypeError: log.info("No Plex id returned for kodiid %s. Aborting playback" " report" % kodiid) return log.debug("Found Plex id %s for Kodi id %s for type %s" % (plexid, kodiid, typus)) # Set some stuff if Kodi initiated playback if ((settings('useDirectPaths') == "1" and not typus == "song") or (typus == "song" and settings('enableMusic') == "true")): if self.StartDirectPath(plexid, typus, tryEncode(currentFile)) is False: log.error('Could not initiate monitoring; aborting') return # Save currentFile for cleanup later and to be able to access refs window('plex_lastPlayedFiled', value=currentFile) window('plex_currently_playing_itemid', value=plexid) window("emby_%s.itemid" % tryEncode(currentFile), value=plexid) log.info('Finish playback startup')