Bandcamp: validate login on init when credentials are configured (#3215)
authorDavid Bishop <teancom@users.noreply.github.com>
Mon, 23 Feb 2026 07:12:34 +0000 (23:12 -0800)
committerGitHub <noreply@github.com>
Mon, 23 Feb 2026 07:12:34 +0000 (08:12 +0100)
Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
music_assistant/providers/bandcamp/__init__.py
tests/providers/bandcamp/test_provider.py

index 7bfb22a44d721eb492cbd6750988284711347c1f..e15a0d687c1fe76a1153bccf8e4b45941b83dfa1 100644 (file)
@@ -124,6 +124,19 @@ class BandcampProvider(MusicProvider):
         )
         self._converters = BandcampConverters(self.domain, self.instance_id)
 
+        # The provider can function without login (search-only),
+        # but if credentials were explicitly configured, validate them now.
+        # A bad login fails hard so the user can fix it immediately;
+        # transient errors (rate limits, network) are logged and the provider
+        # continues since the login may still be valid.
+        if identity:
+            try:
+                await self._client.get_collection_summary()
+            except BandcampMustBeLoggedInError as error:
+                raise LoginFailed("Bandcamp login is invalid or expired.") from error
+            except BandcampAPIError as error:
+                self.logger.warning("Could not validate Bandcamp login: %s", error)
+
     @property
     def is_streaming_provider(self) -> bool:
         """Return True if the provider is a streaming provider."""
index 5961d752015fa2d22aca9a5e8c0e3adef4cf21c9..f5e85ce4fa4b2721f59555071b5d8c44cdbd2ccf 100644 (file)
@@ -59,7 +59,7 @@ async def provider(mass_mock: Mock, manifest_mock: Mock, config_mock: Mock) -> B
 
     # Initialize the provider
     with patch("music_assistant.providers.bandcamp.BandcampAPIClient") as mock_client_class:
-        mock_client = Mock()
+        mock_client = AsyncMock()
         mock_client_class.return_value = mock_client
         await provider.handle_async_init()
 
@@ -77,7 +77,7 @@ async def test_provider_initialization(
 
     # Test that initialization sets the correct values
     with patch("music_assistant.providers.bandcamp.BandcampAPIClient") as mock_client_class:
-        mock_client = Mock()
+        mock_client = AsyncMock()
         mock_client_class.return_value = mock_client
 
         await provider.handle_async_init()
@@ -88,7 +88,7 @@ async def test_provider_initialization(
 async def test_handle_async_init_with_identity(provider: BandcampProvider) -> None:
     """Test successful async initialization with identity token."""
     with patch("music_assistant.providers.bandcamp.BandcampAPIClient") as mock_client_class:
-        mock_client = Mock()
+        mock_client = AsyncMock()
         mock_client_class.return_value = mock_client
 
         await provider.handle_async_init()
@@ -113,7 +113,7 @@ async def test_handle_async_init_without_identity(mass_mock: Mock, manifest_mock
     provider = BandcampProvider(mass_mock, manifest_mock, config)
 
     with patch("music_assistant.providers.bandcamp.BandcampAPIClient") as mock_client_class:
-        mock_client = Mock()
+        mock_client = AsyncMock()
         mock_client_class.return_value = mock_client
 
         await provider.handle_async_init()