mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
cbf646e25b
## 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.
195 lines
5.8 KiB
Markdown
195 lines
5.8 KiB
Markdown
# 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**
|
|
3. **Song.link** (Cross-platform streaming URLs)
|
|
4. **Last.fm** (Social features - can be disabled)
|
|
|
|
---
|
|
|
|
## 💡 **Your Question: Listening Count Implementation**
|
|
|
|
You're absolutely right! Here's how we can handle listening counts:
|
|
|
|
### **Option 1: Use Spotify Data (Recommended)**
|
|
```python
|
|
# 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**
|
|
```python
|
|
# 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)**
|
|
```python
|
|
# 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)
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 **Recommended Implementation**
|
|
|
|
### **Required Services (Always On)**
|
|
```python
|
|
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)**
|
|
```python
|
|
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**! 🎉
|