Skip to content

Add extension-based downloads with Downloads screen - #2922

Open
kurob1993 wants to merge 42 commits into
PixelPlayerHQ:masterfrom
okuru-id:feature/extension-downloads
Open

kurob1993 wants to merge 42 commits into
PixelPlayerHQ:masterfrom
okuru-id:feature/extension-downloads

Conversation

@kurob1993

Copy link
Copy Markdown

Moved to the okuru-id organization fork; supersedes #2920. Same commits, nothing changed.

Summary

Adds extension-based track downloads to a new Downloads screen. Extensions are SpotiFLAC-compatible .sflx packages, run through the gobackend AAR built from SpotiFLAC-Mobile go_backend (MIT). Finished files are saved into a SAF folder the user picks and media-scanned into the library.

Depends on #2921. This branch is stacked on the S3 storage source, so its first commits are that PR's commits. Once that one merges, this diff shrinks to just the download work.

  • Extensions screen:
    • Install .sflx files from storage, or browse and install from a user-configured registry URL (a GitHub repo or a direct registry.json link).
    • Enable, disable or remove installed extensions.
    • Lists are sorted A-Z.
    • Installed rows show version, type and description.
    • An empty registry shows a setup guide.
  • Downloads screen:
    • Search uses metadata extensions; with no query it shows a catalog from the extensions' homeFeed.
    • Before downloading, a sheet asks for the download extension and then its quality. The search and download extensions can differ.
    • Queue cards show cover, status badge, progress and retry/cancel.
  • Download pipeline (DownloadWorker, WorkManager, serial queue):
    • Calls downloadByStrategy in strict mode, locked to the chosen extension.
    • Live progress through progress deltas.
    • Decrypts encrypted streams with FFmpegKit (ffmpeg.mov_key).
    • Fills missing tags and cover with TagLib.
    • Publishes to SAF and media-scans the file.
  • Verification: when an extension needs browser verification, a dialog opens the browser. A spotiflac:// callback activity completes the grant and automatically retries the waiting jobs.
  • Smaller changes:
    • Login activities follow the in-app language.
    • S3 dashboard no longer re-syncs on every open when all folders are synced.
    • S3 folder sync keeps running after leaving the dashboard.
  • Strings: download, extension and S3 strings translated for every app language (de, es, fr, in, it, ko, nb, ru, tr, zh-CN).

New dependency: com.antonkarpenko:ffmpeg-kit-min (stream decryption). The bundled app/libs/gobackend.aar is MIT-licensed SpotiFLAC-Mobile code.

Notes for reviewers

  • No extensions or registry ship with the app. Users add their own, and the UI warns that extensions run third-party code. Whether downloading through a given extension is allowed is up to the user and that service's terms.
  • Design doc and implementation plan are under docs/.

Testing

Manually verified on a Galaxy A51 (Android 13):

  • FLAC 24-bit/96 kHz download, tagged with cover and saved into the library.
  • Encrypted Amazon stream decrypted, with browser verification completing automatically through the callback.
  • Home-feed catalog rendered.
  • Queue UI.
  • Extension install from file and from registry.

No automated tests cover the download flow.

🤖 Generated with Claude Code

- Streaming from any S3-compatible endpoint (Cloudeka etc.) using
  ListObjectsV2 + SigV4 signing and presigned GET URLs (path-style)
- Local stream proxy with cached resolved URLs (55 min) and 1h presign TTL
- Folder-based sync: pick bucket prefixes, sync to Room (DB v45),
  mirrored into the unified library
- Background metadata queue (S3MetadataWorker): embedded tags, duration
  and album artwork probed via presigned range fetch after sync,
  4 files in parallel; live progress banner on the dashboard
- Editable saved connection, logout, per-folder re-sync
- Queue snapshots keep original cloud URIs so playback survives
  proxy restarts; stale 127.0.0.1 entries are dropped on restore
- SigV4 unit tests against AWS test vectors (plain JVM)
- CloudStreamProxy: dedicated upstream client with 15s connect /
  30s read timeouts instead of the shared 8s API client; slow clouds
  (Cloudeka) routinely exceeded 8s to first byte, especially while
  the metadata probe queue was running
- resolveCloudUri: retry once after 400ms before falling back —
  proxy warm-up races and network blips previously left a raw
  s3:// URI for ExoPlayer and failed with "unknown protocol"
- Log each S3 resolve failure path (offline / proxy not ready /
  null resolution) for easier diagnosis
kurob1993 and others added 11 commits October 18, 2026 01:47
Align the download pipeline with SpotiFLAC-Mobile's gobackend contract:

- Parse GetInstalledExtensions as the flat ExtensionInfo object
  (display_name, types, quality_options, has_download_provider,
  error_message, capabilities) instead of a nested manifest, so
  download providers and their quality options are detected.
- Send service/download_provider = chosen download extension and
  source = search extension (was hard-coded "spotify", which Go's
  strict mode locked onto and always failed), plus provider/ISRC ids.
- Write into a per-item output_dir so the extension picks the real
  file extension.
- Add DownloadFinalizer: decrypt "ffmpeg.mov_key" streams (Amazon)
  with FFmpegKit using the reference key/muxer fallback ladder, then
  fill missing tags and cover art with TagLib before publishing.
- Handle spotiflac://session-grant (and OAuth) browser callbacks in
  ExtensionCallbackActivity, completing the grant and retrying the
  downloads waiting on that extension's verification.
- Download sheet: preselect the track's own, last used or only
  download extension; quality options follow the chosen extension.
- Downloads page shows the extension home feed as a catalog before
  searching; restyle the queue as cards with cover, rounded progress
  and icon actions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Sort installed and repository extensions A-Z (Go returns map order)
- Show version, type and description on installed extension rows
- Add a registry URL guide with a link to compatible SpotiFLAC extensions
- Move download worker notifications and errors to string resources
- Translate download, extension and S3 strings for every app language

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local CPU caps are machine-specific and stay out of upstream.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Search now runs through the chosen extension's customSearch with its
manifest filters. Album, artist and playlist results open a page loaded
via getProviderMetadata, with per-track download and download all.
Catalog collections open the same page instead of a name search.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant