1
0
mirror of https://github.com/natekspencer/hacs-oasis_mini.git synced 2025-11-18 10:03:41 -05:00

Adjust media player to allow adding multiple tracks at a time

This commit is contained in:
Nathan Spencer
2025-01-10 21:48:31 +00:00
parent ddabccc4a8
commit 51c4c8a6a2
4 changed files with 74 additions and 24 deletions

View File

@@ -2,11 +2,14 @@
from __future__ import annotations
import logging
from typing import Any
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST
from .pyoasismini import OasisMini
from .pyoasismini import TRACKS, OasisMini
_LOGGER = logging.getLogger(__name__)
def create_client(data: dict[str, Any]) -> OasisMini:
@@ -27,3 +30,21 @@ async def add_and_play_track(device: OasisMini, track: int) -> None:
if device.status_code != 4:
await device.async_play()
def get_track_id(track: str) -> int | None:
"""Get a track id.
`track` can be either an id or title
"""
track = track.lower().strip()
if track not in map(str, TRACKS):
track = next(
(id for id, info in TRACKS.items() if info["name"].lower() == track), track
)
try:
return int(track)
except ValueError:
_LOGGER.warning("Invalid track: %s", track)
return None

View File

@@ -19,7 +19,9 @@ from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import OasisMiniConfigEntry
from .const import DOMAIN
from .entity import OasisMiniEntity
from .helpers import get_track_id
from .pyoasismini.const import TRACKS
@@ -102,18 +104,30 @@ class OasisMiniMediaPlayerEntity(OasisMiniEntity, MediaPlayerEntity):
return MediaPlayerState.ON
return MediaPlayerState.IDLE
def abort_if_busy(self) -> None:
"""Abort if the device is currently busy."""
if self.device.busy:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="device_busy",
translation_placeholders={"name": self._friendly_name_internal()},
)
async def async_media_pause(self) -> None:
"""Send pause command."""
self.abort_if_busy()
await self.device.async_pause()
await self.coordinator.async_request_refresh()
async def async_media_play(self) -> None:
"""Send play command."""
self.abort_if_busy()
await self.device.async_play()
await self.coordinator.async_request_refresh()
async def async_media_stop(self) -> None:
"""Send stop command."""
self.abort_if_busy()
await self.device.async_stop()
await self.coordinator.async_request_refresh()
@@ -127,6 +141,7 @@ class OasisMiniMediaPlayerEntity(OasisMiniEntity, MediaPlayerEntity):
async def async_media_previous_track(self) -> None:
"""Send previous track command."""
self.abort_if_busy()
if (index := self.device.playlist_index - 1) < 0:
index = len(self.device.playlist) - 1
await self.device.async_change_track(index)
@@ -134,6 +149,7 @@ class OasisMiniMediaPlayerEntity(OasisMiniEntity, MediaPlayerEntity):
async def async_media_next_track(self) -> None:
"""Send next track command."""
self.abort_if_busy()
if (index := self.device.playlist_index + 1) >= len(self.device.playlist):
index = 0
await self.device.async_change_track(index)
@@ -147,32 +163,29 @@ class OasisMiniMediaPlayerEntity(OasisMiniEntity, MediaPlayerEntity):
**kwargs: Any,
) -> None:
"""Play a piece of media."""
if media_id not in map(str, TRACKS):
media_id = next(
(
id
for id, info in TRACKS.items()
if info["name"].lower() == media_id.lower()
),
media_id,
)
try:
track = int(media_id)
except ValueError as err:
raise ServiceValidationError(f"Invalid media: {media_id}") from err
self.abort_if_busy()
if media_type == MediaType.PLAYLIST:
raise ServiceValidationError("Playlists are not currently supported")
else:
track = list(filter(None, map(get_track_id, media_id.split(","))))
if not track:
raise ServiceValidationError(f"Invalid media: {media_id}")
device = self.device
enqueue = MediaPlayerEnqueue.NEXT if not enqueue else enqueue
if enqueue == MediaPlayerEnqueue.REPLACE:
await device.async_set_playlist([track])
await device.async_set_playlist(track)
else:
await device.async_add_track_to_playlist(track)
if enqueue in (MediaPlayerEnqueue.NEXT, MediaPlayerEnqueue.PLAY):
# Move track to next item in the playlist
if (index := (len(device.playlist) - 1)) != device.playlist_index:
new_tracks = 1 if isinstance(track, int) else len(track)
if (index := (len(device.playlist) - new_tracks)) != device.playlist_index:
if index != (
_next := min(device.playlist_index + 1, len(device.playlist) - 1)
_next := min(
device.playlist_index + 1, len(device.playlist) - new_tracks
)
):
await device.async_move_track(index, _next)
if enqueue == MediaPlayerEnqueue.PLAY:
@@ -188,6 +201,7 @@ class OasisMiniMediaPlayerEntity(OasisMiniEntity, MediaPlayerEntity):
async def async_clear_playlist(self) -> None:
"""Clear players playlist."""
self.abort_if_busy()
await self.device.async_clear_playlist()
await self.coordinator.async_request_refresh()

View File

@@ -8,7 +8,6 @@ from typing import Any, Awaitable, Final
from urllib.parse import urljoin
from aiohttp import ClientResponseError, ClientSession
import async_timeout
from .const import TRACKS
from .utils import _bit_to_bool, decrypt_svg_content
@@ -159,17 +158,17 @@ class OasisMini:
"""Return the url."""
return f"http://{self._host}/"
async def async_add_track_to_playlist(self, track: int) -> None:
async def async_add_track_to_playlist(self, track: int | list[int]) -> None:
"""Add track to playlist."""
if not track:
return
if isinstance(track, int):
track = [track]
if 0 in self.playlist:
playlist = [t for t in self.playlist if t] + [track]
playlist = [t for t in self.playlist if t] + track
return await self.async_set_playlist(playlist)
await self._async_command(params={"ADDJOBLIST": track})
self.playlist.append(track)
self.playlist.extend(track)
async def async_change_track(self, index: int) -> None:
"""Change the track."""
@@ -312,8 +311,10 @@ class OasisMini:
raise ValueError("Invalid pause option specified")
await self._async_command(params={"WRIWAITAFTER": option})
async def async_set_playlist(self, playlist: list[int]) -> None:
async def async_set_playlist(self, playlist: list[int] | int) -> None:
"""Set the playlist."""
if isinstance(playlist, int):
playlist = [playlist]
if is_playing := (self.status_code == 4):
await self.async_stop()
await self._async_command(params={"WRIJOBLIST": ",".join(map(str, playlist))})