Central update for Plex platforms (#27764)

* Update Plex platforms together

* Remove unnecessary methods

* Overhaul of Plex update logic

* Apply suggestions from code review

Use set instead of list

Co-Authored-By: Martin Hjelmare <marhje52@kth.se>

* Review suggestions and cleanup

* Fixes, remove sensor throttle

* Guarantee entity name, use common scheme

* Keep name stable once set
This commit is contained in:
jjlawren 2019-10-19 16:31:15 -05:00 committed by Martin Hjelmare
parent 5c50fa3405
commit eeb1bfc6f5
6 changed files with 252 additions and 266 deletions

View file

@ -1,17 +1,24 @@
"""Shared class to maintain Plex server instances."""
import logging
import plexapi.myplex
import plexapi.playqueue
import plexapi.server
from requests import Session
import requests.exceptions
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
from homeassistant.const import CONF_TOKEN, CONF_URL, CONF_VERIFY_SSL
from homeassistant.helpers.dispatcher import dispatcher_send
from .const import (
CONF_SERVER,
CONF_SHOW_ALL_CONTROLS,
CONF_USE_EPISODE_ART,
DEFAULT_VERIFY_SSL,
PLEX_NEW_MP_SIGNAL,
PLEX_UPDATE_MEDIA_PLAYER_SIGNAL,
PLEX_UPDATE_SENSOR_SIGNAL,
X_PLEX_DEVICE_NAME,
X_PLEX_PLATFORM,
X_PLEX_PRODUCT,
@ -19,6 +26,8 @@ from .const import (
)
from .errors import NoServersFound, ServerNotSpecified
_LOGGER = logging.getLogger(__name__)
# Set default headers sent by plexapi
plexapi.X_PLEX_DEVICE_NAME = X_PLEX_DEVICE_NAME
plexapi.X_PLEX_PLATFORM = X_PLEX_PLATFORM
@ -31,9 +40,11 @@ plexapi.server.BASE_HEADERS = plexapi.reset_base_headers()
class PlexServer:
"""Manages a single Plex server connection."""
def __init__(self, server_config, options=None):
def __init__(self, hass, server_config, options=None):
"""Initialize a Plex server instance."""
self._hass = hass
self._plex_server = None
self._known_clients = set()
self._url = server_config.get(CONF_URL)
self._token = server_config.get(CONF_TOKEN)
self._server_name = server_config.get(CONF_SERVER)
@ -76,13 +87,69 @@ class PlexServer:
else:
_connect_with_token()
def clients(self):
"""Pass through clients call to plexapi."""
return self._plex_server.clients()
def refresh_entity(self, machine_identifier, device, session):
"""Forward refresh dispatch to media_player."""
dispatcher_send(
self._hass,
PLEX_UPDATE_MEDIA_PLAYER_SIGNAL.format(machine_identifier),
device,
session,
)
def sessions(self):
"""Pass through sessions call to plexapi."""
return self._plex_server.sessions()
def update_platforms(self):
"""Update the platform entities."""
available_clients = {}
new_clients = set()
try:
devices = self._plex_server.clients()
sessions = self._plex_server.sessions()
except plexapi.exceptions.BadRequest:
_LOGGER.exception("Error requesting Plex client data from server")
return
except requests.exceptions.RequestException as ex:
_LOGGER.warning(
"Could not connect to Plex server: %s (%s)", self.friendly_name, ex
)
return
for device in devices:
available_clients[device.machineIdentifier] = {"device": device}
if device.machineIdentifier not in self._known_clients:
new_clients.add(device.machineIdentifier)
_LOGGER.debug("New device: %s", device.machineIdentifier)
for session in sessions:
for player in session.players:
available_clients.setdefault(
player.machineIdentifier, {"device": player}
)
available_clients[player.machineIdentifier]["session"] = session
if player.machineIdentifier not in self._known_clients:
new_clients.add(player.machineIdentifier)
_LOGGER.debug("New session: %s", player.machineIdentifier)
new_entity_configs = []
for client_id, client_data in available_clients.items():
if client_id in new_clients:
new_entity_configs.append(client_data)
else:
self.refresh_entity(
client_id, client_data["device"], client_data.get("session")
)
self._known_clients.update(new_clients)
idle_clients = self._known_clients.difference(available_clients)
for client_id in idle_clients:
self.refresh_entity(client_id, None, None)
if new_entity_configs:
dispatcher_send(self._hass, PLEX_NEW_MP_SIGNAL, new_entity_configs)
dispatcher_send(self._hass, PLEX_UPDATE_SENSOR_SIGNAL, sessions)
@property
def friendly_name(self):