mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
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.
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
# 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**! 🎉
|
||||
Reference in New Issue
Block a user