Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some small bugfixes and tweaks #1642

Merged
merged 6 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions music_assistant/server/helpers/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ async def crossfade_pcm_parts(
_returncode, crossfaded_audio, _stderr = await communicate(args, fade_in_part)
if crossfaded_audio:
LOGGER.log(
5,
VERBOSE_LOG_LEVEL,
"crossfaded 2 pcm chunks. fade_in_part: %s - "
"fade_out_part: %s - fade_length: %s seconds",
len(fade_in_part),
Expand Down Expand Up @@ -310,12 +310,12 @@ async def strip_silence(

# return stripped audio
bytes_stripped = len(audio_data) - len(stripped_data)
if LOGGER.isEnabledFor(5):
if LOGGER.isEnabledFor(VERBOSE_LOG_LEVEL):
pcm_sample_size = int(sample_rate * (bit_depth / 8) * 2)
seconds_stripped = round(bytes_stripped / pcm_sample_size, 2)
location = "end" if reverse else "begin"
LOGGER.log(
5,
VERBOSE_LOG_LEVEL,
"stripped %s seconds of silence from %s of pcm audio. bytes stripped: %s",
seconds_stripped,
location,
Expand All @@ -336,6 +336,8 @@ async def get_stream_details(
Do not try to request streamdetails in advance as this is expiring data.
param media_item: The QueueItem for which to request the streamdetails for.
"""
time_start = time.time()
LOGGER.debug("Getting streamdetails for %s", queue_item.uri)
if seek_position and (queue_item.media_type == MediaType.RADIO or not queue_item.duration):
LOGGER.warning("seeking is not possible on duration-less streams!")
seek_position = 0
Expand Down Expand Up @@ -406,7 +408,8 @@ async def get_stream_details(
streamdetails.target_loudness = None
else:
streamdetails.target_loudness = player_settings.get_value(CONF_VOLUME_NORMALIZATION_TARGET)

process_time = int((time.time() - time_start) * 1000)
LOGGER.debug("retrieved streamdetails for %s in %s milliseconds", queue_item.uri, process_time)
return streamdetails


Expand Down
37 changes: 22 additions & 15 deletions music_assistant/server/helpers/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,22 +128,32 @@ def compare_track(
# return early on exact item_id match
if compare_item_ids(base_item, compare_item):
return True
# return early on (un)matched external id
# return early on (un)matched primary/unique external id
for ext_id in (
ExternalID.MB_RECORDING,
ExternalID.DISCOGS,
ExternalID.MB_TRACK,
ExternalID.ACOUSTID,
):
external_id_match = compare_external_ids(
base_item.external_ids, compare_item.external_ids, ext_id
)
if external_id_match is not None:
return external_id_match
# check secondary external id matches
for ext_id in (
ExternalID.DISCOGS,
ExternalID.TADB,
# make sure to check musicbrainz before isrc
# https://github.com/music-assistant/hass-music-assistant/issues/2316
ExternalID.ISRC,
ExternalID.ASIN,
):
external_id_match = compare_external_ids(
base_item.external_ids, compare_item.external_ids, ext_id
)
if external_id_match is not None:
return external_id_match
if external_id_match is True:
# we got a 'soft-match' on a secondary external id (like ISRC)
# but we do a double check on duration
if abs(base_item.duration - compare_item.duration) <= 2:
return True

# compare name
if not compare_strings(base_item.name, compare_item.name, strict=True):
Expand Down Expand Up @@ -227,18 +237,15 @@ def compare_playlist(
"""Compare two Playlist items and return True if they match."""
if base_item is None or compare_item is None:
return False
# return early on exact item_id match
if compare_item_ids(base_item, compare_item):
return True
# compare owner (if not ItemMapping)
# require (exact) name match
if not compare_strings(base_item.name, compare_item.name, strict=strict):
return False
# require exact owner match (if not ItemMapping)
if isinstance(base_item, Playlist) and isinstance(compare_item, Playlist):
if not compare_strings(base_item.owner, compare_item.owner):
return False
# compare version
if not compare_version(base_item.version, compare_item.version):
return False
# finally comparing on (exact) name match
return compare_strings(base_item.name, compare_item.name, strict=strict)
# a playlist is always unique - so do a strict compare on item id(s)
return compare_item_ids(base_item, compare_item)


def compare_radio(
Expand Down
1 change: 1 addition & 0 deletions music_assistant/server/providers/airplay/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,7 @@ async def cmd_volume_set(self, player_id: str, volume_level: int) -> None:
await airplay_player.raop_stream.send_cli_command(f"VOLUME={volume_level}\n")
mass_player = self.mass.players.get(player_id)
mass_player.volume_level = volume_level
mass_player.volume_muted = volume_level == 0
self.mass.players.update(player_id)
# store last state in cache
await self.mass.cache.set(player_id, volume_level, base_key=CACHE_KEY_PREV_VOLUME)
Expand Down
10 changes: 6 additions & 4 deletions music_assistant/server/providers/radiobrowser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ async def get_tag_folders(self, base_path: str) -> list[BrowseFolder]:
async def get_country_folders(self, base_path: str) -> list[BrowseFolder]:
"""Get a list of country names as BrowseFolder."""
items: list[BrowseFolder] = []
for country in await self.radios.countries(order=Order.NAME, hide_broken=True):
for country in await self.radios.countries(order=Order.NAME, hide_broken=True, limit=1000):
folder = BrowseFolder(
item_id=country.code.lower(),
provider=self.domain,
Expand All @@ -270,7 +270,7 @@ async def get_by_popularity(self) -> Sequence[Radio]:
"""Get radio stations by popularity."""
stations = await self.radios.stations(
hide_broken=True,
limit=5000,
limit=1000,
order=Order.CLICK_COUNT,
reverse=True,
)
Expand All @@ -287,7 +287,8 @@ async def get_by_tag(self, tag: str) -> Sequence[Radio]:
filter_by=FilterBy.TAG_EXACT,
filter_term=tag,
hide_broken=True,
order=Order.NAME,
limit=1000,
order=Order.CLICK_COUNT,
reverse=False,
)
for station in stations:
Expand All @@ -302,7 +303,8 @@ async def get_by_country(self, country_code: str) -> list[Radio]:
filter_by=FilterBy.COUNTRY_CODE_EXACT,
filter_term=country_code,
hide_broken=True,
order=Order.NAME,
limit=1000,
order=Order.CLICK_COUNT,
reverse=False,
)
for station in stations:
Expand Down
45 changes: 23 additions & 22 deletions music_assistant/server/providers/spotify/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,28 +563,29 @@ async def get_audio_stream(
auth_info = await self.login()
librespot = await self.get_librespot_binary()
spotify_uri = f"spotify://track:{streamdetails.item_id}"
args = [
librespot,
"-c",
CACHE_DIR,
"-M",
"256M",
"--passthrough",
"-b",
"320",
"--backend",
"pipe",
"--single-track",
spotify_uri,
"--token",
auth_info["access_token"],
]
if seek_position:
args += ["--start-position", str(int(seek_position))]
chunk_size = get_chunksize(streamdetails.audio_format)
stderr = None if self.logger.isEnabledFor(VERBOSE_LOG_LEVEL) else False
self.logger.log(VERBOSE_LOG_LEVEL, f"Start streaming {spotify_uri} using librespot")
for retry in (True, False):
args = [
librespot,
"-c",
CACHE_DIR,
"-M",
"256M",
"--passthrough",
"-b",
"320",
"--backend",
"pipe",
"--single-track",
spotify_uri,
"--token",
auth_info["access_token"],
]
if seek_position:
args += ["--start-position", str(int(seek_position))]
chunk_size = get_chunksize(streamdetails.audio_format)
stderr = None if self.logger.isEnabledFor(VERBOSE_LOG_LEVEL) else False
self.logger.log(VERBOSE_LOG_LEVEL, f"Start streaming {spotify_uri} using librespot")

async with AsyncProcess(
args,
stdout=True,
Expand All @@ -600,7 +601,7 @@ async def get_audio_stream(
raise AudioError(
f"Failed to stream {spotify_uri} - error: {librespot_proc.returncode}"
)
# do one retry attempt
# do one retry attempt - accounting for the fact that the token might have expired
auth_info = await self.login(force_refresh=True)

def _parse_artist(self, artist_obj):
Expand Down