Fix Unknown Artist fallback during Spotify rate-limiting and update CI to use GHCR

- Add fallback chain in spotify_artist_context construction to use track.artists
  when explicit_artist_context has placeholder names like 'Unknown Artist'
- Add fallback in _extract_spotify_metadata to use original_search['artists']
  when album_artist resolution fails due to Spotify rate-limiting
- This fixes downloads being saved to 'Unknown Artist' folders when Spotify API
  is rate-limited but actual artist data is available from download sources
- Update GitHub Actions workflow to push Docker images only to GitHub Container
  Registry (ghcr.io) instead of Docker Hub
This commit is contained in:
GitHub Actions 2026-04-09 04:41:40 +00:00
parent 37d325ee10
commit 74bdb1c84b
2 changed files with 41 additions and 16 deletions

View file

@ -7,6 +7,10 @@ on:
description: 'Version tag (e.g. 1.6, 1.7)'
required: true
default: '2.2'
push:
branches:
- main
- master
jobs:
build-and-push:
@ -22,11 +26,12 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
@ -39,15 +44,5 @@ jobs:
build-args: |
COMMIT_SHA=${{ github.sha }}
tags: |
boulderbadgedad/soulsync:latest
boulderbadgedad/soulsync:${{ inputs.version_tag }}
- name: Announce release to Discord
if: success()
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_ANNOUNCEMENTS_WEBHOOK }}
run: |
if [ -z "$DISCORD_WEBHOOK" ]; then echo "No webhook configured, skipping"; exit 0; fi
curl -s -H "Content-Type: application/json" \
-d "{\"embeds\": [{\"title\": \"SoulSync v${{ inputs.version_tag }} Released\", \"description\": \"A new version of SoulSync is available! Pull the latest Docker image to update.\n\n\`\`\`\ndocker pull boulderbadgedad/soulsync:${{ inputs.version_tag }}\n\`\`\`\", \"color\": 5025616, \"footer\": {\"text\": \"SoulSync Auto-Release\"}, \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}]}" \
"$DISCORD_WEBHOOK"
ghcr.io/${{ github.repository_owner }}/soulsync:latest
ghcr.io/${{ github.repository_owner }}/soulsync:${{ inputs.version_tag || 'dev' }}

View file

@ -17733,6 +17733,21 @@ def _extract_spotify_metadata(context: dict, artist: dict, album_info: dict) ->
_raw_album_artist = _first_aa
_album_artists_for_collab = _sa_aa
# SPOTIFY RATE LIMIT FIX: When Spotify is rate-limited, explicit_artist_context and spotify_album
# may have placeholder/incomplete artist data. Use actual track artist data from original_search
# which comes from the download source (HiFi, Tidal, etc.) and contains real artist names.
if not _raw_album_artist or _raw_album_artist in ['Unknown Artist', 'Unknown', '']:
if 'artists' in original_search and isinstance(original_search['artists'], list) and len(original_search['artists']) > 0:
first_artist = original_search['artists'][0]
if isinstance(first_artist, dict) and first_artist.get('name'):
_raw_album_artist = first_artist['name']
if not _album_artists_for_collab:
_album_artists_for_collab = [first_artist]
elif isinstance(first_artist, str):
_raw_album_artist = first_artist
if not _album_artists_for_collab:
_album_artists_for_collab = [{'name': first_artist}]
collab_mode = config_manager.get('file_organization.collab_artist_mode', 'first')
if collab_mode == 'first' and _raw_album_artist:
original_search = context.get("original_search_result", {})
@ -27778,9 +27793,24 @@ def _attempt_download_with_candidates(task_id, candidates, track, batch_id=None)
if isinstance(explicit_artist, str):
explicit_artist = {'name': explicit_artist}
# Determine artist name with proper fallback chain:
# 1. explicit_artist.name (if not a placeholder like 'Unknown Artist')
# 2. track.artists[0] (actual track artist data from download source)
# 3. 'Unknown Artist' as last resort
explicit_artist_name = explicit_artist.get('name', '')
is_placeholder_name = explicit_artist_name in ['Unknown Artist', 'Unknown', '', 'Various Artists']
if is_placeholder_name and track.artists:
# Use actual track artist data instead of placeholder from rate-limited context
spotify_artist_name = track.artists[0]
elif explicit_artist_name:
spotify_artist_name = explicit_artist_name
else:
spotify_artist_name = track.artists[0] if track.artists else 'Unknown Artist'
spotify_artist_context = {
'id': explicit_artist.get('id', 'explicit_artist'),
'name': explicit_artist.get('name', track.artists[0] if track.artists else 'Unknown'),
'name': spotify_artist_name,
'genres': explicit_artist.get('genres', [])
}
# Handle both image_url formats (direct string or images array)