def externalSubs(self, playurl): externalsubs = [] mapping = {} itemid = self.API.getRatingKey() mediastreams = self.API.getMediaStreams() kodiindex = 0 for stream in mediastreams: index = stream['Index'] # Since Emby returns all possible tracks together, have to pull only external subtitles. # IsTextSubtitleStream if true, is available to download from emby. if (stream['Type'] == "Subtitle" and stream['IsExternal'] and stream['IsTextSubtitleStream']): # Direct stream url = ("%s/Videos/%s/%s/Subtitles/%s/Stream.srt" % (self.server, itemid, itemid, index)) # map external subtitles for mapping mapping[kodiindex] = index externalsubs.append(url) kodiindex += 1 mapping = json.dumps(mapping) utils.window('emby_%s.indexMapping' % playurl, value=mapping) return externalsubs
def _report_progress(self): # Update and report playback progress kodi_player = self.kodi_player try: play_time = kodi_player.getTime() filename = kodi_player.currentFile # Update positionticks if filename in kodi_player.played_info: kodi_player.played_info[filename]['currentPosition'] = play_time difference = datetime.today() - self.last_progress difference_seconds = difference.seconds # Report progress to Emby server if difference_seconds > 3: kodi_player.reportPlayback() self.last_progress = datetime.today() elif window('emby_command') == "true": # Received a remote control command that # requires updating immediately window('emby_command', clear=True) kodi_player.reportPlayback() self.last_progress = datetime.today() except Exception as error: log.exception(error)
def onSettingsChanged(self): """ Monitor the PKC settings for changes made by the user """ # settings: window-variable items = { 'logLevel': 'plex_logLevel', 'enableContext': 'plex_context', 'plex_restricteduser': '******', 'dbSyncIndicator': 'dbSyncIndicator', 'remapSMB': 'remapSMB', 'replaceSMB': 'replaceSMB', 'force_transcode_pix': 'plex_force_transcode_pix', 'fetch_pms_item_number': 'fetch_pms_item_number' } # Path replacement for typus in REMAP_TYPE_FROM_PLEXTYPE.values(): for arg in ('Org', 'New'): key = 'remapSMB%s%s' % (typus, arg) items[key] = key # Reset the window variables from the settings variables for settings_value, window_value in items.iteritems(): if window(window_value) != settings(settings_value): log.debug('PKC settings changed: %s is now %s' % (settings_value, settings(settings_value))) window(window_value, value=settings(settings_value)) if settings_value == 'fetch_pms_item_number': log.info('Requesting playlist/nodes refresh') window('plex_runLibScan', value="views")
def onPlayBackStopped( self ): # Will be called when user stops xbmc playing a file self.logMsg("ONPLAYBACK_STOPPED", 2) utils.window('emby_customPlaylist', clear=True) utils.window('emby_playbackProps', clear=True) self.logMsg("Clear playlist properties.", 1) self.stopAll()
def watchlater(): """ Listing for plex.tv Watch Later section (if signed in to plex.tv) """ if window('plex_token') == '': log.error('No watch later - not signed in to plex.tv') return xbmcplugin.endOfDirectory(HANDLE, False) if window('plex_restricteduser') == 'true': log.error('No watch later - restricted user') return xbmcplugin.endOfDirectory(HANDLE, False) xml = downloadutils.DownloadUtils().downloadUrl( 'https://plex.tv/pms/playlists/queue/all', authenticate=False, headerOptions={'X-Plex-Token': window('plex_token')}) if xml in (None, 401): log.error('Could not download watch later list from plex.tv') return xbmcplugin.endOfDirectory(HANDLE, False) log.info('Displaying watch later plex.tv items') xbmcplugin.setContent(HANDLE, 'movies') for item in xml: __build_item(item) xbmcplugin.endOfDirectory( handle=HANDLE, cacheToDisc=settings('enableTextureCache') == 'true')
def play_all(self): """ Play all items contained in the xml passed in. Called by Plex Companion """ log.info("Playbackutils play_all called") window('plex_playbackProps', value="true") self.currentPosition = 0 for item in self.xml: api = API(item) successful = True if api.getType() == v.PLEX_TYPE_CLIP: self.add_trailer(item) else: with Get_Plex_DB() as plex_db: db_item = plex_db.getItem_byId(api.getRatingKey()) if db_item is not None: successful = add_item_to_kodi_playlist( self.playqueue, self.currentPosition, kodi_id=db_item[0], kodi_type=db_item[4]) if successful is True: self.currentPosition += 1 if len(item[0]) > 1: self.add_part(item, api, db_item[0], db_item[4]) else: # Item not in Kodi DB self.add_trailer(item) if successful is True: self.playqueue.items[self.currentPosition - 1].ID = item.get( '%sItemID' % self.playqueue.kind)
def externalSubs(self, playurl): externalsubs = [] mapping = {} itemid = self.API.getRatingKey() mediastreams = self.API.getMediaStreams() kodiindex = 0 for stream in mediastreams: index = stream['Index'] # Since Emby returns all possible tracks together, have to pull # only external subtitles. IsTextSubtitleStream if true, is # available to download from emby. if (stream['Type'] == "Subtitle" and stream['IsExternal'] and stream['IsTextSubtitleStream']): # Direct stream url = ("%s/Videos/%s/%s/Subtitles/%s/Stream.srt" % (self.server, itemid, itemid, index)) # map external subtitles for mapping mapping[kodiindex] = index externalsubs.append(url) kodiindex += 1 mapping = json.dumps(mapping) window('emby_%s.indexMapping' % playurl, value=mapping) return externalsubs
def watchlater(): """ Listing for plex.tv Watch Later section (if signed in to plex.tv) """ if window('plex_token') == '': log.error('No watch later - not signed in to plex.tv') return xbmcplugin.endOfDirectory(HANDLE, False) if window('plex_restricteduser') == 'true': log.error('No watch later - restricted user') return xbmcplugin.endOfDirectory(HANDLE, False) xml = downloadutils.DownloadUtils().downloadUrl( 'https://plex.tv/pms/playlists/queue/all', authenticate=False, headerOptions={'X-Plex-Token': window('plex_token')}) if xml in (None, 401): log.error('Could not download watch later list from plex.tv') return xbmcplugin.endOfDirectory(HANDLE, False) log.info('Displaying watch later plex.tv items') xbmcplugin.setContent(HANDLE, 'movies') for item in xml: __build_item(item) xbmcplugin.endOfDirectory( handle=HANDLE, cacheToDisc=settings('enableTextureCache') == 'true')
def onScanFinished(self, library): """ Will be called when Kodi finished scanning the library """ LOG.debug("Kodi library scan %s finished.", library) if library == "video": window('plex_kodiScan', clear=True)
def setUserPref(self): self.logMsg('Setting user preferences', 0) # Only try to get user avatar if there is a token if self.currToken: url = PlexAPI.PlexAPI().GetUserArtworkURL(self.currUser) if url: utils.window('EmbyUserImage', value=url)
def getXArgsDeviceInfo(self, options=None): """ Returns a dictionary that can be used as headers for GET and POST requests. An authentication option is NOT yet added. Inputs: options: dictionary of options that will override the standard header options otherwise set. Output: header dictionary """ # Get addon infos xargs = { 'Accept': '*/*', 'Connection': 'keep-alive', "Content-Type": "application/x-www-form-urlencoded", # "Access-Control-Allow-Origin": "*", # 'X-Plex-Language': 'en', 'X-Plex-Device': self.getAddonName(), 'X-Plex-Client-Platform': self.getPlatform(), 'X-Plex-Device-Name': self.getDeviceName(), 'X-Plex-Platform': self.getPlatform(), # 'X-Plex-Platform-Version': 'unknown', # 'X-Plex-Model': 'unknown', 'X-Plex-Product': self.getAddonName(), 'X-Plex-Version': self.getVersion(), 'X-Plex-Client-Identifier': self.getDeviceId(), 'X-Plex-Provides': 'player', } if window('pms_token'): xargs['X-Plex-Token'] = window('pms_token') if options is not None: xargs.update(options) return xargs
def playAll(self, items, startitem, offset): """ items: list of dicts of the form { 'playQueueItemID': Plex playQueueItemID, e.g. '29175' 'plexId': Plex ratingKey, e.g. '125' 'kodiId': Kodi's db id of the same item } startitem: tuple (typus, id), where typus is either 'playQueueItemID' or 'plexId' and id is the corresponding id as a string offset: First item's time offset to play in Kodi time (an int) """ log.info("---*** PLAY ALL ***---") log.debug('Startitem: %s, offset: %s, items: %s' % (startitem, offset, items)) self.items = items if self.playlist is None: self._initiatePlaylist() if self.playlist is None: log.error('Could not create playlist, abort') return window('plex_customplaylist', value="true") if offset != 0: # Seek to the starting position window('plex_customplaylist.seektime', str(offset)) self._processItems(startitem, startPlayer=True) # Log playlist self._verifyPlaylist() log.debug('Internal playlist: %s' % self.items)
def setUserPref(self): self.logMsg('Setting user preferences', 0) # Only try to get user avatar if there is a token if self.currToken: url = PlexAPI.PlexAPI().GetUserArtworkURL(self.currUser) if url: utils.window('PlexUserImage', value=url)
def _playstate(cls, data): command = data['Command'] player = xbmc.Player() actions = { 'Stop': player.stop, 'Unpause': player.pause, 'Pause': player.pause, 'NextTrack': player.playnext, 'PreviousTrack': player.playprevious } if command == 'Seek': if player.isPlaying(): seek_to = data['SeekPositionTicks'] seek_time = seek_to / 10000000.0 player.seekTime(seek_time) log.info("Seek to %s", seek_time) elif command in actions: actions[command]() log.info("Command: %s completed", command) else: log.info("Unknown command: %s", command) return window('emby_command', value="true")
def externalSubs(self, playurl): externalsubs = [] mapping = {} item = self.item itemid = item['Id'] try: mediastreams = item['MediaSources'][0]['MediaStreams'] except (TypeError, KeyError, IndexError): return kodiindex = 0 for stream in mediastreams: index = stream['Index'] # Since Emby returns all possible tracks together, have to pull only external subtitles. # IsTextSubtitleStream if true, is available to download from emby. if (stream['Type'] == "Subtitle" and stream['IsExternal'] and stream['IsTextSubtitleStream']): # Direct stream url = ("%s/Videos/%s/%s/Subtitles/%s/Stream.srt" % (self.server, itemid, itemid, index)) # map external subtitles for mapping mapping[kodiindex] = index externalsubs.append(url) kodiindex += 1 mapping = json.dumps(mapping) utils.window('emby_%s.indexMapping' % playurl, value=mapping) return externalsubs
def getToken(self): username = self.getUsername() userId = self.getUserId() w_token = window('emby_accessToken%s' % userId) s_token = settings('accessToken') # Verify the window property if w_token: if not s_token: # Save access token if it's missing from settings settings('accessToken', value=w_token) log( "Returning accessToken from WINDOW for username: %s accessToken: %s" % (username, w_token), 2) return w_token # Verify the settings elif s_token: log( "Returning accessToken from SETTINGS for username: %s accessToken: %s" % (username, s_token), 2) window('emby_accessToken%s' % username, value=s_token) return s_token else: log("No token found.", 1) return ""
def setUserPref(self): log.debug('Setting user preferences') # Only try to get user avatar if there is a token if self.currToken: url = PlexAPI.PlexAPI().GetUserArtworkURL(self.currUser) if url: window('PlexUserImage', value=url)
def playAll(self, items, startitem, offset): """ items: list of dicts of the form { 'playQueueItemID': Plex playQueueItemID, e.g. '29175' 'plexId': Plex ratingKey, e.g. '125' 'kodiId': Kodi's db id of the same item } startitem: tuple (typus, id), where typus is either 'playQueueItemID' or 'plexId' and id is the corresponding id as a string offset: First item's time offset to play in Kodi time (an int) """ log.info("---*** PLAY ALL ***---") log.debug('Startitem: %s, offset: %s, items: %s' % (startitem, offset, items)) self.items = items if self.playlist is None: self._initiatePlaylist() if self.playlist is None: log.error('Could not create playlist, abort') return window('plex_customplaylist', value="true") if offset != 0: # Seek to the starting position window('plex_customplaylist.seektime', str(offset)) self._processItems(startitem, startPlayer=True) # Log playlist self._verifyPlaylist() log.debug('Internal playlist: %s' % self.items)
def _action_menu(self): selected = self._selected_option if selected == OPTIONS['Transcode']: window('plex_forcetranscode', value='true') self._PMS_play() elif selected == OPTIONS['PMS_Play']: self._PMS_play() # elif selected == OPTIONS['Refresh']: # self.emby.refreshItem(self.item_id) # elif selected == OPTIONS['AddFav']: # self.emby.updateUserRating(self.item_id, favourite=True) # elif selected == OPTIONS['RemoveFav']: # self.emby.updateUserRating(self.item_id, favourite=False) # elif selected == OPTIONS['RateSong']: # self._rate_song() elif selected == OPTIONS['Addon']: xbmc.executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)') elif selected == OPTIONS['Delete']: self._delete_item()
def onNotification(self, sender, method, data): if method not in ('Playlist.OnAdd', 'Player.OnStop', 'Player.OnClear'): log.info("Method: %s Data: %s", method, data) try: if data: data = json.loads(data, 'utf-8') except: log.info("Error parsing message data: %s", data) return if method == 'Player.OnPlay': self._on_play_(data) elif method == 'VideoLibrary.OnUpdate': self._video_update(data) elif method == 'System.OnSleep': # Connection is going to sleep log.info("Marking the server as offline. System.OnSleep activated.") window('emby_online', value="sleep") elif method == 'System.OnWake': self._system_wake() elif method == 'GUI.OnScreensaverDeactivated': self._screensaver_deactivated()
def onSettingsChanged(self): """ Monitor the PKC settings for changes made by the user """ # settings: window-variable items = { 'logLevel': 'plex_logLevel', 'enableContext': 'plex_context', 'plex_restricteduser': '******', 'dbSyncIndicator': 'dbSyncIndicator', 'remapSMB': 'remapSMB', 'replaceSMB': 'replaceSMB', 'force_transcode_pix': 'plex_force_transcode_pix', 'fetch_pms_item_number': 'fetch_pms_item_number' } # Path replacement for typus in REMAP_TYPE_FROM_PLEXTYPE.values(): for arg in ('Org', 'New'): key = 'remapSMB%s%s' % (typus, arg) items[key] = key # Reset the window variables from the settings variables for settings_value, window_value in items.iteritems(): if window(window_value) != settings(settings_value): log.debug('PKC settings changed: %s is now %s' % (settings_value, settings(settings_value))) window(window_value, value=settings(settings_value)) if settings_value == 'fetch_pms_item_number': log.info('Requesting playlist/nodes refresh') window('plex_runLibScan', value="views")
def play_all(self): """ Play all items contained in the xml passed in. Called by Plex Companion """ log.info("Playbackutils play_all called") window('plex_playbackProps', value="true") self.currentPosition = 0 for item in self.xml: api = API(item) successful = True if api.getType() == v.PLEX_TYPE_CLIP: self.add_trailer(item) else: with Get_Plex_DB() as plex_db: db_item = plex_db.getItem_byId(api.getRatingKey()) if db_item is not None: successful = add_item_to_kodi_playlist( self.playqueue, self.currentPosition, kodi_id=db_item[0], kodi_type=db_item[4]) if successful is True: self.currentPosition += 1 if len(item[0]) > 1: self.add_part(item, api, db_item[0], db_item[4]) else: # Item not in Kodi DB self.add_trailer(item) if successful is True: self.playqueue.items[self.currentPosition - 1].ID = item.get( '%sItemID' % self.playqueue.kind)
def getPlayerProperties(self, playerid): info = {} try: # get info from the player props = self.js.jsonrpc("Player.GetProperties", {"playerid": playerid, "properties": ["time", "totaltime", "speed", "shuffled", "repeat"]}) self.logMsg(self.js.jsonrpc("Player.GetItem", {"playerid": playerid, "properties": ["file", "showlink", "episode", "season"]}), 2) info['time'] = timeToMillis(props['time']) info['duration'] = timeToMillis(props['totaltime']) info['state'] = ("paused", "playing")[int(props['speed'])] info['shuffle'] = ("0","1")[props.get('shuffled', False)] info['repeat'] = pf.getPlexRepeat(props.get('repeat')) # New PMS playQueue attributes cf = self.xbmcplayer.getPlayingFile() info['playQueueID'] = window('playQueueID') info['playQueueVersion'] = window('playQueueVersion') info['playQueueItemID'] = window('plex_%s.playQueueItemID' % cf) info['guid'] = window('plex_%s.guid' % cf) except: info['time'] = 0 info['duration'] = 0 info['state'] = "stopped" info['shuffle'] = False # get the volume from the application info['volume'] = self.volume info['mute'] = self.mute return info
def _playstate(cls, data): command = data['Command'] player = xbmc.Player() actions = { 'Stop': player.stop, 'Unpause': player.pause, 'Pause': player.pause, 'NextTrack': player.playnext, 'PreviousTrack': player.playprevious } if command == 'Seek': if player.isPlaying(): seek_to = data['SeekPositionTicks'] seek_time = seek_to / 10000000.0 player.seekTime(seek_time) log.info("Seek to %s", seek_time) elif command in actions: actions[command]() log.info("Command: %s completed", command) else: log.info("Unknown command: %s", command) return window('emby_command', value="true")
def __init__(self, header, errors): ''' Sets title of the dialog and fills the tree with information stored in given list of ErrorBox instances. ''' QtCore.QObject.__init__(self) elements = loadUi(self._DIALOG_UI, parent=window()) self._dialog = elements["dialog"] self._dialog.setWindowTitle(header) tree = elements["treeWidgetErrors"] items = [] for error in errors: item = QtGui.QTreeWidgetItem(tree) infos = [] fields = vars(error) for name in sorted(fields): if name != "traceback": infos.append(fields[name]) item.setText(0, ", ".join(infos)) QtGui.QTreeWidgetItem(item, [error.traceback]) item.setExpanded(True) items.append(item) tree.resizeColumnToContents(0) size = QtCore.QSize(min(window().size().width(), tree.columnWidth(0) + 40), min(window().size().height(), self._dialog.size().height())) self._dialog.resize(size) for item in items: item.setExpanded(False)
def run(self): # websocket.enableTrace(True) user_id = window('emby_currUser') server = window('emby_server%s' % user_id) token = window('emby_accessToken%s' % user_id) # Get the appropriate prefix for the websocket if "https" in server: server = server.replace('https', "wss") else: server = server.replace('http', "ws") websocket_url = "%s?api_key=%s&deviceId=%s" % (server, token, self.device_id) log.info("websocket url: %s", websocket_url) self._client = websocket.WebSocketApp(websocket_url, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close) self._client.on_open = self.on_open log.warn("----===## Starting WebSocketClient ##===----") while not self.monitor.abortRequested(): if window('emby_online') == "true": self._client.run_forever(ping_interval=10) if self._stop_websocket: break if self.monitor.waitForAbort(5): # Abort was requested, exit break log.warn("##===---- WebSocketClient Stopped ----===##")
def getDeviceId(self): clientId = utils.window('emby_deviceId') if clientId: return clientId addon_path = self.addon.getAddonInfo('path').decode('utf-8') GUID_file = xbmc.translatePath("%s\machine_guid" % addon_path).decode('utf-8') try: GUID = open(GUID_file) except IOError: # machine_guid does not exists. clientId = str("%012X" % uuid4()) GUID = open(GUID_file, 'w') GUID.write(clientId) else: # machine_guid already exists. Get guid. clientId = GUID.read() finally: GUID.close() self.logMsg("DeviceId loaded: %s" % clientId, 1) utils.window('emby_deviceId', value=clientId) return clientId
def onScanStarted(self, library): """ Will be called when Kodi starts scanning the library """ LOG.debug("Kodi library scan %s running.", library) if library == "video": window('plex_kodiScan', value="true")
def getDeviceId(self): clientId = utils.window('emby_deviceId') if clientId: return clientId addon_path = self.addon.getAddonInfo('path').decode('utf-8') if os.path.supports_unicode_filenames: GUID_file = xbmc.translatePath(os.path.join(addon_path, "machine_guid")).decode('utf-8') else: GUID_file = xbmc.translatePath(os.path.join(addon_path.encode("utf-8"), "machine_guid")).decode('utf-8') GUID = xbmcvfs.File(GUID_file) clientId = GUID.read() if not clientId: self.logMsg("Generating a new deviceid...", 1) clientId = str("%012X" % uuid4()) GUID = xbmcvfs.File(GUID_file, 'w') GUID.write(clientId) GUID.close() self.logMsg("DeviceId loaded: %s" % clientId, 1) utils.window('emby_deviceId', value=clientId) return clientId
def getXArgsDeviceInfo(options=None): """ Returns a dictionary that can be used as headers for GET and POST requests. An authentication option is NOT yet added. Inputs: options: dictionary of options that will override the standard header options otherwise set. Output: header dictionary """ xargs = { 'Accept': '*/*', 'Connection': 'keep-alive', "Content-Type": "application/x-www-form-urlencoded", # "Access-Control-Allow-Origin": "*", # 'X-Plex-Language': 'en', 'X-Plex-Device': v.ADDON_NAME, 'X-Plex-Client-Platform': v.PLATFORM, 'X-Plex-Device-Name': v.DEVICENAME, 'X-Plex-Platform': v.PLATFORM, # 'X-Plex-Platform-Version': 'unknown', # 'X-Plex-Model': 'unknown', 'X-Plex-Product': v.ADDON_NAME, 'X-Plex-Version': v.ADDON_VERSION, 'X-Plex-Client-Identifier': getDeviceId(), 'X-Plex-Provides': 'client,controller,player,pubsub-player', } if window('pms_token'): xargs['X-Plex-Token'] = window('pms_token') if options is not None: xargs.update(options) return xargs
def _report_progress(self): # Update and report playback progress kodi_player = self.kodi_player try: play_time = kodi_player.getTime() filename = kodi_player.currentFile # Update positionticks if filename in kodi_player.played_info: kodi_player.played_info[filename][ 'currentPosition'] = play_time difference = datetime.today() - self.last_progress difference_seconds = difference.seconds # Report progress to Emby server if difference_seconds > 3: kodi_player.reportPlayback() self.last_progress = datetime.today() elif window('emby_command') == "true": # Received a remote control command that # requires updating immediately window('emby_command', clear=True) kodi_player.reportPlayback() self.last_progress = datetime.today() except Exception as error: log.exception(error)
def getPlayUrlNew(self): ''' New style to retrieve the best playback method based on sending the profile to the server Based on capabilities the correct path is returned, including livestreams that need to be opened by the server TODO: Close livestream if needed (RequiresClosing in livestream source) ''' playurl = None pbinfo = self.getPlaybackInfo() if pbinfo: xbmc.log("getPlayUrl pbinfo: %s" %(pbinfo)) if pbinfo["Protocol"] == "SupportsDirectPlay": playmethod = "DirectPlay" elif pbinfo["Protocol"] == "SupportsDirectStream": playmethod = "DirectStream" elif pbinfo.get('LiveStreamId'): playmethod = "LiveStream" else: playmethod = "Transcode" playurl = pbinfo["Path"] xbmc.log("getPlayUrl playmethod: %s - playurl: %s" %(playmethod, playurl)) window('emby_%s.playmethod' % playurl, value=playmethod) if pbinfo["RequiresClosing"] and pbinfo.get('LiveStreamId'): window('emby_%s.livestreamid' % playurl, value=pbinfo["LiveStreamId"]) return playurl
def _video_update(self, data): # Manually marking as watched/unwatched try: item = data['item'] kodi_id = item['id'] item_type = item['type'] except (KeyError, TypeError): log.info("Item is invalid for playstate update") else: # Send notification to the server. item_id = self._get_item_id(kodi_id, item_type) if item_id: # Stop from manually marking as watched unwatched, with actual playback. if window('emby_skipWatched%s' % item_id) == "true": # property is set in player.py window('emby_skipWatched%s' % item_id, clear=True) else: # notify the server url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % item_id if data.get('playcount') != 0: self.download(url, action_type="POST") log.info("Mark as watched for itemid: %s", item_id) else: self.download(url, action_type="DELETE") log.info("Mark as unwatched for itemid: %s", item_id)
def __init__(self): self.__dict__ = self._shared_state client_info = clientinfo.ClientInfo() self.emby = embyserver.Read_EmbyServer() version = client_info.get_version() device_name = client_info.get_device_name() device_id = client_info.get_device_id() self._connect = connectionmanager.ConnectionManager(appName="Kodi", appVersion=version, deviceName=device_name, deviceId=device_id) path = xbmc.translatePath( "special://profile/addon_data/plugin.video.emby/").decode('utf-8') if not xbmcvfs.exists(path): xbmcvfs.mkdirs(path) self._connect.setFilePath(path) if window('emby_state.json'): self.state = window('emby_state.json') elif not self.state: self.state = self._connect.connect() log.info("Started with: %s", self.state) window('emby_state.json', value=self.state)
def __run(self): """ Do the work """ log.debug('Starting get metadata thread') # cache local variables because it's faster queue = self.queue out_queue = self.out_queue stopped = self.stopped while stopped() is False: # grabs Plex item from queue try: item = queue.get(block=False) # Empty queue except Empty: sleep(20) continue # Download Metadata xml = GetPlexMetadata(item['itemId']) if xml is None: # Did not receive a valid XML - skip that item for now log.error("Could not get metadata for %s. Skipping that item " "for now" % item['itemId']) # Increase BOTH counters - since metadata won't be processed with sync_info.LOCK: sync_info.GET_METADATA_COUNT += 1 sync_info.PROCESS_METADATA_COUNT += 1 queue.task_done() continue elif xml == 401: log.error('HTTP 401 returned by PMS. Too much strain? ' 'Cancelling sync for now') window('plex_scancrashed', value='401') # Kill remaining items in queue (for main thread to cont.) queue.task_done() break item['XML'] = xml if item.get('get_children') is True: children_xml = GetAllPlexChildren(item['itemId']) try: children_xml[0].attrib except (TypeError, IndexError, AttributeError): log.error('Could not get children for Plex id %s' % item['itemId']) item['children'] = [] else: item['children'] = children_xml # place item into out queue out_queue.put(item) # Keep track of where we are at with sync_info.LOCK: sync_info.GET_METADATA_COUNT += 1 # signals to queue job is done queue.task_done() # Empty queue in case PKC was shut down (main thread hangs otherwise) self.terminate_now() log.debug('Get metadata thread terminated')
def __init__(self, item): self.item = item self.API = PlexAPI.API(item) self.userid = window('currUserId') self.server = window('pms_server') self.machineIdentifier = window('plex_machineIdentifier')
def getUri(self): self.plex_client_Id = window('plex_client_Id') uri = ( 'wss://pubsub.plex.tv/sub/websockets/%s/%s?X-Plex-Token=%s' % (window('currUserId'), self.plex_client_Id, window('plex_token'))) sslopt = {} log.debug("Uri: %s, sslopt: %s" % (uri, sslopt)) return uri, sslopt
def resetAuth(): # User tried login and failed too many times resp = xbmcgui.Dialog().yesno(heading=lang(30132), line1=lang(33050)) if resp: log("Reset login attempts.", 1) window('emby_serverStatus', value="Auth") else: xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
def threadSuspended(self): """ Overwrite to ignore library sync stuff and allow to check for plex_restricteduser """ return (self._threadSuspended or window('plex_restricteduser') == 'true' or not window('plex_token'))
def resetAuth(): # User tried login and failed too many times resp = dialog('yesno', heading="{plex}", line1=lang(39206)) if resp == 1: log.info("Reset login attempts.") window('plex_serverStatus', value="Auth") else: executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
def GetSubFolders(nodeindex): nodetypes = ["",".recent",".recentepisodes",".inprogress",".inprogressepisodes",".unwatched",".nextepisodes",".sets",".genres",".random",".recommended"] for node in nodetypes: title = utils.window('Emby.nodes.%s%s.title' %(nodeindex,node)) if title: path = utils.window('Emby.nodes.%s%s.content' %(nodeindex,node)) addDirectoryItem(title, path) xbmcplugin.endOfDirectory(int(sys.argv[1]))
def __init__(self): self.clientInfo = clientinfo.ClientInfo() self.addonName = self.clientInfo.getAddonName() self.doUtils = downloadutils.DownloadUtils().downloadUrl self.userId = utils.window('emby_currUser') self.server = utils.window('emby_server%s' % self.userId)
def __init__(self, item): self.item = item self.clientInfo = clientinfo.ClientInfo() self.addonName = self.clientInfo.getAddonName() self.userid = utils.window('emby_currUser') self.server = utils.window('emby_server%s' % self.userid)
def __init__(self, item): self.item = item self.API = PlexAPI.API(item) self.userid = window('currUserId') self.server = window('pms_server') self.machineIdentifier = window('plex_machineIdentifier')
def resetAuth(): # User tried login and failed too many times resp = dialog('yesno', heading="{plex}", line1=lang(39206)) if resp == 1: log.info("Reset login attempts.") window('plex_serverStatus', value="Auth") else: executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
def threadSuspended(self): """ Overwrite to ignore library sync stuff and allow to check for plex_restricteduser """ return (self._threadSuspended or window('plex_restricteduser') == 'true' or not window('plex_token'))
def reset_server(self, server_id): # Reserved for userclient only for server in self.servers: if server['ServerId'] == server_id: self.servers.pop(server) window('emby_server%s.json' % server_id, clear=True) window('emby_server%s.name' % server_id, clear=True) log.info("removing %s from available servers", server_id)
def _server_restarting(cls): if settings('supressRestartMsg') == "true": dialog(type_="notification", heading="{emby}", message=lang(33006), icon="{emby}") window('emby_online', value="false")
def GetSubFolders(nodeindex): nodetypes = ["",".recent",".recentepisodes",".inprogress",".inprogressepisodes",".unwatched",".nextepisodes",".sets",".genres",".random",".recommended"] for node in nodetypes: title = window('Plex.nodes.%s%s.title' %(nodeindex,node)) if title: path = window('Plex.nodes.%s%s.content' %(nodeindex,node)) addDirectoryItem(title, path) xbmcplugin.endOfDirectory(HANDLE)
def __init__(self, item): self.item = item self.clientInfo = clientinfo.ClientInfo() self.addonName = self.clientInfo.getAddonName() self.userid = utils.window('emby_currUser') self.server = utils.window('emby_server%s' % self.userid)
def doMainListing(): xbmcplugin.setContent(int(sys.argv[1]), 'files') # Get emby nodes from the window props embyprops = window('Emby.nodes.total') if embyprops: totalnodes = int(embyprops) for i in range(totalnodes): path = window('Emby.nodes.%s.index' % i) if not path: path = window('Emby.nodes.%s.content' % i) label = window('Emby.nodes.%s.title' % i) node = 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: if xbmc.getCondVisibility("Window.IsActive(Pictures)") and node == "photos": addDirectoryItem(label, path) elif xbmc.getCondVisibility("Window.IsActive(Videos)") and node != "photos": addDirectoryItem(label, path) elif not xbmc.getCondVisibility("Window.IsActive(Videos) | Window.IsActive(Pictures) | Window.IsActive(Music)"): addDirectoryItem(label, path) # experimental live tv nodes if not xbmc.getCondVisibility("Window.IsActive(Pictures)"): addDirectoryItem(lang(33051), "plugin://emby.for.kodi/?mode=browsecontent&type=tvchannels&folderid=root") addDirectoryItem(lang(33052), "plugin://emby.for.kodi/?mode=browsecontent&type=recordings&folderid=root") ''' TODO: Create plugin listing for servers servers = window('emby_servers.json') if servers: for server in servers: log.info(window('emby_server%s.name' % server)) addDirectoryItem(window('emby_server%s.name' % server), "plugin://emby.for.kodi/?mode=%s" % server)''' addDirectoryItem(lang(30517), "plugin://emby.for.kodi/?mode=passwords") addDirectoryItem(lang(33053), "plugin://emby.for.kodi/?mode=settings") addDirectoryItem(lang(33054), "plugin://emby.for.kodi/?mode=adduser") addDirectoryItem(lang(33055), "plugin://emby.for.kodi/?mode=refreshplaylist") addDirectoryItem(lang(33056), "plugin://emby.for.kodi/?mode=manualsync") addDirectoryItem(lang(33057), "plugin://emby.for.kodi/?mode=repair") addDirectoryItem(lang(33058), "plugin://emby.for.kodi/?mode=reset") addDirectoryItem(lang(33059), "plugin://emby.for.kodi/?mode=texturecache") addDirectoryItem(lang(33060), "plugin://emby.for.kodi/?mode=thememedia") if settings('backupPath'): addDirectoryItem(lang(33092), "plugin://emby.for.kodi/?mode=backup") xbmcplugin.endOfDirectory(int(sys.argv[1]))
def __init__(self, item): self.item = item self.clientInfo = clientinfo.ClientInfo() self.userid = window('emby_currUser') self.server = window('emby_server%s' % self.userid) self.doUtils = downloadutils.DownloadUtils().downloadUrl
def run(self): LOG.info("----===## Starting UserClient ##===----") stopped = self.stopped suspended = self.suspended while not stopped(): while suspended(): if stopped(): break sleep(1000) if state.PMS_STATUS == "Stop": sleep(500) continue # Verify the connection status to server elif state.PMS_STATUS == "restricted": # Parental control is restricting access self.HasAccess = False elif state.PMS_STATUS == "401": # Unauthorized access, revoke token state.PMS_STATUS = 'Auth' window('plex_serverStatus', value='Auth') self.resetClient() sleep(3000) if self.auth and (self.currUser is None): # Try to authenticate user if not state.PMS_STATUS or state.PMS_STATUS == "Auth": # Set auth flag because we no longer need # to authenticate the user self.auth = False if self.authenticate(): # Successfully authenticated and loaded a user LOG.info("Successfully authenticated!") LOG.info("Current user: %s", self.currUser) LOG.info("Current userId: %s", state.PLEX_USER_ID) self.retry = 0 state.SUSPEND_LIBRARY_THREAD = False window('plex_serverStatus', clear=True) state.PMS_STATUS = False if not self.auth and (self.currUser is None): # Loop if no server found server = self.getServer() # The status Stop is for when user cancelled password dialog. # Or retried too many times if server and state.PMS_STATUS != "Stop": # Only if there's information found to login LOG.debug("Server found: %s", server) self.auth = True # Minimize CPU load sleep(100) LOG.info("##===---- UserClient Stopped ----===##")
def __init__(self): self.clientInfo = clientinfo.ClientInfo() self.addonName = self.clientInfo.getAddonName() self.userid = utils.window('emby_currUser') self.server = utils.window('emby_server%s' % self.userid) self.emby = embyserver.Read_EmbyServer()
def __init__(self): self.clientInfo = clientinfo.ClientInfo() self.addonName = self.clientInfo.getAddonName() self.userid = utils.window('emby_currUser') self.server = utils.window('emby_server%s' % self.userid) self.emby = embyserver.Read_EmbyServer()
def getUri(self): self.plex_client_Id = window('plex_client_Id') uri = ('wss://pubsub.plex.tv/sub/websockets/%s/%s?X-Plex-Token=%s' % (window('currUserId'), self.plex_client_Id, window('plex_token'))) sslopt = {} log.debug("Uri: %s, sslopt: %s" % (uri, sslopt)) return uri, sslopt
def GetSubFolders(nodeindex): nodetypes = ["",".recent",".recentepisodes",".inprogress",".inprogressepisodes",".unwatched",".nextepisodes",".sets",".genres",".random",".recommended"] for node in nodetypes: 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]))
def __init__(self, item): self.item = item self.API = PlexAPI.API(item) self.clientInfo = clientinfo.ClientInfo() self.userid = utils.window('currUserId') self.server = utils.window('pms_server') self.machineIdentifier = utils.window('plex_machineIdentifier')