1 """Support to interface with the Emby API."""
3 from __future__
import annotations
7 from pyemby
import EmbyServer
8 import voluptuous
as vol
11 PLATFORM_SCHEMA
as MEDIA_PLAYER_PLATFORM_SCHEMA,
13 MediaPlayerEntityFeature,
23 EVENT_HOMEASSISTANT_START,
24 EVENT_HOMEASSISTANT_STOP,
32 _LOGGER = logging.getLogger(__name__)
34 MEDIA_TYPE_TRAILER =
"trailer"
36 DEFAULT_HOST =
"localhost"
38 DEFAULT_SSL_PORT = 8920
42 MediaPlayerEntityFeature.PAUSE
43 | MediaPlayerEntityFeature.PREVIOUS_TRACK
44 | MediaPlayerEntityFeature.NEXT_TRACK
45 | MediaPlayerEntityFeature.STOP
46 | MediaPlayerEntityFeature.SEEK
47 | MediaPlayerEntityFeature.PLAY
50 PLATFORM_SCHEMA = MEDIA_PLAYER_PLATFORM_SCHEMA.extend(
52 vol.Required(CONF_API_KEY): cv.string,
53 vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
54 vol.Optional(CONF_PORT): cv.port,
55 vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean,
63 async_add_entities: AddEntitiesCallback,
64 discovery_info: DiscoveryInfoType |
None =
None,
66 """Set up the Emby platform."""
68 host = config.get(CONF_HOST)
69 key = config.get(CONF_API_KEY)
70 port = config.get(CONF_PORT)
71 ssl = config[CONF_SSL]
74 port = DEFAULT_SSL_PORT
if ssl
else DEFAULT_PORT
76 _LOGGER.debug(
"Setting up Emby server at: %s:%s", host, port)
78 emby = EmbyServer(host, key, port, ssl, hass.loop)
80 active_emby_devices: dict[str, EmbyDevice] = {}
81 inactive_emby_devices: dict[str, EmbyDevice] = {}
84 def device_update_callback(data):
85 """Handle devices which are added to Emby."""
88 for dev_id, dev
in emby.devices.items():
89 active_devices.append(dev_id)
91 dev_id
not in active_emby_devices
92 and dev_id
not in inactive_emby_devices
95 active_emby_devices[dev_id] = new
96 new_devices.append(new)
98 elif dev_id
in inactive_emby_devices
and dev.state !=
"Off":
99 add = inactive_emby_devices.pop(dev_id)
100 active_emby_devices[dev_id] = add
101 _LOGGER.debug(
"Showing %s, item: %s", dev_id, add)
102 add.set_available(
True)
105 _LOGGER.debug(
"Adding new devices: %s", new_devices)
109 def device_removal_callback(data):
110 """Handle the removal of devices from Emby."""
111 if data
in active_emby_devices:
112 rem = active_emby_devices.pop(data)
113 inactive_emby_devices[data] = rem
114 _LOGGER.debug(
"Inactive %s, item: %s", data, rem)
115 rem.set_available(
False)
118 def start_emby(event):
119 """Start Emby connection."""
122 async
def stop_emby(event):
123 """Stop Emby connection."""
126 emby.add_new_devices_callback(device_update_callback)
127 emby.add_stale_devices_callback(device_removal_callback)
129 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, start_emby)
130 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_emby)
134 """Representation of an Emby device."""
136 _attr_should_poll =
False
139 """Initialize the Emby device."""
140 _LOGGER.debug(
"New Emby Device initialized with ID: %s", device_id)
151 """Register callback."""
156 """Handle device updates."""
158 if self.
devicedevice.media_position:
162 elif not self.
devicedevice.is_nowplaying:
170 """Set available property."""
175 """Return control ability."""
176 return self.
devicedevice.supports_remote_control
180 """Return the name of the device."""
181 return f
"Emby {self.device.name}" or DEVICE_DEFAULT_NAME
184 def state(self) -> MediaPlayerState | None:
185 """Return the state of the device."""
186 state = self.
devicedevice.state
187 if state ==
"Paused":
188 return MediaPlayerState.PAUSED
189 if state ==
"Playing":
190 return MediaPlayerState.PLAYING
192 return MediaPlayerState.IDLE
194 return MediaPlayerState.OFF
199 """Return current user as app_name."""
201 return self.
devicedevice.username
205 """Content ID of current playing media."""
206 return self.
devicedevice.media_id
210 """Content type of current playing media."""
211 media_type = self.
devicedevice.media_type
212 if media_type ==
"Episode":
213 return MediaType.TVSHOW
214 if media_type ==
"Movie":
215 return MediaType.MOVIE
216 if media_type ==
"Trailer":
217 return MEDIA_TYPE_TRAILER
218 if media_type ==
"Music":
219 return MediaType.MUSIC
220 if media_type ==
"Video":
221 return MediaType.VIDEO
222 if media_type ==
"Audio":
223 return MediaType.MUSIC
224 if media_type ==
"TvChannel":
225 return MediaType.CHANNEL
230 """Return the duration of current playing media in seconds."""
231 return self.
devicedevice.media_runtime
235 """Return the position of current playing media in seconds."""
240 """When was the position of the current playing media valid.
242 Returns value from homeassistant.util.dt.utcnow().
248 """Return the image URL of current playing media."""
249 return self.
devicedevice.media_image_url
253 """Return the title of current playing media."""
254 return self.
devicedevice.media_title
258 """Season of current playing media (TV Show only)."""
259 return self.
devicedevice.media_season
263 """Return the title of the series of current playing media (TV)."""
264 return self.
devicedevice.media_series_title
268 """Return the episode of current playing media (TV only)."""
269 return self.
devicedevice.media_episode
273 """Return the album name of current playing media (Music only)."""
274 return self.
devicedevice.media_album_name
278 """Return the artist of current playing media (Music track only)."""
279 return self.
devicedevice.media_artist
283 """Return the album artist of current playing media (Music only)."""
284 return self.
devicedevice.media_album_artist
288 """Flag media player features that are supported."""
298 """Pause the media player."""
302 """Stop the media player."""
306 """Send next track command."""
307 await self.
devicedevice.media_next()
310 """Send next track command."""
311 await self.
devicedevice.media_previous()
314 """Send seek command."""
None async_write_ha_state(self)