mirror of
https://github.com/home-assistant/core.git
synced 2025-07-08 22:07:10 +00:00
Add media class browse media attribute (#39770)
This commit is contained in:
parent
71c2557405
commit
2a879afc7a
@ -7,6 +7,8 @@ from arcam.fmj.state import State
|
|||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.media_player import BrowseMedia, MediaPlayerEntity
|
from homeassistant.components.media_player import BrowseMedia, MediaPlayerEntity
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
|
MEDIA_CLASS_DIRECTORY,
|
||||||
|
MEDIA_CLASS_MUSIC,
|
||||||
MEDIA_TYPE_MUSIC,
|
MEDIA_TYPE_MUSIC,
|
||||||
SUPPORT_BROWSE_MEDIA,
|
SUPPORT_BROWSE_MEDIA,
|
||||||
SUPPORT_PLAY_MEDIA,
|
SUPPORT_PLAY_MEDIA,
|
||||||
@ -255,6 +257,7 @@ class ArcamFmj(MediaPlayerEntity):
|
|||||||
radio = [
|
radio = [
|
||||||
BrowseMedia(
|
BrowseMedia(
|
||||||
title=preset.name,
|
title=preset.name,
|
||||||
|
media_class=MEDIA_CLASS_MUSIC,
|
||||||
media_content_id=f"preset:{preset.index}",
|
media_content_id=f"preset:{preset.index}",
|
||||||
media_content_type=MEDIA_TYPE_MUSIC,
|
media_content_type=MEDIA_TYPE_MUSIC,
|
||||||
can_play=True,
|
can_play=True,
|
||||||
@ -265,6 +268,7 @@ class ArcamFmj(MediaPlayerEntity):
|
|||||||
|
|
||||||
root = BrowseMedia(
|
root = BrowseMedia(
|
||||||
title="Root",
|
title="Root",
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
media_content_id="root",
|
media_content_id="root",
|
||||||
media_content_type="library",
|
media_content_type="library",
|
||||||
can_play=False,
|
can_play=False,
|
||||||
|
@ -2,6 +2,14 @@
|
|||||||
|
|
||||||
from homeassistant.components.media_player import BrowseMedia
|
from homeassistant.components.media_player import BrowseMedia
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
|
MEDIA_CLASS_ALBUM,
|
||||||
|
MEDIA_CLASS_ARTIST,
|
||||||
|
MEDIA_CLASS_DIRECTORY,
|
||||||
|
MEDIA_CLASS_MOVIE,
|
||||||
|
MEDIA_CLASS_MUSIC,
|
||||||
|
MEDIA_CLASS_PLAYLIST,
|
||||||
|
MEDIA_CLASS_SEASON,
|
||||||
|
MEDIA_CLASS_TV_SHOW,
|
||||||
MEDIA_TYPE_ALBUM,
|
MEDIA_TYPE_ALBUM,
|
||||||
MEDIA_TYPE_ARTIST,
|
MEDIA_TYPE_ARTIST,
|
||||||
MEDIA_TYPE_EPISODE,
|
MEDIA_TYPE_EPISODE,
|
||||||
@ -26,6 +34,16 @@ EXPANDABLE_MEDIA_TYPES = [
|
|||||||
MEDIA_TYPE_SEASON,
|
MEDIA_TYPE_SEASON,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
CONTENT_TYPE_MEDIA_CLASS = {
|
||||||
|
"library_music": MEDIA_CLASS_MUSIC,
|
||||||
|
MEDIA_TYPE_SEASON: MEDIA_CLASS_SEASON,
|
||||||
|
MEDIA_TYPE_ALBUM: MEDIA_CLASS_ALBUM,
|
||||||
|
MEDIA_TYPE_ARTIST: MEDIA_CLASS_ARTIST,
|
||||||
|
MEDIA_TYPE_MOVIE: MEDIA_CLASS_MOVIE,
|
||||||
|
MEDIA_TYPE_PLAYLIST: MEDIA_CLASS_PLAYLIST,
|
||||||
|
MEDIA_TYPE_TVSHOW: MEDIA_CLASS_TV_SHOW,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def build_item_response(media_library, payload):
|
async def build_item_response(media_library, payload):
|
||||||
"""Create response payload for the provided media query."""
|
"""Create response payload for the provided media query."""
|
||||||
@ -124,6 +142,7 @@ async def build_item_response(media_library, payload):
|
|||||||
return
|
return
|
||||||
|
|
||||||
return BrowseMedia(
|
return BrowseMedia(
|
||||||
|
media_class=CONTENT_TYPE_MEDIA_CLASS[search_type],
|
||||||
media_content_id=payload["search_id"],
|
media_content_id=payload["search_id"],
|
||||||
media_content_type=search_type,
|
media_content_type=search_type,
|
||||||
title=title,
|
title=title,
|
||||||
@ -177,6 +196,7 @@ def item_payload(item, media_library):
|
|||||||
|
|
||||||
return BrowseMedia(
|
return BrowseMedia(
|
||||||
title=title,
|
title=title,
|
||||||
|
media_class=CONTENT_TYPE_MEDIA_CLASS[item["type"]],
|
||||||
media_content_type=media_content_type,
|
media_content_type=media_content_type,
|
||||||
media_content_id=media_content_id,
|
media_content_id=media_content_id,
|
||||||
can_play=can_play,
|
can_play=can_play,
|
||||||
@ -192,6 +212,7 @@ def library_payload(media_library):
|
|||||||
Used by async_browse_media.
|
Used by async_browse_media.
|
||||||
"""
|
"""
|
||||||
library_info = BrowseMedia(
|
library_info = BrowseMedia(
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
media_content_id="library",
|
media_content_id="library",
|
||||||
media_content_type="library",
|
media_content_type="library",
|
||||||
title="Media Library",
|
title="Media Library",
|
||||||
|
@ -822,6 +822,7 @@ class MediaPlayerEntity(Entity):
|
|||||||
Payload should follow this format:
|
Payload should follow this format:
|
||||||
{
|
{
|
||||||
"title": str - Title of the item
|
"title": str - Title of the item
|
||||||
|
"media_class": str - Media class
|
||||||
"media_content_type": str - see below
|
"media_content_type": str - see below
|
||||||
"media_content_id": str - see below
|
"media_content_id": str - see below
|
||||||
- Can be passed back in to browse further
|
- Can be passed back in to browse further
|
||||||
@ -1046,6 +1047,7 @@ class BrowseMedia:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
|
media_class: str,
|
||||||
media_content_id: str,
|
media_content_id: str,
|
||||||
media_content_type: str,
|
media_content_type: str,
|
||||||
title: str,
|
title: str,
|
||||||
@ -1055,6 +1057,7 @@ class BrowseMedia:
|
|||||||
thumbnail: Optional[str] = None,
|
thumbnail: Optional[str] = None,
|
||||||
):
|
):
|
||||||
"""Initialize browse media item."""
|
"""Initialize browse media item."""
|
||||||
|
self.media_class = media_class
|
||||||
self.media_content_id = media_content_id
|
self.media_content_id = media_content_id
|
||||||
self.media_content_type = media_content_type
|
self.media_content_type = media_content_type
|
||||||
self.title = title
|
self.title = title
|
||||||
@ -1067,6 +1070,7 @@ class BrowseMedia:
|
|||||||
"""Convert Media class to browse media dictionary."""
|
"""Convert Media class to browse media dictionary."""
|
||||||
response = {
|
response = {
|
||||||
"title": self.title,
|
"title": self.title,
|
||||||
|
"media_class": self.media_class,
|
||||||
"media_content_type": self.media_content_type,
|
"media_content_type": self.media_content_type,
|
||||||
"media_content_id": self.media_content_id,
|
"media_content_id": self.media_content_id,
|
||||||
"can_play": self.can_play,
|
"can_play": self.can_play,
|
||||||
|
@ -29,6 +29,29 @@ ATTR_SOUND_MODE_LIST = "sound_mode_list"
|
|||||||
|
|
||||||
DOMAIN = "media_player"
|
DOMAIN = "media_player"
|
||||||
|
|
||||||
|
MEDIA_CLASS_ALBUM = "album"
|
||||||
|
MEDIA_CLASS_APP = "app"
|
||||||
|
MEDIA_CLASS_APPS = "apps"
|
||||||
|
MEDIA_CLASS_ARTIST = "artist"
|
||||||
|
MEDIA_CLASS_CHANNEL = "channel"
|
||||||
|
MEDIA_CLASS_CHANNELS = "channels"
|
||||||
|
MEDIA_CLASS_COMPOSER = "composer"
|
||||||
|
MEDIA_CLASS_CONTRIBUTING_ARTIST = "contributing_artist"
|
||||||
|
MEDIA_CLASS_DIRECTORY = "directory"
|
||||||
|
MEDIA_CLASS_EPISODE = "episode"
|
||||||
|
MEDIA_CLASS_GAME = "game"
|
||||||
|
MEDIA_CLASS_GENRE = "genre"
|
||||||
|
MEDIA_CLASS_IMAGE = "image"
|
||||||
|
MEDIA_CLASS_MOVIE = "movie"
|
||||||
|
MEDIA_CLASS_MUSIC = "music"
|
||||||
|
MEDIA_CLASS_PLAYLIST = "playlist"
|
||||||
|
MEDIA_CLASS_PODCAST = "podcast"
|
||||||
|
MEDIA_CLASS_SEASON = "season"
|
||||||
|
MEDIA_CLASS_TRACK = "track"
|
||||||
|
MEDIA_CLASS_TV_SHOW = "tv_show"
|
||||||
|
MEDIA_CLASS_URL = "url"
|
||||||
|
MEDIA_CLASS_VIDEO = "video"
|
||||||
|
|
||||||
MEDIA_TYPE_ALBUM = "album"
|
MEDIA_TYPE_ALBUM = "album"
|
||||||
MEDIA_TYPE_APP = "app"
|
MEDIA_TYPE_APP = "app"
|
||||||
MEDIA_TYPE_APPS = "apps"
|
MEDIA_TYPE_APPS = "apps"
|
||||||
|
@ -6,6 +6,7 @@ from typing import Tuple
|
|||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from homeassistant.components.http import HomeAssistantView
|
from homeassistant.components.http import HomeAssistantView
|
||||||
|
from homeassistant.components.media_player.const import MEDIA_CLASS_DIRECTORY
|
||||||
from homeassistant.components.media_player.errors import BrowseError
|
from homeassistant.components.media_player.errors import BrowseError
|
||||||
from homeassistant.components.media_source.error import Unresolvable
|
from homeassistant.components.media_source.error import Unresolvable
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
@ -114,6 +115,7 @@ class LocalSource(MediaSource):
|
|||||||
media = BrowseMediaSource(
|
media = BrowseMediaSource(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
identifier=f"{source_dir_id}/{path.relative_to(self.hass.config.path('media'))}",
|
identifier=f"{source_dir_id}/{path.relative_to(self.hass.config.path('media'))}",
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
media_content_type="directory",
|
media_content_type="directory",
|
||||||
title=title,
|
title=title,
|
||||||
can_play=is_file,
|
can_play=is_file,
|
||||||
|
@ -5,6 +5,8 @@ from typing import List, Optional, Tuple
|
|||||||
|
|
||||||
from homeassistant.components.media_player import BrowseMedia
|
from homeassistant.components.media_player import BrowseMedia
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
|
MEDIA_CLASS_CHANNEL,
|
||||||
|
MEDIA_CLASS_CHANNELS,
|
||||||
MEDIA_TYPE_CHANNEL,
|
MEDIA_TYPE_CHANNEL,
|
||||||
MEDIA_TYPE_CHANNELS,
|
MEDIA_TYPE_CHANNELS,
|
||||||
)
|
)
|
||||||
@ -52,6 +54,7 @@ class MediaSourceItem:
|
|||||||
base = BrowseMediaSource(
|
base = BrowseMediaSource(
|
||||||
domain=None,
|
domain=None,
|
||||||
identifier=None,
|
identifier=None,
|
||||||
|
media_class=MEDIA_CLASS_CHANNELS,
|
||||||
media_content_type=MEDIA_TYPE_CHANNELS,
|
media_content_type=MEDIA_TYPE_CHANNELS,
|
||||||
title="Media Sources",
|
title="Media Sources",
|
||||||
can_play=False,
|
can_play=False,
|
||||||
@ -61,6 +64,7 @@ class MediaSourceItem:
|
|||||||
BrowseMediaSource(
|
BrowseMediaSource(
|
||||||
domain=source.domain,
|
domain=source.domain,
|
||||||
identifier=None,
|
identifier=None,
|
||||||
|
media_class=MEDIA_CLASS_CHANNEL,
|
||||||
media_content_type=MEDIA_TYPE_CHANNEL,
|
media_content_type=MEDIA_TYPE_CHANNEL,
|
||||||
title=source.name,
|
title=source.name,
|
||||||
can_play=False,
|
can_play=False,
|
||||||
|
@ -4,7 +4,10 @@ import logging
|
|||||||
import re
|
import re
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
from homeassistant.components.media_player.const import MEDIA_TYPE_VIDEO
|
from homeassistant.components.media_player.const import (
|
||||||
|
MEDIA_CLASS_VIDEO,
|
||||||
|
MEDIA_TYPE_VIDEO,
|
||||||
|
)
|
||||||
from homeassistant.components.media_player.errors import BrowseError
|
from homeassistant.components.media_player.errors import BrowseError
|
||||||
from homeassistant.components.media_source.const import MEDIA_MIME_TYPES
|
from homeassistant.components.media_source.const import MEDIA_MIME_TYPES
|
||||||
from homeassistant.components.media_source.error import MediaSourceError, Unresolvable
|
from homeassistant.components.media_source.error import MediaSourceError, Unresolvable
|
||||||
@ -91,6 +94,7 @@ class NetatmoSource(MediaSource):
|
|||||||
media = BrowseMediaSource(
|
media = BrowseMediaSource(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
identifier=path,
|
identifier=path,
|
||||||
|
media_class=MEDIA_CLASS_VIDEO,
|
||||||
media_content_type=MEDIA_TYPE_VIDEO,
|
media_content_type=MEDIA_TYPE_VIDEO,
|
||||||
title=title,
|
title=title,
|
||||||
can_play=bool(
|
can_play=bool(
|
||||||
|
@ -11,6 +11,8 @@ from homeassistant.components.media_player import (
|
|||||||
MediaPlayerEntity,
|
MediaPlayerEntity,
|
||||||
)
|
)
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
|
MEDIA_CLASS_CHANNEL,
|
||||||
|
MEDIA_CLASS_CHANNELS,
|
||||||
MEDIA_TYPE_CHANNEL,
|
MEDIA_TYPE_CHANNEL,
|
||||||
MEDIA_TYPE_CHANNELS,
|
MEDIA_TYPE_CHANNELS,
|
||||||
SUPPORT_BROWSE_MEDIA,
|
SUPPORT_BROWSE_MEDIA,
|
||||||
@ -288,6 +290,7 @@ class PhilipsTVMediaPlayer(MediaPlayerEntity):
|
|||||||
|
|
||||||
return BrowseMedia(
|
return BrowseMedia(
|
||||||
title="Channels",
|
title="Channels",
|
||||||
|
media_class=MEDIA_CLASS_CHANNELS,
|
||||||
media_content_id="",
|
media_content_id="",
|
||||||
media_content_type=MEDIA_TYPE_CHANNELS,
|
media_content_type=MEDIA_TYPE_CHANNELS,
|
||||||
can_play=False,
|
can_play=False,
|
||||||
@ -295,6 +298,7 @@ class PhilipsTVMediaPlayer(MediaPlayerEntity):
|
|||||||
children=[
|
children=[
|
||||||
BrowseMedia(
|
BrowseMedia(
|
||||||
title=channel,
|
title=channel,
|
||||||
|
media_class=MEDIA_CLASS_CHANNEL,
|
||||||
media_content_id=channel,
|
media_content_id=channel,
|
||||||
media_content_type=MEDIA_TYPE_CHANNEL,
|
media_content_type=MEDIA_TYPE_CHANNEL,
|
||||||
can_play=True,
|
can_play=True,
|
||||||
|
@ -2,13 +2,31 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.components.media_player import BrowseMedia
|
from homeassistant.components.media_player import BrowseMedia
|
||||||
|
from homeassistant.components.media_player.const import (
|
||||||
|
MEDIA_CLASS_ALBUM,
|
||||||
|
MEDIA_CLASS_ARTIST,
|
||||||
|
MEDIA_CLASS_DIRECTORY,
|
||||||
|
MEDIA_CLASS_EPISODE,
|
||||||
|
MEDIA_CLASS_MOVIE,
|
||||||
|
MEDIA_CLASS_PLAYLIST,
|
||||||
|
MEDIA_CLASS_SEASON,
|
||||||
|
MEDIA_CLASS_TRACK,
|
||||||
|
MEDIA_CLASS_TV_SHOW,
|
||||||
|
MEDIA_CLASS_VIDEO,
|
||||||
|
)
|
||||||
from homeassistant.components.media_player.errors import BrowseError
|
from homeassistant.components.media_player.errors import BrowseError
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownMediaType(BrowseError):
|
||||||
|
"""Unknown media type."""
|
||||||
|
|
||||||
|
|
||||||
EXPANDABLES = ["album", "artist", "playlist", "season", "show"]
|
EXPANDABLES = ["album", "artist", "playlist", "season", "show"]
|
||||||
PLAYLISTS_BROWSE_PAYLOAD = {
|
PLAYLISTS_BROWSE_PAYLOAD = {
|
||||||
"title": "Playlists",
|
"title": "Playlists",
|
||||||
|
"media_class": MEDIA_CLASS_PLAYLIST,
|
||||||
"media_content_id": "all",
|
"media_content_id": "all",
|
||||||
"media_content_type": "playlists",
|
"media_content_type": "playlists",
|
||||||
"can_play": False,
|
"can_play": False,
|
||||||
@ -19,6 +37,18 @@ SPECIAL_METHODS = {
|
|||||||
"Recently Added": "recentlyAdded",
|
"Recently Added": "recentlyAdded",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ITEM_TYPE_MEDIA_CLASS = {
|
||||||
|
"album": MEDIA_CLASS_ALBUM,
|
||||||
|
"artist": MEDIA_CLASS_ARTIST,
|
||||||
|
"episode": MEDIA_CLASS_EPISODE,
|
||||||
|
"movie": MEDIA_CLASS_MOVIE,
|
||||||
|
"playlist": MEDIA_CLASS_PLAYLIST,
|
||||||
|
"season": MEDIA_CLASS_SEASON,
|
||||||
|
"show": MEDIA_CLASS_TV_SHOW,
|
||||||
|
"track": MEDIA_CLASS_TRACK,
|
||||||
|
"video": MEDIA_CLASS_VIDEO,
|
||||||
|
}
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -34,11 +64,17 @@ def browse_media(
|
|||||||
if media is None:
|
if media is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
media_info = item_payload(media)
|
try:
|
||||||
|
media_info = item_payload(media)
|
||||||
|
except UnknownMediaType:
|
||||||
|
return None
|
||||||
if media_info.can_expand:
|
if media_info.can_expand:
|
||||||
media_info.children = []
|
media_info.children = []
|
||||||
for item in media:
|
for item in media:
|
||||||
media_info.children.append(item_payload(item))
|
try:
|
||||||
|
media_info.children.append(item_payload(item))
|
||||||
|
except UnknownMediaType:
|
||||||
|
continue
|
||||||
return media_info
|
return media_info
|
||||||
|
|
||||||
if media_content_id and ":" in media_content_id:
|
if media_content_id and ":" in media_content_id:
|
||||||
@ -65,6 +101,7 @@ def browse_media(
|
|||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"title": title,
|
"title": title,
|
||||||
|
"media_class": MEDIA_CLASS_DIRECTORY,
|
||||||
"media_content_id": f"{media_content_id}:{special_folder}",
|
"media_content_id": f"{media_content_id}:{special_folder}",
|
||||||
"media_content_type": media_content_type,
|
"media_content_type": media_content_type,
|
||||||
"can_play": False,
|
"can_play": False,
|
||||||
@ -75,7 +112,10 @@ def browse_media(
|
|||||||
method = SPECIAL_METHODS[special_folder]
|
method = SPECIAL_METHODS[special_folder]
|
||||||
items = getattr(library_or_section, method)()
|
items = getattr(library_or_section, method)()
|
||||||
for item in items:
|
for item in items:
|
||||||
payload["children"].append(item_payload(item))
|
try:
|
||||||
|
payload["children"].append(item_payload(item))
|
||||||
|
except UnknownMediaType:
|
||||||
|
continue
|
||||||
return BrowseMedia(**payload)
|
return BrowseMedia(**payload)
|
||||||
|
|
||||||
if media_content_type in ["server", None]:
|
if media_content_type in ["server", None]:
|
||||||
@ -99,8 +139,14 @@ def browse_media(
|
|||||||
|
|
||||||
def item_payload(item):
|
def item_payload(item):
|
||||||
"""Create response payload for a single media item."""
|
"""Create response payload for a single media item."""
|
||||||
|
try:
|
||||||
|
media_class = ITEM_TYPE_MEDIA_CLASS[item.type]
|
||||||
|
except KeyError as err:
|
||||||
|
_LOGGER.debug("Unknown type received: %s", item.type)
|
||||||
|
raise UnknownMediaType from err
|
||||||
payload = {
|
payload = {
|
||||||
"title": item.title,
|
"title": item.title,
|
||||||
|
"media_class": media_class,
|
||||||
"media_content_id": str(item.ratingKey),
|
"media_content_id": str(item.ratingKey),
|
||||||
"media_content_type": item.type,
|
"media_content_type": item.type,
|
||||||
"can_play": True,
|
"can_play": True,
|
||||||
@ -116,6 +162,7 @@ def library_section_payload(section):
|
|||||||
"""Create response payload for a single library section."""
|
"""Create response payload for a single library section."""
|
||||||
return BrowseMedia(
|
return BrowseMedia(
|
||||||
title=section.title,
|
title=section.title,
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
media_content_id=section.key,
|
media_content_id=section.key,
|
||||||
media_content_type="library",
|
media_content_type="library",
|
||||||
can_play=False,
|
can_play=False,
|
||||||
@ -128,6 +175,7 @@ def special_library_payload(parent_payload, special_type):
|
|||||||
title = f"{special_type} ({parent_payload.title})"
|
title = f"{special_type} ({parent_payload.title})"
|
||||||
return BrowseMedia(
|
return BrowseMedia(
|
||||||
title=title,
|
title=title,
|
||||||
|
media_class=parent_payload.media_class,
|
||||||
media_content_id=f"{parent_payload.media_content_id}:{special_type}",
|
media_content_id=f"{parent_payload.media_content_id}:{special_type}",
|
||||||
media_content_type=parent_payload.media_content_type,
|
media_content_type=parent_payload.media_content_type,
|
||||||
can_play=False,
|
can_play=False,
|
||||||
@ -139,6 +187,7 @@ def server_payload(plex_server):
|
|||||||
"""Create response payload to describe libraries of the Plex server."""
|
"""Create response payload to describe libraries of the Plex server."""
|
||||||
server_info = BrowseMedia(
|
server_info = BrowseMedia(
|
||||||
title=plex_server.friendly_name,
|
title=plex_server.friendly_name,
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
media_content_id=plex_server.machine_identifier,
|
media_content_id=plex_server.machine_identifier,
|
||||||
media_content_type="server",
|
media_content_type="server",
|
||||||
can_play=False,
|
can_play=False,
|
||||||
@ -165,7 +214,10 @@ def library_payload(plex_server, library_id):
|
|||||||
special_library_payload(library_info, "Recently Added")
|
special_library_payload(library_info, "Recently Added")
|
||||||
)
|
)
|
||||||
for item in library.all():
|
for item in library.all():
|
||||||
library_info.children.append(item_payload(item))
|
try:
|
||||||
|
library_info.children.append(item_payload(item))
|
||||||
|
except UnknownMediaType:
|
||||||
|
continue
|
||||||
return library_info
|
return library_info
|
||||||
|
|
||||||
|
|
||||||
@ -173,5 +225,8 @@ def playlists_payload(plex_server):
|
|||||||
"""Create response payload for all available playlists."""
|
"""Create response payload for all available playlists."""
|
||||||
playlists_info = {**PLAYLISTS_BROWSE_PAYLOAD, "children": []}
|
playlists_info = {**PLAYLISTS_BROWSE_PAYLOAD, "children": []}
|
||||||
for playlist in plex_server.playlists():
|
for playlist in plex_server.playlists():
|
||||||
playlists_info["children"].append(item_payload(playlist))
|
try:
|
||||||
|
playlists_info["children"].append(item_payload(playlist))
|
||||||
|
except UnknownMediaType:
|
||||||
|
continue
|
||||||
return BrowseMedia(**playlists_info)
|
return BrowseMedia(**playlists_info)
|
||||||
|
@ -11,6 +11,11 @@ from homeassistant.components.media_player import (
|
|||||||
MediaPlayerEntity,
|
MediaPlayerEntity,
|
||||||
)
|
)
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
|
MEDIA_CLASS_APP,
|
||||||
|
MEDIA_CLASS_APPS,
|
||||||
|
MEDIA_CLASS_CHANNEL,
|
||||||
|
MEDIA_CLASS_CHANNELS,
|
||||||
|
MEDIA_CLASS_DIRECTORY,
|
||||||
MEDIA_TYPE_APP,
|
MEDIA_TYPE_APP,
|
||||||
MEDIA_TYPE_APPS,
|
MEDIA_TYPE_APPS,
|
||||||
MEDIA_TYPE_CHANNEL,
|
MEDIA_TYPE_CHANNEL,
|
||||||
@ -79,6 +84,7 @@ def browse_media_library(channels: bool = False) -> BrowseMedia:
|
|||||||
"""Create response payload to describe contents of a specific library."""
|
"""Create response payload to describe contents of a specific library."""
|
||||||
library_info = BrowseMedia(
|
library_info = BrowseMedia(
|
||||||
title="Media Library",
|
title="Media Library",
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
media_content_id="library",
|
media_content_id="library",
|
||||||
media_content_type="library",
|
media_content_type="library",
|
||||||
can_play=False,
|
can_play=False,
|
||||||
@ -89,6 +95,7 @@ def browse_media_library(channels: bool = False) -> BrowseMedia:
|
|||||||
library_info.children.append(
|
library_info.children.append(
|
||||||
BrowseMedia(
|
BrowseMedia(
|
||||||
title="Apps",
|
title="Apps",
|
||||||
|
media_class=MEDIA_CLASS_APPS,
|
||||||
media_content_id="apps",
|
media_content_id="apps",
|
||||||
media_content_type=MEDIA_TYPE_APPS,
|
media_content_type=MEDIA_TYPE_APPS,
|
||||||
can_expand=True,
|
can_expand=True,
|
||||||
@ -100,6 +107,7 @@ def browse_media_library(channels: bool = False) -> BrowseMedia:
|
|||||||
library_info.children.append(
|
library_info.children.append(
|
||||||
BrowseMedia(
|
BrowseMedia(
|
||||||
title="Channels",
|
title="Channels",
|
||||||
|
media_class=MEDIA_CLASS_CHANNELS,
|
||||||
media_content_id="channels",
|
media_content_id="channels",
|
||||||
media_content_type=MEDIA_TYPE_CHANNELS,
|
media_content_type=MEDIA_TYPE_CHANNELS,
|
||||||
can_expand=True,
|
can_expand=True,
|
||||||
@ -286,6 +294,7 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
|
|||||||
if media_content_type == MEDIA_TYPE_APPS:
|
if media_content_type == MEDIA_TYPE_APPS:
|
||||||
response = BrowseMedia(
|
response = BrowseMedia(
|
||||||
title="Apps",
|
title="Apps",
|
||||||
|
media_class=MEDIA_CLASS_APPS,
|
||||||
media_content_id="apps",
|
media_content_id="apps",
|
||||||
media_content_type=MEDIA_TYPE_APPS,
|
media_content_type=MEDIA_TYPE_APPS,
|
||||||
can_expand=True,
|
can_expand=True,
|
||||||
@ -294,6 +303,7 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
|
|||||||
BrowseMedia(
|
BrowseMedia(
|
||||||
title=app.name,
|
title=app.name,
|
||||||
thumbnail=self.coordinator.roku.app_icon_url(app.app_id),
|
thumbnail=self.coordinator.roku.app_icon_url(app.app_id),
|
||||||
|
media_class=MEDIA_CLASS_APP,
|
||||||
media_content_id=app.app_id,
|
media_content_id=app.app_id,
|
||||||
media_content_type=MEDIA_TYPE_APP,
|
media_content_type=MEDIA_TYPE_APP,
|
||||||
can_play=True,
|
can_play=True,
|
||||||
@ -306,6 +316,7 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
|
|||||||
if media_content_type == MEDIA_TYPE_CHANNELS:
|
if media_content_type == MEDIA_TYPE_CHANNELS:
|
||||||
response = BrowseMedia(
|
response = BrowseMedia(
|
||||||
title="Channels",
|
title="Channels",
|
||||||
|
media_class=MEDIA_CLASS_CHANNELS,
|
||||||
media_content_id="channels",
|
media_content_id="channels",
|
||||||
media_content_type=MEDIA_TYPE_CHANNELS,
|
media_content_type=MEDIA_TYPE_CHANNELS,
|
||||||
can_expand=True,
|
can_expand=True,
|
||||||
@ -313,6 +324,7 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity):
|
|||||||
children=[
|
children=[
|
||||||
BrowseMedia(
|
BrowseMedia(
|
||||||
title=channel.name,
|
title=channel.name,
|
||||||
|
media_class=MEDIA_CLASS_CHANNEL,
|
||||||
media_content_id=channel.number,
|
media_content_id=channel.number,
|
||||||
media_content_type=MEDIA_TYPE_CHANNEL,
|
media_content_type=MEDIA_TYPE_CHANNEL,
|
||||||
can_play=True,
|
can_play=True,
|
||||||
|
@ -17,6 +17,14 @@ import voluptuous as vol
|
|||||||
from homeassistant.components.media_player import BrowseMedia, MediaPlayerEntity
|
from homeassistant.components.media_player import BrowseMedia, MediaPlayerEntity
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
ATTR_MEDIA_ENQUEUE,
|
ATTR_MEDIA_ENQUEUE,
|
||||||
|
MEDIA_CLASS_ALBUM,
|
||||||
|
MEDIA_CLASS_ARTIST,
|
||||||
|
MEDIA_CLASS_COMPOSER,
|
||||||
|
MEDIA_CLASS_CONTRIBUTING_ARTIST,
|
||||||
|
MEDIA_CLASS_DIRECTORY,
|
||||||
|
MEDIA_CLASS_GENRE,
|
||||||
|
MEDIA_CLASS_PLAYLIST,
|
||||||
|
MEDIA_CLASS_TRACK,
|
||||||
MEDIA_TYPE_ALBUM,
|
MEDIA_TYPE_ALBUM,
|
||||||
MEDIA_TYPE_ARTIST,
|
MEDIA_TYPE_ARTIST,
|
||||||
MEDIA_TYPE_COMPOSER,
|
MEDIA_TYPE_COMPOSER,
|
||||||
@ -103,6 +111,23 @@ EXPANDABLE_MEDIA_TYPES = [
|
|||||||
SONOS_PLAYLISTS,
|
SONOS_PLAYLISTS,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SONOS_TO_MEDIA_CLASSES = {
|
||||||
|
SONOS_ALBUM: MEDIA_CLASS_ALBUM,
|
||||||
|
SONOS_ALBUM_ARTIST: MEDIA_CLASS_ARTIST,
|
||||||
|
SONOS_ARTIST: MEDIA_CLASS_CONTRIBUTING_ARTIST,
|
||||||
|
SONOS_COMPOSER: MEDIA_CLASS_COMPOSER,
|
||||||
|
SONOS_GENRE: MEDIA_CLASS_GENRE,
|
||||||
|
SONOS_PLAYLISTS: MEDIA_CLASS_PLAYLIST,
|
||||||
|
SONOS_TRACKS: MEDIA_CLASS_TRACK,
|
||||||
|
"object.container.album.musicAlbum": MEDIA_CLASS_ALBUM,
|
||||||
|
"object.container.genre.musicGenre": MEDIA_CLASS_PLAYLIST,
|
||||||
|
"object.container.person.composer": MEDIA_CLASS_PLAYLIST,
|
||||||
|
"object.container.person.musicArtist": MEDIA_CLASS_ARTIST,
|
||||||
|
"object.container.playlistContainer.sameArtist": MEDIA_CLASS_ARTIST,
|
||||||
|
"object.container.playlistContainer": MEDIA_CLASS_PLAYLIST,
|
||||||
|
"object.item.audioItem.musicTrack": MEDIA_CLASS_TRACK,
|
||||||
|
}
|
||||||
|
|
||||||
SONOS_TO_MEDIA_TYPES = {
|
SONOS_TO_MEDIA_TYPES = {
|
||||||
SONOS_ALBUM: MEDIA_TYPE_ALBUM,
|
SONOS_ALBUM: MEDIA_TYPE_ALBUM,
|
||||||
SONOS_ALBUM_ARTIST: MEDIA_TYPE_ARTIST,
|
SONOS_ALBUM_ARTIST: MEDIA_TYPE_ARTIST,
|
||||||
@ -1462,9 +1487,12 @@ def build_item_response(media_library, payload):
|
|||||||
except IndexError:
|
except IndexError:
|
||||||
title = LIBRARY_TITLES_MAPPING[payload["idstring"]]
|
title = LIBRARY_TITLES_MAPPING[payload["idstring"]]
|
||||||
|
|
||||||
|
media_class = SONOS_TO_MEDIA_CLASSES[MEDIA_TYPES_TO_SONOS[payload["search_type"]]]
|
||||||
|
|
||||||
return BrowseMedia(
|
return BrowseMedia(
|
||||||
title=title,
|
title=title,
|
||||||
thumbnail=thumbnail,
|
thumbnail=thumbnail,
|
||||||
|
media_class=media_class,
|
||||||
media_content_id=payload["idstring"],
|
media_content_id=payload["idstring"],
|
||||||
media_content_type=payload["search_type"],
|
media_content_type=payload["search_type"],
|
||||||
children=[item_payload(item) for item in media],
|
children=[item_payload(item) for item in media],
|
||||||
@ -1482,6 +1510,7 @@ def item_payload(item):
|
|||||||
return BrowseMedia(
|
return BrowseMedia(
|
||||||
title=item.title,
|
title=item.title,
|
||||||
thumbnail=getattr(item, "album_art_uri", None),
|
thumbnail=getattr(item, "album_art_uri", None),
|
||||||
|
media_class=SONOS_TO_MEDIA_CLASSES[get_media_type(item)],
|
||||||
media_content_id=get_content_id(item),
|
media_content_id=get_content_id(item),
|
||||||
media_content_type=SONOS_TO_MEDIA_TYPES[get_media_type(item)],
|
media_content_type=SONOS_TO_MEDIA_TYPES[get_media_type(item)],
|
||||||
can_play=can_play(item.item_class),
|
can_play=can_play(item.item_class),
|
||||||
@ -1497,6 +1526,7 @@ def library_payload(media_library):
|
|||||||
"""
|
"""
|
||||||
return BrowseMedia(
|
return BrowseMedia(
|
||||||
title="Music Library",
|
title="Music Library",
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
media_content_id="library",
|
media_content_id="library",
|
||||||
media_content_type="library",
|
media_content_type="library",
|
||||||
can_play=False,
|
can_play=False,
|
||||||
|
@ -11,6 +11,12 @@ from yarl import URL
|
|||||||
|
|
||||||
from homeassistant.components.media_player import BrowseMedia, MediaPlayerEntity
|
from homeassistant.components.media_player import BrowseMedia, MediaPlayerEntity
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
|
MEDIA_CLASS_ALBUM,
|
||||||
|
MEDIA_CLASS_ARTIST,
|
||||||
|
MEDIA_CLASS_DIRECTORY,
|
||||||
|
MEDIA_CLASS_PLAYLIST,
|
||||||
|
MEDIA_CLASS_PODCAST,
|
||||||
|
MEDIA_CLASS_TRACK,
|
||||||
MEDIA_TYPE_ALBUM,
|
MEDIA_TYPE_ALBUM,
|
||||||
MEDIA_TYPE_ARTIST,
|
MEDIA_TYPE_ARTIST,
|
||||||
MEDIA_TYPE_EPISODE,
|
MEDIA_TYPE_EPISODE,
|
||||||
@ -96,6 +102,29 @@ LIBRARY_MAP = {
|
|||||||
"new_releases": "New Releases",
|
"new_releases": "New Releases",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONTENT_TYPE_MEDIA_CLASS = {
|
||||||
|
"current_user_playlists": MEDIA_CLASS_PLAYLIST,
|
||||||
|
"current_user_followed_artists": MEDIA_CLASS_ARTIST,
|
||||||
|
"current_user_saved_albums": MEDIA_CLASS_ALBUM,
|
||||||
|
"current_user_saved_tracks": MEDIA_CLASS_TRACK,
|
||||||
|
"current_user_saved_shows": MEDIA_CLASS_PODCAST,
|
||||||
|
"current_user_recently_played": MEDIA_CLASS_TRACK,
|
||||||
|
"current_user_top_artists": MEDIA_CLASS_ARTIST,
|
||||||
|
"current_user_top_tracks": MEDIA_CLASS_TRACK,
|
||||||
|
"featured_playlists": MEDIA_CLASS_PLAYLIST,
|
||||||
|
"categories": MEDIA_CLASS_DIRECTORY,
|
||||||
|
"category_playlists": MEDIA_CLASS_PLAYLIST,
|
||||||
|
"new_releases": MEDIA_CLASS_ALBUM,
|
||||||
|
MEDIA_TYPE_PLAYLIST: MEDIA_CLASS_PLAYLIST,
|
||||||
|
MEDIA_TYPE_ALBUM: MEDIA_CLASS_ALBUM,
|
||||||
|
MEDIA_TYPE_ARTIST: MEDIA_CLASS_ARTIST,
|
||||||
|
MEDIA_TYPE_SHOW: MEDIA_CLASS_PODCAST,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MissingMediaInformation(BrowseError):
|
||||||
|
"""Missing media required information."""
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -498,24 +527,32 @@ def build_item_response(spotify, user, payload):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
if media_content_type == "categories":
|
if media_content_type == "categories":
|
||||||
return BrowseMedia(
|
media_item = BrowseMedia(
|
||||||
title=LIBRARY_MAP.get(media_content_id),
|
title=LIBRARY_MAP.get(media_content_id),
|
||||||
|
media_class=CONTENT_TYPE_MEDIA_CLASS[media_content_type],
|
||||||
media_content_id=media_content_id,
|
media_content_id=media_content_id,
|
||||||
media_content_type=media_content_type,
|
media_content_type=media_content_type,
|
||||||
can_play=False,
|
can_play=False,
|
||||||
can_expand=True,
|
can_expand=True,
|
||||||
children=[
|
children=[],
|
||||||
|
)
|
||||||
|
for item in items:
|
||||||
|
try:
|
||||||
|
item_id = item["id"]
|
||||||
|
except KeyError:
|
||||||
|
_LOGGER.debug("Missing id for media item: %s", item)
|
||||||
|
continue
|
||||||
|
media_item.children.append(
|
||||||
BrowseMedia(
|
BrowseMedia(
|
||||||
title=item.get("name"),
|
title=item.get("name"),
|
||||||
media_content_id=item["id"],
|
media_class=MEDIA_CLASS_PLAYLIST,
|
||||||
|
media_content_id=item_id,
|
||||||
media_content_type="category_playlists",
|
media_content_type="category_playlists",
|
||||||
thumbnail=fetch_image_url(item, key="icons"),
|
thumbnail=fetch_image_url(item, key="icons"),
|
||||||
can_play=False,
|
can_play=False,
|
||||||
can_expand=True,
|
can_expand=True,
|
||||||
)
|
)
|
||||||
for item in items
|
)
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
if title is None:
|
if title is None:
|
||||||
if "name" in media:
|
if "name" in media:
|
||||||
@ -525,12 +562,18 @@ def build_item_response(spotify, user, payload):
|
|||||||
|
|
||||||
response = {
|
response = {
|
||||||
"title": title,
|
"title": title,
|
||||||
|
"media_class": CONTENT_TYPE_MEDIA_CLASS[media_content_type],
|
||||||
"media_content_id": media_content_id,
|
"media_content_id": media_content_id,
|
||||||
"media_content_type": media_content_type,
|
"media_content_type": media_content_type,
|
||||||
"can_play": media_content_type in PLAYABLE_MEDIA_TYPES,
|
"can_play": media_content_type in PLAYABLE_MEDIA_TYPES,
|
||||||
"children": [item_payload(item) for item in items],
|
"children": [],
|
||||||
"can_expand": True,
|
"can_expand": True,
|
||||||
}
|
}
|
||||||
|
for item in items:
|
||||||
|
try:
|
||||||
|
response["children"].append(item_payload(item))
|
||||||
|
except MissingMediaInformation:
|
||||||
|
continue
|
||||||
|
|
||||||
if "images" in media:
|
if "images" in media:
|
||||||
response["thumbnail"] = fetch_image_url(media)
|
response["thumbnail"] = fetch_image_url(media)
|
||||||
@ -546,20 +589,31 @@ def item_payload(item):
|
|||||||
|
|
||||||
Used by async_browse_media.
|
Used by async_browse_media.
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
|
media_type = item["type"]
|
||||||
|
media_id = item["uri"]
|
||||||
|
except KeyError as err:
|
||||||
|
_LOGGER.debug("Missing type or uri for media item: %s", item)
|
||||||
|
raise MissingMediaInformation from err
|
||||||
|
|
||||||
can_expand = item["type"] not in [
|
can_expand = media_type not in [
|
||||||
MEDIA_TYPE_TRACK,
|
MEDIA_TYPE_TRACK,
|
||||||
MEDIA_TYPE_EPISODE,
|
MEDIA_TYPE_EPISODE,
|
||||||
]
|
]
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"title": item.get("name"),
|
"title": item.get("name"),
|
||||||
"media_content_id": item["uri"],
|
"media_content_id": media_id,
|
||||||
"media_content_type": item["type"],
|
"media_content_type": media_type,
|
||||||
"can_play": item["type"] in PLAYABLE_MEDIA_TYPES,
|
"can_play": media_type in PLAYABLE_MEDIA_TYPES,
|
||||||
"can_expand": can_expand,
|
"can_expand": can_expand,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
**payload,
|
||||||
|
"media_class": CONTENT_TYPE_MEDIA_CLASS[media_type],
|
||||||
|
}
|
||||||
|
|
||||||
if "images" in item:
|
if "images" in item:
|
||||||
payload["thumbnail"] = fetch_image_url(item)
|
payload["thumbnail"] = fetch_image_url(item)
|
||||||
elif MEDIA_TYPE_ALBUM in item:
|
elif MEDIA_TYPE_ALBUM in item:
|
||||||
@ -576,6 +630,7 @@ def library_payload():
|
|||||||
"""
|
"""
|
||||||
library_info = {
|
library_info = {
|
||||||
"title": "Media Library",
|
"title": "Media Library",
|
||||||
|
"media_class": MEDIA_CLASS_DIRECTORY,
|
||||||
"media_content_id": "library",
|
"media_content_id": "library",
|
||||||
"media_content_type": "library",
|
"media_content_type": "library",
|
||||||
"can_play": False,
|
"can_play": False,
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components import media_source
|
from homeassistant.components import media_source
|
||||||
|
from homeassistant.components.media_player.const import MEDIA_CLASS_DIRECTORY
|
||||||
from homeassistant.components.media_player.errors import BrowseError
|
from homeassistant.components.media_player.errors import BrowseError
|
||||||
from homeassistant.components.media_source import const
|
from homeassistant.components.media_source import const
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
@ -77,6 +78,7 @@ async def test_websocket_browse_media(hass, hass_ws_client):
|
|||||||
domain=const.DOMAIN,
|
domain=const.DOMAIN,
|
||||||
identifier="/media",
|
identifier="/media",
|
||||||
title="Local Media",
|
title="Local Media",
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
media_content_type="listing",
|
media_content_type="listing",
|
||||||
can_play=False,
|
can_play=False,
|
||||||
can_expand=True,
|
can_expand=True,
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
"""Test Media Source model methods."""
|
"""Test Media Source model methods."""
|
||||||
from homeassistant.components.media_player.const import MEDIA_TYPE_MUSIC
|
from homeassistant.components.media_player.const import (
|
||||||
|
MEDIA_CLASS_DIRECTORY,
|
||||||
|
MEDIA_CLASS_MUSIC,
|
||||||
|
MEDIA_TYPE_MUSIC,
|
||||||
|
)
|
||||||
from homeassistant.components.media_source import const, models
|
from homeassistant.components.media_source import const, models
|
||||||
|
|
||||||
|
|
||||||
@ -8,6 +12,7 @@ async def test_browse_media_as_dict():
|
|||||||
base = models.BrowseMediaSource(
|
base = models.BrowseMediaSource(
|
||||||
domain=const.DOMAIN,
|
domain=const.DOMAIN,
|
||||||
identifier="media",
|
identifier="media",
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
media_content_type="folder",
|
media_content_type="folder",
|
||||||
title="media/",
|
title="media/",
|
||||||
can_play=False,
|
can_play=False,
|
||||||
@ -17,6 +22,7 @@ async def test_browse_media_as_dict():
|
|||||||
models.BrowseMediaSource(
|
models.BrowseMediaSource(
|
||||||
domain=const.DOMAIN,
|
domain=const.DOMAIN,
|
||||||
identifier="media/test.mp3",
|
identifier="media/test.mp3",
|
||||||
|
media_class=MEDIA_CLASS_MUSIC,
|
||||||
media_content_type=MEDIA_TYPE_MUSIC,
|
media_content_type=MEDIA_TYPE_MUSIC,
|
||||||
title="test.mp3",
|
title="test.mp3",
|
||||||
can_play=True,
|
can_play=True,
|
||||||
@ -26,12 +32,14 @@ async def test_browse_media_as_dict():
|
|||||||
|
|
||||||
item = base.as_dict()
|
item = base.as_dict()
|
||||||
assert item["title"] == "media/"
|
assert item["title"] == "media/"
|
||||||
|
assert item["media_class"] == MEDIA_CLASS_DIRECTORY
|
||||||
assert item["media_content_type"] == "folder"
|
assert item["media_content_type"] == "folder"
|
||||||
assert item["media_content_id"] == f"{const.URI_SCHEME}{const.DOMAIN}/media"
|
assert item["media_content_id"] == f"{const.URI_SCHEME}{const.DOMAIN}/media"
|
||||||
assert not item["can_play"]
|
assert not item["can_play"]
|
||||||
assert item["can_expand"]
|
assert item["can_expand"]
|
||||||
assert len(item["children"]) == 1
|
assert len(item["children"]) == 1
|
||||||
assert item["children"][0]["title"] == "test.mp3"
|
assert item["children"][0]["title"] == "test.mp3"
|
||||||
|
assert item["children"][0]["media_class"] == MEDIA_CLASS_MUSIC
|
||||||
|
|
||||||
|
|
||||||
async def test_browse_media_parent_no_children():
|
async def test_browse_media_parent_no_children():
|
||||||
@ -39,6 +47,7 @@ async def test_browse_media_parent_no_children():
|
|||||||
base = models.BrowseMediaSource(
|
base = models.BrowseMediaSource(
|
||||||
domain=const.DOMAIN,
|
domain=const.DOMAIN,
|
||||||
identifier="media",
|
identifier="media",
|
||||||
|
media_class=MEDIA_CLASS_DIRECTORY,
|
||||||
media_content_type="folder",
|
media_content_type="folder",
|
||||||
title="media/",
|
title="media/",
|
||||||
can_play=False,
|
can_play=False,
|
||||||
@ -47,6 +56,7 @@ async def test_browse_media_parent_no_children():
|
|||||||
|
|
||||||
item = base.as_dict()
|
item = base.as_dict()
|
||||||
assert item["title"] == "media/"
|
assert item["title"] == "media/"
|
||||||
|
assert item["media_class"] == MEDIA_CLASS_DIRECTORY
|
||||||
assert item["media_content_type"] == "folder"
|
assert item["media_content_type"] == "folder"
|
||||||
assert item["media_content_id"] == f"{const.URI_SCHEME}{const.DOMAIN}/media"
|
assert item["media_content_id"] == f"{const.URI_SCHEME}{const.DOMAIN}/media"
|
||||||
assert not item["can_play"]
|
assert not item["can_play"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user