def __init__(self, name, plex_url, plex_user, plex_password, plex_server, plex_token, verify_ssl): """Initialize the sensor.""" from plexapi.myplex import MyPlexAccount from plexapi.server import PlexServer from requests import Session self._name = name self._state = 0 self._now_playing = [] cert_session = None if not verify_ssl: _LOGGER.info("Ignoring SSL verification") cert_session = Session() cert_session.verify = False if plex_token: self._server = PlexServer(plex_url, plex_token, cert_session) elif plex_user and plex_password: user = MyPlexAccount(plex_user, plex_password) server = plex_server if plex_server else user.resources()[0].name self._server = user.resource(server).connect() else: self._server = PlexServer(plex_url, None, cert_session)
def checkPlexClientsActive(self): try: plex = PlexServer(self._baseurl, self._token) for client in plex.clients(): if client.isPlayingMedia(): return True except: pass return False
def __init__(self, language, plex_url, client_name): self.lang = language self.formatHelper = FormatHelper(language) self.plex = PlexServer(plex_url) self.client = self.plex.client(client_name) # last results for context awareness self.found_media = [] self.found_actions = [] self.last_request = [] self.last_picked = None # filter configuration self.filterable_in_episode = ['director', 'writer', 'year', 'decade'] self.filterable_in_show = ['actor', 'genre', 'contentRating'] self.filter_config = {'actor': self.formatHelper.filter_person, 'director': self.formatHelper.filter_person, 'writer': self.formatHelper.filter_person, 'producer': self.formatHelper.filter_person, 'year': self.formatHelper.filter_year, 'decade': self.formatHelper.filter_year, 'genre': self.formatHelper.filter_case_insensitive, 'country': self.formatHelper.filter_case_insensitive, 'contentRating': self.formatHelper.filter_case_insensitive} for section in self.plex.library.sections(): if section.TYPE == 'movie': self.movies = section elif section.TYPE == 'show': self.shows = section
def __init__(self, opts): self.opts = opts # command line options self.clsnames = [c for c in opts.clsnames.split(',') if c] # list of clsnames to report (blank=all) self.account = MyPlexAccount() # MyPlexAccount instance self.plex = PlexServer() # PlexServer instance self.total = 0 # Total objects parsed self.attrs = defaultdict(dict) # Attrs result set
def __init__(self, name, plex_url, plex_user, plex_password, plex_server, plex_token): """Initialize the sensor.""" from plexapi.myplex import MyPlexAccount from plexapi.server import PlexServer self._name = name self._state = 0 self._now_playing = [] if plex_token: self._server = PlexServer(plex_url, plex_token) elif plex_user and plex_password: user = MyPlexAccount(plex_user, plex_password) server = plex_server if plex_server else user.resources()[0].name self._server = user.resource(server).connect() else: self._server = PlexServer(plex_url)
def main(): """Main script""" global PLAYLISTS plex_server = PlexServer(PLEX_URL, PLEX_TOKEN) plex_users = get_user_tokens(plex_server.machineIdentifier) plex_users[plex_server.myPlexUsername] = plex_server._token plex_user = PlexServer(PLEX_URL, plex_users[FROM_USER]) plex_playlists = { playlist.title: playlist.items() for playlist in plex_user.playlists() } if not PLAYLISTS: PLAYLISTS = plex_playlists # Default to all playlists for playlist in PLAYLISTS: if playlist in SKIP_PLAYLISTS: print("Skipping '{playlist}'...".format(playlist=playlist)) continue playlist_items = plex_playlists.get(playlist) if not playlist_items: print("Playlist '{playlist}' not found on the server. Skipping.". format(playlist=playlist)) continue print("Cloning the '{title}' playlist...".format(title=playlist)) for user in TO_USERS: user_token = plex_users.get(user) if not user_token: print("...User '{user}' not found in shared users. Skipping.". format(user=user)) continue user_plex = PlexServer(PLEX_URL, user_token) # Delete the old playlist try: user_playlist = user_plex.playlist(playlist) user_playlist.delete() except: pass # Create a new playlist user_plex.createPlaylist(playlist, playlist_items) print("...Created playlist for '{user}'.".format(user=user)) return
def __init__(self): ## some initial tests if len(ppTagConfig.PLEX_TOKEN) == 0: # get a token try: account = MyPlexAccount(ppTagConfig.PLEX_LOGIN, ppTagConfig.PLEX_PASS) except Exception as e: raise("Error fetching from Plex API: {err}".format(err=e)) # print the Token and message to enter it here print('use this token') print (account.authenticationToken) print('and put it into the file config.py after PLEX_TOKEN: ') raise # some lists for data self.users = list() self.photoSections = list() self.serverId = '' # creating the client id self.clientId = uuid3(NAMESPACE_URL, "pptag").hex self.plex = PlexServer(ppTagConfig.PLEX_URL, ppTagConfig.PLEX_TOKEN) apiUsers = self.fetchPlexApi("/api/home/users","GET",True) userList = apiUsers['MediaContainer']['User'] if isinstance(userList, list): users = userList else: users = list() users.append(userList) for user in users: if isinstance(user, dict): if user['@title'] in ppTagConfig.USERDATA.keys(): pin = ppTagConfig.USERDATA.get(user['@title']) u = userData(user['@id'],user['@uuid'],user['@title'], pin) self.users.append(u) self.getAccessTokenForUser() for user in self.users: if user.token == '': print('no token found for user {user}'.format(user=user.title)) self.users.remove(user) # else: # print(user.title) # print(user.token) # print (plex.machineIdentifier) for section in self.plex.library.sections(): if section.type == 'photo': self.photoSections.append(section.key)
class PlexSensor(Entity): """Plex now playing sensor.""" # pylint: disable=too-many-arguments def __init__(self, name, plex_url, plex_user, plex_password, plex_server): """Initialize the sensor.""" from plexapi.utils import NA self._na_type = NA self._name = name self._state = 0 self._now_playing = [] if plex_user and plex_password: from plexapi.myplex import MyPlexAccount user = MyPlexAccount.signin(plex_user, plex_password) server = plex_server if plex_server else user.resources()[0].name self._server = user.resource(server).connect() else: from plexapi.server import PlexServer self._server = PlexServer(plex_url) self.update() @property def name(self): """Return the name of the sensor.""" return self._name @property def state(self): """Return the state of the sensor.""" return self._state @property def unit_of_measurement(self): """Return the unit this state is expressed in.""" return "Watching" @property def device_state_attributes(self): """Return the state attributes.""" return {content[0]: content[1] for content in self._now_playing} @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """Update method for plex sensor.""" sessions = self._server.sessions() now_playing = [] for sess in sessions: user = sess.user.title if sess.user is not self._na_type else "" title = sess.title if sess.title is not self._na_type else "" year = sess.year if sess.year is not self._na_type else "" now_playing.append((user, "{0} ({1})".format(title, year))) self._state = len(sessions) self._now_playing = now_playing
class PlexSensor(Entity): """Representation of a Plex now playing sensor.""" # pylint: disable=too-many-arguments def __init__(self, name, plex_url, plex_user, plex_password, plex_server): """Initialize the sensor.""" from plexapi.utils import NA from plexapi.myplex import MyPlexAccount from plexapi.server import PlexServer self._na_type = NA self._name = name self._state = 0 self._now_playing = [] if plex_user and plex_password: user = MyPlexAccount.signin(plex_user, plex_password) server = plex_server if plex_server else user.resources()[0].name self._server = user.resource(server).connect() else: self._server = PlexServer(plex_url) self.update() @property def name(self): """Return the name of the sensor.""" return self._name @property def state(self): """Return the state of the sensor.""" return self._state @property def unit_of_measurement(self): """Return the unit this state is expressed in.""" return "Watching" @property def device_state_attributes(self): """Return the state attributes.""" return {content[0]: content[1] for content in self._now_playing} @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """Update method for Plex sensor.""" sessions = self._server.sessions() now_playing = [] for sess in sessions: user = sess.username if sess.username is not self._na_type else "" title = sess.title if sess.title is not self._na_type else "" year = sess.year if sess.year is not self._na_type else "" now_playing.append((user, "{0} ({1})".format(title, year))) self._state = len(sessions) self._now_playing = now_playing
def __init__(self, name, plex_url, plex_user, plex_password, plex_server): """Initialize the sensor.""" from plexapi.utils import NA from plexapi.myplex import MyPlexAccount from plexapi.server import PlexServer self._na_type = NA self._name = name self._state = 0 self._now_playing = [] if plex_user and plex_password: user = MyPlexAccount.signin(plex_user, plex_password) server = plex_server if plex_server else user.resources()[0].name self._server = user.resource(server).connect() else: self._server = PlexServer(plex_url) self.update()
def __init__(self, base_url, token): self.base_url = base_url self.queue = list() self.queue_index = -1 self.play_queue_order = list() self.play_modes = TizEnumeration(["NORMAL", "SHUFFLE"]) self.current_play_mode = self.play_modes.NORMAL self.now_playing_track = None self._plex = PlexServer(base_url, token) self._music = self._plex.library.section('Music')
def plex_test(bot, trigger): try: baseurl = bot.config.plex.baseurl token = bot.config.plex.token plex = PlexServer(baseurl, token) return plex except requests.exceptions.ConnectionError: bot.reply("Plex server unreachable.") except plexapi.exceptions.Unauthorized: bot.reply("Bad Plex token configured.")
def __init__(self, meme): self.meme = meme self.userCooldown = [] self.api_token = config['Plex']['RadarrToken'] self.api_url_base = config['Plex']['RadarrURL'] self.plex_token = config['Plex']['PlexToken'] self.plex_baseurl = config['Plex']['PlexURL'] self.plex = PlexServer(self.plex_baseurl, self.plex_token)
def copyToUser(self, user): """ Copy playlist to another user account. """ from plexapi.server import PlexServer myplex = self._server.myPlexAccount() user = myplex.user(user) # Get the token for your machine. token = user.get_token(self._server.machineIdentifier) # Login to your server using your friends credentials. user_server = PlexServer(self._server._baseurl, token) return self.create(user_server, self.title, self.items())
def test_server_Server_query(pms): assert pms.query('/') from plexapi.server import PlexServer with pytest.raises(BadRequest): assert pms.query('/asdasdsada/12123127/aaaa', headers={'random_headers': '1337'}) with pytest.raises(NotFound): # This is really requests.exceptions.HTTPError: # 401 Client Error: Unauthorized for url: PlexServer('http://138.68.157.5:32400', '1234')
def list_libraries(): plex = PlexServer(CONFIG['plex_url'], CONFIG['plex_token']) plex_sections = plex.library.sections() for plex_section in plex_sections: if plex_section.type != 'movie': continue print('ID: %s Name: %s' % (str(plex_section.key).ljust(4, ' '), plex_section.title))
def get_plex(): global _plex_instance if not _plex_instance: session = requests.Session() if app.debug: # When we are running in debug mode, disable the (default) gzip encoding so we can better # observe the communicate with the Plex server session.headers['Accept-Encoding'] = 'default' _plex_instance = PlexServer(app.config['PLEX_URL'], app.config['PLEX_TOKEN'], session=session) return _plex_instance
def migrate(plex_url: str, plex_token: str, jellyfin_url: str, jellyfin_token: str, jellyfin_user: str, secure: bool, debug: bool, no_skip: bool): # Remove insecure request warnings if not secure: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Setup sessions session = requests.Session() session.verify = secure plex = PlexServer(plex_url, plex_token, session=session) jellyfin = JellyFinServer( url=jellyfin_url, api_key=jellyfin_token, session=session) # Watched list from Plex plex_watched = [] # Get all Plex watched movies plex_movies = plex.library.section('Films') for m in plex_movies.search(unwatched=False): info = _extract_provider(data=m.guid) info['title'] = m.title plex_watched.append(info) # Get all Plex watched episodes plex_tvshows = plex.library.section('TV Shows') plex_watched_episodes = [] for show in plex_tvshows.search(unwatched=False): for e in plex.library.section('TV Shows').get(show.title).episodes(): info = _extract_provider(data=m.guid) info['title'] = f"{show.title} {e.seasonEpisode.capitalize()} {e.title}" # s01e03 > S01E03 plex_watched.append(info) # This gets all jellyfin movies since filtering on provider id isn't supported: # https://github.com/jellyfin/jellyfin/issues/1990 jf_uid = jellyfin.get_user_id(name=jellyfin_user) jf_library = jellyfin.get_all(user_id=jf_uid) for watched in plex_watched: search_result = _search(jf_library, watched) if search_result and not search_result['UserData']['Played']: jellyfin.mark_watched( user_id=jf_uid, item_id=search_result['Id']) print(f"{bcolors.OKGREEN}Marked {watched['title']} as watched{bcolors.ENDC}") elif not search_result: print(f"{bcolors.WARNING}No matches for {watched['title']}{bcolors.ENDC}") if not skip: sys.exit(1) else: if debug: print(f"{bcolors.OKBLUE}{watched['title']}{bcolors.ENDC}") print(f"{bcolors.OKGREEN}Succesfully migrated {len(plex_watched)} items{bcolors.ENDC}")
def main(self): """Perform all search and print logic.""" for r in self.account.resources(): if r.product == "Plex Media Server": self.available_servers.append(r) for this_server in self.available_servers: if not this_server.presence: continue try: for connection in this_server.connections: if connection.local: continue this_server_connection = PlexServer( connection.uri, this_server.accessToken) relay_status = "" if connection.relay: if self.relay is False: log.debug( f"Skipping {this_server_connection.friendlyName} relay" ) continue else: relay_status = " (relay)" print("\n") print("=" * 79) print( f'Server: "{this_server_connection.friendlyName}"{relay_status}' ) # TODO: add flags for each media type to help sort down what is displayed (since /hub/seach?mediatype="foo" doesn't work) # TODO: write handlers for each type # TODO: save results to a native data structure and have different output methods (eg: json, download links, csv) for item in this_server_connection.search(self.title): self.print_all_items_for_server( self, item, this_server.accessToken) except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout) as e: print(f'ERROR: connection to "{this_server.name}" failed.') log.debug(e) continue
def __init__(self, name, plex_url, plex_user, plex_password, plex_server, plex_token, plex_machine_id): """Initialize the sensor.""" from plexapi.myplex import MyPlexAccount from plexapi.server import PlexServer self._name = name self._media_attrs = {} self._plex_machine_id = plex_machine_id self._player_state = 'idle' self._machineIdentifier = plex_machine_id self._device = None self._is_player_active = False self._is_player_available = False self._player = None self._make = 'AppleTV' self._session = None self._session_type = None self._session_username = None self._state = STATE_IDLE self._entity_picture = None self._plex_url = plex_url self._plex_token = plex_token self._media_content_id = None self._media_content_rating = None self._media_content_type = None self._media_duration = None self._media_image_url = None self._media_title = None self._media_ratio = None self._media_episode = None self._media_season = None self._media_series_title = None if plex_token: self._server = PlexServer(plex_url, plex_token) elif plex_user and plex_password: user = MyPlexAccount(plex_user, plex_password) server = plex_server if plex_server else user.resources()[0].name self._server = user.resource(server).connect() else: self._server = PlexServer(plex_url)
def connect_plex_server_by_url(req): try: server_url = req.form['server_url'] server_token = req.form['server_token'] plex = PlexServer(server_url, server_token) sections = plex.library.sections() return len(sections) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) return 'fail'
def init_client(self, conf): """ Create a http client for plex based on a password or token depending on conf file. If both are set we use the password. """ if conf.password is not None: account = MyPlexAccount(conf.user, conf.password) return account.resource(conf.host).connect() else: return PlexServer(conf.host, conf.token)
def get_movie(movie, url, token): results = PlexServer(url, token).search(movie["title"]) # return movie if it exists for plex_movie in results: if plex_movie.type == "movie" and str(plex_movie.year) in str( movie["year"]): return plex_movie return False
def connect(self): baseurl = 'http://{0}:{1}'.format(self._servername, self._port) try: self._plex = PlexServer(baseurl, self._token) except plexapi.exceptions.Unauthorized as e: logging.error('Authorization error when connecting to plex') raise e self._music = self._plex.library.section("Music")
def parse_data(self, data: dict): try: server = PlexServer( 'http://{0}:{1}'.format(self.config.PLEX_HOST, self.config.PLEX_PORT), self.config.PLEX_TOKEN) plex_data = server.search(data['title']) self.next_data = data.copy() if 'serial' in data.keys() and data['serial']: result = self.check_serials(plex_data, data) else: result = self.check_film(plex_data, data) return len(result) == 0 except Exception as ex: logger.debug(ex) self.next_data = data.copy() return True
def execute(): plex = PlexServer(settings.PLEX_URL, settings.PLEX_TOKEN) plex_sections = plex.library.sections() for plex_section in plex_sections: for collection in plex_section.collection(): if collection.childCount <= 1 and collection.title not in settings.IGNORE_SINGLE_VIDEO_COLLECTIONS: print("Removing collection: {title}".format( title=collection.title)) collection.delete()
def fetch_plex_instance(pi_dash, username=None, password=None, host=None): username = username or pi_dash.config.get('plexserver', 'username', from_keyring=True) password = password or pi_dash.config.get('plexserver', 'password', from_keyring=True) host = host or pi_dash.config.get('plexserver', 'host', '') if username: log.info('Logging into MyPlex with user %s', username) user = MyPlexAccount.signin(username, password) log.info('Connecting to Plex host: %s', host) return user.resource(host).connect() log.info('Connecting to Plex host: %s', host) return PlexServer(host)
def get_plexhistory(key): """ Fetch plex recently added. """ values = {'items': []} plex = PlexServer() config = _get_config() accounts = {a.accountID: a.name for a in plex.systemAccounts()} mindate = datetime.now() - timedelta(days=30) history = plex.history(150, mindate=mindate) for vdata in history: video = {} video['type'] = vdata.type video['viewed'] = _datetime_to_str(vdata.viewedAt) video['title'] = _video_title(vdata)[:15] video['account'] = accounts.get(vdata.accountID, 'Unknown') video['account'] = config.plexhistory_names.get( video['account'], video['account'])[:6] if not _ignored(video['account'], config.plexhistory_ignore): values['items'].append(video) values['total'] = len(values['items']) with open(join(CACHE, f'{key}.json'), 'w') as handle: json.dump(values, handle)
def test_server_Server_session(): # Mock Sesstion class MySession(Session): def __init__(self): super(self.__class__, self).__init__() self.plexapi_session_test = True # Test Code plex = PlexServer(utils.SERVER_BASEURL, utils.SERVER_TOKEN, session=MySession()) assert hasattr(plex._session, 'plexapi_session_test')
def __init__(self, config): """ __init__ """ token = config["Plex"]["token"] baseurl = "http://{0}:32400".format(config["Plex"]["ip"]) try: self.plex = PlexServer(baseurl, token) movie_continue = True except ConnectionError: print("Down") movie_continue = False if movie_continue: self.get_avail_movies()
def main(): logging.basicConfig(level=logging.INFO) secondsToWait = int(os.environ.get('SECONDS_TO_WAIT', 1800)) baseurl = os.environ.get('PLEX_URL') token = os.environ.get('PLEX_TOKEN') while True: plex = PlexServer(baseurl, token) client_credentials_manager = SpotifyClientCredentials() sp = spotipy.Spotify( client_credentials_manager=client_credentials_manager) runSync(plex, sp) time.sleep(secondsToWait)
def processEvent(payload): if not payload: logger.error("Empty payload. Early return.") return plex = PlexServer(os.environ["PLEXAPI_AUTH_SERVER_BASEURL"], os.environ["PLEXAPI_AUTH_SERVER_TOKEN"]) event_type = payload.get('event') if not event_type or event_type == '': logger.error("No event type") return logger.info(f'Processing {event_type} event.') # Do your thing
def auto_delete(): print('\n%s Starting plex-autodelete script..' % datestr()) plex = PlexServer() for section in plex.library.sections(): if section.type in ('show',): deleted = 0 for tag, keep in TAGS.items(): func = keep_season if keep == 'season' else keep_episodes for show in section.search(collection=tag): deleted += func(show, keep) if deleted: section.update()
def getPlexTracks(plex: PlexServer, spotifyTracks: []) -> List[Track]: plexTracks = [] for spotifyTrack in spotifyTracks: track = spotifyTrack['track'] logging.info("Searching Plex for: %s by %s" % (track['name'], track['artists'][0]['name'])) try: musicTracks = plex.search(track['name'], mediatype='track') except: try: musicTracks = plex.search(track['name'], mediatype='track') except: logging.info("Issue making plex request") continue if len(musicTracks) > 0: plexMusic = filterPlexArray(musicTracks, track['name'], track['artists'][0]['name']) if len(plexMusic) > 0: logging.info("Found Plex Song: %s by %s" % (track['name'], track['artists'][0]['name'])) plexTracks.append(plexMusic[0]) return plexTracks
def test_server_Server_session(account): # Mock Sesstion class MySession(Session): def __init__(self): super(self.__class__, self).__init__() self.plexapi_session_test = True # Test Code plex = PlexServer(utils.SERVER_BASEURL, account.authenticationToken, session=MySession()) assert hasattr(plex._session, "plexapi_session_test")
class Plex(object): def __init__(self, url, token): self.plex = PlexServer(url, token) def get_library(self, section_id): return self.plex.library.sectionByID(str(section_id)) def get_library_items(self, section_id): return self.get_library(str(section_id)).all() def get_item(self, rating_key): return self.plex.fetchItem(rating_key)
def sync_all(): global user_plex plex = PlexServer(PLEX_URL, PLEX_TOKEN) plex_users = get_user_tokens(plex.machineIdentifier) user_token = plex_users.get(FROM_USER) playlists_to_sync = get_playlists_from_user(user_token) for playlist in playlists_to_sync: playlist_items = playlist.items() for user in TO_USERS: user_token = plex_users.get(user) user_plex = PlexServer(PLEX_URL, user_token) # Delete the old playlist try: logging.info( f'Syncing Playlist {playlist.title} to user {user}') user_playlist = user_plex.playlist(playlist.title) user_playlist.delete() except Exception as e: logging.error(e) try: user_plex.createPlaylist(title=playlist.title, items=playlist_items) except Exception as e: logging.error(e)
def __init__(self, name, plex_url, plex_user, plex_password, plex_server): """Initialize the sensor.""" self._name = name self._state = 0 self._now_playing = [] if plex_user and plex_password: from plexapi.myplex import MyPlexUser user = MyPlexUser.signin(plex_user, plex_password) server = plex_server if plex_server else user.resources()[0].name self._server = user.getResource(server).connect() else: from plexapi.server import PlexServer self._server = PlexServer(plex_url) self.update()
class PlexAttributes(): def __init__(self, opts): self.opts = opts # command line options self.clsnames = [c for c in opts.clsnames.split(',') if c] # list of clsnames to report (blank=all) self.account = MyPlexAccount() # MyPlexAccount instance self.plex = PlexServer() # PlexServer instance self.total = 0 # Total objects parsed self.attrs = defaultdict(dict) # Attrs result set def run(self): starttime = time.time() self._parse_myplex() self._parse_server() self._parse_search() self._parse_library() self._parse_audio() self._parse_photo() self._parse_movie() self._parse_show() self._parse_client() self._parse_playlist() self._parse_sync() self.runtime = round((time.time() - starttime) / 60.0, 1) return self def _parse_myplex(self): self._load_attrs(self.account, 'myplex') self._load_attrs(self.account.devices(), 'myplex') for resource in self.account.resources(): self._load_attrs(resource, 'myplex') self._load_attrs(resource.connections, 'myplex') self._load_attrs(self.account.users(), 'myplex') def _parse_server(self): self._load_attrs(self.plex, 'serv') self._load_attrs(self.plex.account(), 'serv') self._load_attrs(self.plex.history()[:50], 'hist') self._load_attrs(self.plex.history()[50:], 'hist') self._load_attrs(self.plex.sessions(), 'sess') def _parse_search(self): for search in ('cre', 'ani', 'mik', 'she', 'bea'): self._load_attrs(self.plex.search(search), 'hub') def _parse_library(self): cat = 'lib' self._load_attrs(self.plex.library, cat) # self._load_attrs(self.plex.library.all()[:50], 'all') self._load_attrs(self.plex.library.onDeck()[:50], 'deck') self._load_attrs(self.plex.library.recentlyAdded()[:50], 'add') for search in ('cat', 'dog', 'rat', 'gir', 'mou'): self._load_attrs(self.plex.library.search(search)[:50], 'srch') # TODO: Implement section search (remove library search?) # TODO: Implement section search filters def _parse_audio(self): cat = 'lib' for musicsection in self.plex.library.sections(): if musicsection.TYPE == library.MusicSection.TYPE: self._load_attrs(musicsection, cat) for artist in musicsection.all(): self._load_attrs(artist, cat) for album in artist.albums(): self._load_attrs(album, cat) for track in album.tracks(): self._load_attrs(track, cat) def _parse_photo(self): cat = 'lib' for photosection in self.plex.library.sections(): if photosection.TYPE == library.PhotoSection.TYPE: self._load_attrs(photosection, cat) for photoalbum in photosection.all(): self._load_attrs(photoalbum, cat) for photo in photoalbum.photos(): self._load_attrs(photo, cat) def _parse_movie(self): cat = 'lib' for moviesection in self.plex.library.sections(): if moviesection.TYPE == library.MovieSection.TYPE: self._load_attrs(moviesection, cat) for movie in moviesection.all(): self._load_attrs(movie, cat) def _parse_show(self): cat = 'lib' for showsection in self.plex.library.sections(): if showsection.TYPE == library.ShowSection.TYPE: self._load_attrs(showsection, cat) for show in showsection.all(): self._load_attrs(show, cat) for season in show.seasons(): self._load_attrs(season, cat) for episode in season.episodes(): self._load_attrs(episode, cat) def _parse_client(self): for device in self.account.devices(): client = self._safe_connect(device) if client is not None: self._load_attrs(client, 'myplex') for client in self.plex.clients(): self._safe_connect(client) self._load_attrs(client, 'client') def _parse_playlist(self): for playlist in self.plex.playlists(): self._load_attrs(playlist, 'pl') for item in playlist.items(): self._load_attrs(item, 'pl') playqueue = PlayQueue.create(self.plex, playlist) self._load_attrs(playqueue, 'pq') def _parse_sync(self): # TODO: Get plexattrs._parse_sync() working. pass def _load_attrs(self, obj, cat=None): if isinstance(obj, (list, tuple)): return [self._parse_objects(item, cat) for item in obj] self._parse_objects(obj, cat) def _parse_objects(self, obj, cat=None): clsname = '%s.%s' % (obj.__module__, obj.__class__.__name__) clsname = clsname.replace('plexapi.', '') if self.clsnames and clsname not in self.clsnames: return None self._print_the_little_dot() if clsname not in self.attrs: self.attrs[clsname] = copy.deepcopy(NAMESPACE) self.attrs[clsname]['total'] += 1 self._load_xml_attrs(clsname, obj._data, self.attrs[clsname]['xml'], self.attrs[clsname]['examples'], self.attrs[clsname]['categories'], cat) self._load_obj_attrs(clsname, obj, self.attrs[clsname]['obj'], self.attrs[clsname]['docs']) def _print_the_little_dot(self): self.total += 1 if not self.total % 100: sys.stdout.write('.') if not self.total % 8000: sys.stdout.write('\n') sys.stdout.flush() def _load_xml_attrs(self, clsname, elem, attrs, examples, categories, cat): if elem is None: return None for attr in sorted(elem.attrib.keys()): attrs[attr] += 1 if cat: categories[attr].add(cat) if elem.attrib[attr] and len(examples[attr]) <= self.opts.examples: examples[attr].add(elem.attrib[attr]) for subelem in elem: attrname = TAGATTRS.get(subelem.tag, '%ss' % subelem.tag.lower()) attrs['%s[]' % attrname] += 1 def _load_obj_attrs(self, clsname, obj, attrs, docs): if clsname in STOP_RECURSING_AT: return None if isinstance(obj, PlexObject) and clsname not in DONT_RELOAD: self._safe_reload(obj) alldocs = '\n\n'.join(self._all_docs(obj.__class__)) for attr, value in obj.__dict__.items(): if value is None or isinstance(value, (str, bool, float, int, datetime)): if not attr.startswith('_') and attr not in IGNORES.get(clsname, []): attrs[attr] += 1 if re.search('\s{8}%s\s\(.+?\)\:' % attr, alldocs) is not None: docs[attr] += 1 if isinstance(value, list): if not attr.startswith('_') and attr not in IGNORES.get(clsname, []): if value and isinstance(value[0], PlexObject): attrs['%s[]' % attr] += 1 [self._parse_objects(obj) for obj in value] def _all_docs(self, cls, docs=None): import inspect docs = docs or [] if cls.__doc__ is not None: docs.append(cls.__doc__) for parent in inspect.getmro(cls): if parent != cls: docs += self._all_docs(parent) return docs def print_report(self): total_attrs = 0 for clsname in sorted(self.attrs.keys()): if self._clsname_match(clsname): meta = self.attrs[clsname] count = meta['total'] print(_('\n%s (%s)\n%s' % (clsname, count, '-' * 30), 'yellow')) attrs = sorted(set(list(meta['xml'].keys()) + list(meta['obj'].keys()))) for attr in attrs: state = self._attr_state(clsname, attr, meta) count = meta['xml'].get(attr, 0) categories = ','.join(meta['categories'].get(attr, ['--'])) examples = '; '.join(list(meta['examples'].get(attr, ['--']))[:3])[:80] print('%7s %3s %-30s %-20s %s' % (count, state, attr, categories, examples)) total_attrs += count print(_('\nSUMMARY\n%s' % ('-' * 30), 'yellow')) print('%7s %3s %3s %3s %-20s %s' % ('total', 'new', 'old', 'doc', 'categories', 'clsname')) for clsname in sorted(self.attrs.keys()): if self._clsname_match(clsname): print('%7s %12s %12s %12s %s' % (self.attrs[clsname]['total'], _(self.attrs[clsname]['new'] or '', 'cyan'), _(self.attrs[clsname]['old'] or '', 'red'), _(self.attrs[clsname]['doc'] or '', 'purple'), clsname)) print('\nPlex Version %s' % self.plex.version) print('PlexAPI Version %s' % plexapi.VERSION) print('Total Objects %s' % sum([x['total'] for x in self.attrs.values()])) print('Runtime %s min\n' % self.runtime) def _clsname_match(self, clsname): if not self.clsnames: return True for cname in self.clsnames: if cname.lower() in clsname.lower(): return True return False def _attr_state(self, clsname, attr, meta): if attr in meta['xml'].keys() and attr not in meta['obj'].keys(): self.attrs[clsname]['new'] += 1 return _('new', 'blue') if attr not in meta['xml'].keys() and attr in meta['obj'].keys(): self.attrs[clsname]['old'] += 1 return _('old', 'red') if attr not in meta['docs'].keys() and attr in meta['obj'].keys(): self.attrs[clsname]['doc'] += 1 return _('doc', 'purple') return _(' ', 'green') def _safe_connect(self, elem): try: return elem.connect() except: return None def _safe_reload(self, elem): try: elem.reload() except: pass
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Listen to plex alerts and print them to the console. Because we're using print as a function, example only works in Python3. """ import time from plexapi.server import PlexServer def _print(msg): print(msg) if __name__ == '__main__': try: plex = PlexServer() listener = plex.startAlertListener(_print) while True: time.sleep(1) except KeyboardInterrupt: listener.stop()
class Remote: def __init__(self, language, plex_url, client_name): self.lang = language self.formatHelper = FormatHelper(language) self.plex = PlexServer(plex_url) self.client = self.plex.client(client_name) # last results for context awareness self.found_media = [] self.found_actions = [] self.last_request = [] self.last_picked = None # filter configuration self.filterable_in_episode = ['director', 'writer', 'year', 'decade'] self.filterable_in_show = ['actor', 'genre', 'contentRating'] self.filter_config = {'actor': self.formatHelper.filter_person, 'director': self.formatHelper.filter_person, 'writer': self.formatHelper.filter_person, 'producer': self.formatHelper.filter_person, 'year': self.formatHelper.filter_year, 'decade': self.formatHelper.filter_year, 'genre': self.formatHelper.filter_case_insensitive, 'country': self.formatHelper.filter_case_insensitive, 'contentRating': self.formatHelper.filter_case_insensitive} for section in self.plex.library.sections(): if section.TYPE == 'movie': self.movies = section elif section.TYPE == 'show': self.shows = section def execute(self, text): print(text) commands = self.lang.match(text.lower()) self.search(commands) self.filter_highest_priority() return self.execute_actions() def search(self, commands): self.found_media = [] self.found_actions = [] threads = [] for priority, matched in commands: search_actions = [action for action in ['play', 'navigate', 'follow_up'] if action in matched] direct_actions = [action for action in ['another_one', 'play_it', 'main_menu', 'subtitle_on', 'subtitle_off', 'subtitle_toggle', 'language_toggle', 'osd', 'jump_forward', 'jump_backward', 'pause', 'play_after_pause'] if action in matched] if direct_actions: self.found_media.append((priority, direct_actions, None)) else: if 'movie' in matched: function = self.search_movies elif 'tv' in matched: function = self.search_episodes else: function = self.search_general thr = threading.Thread(target=function, args=[matched, priority, search_actions]) threads.append(thr) thr.start() for thr in threads: thr.join() def search_movies(self, matched, priority, actions): title = matched.get('title') if 'unseen' in matched: movie_filter = 'unwatched' else: movie_filter = 'all' multi_filters = self.create_filter(self.movies, matched) if multi_filters: results = self.movies.search(title, filter=movie_filter, **multi_filters.pop()) for filters in multi_filters: filter_results = self.movies.search(title, filter=movie_filter, **filters) results = [result for result in results if result in filter_results] for video in self.post_filter(matched, results): self.found_media.append((priority, actions, video)) def search_episodes(self, matched, priority, actions): title = matched.get('title') season = matched.get('season') if 'unseen' in matched: watched_filter = 'unwatched' matched['oldest'] = None else: watched_filter = 'all' show_multi_filters = self.create_filter(self.shows, filter_dict(matched, self.filterable_in_show)) episode_multi_filters = self.create_filter(self.shows, filter_dict(matched, self.filterable_in_episode)) if show_multi_filters is None or episode_multi_filters is None: return episode_set = [] used_episode_filter = False if episode_multi_filters[0]: used_episode_filter = True episode_set = self.shows.searchEpisodes(None, filter=watched_filter, **episode_multi_filters.pop()) for filters in episode_multi_filters: filter_episode_set = self.shows.searchEpisodes(title, filter=watched_filter, **filters) episode_set = [result for result in episode_set if result in filter_episode_set] results = [] used_show_filter = False if show_multi_filters[0] or season or not used_episode_filter or title or watched_filter == 'unwatched': used_show_filter = True show_set = self.shows.search(title, filter=watched_filter, **show_multi_filters.pop()) for filters in show_multi_filters: filter_show_set = self.shows.search(title, filter=watched_filter, **filters) show_set = [result for result in show_set if result in filter_show_set] for show in show_set: if season: show = show.season(self.formatHelper.season_format(season)) res = show.episodes(watched='unseen' not in matched) results += self.post_filter(matched, res) if used_episode_filter: if used_show_filter: results = [result for result in results if result in episode_set] else: results = episode_set results = self.post_filter(matched, results) for video in results: self.found_media.append((priority, actions, video)) def search_general(self, matched, priority, actions): title = matched.get('title') results = self.plex.search(title) results = self.post_filter(matched, results) for video in results: self.found_media.append((priority, actions, video)) def create_filter(self, library, matched): multi_filter = [{}] for key, filter_method in self.filter_config.iteritems(): entities = matched.get(key) if entities: server_entities = getattr(library, 'get_' + key)() for index, entity in enumerate(entities.split(self.lang.and_phrase())): res = filter_method(server_entities, entity) if res: if len(multi_filter) <= index: multi_filter.append(multi_filter[0].copy()) filters = multi_filter[index] filters[key] = res else: return None return multi_filter @staticmethod def post_filter(matched, results): if 'higher_rating' in matched and results: border = float(matched['higher_rating']) results = [video for video in results if hasattr(video, 'rating') and float(video.rating) > border] if 'lower_rating' in matched and results: border = float(matched['lower_rating']) results = [video for video in results if hasattr(video, 'rating') and float(video.rating) < border] if 'newest' in matched and len(results) > 1: newest = results[0] newest_date = datetime(1, 1, 1) for video in results: if hasattr(video, 'originallyAvailableAt') and video.originallyAvailableAt > newest_date: newest_date = video.originallyAvailableAt newest = video return [newest] if 'oldest' in matched and len(results) > 1: oldest = results[0] oldest_date = datetime(9999, 1, 1) for video in results: if hasattr(video, 'originallyAvailableAt') and video.originallyAvailableAt < oldest_date: oldest_date = video.originallyAvailableAt oldest = video return [oldest] return results def filter_highest_priority(self): highest_priority = -1 for priority, actions, media in self.found_media: highest_priority = max(priority, highest_priority) filtered = [] highest_priority_actions = [] for priority, actions, media in self.found_media: if priority == highest_priority: highest_priority_actions += actions filtered.append(media) self.found_actions = highest_priority_actions self.found_media = filtered def execute_actions(self): if self.found_actions: print(self.found_actions[0]) # direct actions if 'main_menu' in self.found_actions: self.client.stop() if 'subtitle_on' in self.found_actions: self.client.subtitle('on') if 'subtitle_off' in self.found_actions: self.client.subtitle('off') if 'subtitle_toggle' in self.found_actions: self.client.subtitle('next') if 'language_toggle' in self.found_actions: self.client.switch_language() if 'osd' in self.found_actions: self.client.toggleOSD() if 'jump_forward' in self.found_actions: self.client.stepForward() if 'jump_backward' in self.found_actions: self.client.stepBack() if 'pause' in self.found_actions: self.client.pause() if 'play_after_pause' in self.found_actions: self.client.play() if 'another_one' in self.found_actions: self.last_picked = self.pick_another_one() if self.last_picked: self.client.navigate(self.last_picked) if 'play_it' in self.found_actions: if self.last_picked: self.client.playMedia(self.last_picked) # search actions if 'follow_up' in self.found_actions or 'play' in self.found_actions or 'navigate' in self.found_actions: if 'follow_up' in self.found_actions: self.found_media = [f for f in self.found_media if f in self.last_request] self.last_picked = self.pick_one() self.last_request = self.found_media if self.last_picked: if 'play' in self.found_actions: print('play ' + str(self.last_picked)) self.client.playMedia(self.last_picked) elif 'navigate' in self.found_actions: print('go to ' + str(self.last_picked)) self.client.navigate(self.last_picked) return len(self.found_actions) > 0 def pick_one(self): if len(self.found_media) == 0: return None pos = Random().randint(0, len(self.found_media) - 1) return self.found_media[pos] def pick_another_one(self): if len(self.last_request) == 0: return None if len(self.last_request) == 1: return self.last_request[0] video = None while not video or video == self.last_picked: video = self.last_request[Random().randint(0, len(self.last_request) - 1)] return video
class PlexSensor(Entity): """Representation of a Plex now playing sensor.""" def __init__(self, name, plex_url, plex_user, plex_password, plex_server, plex_token): """Initialize the sensor.""" from plexapi.myplex import MyPlexAccount from plexapi.server import PlexServer self._name = name self._state = 0 self._now_playing = [] if plex_token: self._server = PlexServer(plex_url, plex_token) elif plex_user and plex_password: user = MyPlexAccount(plex_user, plex_password) server = plex_server if plex_server else user.resources()[0].name self._server = user.resource(server).connect() else: self._server = PlexServer(plex_url) @property def name(self): """Return the name of the sensor.""" return self._name @property def state(self): """Return the state of the sensor.""" return self._state @property def unit_of_measurement(self): """Return the unit this state is expressed in.""" return "Watching" @property def device_state_attributes(self): """Return the state attributes.""" return {content[0]: content[1] for content in self._now_playing} @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """Update method for Plex sensor.""" sessions = self._server.sessions() now_playing = [] for sess in sessions: user = sess.usernames[0] device = sess.players[0].title now_playing_user = "******".format(user, device) now_playing_title = "" if sess.TYPE == 'episode': # example: # "Supernatural (2005) - S01 · E13 - Route 666" season_title = sess.grandparentTitle if sess.show().year is not None: season_title += " ({0})".format(sess.show().year) season_episode = "S{0}".format(sess.parentIndex) if sess.index is not None: season_episode += " · E{0}".format(sess.index) episode_title = sess.title now_playing_title = "{0} - {1} - {2}".format(season_title, season_episode, episode_title) elif sess.TYPE == 'track': # example: # "Billy Talent - Afraid of Heights - Afraid of Heights" track_artist = sess.grandparentTitle track_album = sess.parentTitle track_title = sess.title now_playing_title = "{0} - {1} - {2}".format(track_artist, track_album, track_title) else: # example: # "picture_of_last_summer_camp (2015)" # "The Incredible Hulk (2008)" now_playing_title = sess.title if sess.year is not None: now_playing_title += " ({0})".format(sess.year) now_playing.append((now_playing_user, now_playing_title)) self._state = len(sessions) self._now_playing = now_playing
class tizplexproxy(object): """A class that accesses Plex servers, retrieves track URLs and creates and manages a playback queue. """ def __init__(self, base_url, token): self.base_url = base_url self.queue = list() self.queue_index = -1 self.play_queue_order = list() self.play_modes = TizEnumeration(["NORMAL", "SHUFFLE"]) self.current_play_mode = self.play_modes.NORMAL self.now_playing_track = None self._plex = PlexServer(base_url, token) self._music = self._plex.library.section('Music') def set_play_mode(self, mode): """ Set the playback mode. :param mode: current valid values are "NORMAL" and "SHUFFLE" """ self.current_play_mode = getattr(self.play_modes, mode) self.__update_play_queue_order() def enqueue_audio_tracks(self, arg): """Search the Plex server for audio tracks and add them to the playback queue. :param arg: a search string """ logging.info('arg : %s', arg) print_msg("[Plex] [Track search in server] : '{0}'. " \ .format(self.base_url)) try: count = len(self.queue) try: tracks = self._music.searchTracks(title=arg) for track in tracks: track_info = TrackInfo(track, track.artist(), track.album()) self.add_to_playback_queue(track_info) except (NotFound): pass if count == len(self.queue): tracks = self._music.search(libtype='track') for track in tracks: track_name = track.title if fuzz.partial_ratio(arg, track_name) > 60: track_info = TrackInfo(track, track.artist(), track.album()) self.add_to_playback_queue(track_info) if count == len(self.queue): raise ValueError self.__update_play_queue_order() except ValueError: raise ValueError(str("Track not found : %s" % arg)) def enqueue_audio_artist(self, arg): """Obtain an artist from the Plex server and add all the artist's audio tracks to the playback queue. :param arg: an artist search term """ logging.info('arg : %s', arg) print_msg("[Plex] [Artist search in server] : '{0}'. " \ .format(self.base_url)) try: count = len(self.queue) artist = None artist_name = '' try: artists = self._music.searchArtists(title=arg) for artist in artists: artist_name = artist.title print_wrn("[Plex] Playing '{0}'." \ .format(artist_name.encode('utf-8'))) for album in artist.albums(): for track in album.tracks(): track_info = TrackInfo(track, artist, album) self.add_to_playback_queue(track_info) except (NotFound): pass if count == len(self.queue): artist_dict = dict() artist_names = list() artists = self._music.search(libtype='artist') for art in artists: artist_names.append(art.title) artist_dict[art.title] = art if len(artist_names) > 1: artist_name = process.extractOne(arg, artist_names)[0] artist = artist_dict[artist_name] elif len(artist_names) == 1: artist_name = artist_names[0] artist = artist_dict[artist_name] if artist: print_wrn("[Plex] '{0}' not found. " \ "Playing '{1}' instead." \ .format(arg.encode('utf-8'), \ artist_name.encode('utf-8'))) for album in artist.albums(): for track in album.tracks(): track_info = TrackInfo(track, artist, album) self.add_to_playback_queue(track_info) if count == len(self.queue): raise ValueError self.__update_play_queue_order() except ValueError: raise ValueError(str("Artist not found : %s" % arg)) def enqueue_audio_album(self, arg): """Obtain an album from the Plex server and add all its tracks to the playback queue. :param arg: an album search term """ logging.info('arg : %s', arg) print_msg("[Plex] [Album search in server] : '{0}'. " \ .format(self.base_url)) try: count = len(self.queue) album = None album_name = '' try: albums = self._music.searchAlbums(title=arg) for album in albums: album_name = album.title print_wrn("[Plex] Playing '{0}'." \ .format(album_name.encode('utf-8'))) for track in album.tracks(): track_info = TrackInfo(track, track.artist(), album) self.add_to_playback_queue(track_info) except (NotFound): pass if count == len(self.queue): album_dict = dict() album_names = list() albums = self._music.search(libtype='album') for alb in albums: album_names.append(alb.title) album_dict[alb.title] = alb if len(album_names) > 1: album_name = process.extractOne(arg, album_names)[0] album = album_dict[album_name] elif len(album_names) == 1: album_name = album_names[0] album = album_dict[album_name] if album: print_wrn("[Plex] '{0}' not found. " \ "Playing '{1}' instead." \ .format(arg.encode('utf-8'), \ album_name.encode('utf-8'))) for track in album.tracks(): track_info = TrackInfo(track, album, album) self.add_to_playback_queue(track_info) if count == len(self.queue): raise ValueError self.__update_play_queue_order() except ValueError: raise ValueError(str("Album not found : %s" % arg)) def enqueue_audio_playlist(self, arg): """Add all audio tracks in a Plex playlist to the playback queue. :param arg: a playlist search term """ logging.info('arg : %s', arg) print_msg("[Plex] [Playlist search in server] : '{0}'. " \ .format(self.base_url)) try: count = len(self.queue) playlist_title = '' playlist = None try: playlist = self._plex.playlist(title=arg) if playlist: playlist_title = playlist.title print_wrn("[Plex] Playing '{0}'." \ .format(playlist_title.encode('utf-8'))) for item in playlist.items(): if item.TYPE == 'track': track = item track_info = TrackInfo(track, track.artist(), \ track.album()) self.add_to_playback_queue(track_info) if count == len(self.queue): print_wrn("[Plex] '{0}' No audio tracks found." \ .format(playlist_title.encode('utf-8'))) raise ValueError except (NotFound): pass if count == len(self.queue): playlist_dict = dict() playlist_titles = list() playlists = self._plex.playlists() for pl in playlists: playlist_titles.append(pl.title) playlist_dict[pl.title] = pl if len(playlist_titles) > 1: playlist_title = process.extractOne(arg, playlist_titles)[0] playlist = playlist_dict[playlist_title] elif len(playlist_titles) == 1: playlist_title = playlist_titles[0] playlist = playlist_dict[playlist_title] if playlist: print_wrn("[Plex] '{0}' not found. " \ "Playing '{1}' instead." \ .format(arg.encode('utf-8'), \ playlist_title.encode('utf-8'))) for item in playlist.items(): if item.TYPE == 'track': track = item track_info = TrackInfo(track, track.artist(), \ track.album()) self.add_to_playback_queue(track_info) if count == len(self.queue): print_wrn("[Plex] '{0}' No audio tracks found." \ .format(playlist_title.encode('utf-8'))) if count == len(self.queue): raise ValueError self.__update_play_queue_order() except (ValueError, NotFound): raise ValueError(str("Playlist not found or no audio tracks in playlist : %s" % arg)) def current_audio_track_title(self): """ Retrieve the current track's title. """ track = self.now_playing_track title = '' if track: title = to_ascii(track.title).encode("utf-8") return title def current_audio_track_artist(self): """ Retrieve the current track's artist. """ track = self.now_playing_track artist = '' if track: artist = to_ascii(track.artist).encode("utf-8") return artist def current_audio_track_album(self): """ Retrieve the current track's album. """ track = self.now_playing_track album = '' if track: album = to_ascii(track.album).encode("utf-8") return album def current_audio_track_year(self): """ Retrieve the current track's publication year. """ track = self.now_playing_track year = 0 if track: year = track.year return year def current_audio_track_file_size(self): """ Retrieve the current track's file size. """ track = self.now_playing_track size = 0 if track: size = track.size return size def current_audio_track_duration(self): """ Retrieve the current track's duration. """ track = self.now_playing_track duration = 0 if track: duration = track.duration return duration def current_audio_track_bitrate(self): """ Retrieve the current track's bitrate. """ track = self.now_playing_track bitrate = 0 if track: bitrate = track.bitrate return bitrate def current_audio_track_codec(self): """ Retrieve the current track's codec. """ track = self.now_playing_track codec = '' if track: codec = to_ascii(track.codec).encode("utf-8") return codec def current_audio_track_album_art(self): """ Retrieve the current track's album_art. """ track = self.now_playing_track album_art = '' if track: album_art = to_ascii(track.thumb_url).encode("utf-8") return album_art def current_audio_track_queue_index_and_queue_length(self): """ Retrieve index in the queue (starting from 1) of the current track and the length of the playback queue. """ return self.play_queue_order[self.queue_index] + 1, len(self.queue) def clear_queue(self): """ Clears the playback queue. """ self.queue = list() self.queue_index = -1 def remove_current_url(self): """Remove the currently active url from the playback queue. """ logging.info("") if len(self.queue) and self.queue_index: track = self.queue[self.queue_index] print_nfo("[Plex] [Track] '{0}' removed." \ .format(to_ascii(track['i'].title).encode("utf-8"))) del self.queue[self.queue_index] self.queue_index -= 1 if self.queue_index < 0: self.queue_index = 0 self.__update_play_queue_order() def next_url(self): """ Retrieve the url of the next track in the playback queue. """ logging.info("") try: if len(self.queue): self.queue_index += 1 if (self.queue_index < len(self.queue)) \ and (self.queue_index >= 0): next_track = self.queue[self.play_queue_order \ [self.queue_index]] return self.__retrieve_track_url(next_track) else: self.queue_index = -1 return self.next_url() else: return '' except (KeyError, AttributeError): # TODO: We don't remove this for now # del self.queue[self.queue_index] logging.info("exception") return self.next_url() def prev_url(self): """ Retrieve the url of the previous track in the playback queue. """ logging.info("") try: if len(self.queue): self.queue_index -= 1 if (self.queue_index < len(self.queue)) \ and (self.queue_index >= 0): prev_track = self.queue[self.play_queue_order \ [self.queue_index]] return self.__retrieve_track_url(prev_track) else: self.queue_index = len(self.queue) return self.prev_url() else: return '' except (KeyError, AttributeError): # TODO: We don't remove this for now # del self.queue[self.queue_index] logging.info("exception") return self.prev_url() def __update_play_queue_order(self): """ Update the queue playback order. A sequential order is applied if the current play mode is "NORMAL" or a random order if current play mode is "SHUFFLE" """ total_tracks = len(self.queue) if total_tracks: if not len(self.play_queue_order): # Create a sequential play order, if empty self.play_queue_order = range(total_tracks) if self.current_play_mode == self.play_modes.SHUFFLE: random.shuffle(self.play_queue_order) print_nfo("[Plex] [Tracks in queue] '{0}'." \ .format(total_tracks)) def __retrieve_track_url(self, track): """ Retrieve a track url """ try: self.now_playing_track = track return track.url.encode("utf-8") except AttributeError: logging.info("Could not retrieve the track url!") raise def add_to_playback_queue(self, track): """ Add to the playback queue. """ print_nfo("[Plex] [Track] '{0}' [{1}]." \ .format(to_ascii(track.title).encode("utf-8"), \ to_ascii(track.codec))) queue_index = len(self.queue) self.queue.append(track)