Compare commits

...
Sign in to create a new pull request.

2 commits

Author SHA1 Message Date
Erik
deb196af36 Enable spotify media browsing for google cast devices 2022-01-28 14:26:35 +01:00
Erik
46239cc97c Minor refactoring of cast media_player 2022-01-28 14:23:18 +01:00

View file

@ -4,7 +4,6 @@ from __future__ import annotations
import asyncio
from contextlib import suppress
from datetime import datetime, timedelta
import functools as ft
import json
import logging
from urllib.parse import quote
@ -21,7 +20,7 @@ from pychromecast.socket_client import (
)
import voluptuous as vol
from homeassistant.components import media_source, plex, zeroconf
from homeassistant.components import media_source, plex, spotify, zeroconf
from homeassistant.components.http.auth import async_sign_path
from homeassistant.components.media_player import (
BrowseError,
@ -461,33 +460,10 @@ class CastDevice(MediaPlayerEntity):
media_controller = self._media_controller()
media_controller.seek(position)
async def async_browse_media(self, media_content_type=None, media_content_id=None):
"""Implement the websocket media browsing helper."""
kwargs = {}
async def _async_root_payload(self, content_filter):
"""Generate root node."""
children = []
if self._chromecast.cast_type == pychromecast.const.CAST_TYPE_AUDIO:
kwargs["content_filter"] = lambda item: item.media_content_type.startswith(
"audio/"
)
if media_content_id is not None:
if plex.is_plex_media_id(media_content_id):
return await plex.async_browse_media(
self.hass,
media_content_type,
media_content_id,
platform=CAST_DOMAIN,
)
return await media_source.async_browse_media(
self.hass, media_content_id, **kwargs
)
if media_content_type == "plex":
return await plex.async_browse_media(
self.hass, None, None, platform=CAST_DOMAIN
)
# Add external sources
if "plex" in self.hass.config.components:
children.append(
BrowseMedia(
@ -501,15 +477,30 @@ class CastDevice(MediaPlayerEntity):
)
)
if "spotify" in self.hass.config.components:
children.append(
BrowseMedia(
title="Spotify",
media_class=MEDIA_CLASS_APP,
media_content_id="",
media_content_type="spotify",
thumbnail="https://brands.home-assistant.io/_/spotify/logo.png",
can_play=False,
can_expand=True,
)
)
# Add local media source
try:
result = await media_source.async_browse_media(
self.hass, media_content_id, **kwargs
self.hass, None, content_filter=content_filter
)
children.append(result)
except BrowseError:
if not children:
raise
# If there's only one media source, resolve it
if len(children) == 1:
return await self.async_browse_media(
children[0].media_content_type,
@ -526,6 +517,44 @@ class CastDevice(MediaPlayerEntity):
children=children,
)
async def async_browse_media(self, media_content_type=None, media_content_id=None):
"""Implement the websocket media browsing helper."""
content_filter = None
if self._chromecast.cast_type == pychromecast.const.CAST_TYPE_AUDIO:
def audio_content_filter(item):
"""Filter non audio content."""
return item.media_content_type.startswith("audio/")
content_filter = audio_content_filter
if media_content_id is None:
return await self._async_root_payload(content_filter)
if plex.is_plex_media_id(media_content_id):
return await plex.async_browse_media(
self.hass, media_content_type, media_content_id, platform=CAST_DOMAIN
)
if media_content_type == "plex":
return await plex.async_browse_media(
self.hass, None, None, platform=CAST_DOMAIN
)
if spotify.is_spotify_media_type(media_content_type):
return await spotify.async_browse_media(
self.hass, media_content_type, media_content_id, can_play_artist=False
)
if media_content_type == "spotify":
return await spotify.async_browse_media(
self.hass, None, None, can_play_artist=False
)
return await media_source.async_browse_media(
self.hass, media_content_id, content_filter=content_filter
)
async def async_play_media(self, media_type, media_id, **kwargs):
"""Play a piece of media."""
# Handle media_source
@ -547,12 +576,6 @@ class CastDevice(MediaPlayerEntity):
hass_url = get_url(self.hass, prefer_external=True)
media_id = f"{hass_url}{media_id}"
await self.hass.async_add_executor_job(
ft.partial(self.play_media, media_type, media_id, **kwargs)
)
def play_media(self, media_type, media_id, **kwargs):
"""Play media from a URL."""
extra = kwargs.get(ATTR_MEDIA_EXTRA, {})
metadata = extra.get("metadata")
@ -571,7 +594,9 @@ class CastDevice(MediaPlayerEntity):
if "app_id" in app_data:
app_id = app_data.pop("app_id")
_LOGGER.info("Starting Cast app by ID %s", app_id)
self._chromecast.start_app(app_id)
await self.hass.async_add_executor_job(
self._chromecast.start_app, app_id
)
if app_data:
_LOGGER.warning(
"Extra keys %s were ignored. Please use app_name to cast media",
@ -581,21 +606,35 @@ class CastDevice(MediaPlayerEntity):
app_name = app_data.pop("app_name")
try:
quick_play(self._chromecast, app_name, app_data)
await self.hass.async_add_executor_job(
quick_play, self._chromecast, app_name, app_data
)
except NotImplementedError:
_LOGGER.error("App %s not supported", app_name)
# Handle plex
elif media_id and media_id.startswith(PLEX_URI_SCHEME):
media_id = media_id[len(PLEX_URI_SCHEME) :]
media = lookup_plex_media(self.hass, media_type, media_id)
media = await self.hass.async_add_executor_job(
lookup_plex_media, self.hass, media_type, media_id
)
if media is None:
return
controller = PlexController()
self._chromecast.register_handler(controller)
controller.play_media(media)
await self.hass.async_add_executor_job(controller.play_media, media)
# Handle spotify
elif media_id and media_id.startswith("spotify:"):
data = {"entity_id": self.entity_id, "uri": media_id}
await self.hass.services.async_call(
"spotcast", "start", data, blocking=False
)
else:
app_data = {"media_id": media_id, "media_type": media_type, **extra}
quick_play(self._chromecast, "default_media_receiver", app_data)
await self.hass.async_add_executor_job(
quick_play, self._chromecast, "default_media_receiver", app_data
)
def _media_status(self):
"""