diff --git a/core/genius_worker.py b/core/genius_worker.py index 1ddf0494..73782a98 100644 --- a/core/genius_worker.py +++ b/core/genius_worker.py @@ -352,6 +352,7 @@ class GeniusWorker: genius_id = str(full_data.get('id', search_data.get('id', ''))) description = self.client.extract_description(full_data.get('description')) image_url = full_data.get('image_url') or search_data.get('image_url') + genius_url = full_data.get('url') or search_data.get('url') # Alternate names alt_names = full_data.get('alternate_names', []) @@ -364,9 +365,10 @@ class GeniusWorker: genius_last_attempted = CURRENT_TIMESTAMP, genius_description = ?, genius_alt_names = ?, + genius_url = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? - """, (genius_id, description, alt_names_json, artist_id)) + """, (genius_id, description, alt_names_json, genius_url, artist_id)) # Backfill thumb_url if image_url: diff --git a/database/music_database.py b/database/music_database.py index 5ec5b951..ef016777 100644 --- a/database/music_database.py +++ b/database/music_database.py @@ -1478,6 +1478,8 @@ class MusicDatabase: cursor.execute("ALTER TABLE artists ADD COLUMN genius_description TEXT") if 'genius_alt_names' not in artists_columns: cursor.execute("ALTER TABLE artists ADD COLUMN genius_alt_names TEXT") + if 'genius_url' not in artists_columns: + cursor.execute("ALTER TABLE artists ADD COLUMN genius_url TEXT") cursor.execute("CREATE INDEX IF NOT EXISTS idx_artists_lastfm_status ON artists (lastfm_match_status)") cursor.execute("CREATE INDEX IF NOT EXISTS idx_artists_genius_id ON artists (genius_id)") diff --git a/webui/static/script.js b/webui/static/script.js index ce9c9d14..32f499b0 100644 --- a/webui/static/script.js +++ b/webui/static/script.js @@ -33435,6 +33435,8 @@ function renderArtistMetaPanel(artist) { { key: 'deezer_id', label: 'Deezer', svc: 'deezer' }, { key: 'audiodb_id', label: 'AudioDB', svc: 'audiodb' }, { key: 'itunes_artist_id', label: 'iTunes', svc: 'itunes' }, + { key: 'lastfm_url', label: 'Last.fm', svc: 'lastfm' }, + { key: 'genius_url', label: 'Genius', svc: 'genius' }, ]; idSources.forEach(src => { if (artist[src.key]) { @@ -33853,6 +33855,7 @@ function renderExpandedAlbumHeader(album) { { key: 'deezer_id', label: 'Deezer', svc: 'deezer' }, { key: 'audiodb_id', label: 'AudioDB', svc: 'audiodb' }, { key: 'itunes_album_id', label: 'iTunes', svc: 'itunes' }, + { key: 'lastfm_url', label: 'Last.fm', svc: 'lastfm' }, ]; idFields.forEach(f => { if (album[f.key]) { @@ -34386,6 +34389,15 @@ function getServiceUrl(service, entityType, id) { album: `https://music.apple.com/album/${id}`, track: `https://music.apple.com/song/${id}`, }, + lastfm: { + artist: id, // lastfm_url is already a full URL + album: id, + track: id, + }, + genius: { + artist: id, // genius_url is already a full URL + track: id, // genius_url on tracks is already a full URL + }, }; return urls[service] && urls[service][entityType] || null; } diff --git a/webui/static/style.css b/webui/static/style.css index 0591a9f8..5c8bbaaf 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -30830,6 +30830,8 @@ a.enhanced-id-badge:visited { .enhanced-id-badge.mb { background: rgba(186, 72, 27, 0.15); color: #e8834a; border: 1px solid rgba(186, 72, 27, 0.25); } .enhanced-id-badge.deezer { background: rgba(160, 55, 200, 0.15); color: #c770e8; border: 1px solid rgba(160, 55, 200, 0.25); } .enhanced-id-badge.audiodb { background: rgba(50, 120, 220, 0.15); color: #5a9de6; border: 1px solid rgba(50, 120, 220, 0.25); } +.enhanced-id-badge.lastfm { background: rgba(185, 0, 0, 0.15); color: #d42f2f; border: 1px solid rgba(185, 0, 0, 0.25); } +.enhanced-id-badge.genius { background: rgba(255, 255, 100, 0.12); color: #e8d44d; border: 1px solid rgba(255, 255, 100, 0.2); } .enhanced-id-badge.server { background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.5); border: 1px solid rgba(255,255,255,0.12); } .enhanced-meta-edit-toggle {