From: Marcel van der Veldt Date: Mon, 10 Mar 2025 13:19:37 +0000 (+0100) Subject: Ignore playlists which are stored with album tracks (#2017) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=f5536477c1146a81e2c685b6396c99d3b4d79309;p=music-assistant-server.git Ignore playlists which are stored with album tracks (#2017) --- diff --git a/music_assistant/providers/filesystem_local/__init__.py b/music_assistant/providers/filesystem_local/__init__.py index e96c39f5..d4c8a8c1 100644 --- a/music_assistant/providers/filesystem_local/__init__.py +++ b/music_assistant/providers/filesystem_local/__init__.py @@ -75,6 +75,7 @@ from .constants import ( AUDIOBOOK_EXTENSIONS, CONF_ENTRY_CONTENT_TYPE, CONF_ENTRY_CONTENT_TYPE_READ_ONLY, + CONF_ENTRY_IGNORE_ALBUM_PLAYLISTS, CONF_ENTRY_MISSING_ALBUM_ARTIST, CONF_ENTRY_PATH, IMAGE_EXTENSIONS, @@ -136,8 +137,14 @@ async def get_config_entries( CONF_ENTRY_CONTENT_TYPE, CONF_ENTRY_PATH, CONF_ENTRY_MISSING_ALBUM_ARTIST, + CONF_ENTRY_IGNORE_ALBUM_PLAYLISTS, ) - return (CONF_ENTRY_PATH, CONF_ENTRY_CONTENT_TYPE_READ_ONLY, CONF_ENTRY_MISSING_ALBUM_ARTIST) + return ( + CONF_ENTRY_PATH, + CONF_ENTRY_CONTENT_TYPE_READ_ONLY, + CONF_ENTRY_MISSING_ALBUM_ARTIST, + CONF_ENTRY_IGNORE_ALBUM_PLAYLISTS, + ) class LocalFileSystemProvider(MusicProvider): @@ -354,12 +361,9 @@ class LocalFileSystemProvider(MusicProvider): self.sync_running = True try: for item in listdir(self.base_path): - cur_filenames.add(item.relative_path) - # continue if the item did not change (checksum still the same) prev_checksum = file_checksums.get(item.relative_path) - if item.checksum == prev_checksum: - continue - self._process_item(item, prev_checksum) + if self._process_item(item, prev_checksum): + cur_filenames.add(item.relative_path) finally: self.sync_running = False @@ -378,10 +382,27 @@ class LocalFileSystemProvider(MusicProvider): # process orphaned albums and artists await self._process_orphaned_albums_and_artists() - def _process_item(self, item: FileSystemItem, prev_checksum: str | None) -> None: + def _process_item(self, item: FileSystemItem, prev_checksum: str | None) -> bool: """Process a single item. NOT async friendly.""" try: self.logger.debug("Processing: %s", item.relative_path) + + # ignore playlists that are in album directories + # we need to run this check early because the setting may have changed + if ( + item.ext in PLAYLIST_EXTENSIONS + and self.media_content_type == "music" + and self.config.get_value(CONF_ENTRY_IGNORE_ALBUM_PLAYLISTS.key) + ): + # we assume this in a bit of a dumb way by just checking if the playlist + # is more than 1 level deep in the directory structure + if len(item.relative_path.split("/")) > 2: + return False + + # return early if the item did not change (checksum still the same) + if item.checksum == prev_checksum: + return True + if item.ext in TRACK_EXTENSIONS and self.media_content_type == "music": # handle track item tags = parse_tags(item.absolute_path, item.file_size) @@ -396,7 +417,7 @@ class LocalFileSystemProvider(MusicProvider): ) asyncio.run_coroutine_threadsafe(process_track(), self.mass.loop).result() - return + return True if item.ext in AUDIOBOOK_EXTENSIONS and self.media_content_type == "audiobooks": # handle audiobook item @@ -415,7 +436,7 @@ class LocalFileSystemProvider(MusicProvider): ) asyncio.run_coroutine_threadsafe(process_audiobook(), self.mass.loop).result() - return + return True if item.ext in PODCAST_EPISODE_EXTENSIONS and self.media_content_type == "podcasts": # handle podcast(episode) item @@ -432,9 +453,10 @@ class LocalFileSystemProvider(MusicProvider): ) asyncio.run_coroutine_threadsafe(process_episode(), self.mass.loop).result() - return + return True if item.ext in PLAYLIST_EXTENSIONS and self.media_content_type == "music": + # handle playlist item async def process_playlist() -> None: playlist = await self.get_playlist(item.relative_path) @@ -446,7 +468,7 @@ class LocalFileSystemProvider(MusicProvider): ) asyncio.run_coroutine_threadsafe(process_playlist(), self.mass.loop).result() - return + return True except Exception as err: # we don't want the whole sync to crash on one file so we catch all exceptions here @@ -456,6 +478,7 @@ class LocalFileSystemProvider(MusicProvider): str(err), exc_info=err if self.logger.isEnabledFor(logging.DEBUG) else None, ) + return False async def _process_orphaned_albums_and_artists(self) -> None: """Process deletion of orphaned albums and artists.""" diff --git a/music_assistant/providers/filesystem_local/constants.py b/music_assistant/providers/filesystem_local/constants.py index cb536700..9e79427d 100644 --- a/music_assistant/providers/filesystem_local/constants.py +++ b/music_assistant/providers/filesystem_local/constants.py @@ -53,6 +53,18 @@ CONF_ENTRY_CONTENT_TYPE_READ_ONLY = ConfigEntry.from_dict( } ) +CONF_ENTRY_IGNORE_ALBUM_PLAYLISTS = ConfigEntry( + key="ignore_album_playlists", + type=ConfigEntryType.BOOLEAN, + label="Ignore playlists with album tracks within album folders", + description="A digital album often comes with a playlist file (.m3u) " + "that contains the tracks of the album. Adding all these playlists to the library, " + "is not very practical so it's better to just ignore them.\n\n" + "If this option is enabled, any playlists will be ignored which are more than " + "1 level deep in the folder structure. E.g. /music/artistname/albumname/playlist.m3u", + default_value=True, + required=False, +) TRACK_EXTENSIONS = { "aac", diff --git a/music_assistant/providers/filesystem_smb/__init__.py b/music_assistant/providers/filesystem_smb/__init__.py index 3d762e39..606582c0 100644 --- a/music_assistant/providers/filesystem_smb/__init__.py +++ b/music_assistant/providers/filesystem_smb/__init__.py @@ -17,6 +17,7 @@ from music_assistant.providers.filesystem_local import LocalFileSystemProvider, from music_assistant.providers.filesystem_local.constants import ( CONF_ENTRY_CONTENT_TYPE, CONF_ENTRY_CONTENT_TYPE_READ_ONLY, + CONF_ENTRY_IGNORE_ALBUM_PLAYLISTS, CONF_ENTRY_MISSING_ALBUM_ARTIST, ) @@ -121,6 +122,7 @@ async def get_config_entries( "want to pass to the mount command if needed for your particular setup.", ), CONF_ENTRY_MISSING_ALBUM_ARTIST, + CONF_ENTRY_IGNORE_ALBUM_PLAYLISTS, ) if instance_id is None or values is None: