14 KiB
Playlist Download Implementation Plan
Overview
This document outlines the implementation plan for the "Download Missing Tracks" feature that enables intelligent playlist downloads with Plex integration and Soulseek source matching.
Feature Requirements
Core Functionality
- Plex Integration: Check track existence before downloading (if Plex connected)
- Fallback Mode: Download all tracks if no Plex connection
- Intelligent Matching: Use Spotify metadata to match Soulseek results
- File Organization: Create playlist-based folder structure in Transfer directory
- Metadata Enhancement: Apply Spotify metadata to downloaded tracks
- Progress Tracking: Real-time download progress and status updates
User Experience Flow
- User clicks "Download Missing Tracks" in playlist details modal
- System checks Plex connection status
- If Plex connected: analyze playlist and identify missing tracks
- If no Plex: queue all tracks for download
- Use existing Spotify matching for artist/track identification
- Download tracks to Transfer/[PLAYLIST_NAME]/ folder structure
- Apply Spotify metadata to downloaded files
Current Architecture Analysis
Downloads.py Strengths
- Robust download workflow with
start_download(),start_matched_download()patterns - Sophisticated track matching via
SpotifyMatchingModalandMusicMatchingEngine - File organization system with Transfer folder structure (Artist/Album/Track)
- Queue management with progress tracking and status monitoring
- Metadata enhancement from Spotify API integration
- Thread-safe operations with background workers
Plex Integration Capabilities
- Track existence checking via
PlexClient._find_track()method - Bulk track retrieval with
search_tracks()(up to 10K tracks) - Matching engine integration with confidence scoring (0.7+ threshold)
- Lazy connection pattern prevents UI blocking
Extension Points Identified
start_matched_download()pattern can be extended for playlist context- Existing
SpotifyMatchingModalcan handle batch artist selection - Current Transfer folder organization supports playlist grouping
- Thread management patterns support playlist-scale operations
Implementation Plan
Phase 1: Core Infrastructure
1. Create Playlist Download Service
File: /services/playlist_download_service.py (NEW)
Purpose: Orchestrate playlist-wide download operations
Key Components:
class PlaylistDownloadService:
def __init__(self, spotify_client, plex_client, soulseek_client, downloads_page):
self.spotify_client = spotify_client
self.plex_client = plex_client
self.soulseek_client = soulseek_client
self.downloads_page = downloads_page
async def download_missing_tracks(self, playlist: PlaylistInfo):
"""Main entry point for playlist downloads"""
def _check_plex_existence(self, tracks: List[SpotifyTrack]) -> List[SpotifyTrack]:
"""Check which tracks are missing from Plex"""
def _queue_playlist_downloads(self, tracks: List[SpotifyTrack], playlist_name: str):
"""Add tracks to download queue with playlist organization"""
def _create_playlist_folder_structure(self, playlist_name: str) -> str:
"""Create Transfer/[PLAYLIST_NAME]/ directory structure"""
Estimated Lines: 300-400
2. Extend Downloads Page Integration
File: /ui/pages/downloads.py (MODIFY)
Changes Required:
- Add
start_playlist_download()method following existing patterns - Extend download queue to support playlist containers
- Add playlist-level progress tracking
- Integrate with existing
SpotifyMatchingModalfor batch operations
New Methods:
def start_playlist_download(self, playlist: PlaylistInfo):
"""Initiate playlist-wide download operation"""
def _handle_playlist_download_progress(self, playlist_id: str, progress: dict):
"""Track progress across multiple playlist downloads"""
def _organize_playlist_download(self, track_result: TrackResult, playlist_name: str):
"""Apply playlist-specific folder organization"""
Estimated Lines Added: 100-150
3. Enhance Sync Page Modal
File: /ui/pages/sync.py (MODIFY)
Changes Required:
- Connect "Download Missing Tracks" button to playlist download service
- Add playlist download progress indicators
- Handle user feedback for Plex vs. non-Plex scenarios
New Methods:
def on_download_missing_tracks_clicked(self):
"""Handle Download Missing Tracks button click"""
def _show_playlist_download_progress(self, playlist_id: str):
"""Display download progress in modal"""
def _handle_download_completion(self, playlist_id: str, results: dict):
"""Process playlist download completion"""
Button Integration:
# In create_buttons() method
download_btn.clicked.connect(self.on_download_missing_tracks_clicked)
Estimated Lines Added: 50-75
Phase 2: Plex Integration Optimization
1. Enhance Track Existence Checking
File: /core/plex_client.py (MODIFY)
New Methods:
def check_tracks_existence_batch(self, spotify_tracks: List[SpotifyTrack]) -> Dict[str, PlexTrackInfo]:
"""Efficiently check existence of multiple tracks"""
def _build_track_cache(self) -> Dict[str, PlexTrackInfo]:
"""Create in-memory cache of all Plex tracks for fast lookup"""
def _normalize_track_key(self, title: str, artist: str) -> str:
"""Create normalized key for track matching"""
Optimization Strategy:
- Cache all Plex tracks in memory for O(1) lookup
- Use normalized title+artist keys for matching
- Leverage existing
MusicMatchingEnginefor confidence scoring - Implement batch processing for large playlists
Estimated Lines Added: 75-100
2. Smart Download Logic Implementation
Core Algorithm:
def determine_tracks_to_download(self, playlist_tracks: List[SpotifyTrack]) -> Tuple[List[SpotifyTrack], Dict[str, str]]:
"""
Returns:
- List of tracks to download
- Dictionary of skipped tracks with reasons
"""
if not self.plex_client.is_connected():
return playlist_tracks, {}
tracks_to_download = []
skipped_tracks = {}
plex_cache = self.plex_client._build_track_cache()
for track in playlist_tracks:
existing_track = self._find_in_cache(track, plex_cache)
if existing_track and self._calculate_confidence(track, existing_track) >= 0.8:
skipped_tracks[track.id] = f"Already exists in Plex: {existing_track.title}"
else:
tracks_to_download.append(track)
return tracks_to_download, skipped_tracks
Phase 3: Enhanced Matching & Metadata
1. Leverage Existing Spotify Matching
Files: /ui/pages/downloads.py, /core/matching_engine.py (MODIFY)
Extensions Required:
- Extend
SpotifyMatchingModalfor playlist context - Add batch artist suggestion for album-heavy playlists
- Use existing confidence scoring algorithms
- Apply Spotify metadata to matched downloads
Playlist Context Enhancement:
class PlaylistSpotifyMatchingModal(SpotifyMatchingModal):
def __init__(self, track_results: List[TrackResult], playlist_context: PlaylistInfo):
super().__init__(track_results)
self.playlist_context = playlist_context
def _generate_playlist_aware_suggestions(self):
"""Generate suggestions considering playlist context (album groupings, etc.)"""
2. Soulseek Result Matching Integration
Leverage Existing Systems:
- Use existing search and matching algorithms from downloads.py
- Apply track info from Spotify API (title, artist, album, duration)
- Leverage existing
TrackResultparsing and scoring - Maintain current quality filtering and selection logic
Phase 4: File Organization & Metadata
1. Transfer Folder Structure
Pattern Implementation:
Transfer/
[PLAYLIST_NAME]/
ARTIST_NAME/
ARTIST_NAME - ALBUM_NAME/
01 - TRACK_NAME.flac
cover.jpg
ARTIST_NAME/
ARTIST_NAME - SINGLE_NAME/
SINGLE_NAME.flac
cover.jpg
Organization Logic:
def _create_playlist_folder_structure(self, playlist_name: str, track: SpotifyTrack) -> str:
"""Create appropriate folder structure within playlist directory"""
base_path = os.path.join(config_manager.get('soulseek.transfer_path'), playlist_name)
if self._is_part_of_album(track):
return os.path.join(base_path, track.artist, f"{track.artist} - {track.album}")
else:
return os.path.join(base_path, track.artist, f"{track.artist} - {track.title}")
2. Metadata Enhancement
Integration with Existing Systems:
- Apply Spotify track metadata to downloaded files
- Use existing metadata writing functionality from downloads.py
- Preserve track numbers, album info, cover art
- Maintain existing file naming conventions
Technical Implementation Details
Performance Optimizations
- Plex Track Caching: Load all Plex tracks once, cache in memory for O(1) lookups
- Batch Processing: Process large playlists (>100 tracks) in chunks
- Progressive Downloads: Use existing thread pool patterns for concurrent downloads
- Background Processing: Leverage existing worker thread architecture
Error Handling Strategies
- Plex Connection Failures: Graceful fallback to "download all tracks" mode
- Soulseek Search Failures: Use existing retry mechanisms and error handling
- Download Failures: Leverage existing queue management and retry logic
- Metadata Failures: Graceful degradation with basic file naming
User Experience Enhancements
- Progress Indicators: Real-time progress for playlist analysis and downloads
- Skip Existing Option: Clear feedback when tracks exist in Plex
- Batch Operations: Efficient handling of large playlists
- Status Feedback: Clear messaging for Plex vs. non-Plex scenarios
Thread Safety Considerations
- Queue Thread Safety: Use existing
ThreadSafeQueueManagerpatterns - UI Updates: Leverage existing signal/slot patterns for thread-safe UI updates
- Resource Management: Follow existing thread cleanup and management patterns
Integration Points
Existing Service Integration
- SyncService: Extend existing playlist sync workflows
- Downloads Page: Integrate with current download management
- Spotify Client: Use existing OAuth and API integration
- Plex Client: Extend current track lookup and library access
Signal/Slot Connections
# In sync.py - PlaylistDetailsModal
self.download_btn.clicked.connect(self.on_download_missing_tracks_clicked)
# Progress tracking
self.playlist_download_service.progress_updated.connect(self.update_download_progress)
self.playlist_download_service.download_completed.connect(self.on_playlist_download_complete)
Testing Strategy
Unit Testing
- Track Existence Checking: Test Plex integration with various track matching scenarios
- Download Logic: Test playlist download workflow with and without Plex
- File Organization: Test folder structure creation and metadata application
Integration Testing
- End-to-End Workflow: Test complete playlist download from button click to completion
- Error Scenarios: Test Plex disconnection, Soulseek failures, network issues
- Large Playlist Handling: Test performance with 100+ track playlists
User Acceptance Testing
- Plex Integration: Verify correct skip behavior for existing tracks
- Progress Tracking: Ensure clear feedback during long download operations
- File Organization: Verify correct Transfer folder structure and metadata
Future Enhancements (Post-MVP)
Database Integration
- Download History: Track download history and statistics
- Playlist Sync Status: Store playlist sync timestamps and status
- Quality Tracking: Record download quality and source information
- User Preferences: Store user settings and preferences
Advanced Features
- Selective Download: Allow users to manually select tracks from playlist
- Quality Preferences: Automatic quality selection based on user preferences
- Duplicate Detection: Advanced duplicate handling across playlists
- Sync Scheduling: Automatic periodic playlist synchronization
Estimated Implementation Timeline
Phase 1: Core Infrastructure (2-3 days)
- Create
PlaylistDownloadService - Basic downloads.py integration
- Sync page button connection
Phase 2: Plex Integration (1-2 days)
- Optimize track existence checking
- Implement smart download logic
- Add playlist analysis
Phase 3: Enhanced Matching (1-2 days)
- Extend Spotify matching for playlists
- Integrate with existing Soulseek matching
- Add metadata enhancement
Phase 4: File Organization & Polish (1-2 days)
- Implement Transfer folder structure
- Add progress tracking and error handling
- User experience refinements
Total Estimated Effort: 5-9 days
Success Criteria
Functional Requirements
- ✅ Playlist tracks download to Transfer/[PLAYLIST_NAME]/ structure
- ✅ Plex integration skips existing tracks (confidence ≥ 0.8)
- ✅ Fallback to download all tracks when Plex not connected
- ✅ Spotify metadata applied to downloaded files
- ✅ Progress tracking and error handling
Performance Requirements
- ✅ Playlist analysis completes within 10 seconds for 100-track playlists
- ✅ Download initiation within 5 seconds of button click
- ✅ UI remains responsive during playlist processing
User Experience Requirements
- ✅ Clear feedback for Plex vs. non-Plex scenarios
- ✅ Progress indicators for long-running operations
- ✅ Intuitive folder organization in Transfer directory
- ✅ Error handling with clear user messaging
This implementation plan leverages the existing robust architecture while adding intelligent Plex checking and playlist-based download functionality in a maintainable and extensible way.