Skip to content

Commit

Permalink
Feat: Bump models to 1.1.2
Browse files Browse the repository at this point in the history
Feat: Bump models to 1.1.2
Feat: Adjust code to changes in the models
Feat: Refactor sync to group to make it more universal
  • Loading branch information
marcelveldt committed Nov 20, 2024
1 parent 5339405 commit d517198
Show file tree
Hide file tree
Showing 42 changed files with 320 additions and 328 deletions.
195 changes: 104 additions & 91 deletions music_assistant/controllers/players.py

Large diffs are not rendered by default.

28 changes: 7 additions & 21 deletions music_assistant/helpers/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import eyed3
from music_assistant_models.enums import AlbumType
from music_assistant_models.errors import InvalidDataError
from music_assistant_models.media_items import MediaItemChapter

from music_assistant.constants import MASS_LOGGER_NAME, UNKNOWN_ARTIST
from music_assistant.helpers.process import AsyncProcess
Expand Down Expand Up @@ -260,14 +259,14 @@ def album_artist_sort_names(self) -> tuple[str, ...]:
"""Return artist sort name tag(s) if present."""
return split_items(self.tags.get("albumartistsort"), False)

@property
def is_audiobook(self) -> bool:
"""Return True if this is an audiobook."""
return self.filename.endswith("m4b") and len(self.chapters) > 1

