mirror of https://github.com/Nezreka/SoulSync.git
parent
63c24c6c2d
commit
dd9aeb4d4d
@ -1,259 +0,0 @@
|
||||
# 🎯 SoulSync Matched Download System - Technical Deep Dive
|
||||
|
||||
## Overview
|
||||
|
||||
SoulSync's matched download system is the core mechanism that transforms messy, inconsistent Soulseek filenames into pristine, Spotify-accurate folder structures. This system is used universally across all download modalities in the application.
|
||||
|
||||
## Universal System Usage
|
||||
|
||||
**All download modals use the same matched download system:**
|
||||
|
||||
### 📋 **Sync Page**: "Download Missing Tracks" Modal
|
||||
- **Entry Point**: `DownloadMissingTracksModal` in `sync.py`
|
||||
- **Flow**: User selects tracks → SpotifyMatchingModal → `_handle_match_confirmed()` → `_start_download_with_artist()`
|
||||
- **Organization**: Uses `_organize_matched_download()` for file placement
|
||||
|
||||
### 🎨 **Artists Page**: "Download Missing Album Tracks" Modal
|
||||
- **Entry Point**: `DownloadMissingAlbumTracksModal` in `artists.py`
|
||||
- **Flow**: Same as Sync page - all paths lead to downloads.py
|
||||
- **Special Feature**: Can force album mode with `_force_album_mode = True`
|
||||
|
||||
### 📊 **Dashboard Page**: Automatic Wishlist Processing
|
||||
- **Entry Point**: `DownloadMissingWishlistTracksModal` in `dashboard.py`
|
||||
- **Flow**: Background processing every 60 minutes → same matched download system
|
||||
- **Automation**: Processes up to 25 wishlist tracks without user intervention
|
||||
|
||||
### 💿 **Downloads Page**: Manual "Matched Download" Button
|
||||
- **Entry Point**: Direct user click on matched download button
|
||||
- **Flow**: `SpotifyMatchingModal` → same system as all others
|
||||
|
||||
**Key Point**: All modals ultimately call the same core functions in `downloads.py`, ensuring consistent behavior and file organization across the entire application.
|
||||
|
||||
---
|
||||
|
||||
## Folder Structure Decision Matrix
|
||||
|
||||
### 🎵 **Album Track Structure**
|
||||
```
|
||||
Transfer/
|
||||
├── ARTIST_NAME/
|
||||
└── ARTIST_NAME - ALBUM_NAME/
|
||||
├── 01 - Track Title.flac
|
||||
├── 02 - Another Track.flac
|
||||
└── 03 - Final Track.flac
|
||||
```
|
||||
|
||||
### 🎤 **Single Track Structure**
|
||||
```
|
||||
Transfer/
|
||||
├── ARTIST_NAME/
|
||||
└── ARTIST_NAME - SINGLE_NAME/
|
||||
└── Single Name.flac
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The Algorithm: Album vs Single Decision
|
||||
|
||||
### **Priority 1: Forced Album Mode** (Always Album)
|
||||
```python
|
||||
if hasattr(download_item, '_force_album_mode') and download_item._force_album_mode:
|
||||
return {'is_album': True, ...}
|
||||
```
|
||||
- **When**: User explicitly selected album mode via "Download Missing Album Tracks"
|
||||
- **Result**: Album structure regardless of Spotify data
|
||||
|
||||
### **Priority 2: Album-Aware Search** (Existing Context)
|
||||
```python
|
||||
if download_item.album and download_item.album != "Unknown Album":
|
||||
# Search within that specific album context
|
||||
```
|
||||
- **When**: Download item has existing album information
|
||||
- **Process**: Searches Spotify for track within specific album
|
||||
|
||||
### **Priority 3: Spotify API Decision** (The Core Logic)
|
||||
```python
|
||||
# Get detailed track info from Spotify API
|
||||
detailed_track = self.spotify_client.get_track_details(best_match.id)
|
||||
|
||||
# THE CRITICAL DECISION:
|
||||
is_album = (
|
||||
# 1. Spotify classifies as 'album' (not 'single')
|
||||
album_type == 'album' and
|
||||
# 2. Album has multiple tracks (not just 1)
|
||||
total_tracks > 1 and
|
||||
# 3. Album name ≠ Track name (prevents self-titled singles)
|
||||
album_name != track_name and
|
||||
# 4. Album name ≠ Artist name (prevents artist name albums)
|
||||
album_name != artist_name
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Real-World Decision Examples
|
||||
|
||||
### **Case Study: "bad guy" by Billie Eilish**
|
||||
|
||||
**The Challenge**: Track exists as both single and album track
|
||||
- **Single Version**: `album_type: "single"`, `total_tracks: 1`
|
||||
- **Album Version**: `album_type: "album"`, `total_tracks: 14`, album: "WHEN WE ALL FALL ASLEEP, WHERE DO WE GO?"
|
||||
|
||||
**SoulSync's Decision Process**:
|
||||
```python
|
||||
# Spotify search returns album version first (canonical)
|
||||
album_type = "album" # ✅ TRUE
|
||||
total_tracks = 14 # ✅ TRUE (14 > 1)
|
||||
album_name = "WHEN WE ALL FALL ASLEEP, WHERE DO WE GO?"
|
||||
track_name = "bad guy" # ✅ TRUE (album ≠ track)
|
||||
artist_name = "Billie Eilish" # ✅ TRUE (album ≠ artist)
|
||||
|
||||
# Result: is_album = TRUE
|
||||
```
|
||||
|
||||
**Final Structure**:
|
||||
```
|
||||
Transfer/
|
||||
└── Billie Eilish/
|
||||
└── Billie Eilish - WHEN WE ALL FALL ASLEEP, WHERE DO WE GO?/
|
||||
├── 01 - bury a friend.flac
|
||||
├── 02 - bad guy.flac // Album context preserved!
|
||||
└── 03 - xanny.flac
|
||||
```
|
||||
|
||||
### **Edge Cases Handled**
|
||||
|
||||
| Scenario | Spotify Data | Decision | Structure |
|
||||
|----------|-------------|----------|-----------|
|
||||
| **Normal Album Track** | `album_type: "album"`, `total_tracks: 12` | Album | `Artist/Artist - Album/01 - Track.flac` |
|
||||
| **True Single** | `album_type: "single"`, `total_tracks: 1` | Single | `Artist/Artist - Track/Track.flac` |
|
||||
| **Self-Titled** | Track: "Metallica", Album: "Metallica" | Single | `Artist/Artist - Track/Track.flac` |
|
||||
| **Artist Name Album** | Track: "Something", Album: "Pink Floyd" | Single | `Artist/Artist - Track/Track.flac` |
|
||||
|
||||
---
|
||||
|
||||
## Naming Source Hierarchy
|
||||
|
||||
### **Artist Folder**: `Transfer/ARTIST_NAME/`
|
||||
- **Source**: `download_item.matched_artist.name` (Spotify Artist object)
|
||||
- **NOT** the original Soulseek filename artist
|
||||
|
||||
### **Album Folder**: `ARTIST_NAME - ALBUM_NAME/`
|
||||
```python
|
||||
# Both parts from Spotify match
|
||||
album_folder_name = f"{artist.name} - {album_info['album_name']}"
|
||||
```
|
||||
- **Artist**: `matched_artist.name` from Spotify
|
||||
- **Album**: Priority order:
|
||||
1. `download_item.matched_album.name` (Spotify album)
|
||||
2. `download_item._force_album_name` (user-selected)
|
||||
3. Cleaned original Soulseek album name
|
||||
|
||||
### **Track Filename**: `01 - Track Title.ext`
|
||||
```python
|
||||
track_filename = f"{track_number:02d} - {clean_track_name}{file_ext}"
|
||||
```
|
||||
|
||||
**Track Number Source**:
|
||||
- **Primary**: Spotify track number from album
|
||||
- **Fallback**: Sequential numbering (1, 2, 3...)
|
||||
|
||||
**Track Title Priority**:
|
||||
1. `download_item._spotify_clean_title` (Spotify track name)
|
||||
2. `album_info.get('clean_track_name')` (processed Spotify name)
|
||||
3. `download_item.title` (original Soulseek filename)
|
||||
|
||||
---
|
||||
|
||||
## File Sanitization & Cleaning
|
||||
|
||||
### **Filename Sanitization**
|
||||
```python
|
||||
def _sanitize_filename(self, filename: str) -> str:
|
||||
# Replace invalid characters with underscores
|
||||
sanitized = re.sub(r'[<>:"/\\|?*]', '_', filename)
|
||||
# Consolidate multiple spaces
|
||||
sanitized = re.sub(r'\s+', ' ', sanitized).strip()
|
||||
# Limit to 200 characters
|
||||
return sanitized[:200]
|
||||
```
|
||||
|
||||
### **Album Title Cleaning**
|
||||
Removes Soulseek noise patterns:
|
||||
- **Artist redundancy**: "Kendrick Lamar - good kid, m.A.A.d city" → "good kid, m.A.A.d city"
|
||||
- **Quality indicators**: "[320 Kbps]", "[FLAC]", "(2012)"
|
||||
- **Format tags**: "[Album+iTunes+Bonus Tracks]", "[Deluxe Edition]"
|
||||
|
||||
---
|
||||
|
||||
## Smart Album Grouping System
|
||||
|
||||
### **Consistency Cache**
|
||||
```python
|
||||
# Ensures all tracks from same album get identical folder names
|
||||
self.album_name_cache[f"{artist}::{base_album}"] = resolved_name
|
||||
```
|
||||
|
||||
### **Upgrade Logic**
|
||||
If ANY track is from a deluxe/special edition:
|
||||
- ALL tracks get grouped under that enhanced name
|
||||
- Prevents folder fragmentation (e.g., "Album" vs "Album (Deluxe)")
|
||||
|
||||
### **Base Album Extraction**
|
||||
```python
|
||||
# "The Dark Side of the Moon (2011 Remaster)" → "The Dark Side of the Moon"
|
||||
base_album = self._get_base_album_name(album_name)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration Flow Diagram
|
||||
|
||||
```
|
||||
[User Action: Download Missing Tracks]
|
||||
↓
|
||||
[SpotifyMatchingModal: Select Artist/Album]
|
||||
↓
|
||||
[_handle_match_confirmed(): Attach Spotify metadata]
|
||||
• download_item.matched_artist = Artist
|
||||
• download_item.matched_album = Album
|
||||
• download_item._spotify_clean_title = Title
|
||||
↓
|
||||
[_start_download_with_artist(): Preserve metadata]
|
||||
↓
|
||||
[Download Completion]
|
||||
↓
|
||||
[_organize_matched_download(): Apply naming system]
|
||||
• _detect_album_info(): Album vs Single decision
|
||||
• _resolve_album_group(): Consistent album naming
|
||||
• _sanitize_filename(): Safe filesystem names
|
||||
↓
|
||||
[Final Organization: Clean folder structure]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Why This System Is Powerful
|
||||
|
||||
1. **Universal Consistency**: Same logic across all download methods
|
||||
2. **Spotify Accuracy**: Uses official metadata, not messy filenames
|
||||
3. **Album Bias**: Prefers proper album organization over scattered singles
|
||||
4. **Smart Grouping**: Prevents folder fragmentation for different editions
|
||||
5. **Context Preservation**: Maintains musical relationships and album integrity
|
||||
|
||||
The result is a pristine, professionally organized music library that looks like it was curated by a music service, regardless of how chaotic the original Soulseek files were named.
|
||||
|
||||
---
|
||||
|
||||
## Key Files & Functions
|
||||
|
||||
- **`ui/pages/downloads.py`**: Core organization logic
|
||||
- `_organize_matched_download()`: Main organization function
|
||||
- `_detect_album_info()`: Album vs single decision
|
||||
- `_start_download_with_artist()`: Metadata preservation
|
||||
- **`ui/pages/sync.py`**: Playlist-based download modal
|
||||
- **`ui/pages/artists.py`**: Artist discography download modal
|
||||
- **`ui/pages/dashboard.py`**: Wishlist automatic processing
|
||||
- **SpotifyMatchingModal**: User selection interface (shared across all modals)
|
||||
|
||||
This system ensures that whether you're downloading from playlists, artist pages, or the automatic wishlist, every track gets the same high-quality, Spotify-matched organization.
|
||||
@ -1,161 +0,0 @@
|
||||
# 🎵 SoulSync Metadata Enhancement System - Implementation Complete
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
The metadata enhancement system has been successfully implemented in SoulSync! This powerful feature automatically enriches downloaded music files with accurate Spotify metadata, transforming them from messy Soulseek files into perfectly tagged, Plex-ready tracks.
|
||||
|
||||
## ✨ Features Implemented
|
||||
|
||||
### 🎼 **Core Metadata Enhancement Engine**
|
||||
- **Universal Integration**: Automatically enhances every matched download
|
||||
- **Multi-Format Support**: MP3 (ID3v2.4), FLAC (Vorbis), MP4/M4A (iTunes), OGG (Vorbis)
|
||||
- **Rich Metadata**: Artist, Album, Title, Track #, Total Tracks, Release Date, Genres
|
||||
- **Plex Optimization**: Album Artist tags and format-specific optimizations for perfect Plex integration
|
||||
|
||||
### 🎨 **High-Quality Album Art Embedding**
|
||||
- **Direct Spotify Integration**: Downloads 640x640 high-quality album art from Spotify CDN
|
||||
- **Format-Appropriate Embedding**: ID3 APIC for MP3, PICTURE for FLAC, covr for MP4/M4A
|
||||
- **Smart Caching**: Avoids redundant downloads for multiple tracks from same album
|
||||
- **Network Resilience**: Graceful fallback when album art is unavailable
|
||||
|
||||
### ⚙️ **Configuration & User Control**
|
||||
- **Settings Page Integration**: Three toggle switches for granular control
|
||||
- **Per-Feature Control**: Enable/disable metadata enhancement, album art embedding, and Plex optimizations
|
||||
- **Real-Time Configuration**: Changes apply immediately to new downloads
|
||||
- **Smart Defaults**: Enabled by default with user-friendly settings
|
||||
|
||||
### 🔄 **Seamless Integration**
|
||||
- **Zero User Intervention**: Works automatically with all download modals (Sync, Artists, Dashboard, Downloads)
|
||||
- **Perfect Timing**: Enhances metadata after file organization but before final completion
|
||||
- **Error Handling**: Comprehensive fallback system preserves original tags on any failure
|
||||
- **Performance Optimized**: Background processing doesn't impact UI responsiveness
|
||||
|
||||
## 🛠️ Technical Implementation
|
||||
|
||||
### **Integration Point**
|
||||
```python
|
||||
# In _organize_matched_download() after file move:
|
||||
if self._enhance_file_metadata(new_file_path, download_item, artist, album_info):
|
||||
print(f"✅ Metadata enhanced with Spotify data")
|
||||
else:
|
||||
print(f"⚠️ Metadata enhancement failed, using original tags")
|
||||
```
|
||||
|
||||
### **Core Enhancement Pipeline**
|
||||
1. **Load Audio File**: Uses Mutagen to detect and load the audio file
|
||||
2. **Extract Spotify Metadata**: Pulls rich data from matched Artist/Album objects
|
||||
3. **Format Detection**: Identifies MP3/FLAC/MP4/OGG for appropriate tag handling
|
||||
4. **Apply Tags**: Uses format-specific tag writers for optimal compatibility
|
||||
5. **Embed Album Art**: Downloads and embeds high-quality Spotify album art
|
||||
6. **Validation**: Ensures successful enhancement with comprehensive error handling
|
||||
|
||||
### **Metadata Mapping**
|
||||
|
||||
| Field | Purpose | MP3 (ID3v2.4) | FLAC | MP4/M4A |
|
||||
|-------|---------|---------------|------|---------|
|
||||
| **Title** | Track name | TIT2 | TITLE | ©nam |
|
||||
| **Artist** | Primary performer | TPE1 | ARTIST | ©ART |
|
||||
| **Album Artist** | **Critical for Plex** | TPE2 | ALBUMARTIST | aART |
|
||||
| **Album** | Album/single name | TALB | ALBUM | ©alb |
|
||||
| **Date** | Release year | TDRC | DATE | ©day |
|
||||
| **Track Number** | Track position | TRCK | TRACKNUMBER | trkn |
|
||||
| **Genre** | Music classification | TCON | GENRE | ©gen |
|
||||
| **Album Art** | Visual identification | APIC | PICTURE | covr |
|
||||
|
||||
## 📁 Configuration
|
||||
|
||||
### **config.json Addition**
|
||||
```json
|
||||
{
|
||||
"metadata_enhancement": {
|
||||
"enabled": true,
|
||||
"embed_album_art": true,
|
||||
"plex_optimizations": true,
|
||||
"preserve_original_tags": false,
|
||||
"supported_formats": ["mp3", "flac", "mp4", "m4a", "ogg"],
|
||||
"fallback_behavior": "preserve_original",
|
||||
"logging_level": "info"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Settings Page Controls**
|
||||
- **Enable metadata enhancement with Spotify data**: Master toggle for the entire system
|
||||
- **Embed high-quality album art from Spotify**: Control album art embedding
|
||||
- **Apply Plex-specific tag optimizations**: Enable Album Artist and other Plex-friendly tags
|
||||
- **Supported Formats Display**: Shows MP3, FLAC, MP4/M4A, OGG
|
||||
|
||||
## 🎯 Expected Benefits
|
||||
|
||||
### **For Plex Users**
|
||||
- **Instant Recognition**: Plex immediately identifies artists, albums, and tracks
|
||||
- **Perfect Organization**: No manual matching or correction needed
|
||||
- **Rich Metadata**: Genres, release years, and popularity for smart features
|
||||
- **Visual Appeal**: High-quality embedded album art throughout library
|
||||
- **Advanced Features**: Artist radio, similar tracks, and decade organization work perfectly
|
||||
|
||||
### **For Music Libraries**
|
||||
- **Professional Quality**: Broadcast-standard metadata consistency
|
||||
- **Cross-Platform**: Enhanced files work in any music application
|
||||
- **Future-Proof**: Rich metadata supports advanced music features
|
||||
- **Backup Reliability**: Metadata travels with files during backup/migration
|
||||
|
||||
### **For Users**
|
||||
- **"Set and Forget"**: Files are perfectly tagged automatically
|
||||
- **Zero Manual Work**: No more editing tags or fixing metadata
|
||||
- **Consistency**: Uniform metadata quality across entire library
|
||||
- **Peace of Mind**: Every download is enhanced to perfection
|
||||
|
||||
## 🔧 Usage
|
||||
|
||||
### **For New Downloads**
|
||||
1. Download any track using SoulSync's matched download system
|
||||
2. The system automatically detects the matched Spotify data
|
||||
3. After file organization, metadata is enhanced using Spotify information
|
||||
4. Album art is downloaded and embedded from Spotify's CDN
|
||||
5. Files are ready for Plex with perfect metadata!
|
||||
|
||||
### **Verification**
|
||||
Check the console output during downloads for metadata enhancement status:
|
||||
- `🎵 Enhancing metadata for: [filename]`
|
||||
- `🎯 Extracted metadata: Artist - Title (Album)`
|
||||
- `🎨 Downloading album art for embedding...`
|
||||
- `✅ Metadata enhanced with Spotify data`
|
||||
|
||||
### **Troubleshooting**
|
||||
- **No Enhancement**: Check Settings > Metadata Enhancement > Enable checkbox
|
||||
- **No Album Art**: Verify embed album art setting and internet connection
|
||||
- **Format Issues**: Only MP3, FLAC, MP4/M4A, and OGG files are supported
|
||||
- **Error Messages**: Check console output for detailed error information
|
||||
|
||||
## 📊 Implementation Stats
|
||||
|
||||
- **Files Modified**: 3 (downloads.py, settings.py, config.json)
|
||||
- **New Methods Added**: 8 core metadata enhancement functions
|
||||
- **Lines of Code**: ~350 lines of new functionality
|
||||
- **Audio Formats**: 4 format-specific tag writers
|
||||
- **Configuration Options**: 7 user-controllable settings
|
||||
- **Integration Points**: 1 seamless hook in matched download system
|
||||
|
||||
## 🚀 Future Enhancements
|
||||
|
||||
The system is designed for extensibility. Potential future improvements:
|
||||
|
||||
1. **Batch Processing**: Enhance existing files in Transfer folder
|
||||
2. **Advanced Genre Intelligence**: Multi-level genre classification
|
||||
3. **Custom Metadata Fields**: User-defined tag additions
|
||||
4. **Metadata Validation**: Post-enhancement quality checks
|
||||
5. **Performance Analytics**: Track enhancement success rates
|
||||
|
||||
## 🎉 Conclusion
|
||||
|
||||
The metadata enhancement system transforms SoulSync from a simple file organizer into a complete music library curator. Every downloaded track now comes with:
|
||||
|
||||
- ✅ Accurate artist, album, and track information from Spotify
|
||||
- ✅ Proper track numbering and album organization
|
||||
- ✅ High-quality embedded album art (640x640 from Spotify)
|
||||
- ✅ Genre classification and release date information
|
||||
- ✅ Plex-optimized tags for instant recognition
|
||||
- ✅ Cross-platform compatibility with all music applications
|
||||
|
||||
**The feature is now live and ready to enhance your music collection automatically!** 🎵
|
||||
Loading…
Reference in new issue