feat(auto): real metadata, quality sort and name buckets for local music [size:exception]
Local tracks now show embedded title/artist/album art (via native MediaMetadataRetriever, cached through the existing FileProvider) instead of the raw filename, falling back gracefully when a file has no usable tags. Adds two navigable entry points per folder: sort by audio quality (bitrate, capped at 150 tracks per folder to bound worst-case latency) and alphabetical name buckets -- the closest realistic form of "filtering" given Android Auto has no text-search UI in this integration. Metadata resolves only for the page actually being browsed (same slice-cheap-then-map discipline as the paging change), backed by a flat 256-entry LRU session cache that survives across pages. No new permission, no new pub dependency, no l10n changes (car-tree labels stay hardcoded Spanish, matching every existing label in the tree).
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Proposal: Android Auto Local Music — Phase 2 (Real Metadata, Sort, Name Buckets)
|
||||
|
||||
## Intent
|
||||
Phase 1 shipped browsable SAF folders with filename-only titles and generic placeholder art. Phase 2 delivers the deferred polish: real embedded metadata (title/artist/bitrate/sample-rate/album art), sort by name and audio quality, and name-based navigation — without breaking Phase 1's lazy paging philosophy or its pure-SAF, zero-dangerous-permission stance.
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
- **A. Real metadata** — resolve embedded title/artist/bitrate/sample-rate + embedded album art for tracks on the page being shown/played, replacing filename title and `station_art_*` placeholder.
|
||||
- **B. Sort** — name (filename, already cheap) and quality (bitrate desc, reusing the `ordenarEmisoras(..., OrdenEmisoras.calidad)` comparator shape) exposed as separate navigable sort-mode entries (Android Auto cannot re-sort in place).
|
||||
- **C. Name navigation** — alphabetical navigable buckets (A–F, etc.) as the realistic, browse-tree-native form of "filter by name".
|
||||
- New translatable strings (sort-mode labels, "unknown metadata" text) added to ALL 13 ARB files from the start.
|
||||
|
||||
### Out of Scope
|
||||
- Phase 3: subfolder scoping, shuffle, transport-control polish.
|
||||
- Live text-search box (impossible under legacy MediaBrowserService).
|
||||
- Voice search via `audio_service.onSearch` — flagged as Phase 3 candidate.
|
||||
|
||||
## Capabilities
|
||||
### New Capabilities
|
||||
- None.
|
||||
### Modified Capabilities
|
||||
- `local-music-browse`: gains metadata resolution, quality sort, alphabetical buckets (confirm exact spec name in `openspec/specs/` during sdd-spec).
|
||||
- `android-auto-navigation`: local branch gains sort-mode + bucket entries.
|
||||
|
||||
## Approach — Metadata Extraction Decision (the one open technical call)
|
||||
**DECISION: native `android.media.MediaMetadataRetriever` on the existing `pluriwave/file_actions` channel. No new pub dependency.**
|
||||
|
||||
Why, versus the Dart packages:
|
||||
- Phase 1 tracks are `content://` SAF URIs (`buildDocumentUriUsingTree`), NOT file paths and NOT guaranteed MediaStore-indexed. `on_audio_query` is MediaStore-based and would (a) miss files outside standard media folders reached via an arbitrary SAF tree and (b) reintroduce `READ_MEDIA_AUDIO`, the dangerous permission Phase 1 deliberately rejected — REJECT.
|
||||
- `audio_metadata_reader` / `flutter_media_metadata` need a `File`/bytes; SAF `content://` gives neither, so we'd still need native byte-streaming — more complexity, no less native code.
|
||||
- `MediaMetadataRetriever.setDataSource(context, uri)` accepts a `content://` URI directly, returns TITLE/ARTIST/BITRATE + `getEmbeddedPicture()` bytes, reuses the existing `contentResolver`, adds zero deps and zero permissions. Consistent with the Phase 1 hand-rolled-channel ADR.
|
||||
|
||||
**DECISION: parse-on-demand + bounded in-memory session cache. NOT eager-scan-and-cache** — eager scan is slow, needs a persistence store, and goes stale when the user adds/removes files. On-demand is always fresh and matches paging. Design formalizes cache bounds/eviction.
|
||||
|
||||
Tension to formalize in sdd-design: **sort-by-quality needs bitrate for the whole folder**, so it must resolve metadata for all tracks in that folder (not just the visible page). Mitigation: name sort stays metadata-free (filename only); quality-sort cost is paid only when the user opts into that entry.
|
||||
|
||||
## Affected Areas
|
||||
| Area | Impact | Description |
|
||||
|------|--------|-------------|
|
||||
| `MainActivity.kt` (`file_actions`) | Modified | New `readAudioMetadata(treeUri, documentId)` via MediaMetadataRetriever; embedded-art delivery (cache file + existing FileProvider) — static-review-only |
|
||||
| `lib/modelos/pista_local.dart` | Modified | Add artist/bitrate/sampleRate/artUri fields |
|
||||
| `lib/servicios/musica_local_auto.dart` | Modified | Metadata channel call + session cache |
|
||||
| `lib/servicios/navegacion_auto.dart` | Modified | Metadata-backed title/subtitle/art; sort-mode + bucket entries |
|
||||
| `lib/l10n/*.arb` (13) | Modified | Sort/metadata labels |
|
||||
|
||||
## Risks
|
||||
| Risk | Likelihood | Mitigation |
|
||||
|------|------------|------------|
|
||||
| MMR sample-rate key is API 31+ | High | Degrade gracefully, reuse existing "unknown" handling |
|
||||
| `artUri` needs a static URI, not bytes | High | Persist embedded art to cache dir, serve via existing FileProvider |
|
||||
| Native untestable here (no build/DHU) | High | Static-review-only; keep sort/bucket/mapping logic pure Dart |
|
||||
| Quality-sort forces full-folder parse | Med | Opt-in cost only when that entry is chosen |
|
||||
| ARB drift across 13 locales | Med | All 13 in tasks from the start |
|
||||
|
||||
## Rollback Plan
|
||||
Additive over Phase 1. Revert by removing `readAudioMetadata`, restoring filename title + placeholder art, and dropping sort-mode/bucket entries. Phase 1 browse/play untouched.
|
||||
|
||||
## Dependencies
|
||||
- None new (native MMR, no pub package).
|
||||
|
||||
## Success Criteria
|
||||
- [ ] Tracks show embedded title/artist and real album art when present, filename/placeholder fallback otherwise.
|
||||
- [ ] Name and quality sort available as navigable entries; quality orders by bitrate desc.
|
||||
- [ ] Alphabetical buckets navigable within a folder.
|
||||
- [ ] Metadata resolved on-demand only; no eager scan, no persistence staleness.
|
||||
- [ ] All 13 ARB files carry new strings; no regression to Phase 1 or stations; pure Dart unit-tested, native static-reviewed.
|
||||
Reference in New Issue
Block a user