Use new constants in dlna_dmr media player (#78045)

This commit is contained in:
epenet 2022-09-09 09:03:59 +02:00 committed by GitHub
parent 7ff23506fe
commit 8b3ce8c58c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 179 additions and 183 deletions

View File

@ -7,7 +7,7 @@ from typing import Final
from async_upnp_client.profiles.dlna import PlayMode as _PlayMode
from homeassistant.components.media_player import const as _mp_const
from homeassistant.components.media_player import MediaType, RepeatMode
LOGGER = logging.getLogger(__package__)
@ -28,66 +28,66 @@ PROTOCOL_ANY: Final = "*"
STREAMABLE_PROTOCOLS: Final = [PROTOCOL_HTTP, PROTOCOL_RTSP, PROTOCOL_ANY]
# Map UPnP class to media_player media_content_type
MEDIA_TYPE_MAP: Mapping[str, str] = {
"object": _mp_const.MEDIA_TYPE_URL,
"object.item": _mp_const.MEDIA_TYPE_URL,
"object.item.imageItem": _mp_const.MEDIA_TYPE_IMAGE,
"object.item.imageItem.photo": _mp_const.MEDIA_TYPE_IMAGE,
"object.item.audioItem": _mp_const.MEDIA_TYPE_MUSIC,
"object.item.audioItem.musicTrack": _mp_const.MEDIA_TYPE_MUSIC,
"object.item.audioItem.audioBroadcast": _mp_const.MEDIA_TYPE_MUSIC,
"object.item.audioItem.audioBook": _mp_const.MEDIA_TYPE_PODCAST,
"object.item.videoItem": _mp_const.MEDIA_TYPE_VIDEO,
"object.item.videoItem.movie": _mp_const.MEDIA_TYPE_MOVIE,
"object.item.videoItem.videoBroadcast": _mp_const.MEDIA_TYPE_TVSHOW,
"object.item.videoItem.musicVideoClip": _mp_const.MEDIA_TYPE_VIDEO,
"object.item.playlistItem": _mp_const.MEDIA_TYPE_PLAYLIST,
"object.item.textItem": _mp_const.MEDIA_TYPE_URL,
"object.item.bookmarkItem": _mp_const.MEDIA_TYPE_URL,
"object.item.epgItem": _mp_const.MEDIA_TYPE_EPISODE,
"object.item.epgItem.audioProgram": _mp_const.MEDIA_TYPE_EPISODE,
"object.item.epgItem.videoProgram": _mp_const.MEDIA_TYPE_EPISODE,
"object.container": _mp_const.MEDIA_TYPE_PLAYLIST,
"object.container.person": _mp_const.MEDIA_TYPE_ARTIST,
"object.container.person.musicArtist": _mp_const.MEDIA_TYPE_ARTIST,
"object.container.playlistContainer": _mp_const.MEDIA_TYPE_PLAYLIST,
"object.container.album": _mp_const.MEDIA_TYPE_ALBUM,
"object.container.album.musicAlbum": _mp_const.MEDIA_TYPE_ALBUM,
"object.container.album.photoAlbum": _mp_const.MEDIA_TYPE_ALBUM,
"object.container.genre": _mp_const.MEDIA_TYPE_GENRE,
"object.container.genre.musicGenre": _mp_const.MEDIA_TYPE_GENRE,
"object.container.genre.movieGenre": _mp_const.MEDIA_TYPE_GENRE,
"object.container.channelGroup": _mp_const.MEDIA_TYPE_CHANNELS,
"object.container.channelGroup.audioChannelGroup": _mp_const.MEDIA_TYPE_CHANNELS,
"object.container.channelGroup.videoChannelGroup": _mp_const.MEDIA_TYPE_CHANNELS,
"object.container.epgContainer": _mp_const.MEDIA_TYPE_TVSHOW,
"object.container.storageSystem": _mp_const.MEDIA_TYPE_PLAYLIST,
"object.container.storageVolume": _mp_const.MEDIA_TYPE_PLAYLIST,
"object.container.storageFolder": _mp_const.MEDIA_TYPE_PLAYLIST,
"object.container.bookmarkFolder": _mp_const.MEDIA_TYPE_PLAYLIST,
MEDIA_TYPE_MAP: Mapping[str, MediaType] = {
"object": MediaType.URL,
"object.item": MediaType.URL,
"object.item.imageItem": MediaType.IMAGE,
"object.item.imageItem.photo": MediaType.IMAGE,
"object.item.audioItem": MediaType.MUSIC,
"object.item.audioItem.musicTrack": MediaType.MUSIC,
"object.item.audioItem.audioBroadcast": MediaType.MUSIC,
"object.item.audioItem.audioBook": MediaType.PODCAST,
"object.item.videoItem": MediaType.VIDEO,
"object.item.videoItem.movie": MediaType.MOVIE,
"object.item.videoItem.videoBroadcast": MediaType.TVSHOW,
"object.item.videoItem.musicVideoClip": MediaType.VIDEO,
"object.item.playlistItem": MediaType.PLAYLIST,
"object.item.textItem": MediaType.URL,
"object.item.bookmarkItem": MediaType.URL,
"object.item.epgItem": MediaType.EPISODE,
"object.item.epgItem.audioProgram": MediaType.EPISODE,
"object.item.epgItem.videoProgram": MediaType.EPISODE,
"object.container": MediaType.PLAYLIST,
"object.container.person": MediaType.ARTIST,
"object.container.person.musicArtist": MediaType.ARTIST,
"object.container.playlistContainer": MediaType.PLAYLIST,
"object.container.album": MediaType.ALBUM,
"object.container.album.musicAlbum": MediaType.ALBUM,
"object.container.album.photoAlbum": MediaType.ALBUM,
"object.container.genre": MediaType.GENRE,
"object.container.genre.musicGenre": MediaType.GENRE,
"object.container.genre.movieGenre": MediaType.GENRE,
"object.container.channelGroup": MediaType.CHANNELS,
"object.container.channelGroup.audioChannelGroup": MediaType.CHANNELS,
"object.container.channelGroup.videoChannelGroup": MediaType.CHANNELS,
"object.container.epgContainer": MediaType.TVSHOW,
"object.container.storageSystem": MediaType.PLAYLIST,
"object.container.storageVolume": MediaType.PLAYLIST,
"object.container.storageFolder": MediaType.PLAYLIST,
"object.container.bookmarkFolder": MediaType.PLAYLIST,
}
# Map media_player media_content_type to UPnP class. Not everything will map
# directly, in which case it's not specified and other defaults will be used.
MEDIA_UPNP_CLASS_MAP: Mapping[str, str] = {
_mp_const.MEDIA_TYPE_ALBUM: "object.container.album.musicAlbum",
_mp_const.MEDIA_TYPE_ARTIST: "object.container.person.musicArtist",
_mp_const.MEDIA_TYPE_CHANNEL: "object.item.videoItem.videoBroadcast",
_mp_const.MEDIA_TYPE_CHANNELS: "object.container.channelGroup",
_mp_const.MEDIA_TYPE_COMPOSER: "object.container.person.musicArtist",
_mp_const.MEDIA_TYPE_CONTRIBUTING_ARTIST: "object.container.person.musicArtist",
_mp_const.MEDIA_TYPE_EPISODE: "object.item.epgItem.videoProgram",
_mp_const.MEDIA_TYPE_GENRE: "object.container.genre",
_mp_const.MEDIA_TYPE_IMAGE: "object.item.imageItem",
_mp_const.MEDIA_TYPE_MOVIE: "object.item.videoItem.movie",
_mp_const.MEDIA_TYPE_MUSIC: "object.item.audioItem.musicTrack",
_mp_const.MEDIA_TYPE_PLAYLIST: "object.item.playlistItem",
_mp_const.MEDIA_TYPE_PODCAST: "object.item.audioItem.audioBook",
_mp_const.MEDIA_TYPE_SEASON: "object.item.epgItem.videoProgram",
_mp_const.MEDIA_TYPE_TRACK: "object.item.audioItem.musicTrack",
_mp_const.MEDIA_TYPE_TVSHOW: "object.item.videoItem.videoBroadcast",
_mp_const.MEDIA_TYPE_URL: "object.item.bookmarkItem",
_mp_const.MEDIA_TYPE_VIDEO: "object.item.videoItem",
MEDIA_UPNP_CLASS_MAP: Mapping[MediaType | str, str] = {
MediaType.ALBUM: "object.container.album.musicAlbum",
MediaType.ARTIST: "object.container.person.musicArtist",
MediaType.CHANNEL: "object.item.videoItem.videoBroadcast",
MediaType.CHANNELS: "object.container.channelGroup",
MediaType.COMPOSER: "object.container.person.musicArtist",
MediaType.CONTRIBUTING_ARTIST: "object.container.person.musicArtist",
MediaType.EPISODE: "object.item.epgItem.videoProgram",
MediaType.GENRE: "object.container.genre",
MediaType.IMAGE: "object.item.imageItem",
MediaType.MOVIE: "object.item.videoItem.movie",
MediaType.MUSIC: "object.item.audioItem.musicTrack",
MediaType.PLAYLIST: "object.item.playlistItem",
MediaType.PODCAST: "object.item.audioItem.audioBook",
MediaType.SEASON: "object.item.epgItem.videoProgram",
MediaType.TRACK: "object.item.audioItem.musicTrack",
MediaType.TVSHOW: "object.item.videoItem.videoBroadcast",
MediaType.URL: "object.item.bookmarkItem",
MediaType.VIDEO: "object.item.videoItem",
}
# Translation of MediaMetadata keys to DIDL-Lite keys.
@ -109,32 +109,32 @@ MEDIA_METADATA_DIDL: Mapping[str, str] = {
# of play modes in order of suitability. Fall back to _PlayMode.NORMAL in any
# case. NOTE: This list is slightly different to that in SHUFFLE_PLAY_MODES,
# due to fallback behaviour when turning on repeat modes.
REPEAT_PLAY_MODES: Mapping[tuple[bool, str], list[_PlayMode]] = {
(False, _mp_const.REPEAT_MODE_OFF): [
REPEAT_PLAY_MODES: Mapping[tuple[bool, RepeatMode], list[_PlayMode]] = {
(False, RepeatMode.OFF): [
_PlayMode.NORMAL,
],
(False, _mp_const.REPEAT_MODE_ONE): [
(False, RepeatMode.ONE): [
_PlayMode.REPEAT_ONE,
_PlayMode.REPEAT_ALL,
_PlayMode.NORMAL,
],
(False, _mp_const.REPEAT_MODE_ALL): [
(False, RepeatMode.ALL): [
_PlayMode.REPEAT_ALL,
_PlayMode.REPEAT_ONE,
_PlayMode.NORMAL,
],
(True, _mp_const.REPEAT_MODE_OFF): [
(True, RepeatMode.OFF): [
_PlayMode.SHUFFLE,
_PlayMode.RANDOM,
_PlayMode.NORMAL,
],
(True, _mp_const.REPEAT_MODE_ONE): [
(True, RepeatMode.ONE): [
_PlayMode.REPEAT_ONE,
_PlayMode.RANDOM,
_PlayMode.SHUFFLE,
_PlayMode.NORMAL,
],
(True, _mp_const.REPEAT_MODE_ALL): [
(True, RepeatMode.ALL): [
_PlayMode.RANDOM,
_PlayMode.REPEAT_ALL,
_PlayMode.SHUFFLE,
@ -146,31 +146,31 @@ REPEAT_PLAY_MODES: Mapping[tuple[bool, str], list[_PlayMode]] = {
# of play modes in order of suitability. Fall back to _PlayMode.NORMAL in any
# case.
SHUFFLE_PLAY_MODES: Mapping[tuple[bool, str], list[_PlayMode]] = {
(False, _mp_const.REPEAT_MODE_OFF): [
(False, RepeatMode.OFF): [
_PlayMode.NORMAL,
],
(False, _mp_const.REPEAT_MODE_ONE): [
(False, RepeatMode.ONE): [
_PlayMode.REPEAT_ONE,
_PlayMode.REPEAT_ALL,
_PlayMode.NORMAL,
],
(False, _mp_const.REPEAT_MODE_ALL): [
(False, RepeatMode.ALL): [
_PlayMode.REPEAT_ALL,
_PlayMode.REPEAT_ONE,
_PlayMode.NORMAL,
],
(True, _mp_const.REPEAT_MODE_OFF): [
(True, RepeatMode.OFF): [
_PlayMode.SHUFFLE,
_PlayMode.RANDOM,
_PlayMode.NORMAL,
],
(True, _mp_const.REPEAT_MODE_ONE): [
(True, RepeatMode.ONE): [
_PlayMode.RANDOM,
_PlayMode.SHUFFLE,
_PlayMode.REPEAT_ONE,
_PlayMode.NORMAL,
],
(True, _mp_const.REPEAT_MODE_ALL): [
(True, RepeatMode.ALL): [
_PlayMode.RANDOM,
_PlayMode.SHUFFLE,
_PlayMode.REPEAT_ALL,

View File

@ -19,27 +19,16 @@ from typing_extensions import Concatenate, ParamSpec
from homeassistant import config_entries
from homeassistant.components import media_source, ssdp
from homeassistant.components.media_player import (
ATTR_MEDIA_EXTRA,
BrowseMedia,
MediaPlayerEntity,
MediaPlayerEntityFeature,
MediaPlayerState,
MediaType,
RepeatMode,
async_process_play_media_url,
)
from homeassistant.components.media_player.const import (
ATTR_MEDIA_EXTRA,
REPEAT_MODE_ALL,
REPEAT_MODE_OFF,
REPEAT_MODE_ONE,
)
from homeassistant.const import (
CONF_DEVICE_ID,
CONF_TYPE,
CONF_URL,
STATE_IDLE,
STATE_OFF,
STATE_ON,
STATE_PAUSED,
STATE_PLAYING,
)
from homeassistant.const import CONF_DEVICE_ID, CONF_TYPE, CONF_URL
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry, entity_registry
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -466,27 +455,27 @@ class DlnaDmrEntity(MediaPlayerEntity):
return f"{self.udn}::{self.device_type}"
@property
def state(self) -> str | None:
def state(self) -> MediaPlayerState | None:
"""State of the player."""
if not self._device or not self.available:
return STATE_OFF
return MediaPlayerState.OFF
if self._device.transport_state is None:
return STATE_ON
return MediaPlayerState.ON
if self._device.transport_state in (
TransportState.PLAYING,
TransportState.TRANSITIONING,
):
return STATE_PLAYING
return MediaPlayerState.PLAYING
if self._device.transport_state in (
TransportState.PAUSED_PLAYBACK,
TransportState.PAUSED_RECORDING,
):
return STATE_PAUSED
return MediaPlayerState.PAUSED
if self._device.transport_state == TransportState.VENDOR_DEFINED:
# Unable to map this state to anything reasonable, so it's "Unknown"
return None
return STATE_IDLE
return MediaPlayerState.IDLE
@property
def supported_features(self) -> int:
@ -586,7 +575,7 @@ class DlnaDmrEntity(MediaPlayerEntity):
@catch_request_errors
async def async_play_media(
self, media_type: str, media_id: str, **kwargs: Any
self, media_type: MediaType | str, media_id: str, **kwargs: Any
) -> None:
"""Play a piece of media."""
_LOGGER.debug("Playing media: %s, %s, %s", media_type, media_id, kwargs)
@ -683,7 +672,7 @@ class DlnaDmrEntity(MediaPlayerEntity):
"""Enable/disable shuffle mode."""
assert self._device is not None
repeat = self.repeat or REPEAT_MODE_OFF
repeat = self.repeat or RepeatMode.OFF
potential_play_modes = SHUFFLE_PLAY_MODES[(shuffle, repeat)]
valid_play_modes = self._device.valid_play_modes
@ -698,7 +687,7 @@ class DlnaDmrEntity(MediaPlayerEntity):
)
@property
def repeat(self) -> str | None:
def repeat(self) -> RepeatMode | None:
"""Return current repeat mode."""
if not self._device:
return None
@ -710,15 +699,15 @@ class DlnaDmrEntity(MediaPlayerEntity):
return None
if play_mode == PlayMode.REPEAT_ONE:
return REPEAT_MODE_ONE
return RepeatMode.ONE
if play_mode in (PlayMode.REPEAT_ALL, PlayMode.RANDOM):
return REPEAT_MODE_ALL
return RepeatMode.ALL
return REPEAT_MODE_OFF
return RepeatMode.OFF
@catch_request_errors
async def async_set_repeat(self, repeat: str) -> None:
async def async_set_repeat(self, repeat: RepeatMode) -> None:
"""Set repeat mode."""
assert self._device is not None
@ -839,7 +828,7 @@ class DlnaDmrEntity(MediaPlayerEntity):
return self._device.current_track_uri
@property
def media_content_type(self) -> str | None:
def media_content_type(self) -> MediaType | None:
"""Content type of current playing media."""
if not self._device or not self._device.media_class:
return None

View File

@ -21,7 +21,6 @@ import pytest
from homeassistant import const as ha_const
from homeassistant.components import ssdp
from homeassistant.components.dlna_dmr import media_player
from homeassistant.components.dlna_dmr.const import (
CONF_BROWSE_UNFILTERED,
CONF_CALLBACK_URL_OVERRIDE,
@ -30,10 +29,17 @@ from homeassistant.components.dlna_dmr.const import (
DOMAIN as DLNA_DOMAIN,
)
from homeassistant.components.dlna_dmr.data import EventListenAddr
from homeassistant.components.media_player import ATTR_TO_PROPERTY, const as mp_const
from homeassistant.components.media_player.const import DOMAIN as MP_DOMAIN
from homeassistant.components.media_source.const import DOMAIN as MS_DOMAIN
from homeassistant.components.media_source.models import PlayMedia
from homeassistant.components.dlna_dmr.media_player import DlnaDmrEntity
from homeassistant.components.media_player import (
ATTR_TO_PROPERTY,
DOMAIN as MP_DOMAIN,
MediaPlayerEntityFeature,
MediaPlayerState,
MediaType,
RepeatMode,
const as mp_const,
)
from homeassistant.components.media_source import DOMAIN as MS_DOMAIN, PlayMedia
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import async_get as async_get_dr
@ -223,7 +229,7 @@ async def test_setup_entry_no_options(
ANY, {"_udn": MOCK_DEVICE_UDN, "NTS": "ssdp:byebye"}
)
# Quick check of the state to verify the entity has a connected DmrDevice
assert mock_state.state == media_player.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
# Check the name matches that supplied
assert mock_state.name == MOCK_DEVICE_NAME
@ -292,7 +298,7 @@ async def test_setup_entry_with_options(
ANY, {"_udn": MOCK_DEVICE_UDN, "NTS": "ssdp:byebye"}
)
# Quick check of the state to verify the entity has a connected DmrDevice
assert mock_state.state == media_player.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
# Check the name matches that supplied
assert mock_state.name == MOCK_DEVICE_NAME
@ -359,7 +365,7 @@ async def test_event_subscribe_rejected(
assert mock_state is not None
# Device should be connected
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
# Device should not be unsubscribed
dmr_device_mock.async_unsubscribe_services.assert_not_awaited()
@ -385,14 +391,14 @@ async def test_available_device(
# Check entity state gets updated when device changes state
for (dev_state, ent_state) in [
(None, ha_const.STATE_ON),
(TransportState.STOPPED, ha_const.STATE_IDLE),
(TransportState.PLAYING, ha_const.STATE_PLAYING),
(TransportState.TRANSITIONING, ha_const.STATE_PLAYING),
(TransportState.PAUSED_PLAYBACK, ha_const.STATE_PAUSED),
(TransportState.PAUSED_RECORDING, ha_const.STATE_PAUSED),
(TransportState.RECORDING, ha_const.STATE_IDLE),
(TransportState.NO_MEDIA_PRESENT, ha_const.STATE_IDLE),
(None, MediaPlayerState.ON),
(TransportState.STOPPED, MediaPlayerState.IDLE),
(TransportState.PLAYING, MediaPlayerState.PLAYING),
(TransportState.TRANSITIONING, MediaPlayerState.PLAYING),
(TransportState.PAUSED_PLAYBACK, MediaPlayerState.PAUSED),
(TransportState.PAUSED_RECORDING, MediaPlayerState.PAUSED),
(TransportState.RECORDING, MediaPlayerState.IDLE),
(TransportState.NO_MEDIA_PRESENT, MediaPlayerState.IDLE),
(TransportState.VENDOR_DEFINED, ha_const.STATE_UNKNOWN),
]:
dmr_device_mock.profile_device.available = True
@ -416,16 +422,19 @@ async def test_feature_flags(
"""Test feature flags of a connected DlnaDmrEntity."""
# Check supported feature flags, one at a time.
FEATURE_FLAGS: list[tuple[str, int]] = [
("has_volume_level", mp_const.SUPPORT_VOLUME_SET),
("has_volume_mute", mp_const.SUPPORT_VOLUME_MUTE),
("can_play", mp_const.SUPPORT_PLAY),
("can_pause", mp_const.SUPPORT_PAUSE),
("can_stop", mp_const.SUPPORT_STOP),
("can_previous", mp_const.SUPPORT_PREVIOUS_TRACK),
("can_next", mp_const.SUPPORT_NEXT_TRACK),
("has_play_media", mp_const.SUPPORT_PLAY_MEDIA | mp_const.SUPPORT_BROWSE_MEDIA),
("can_seek_rel_time", mp_const.SUPPORT_SEEK),
("has_presets", mp_const.SUPPORT_SELECT_SOUND_MODE),
("has_volume_level", MediaPlayerEntityFeature.VOLUME_SET),
("has_volume_mute", MediaPlayerEntityFeature.VOLUME_MUTE),
("can_play", MediaPlayerEntityFeature.PLAY),
("can_pause", MediaPlayerEntityFeature.PAUSE),
("can_stop", MediaPlayerEntityFeature.STOP),
("can_previous", MediaPlayerEntityFeature.PREVIOUS_TRACK),
("can_next", MediaPlayerEntityFeature.NEXT_TRACK),
(
"has_play_media",
MediaPlayerEntityFeature.PLAY_MEDIA | MediaPlayerEntityFeature.BROWSE_MEDIA,
),
("can_seek_rel_time", MediaPlayerEntityFeature.SEEK),
("has_presets", MediaPlayerEntityFeature.SELECT_SOUND_MODE),
]
# Clear all feature properties
@ -446,10 +455,10 @@ async def test_feature_flags(
# shuffle and repeat features depend on the available play modes
PLAY_MODE_FEATURE_FLAGS: list[tuple[PlayMode, int]] = [
(PlayMode.NORMAL, 0),
(PlayMode.SHUFFLE, mp_const.SUPPORT_SHUFFLE_SET),
(PlayMode.REPEAT_ONE, mp_const.SUPPORT_REPEAT_SET),
(PlayMode.REPEAT_ALL, mp_const.SUPPORT_REPEAT_SET),
(PlayMode.RANDOM, mp_const.SUPPORT_SHUFFLE_SET),
(PlayMode.SHUFFLE, MediaPlayerEntityFeature.SHUFFLE_SET),
(PlayMode.REPEAT_ONE, MediaPlayerEntityFeature.REPEAT_SET),
(PlayMode.REPEAT_ALL, MediaPlayerEntityFeature.REPEAT_SET),
(PlayMode.RANDOM, MediaPlayerEntityFeature.SHUFFLE_SET),
(PlayMode.DIRECT_1, 0),
(PlayMode.INTRO, 0),
(PlayMode.VENDOR_DEFINED, 0),
@ -497,13 +506,13 @@ async def test_attributes(
# media_content_type is mapped from UPnP class to MediaPlayer type
dmr_device_mock.media_class = "object.item.audioItem.musicTrack"
attrs = await get_attrs(hass, mock_entity_id)
assert attrs[mp_const.ATTR_MEDIA_CONTENT_TYPE] == mp_const.MEDIA_TYPE_MUSIC
assert attrs[mp_const.ATTR_MEDIA_CONTENT_TYPE] == MediaType.MUSIC
dmr_device_mock.media_class = "object.item.videoItem.movie"
attrs = await get_attrs(hass, mock_entity_id)
assert attrs[mp_const.ATTR_MEDIA_CONTENT_TYPE] == mp_const.MEDIA_TYPE_MOVIE
assert attrs[mp_const.ATTR_MEDIA_CONTENT_TYPE] == MediaType.MOVIE
dmr_device_mock.media_class = "object.item.videoItem.videoBroadcast"
attrs = await get_attrs(hass, mock_entity_id)
assert attrs[mp_const.ATTR_MEDIA_CONTENT_TYPE] == mp_const.MEDIA_TYPE_TVSHOW
assert attrs[mp_const.ATTR_MEDIA_CONTENT_TYPE] == MediaType.TVSHOW
# media_season & media_episode have a special case
dmr_device_mock.media_season_number = "0"
@ -519,13 +528,13 @@ async def test_attributes(
# shuffle and repeat is based on device's play mode
for play_mode, shuffle, repeat in [
(PlayMode.NORMAL, False, mp_const.REPEAT_MODE_OFF),
(PlayMode.SHUFFLE, True, mp_const.REPEAT_MODE_OFF),
(PlayMode.REPEAT_ONE, False, mp_const.REPEAT_MODE_ONE),
(PlayMode.REPEAT_ALL, False, mp_const.REPEAT_MODE_ALL),
(PlayMode.RANDOM, True, mp_const.REPEAT_MODE_ALL),
(PlayMode.DIRECT_1, False, mp_const.REPEAT_MODE_OFF),
(PlayMode.INTRO, False, mp_const.REPEAT_MODE_OFF),
(PlayMode.NORMAL, False, RepeatMode.OFF),
(PlayMode.SHUFFLE, True, RepeatMode.OFF),
(PlayMode.REPEAT_ONE, False, RepeatMode.ONE),
(PlayMode.REPEAT_ALL, False, RepeatMode.ALL),
(PlayMode.RANDOM, True, RepeatMode.ALL),
(PlayMode.DIRECT_1, False, RepeatMode.OFF),
(PlayMode.INTRO, False, RepeatMode.OFF),
]:
dmr_device_mock.play_mode = play_mode
attrs = await get_attrs(hass, mock_entity_id)
@ -620,7 +629,7 @@ async def test_play_media_stopped(
mp_const.SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: mock_entity_id,
mp_const.ATTR_MEDIA_CONTENT_TYPE: mp_const.MEDIA_TYPE_MUSIC,
mp_const.ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
mp_const.ATTR_MEDIA_CONTENT_ID: "http://192.88.99.20:8200/MediaItems/17621.mp3",
mp_const.ATTR_MEDIA_ENQUEUE: False,
},
@ -652,7 +661,7 @@ async def test_play_media_playing(
mp_const.SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: mock_entity_id,
mp_const.ATTR_MEDIA_CONTENT_TYPE: mp_const.MEDIA_TYPE_MUSIC,
mp_const.ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
mp_const.ATTR_MEDIA_CONTENT_ID: "http://192.88.99.20:8200/MediaItems/17621.mp3",
mp_const.ATTR_MEDIA_ENQUEUE: False,
},
@ -685,7 +694,7 @@ async def test_play_media_no_autoplay(
mp_const.SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: mock_entity_id,
mp_const.ATTR_MEDIA_CONTENT_TYPE: mp_const.MEDIA_TYPE_MUSIC,
mp_const.ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
mp_const.ATTR_MEDIA_CONTENT_ID: "http://192.88.99.20:8200/MediaItems/17621.mp3",
mp_const.ATTR_MEDIA_ENQUEUE: False,
mp_const.ATTR_MEDIA_EXTRA: {"autoplay": False},
@ -716,7 +725,7 @@ async def test_play_media_metadata(
mp_const.SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: mock_entity_id,
mp_const.ATTR_MEDIA_CONTENT_TYPE: mp_const.MEDIA_TYPE_MUSIC,
mp_const.ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
mp_const.ATTR_MEDIA_CONTENT_ID: "http://192.88.99.20:8200/MediaItems/17621.mp3",
mp_const.ATTR_MEDIA_ENQUEUE: False,
mp_const.ATTR_MEDIA_EXTRA: {
@ -746,7 +755,7 @@ async def test_play_media_metadata(
mp_const.SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: mock_entity_id,
mp_const.ATTR_MEDIA_CONTENT_TYPE: mp_const.MEDIA_TYPE_TVSHOW,
mp_const.ATTR_MEDIA_CONTENT_TYPE: MediaType.TVSHOW,
mp_const.ATTR_MEDIA_CONTENT_ID: "http://192.88.99.20:8200/MediaItems/123.mkv",
mp_const.ATTR_MEDIA_ENQUEUE: False,
mp_const.ATTR_MEDIA_EXTRA: {
@ -878,21 +887,21 @@ async def test_shuffle_repeat_modes(
# Test repeat with all variations of existing play mode
for init_mode, repeat_set, expect_mode in [
(PlayMode.NORMAL, mp_const.REPEAT_MODE_OFF, PlayMode.NORMAL),
(PlayMode.SHUFFLE, mp_const.REPEAT_MODE_OFF, PlayMode.SHUFFLE),
(PlayMode.REPEAT_ONE, mp_const.REPEAT_MODE_OFF, PlayMode.NORMAL),
(PlayMode.REPEAT_ALL, mp_const.REPEAT_MODE_OFF, PlayMode.NORMAL),
(PlayMode.RANDOM, mp_const.REPEAT_MODE_OFF, PlayMode.SHUFFLE),
(PlayMode.NORMAL, mp_const.REPEAT_MODE_ONE, PlayMode.REPEAT_ONE),
(PlayMode.SHUFFLE, mp_const.REPEAT_MODE_ONE, PlayMode.REPEAT_ONE),
(PlayMode.REPEAT_ONE, mp_const.REPEAT_MODE_ONE, PlayMode.REPEAT_ONE),
(PlayMode.REPEAT_ALL, mp_const.REPEAT_MODE_ONE, PlayMode.REPEAT_ONE),
(PlayMode.RANDOM, mp_const.REPEAT_MODE_ONE, PlayMode.REPEAT_ONE),
(PlayMode.NORMAL, mp_const.REPEAT_MODE_ALL, PlayMode.REPEAT_ALL),
(PlayMode.SHUFFLE, mp_const.REPEAT_MODE_ALL, PlayMode.RANDOM),
(PlayMode.REPEAT_ONE, mp_const.REPEAT_MODE_ALL, PlayMode.REPEAT_ALL),
(PlayMode.REPEAT_ALL, mp_const.REPEAT_MODE_ALL, PlayMode.REPEAT_ALL),
(PlayMode.RANDOM, mp_const.REPEAT_MODE_ALL, PlayMode.RANDOM),
(PlayMode.NORMAL, RepeatMode.OFF, PlayMode.NORMAL),
(PlayMode.SHUFFLE, RepeatMode.OFF, PlayMode.SHUFFLE),
(PlayMode.REPEAT_ONE, RepeatMode.OFF, PlayMode.NORMAL),
(PlayMode.REPEAT_ALL, RepeatMode.OFF, PlayMode.NORMAL),
(PlayMode.RANDOM, RepeatMode.OFF, PlayMode.SHUFFLE),
(PlayMode.NORMAL, RepeatMode.ONE, PlayMode.REPEAT_ONE),
(PlayMode.SHUFFLE, RepeatMode.ONE, PlayMode.REPEAT_ONE),
(PlayMode.REPEAT_ONE, RepeatMode.ONE, PlayMode.REPEAT_ONE),
(PlayMode.REPEAT_ALL, RepeatMode.ONE, PlayMode.REPEAT_ONE),
(PlayMode.RANDOM, RepeatMode.ONE, PlayMode.REPEAT_ONE),
(PlayMode.NORMAL, RepeatMode.ALL, PlayMode.REPEAT_ALL),
(PlayMode.SHUFFLE, RepeatMode.ALL, PlayMode.RANDOM),
(PlayMode.REPEAT_ONE, RepeatMode.ALL, PlayMode.REPEAT_ALL),
(PlayMode.REPEAT_ALL, RepeatMode.ALL, PlayMode.REPEAT_ALL),
(PlayMode.RANDOM, RepeatMode.ALL, PlayMode.RANDOM),
]:
dmr_device_mock.play_mode = init_mode
await hass.services.async_call(
@ -926,7 +935,7 @@ async def test_shuffle_repeat_modes(
ha_const.SERVICE_REPEAT_SET,
{
ATTR_ENTITY_ID: mock_entity_id,
mp_const.ATTR_MEDIA_REPEAT: mp_const.REPEAT_MODE_OFF,
mp_const.ATTR_MEDIA_REPEAT: RepeatMode.OFF,
},
blocking=True,
)
@ -1226,7 +1235,7 @@ async def test_unavailable_device(
(
mp_const.SERVICE_PLAY_MEDIA,
{
mp_const.ATTR_MEDIA_CONTENT_TYPE: mp_const.MEDIA_TYPE_MUSIC,
mp_const.ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
mp_const.ATTR_MEDIA_CONTENT_ID: "http://192.88.99.20:8200/MediaItems/17621.mp3",
mp_const.ATTR_MEDIA_ENQUEUE: False,
},
@ -1318,7 +1327,7 @@ async def test_become_available(
# Quick check of the state to verify the entity has a connected DmrDevice
mock_state = hass.states.get(mock_entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
# Check hass device information is now filled in
dev_reg = async_get_dr(hass)
device = dev_reg.async_get_device(identifiers={(DLNA_DOMAIN, MOCK_DEVICE_UDN)})
@ -1496,7 +1505,7 @@ async def test_multiple_ssdp_alive(
# Device should be available
mock_state = hass.states.get(mock_disconnected_entity_id)
assert mock_state is not None
assert mock_state.state == media_player.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
async def test_ssdp_byebye(
@ -1592,7 +1601,7 @@ async def test_ssdp_update_seen_bootid(
# Device was not reconnected, even with a new boot ID
mock_state = hass.states.get(entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
assert dmr_device_mock.async_unsubscribe_services.await_count == 0
assert dmr_device_mock.async_subscribe_services.await_count == 1
@ -1617,7 +1626,7 @@ async def test_ssdp_update_seen_bootid(
# Nothing should change
mock_state = hass.states.get(entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
assert dmr_device_mock.async_unsubscribe_services.await_count == 0
assert dmr_device_mock.async_subscribe_services.await_count == 1
@ -1642,7 +1651,7 @@ async def test_ssdp_update_seen_bootid(
# Nothing should change
mock_state = hass.states.get(entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
assert dmr_device_mock.async_unsubscribe_services.await_count == 0
assert dmr_device_mock.async_subscribe_services.await_count == 1
@ -1662,7 +1671,7 @@ async def test_ssdp_update_seen_bootid(
mock_state = hass.states.get(entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
assert dmr_device_mock.async_unsubscribe_services.await_count == 0
assert dmr_device_mock.async_subscribe_services.await_count == 1
@ -1719,7 +1728,7 @@ async def test_ssdp_update_missed_bootid(
# Device should not reconnect yet
mock_state = hass.states.get(entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
assert dmr_device_mock.async_unsubscribe_services.await_count == 0
assert dmr_device_mock.async_subscribe_services.await_count == 1
@ -1739,7 +1748,7 @@ async def test_ssdp_update_missed_bootid(
mock_state = hass.states.get(entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
assert dmr_device_mock.async_unsubscribe_services.await_count == 1
assert dmr_device_mock.async_subscribe_services.await_count == 2
@ -1778,7 +1787,7 @@ async def test_ssdp_bootid(
mock_state = hass.states.get(entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
assert dmr_device_mock.async_subscribe_services.call_count == 1
assert dmr_device_mock.async_unsubscribe_services.call_count == 0
@ -1798,7 +1807,7 @@ async def test_ssdp_bootid(
mock_state = hass.states.get(entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
assert dmr_device_mock.async_subscribe_services.call_count == 1
assert dmr_device_mock.async_unsubscribe_services.call_count == 0
@ -1818,7 +1827,7 @@ async def test_ssdp_bootid(
mock_state = hass.states.get(entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
assert dmr_device_mock.async_subscribe_services.call_count == 2
assert dmr_device_mock.async_unsubscribe_services.call_count == 1
@ -1849,14 +1858,14 @@ async def test_become_unavailable(
mock_state = hass.states.get(mock_entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
# With a working connection, the state should be restored
await async_update_entity(hass, mock_entity_id)
dmr_device_mock.async_update.assert_any_call(do_ping=True)
mock_state = hass.states.get(mock_entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
# Break the service again, and the connection too. An update will cause the
# device to be disconnected
@ -1918,7 +1927,7 @@ async def test_poll_availability(
mock_state = hass.states.get(mock_entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
# Clean up
assert await hass.config_entries.async_remove(config_entry_mock.entry_id) == {
@ -1938,9 +1947,7 @@ async def test_disappearing_device(
directly to skip the availability check.
"""
# Retrieve entity directly.
entity: media_player.DlnaDmrEntity = hass.data[MP_DOMAIN].get_entity(
mock_disconnected_entity_id
)
entity: DlnaDmrEntity = hass.data[MP_DOMAIN].get_entity(mock_disconnected_entity_id)
# Test attribute access
for attr in ATTR_TO_PROPERTY:
@ -1964,7 +1971,7 @@ async def test_disappearing_device(
await entity.async_media_previous_track()
await entity.async_media_next_track()
await entity.async_set_shuffle(True)
await entity.async_set_repeat(mp_const.REPEAT_MODE_ALL)
await entity.async_set_repeat(RepeatMode.ALL)
await entity.async_select_sound_mode("Default")
@ -2023,7 +2030,7 @@ async def test_config_update_listen_port(
# Check that its still connected
mock_state = hass.states.get(mock_entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
async def test_config_update_connect_failure(
@ -2097,7 +2104,7 @@ async def test_config_update_callback_url(
# Check that its still connected
mock_state = hass.states.get(mock_entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE
async def test_config_update_poll_availability(
@ -2138,4 +2145,4 @@ async def test_config_update_poll_availability(
# Check that its still connected
mock_state = hass.states.get(mock_entity_id)
assert mock_state is not None
assert mock_state.state == ha_const.STATE_IDLE
assert mock_state.state == MediaPlayerState.IDLE