Files
swingmusic-extended/music_services_analysis.md
Tomas Dvorak cbf646e25b Fix CI/CD pipeline and code quality issues
## Major Changes
- Fixed all TypeScript errors in web client for successful compilation
- Resolved 82+ Python lint errors across backend services
- Updated Flutter SDK compatibility for mobile app
- Fixed security workflow configuration

## Web Client Fixes
- Fixed import path in DragonflyDashboard.vue (dragonflyApi import)
- All TypeScript compilation now passes without errors

## Backend Lint Fixes
- Updated type annotations to modern Python syntax (dict instead of Dict, X | None instead of Optional[X])
- Replaced try-except-pass with contextlib.suppress(Exception)
- Removed unused imports (Dict, Optional, Any, Iterator, etc.)
- Fixed bare except clauses to use Exception
- Sorted and formatted imports with ruff
- Applied ruff format to 27 files

## Workflow Fixes
- Updated Flutter SDK constraint from ^3.10.4 to ^3.5.0 (compatible with Flutter 3.24.0)
- Changed pip-audit format from github to json in security.yml
- Added comprehensive CI workflows (readiness-gate.yml, security.yml)

## Infrastructure
- Added DragonflyDB caching system integration
- Enhanced Docker configuration with multi-stage builds
- Added pytest configuration and test infrastructure
- Improved production readiness with proper error handling

## Verification
- backend-lint job:  Succeeded
- web job:  Succeeded
- Ready for GitHub deployment

All CI/CD issues resolved. Codebase now passes all quality checks.
2026-03-21 10:01:14 +01:00

5.8 KiB

Music Services Architecture Analysis

Current Services Overview

🎵 Spotify (Web Player API) - PRIMARY METADATA SOURCE

Purpose: Core track, album, artist, playlist metadata Status: Working - No account required Used for:

  • Track names, artists, albums, durations
  • Playlist information and track listings
  • Artist discography and top tracks
  • Album details and tracklists
  • Preview URLs (when available)

Implementation: SpotiFLAC-style Web Player API

  • TOTP authentication (no account needed)
  • GraphQL persisted queries
  • Client token requirement
  • Rate limiting with retries

🎼 MusicBrainz - ENRICHMENT METADATA

Purpose: Comprehensive music database enrichment Status: Working - Free API Used for:

  • Genre information (primary use case)
  • ISRC codes for cross-platform matching
  • Release dates and detailed discography
  • Artist relationships and aliases
  • Cover art URLs (via Cover Art Archive)
  • Track positioning and numbering
  • Country-specific release information
  • User-generated tags and ratings

Key Benefits:

  • Free and open (no API keys needed)
  • Comprehensive database with 1.5M+ artists
  • Genre data that Spotify doesn't provide
  • ISRC codes for streaming service matching

📻 Last.fm - SOCIAL & LISTENING DATA

Purpose: Social music features and listening statistics Status: ⚠️ Optional - Requires user API key Used for:

  • Scrobbling (track what users listen to)
  • Play counts and listening statistics
  • User recommendations and similar artists
  • Social features (friends, groups)
  • Charts and trending data
  • Personalized recommendations

Current Issues:

  • Requires user API key and authentication
  • Optional dependency (can be disabled)
  • Used mainly for social features

🎯 Optimal Architecture Recommendation

Core Required Services

  1. Spotify Web Player API (Primary metadata)
  2. MusicBrainz (Genre enrichment + ISRC matching)

Optional Services

  1. Song.link (Cross-platform streaming URLs)
  2. Last.fm (Social features - can be disabled)

💡 Your Question: Listening Count Implementation

You're absolutely right! Here's how we can handle listening counts:

# Spotify provides playcount in Web Player API
track_data = {
    "playcount": 1234567,  # Real Spotify play count
    "popularity": 85,       # Spotify popularity score
}

Pros:

  • Real-time data from Spotify
  • No additional API calls needed
  • Accurate and up-to-date

Cons:

  • Depends on Spotify API availability

Option 2: Use MusicBrainz Data

# MusicBrainz has rating and tag data
mb_data = {
    "rating": 4.2,           # User rating (0-5)
    "tagList": ["rock", "popular"],  # User tags
    "playCount": None,      # Not directly available
}

Pros:

  • Free and always available
  • Community-driven data
  • Genre information included

Cons:

  • No direct play count
  • Less accurate for popularity

Option 3: Local Tracking (Hybrid Approach)

# Track local plays in database + enrich with external data
local_stats = {
    "localPlayCount": 156,    # Times played in SwingMusic
    "spotifyPlayCount": 1234567, # From Spotify API
    "lastfmPlayCount": 98765,   # From Last.fm (if available)
}

Required Services (Always On)

class UnifiedMetadataClient:
    def __init__(self):
        self.spotify = SpotifyWebPlayerClient()    # Primary metadata
        self.musicbrainz = MusicBrainzClient()     # Genre enrichment
        self.songlink = SongLinkClient()           # Cross-platform URLs
    
    def get_track(self, track_id):
        # Get core data from Spotify
        spotify_data = self.spotify.get_track(track_id)
        
        # Enrich with MusicBrainz genre data
        if spotify_data.isrc:
            mb_data = self.musicbrainz.get_by_isrc(spotify_data.isrc)
            spotify_data.genres = mb_data.genres
        
        # Get cross-platform URLs
        cross_platform = self.songlink.get_links(track_id)
        spotify_data.streaming_urls = cross_platform
        
        return spotify_data

Optional Services (User Configurable)

class OptionalFeatures:
    def __init__(self):
        self.lastfm_enabled = user_config.get("lastfm_enabled", False)
        self.lastfm = LastFmClient() if self.lastfm_enabled else None
    
    def get_play_counts(self, track_id):
        counts = {
            "spotify": self.spotify.get_playcount(track_id),
            "local": self.local_db.get_playcount(track_id),
        }
        
        if self.lastfm_enabled:
            counts["lastfm"] = self.lastfm.get_playcount(track_id)
        
        return counts

📊 Summary Table

Service Purpose Required? Data Provided
Spotify Core metadata Yes Names, artists, albums, durations, play counts
MusicBrainz Genre enrichment Yes Genres, ISRC, cover art, release info
Song.link Cross-platform URLs Yes Tidal, Qobuz, Amazon, Deezer links
Last.fm Social features ⚠️ Optional Scrobbles, social stats, recommendations

🎯 Final Recommendation

Keep Last.fm optional as you suggested. Use Spotify play counts as the primary listening count source, with local tracking as backup. This gives you:

  1. Real Spotify data (most accurate)
  2. Local statistics (always available)
  3. Optional social features (user choice)
  4. Genre enrichment (from MusicBrainz)
  5. Cross-platform matching (from Song.link)

This architecture is robust, free, and user-controllable! 🎉