620 lines
24 KiB
Python
620 lines
24 KiB
Python
import logging
|
|
|
|
import msgspec
|
|
|
|
from api.v1.schemas.settings import (
|
|
LidarrConnectionSettings,
|
|
JellyfinConnectionSettings,
|
|
ListenBrainzConnectionSettings,
|
|
NavidromeConnectionSettings,
|
|
YouTubeConnectionSettings,
|
|
LastFmConnectionSettings,
|
|
LidarrVerifyResponse,
|
|
LidarrMetadataProfilePreferences,
|
|
UserPreferences,
|
|
LidarrProfileSummary,
|
|
LidarrRootFolderSummary,
|
|
NAVIDROME_PASSWORD_MASK,
|
|
LASTFM_SECRET_MASK,
|
|
)
|
|
from core.config import Settings, get_settings
|
|
from core.exceptions import ExternalServiceError
|
|
from infrastructure.cache.cache_keys import (
|
|
ARTIST_INFO_PREFIX,
|
|
ALBUM_INFO_PREFIX,
|
|
JELLYFIN_PREFIX,
|
|
LOCAL_FILES_PREFIX,
|
|
SOURCE_RESOLUTION_PREFIX,
|
|
musicbrainz_prefixes,
|
|
listenbrainz_prefixes,
|
|
lastfm_prefixes,
|
|
home_prefixes,
|
|
)
|
|
from infrastructure.cache.memory_cache import InMemoryCache, CacheInterface
|
|
from infrastructure.http.client import get_http_client
|
|
from repositories.jellyfin_models import JellyfinUser
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class JellyfinVerifyResult(msgspec.Struct):
|
|
success: bool
|
|
message: str
|
|
users: list[JellyfinUser] | None = None
|
|
|
|
|
|
class ListenBrainzVerifyResult(msgspec.Struct):
|
|
valid: bool
|
|
message: str
|
|
|
|
|
|
class NavidromeVerifyResult(msgspec.Struct):
|
|
valid: bool
|
|
message: str
|
|
|
|
|
|
class YouTubeVerifyResult(msgspec.Struct):
|
|
valid: bool
|
|
message: str
|
|
|
|
|
|
class LastFmVerifyResult(msgspec.Struct):
|
|
valid: bool
|
|
message: str
|
|
|
|
|
|
class SettingsService:
|
|
def __init__(self, preferences_service, cache: CacheInterface):
|
|
self._preferences_service = preferences_service
|
|
self._cache = cache
|
|
|
|
async def verify_lidarr(self, settings: LidarrConnectionSettings) -> LidarrVerifyResponse:
|
|
try:
|
|
from infrastructure.validators import validate_service_url
|
|
validate_service_url(settings.lidarr_url, label="Lidarr URL")
|
|
|
|
from repositories.lidarr import LidarrRepository
|
|
from repositories.lidarr.base import reset_lidarr_circuit_breaker
|
|
|
|
reset_lidarr_circuit_breaker()
|
|
|
|
app_settings = get_settings()
|
|
http_client = get_http_client(app_settings)
|
|
|
|
temp_settings = Settings(
|
|
lidarr_url=settings.lidarr_url,
|
|
lidarr_api_key=settings.lidarr_api_key,
|
|
quality_profile_id=app_settings.quality_profile_id,
|
|
metadata_profile_id=app_settings.metadata_profile_id,
|
|
)
|
|
temp_cache = InMemoryCache(max_entries=100)
|
|
|
|
temp_repo = LidarrRepository(
|
|
settings=temp_settings,
|
|
http_client=http_client,
|
|
cache=temp_cache
|
|
)
|
|
|
|
status = await temp_repo.get_status()
|
|
|
|
if status.status != "ok":
|
|
return LidarrVerifyResponse(
|
|
success=False,
|
|
message=status.message or "Couldn't connect",
|
|
quality_profiles=[],
|
|
metadata_profiles=[],
|
|
root_folders=[]
|
|
)
|
|
|
|
quality_profiles_raw = await temp_repo.get_quality_profiles()
|
|
quality_profiles = [
|
|
LidarrProfileSummary(id=int(p.get("id", 0)), name=str(p.get("name", "Unknown")))
|
|
for p in quality_profiles_raw
|
|
]
|
|
|
|
metadata_profiles_raw = await temp_repo.get_metadata_profiles()
|
|
metadata_profiles = [
|
|
LidarrProfileSummary(id=int(p.get("id", 0)), name=str(p.get("name", "Unknown")))
|
|
for p in metadata_profiles_raw
|
|
]
|
|
|
|
root_folders_raw = await temp_repo.get_root_folders()
|
|
root_folders = [
|
|
LidarrRootFolderSummary(id=str(r.get("id", "")), path=str(r.get("path", "")))
|
|
for r in root_folders_raw
|
|
]
|
|
|
|
return LidarrVerifyResponse(
|
|
success=True,
|
|
message="Connected to Lidarr",
|
|
quality_profiles=quality_profiles,
|
|
metadata_profiles=metadata_profiles,
|
|
root_folders=root_folders
|
|
)
|
|
except ExternalServiceError as e:
|
|
logger.warning(f"Lidarr connection test failed: {e}")
|
|
return LidarrVerifyResponse(
|
|
success=False,
|
|
message="Couldn't reach Lidarr",
|
|
quality_profiles=[],
|
|
metadata_profiles=[],
|
|
root_folders=[]
|
|
)
|
|
except Exception as e:
|
|
logger.exception(f"Failed to verify Lidarr connection: {e}")
|
|
return LidarrVerifyResponse(
|
|
success=False,
|
|
message="Couldn't finish the connection test",
|
|
quality_profiles=[],
|
|
metadata_profiles=[],
|
|
root_folders=[]
|
|
)
|
|
|
|
async def verify_jellyfin(self, settings: JellyfinConnectionSettings) -> JellyfinVerifyResult:
|
|
try:
|
|
from infrastructure.validators import validate_service_url
|
|
validate_service_url(settings.jellyfin_url, label="Jellyfin URL")
|
|
|
|
from repositories.jellyfin_repository import JellyfinRepository
|
|
|
|
JellyfinRepository.reset_circuit_breaker()
|
|
|
|
app_settings = get_settings()
|
|
http_client = get_http_client(app_settings)
|
|
temp_cache = InMemoryCache(max_entries=100)
|
|
|
|
temp_repo = JellyfinRepository(http_client=http_client, cache=temp_cache)
|
|
temp_repo.configure(
|
|
base_url=settings.jellyfin_url,
|
|
api_key=settings.api_key,
|
|
user_id=settings.user_id
|
|
)
|
|
|
|
success, message = await temp_repo.validate_connection()
|
|
|
|
users = []
|
|
if success:
|
|
jf_users = await temp_repo.fetch_users_direct()
|
|
users = [JellyfinUser(id=u.id, name=u.name) for u in jf_users]
|
|
|
|
return JellyfinVerifyResult(success=success, message=message, users=users)
|
|
except Exception as e:
|
|
logger.exception(f"Failed to verify Jellyfin connection: {e}")
|
|
return JellyfinVerifyResult(
|
|
success=False,
|
|
message="Couldn't finish the connection test"
|
|
)
|
|
|
|
async def verify_listenbrainz(self, settings: ListenBrainzConnectionSettings) -> ListenBrainzVerifyResult:
|
|
try:
|
|
from repositories.listenbrainz_repository import ListenBrainzRepository
|
|
|
|
ListenBrainzRepository.reset_circuit_breaker()
|
|
|
|
app_settings = get_settings()
|
|
http_client = get_http_client(app_settings)
|
|
temp_cache = InMemoryCache(max_entries=100)
|
|
|
|
temp_repo = ListenBrainzRepository(http_client=http_client, cache=temp_cache)
|
|
temp_repo.configure(
|
|
username=settings.username,
|
|
user_token=settings.user_token
|
|
)
|
|
|
|
if settings.user_token:
|
|
valid, message = await temp_repo.validate_token()
|
|
else:
|
|
valid, message = await temp_repo.validate_username(settings.username)
|
|
|
|
return ListenBrainzVerifyResult(valid=valid, message=message)
|
|
except Exception as e:
|
|
logger.exception(f"Failed to verify ListenBrainz connection: {e}")
|
|
return ListenBrainzVerifyResult(
|
|
valid=False,
|
|
message="Couldn't finish the connection test"
|
|
)
|
|
|
|
async def clear_caches_for_preference_change(self) -> int:
|
|
total = 0
|
|
total += await self._cache.clear_prefix(ARTIST_INFO_PREFIX)
|
|
total += await self._cache.clear_prefix(ALBUM_INFO_PREFIX)
|
|
for prefix in musicbrainz_prefixes():
|
|
total += await self._cache.clear_prefix(prefix)
|
|
logger.info(f"Cleared {total} cache entries for preference change")
|
|
return total
|
|
|
|
async def clear_home_cache(self) -> int:
|
|
total = 0
|
|
for prefix in home_prefixes():
|
|
total += await self._cache.clear_prefix(prefix)
|
|
total += await self._cache.clear_prefix(JELLYFIN_PREFIX)
|
|
for prefix in listenbrainz_prefixes():
|
|
total += await self._cache.clear_prefix(prefix)
|
|
for prefix in lastfm_prefixes():
|
|
total += await self._cache.clear_prefix(prefix)
|
|
logger.info(f"Cleared {total} home/discover/integration cache entries")
|
|
return total
|
|
|
|
async def clear_local_files_cache(self) -> int:
|
|
cleared = await self._cache.clear_prefix(LOCAL_FILES_PREFIX)
|
|
logger.info(f"Cleared {cleared} local files cache entries")
|
|
return cleared
|
|
|
|
async def clear_source_resolution_cache(self) -> int:
|
|
cleared = await self._cache.clear_prefix(SOURCE_RESOLUTION_PREFIX)
|
|
logger.info(f"Cleared {cleared} source-resolution cache entries")
|
|
return cleared
|
|
|
|
# Lifecycle methods — one per integration settings change
|
|
|
|
async def on_jellyfin_settings_changed(self) -> None:
|
|
"""Full cache/state reset when Jellyfin settings change."""
|
|
from repositories.jellyfin_repository import JellyfinRepository
|
|
from core.dependencies import (
|
|
get_jellyfin_repository, get_jellyfin_playback_service,
|
|
get_jellyfin_library_service, get_home_service,
|
|
get_home_charts_service, get_mbid_store,
|
|
)
|
|
JellyfinRepository.reset_circuit_breaker()
|
|
get_jellyfin_repository.cache_clear()
|
|
get_jellyfin_playback_service.cache_clear()
|
|
get_jellyfin_library_service.cache_clear()
|
|
get_home_service.cache_clear()
|
|
get_home_charts_service.cache_clear()
|
|
mbid_store = get_mbid_store()
|
|
await mbid_store.clear_jellyfin_mbid_index()
|
|
await self.clear_home_cache()
|
|
await self.clear_source_resolution_cache()
|
|
logger.info("Jellyfin settings change: all caches/singletons reset")
|
|
|
|
async def on_navidrome_settings_changed(self, enabled: bool = False) -> None:
|
|
"""Full cache/state reset when Navidrome settings change."""
|
|
from repositories.navidrome_repository import NavidromeRepository
|
|
from core.dependencies import (
|
|
get_navidrome_repository, get_navidrome_library_service,
|
|
get_navidrome_playback_service, get_home_service,
|
|
get_home_charts_service, get_mbid_store,
|
|
)
|
|
NavidromeRepository.reset_circuit_breaker()
|
|
get_navidrome_repository.cache_clear()
|
|
get_navidrome_library_service.cache_clear()
|
|
get_navidrome_playback_service.cache_clear()
|
|
get_home_service.cache_clear()
|
|
get_home_charts_service.cache_clear()
|
|
mbid_store = get_mbid_store()
|
|
await mbid_store.clear_navidrome_mbid_indexes()
|
|
new_repo = get_navidrome_repository()
|
|
await new_repo.clear_cache()
|
|
await self.clear_home_cache()
|
|
await self.clear_source_resolution_cache()
|
|
if enabled:
|
|
import asyncio
|
|
from core.tasks import warm_navidrome_mbid_cache
|
|
from core.task_registry import TaskRegistry
|
|
registry = TaskRegistry.get_instance()
|
|
if not registry.is_running("navidrome-mbid-warmup"):
|
|
_nav_task = asyncio.create_task(warm_navidrome_mbid_cache())
|
|
try:
|
|
registry.register("navidrome-mbid-warmup", _nav_task)
|
|
except RuntimeError:
|
|
pass
|
|
logger.info("Navidrome settings change: all caches/singletons reset")
|
|
|
|
async def on_lastfm_settings_changed(self) -> None:
|
|
"""Full cache/state reset when Last.fm settings change."""
|
|
from repositories.lastfm_repository import LastFmRepository
|
|
from core.dependencies import (
|
|
get_lastfm_repository, get_lastfm_auth_service,
|
|
clear_lastfm_dependent_caches,
|
|
)
|
|
LastFmRepository.reset_circuit_breaker()
|
|
get_lastfm_repository.cache_clear()
|
|
get_lastfm_auth_service.cache_clear()
|
|
clear_lastfm_dependent_caches()
|
|
await self.clear_home_cache()
|
|
logger.info("Last.fm settings change: all caches/singletons reset")
|
|
|
|
async def on_listenbrainz_settings_changed(self) -> None:
|
|
"""Full cache/state reset when ListenBrainz settings change."""
|
|
from repositories.listenbrainz_repository import ListenBrainzRepository
|
|
from core.dependencies import clear_listenbrainz_dependent_caches
|
|
ListenBrainzRepository.reset_circuit_breaker()
|
|
clear_listenbrainz_dependent_caches()
|
|
await self.clear_home_cache()
|
|
logger.info("ListenBrainz settings change: all caches/singletons reset")
|
|
|
|
async def on_youtube_settings_changed(self) -> None:
|
|
"""Reset YouTube singleton and clear home caches when settings change."""
|
|
from core.dependencies import get_youtube_repo
|
|
get_youtube_repo.cache_clear()
|
|
await self.clear_home_cache()
|
|
logger.info("YouTube settings change: singleton reset, home caches cleared")
|
|
|
|
async def on_coverart_settings_changed(self) -> None:
|
|
"""Reset coverart singleton when settings change."""
|
|
from core.dependencies import get_coverart_repository
|
|
get_coverart_repository.cache_clear()
|
|
logger.info("Coverart settings change: singleton reset")
|
|
|
|
async def on_local_files_settings_changed(self) -> None:
|
|
"""Full cache reset when local files settings change."""
|
|
await self.clear_local_files_cache()
|
|
await self.clear_source_resolution_cache()
|
|
logger.info("Local files settings change: caches reset")
|
|
|
|
async def on_lidarr_settings_changed(self) -> None:
|
|
"""Full cache reset when Lidarr settings change."""
|
|
from core.dependencies import get_library_db, get_home_service
|
|
from infrastructure.cache.cache_keys import LIDARR_PREFIX
|
|
|
|
await self.clear_home_cache()
|
|
await self._cache.clear_prefix(LIDARR_PREFIX)
|
|
|
|
library_db = get_library_db()
|
|
await library_db.clear()
|
|
|
|
try:
|
|
home_service = get_home_service()
|
|
home_service.clear_genre_disk_cache()
|
|
except Exception: # noqa: BLE001
|
|
logger.debug("Genre disk cache cleanup skipped (home service unavailable)")
|
|
|
|
logger.info("Lidarr settings change: home, lidarr, library and genre caches reset")
|
|
|
|
def _create_lidarr_repo(self) -> "LidarrRepository":
|
|
from repositories.lidarr import LidarrRepository
|
|
|
|
app_settings = get_settings()
|
|
if not app_settings.lidarr_url or not app_settings.lidarr_api_key:
|
|
raise ExternalServiceError("Lidarr is not configured")
|
|
|
|
http_client = get_http_client(app_settings)
|
|
temp_cache = InMemoryCache(max_entries=100)
|
|
return LidarrRepository(
|
|
settings=app_settings,
|
|
http_client=http_client,
|
|
cache=temp_cache,
|
|
)
|
|
|
|
@staticmethod
|
|
def _lidarr_profile_to_preferences(profile: dict) -> LidarrMetadataProfilePreferences:
|
|
primary = [
|
|
item["albumType"]["name"].lower()
|
|
for item in profile.get("primaryAlbumTypes", [])
|
|
if item.get("allowed")
|
|
]
|
|
secondary = [
|
|
item["albumType"]["name"].lower()
|
|
for item in profile.get("secondaryAlbumTypes", [])
|
|
if item.get("allowed")
|
|
]
|
|
statuses = [
|
|
item["releaseStatus"]["name"].lower()
|
|
for item in profile.get("releaseStatuses", [])
|
|
if item.get("allowed")
|
|
]
|
|
return LidarrMetadataProfilePreferences(
|
|
profile_id=profile["id"],
|
|
profile_name=profile.get("name", "Unknown"),
|
|
primary_types=primary,
|
|
secondary_types=secondary,
|
|
release_statuses=statuses,
|
|
)
|
|
|
|
@staticmethod
|
|
def _apply_preferences_to_profile(
|
|
profile: dict, preferences: UserPreferences
|
|
) -> dict:
|
|
for item in profile.get("primaryAlbumTypes", []):
|
|
name = item["albumType"]["name"].lower()
|
|
item["allowed"] = name in preferences.primary_types
|
|
for item in profile.get("secondaryAlbumTypes", []):
|
|
name = item["albumType"]["name"].lower()
|
|
item["allowed"] = name in preferences.secondary_types
|
|
for item in profile.get("releaseStatuses", []):
|
|
name = item["releaseStatus"]["name"].lower()
|
|
item["allowed"] = name in preferences.release_statuses
|
|
return profile
|
|
|
|
def _resolve_profile_id(self, profile_id: int | None) -> int:
|
|
if profile_id is not None:
|
|
return profile_id
|
|
connection = self._preferences_service.get_lidarr_connection()
|
|
return connection.metadata_profile_id
|
|
|
|
async def list_lidarr_metadata_profiles(
|
|
self,
|
|
) -> list[dict]:
|
|
repo = self._create_lidarr_repo()
|
|
try:
|
|
profiles = await repo.get_metadata_profiles()
|
|
except Exception as e: # noqa: BLE001
|
|
logger.error(f"Failed to list Lidarr metadata profiles: {e}")
|
|
raise ExternalServiceError(
|
|
f"Failed to list Lidarr metadata profiles: {e}"
|
|
)
|
|
return [{"id": p["id"], "name": p["name"]} for p in profiles]
|
|
|
|
async def get_lidarr_metadata_profile_preferences(
|
|
self,
|
|
profile_id: int | None = None,
|
|
) -> LidarrMetadataProfilePreferences:
|
|
resolved_id = self._resolve_profile_id(profile_id)
|
|
|
|
repo = self._create_lidarr_repo()
|
|
try:
|
|
profile = await repo.get_metadata_profile(resolved_id)
|
|
except Exception as e: # noqa: BLE001
|
|
logger.error(f"Failed to fetch Lidarr metadata profile {resolved_id}: {e}")
|
|
raise ExternalServiceError(
|
|
f"Failed to fetch Lidarr metadata profile: {e}"
|
|
)
|
|
|
|
return self._lidarr_profile_to_preferences(profile)
|
|
|
|
async def update_lidarr_metadata_profile(
|
|
self,
|
|
preferences: UserPreferences,
|
|
profile_id: int | None = None,
|
|
) -> LidarrMetadataProfilePreferences:
|
|
resolved_id = self._resolve_profile_id(profile_id)
|
|
|
|
repo = self._create_lidarr_repo()
|
|
try:
|
|
profile = await repo.get_metadata_profile(resolved_id)
|
|
except Exception as e: # noqa: BLE001
|
|
logger.error(f"Failed to fetch Lidarr metadata profile {resolved_id}: {e}")
|
|
raise ExternalServiceError(
|
|
f"Failed to fetch Lidarr metadata profile: {e}"
|
|
)
|
|
|
|
updated_profile = self._apply_preferences_to_profile(profile, preferences)
|
|
|
|
validations = [
|
|
(
|
|
"primaryAlbumTypes",
|
|
"primary album type",
|
|
"e.g. Album",
|
|
),
|
|
(
|
|
"secondaryAlbumTypes",
|
|
"secondary album type",
|
|
"e.g. Studio",
|
|
),
|
|
(
|
|
"releaseStatuses",
|
|
"release status",
|
|
"e.g. Official",
|
|
),
|
|
]
|
|
for key, label, example in validations:
|
|
if not any(item.get("allowed") for item in updated_profile.get(key, [])):
|
|
raise ExternalServiceError(
|
|
f"Lidarr requires at least one {label} to be enabled. "
|
|
f"Please enable at least one ({example}) before syncing."
|
|
)
|
|
|
|
try:
|
|
result = await repo.update_metadata_profile(resolved_id, updated_profile)
|
|
except Exception as e: # noqa: BLE001
|
|
logger.error(f"Failed to update Lidarr metadata profile {resolved_id}: {e}")
|
|
raise ExternalServiceError(
|
|
f"Failed to update Lidarr metadata profile: {e}"
|
|
)
|
|
|
|
logger.info(f"Updated Lidarr metadata profile '{result.get('name')}' (ID: {resolved_id})")
|
|
return self._lidarr_profile_to_preferences(result)
|
|
|
|
# Verify methods — Navidrome, YouTube, Last.fm
|
|
|
|
async def verify_navidrome(
|
|
self, settings: NavidromeConnectionSettings
|
|
) -> NavidromeVerifyResult:
|
|
try:
|
|
from infrastructure.validators import validate_service_url
|
|
validate_service_url(settings.navidrome_url, label="Navidrome URL")
|
|
|
|
from repositories.navidrome_repository import NavidromeRepository
|
|
|
|
NavidromeRepository.reset_circuit_breaker()
|
|
|
|
app_settings = get_settings()
|
|
http_client = get_http_client(app_settings)
|
|
temp_cache = InMemoryCache(max_entries=100)
|
|
|
|
temp_repo = NavidromeRepository(http_client=http_client, cache=temp_cache)
|
|
|
|
password = settings.password
|
|
if password == NAVIDROME_PASSWORD_MASK:
|
|
raw = self._preferences_service.get_navidrome_connection_raw()
|
|
password = raw.password
|
|
|
|
temp_repo.configure(
|
|
url=settings.navidrome_url,
|
|
username=settings.username,
|
|
password=password,
|
|
)
|
|
|
|
ok = await temp_repo.ping()
|
|
if ok:
|
|
return NavidromeVerifyResult(
|
|
valid=True, message="Connected to Navidrome successfully"
|
|
)
|
|
return NavidromeVerifyResult(
|
|
valid=False,
|
|
message="Navidrome didn't respond. Check the URL and credentials.",
|
|
)
|
|
except Exception as e:
|
|
logger.exception("Failed to verify Navidrome connection: %s", e)
|
|
return NavidromeVerifyResult(
|
|
valid=False,
|
|
message="Couldn't finish the connection test",
|
|
)
|
|
|
|
async def verify_youtube(
|
|
self, settings: YouTubeConnectionSettings
|
|
) -> YouTubeVerifyResult:
|
|
try:
|
|
from repositories.youtube import YouTubeRepository
|
|
|
|
app_settings = get_settings()
|
|
http_client = get_http_client(app_settings)
|
|
temp_repo = YouTubeRepository(
|
|
http_client=http_client,
|
|
api_key=settings.api_key.strip(),
|
|
daily_quota_limit=settings.daily_quota_limit,
|
|
)
|
|
valid, message = await temp_repo.verify_api_key(settings.api_key.strip())
|
|
return YouTubeVerifyResult(valid=valid, message=message)
|
|
except Exception as e:
|
|
logger.exception("Failed to verify YouTube connection: %s", e)
|
|
return YouTubeVerifyResult(
|
|
valid=False,
|
|
message="Couldn't finish the connection test",
|
|
)
|
|
|
|
async def verify_lastfm(
|
|
self, settings: LastFmConnectionSettings
|
|
) -> LastFmVerifyResult:
|
|
try:
|
|
from repositories.lastfm_repository import LastFmRepository
|
|
|
|
app_settings = get_settings()
|
|
http_client = get_http_client(app_settings)
|
|
|
|
current = self._preferences_service.get_lastfm_connection()
|
|
shared_secret = settings.shared_secret
|
|
if shared_secret.startswith(LASTFM_SECRET_MASK):
|
|
shared_secret = current.shared_secret
|
|
|
|
session_key = settings.session_key
|
|
if session_key.startswith(LASTFM_SECRET_MASK):
|
|
session_key = current.session_key
|
|
|
|
temp_repo = LastFmRepository(
|
|
http_client=http_client,
|
|
cache=InMemoryCache(),
|
|
api_key=settings.api_key,
|
|
shared_secret=shared_secret,
|
|
session_key=session_key,
|
|
)
|
|
valid, message = await temp_repo.validate_api_key()
|
|
if not valid:
|
|
return LastFmVerifyResult(valid=False, message=message)
|
|
|
|
if session_key:
|
|
session_valid, session_message = await temp_repo.validate_session()
|
|
if not session_valid:
|
|
return LastFmVerifyResult(
|
|
valid=False,
|
|
message=f"The API key looks good, but the saved session isn't valid: {session_message}",
|
|
)
|
|
return LastFmVerifyResult(valid=True, message=session_message)
|
|
|
|
return LastFmVerifyResult(valid=valid, message=message)
|
|
except Exception as e:
|
|
logger.exception("Failed to verify Last.fm connection: %s", e)
|
|
return LastFmVerifyResult(
|
|
valid=False, message="Couldn't finish the Last.fm connection test"
|
|
)
|