Create PLAYLIST_DOWNLOAD_IMPLEMENTATION.md
This commit is contained in:
parent
321d632b6a
commit
decd1f3939
1 changed files with 368 additions and 0 deletions
368
PLAYLIST_DOWNLOAD_IMPLEMENTATION.md
Normal file
368
PLAYLIST_DOWNLOAD_IMPLEMENTATION.md
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
# 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
|
||||
1. User clicks "Download Missing Tracks" in playlist details modal
|
||||
2. System checks Plex connection status
|
||||
3. If Plex connected: analyze playlist and identify missing tracks
|
||||
4. If no Plex: queue all tracks for download
|
||||
5. Use existing Spotify matching for artist/track identification
|
||||
6. Download tracks to Transfer/[PLAYLIST_NAME]/ folder structure
|
||||
7. 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 `SpotifyMatchingModal` and `MusicMatchingEngine`
|
||||
- **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 `SpotifyMatchingModal` can 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**:
|
||||
```python
|
||||
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 `SpotifyMatchingModal` for batch operations
|
||||
|
||||
**New Methods**:
|
||||
```python
|
||||
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**:
|
||||
```python
|
||||
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**:
|
||||
```python
|
||||
# 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**:
|
||||
```python
|
||||
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 `MusicMatchingEngine` for confidence scoring
|
||||
- Implement batch processing for large playlists
|
||||
|
||||
**Estimated Lines Added**: 75-100
|
||||
|
||||
#### 2. Smart Download Logic Implementation
|
||||
|
||||
**Core Algorithm**:
|
||||
```python
|
||||
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 `SpotifyMatchingModal` for playlist context
|
||||
- Add batch artist suggestion for album-heavy playlists
|
||||
- Use existing confidence scoring algorithms
|
||||
- Apply Spotify metadata to matched downloads
|
||||
|
||||
**Playlist Context Enhancement**:
|
||||
```python
|
||||
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 `TrackResult` parsing 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**:
|
||||
```python
|
||||
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 `ThreadSafeQueueManager` patterns
|
||||
- **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
|
||||
```python
|
||||
# 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.
|
||||
Loading…
Reference in a new issue