def cli(debug, username, password, servername, url, token, config): """ Entry point for the CLI.""" global PMS # click.echo('debug %s' % debug) # click.echo('username %s' % username) # click.echo('password %s' % password) # click.echo('servername %s' % servername) # click.echo('url %s' % url) # click.echo('token %s' % token) # click.echo('config %s' % config) if debug: LOG.setLevel(logging.DEBUG) else: LOG.setLevel(logging.INFO) if username and password and servername: from plexapi.myplex import MyPlexAccount acc = MyPlexAccount(username, password) PMS = acc.resource(servername).connect() elif url and token: PMS = PlexServer(url, token) else: PMS = PlexServer('', '') # plexapi will pull config file.. # CONFIG is unused atm. click.echo('Watching for media on %s' % PMS.friendlyName)
def choose_managed_user(account: MyPlexAccount): users = [u.title for u in account.users() if u.friend] if not users: return None click.echo(success("Managed user(s) found:")) users = sorted(users) for user in users: click.echo(f"- {user}") if not click.confirm(PROMPT_MANAGED_USER): return None # choice = prompt_choice(users) user = click.prompt( title("Please select:"), type=Choice(users), show_default=True, ) # Sanity check, even the user can't input invalid user user_account = account.user(user) if user_account: return user return None
def _connect_server(self, user, password, server): print("Connecting to plex server {server} with user: {user}...".format( server=server, user=user)) self.account = MyPlexAccount(user, password) self.server = self.account.resource(server).connect() self.token = self.account.resource(server).accessToken
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 getMyPlexAccount(opts=None): # pragma: no cover """ Helper function tries to get a MyPlex Account instance by checking the the following locations for a username and password. This is useful to create user-friendly command line tools. 1. command-line options (opts). 2. environment variables and config.ini 3. Prompt on the command line. """ from plexapi import CONFIG from plexapi.myplex import MyPlexAccount # 1. Check command-line options if opts and opts.username and opts.password: print('Authenticating with Plex.tv as %s..' % opts.username) return MyPlexAccount(opts.username, opts.password) # 2. Check Plexconfig (environment variables and config.ini) config_username = CONFIG.get('auth.myplex_username') config_password = CONFIG.get('auth.myplex_password') if config_username and config_password: print('Authenticating with Plex.tv as %s..' % config_username) return MyPlexAccount(config_username, config_password) config_token = CONFIG.get('auth.server_token') if config_token: print('Authenticating with Plex.tv with token') return MyPlexAccount(token=config_token) # 3. Prompt for username and password on the command line username = input('What is your plex.tv username: '******'What is your plex.tv password: '******'Authenticating with Plex.tv as %s..' % username) return MyPlexAccount(username, password)
def authenticate(): method = plex_settings['authentication_method'].lower() try: # Direct connection if method == 'direct': base_url = plex_settings['base_url'] token = plex_settings['token'] plex = PlexServer(base_url, token) # Myplex connection elif method == 'myplex': plex_server = plex_settings['server'] plex_user = plex_settings['myplex_user'] plex_password = plex_settings['myplex_password'] account = MyPlexAccount(plex_user, plex_password) plex = account.resource(plex_server).connect() else: logger.critical( '[PLEX] Failed to authenticate due to invalid settings or authentication info, exiting...') sys.exit() return plex except Exception as e: logger.error( 'Unable to authenticate to Plex Media Server, traceback: %s' % (e)) return None
class HoodexPlexServer(object): account = None server = None token = "" def __init__(self, user, password, server): self._connect_server(user=user, password=password, server=server) def _connect_server(self, user, password, server): print("Connecting to plex server {server} with user: {user}...".format( server=server, user=user)) self.account = MyPlexAccount(user, password) self.server = self.account.resource(server).connect() self.token = self.account.resource(server).accessToken def get_last_added(self, library_name): media_list = [] for media in self.server.library.section(library_name).recentlyAdded(): local_path = media.locations[0] file_name = os.path.basename(local_path) media_list.append({ "file_name": local_path, "name": file_name, "url": media.media[0].parts[0].key }) return media_list
def get_pms(url=None, token=None, username=None, password=None, servername=None, verify_ssl=None): # pragma: no cover url = url or CONFIG['server'].get('url') token = token or CONFIG['server'].get('token') verify_ssl = verify_ssl or CONFIG['server'].get('verify_ssl', False) servername = servername or CONFIG['server'].get('name') if url and token: url = url.rstrip('/') sess = requests.Session() if not verify_ssl: # Disable the urllib3 warning as the user # has choosen to not verify the http request. # why the f**k isnt this default? requests.packages.urllib3.disable_warnings() sess.verify = False PMS = PlexServer(url, token, sess) elif username and password and servername: acc = MyPlexAccount(username, password) PMS = acc.resource(servername).connect() assert PMS is not None, 'You need to add a url and token or username password and servername' LOG.debug('Getting server %s', PMS.friendlyName) return PMS
def get_plex_server(): PlexMethod = MyPlexAccount if fpssConfig['plexmethod'] == 'MyPlexAccount': # Use the My Plex Account method of connecting #account = MyPlexAccount(fpssConfig['plexusername'], fpssConfig['plexpassword'], token=fpssConfig['plexauthtoken'], timeout=5) account = MyPlexAccount(fpssConfig['plexusername'], fpssConfig['plexpassword'], timeout=5) cons = account.resource(fpssConfig['plexserver']).connections print("Connections available:", len(cons), "Access Token:", account.resource(fpssConfig['plexserver']).accessToken) for r in range(0, len(cons)): conr = cons[r] #print(dir(conr)) print(conr.address, conr.httpuri, conr.protocol, conr.key, conr.uri, conr.local) #print(cons[r]) #exit() try: pms = account.resource(fpssConfig['plexserver']).connect() except plexapi.exceptions.NotFound: print("Could not connect to plex") exit(-1) else: baseurl = fpssConfig['plexmethod'] pms = PlexServer(baseurl, fpssConfig['plexauthtoken']) return pms
def get_pms(url=None, token=None, username=None, password=None, servername=None, verify_ssl=None): # pragma: no cover url = url or CONFIG['server'].get('url') token = token or CONFIG['server'].get('token') verify_ssl = verify_ssl or CONFIG['server'].get('verify_ssl', False) servername = servername or CONFIG['server'].get('name') if url and token: sess = requests.Session() if not verify_ssl: sess.verify = False PMS = PlexServer(url, token, sess) elif username and password and servername: acc = MyPlexAccount(username, password) PMS = acc.resource(servername).connect() assert PMS is not None, 'You need to add a url and token or username password and servername' LOG.debug('Getting server %s', PMS.friendlyName) return PMS
def signInOnline(): """ Returns a :class:`~plexapi.server.PlexServer` by connecting online through MyPlex. """ # Attempt to sign on isSignedIn = False while not isSignedIn: # Get login info from user username = input("Plex username: "******"Plex password: "******"Plex server name: ") # Sign in via MyPlex print("Signing in (this may take awhile)...") try: account = MyPlexAccount(username, password) plexServer = account.resource(serverName).connect() isSignedIn = True except BadRequest: print("Error: Login failed. Are your credentials correct?") except NotFound: print("Error: Server '%s' not found linked to your account." % serverName) return plexServer
def __init__(self): MycroftSkill.__init__(self) # List of services. Names in config must match API names. self.services = self.settings.get('services').lower().split(',') # Some titles are only available in certain countries self.country = self.settings.get('country').lower() # RapidAPI keys for Utelly API and IMDB API self.header_apiKey = self.settings.get('x-rapidapi-key') # Plex info self.plexAccount = MyPlexAccount(self.settings.get('plexUsername'), self.settings.get('plexPassword')) self.plexServers = [] # Service host info - from Rapid API self.header_utellyHost = self.settings.get('utellyHost') self.header_imdbHost = self.settings.get('imdbHost') # URLs for each service - from Rapid API self.utellyUrl = f'https://{self.header_utellyHost}/idlookup' self.imdbUrl = f'https://{self.header_imdbHost}/title/find' # If this is set to true, then the skill will offer to download a title if it can't be found. # Is there a way for this skill to just check if the other skill is loaded? self.couchPotato = self.settings.get('couchPotato')
def connect_to_plex(username, password, server_name): """Connect to Plex""" account = MyPlexAccount(username, password) plex = account.resource(server_name).connect() return plex
def __init__(self, settings): self.__settings = settings try: account = MyPlexAccount(settings.plex["user"], settings.plex["password"]) self.__plex = account.resource(settings.plex["servername"]).connect() except: print("Could not connect to Plex API")
def get_pms(url=None, token=None, username=None, password=None, servername=None, verify_ssl=None): from plexapi.myplex import MyPlexAccount from plexapi.server import PlexServer url = url or CONFIG.get('url') token = token or CONFIG.get('token') verify_ssl = verify_ssl or CONFIG.get('verify_ssl', False) if url and token: sess = requests.Session() if not verify_ssl: sess.verify = False PMS = PlexServer(url, token, sess) elif username and password and servername: acc = MyPlexAccount(username, password) PMS = acc.resource(servername).connect() LOG.debug('Getting server %s', PMS.friendlyName) return PMS
def inviteFriend(): request_data = request.get_json() username = request_data['username'] password = request_data['password'] friend_username = request_data['friendusername'] print(username) print(password) print(friend_username) try: a = MyPlexAccount(username=f"{username}", password=f"{password}", token=token, session=None, timeout=None) a.inviteFriend(user=f"{friend_username}", server=plex, sections=None, allowSync=False, allowCameraUpload=False, allowChannels=False, filterMovies=None, filterTelevision=None, filterMusic=None) return "invited successfully" except: return "you aleady requested or username is wrong"
async def connect(self) -> None: while True: try: if self.token: self.plex_account = MyPlexAccount(self.username, token=self.token) else: self.plex_account = MyPlexAccount(self.username, self.password) log.info(f'Logged into Plex as {self.username}.') self.plex_server = self.plex_account.resource( self.server).connect() log.info(f'Connected to Plex {self.server} server.') break except Exception as err: log.error(f'Failed to connect to Plex: {err}') log.debug('Attempting reconnection in 10 seconds..') await asyncio.sleep(10) log.debug('Attempting to open IPC connection to Discord..') await super().connect() log.info('IPC connection established to Discord.') self.connected.set()
def dub(username: str = username, password: str = password, servername: str = servername, show: str = show, lang: str = lang): """Set the default dubs for every episode of the show.""" account = MyPlexAccount(username, password) plex: PlexServer = account.resource(servername).connect() try: not_found_dubs_count = 0 for part in _get_media_parts(plex, show): is_found = False for audio in part.audioStreams(): if audio.languageCode == lang: part.setDefaultAudioStream(audio) is_found = True break if not is_found: not_found_dubs_count += 1 if GLOBAL_OPTIONS['verbose']: typer.echo( f'Audio for "{lang}" not found for file: {part.file}', err=True) if not_found_dubs_count != 0: typer.echo(f'{not_found_dubs_count} dubs were not found', err=True) raise typer.Abort() except NotFound as e: typer.echo("Show, media item, or device is not found.", err=True) typer.echo(e, err=True) raise typer.Abort() typer.echo('Success!')
class EntangledPOC: def __init__(self): username = '******' password = load_password() self.account = MyPlexAccount(username, password) self.resource: PlexClient = None def list_resources(self): resources = self.account.resources() print(resources) def connect_to(self, resource_name): self.resource = self.account.resource(resource_name).connect() def play(self): if not self.resource: return self.resource.play() def pause(self): if not self.resource: return self.resource.pause() def go_to_10_min_in_movie(self): ten_minutes_ms = 10 * 60 * 1000 self.resource.seekTo(ten_minutes_ms)
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 choose_managed_user(account: MyPlexAccount): users = [u.title for u in account.users()] if not users: return None click.echo(success("Managed user(s) found:")) users = sorted(users) users.insert(0, account.username) user = inquirer.select( message="Select the user you would like to use:", choices=users, default=None, style=style, qmark="", pointer=">", ).execute() if user == account.username: return None # Sanity check, even the user can't input invalid user user_account = account.user(user) if user_account: return user return None
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._media_attrs = {} self._sessions = None self._session = None self._sessioncount = 0 self._session_type = None self._plex_url = plex_url self._plex_token = plex_token """Set all Media Items to None.""" # General self._media_content_type = None self._media_title = None # TV Show 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 main(): args = get_args() if args.debug: logger.setLevel(logging.DEBUG) if args.account: # ## Connect via Account account = MyPlexAccount(args.username, args.password) plex = account.resource(args.resource).connect() elif args.server: # ## Connect via Direct URL baseurl = args.baseurl token = args.token plex = PlexServer(baseurl, token) else: exit(1) all_shows = plex.library.section('TV Shows') # shows = get_unwatched_shows(all_shows.all()) episodes = get_random_episodes(all_shows, n=args.number) for episode in episodes: season_episode = episode.seasonEpisode # skipped = skipped_missing(all_shows.get(title=episode.grandparentTitle), episode) # playlist = Playlist(plex, ) plex.playlist(title=args.name).delete() Playlist.create(server=plex, title=args.name, items=episodes)
class PythonLibPlexApi(PlexApi): # TODO # Add a 'connect_to_account' and 'connect_to_resource' method # and call them both in 'Entangled' (test via outside-in testing # that it's been call during 'Entangled' '__init__') # Then in the 'list_all_resources' script, only call 'connect_to_account' # Boom lifecyle problem solved, and it's transparent to the higher level # using 'Entangled' def __init__(self) -> None: self.username = os.environ['PLEX_USER'] self.password = os.environ['PLEX_PASS'] self.resource_name = os.environ['PLEX_RESOURCE'] self._connect_to_resource() def _connect_to_resource(self): self.account = MyPlexAccount(self.username, self.password) if (self.resource_name): self.resource = self.account.resource(self.resource_name).connect() else: logger.info("DEBUG TEMP: Add resource to envvar") @ensure_connected_to_account def all_resources(self): return self.account.resources() @ensure_connected_to_resource def current_movie_time(self): logger.info('Getting current movie time') # TODO: Fix 'self.resource.timeline.time' can be None sometimes if the movie was paused. Find solution. print(self.resource.timeline.time) import math timestamp = math.floor(self.resource.timeline.time / 1000) hours = math.floor(timestamp/3600) min = math.floor(timestamp / 60) - hours * 60 secs = timestamp - hours*3600 - min*60 current_time = f"{hours}:{min:02}:{secs:02}" return current_time @ensure_connected_to_resource def seek_to(self, hour, minute, second): logger.info(f"Seeking to: '{hour}:{minute}:{second}") def seconds(seconds_num): return seconds_num * 1000 def minutes(minutes_num): return seconds(minutes_num * 60) def hours(hours_num): return minutes(hours_num * 60) self.resource.seekTo( hours(hour) + minutes(minute) + seconds(second) ) @ensure_connected_to_resource def play(self): logger.info('Playing') self.resource.play()
def connect(self, server, username, password=''): self.logger.info( f'Connecting to the Plex Server {server} with username {username}.' ) connection_attempts_left = self.maximum_connection_attempts while connection_attempts_left > 0: time.sleep( 1 ) # important. Otherwise, the above print statement can be flushed after if not password: password = getpass.getpass() try: self.account = MyPlexAccount(username, password) break except NotFound: print( f'Username {username} or password wrong for server {server}.' ) password = '' connection_attempts_left -= 1 except BadRequest as error: self.logger.warning('Failed to connect: {}'.format(error)) connection_attempts_left -= 1 if connection_attempts_left == 0 or self.account is None: self.logger.error('Exiting after {} failed attempts ...'.format( self.maximum_connection_attempts)) exit(1) self.logger.info( 'Connecting to remote player {} on the server {}'.format( self.name(), server)) try: self.plex_api_connection = self.account.resource(server).connect( timeout=5) self.logger.info('Successfully connected') except NotFound: # This also happens if the user is not the owner of the server self.logger.error('Error: Unable to connect') exit(1) self.logger.info('Looking for music libraries') music_libraries = { section.key: section for section in self.plex_api_connection.library.sections() if section.type == 'artist' } if len(music_libraries) == 0: self.logger.error('No music library found') exit(1) elif len(music_libraries) == 1: self.music_library = list(music_libraries.values())[0] self.logger.debug('Found 1 music library') else: print('Found multiple music libraries:') for key, library in music_libraries.items(): print('\t[{}]: {}'.format(key, library.title)) choice = input('Select the library to sync with: ') self.music_library = music_libraries[choice]
def validate_password(self, field, value): if not value: return value try: MyPlexAccount.signin(self.fields.username.value, value) return value except Unauthorized: raise ValidationError('Invalid username or password.')
def plex_account_test(servername, username, password): account = MyPlexAccount(username, password) # returns a PlexServer instance plex_server = account.resource(servername).connect() playlists = plex_server.playlists() for playlist in playlists: print("Playlist Title: {}".format(playlist.title)) print("Playlist Items: {}".format(playlist.items))
def login(self, username, password): try: self._account = MyPlexAccount(username, password) self.set_token(self._account._token, self._account.username, self._account.email, self._account.uuid) self.emit('login-status', True, '') except: self.emit('login-status', False, 'Login failed')
def get_friends(config): token = config['plex']['token'] account = MyPlexAccount(token) columns = ['email', 'cleaned_email'] friends = [(user.email, clean_email(user.email)) for user in account.users() if user.friend] frame = pd.DataFrame(friends, columns=columns) return frame
def connect_to_plex(username, password, server): """ Takes the plex username, password and server name in order to establish a connection and retrieve data. """ account = MyPlexAccount(username, password) my_plex = account.resource(server).connect() return my_plex
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 fetch_server(args): if args.resource and args.username and args.password: log(0, 'Signing in as MyPlex account %s..' % args.username) account = MyPlexAccount.signin(args.username, args.password) log(0, 'Connecting to Plex server %s..' % args.resource) return account.resource(args.resource).connect(), account elif args.baseurl and args.token: log(0, 'Connecting to Plex server %s..' % args.baseurl) return server.PlexServer(args.baseurl, args.token), None return server.PlexServer(), None
def fetch_plex_instance(pkmeter, username=None, password=None, host=None): username = username or pkmeter.config.get('plexserver', 'username', from_keyring=True) password = password or pkmeter.config.get('plexserver', 'password', from_keyring=True) host = host or pkmeter.config.get('plexserver', 'host', '') if username: log.info('Logging into MyPlex with user %s', username) user = MyPlexAccount.signin(username, password) return user.resource(host).connect() log.info('Connecting to Plex host: %s', host) return PlexServer(host)
def __init__(self, config, audio): super(PlexBackend, self).__init__(audio=audio) self.config = config self.session = get_requests_session(proxy_config=config['proxy'], user_agent='%s/%s' % (mopidy_plex.Extension.dist_name, mopidy_plex.__version__) ) self.account = MyPlexAccount.signin(config['plex']['username'], config['plex']['password']) self.plex = self.account.resource(config['plex']['server']).connect() self.music = [s for s in self.plex.library.sections() if s.TYPE == MusicSection.TYPE][0] logger.debug('Found music section on plex server %s: %s', self.plex, self.music) self.uri_schemes = ['plex', ] self.library = PlexLibraryProvider(backend=self) self.playback = PlexPlaybackProvider(audio=audio, backend=self) self.playlists = PlexPlaylistsProvider(backend=self)
def get_servers_from_account(): if SECRETS is None: return {} try: account = MyPlexAccount.signin(*SECRETS) account_servers = { resource.clientIdentifier: resource for resource in account.resources() if "server" in resource.provides } return account_servers except Unauthorized: LOGGER.error("Could not authorize your account with the given " "credentials.") return {} except BadRequest: LOGGER.error("Blabla") # TODO: retry return {}
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()
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