Example #1
0
    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)
Example #2
0
 def checkPlexClientsActive(self):
     try:
         plex = PlexServer(self._baseurl, self._token)
         for client in plex.clients():
             if client.isPlayingMedia():
                 return True
     except:
         pass
     return False
Example #3
0
    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
Example #4
0
 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
Example #5
0
    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
Example #7
0
    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)
Example #8
0
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
Example #9
0
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
Example #10
0
    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')
Example #12
0
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.")
Example #13
0
    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)
Example #14
0
 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())
Example #15
0
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')
Example #16
0
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))
Example #17
0
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
Example #18
0
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}")
Example #19
0
    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)
Example #21
0
 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'
Example #22
0
 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)
Example #23
0
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
Example #24
0
    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")
Example #25
0
    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()
Example #27
0
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)
Example #28
0
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)
Example #29
0
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')
Example #30
0
 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)
Example #32
0
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()
Example #34
0
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
Example #35
0
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")
Example #36
0
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)
Example #37
0
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)
Example #38
0
    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()
Example #39
0
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()
Example #41
0
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
Example #42
0
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)