Various small glitches resolved regarding podcasts and audiobooks
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Sat, 4 Jan 2025 23:31:36 +0000 (00:31 +0100)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Sat, 4 Jan 2025 23:31:36 +0000 (00:31 +0100)
music_assistant/constants.py
music_assistant/controllers/media/audiobooks.py
music_assistant/controllers/media/podcasts.py
music_assistant/helpers/resources/silence_long.ogg [new file with mode: 0644]
music_assistant/providers/test/__init__.py
pyproject.toml
requirements_all.txt

index 70817afa2f9e14bf636532b93ef3454be6f9e310..301bad85b10f26e074bc065145027697342474a7 100644 (file)
@@ -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(
index d47f8b828e0e449b4fac0ebbcd02738e22df075e..0d23d6fa3f4cf0ff8536146bbc79d137ff1c4bde 100644 (file)
@@ -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}"
index cf1f53b30383dfdb4ee3bb55db7d6613440af5da..a8267d153c162581d7e5d05b3ab12527c290194e 100644 (file)
@@ -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 (file)
index 0000000..df4e96e
Binary files /dev/null and b/music_assistant/helpers/resources/silence_long.ogg differ
index d7aac0e775662f7ccb8c01dd073ffcf9e7ae6fd8..eae108644af5c5e0d94b0474bae3d422d06e8c21 100644 (file)
@@ -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,
         )
index 11fcf40b01220d219937801ed315508e28b1b713..63823b56edfb2c3d89eff085c9a33c29f045d3ca 100644 (file)
@@ -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",
index 0424ebd32199421c90572aee9da88c1175611f5a..2330f6b1af819a641548bc0717587ee1c1ffc176 100644 (file)
@@ -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