def get_servers(): username = session[USERNAME] password = session[PASSWORD] plex_server = Plex(username, password) servers = plex_server.get_plex_server_resources() names = [server.name for server in servers] return jsonify(names)
def read_line_retry(self, timeout=60, ping=False, stale_sleep=1.0): line = None stale_since = None while not line: line = self.read_line() if line: stale_since = None time.sleep(0.05) break if stale_since is None: stale_since = time.time() time.sleep(stale_sleep) continue elif (time.time() - stale_since) > timeout: return None elif (time.time() - stale_since) > timeout / 2: # Nothing returned for 5 seconds if self.file.get_path() != self.path: log.debug("Log file moved (probably rotated), closing") self.close() elif ping: # Ping server to see if server is still active Plex.detail() ping = False time.sleep(stale_sleep) return line
def test_cache(): http_cache = {} # Mock response body = read('fixtures/detail_a.xml', mode='r') responses.add_callback( responses.GET, 'http://mock:32400/', callback=lambda request: (200, {}, body), content_type='application/xml' ) with Plex.configuration.cache(http=http_cache): # Check initial version retrieval assert Plex.version() == "0.9.9.16.555-50cd0c3" # Change body, ensure cached version is returned body = read('fixtures/detail_b.xml', mode='r') assert Plex.version() == "0.9.9.16.555-50cd0c3" # Clear cache, ensure version has changed http_cache.clear() assert Plex.version() == "0.9.9.14.531-7eef8c6"
def add_movies(): data = request.json if (not data): return { "error": "You need to include movies, playlist name and users" }, 400 movie_list = data["movies"] name = data["name"] users = data["users"] if (not movie_list or not name or not users): return { "error": "You need to include movies, playlist name and users" }, 400 username = session[USERNAME] password = session[PASSWORD] server = session[SERVER] imdb_id = session[IMDB_ID] if (not username or not password or not server or not imdb_id): return {"error": "Could not find session data"}, 500 plex_server = Plex(username, password) plex_server.add_resource_by_name(server) plex_server.connect() playlist, failed_movies = plex_server.add_playlist(name, movie_list) if (len(users) > 0 and playlist is not None): plex_server.copy_to_users(playlist, users) return jsonify(failed_movies)
def fetch(result, player): # Fetch client details client = Plex.clients().get(player['key']) if not client: log.info('Unable to find client with key %r', player['key']) return result, None # Merge client details from plex API result = merge(result, dict([ (key, getattr(client, key)) for key in [ 'device_class', 'product', 'version', 'host', 'address', 'port', 'protocol', 'protocol_capabilities', 'protocol_version' ] if getattr(client, key) ])) return result, client
def create_session(self, info): if not info.get('ratingKey'): log.warn('Invalid ratingKey provided from activity info') return None # Metadata metadata = Metadata.get(info['ratingKey']) # Guid guid = Guid.parse(metadata.guid) if metadata else None ws = WatchSession.from_info(info, metadata, guid, info['ratingKey']) ws.skip = not metadata # Fetch client by `machineIdentifier` ws.client = Plex.clients().get(info['machineIdentifier']) if not ws.client: # Create dummy client from `info` ws.client = Client(Plex.client, 'clients') ws.client.name = info.get('client', None) ws.client.machine_identifier = info.get('machineIdentifier', None) ws.client.address = info.get('address', None) ws.client.port = info.get('port', None) # Create dummy user from `info` ws.user = User(Plex.client, 'accounts') ws.user.id = info['user_id'] ws.user.title = info['user_name'] ws.save() log.debug('created session: %s', ws) return ws
def create_session(self, session_key, state): """ :type session_key: str :type state: str :rtype: WatchSession or None """ log.debug('Creating a WatchSession for the current media') item = Plex['status'].sessions().get(session_key) if not item: log.warn('Unable to find session with key "%s"', session_key) return None # Metadata metadata = Metadata.get(item.rating_key) # Guid guid = Guid.parse(metadata.guid) if metadata else None # Create WatchSession ws = WatchSession.from_session(item.session, metadata, guid, item.rating_key, state) ws.skip = not metadata # Fetch client by `machineIdentifier` ws.client = Plex.clients().get(item.session.player.machine_identifier) ws.save() log.debug('created session: %s', ws) return ws
def scrape_imdb(): data = request.json if (not data): return {"error": "You need to include an IMDb id"}, 400 imdb_id = data[IMDB_ID] if (not imdb_id): return {"error": "You need to include an IMDb id"}, 400 username = session[USERNAME] password = session[PASSWORD] server = session[SERVER] if (not username or not password or not server): return {"error": "Could not find session data"}, 500 plex_server = Plex(username, password) plex_server.add_resource_by_name(server) plex_server.connect() movies = plex_server.scrape_imdb("https://www.imdb.com/list/" + imdb_id) if (not movies): return {"error": "You need to include a valid IMDb id"}, 400 session[IMDB_ID] = imdb_id return jsonify(movies)
def test_version(): responses.add(responses.GET, 'http://mock:32400', body=read('fixtures/detail_a.xml'), status=200, content_type='application/xml') version = Plex.version() assert version == "0.9.9.16.555-50cd0c3"
def test_version(): responses.add( responses.GET, 'http://mock:32400', body=read('fixtures/detail_a.xml'), status=200, content_type='application/xml' ) version = Plex.version() assert version == "0.9.9.16.555-50cd0c3"
def test_booleans(): responses.add( responses.GET, 'http://mock:32400', body=read('fixtures/detail_a.xml'), status=200, content_type='application/xml' ) detail = Plex.detail() assert detail is not None assert detail.multiuser is True assert detail.sync is False
def monitor(config): global dimmed global playing logger = logging.getLogger(__name__) while True: time.sleep(1) plex = Plex(config) metadata = plex.get_media_metadata_from_sessions(USER_ID) if metadata: playing = True lifx = Lifx(config) light_id = config.get('plex-lifx', 'lifx_light_id') state = metadata['srobbling'] if state == 'playing' and not dimmed: logger.info("PLAYING - Dimming till 0 light bulb {light_id}".format(light_id=light_id)) lifx.set_state(light_id, 'on', None, 0.5, None) time.sleep(1) lifx.set_state(light_id, 'off', None, 0, None) dimmed = True elif dimmed: logger.info("PAUSED - Dimming till 0.5 light bulb {light_id}".format(light_id=light_id)) lifx.set_state(light_id, 'on', None, 0.5, None) dimmed = False elif playing: logger.info("STOPPED - Turning light bulb {light_id} on".format(light_id=light_id)) lifx.set_state(light_id, 'on', None, 1, None) dimmed = False playing = False
def init_raven(cls): # Retrieve server details server = Plex.detail() if not server: return # Set client name to a hash of `machine_identifier` RAVEN.name = md5(server.machine_identifier) RAVEN.tags.update({ 'server.version': server.version })
def choose_server(): data = request.json if (not data): return {"error": "You need to include a server name"}, 400 server = data[SERVER] if (not server): return {"error": "You need to include a server name"}, 400 username = session[USERNAME] password = session[PASSWORD] plex_server = Plex(username, password) try: plex_server.add_resource_by_name(server) except NotMediaServerError: return {"error": "Not a plex server"}, 400 except NoServerError: return {"error": "No server with that name"}, 400 session[SERVER] = server return {"message": "Success"}, 200
def test_clients_filter(): responses.add( responses.GET, 'http://mock:32400/clients', body=read('fixtures/clients.xml'), status=200, content_type='application/xml' ) container = Plex.clients() assert container is not None items = list(container.filter(["a7d1b50a-42d1-40b5-9db6-6b0afd013438"])) assert len(items) == 1 assert items[0].machine_identifier == "a7d1b50a-42d1-40b5-9db6-6b0afd013438"
def test_detail(): responses.add( responses.GET, 'http://mock:32400', body=read('fixtures/detail_a.xml'), status=200, content_type='application/xml' ) detail = Plex.detail() assert detail is not None assert detail.friendly_name == "Mock Server" assert detail.platform == "Windows" assert detail.platform_version == "6.2 (Build 9200)"
def test_detail(): responses.add(responses.GET, 'http://mock:32400', body=read('fixtures/detail_malformed.xml'), status=200, content_type='application/xml') detail = Plex.detail() if PARSER == 'etree.HTMLParser': assert detail is not None assert detail.platform_version == six.u('6.2 (Build 9200)\xff\xff') else: assert detail is None
def test_detail(): responses.add( responses.GET, 'http://mock:32400', body=read('fixtures/detail_malformed.xml'), status=200, content_type='application/xml' ) detail = Plex.detail() if PARSER == 'etree.HTMLParser': assert detail is not None assert detail.platform_version == six.u('6.2 (Build 9200)\xff\xff') else: assert detail is None
def test_detail(): responses.add(responses.GET, 'http://mock:32400', body=read('fixtures/detail_a.xml'), status=200, content_type='application/xml') detail = Plex.detail() assert detail is not None assert detail.friendly_name == "Mock Server" assert detail.platform == "Windows" assert detail.platform_version == "6.2 (Build 9200)"
def test(cls): if Plex['status'].sessions() is None: log.info("Error while retrieving sessions, assuming WebSocket method isn't available") return False detail = Plex.detail() if detail is None: log.info('Error while retrieving server info for testing') return False if not detail.multiuser: log.info("Server info indicates multi-user support isn't available, WebSocket method not available") return False return True
def test_cache(): http_cache = {} # Mock response body = read('fixtures/detail_a.xml', mode='r') responses.add_callback(responses.GET, 'http://mock:32400/', callback=lambda request: (200, {}, body), content_type='application/xml') with Plex.configuration.cache(http=http_cache): # Check initial version retrieval assert Plex.version() == "0.9.9.16.555-50cd0c3" # Change body, ensure cached version is returned body = read('fixtures/detail_b.xml', mode='r') assert Plex.version() == "0.9.9.16.555-50cd0c3" # Clear cache, ensure version has changed http_cache.clear() assert Plex.version() == "0.9.9.14.531-7eef8c6"
def test_clients_filter(): responses.add(responses.GET, 'http://mock:32400/clients', body=read('fixtures/clients.xml'), status=200, content_type='application/xml') container = Plex.clients() assert container is not None items = list(container.filter(["a7d1b50a-42d1-40b5-9db6-6b0afd013438"])) assert len(items) == 1 assert items[ 0].machine_identifier == "a7d1b50a-42d1-40b5-9db6-6b0afd013438"
def process_server_state(cls): # Check startup state server = Plex.detail() if server is None: log.info('Unable to check startup state, detail request failed') return # Check server startup state if server.start_state is None: return if server.start_state == 'startingPlugins': return cls.on_starting_plugins() log.error('Unhandled server start state %r', server.start_state)
def get_users(): username = session[USERNAME] password = session[PASSWORD] server = session[SERVER] if (not username or not password or not server): return {"error": "Could not find session data"}, 500 plex_server = Plex(username, password) plex_server.add_resource_by_name(server) plex_server.connect() users = plex_server.get_users() return jsonify(users)
def test_clients(): responses.add( responses.GET, 'http://mock:32400/clients', body=read('fixtures/clients.xml'), status=200, content_type='application/xml' ) container = Plex.clients() assert container is not None items = list(container) assert len(items) == 1 assert items[0].name == "One" assert items[0].address == "192.168.1.100" assert items[0].version == "1.2.2.331-2d6426d7" assert items[0].protocol_capabilities == "navigation,playback,timeline,mirror,playqueues"
def test_clients_get(): responses.add( responses.GET, 'http://mock:32400/clients', body=read('fixtures/clients.xml'), status=200, content_type='application/xml' ) container = Plex.clients() assert container is not None # Try retrieve item that exists item = container.get("a7d1b50a-42d1-40b5-9db6-6b0afd013438") assert item is not None assert item.machine_identifier == "a7d1b50a-42d1-40b5-9db6-6b0afd013438" # Try retrieve item that doesn't exist item = container.get("invalid-identifier") assert item is None
def test(cls): if Plex['status'].sessions() is None: log.info( "Error while retrieving sessions, assuming WebSocket method isn't available" ) return False detail = Plex.detail() if detail is None: log.info('Error while retrieving server info for testing') return False if not detail.multiuser: log.info( "Server info indicates multi-user support isn't available, WebSocket method not available" ) return False return True
def test_clients_get(): responses.add(responses.GET, 'http://mock:32400/clients', body=read('fixtures/clients.xml'), status=200, content_type='application/xml') container = Plex.clients() assert container is not None # Try retrieve item that exists item = container.get("a7d1b50a-42d1-40b5-9db6-6b0afd013438") assert item is not None assert item.machine_identifier == "a7d1b50a-42d1-40b5-9db6-6b0afd013438" # Try retrieve item that doesn't exist item = container.get("invalid-identifier") assert item is None
def test_clients(): responses.add(responses.GET, 'http://mock:32400/clients', body=read('fixtures/clients.xml'), status=200, content_type='application/xml') container = Plex.clients() assert container is not None items = list(container) assert len(items) == 1 assert items[0].name == "One" assert items[0].address == "192.168.1.100" assert items[0].version == "1.2.2.331-2d6426d7" assert items[ 0].protocol_capabilities == "navigation,playback,timeline,mirror,playqueues"
def sign_in(): data = request.json if (not data): return {"error": "You need to include username and password"}, 400 username = data[USERNAME] password = data[PASSWORD] if (not username or not password): return {"error": "You need to include username and password"}, 400 try: plex_server = Plex(username, password) except SignInError: return {"error": "Wrong username or password"}, 401 session[USERNAME] = username session[PASSWORD] = password return {"message": "Success"}, 200
def test_servers(): responses.add( responses.GET, 'http://mock:32400/servers', body=read('fixtures/servers.xml'), status=200, content_type='application/xml' ) container = Plex.servers() assert container is not None items = list(container) assert len(items) == 2 assert items[0].name == "One" assert items[0].address == "192.168.1.100" assert items[0].version == "0.9.9.16.555-50cd0c3" assert items[1].name == "Two" assert items[1].address == "192.168.1.101" assert items[1].version == "0.9.9.14.531-7eef8c6"
def main(): app = QApplication([]) engine = QQmlApplicationEngine() # Instances of Objects plex = Plex(os.environ['USERNAME'], os.environ['PASSWORD'], os.environ['SERVER_NAME']) # Expose instances context = engine.rootContext() context.setContextProperty("plex", plex) # Load the view view_path = join(dirname(__file__), 'views/view.qml') engine.load(abspath(view_path)) if not engine.rootObjects(): sys.exit(-1) sys.exit(app.exec_())
def test_servers(): responses.add(responses.GET, 'http://mock:32400/servers', body=read('fixtures/servers.xml'), status=200, content_type='application/xml') container = Plex.servers() assert container is not None items = list(container) assert len(items) == 2 assert items[0].name == "One" assert items[0].address == "192.168.1.100" assert items[0].version == "0.9.9.16.555-50cd0c3" assert items[1].name == "Two" assert items[1].address == "192.168.1.101" assert items[1].version == "0.9.9.14.531-7eef8c6"
def setup_logger(): formatter = logging.Formatter('%(asctime)s %(message)s') handler = logging.FileHandler('failed-lookup.log') handler.setFormatter(formatter) logger.addHandler(handler) logging.getLogger().addHandler(logging.StreamHandler(sys.stdout)) logger.setLevel(logging.INFO) if __name__ == '__main__': config_parser.read('settings.ini') plex = PlexServer(config_parser.get('Plex', 'url'), config_parser.get('Plex', 'token')) plex_interface = Plex() min_weight = int(config_parser.get('AniDB', 'min_tag_weight')) setup_logger() titles = [] anime_library = plex.library.section( config_parser.get('Plex', 'anime_library')) plex_interface.set_library(anime_library) for video in anime_library.search(): titles.append(AniDBTitle(video.title)) #plex_interface.add_show(video.title, video) for anime in titles: print('Processing "{}"'.format(anime.title)) anime.anidb_id = anidb.find_id(anime)
def get_synced_items(self, machine_id=None, client_id_filter=None, user_id_filter=None, rating_key_filter=None, sync_id_filter=None): if not machine_id: machine_id = plexpy.CONFIG.PMS_IDENTIFIER if isinstance(rating_key_filter, list): rating_key_filter = [str(k) for k in rating_key_filter] elif rating_key_filter: rating_key_filter = [str(rating_key_filter)] if isinstance(user_id_filter, list): user_id_filter = [str(k) for k in user_id_filter] elif user_id_filter: user_id_filter = [str(user_id_filter)] sync_list = self.get_plextv_sync_lists(machine_id, output_format='xml') user_data = users.Users() synced_items = [] try: xml_head = sync_list.getElementsByTagName('SyncList') except Exception as e: logger.warn("Tautulli PlexTV :: Unable to parse XML for get_synced_items: %s." % e) return {} for a in xml_head: client_id = helpers.get_xml_attr(a, 'clientIdentifier') # Filter by client_id if client_id_filter and str(client_id_filter) != client_id: continue sync_list_id = helpers.get_xml_attr(a, 'id') sync_device = a.getElementsByTagName('Device') for device in sync_device: device_user_id = helpers.get_xml_attr(device, 'userID') try: device_username = user_data.get_details(user_id=device_user_id)['username'] device_friendly_name = user_data.get_details(user_id=device_user_id)['friendly_name'] except: device_username = '' device_friendly_name = '' device_name = helpers.get_xml_attr(device, 'name') device_product = helpers.get_xml_attr(device, 'product') device_product_version = helpers.get_xml_attr(device, 'productVersion') device_platform = helpers.get_xml_attr(device, 'platform') device_platform_version = helpers.get_xml_attr(device, 'platformVersion') device_type = helpers.get_xml_attr(device, 'device') device_model = helpers.get_xml_attr(device, 'model') device_last_seen = helpers.get_xml_attr(device, 'lastSeenAt') # Filter by user_id if user_id_filter and device_user_id not in user_id_filter: continue for synced in a.getElementsByTagName('SyncItems'): sync_item = synced.getElementsByTagName('SyncItem') for item in sync_item: sync_media_type = None rating_key = None for location in item.getElementsByTagName('Location'): location_uri = unquote(helpers.get_xml_attr(location, 'uri')) if location_uri.startswith('library://'): if 'collection' in location_uri: sync_media_type = 'collection' clean_uri = location_uri.split('/') rating_key = next((j for i, j in zip(clean_uri[:-1], clean_uri[1:]) if i in ('metadata', 'collections')), None) elif location_uri.startswith('playlist://'): sync_media_type = 'playlist' tokens = users.Users().get_tokens(user_id=device_user_id) if tokens['server_token']: plex = Plex(token=tokens['server_token']) for playlist in plex.PlexServer.playlists(): if location_uri.endswith(playlist.guid): rating_key = str(playlist.ratingKey) # String for backwards consistency # Filter by rating_key if rating_key_filter and rating_key not in rating_key_filter: continue sync_id = helpers.get_xml_attr(item, 'id') # Filter by sync_id if sync_id_filter and str(sync_id_filter) != sync_id: continue sync_version = helpers.get_xml_attr(item, 'version') sync_root_title = helpers.get_xml_attr(item, 'rootTitle') sync_title = helpers.get_xml_attr(item, 'title') sync_metadata_type = helpers.get_xml_attr(item, 'metadataType') sync_content_type = helpers.get_xml_attr(item, 'contentType') for status in item.getElementsByTagName('Status'): status_failure_code = helpers.get_xml_attr(status, 'failureCode') status_failure = helpers.get_xml_attr(status, 'failure') status_state = helpers.get_xml_attr(status, 'state') status_item_count = helpers.get_xml_attr(status, 'itemsCount') status_item_complete_count = helpers.get_xml_attr(status, 'itemsCompleteCount') status_item_downloaded_count = helpers.get_xml_attr(status, 'itemsDownloadedCount') status_item_ready_count = helpers.get_xml_attr(status, 'itemsReadyCount') status_item_successful_count = helpers.get_xml_attr(status, 'itemsSuccessfulCount') status_total_size = helpers.get_xml_attr(status, 'totalSize') status_item_download_percent_complete = helpers.get_percent( status_item_downloaded_count, status_item_count) for settings in item.getElementsByTagName('MediaSettings'): settings_video_bitrate = helpers.get_xml_attr(settings, 'maxVideoBitrate') settings_video_quality = helpers.get_xml_attr(settings, 'videoQuality') settings_video_resolution = helpers.get_xml_attr(settings, 'videoResolution') settings_audio_boost = helpers.get_xml_attr(settings, 'audioBoost') settings_audio_bitrate = helpers.get_xml_attr(settings, 'musicBitrate') settings_photo_quality = helpers.get_xml_attr(settings, 'photoQuality') settings_photo_resolution = helpers.get_xml_attr(settings, 'photoResolution') sync_details = {"device_name": device_name, "platform": device_platform, "user_id": device_user_id, "user": device_friendly_name, "username": device_username, "root_title": sync_root_title, "sync_title": sync_title, "metadata_type": sync_metadata_type, "content_type": sync_content_type, "rating_key": rating_key, "state": status_state, "item_count": status_item_count, "item_complete_count": status_item_complete_count, "item_downloaded_count": status_item_downloaded_count, "item_downloaded_percent_complete": status_item_download_percent_complete, "video_bitrate": settings_video_bitrate, "audio_bitrate": settings_audio_bitrate, "photo_quality": settings_photo_quality, "video_quality": settings_video_quality, "total_size": status_total_size, "failure": status_failure, "client_id": client_id, "sync_id": sync_id, "sync_media_type": sync_media_type } synced_items.append(sync_details) return session.filter_session_info(synced_items, filter_key='user_id')