Shuttle2 icon indicating copy to clipboard operation
Shuttle2 copied to clipboard

Add offline song download feature

Open timusus opened this issue 2 months ago • 0 comments

…by, Plex)

This implements comprehensive offline download functionality for remote media providers, allowing users to download songs for offline playback similar to Spotify.

Core Features

Database Schema

  • Added DownloadState enum to track download states (NONE, QUEUED, DOWNLOADING, PAUSED, COMPLETED, FAILED)
  • Created DownloadData entity with Room database support
  • Added DownloadDao with comprehensive query methods
  • Incremented database version to 41
  • Added TypeConverter for DownloadState

Download Repository

  • Created DownloadRepository interface for download operations
  • Implemented DownloadRepositoryImpl with full CRUD operations
  • Supports queuing, progress tracking, pause/resume, and cancellation
  • Includes automatic file cleanup when downloads are removed

Download Manager

  • Implemented DownloadManager singleton for coordinating downloads
  • Supports concurrent downloads (max 3 simultaneous)
  • Automatic queue processing
  • Progress tracking and error handling
  • File storage in app-specific directories organized by provider

Provider Integration

  • Jellyfin: Added buildJellyfinDownloadPath() for direct download URLs (no transcoding)
  • Emby: Added buildEmbyDownloadPath() for direct download URLs
  • Plex: Added buildPlexDownloadPath() for direct download URLs
  • All download URLs use static=true to avoid transcoding and get original files

Offline Playback

  • Updated JellyfinMediaInfoProvider to check for offline files first
  • Updated EmbyMediaInfoProvider to check for offline files first
  • Updated PlexMediaInfoProvider to check for offline files first
  • Seamless fallback to streaming if file not downloaded
  • Returns file:// URIs for downloaded content (isRemote = false)

Dependency Injection

  • Added DownloadRepository binding in RepositoryModule
  • Injected DownloadRepository into all MediaInfoProviders
  • DownloadManager uses constructor injection with Hilt

Architecture

The implementation follows the existing codebase patterns:

  • Repository pattern for data access
  • Hilt/Dagger for dependency injection
  • Room for database operations
  • Coroutines for async operations
  • Clean separation between data, domain, and presentation layers

Storage Structure

/data/data/com.simplecityapps.shuttle/files/downloads/
├── jellyfin/
│   └── {itemId}.{ext}
├── emby/
│   └── {itemId}.{ext}
└── plex/
    └── {itemId}.{ext}

Next Steps (for future PRs)

  1. Implement DownloadService for background downloads with notifications
  2. Add UI components (download buttons, progress indicators)
  3. Implement batch download for albums/playlists
  4. Add download settings (WiFi-only, storage location, quality)
  5. Implement storage management and cleanup UI
  6. Add download notifications with progress
  7. Handle network changes and retry logic
  8. Add tests for download functionality

Addresses #88

timusus avatar Nov 16 '25 09:11 timusus