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
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"))
)
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,
+ }
)
{**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(
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(
)
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"]
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}"
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(
)
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"]
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
)
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:
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={
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,
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,
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,
)
"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",
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