From 66f8e2803aa7da7d88d1e680e75e83287a5f47ee Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 5 Jan 2025 00:31:36 +0100 Subject: [PATCH] Various small glitches resolved regarding podcasts and audiobooks --- music_assistant/constants.py | 27 +++++++++++++++--- .../controllers/media/audiobooks.py | 10 +++---- music_assistant/controllers/media/podcasts.py | 10 +++---- .../helpers/resources/silence_long.ogg | Bin 0 -> 10389 bytes music_assistant/providers/test/__init__.py | 18 +++++++----- pyproject.toml | 2 +- requirements_all.txt | 2 +- 7 files changed, 46 insertions(+), 23 deletions(-) create mode 100644 music_assistant/helpers/resources/silence_long.ogg diff --git a/music_assistant/constants.py b/music_assistant/constants.py index 70817afa..301bad85 100644 --- a/music_assistant/constants.py +++ b/music_assistant/constants.py @@ -3,7 +3,11 @@ import pathlib from typing import Final -from music_assistant_models.config_entries import ConfigEntry, ConfigEntryType, ConfigValueOption +from music_assistant_models.config_entries import ( + ConfigEntry, + ConfigEntryType, + ConfigValueOption, +) API_SCHEMA_VERSION: Final[int] = 26 MIN_SCHEMA_VERSION: Final[int] = 24 @@ -23,6 +27,7 @@ RESOURCES_DIR: Final[pathlib.Path] = ( ANNOUNCE_ALERT_FILE: Final[str] = str(RESOURCES_DIR.joinpath("announce.mp3")) SILENCE_FILE: Final[str] = str(RESOURCES_DIR.joinpath("silence.mp3")) +SILENCE_FILE_LONG: Final[str] = str(RESOURCES_DIR.joinpath("silence_long.ogg")) VARIOUS_ARTISTS_FANART: Final[str] = str(RESOURCES_DIR.joinpath("fallback_fanart.jpeg")) MASS_LOGO: Final[str] = str(RESOURCES_DIR.joinpath("logo.png")) @@ -149,11 +154,21 @@ CONF_ENTRY_FLOW_MODE_DEFAULT_ENABLED = ConfigEntry.from_dict( ) CONF_ENTRY_FLOW_MODE_ENFORCED = ConfigEntry.from_dict( - {**CONF_ENTRY_FLOW_MODE.to_dict(), "default_value": True, "value": True, "hidden": True} + { + **CONF_ENTRY_FLOW_MODE.to_dict(), + "default_value": True, + "value": True, + "hidden": True, + } ) CONF_ENTRY_FLOW_MODE_HIDDEN_DISABLED = ConfigEntry.from_dict( - {**CONF_ENTRY_FLOW_MODE.to_dict(), "default_value": False, "value": False, "hidden": True} + { + **CONF_ENTRY_FLOW_MODE.to_dict(), + "default_value": False, + "value": False, + "hidden": True, + } ) @@ -439,7 +454,11 @@ CONF_ENTRY_HTTP_PROFILE_FORCED_1 = ConfigEntry.from_dict( {**CONF_ENTRY_HTTP_PROFILE.to_dict(), "default_value": "chunked", "hidden": True} ) CONF_ENTRY_HTTP_PROFILE_FORCED_2 = ConfigEntry.from_dict( - {**CONF_ENTRY_HTTP_PROFILE.to_dict(), "default_value": "no_content_length", "hidden": True} + { + **CONF_ENTRY_HTTP_PROFILE.to_dict(), + "default_value": "no_content_length", + "hidden": True, + } ) CONF_ENTRY_ENABLE_ICY_METADATA = ConfigEntry( diff --git a/music_assistant/controllers/media/audiobooks.py b/music_assistant/controllers/media/audiobooks.py index d47f8b82..0d23d6fa 100644 --- a/music_assistant/controllers/media/audiobooks.py +++ b/music_assistant/controllers/media/audiobooks.py @@ -212,9 +212,7 @@ class AudiobooksController(MediaControllerBase[Audiobook]): items = await prov.get_audiobook_chapters(item_id) async def set_resume_position(chapter: Chapter) -> None: - if chapter.resume_position_ms is not None: - return - if chapter.fully_played is not None: + if chapter.fully_played is not None or chapter.resume_position_ms: return # TODO: inject resume position info here for providers that do not natively provide it resume_info_db_row = await self.mass.music.database.get_row( @@ -227,7 +225,7 @@ class AudiobooksController(MediaControllerBase[Audiobook]): ) if resume_info_db_row is None: return - if resume_info_db_row["seconds_played"] is not None: + if resume_info_db_row["seconds_played"]: chapter.resume_position_ms = int(resume_info_db_row["seconds_played"] * 1000) if resume_info_db_row["fully_played"] is not None: chapter.fully_played = resume_info_db_row["fully_played"] @@ -263,7 +261,9 @@ class AudiobooksController(MediaControllerBase[Audiobook]): async def find_prov_match(provider: MusicProvider): self.logger.debug( - "Trying to match audiobook %s on provider %s", db_audiobook.name, provider.name + "Trying to match audiobook %s on provider %s", + db_audiobook.name, + provider.name, ) match_found = False search_str = f"{author_name} - {db_audiobook.name}" diff --git a/music_assistant/controllers/media/podcasts.py b/music_assistant/controllers/media/podcasts.py index cf1f53b3..a8267d15 100644 --- a/music_assistant/controllers/media/podcasts.py +++ b/music_assistant/controllers/media/podcasts.py @@ -205,9 +205,7 @@ class PodcastsController(MediaControllerBase[Podcast]): items = await prov.get_podcast_episodes(item_id) async def set_resume_position(episode: Episode) -> None: - if episode.resume_position_ms is not None: - return - if episode.fully_played is not None: + if episode.fully_played is not None or episode.resume_position_ms: return # TODO: inject resume position info here for providers that do not natively provide it resume_info_db_row = await self.mass.music.database.get_row( @@ -220,7 +218,7 @@ class PodcastsController(MediaControllerBase[Podcast]): ) if resume_info_db_row is None: return - if resume_info_db_row["seconds_played"] is not None: + if resume_info_db_row["seconds_played"]: episode.resume_position_ms = int(resume_info_db_row["seconds_played"] * 1000) if resume_info_db_row["fully_played"] is not None: episode.fully_played = resume_info_db_row["fully_played"] @@ -253,7 +251,9 @@ class PodcastsController(MediaControllerBase[Podcast]): async def find_prov_match(provider: MusicProvider): self.logger.debug( - "Trying to match podcast %s on provider %s", db_podcast.name, provider.name + "Trying to match podcast %s on provider %s", + db_podcast.name, + provider.name, ) match_found = False search_str = db_podcast.name diff --git a/music_assistant/helpers/resources/silence_long.ogg b/music_assistant/helpers/resources/silence_long.ogg new file mode 100644 index 0000000000000000000000000000000000000000..df4e96eb601690de96a37467041f9952e77f80c0 GIT binary patch literal 10389 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 DS=)1t literal 0 HcmV?d00001 diff --git a/music_assistant/providers/test/__init__.py b/music_assistant/providers/test/__init__.py index d7aac0e7..eae10864 100644 --- a/music_assistant/providers/test/__init__.py +++ b/music_assistant/providers/test/__init__.py @@ -31,7 +31,11 @@ from music_assistant_models.media_items import ( ) from music_assistant_models.streamdetails import StreamDetails -from music_assistant.constants import MASS_LOGO, SILENCE_FILE, VARIOUS_ARTISTS_FANART +from music_assistant.constants import ( + MASS_LOGO, + SILENCE_FILE_LONG, + VARIOUS_ARTISTS_FANART, +) from music_assistant.models.music_provider import MusicProvider if TYPE_CHECKING: @@ -158,7 +162,7 @@ class TestProvider(MusicProvider): item_id=prov_track_id, provider=self.instance_id, name=f"Test Track {artist_idx} - {album_idx} - {track_idx}", - duration=5, + duration=60, artists=UniqueList([await self.get_artist(artist_idx)]), album=await self.get_album(f"{artist_idx}_{album_idx}"), provider_mappings={ @@ -293,7 +297,7 @@ class TestProvider(MusicProvider): item_id=f"{prov_audiobook_id}_{chapter_idx}", provider=self.instance_id, name=f"Test Chapter {prov_audiobook_id}-{chapter_idx}", - duration=5, + duration=60, audiobook=ItemMapping( item_id=prov_audiobook_id, provider=self.instance_id, @@ -328,7 +332,7 @@ class TestProvider(MusicProvider): item_id=f"{prov_podcast_id}_{episode_idx}", provider=self.instance_id, name=f"Test Episode {prov_podcast_id}-{episode_idx}", - duration=5, + duration=60, podcast=ItemMapping( item_id=prov_podcast_id, provider=self.instance_id, @@ -360,13 +364,13 @@ class TestProvider(MusicProvider): provider=self.instance_id, item_id=item_id, audio_format=AudioFormat( - content_type=ContentType.MP3, - sample_rate=44100, + content_type=ContentType.OGG, + sample_rate=48000, bit_depth=16, channels=2, ), media_type=media_type, stream_type=StreamType.HTTP, - path=SILENCE_FILE, + path=SILENCE_FILE_LONG, can_seek=True, ) diff --git a/pyproject.toml b/pyproject.toml index 11fcf40b..63823b56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ dependencies = [ "mashumaro==3.14", "memory-tempfile==2.2.3", "music-assistant-frontend==2.10.0", - "music-assistant-models==1.1.5", + "music-assistant-models==1.1.6", "orjson==3.10.12", "pillow==11.0.0", "python-slugify==8.0.4", diff --git a/requirements_all.txt b/requirements_all.txt index 0424ebd3..2330f6b1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -24,7 +24,7 @@ ifaddr==0.2.0 mashumaro==3.14 memory-tempfile==2.2.3 music-assistant-frontend==2.10.0 -music-assistant-models==1.1.5 +music-assistant-models==1.1.6 orjson==3.10.12 pillow==11.0.0 pkce==1.0.3 -- 2.34.1