fix migration of url provider
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 16 Apr 2024 07:53:28 +0000 (09:53 +0200)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Tue, 16 Apr 2024 07:53:28 +0000 (09:53 +0200)
music_assistant/constants.py
music_assistant/server/controllers/music.py
music_assistant/server/providers/builtin/__init__.py
music_assistant/server/providers/filesystem_local/__init__.py

index 6ba1e210720440b3c42795a9b23d10c1a6aabf5b..52a6272e267dfcdd3b9ddb7cf4e435d9e8d59261 100644 (file)
@@ -5,7 +5,7 @@ from typing import Final
 
 API_SCHEMA_VERSION: Final[int] = 24
 MIN_SCHEMA_VERSION: Final[int] = 24
-DB_SCHEMA_VERSION: Final[int] = 30
+DB_SCHEMA_VERSION: Final[int] = 29
 
 MASS_LOGGER_NAME: Final[str] = "music_assistant"
 
index 48f12474da5855c2f71e41f0d37ef3958cce3269..02d3da99b772f481353b22bf4f387ef611b86778 100644 (file)
@@ -27,12 +27,7 @@ from music_assistant.common.models.errors import (
     MusicAssistantError,
     ProviderUnavailableError,
 )
-from music_assistant.common.models.media_items import (
-    BrowseFolder,
-    MediaItemType,
-    ProviderMapping,
-    SearchResults,
-)
+from music_assistant.common.models.media_items import BrowseFolder, MediaItemType, SearchResults
 from music_assistant.common.models.provider import SyncTask
 from music_assistant.common.models.streamdetails import LoudnessMeasurement
 from music_assistant.constants import (
@@ -750,31 +745,8 @@ class MusicController(CoreController):
             db_path_backup = db_path + ".backup"
             await asyncio.to_thread(shutil.copyfile, db_path, db_path_backup)
 
-            # handle db migration to 30: uri provider --> builtin provider
-            if prev_version < 30:
-                await self.mass.cache.clear("url")
-                for ctrl in (
-                    self.mass.music.radio,
-                    self.mass.music.tracks,
-                    self.mass.music.artists,
-                ):
-                    prov_items = await ctrl.get_library_items_by_prov_id("url")
-                    for item in prov_items:
-                        try:
-                            await ctrl.add_provider_mapping(
-                                item.item_id,
-                                ProviderMapping(
-                                    item_id=item.item_id,
-                                    provider_domain="builtin",
-                                    provider_instance="builtin",  # yeah, we're cheating here
-                                ),
-                            )
-                            await ctrl.remove_provider_mappings(item.item_id, "url")
-                        except Exception as err:
-                            self.logger.exception(err)
-
             # handle db migration from previous schema to this one
-            if prev_version in (27, 28, 29):
+            if prev_version in (27, 28):
                 self.logger.info(
                     "Performing database migration from %s to %s",
                     prev_version,
index 320c22bbc245ae044c0e038fda772c96cbe4f0c8..217a49a9684c6e60a57b63a0885668cee12a6237 100644 (file)
@@ -131,11 +131,43 @@ async def get_config_entries(
 class BuiltinProvider(MusicProvider):
     """Built-in/generic provider to handle (manually added) media from files and (remote) urls."""
 
-    def __init__(
-        self, mass: MusicAssistant, manifest: ProviderManifest, config: ProviderConfig
-    ) -> None:
-        """Initialize MusicProvider."""
-        super().__init__(mass, manifest, config)
+    async def loaded_in_mass(self) -> None:
+        """Call after the provider has been loaded."""
+        # TEMP: Migrate URL provider entries to builtin
+        # TODO: Remove this once 2.0 is released!
+        cache_key = f"{self.instance_id}.url_migration_done"
+        if await self.mass.cache.get(cache_key):
+            return
+        self.logger.info("Starting migration...")
+        url_instance_id: str | None = None
+        for ctrl in (
+            self.mass.music.radio,
+            self.mass.music.tracks,
+            self.mass.music.artists,
+        ):
+            prov_items = await ctrl.get_library_items_by_prov_id("url")
+            for item in prov_items:
+                try:
+                    existing_mapping = next(
+                        x for x in item.provider_mappings if x.provider_domain == "url"
+                    )
+                    # add new prov mapping for the builtin provider
+                    new_mapping = ProviderMapping.from_dict(existing_mapping.to_dict())
+                    new_mapping.provider_instance = self.instance_id
+                    new_mapping.provider_domain = self.domain
+                    new_mapping.available = True
+                    await ctrl.add_provider_mapping(item.item_id, new_mapping)
+                    await self.library_add(item)
+                    # lookup instance id of the url provider if we dont have it yet
+                    url_instance_id = existing_mapping.provider_instance
+                    # remove the old provider mapping for url provider
+                    await ctrl.remove_provider_mappings(item.item_id, url_instance_id)
+                    self.logger.info("Migrated item %s", item.name)
+                except Exception as err:
+                    self.logger.exception(err)
+        if url_instance_id:
+            await self.mass.cache.clear(url_instance_id)
+        await self.mass.cache.set(cache_key, True, expiration=365 * 86400)
 
     @property
     def is_streaming_provider(self) -> bool:
index c00eaf9a2ac6c2afea512b6e1f833986d656b134..32e5fafd4f82574bcaf5887154facaecf8ae968a 100644 (file)
@@ -212,7 +212,7 @@ class LocalFileSystemProvider(FileSystemProviderBase):
         # so the filesystem is not longer polluted/abused for this.
         # this code hunts these playlists, migrates them to the universal provider
         # and cleans up the files.
-        cache_key = f"{self.instance_id}.playlist_migrattion_done"
+        cache_key = f"{self.instance_id}.playlist_migration_done"
         if await self.mass.cache.get(cache_key):
             return
         self.logger.info("Starting playlist migration...")