From 3c20f70b602c8cc21ababf3d2bf66e6e37f36350 Mon Sep 17 00:00:00 2001 From: Fabian Munkes <105975993+fmunkes@users.noreply.github.com> Date: Sun, 4 Jan 2026 00:17:35 +0100 Subject: [PATCH] ABS/ iTunes podcasts: allow translation of folders (#2913) --- .../providers/audiobookshelf/__init__.py | 66 ++++++++++--------- .../providers/audiobookshelf/constants.py | 43 ++++++++---- .../providers/itunes_podcasts/__init__.py | 4 +- 3 files changed, 66 insertions(+), 47 deletions(-) diff --git a/music_assistant/providers/audiobookshelf/__init__.py b/music_assistant/providers/audiobookshelf/__init__.py index 85e7c38d..63b1d04b 100644 --- a/music_assistant/providers/audiobookshelf/__init__.py +++ b/music_assistant/providers/audiobookshelf/__init__.py @@ -72,6 +72,7 @@ from music_assistant.providers.audiobookshelf.parsers import ( from .constants import ( ABS_BROWSE_ITEMS_TO_PATH, ABS_SHELF_ID_ICONS, + ABS_SHELF_ID_TRANSLATION_KEY, AIOHTTP_TIMEOUT, CACHE_CATEGORY_LIBRARIES, CACHE_KEY_LIBRARIES, @@ -82,8 +83,8 @@ from .constants import ( CONF_URL, CONF_USERNAME, CONF_VERIFY_SSL, - AbsBrowseItemsBook, - AbsBrowseItemsPodcast, + AbsBrowseItemsBookTranslationKey, + AbsBrowseItemsPodcastTranslationKey, AbsBrowsePaths, ) from .helpers import LibrariesHelper, LibraryHelper, ProgressGuard @@ -709,12 +710,14 @@ for more details. # newest-episodes # etc name = f"{shelf_id.capitalize().replace('-', ' ')}" + if ABS_SHELF_ID_TRANSLATION_KEY.get(shelf_id): + name = "" # use translation key if available folders.append( RecommendationFolder( item_id=f"{shelf_id}", name=name, icon=ABS_SHELF_ID_ICONS.get(shelf_id), - # translation_key=shelf.id_, + translation_key=ABS_SHELF_ID_TRANSLATION_KEY.get(shelf_id), items=UniqueList(recommendation_items), provider=self.instance_id, ) @@ -726,17 +729,10 @@ for more details. # from _browse_lib_audiobooks, i.e. Authors, Narrators etc. # Podcast libs do not have filter folders, so always the root folders. browse_items: list[MediaItemType | BrowseFolder] = [] + translation_key = "libraries" if len(self.libraries.audiobooks) <= 1: - browse_names = [ - x.name for x in self.libraries.audiobooks.values() - ] # single name (or no name) - if len(self.libraries.podcasts) == 1: - browse_names.extend( - [x.name for x in self.libraries.podcasts.values()] - ) # single name again - else: - browse_names.append("Podcasts") - browse_name = " & ".join(browse_names) + if len(self.libraries.podcasts) == 0: + translation_key = "library" # audiobooklibs are first, and we have at max 1 audiobook lib _browse_root = self._browse_root(append_mediatype_suffix=False) @@ -749,15 +745,14 @@ for more details. # add podcast roots browse_items.extend(_browse_root[1:]) else: - browse_name = "Your libraries" - browse_items = list(self._browse_root()) + folders.append( RecommendationFolder( item_id="browse", - name=browse_name, + name="", # use translation key icon="mdi-bookshelf", - # translation_key=shelf.id_, + translation_key=translation_key, items=UniqueList(browse_items), provider=self.instance_id, ) @@ -1040,10 +1035,13 @@ for more details. def _browse_root(self, append_mediatype_suffix: bool = True) -> Sequence[BrowseFolder]: items = [] - def _get_folder(path: str, lib_id: str, lib_name: str) -> BrowseFolder: + def _get_folder( + path: str, lib_id: str, lib_name: str, translation_key: str | None = None + ) -> BrowseFolder: return BrowseFolder( item_id=lib_id, name=lib_name, + translation_key=translation_key, # if given, : in frontend provider=self.instance_id, path=f"{self.instance_id}://{path}", ) @@ -1052,20 +1050,23 @@ for more details. self._log_no_libraries() return [] + translation_key: str | None for lib_id, lib in self.libraries.audiobooks.items(): path = f"{AbsBrowsePaths.LIBRARIES_BOOK} {lib_id}" + translation_key = None if append_mediatype_suffix: - name = f"{lib.name} ({AbsBrowseItemsBook.AUDIOBOOKS})" - else: - name = lib.name - items.append(_get_folder(path, lib_id, name)) + translation_key = AbsBrowseItemsBookTranslationKey.AUDIOBOOKS + items.append( + _get_folder(path, lib_id, lib_name=lib.name, translation_key=translation_key) + ) for lib_id, lib in self.libraries.podcasts.items(): path = f"{AbsBrowsePaths.LIBRARIES_PODCAST} {lib_id}" + translation_key = None if append_mediatype_suffix: - name = f"{lib.name} ({AbsBrowseItemsPodcast.PODCASTS})" - else: - name = lib.name - items.append(_get_folder(path, lib_id, name)) + translation_key = AbsBrowseItemsPodcastTranslationKey.PODCASTS + items.append( + _get_folder(path, lib_id, lib_name=lib.name, translation_key=translation_key) + ) return items async def _browse_lib_podcasts(self, library_id: str) -> list[MediaItemType]: @@ -1085,12 +1086,13 @@ for more details. def _browse_lib_audiobooks(self, current_path: str) -> Sequence[BrowseFolder]: items = [] - for item_name in AbsBrowseItemsBook: - path = current_path + "/" + ABS_BROWSE_ITEMS_TO_PATH[item_name] + for translation_key in AbsBrowseItemsBookTranslationKey: + path = current_path + "/" + ABS_BROWSE_ITEMS_TO_PATH[translation_key] items.append( BrowseFolder( - item_id=item_name.lower(), - name=item_name, + item_id=translation_key.lower(), + name="", # use translation key + translation_key=translation_key, provider=self.instance_id, path=path, ) @@ -1200,7 +1202,9 @@ for more details. items.append( BrowseFolder( item_id=series.id_, - name=f"{series.name} ({AbsBrowseItemsBook.SERIES})", + # frontend does : + name=series.name, + translation_key="series_singular", provider=self.instance_id, path=path, ) diff --git a/music_assistant/providers/audiobookshelf/constants.py b/music_assistant/providers/audiobookshelf/constants.py index d83deb3c..4442cdf0 100644 --- a/music_assistant/providers/audiobookshelf/constants.py +++ b/music_assistant/providers/audiobookshelf/constants.py @@ -37,28 +37,28 @@ class AbsBrowsePaths(StrEnum): AUDIOBOOKS = "b" -class AbsBrowseItemsBook(StrEnum): - """Folder names in browse view for books.""" +class AbsBrowseItemsBookTranslationKey(StrEnum): + """translation keys in browse view for books.""" - AUTHORS = "Authors" - NARRATORS = "Narrators" - SERIES = "Series" - COLLECTIONS = "Collections" - AUDIOBOOKS = "Audiobooks" + AUTHORS = "authors" + NARRATORS = "narrators" + SERIES = "series_plural" + COLLECTIONS = "collections" + AUDIOBOOKS = "audiobooks" -class AbsBrowseItemsPodcast(StrEnum): +class AbsBrowseItemsPodcastTranslationKey(StrEnum): """Folder names in browse view for podcasts.""" - PODCASTS = "Podcasts" + PODCASTS = "podcasts" ABS_BROWSE_ITEMS_TO_PATH: dict[str, str] = { - AbsBrowseItemsBook.AUTHORS: AbsBrowsePaths.AUTHORS, - AbsBrowseItemsBook.NARRATORS: AbsBrowsePaths.NARRATORS, - AbsBrowseItemsBook.SERIES: AbsBrowsePaths.SERIES, - AbsBrowseItemsBook.COLLECTIONS: AbsBrowsePaths.COLLECTIONS, - AbsBrowseItemsBook.AUDIOBOOKS: AbsBrowsePaths.AUDIOBOOKS, + AbsBrowseItemsBookTranslationKey.AUTHORS: AbsBrowsePaths.AUTHORS, + AbsBrowseItemsBookTranslationKey.NARRATORS: AbsBrowsePaths.NARRATORS, + AbsBrowseItemsBookTranslationKey.SERIES: AbsBrowsePaths.SERIES, + AbsBrowseItemsBookTranslationKey.COLLECTIONS: AbsBrowsePaths.COLLECTIONS, + AbsBrowseItemsBookTranslationKey.AUDIOBOOKS: AbsBrowsePaths.AUDIOBOOKS, } ABS_SHELF_ID_ICONS: dict[str, str] = { @@ -73,3 +73,18 @@ ABS_SHELF_ID_ICONS: dict[str, str] = { AbsShelfId.NEWEST_EPISODES: "mdi-plus-box-multiple-outline", AbsShelfId.DISCOVER: "mdi-magnify", } + +# for some keys there already is a good MA variant +# note: recommendation keys are in a subdict +ABS_SHELF_ID_TRANSLATION_KEY: dict[str, str] = { + AbsShelfId.LISTEN_AGAIN: "listen_again", + AbsShelfId.CONTINUE_LISTENING: "in_progress_items", + AbsShelfId.CONTINUE_SERIES: "in_progress_series", + AbsShelfId.RECOMMENDED: "recommended", + AbsShelfId.RECENTLY_ADDED: "recently_added", + AbsShelfId.EPISODES_RECENTLY_ADDED: "episodes_recently_added", + AbsShelfId.RECENT_SERIES: "recent_series", + AbsShelfId.NEWEST_AUTHORS: "newest_authors", + AbsShelfId.NEWEST_EPISODES: "newest_episodes", + AbsShelfId.DISCOVER: "discover", +} diff --git a/music_assistant/providers/itunes_podcasts/__init__.py b/music_assistant/providers/itunes_podcasts/__init__.py index 1352b0d4..fab24f7a 100644 --- a/music_assistant/providers/itunes_podcasts/__init__.py +++ b/music_assistant/providers/itunes_podcasts/__init__.py @@ -262,9 +262,9 @@ class ITunesPodcastsProvider(MusicProvider): return [ RecommendationFolder( item_id="itunes-top-podcasts", - name="Trending podcasts", + name="", icon="mdi-trending-up", - # translation_key=shelf.id_, + translation_key="trending_podcasts", items=UniqueList(podcast_list), provider=self.instance_id, ) -- 2.34.1