Sync music to a connected device, with optional re-encoding #94

Open
opened 2026-08-18 20:37:44 +00:00 by yonlu · 0 comments
Owner

Sync music to a connected Android device over MTP, optionally re-encoding it on the way so a phone does not have to carry FLAC.

Salvaged from phase 6 of docs/dev/roadmap.md, which is deleted — it described an app that no longer exists and its phases 1, 2, 3 and 5 have all shipped. This is one of three things in it that were genuinely never built.

This is a vision item, not scheduled work. It is filed so the intent survives the document, not because it is next. It is also the largest unbuilt feature named anywhere in the project.

Two halves, and the second is useful alone

Device sync (MTP). Detect connected devices and their storage volumes, then transfer selected playlists or tracks. The Go options are libmtp bindings, gousb for raw USB, or shelling out to jmtpfs / go-mtpfs. Bindings mean cgo, which this project has spent real effort avoiding — cmd/indexbuild and cmd/indexexport build with CGO_ENABLED=0 precisely so they need no GTK, and the SQLite driver is modernc's pure-Go one for the same reason. An external binary keeps that property and is worth costing out first.

A re-encoding pipeline. Encoding profiles (format, bitrate, sample rate) with presets, and a cache keyed on source-file hash + profile so a second sync does not re-encode what it already did. FFmpeg is the obvious engine, called as a binary rather than bound.

The pipeline is worth having on its own — "export this playlist as 192k MP3 to a folder" is the same machinery without any USB in it, and it is a far cheaper first step that proves the encoding half before the transport half is attempted.

What it would need from the rest of the app

  • A jobs registration, because it is long-running, cancellable and has real progress — a sync that cannot be stopped mid-transfer is not shippable.
  • Per-device sync profiles in config, and an encoding cache with a budget, not just a location. Every cache in this app that grows with use declares a ceiling beside its retention (browsedArtBudget, httpCacheBudget); an encoding cache is the most obviously unbounded one yet.
  • A decision about what "delete removed tracks from the device" means, which is the part of any sync feature that destroys data.

Done when

A playlist can be sent to a connected device at a chosen quality, the transfer is visible and cancellable, and a second run transfers only what changed.

Sync music to a connected Android device over MTP, optionally re-encoding it on the way so a phone does not have to carry FLAC. Salvaged from phase 6 of `docs/dev/roadmap.md`, which is deleted — it described an app that no longer exists and its phases 1, 2, 3 and 5 have all shipped. This is one of three things in it that were genuinely never built. **This is a vision item, not scheduled work.** It is filed so the intent survives the document, not because it is next. It is also the largest unbuilt feature named anywhere in the project. ## Two halves, and the second is useful alone **Device sync (MTP).** Detect connected devices and their storage volumes, then transfer selected playlists or tracks. The Go options are libmtp bindings, `gousb` for raw USB, or shelling out to `jmtpfs` / `go-mtpfs`. Bindings mean cgo, which this project has spent real effort avoiding — `cmd/indexbuild` and `cmd/indexexport` build with `CGO_ENABLED=0` precisely so they need no GTK, and the SQLite driver is modernc's pure-Go one for the same reason. An external binary keeps that property and is worth costing out first. **A re-encoding pipeline.** Encoding profiles (format, bitrate, sample rate) with presets, and a cache keyed on source-file hash + profile so a second sync does not re-encode what it already did. FFmpeg is the obvious engine, called as a binary rather than bound. The pipeline is worth having on its own — "export this playlist as 192k MP3 to a folder" is the same machinery without any USB in it, and it is a far cheaper first step that proves the encoding half before the transport half is attempted. ## What it would need from the rest of the app - A `jobs` registration, because it is long-running, cancellable and has real progress — a sync that cannot be stopped mid-transfer is not shippable. - Per-device sync profiles in config, and an encoding cache with a **budget**, not just a location. Every cache in this app that grows with use declares a ceiling beside its retention (`browsedArtBudget`, `httpCacheBudget`); an encoding cache is the most obviously unbounded one yet. - A decision about what "delete removed tracks from the device" means, which is the part of any sync feature that destroys data. ## Done when A playlist can be sent to a connected device at a chosen quality, the transfer is visible and cancellable, and a second run transfers only what changed.
yonlu added the Platform/DesktopKind/Feature
Priority
Low
4
labels 2026-08-18 20:37:44 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: yonlu/yellowjacket#94