Optimize watchlist card CSS, backfill missing album covers

Watchlist cards: removed spring-bounce transitions, staggered
animations, and multi-layer hover shadows. Added CSS containment
and will-change for smoother scrolling.

Recent releases: backfill missing album cover art on page load
via metadata source lookup. Persists found covers to database.
pull/253/head
Broque Thomas 2 months ago
parent f725b66afe
commit 6c3b9ddfc2

@ -7235,6 +7235,21 @@ class MusicDatabase:
logger.error(f"Error getting discovery recent albums: {e}")
return []
def update_discovery_recent_album_cover(self, album_id: str, cover_url: str) -> bool:
"""Backfill a missing cover URL on a recent album entry."""
try:
with self._get_connection() as conn:
cursor = conn.cursor()
cursor.execute("""
UPDATE discovery_recent_albums SET album_cover_url = ?
WHERE album_spotify_id = ? OR album_itunes_id = ? OR album_deezer_id = ?
""", (cover_url, album_id, album_id, album_id))
conn.commit()
return cursor.rowcount > 0
except Exception as e:
logger.debug(f"Error updating recent album cover: {e}")
return False
def clear_discovery_recent_albums(self, profile_id: int = 1) -> bool:
"""Clear cached recent albums for a profile"""
try:

@ -35785,6 +35785,40 @@ def get_discover_recent_releases():
# Get cached recent albums filtered by source (max 20)
albums = database.get_discovery_recent_albums(limit=20, source=active_source, profile_id=get_current_profile_id())
# Backfill missing cover art from metadata source
for album in albums:
if not album.get('album_cover_url'):
cover = None
album_id = album.get('album_deezer_id') or album.get('album_itunes_id') or album.get('album_spotify_id')
try:
# Try direct ID lookup first
if album_id:
fallback = _get_metadata_fallback_client()
if fallback:
album_data = fallback.get_album(str(album_id))
if album_data:
imgs = album_data.get('images', [])
cover = album_data.get('image_url') or (imgs[0].get('url') if imgs else None)
# Fallback: search by name
if not cover and album.get('album_name') and album.get('artist_name'):
fallback = _get_metadata_fallback_client()
if fallback:
results = fallback.search_albums(f"{album['artist_name']} {album['album_name']}", limit=1)
if results and hasattr(results[0], 'image_url') and results[0].image_url:
cover = results[0].image_url
album_id = str(results[0].id)
if cover:
album['album_cover_url'] = cover
if album_id:
try:
database.update_discovery_recent_album_cover(album_id, cover)
except Exception:
pass
except Exception:
pass
return jsonify({"success": True, "albums": albums, "source": active_source})
except Exception as e:

@ -12926,53 +12926,22 @@ body.helper-mode-active #dashboard-activity-feed:hover {
cursor: pointer;
background: rgba(18, 18, 18, 1);
border: 1px solid rgba(255, 255, 255, 0.06);
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1),
border-color 0.3s ease,
box-shadow 0.3s ease;
transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
contain: layout style paint;
will-change: transform;
}
.watchlist-artist-card:hover {
transform: translateY(-6px);
border-color: rgba(var(--accent-rgb), 0.3);
box-shadow:
0 16px 40px rgba(0, 0, 0, 0.5),
0 0 30px rgba(var(--accent-rgb), 0.12),
0 0 60px rgba(var(--accent-rgb), 0.05);
transform: translateY(-4px);
border-color: rgba(var(--accent-rgb), 0.25);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
}
.watchlist-artist-card:active {
transform: translateY(-2px);
}
/* Card entrance animation */
@keyframes watchlistCardIn {
from {
opacity: 0;
transform: translateY(16px) scale(0.97);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.watchlist-artist-card {
animation: watchlistCardIn 0.35s ease-out backwards;
}
.watchlist-artist-card:nth-child(1) { animation-delay: 0.02s; }
.watchlist-artist-card:nth-child(2) { animation-delay: 0.04s; }
.watchlist-artist-card:nth-child(3) { animation-delay: 0.06s; }
.watchlist-artist-card:nth-child(4) { animation-delay: 0.08s; }
.watchlist-artist-card:nth-child(5) { animation-delay: 0.10s; }
.watchlist-artist-card:nth-child(6) { animation-delay: 0.12s; }
.watchlist-artist-card:nth-child(7) { animation-delay: 0.14s; }
.watchlist-artist-card:nth-child(8) { animation-delay: 0.16s; }
.watchlist-artist-card:nth-child(9) { animation-delay: 0.18s; }
.watchlist-artist-card:nth-child(10) { animation-delay: 0.20s; }
.watchlist-artist-card:nth-child(n+11) { animation-delay: 0.22s; }
/* Image container with gradient fade */
.watchlist-card-image {
position: relative;
@ -13001,8 +12970,7 @@ body.helper-mode-active #dashboard-activity-feed:hover {
height: 100%;
object-fit: cover;
display: block;
transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94),
filter 0.4s ease;
transition: transform 0.3s ease;
}
.watchlist-artist-card:hover .watchlist-card-image img {

Loading…
Cancel
Save