@property
def album_type(self) -> AlbumType:
"""Return albumtype tag if present."""
# handle audiobook/podcast
if self.filename.endswith("m4b") and len(self.chapters) > 1:
return AlbumType.AUDIOBOOK
if "podcast" in self.tags.get("genre", "").lower() and len(self.chapters) > 1:
return AlbumType.PODCAST
if self.tags.get("compilation", "") == "1":
return AlbumType.COMPILATION
tag = (
Expand All @@ -280,8 +279,6 @@ def album_type(self) -> AlbumType:
# the album type tag is messy within id3 and may even contain multiple types
# try to parse one in order of preference
for album_type in (
AlbumType.PODCAST,
AlbumType.AUDIOBOOK,
AlbumType.COMPILATION,
AlbumType.EP,
AlbumType.SINGLE,
Expand Down Expand Up @@ -316,20 +313,9 @@ def barcode(self) -> str | None:
return None

@property
def chapters(self) -> list[MediaItemChapter]:
def chapters(self) -> list[dict[str, Any]]:
"""Return chapters in MediaItem (if any)."""
chapters: list[MediaItemChapter] = []
if raw_chapters := self.raw.get("chapters"):
for chapter_data in raw_chapters:
chapters.append(
MediaItemChapter(
chapter_id=chapter_data["id"],
position_start=chapter_data["start"],
position_end=chapter_data["end"],
title=chapter_data.get("tags", {}).get("title"),
)
)
return chapters
return self.raw.get("chapters") or []

@property
def lyrics(self) -> str | None:
Expand Down
6 changes: 3 additions & 3 deletions music_assistant/models/metadata_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@

# ruff: noqa: ARG001, ARG002

DEFAULT_SUPPORTED_FEATURES = (
DEFAULT_SUPPORTED_FEATURES = {
ProviderFeature.ARTIST_METADATA,
ProviderFeature.ALBUM_METADATA,
ProviderFeature.TRACK_METADATA,
)
}


class MetadataProvider(Provider):
Expand All @@ -27,7 +27,7 @@ class MetadataProvider(Provider):
"""

@property
def supported_features(self) -> tuple[ProviderFeature, ...]:
def supported_features(self) -> set[ProviderFeature]:
"""Return the features supported by this Provider."""
return DEFAULT_SUPPORTED_FEATURES

Expand Down
16 changes: 8 additions & 8 deletions music_assistant/models/player_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ async def cmd_previous(self, player_id: str) -> None:
# will only be called for players with 'next_previous' feature set.
raise NotImplementedError

async def cmd_sync(self, player_id: str, target_player: str) -> None:
"""Handle SYNC command for given player.
async def cmd_group(self, player_id: str, target_player: str) -> None:
"""Handle GROUP command for given player.
Join/add the given player(id) to the given (master) player/sync group.
Expand All @@ -180,21 +180,21 @@ async def cmd_sync(self, player_id: str, target_player: str) -> None:
# will only be called for players with SYNC feature set.
raise NotImplementedError

async def cmd_unsync(self, player_id: str) -> None:
"""Handle UNSYNC command for given player.
async def cmd_ungroup(self, player_id: str) -> None:
"""Handle UNGROUP command for given player.
Remove the given player from any syncgroups it currently is synced to.
Remove the given player from any (sync)groups it currently is grouped to.
- player_id: player_id of the player to handle the command.
"""
# will only be called for players with SYNC feature set.
raise NotImplementedError

async def cmd_sync_many(self, target_player: str, child_player_ids: list[str]) -> None:
async def cmd_group_many(self, target_player: str, child_player_ids: list[str]) -> None:
"""Create temporary sync group by joining given players to target player."""
for child_id in child_player_ids:
# default implementation, simply call the cmd_sync for all child players
await self.cmd_sync(child_id, target_player)
# default implementation, simply call the cmd_group for all child players
await self.cmd_group(child_id, target_player)

async def poll_player(self, player_id: str) -> None:
"""Poll player for state updates.
Expand Down
2 changes: 1 addition & 1 deletion music_assistant/models/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def __init__(
self.available = False

@property
def supported_features(self) -> tuple[ProviderFeature, ...]:
def supported_features(self) -> set[ProviderFeature]:
"""Return the features supported by this Provider."""
return ()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ class MyDemoMusicprovider(MusicProvider):
"""

@property
def supported_features(self) -> tuple[ProviderFeature, ...]:
def supported_features(self) -> set[ProviderFeature]:
"""Return the features supported by this Provider."""
# MANDATORY
# you should return a tuple of provider-level features
Expand Down
14 changes: 7 additions & 7 deletions music_assistant/providers/_template_player_provider/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class MyDemoPlayerprovider(PlayerProvider):
"""

@property
def supported_features(self) -> tuple[ProviderFeature, ...]:
def supported_features(self) -> set[ProviderFeature]:
"""Return the features supported by this Provider."""
# MANDATORY
# you should return a tuple of provider-level features
Expand Down Expand Up @@ -210,7 +210,7 @@ async def on_mdns_service_state_change(
device_info=DeviceInfo(
model="Model XYX",
manufacturer="Super Brand",
address=cur_address,
ip_address=cur_address,
),
# set the supported features for this player only with
# the ones the player actually supports
Expand Down Expand Up @@ -339,8 +339,8 @@ async def enqueue_next_media(self, player_id: str, media: PlayerMedia) -> None:
"""
# this method should handle the enqueuing of the next queue item on the player.

async def cmd_sync(self, player_id: str, target_player: str) -> None:
"""Handle SYNC command for given player.
async def cmd_group(self, player_id: str, target_player: str) -> None:
"""Handle GROUP command for given player.
Join/add the given player(id) to the given (master) player/sync group.
Expand All @@ -351,10 +351,10 @@ async def cmd_sync(self, player_id: str, target_player: str) -> None:
# this method should handle the sync command for the given player.
# you should join the given player to the target_player/syncgroup.

async def cmd_unsync(self, player_id: str) -> None:
"""Handle UNSYNC command for given player.
async def cmd_ungroup(self, player_id: str) -> None:
"""Handle UNGROUP command for given player.
Remove the given player from any syncgroups it currently is synced to.
Remove the given player from any (sync)groups it currently is grouped to.
- player_id: player_id of the player to handle the command.
"""
Expand Down
17 changes: 9 additions & 8 deletions music_assistant/providers/airplay/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class AirplayProvider(PlayerProvider):
_play_media_lock: asyncio.Lock = asyncio.Lock()

@property
def supported_features(self) -> tuple[ProviderFeature, ...]:
def supported_features(self) -> set[ProviderFeature]:
"""Return the features supported by this Provider."""
return (ProviderFeature.SYNC_PLAYERS,)

Expand Down Expand Up @@ -210,7 +210,7 @@ async def on_mdns_service_state_change(
mass_player.device_info = DeviceInfo(
model=mass_player.device_info.model,
manufacturer=mass_player.device_info.manufacturer,
address=str(cur_address),
ip_address=str(cur_address),
)
if not mass_player.available:
self.logger.debug("Player back online: %s", display_name)
Expand Down Expand Up @@ -347,8 +347,8 @@ async def cmd_volume_set(self, player_id: str, volume_level: int) -> None:
await self.mass.cache.set(player_id, volume_level, base_key=CACHE_KEY_PREV_VOLUME)

@lock
async def cmd_sync(self, player_id: str, target_player: str) -> None:
"""Handle SYNC command for given player.
async def cmd_group(self, player_id: str, target_player: str) -> None:
"""Handle GROUP command for given player.
Join/add the given player(id) to the given (master) player/sync group.
Expand Down Expand Up @@ -398,10 +398,10 @@ async def cmd_sync(self, player_id: str, target_player: str) -> None:
self.mass.players.update(parent_player.player_id, skip_forward=True)

@lock
async def cmd_unsync(self, player_id: str) -> None:
"""Handle UNSYNC command for given player.
async def cmd_ungroup(self, player_id: str) -> None:
"""Handle UNGROUP command for given player.
Remove the given player from any syncgroups it currently is synced to.
Remove the given player from any (sync)groups it currently is grouped to.
- player_id: player_id of the player to handle the command.
"""
Expand Down Expand Up @@ -518,10 +518,11 @@ async def _setup_player(
),
supported_features=(
PlayerFeature.PAUSE,
PlayerFeature.SYNC,
PlayerFeature.SET_MEMBERS,
PlayerFeature.VOLUME_SET,
),
volume_level=volume,
can_group_with={self.instance_id},
)
await self.mass.players.register_or_update(mass_player)

Expand Down
6 changes: 3 additions & 3 deletions music_assistant/providers/apple_music/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
from music_assistant.models import ProviderInstanceType


SUPPORTED_FEATURES = (
SUPPORTED_FEATURES = {
ProviderFeature.LIBRARY_ARTISTS,
ProviderFeature.LIBRARY_ALBUMS,
ProviderFeature.LIBRARY_TRACKS,
Expand All @@ -63,7 +63,7 @@
ProviderFeature.ARTIST_ALBUMS,
ProviderFeature.ARTIST_TOPTRACKS,
ProviderFeature.SIMILAR_TRACKS,
)
}

DEVELOPER_TOKEN = app_var(8)
WIDEVINE_BASE_PATH = "/usr/local/bin/widevine_cdm"
Expand Down Expand Up @@ -127,7 +127,7 @@ async def handle_async_init(self) -> None:
self._decrypt_private_key = await _file.read()

@property
def supported_features(self) -> tuple[ProviderFeature, ...]:
def supported_features(self) -> set[ProviderFeature]:
"""Return the features supported by this Provider."""
return SUPPORTED_FEATURES

Expand Down
28 changes: 15 additions & 13 deletions music_assistant/providers/bluesound/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@


PLAYER_FEATURES_BASE = {
PlayerFeature.SYNC,
PlayerFeature.SET_MEMBERS,
PlayerFeature.VOLUME_MUTE,
PlayerFeature.PAUSE,
}
Expand Down Expand Up @@ -188,9 +188,10 @@ async def update_attributes(self) -> None:

if self.sync_status.leader is None:
if self.sync_status.followers:
self.mass_player.group_childs = (
self.sync_status.followers if len(self.sync_status.followers) > 1 else set()
)
if len(self.sync_status.followers) > 1:
self.mass_player.group_childs.set(self.sync_status.followers)
else:
self.mass_player.group_childs.clear()
self.mass_player.synced_to = None

if self.status.state == "stream":
Expand All @@ -205,7 +206,7 @@ async def update_attributes(self) -> None:
self.mass_player.current_media = None

else:
self.mass_player.group_childs = set()
self.mass_player.group_childs.clear()
self.mass_player.synced_to = self.sync_status.leader
self.mass_player.active_source = self.sync_status.leader

Expand All @@ -219,9 +220,9 @@ class BluesoundPlayerProvider(PlayerProvider):
bluos_players: dict[str, BluesoundPlayer]

@property
def supported_features(self) -> tuple[ProviderFeature, ...]:
def supported_features(self) -> set[ProviderFeature]:
"""Return the features supported by this Provider."""
return (ProviderFeature.SYNC_PLAYERS,)
return {ProviderFeature.SYNC_PLAYERS}

async def handle_async_init(self) -> None:
"""Handle async initialization of the provider."""
Expand Down Expand Up @@ -257,7 +258,7 @@ async def on_mdns_service_state_change(
mass_player.device_info = DeviceInfo(
model=mass_player.device_info.model,
manufacturer=mass_player.device_info.manufacturer,
address=str(cur_address),
ip_address=str(cur_address),
)
if not mass_player.available:
self.logger.debug("Player back online: %s", mass_player.display_name)
Expand All @@ -284,7 +285,7 @@ async def on_mdns_service_state_change(
device_info=DeviceInfo(
model="BluOS speaker",
manufacturer="Bluesound",
address=cur_address,
ip_address=cur_address,
),
# Set the supported features for this player
supported_features=(
Expand All @@ -294,6 +295,7 @@ async def on_mdns_service_state_change(
),
needs_poll=True,
poll_interval=30,
can_group_with={self.instance_id},
)
await self.mass.players.register(mass_player)

Expand Down Expand Up @@ -392,12 +394,12 @@ async def poll_player(self, player_id: str) -> None:
if bluos_player := self.bluos_players[player_id]:
await bluos_player.update_attributes()

# TODO fix sync & unsync
# TODO fix sync & ungroup

async def cmd_sync(self, player_id: str, target_player: str) -> None:
async def cmd_group(self, player_id: str, target_player: str) -> None:
"""Handle SYNC command for BluOS player."""

async def cmd_unsync(self, player_id: str) -> None:
"""Handle UNSYNC command for BluOS player."""
async def cmd_ungroup(self, player_id: str) -> None:
"""Handle UNGROUP command for BluOS player."""
if bluos_player := self.bluos_players[player_id]:
await bluos_player.client.player.leave_group()
6 changes: 3 additions & 3 deletions music_assistant/providers/builtin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ def is_streaming_provider(self) -> bool:
return False

@property
def supported_features(self) -> tuple[ProviderFeature, ...]:
def supported_features(self) -> set[ProviderFeature]:
"""Return the features supported by this Provider."""
return (
return {
ProviderFeature.BROWSE,
ProviderFeature.LIBRARY_TRACKS,
ProviderFeature.LIBRARY_RADIOS,
Expand All @@ -176,7 +176,7 @@ def supported_features(self) -> tuple[ProviderFeature, ...]:
ProviderFeature.LIBRARY_RADIOS_EDIT,
ProviderFeature.PLAYLIST_CREATE,
ProviderFeature.PLAYLIST_TRACKS_EDIT,
)
}

async def get_track(self, prov_track_id: str) -> Track:
"""Get full track details by id."""
Expand Down
Loading

0 comments on commit d517198

Please sign in to comment.