Skip to content

fix(sync): write playlist .m3u manifests to the device - #267

Merged
lqdev merged 1 commit into
mainfrom
fix/issue-266-sync-playlist-m3u
Jun 7, 2026
Merged

fix(sync): write playlist .m3u manifests to the device#267
lqdev merged 1 commit into
mainfrom
fix/issue-266-sync-playlist-m3u

Conversation

@lqdev

@lqdev lqdev commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #266 — Playlists copied to a device contained the audio files but no .m3u manifest, so media players couldn't open a synced playlist as a unit.

The local manifests were generated correctly (#255), but the device-sync path never copied them: scan_playlists_for_sync (src/download/manager.rs) only scanned each playlist's audio/ subfolder, so the sibling <name>.m3u was never added to the sync set. A verbatim copy would also have been broken — device sync flattens playlists (Playlists/<name>/audio/<file>Playlists/<name>/<file>, no audio/ subfolder) while the local manifest references audio/<file>.

sync_to_device now writes a device-layout manifest at Playlists/<name>/<name>.m3u for every playlist with synced audio, rewriting each path line to drop the audio/ prefix while preserving #EXTM3U/#EXTINF titles and episode order.

Changes

  • src/playlist/file_manager.rs: add pure PlaylistFileManager::transform_m3u_for_device helper (strips a leading audio/ or audio\ from path lines; leaves #EXTM3U/#EXTINF and already-flat paths untouched).
  • src/download/manager.rs: add a sync_playlist_manifests step to sync_to_device (after audio copy, before orphan deletion). It:
    • derives playlists-with-synced-audio from pc_files,
    • writes the transformed manifest to the device,
    • is idempotent (reads the device file directly and skips unchanged manifests — .m3u is excluded from the audio-only device_files scan),
    • honors dry_run (reported, not written),
    • is regenerated by hard_sync,
    • runs its own orphan pass to delete a stale device manifest once its playlist no longer has synced audio (the main orphan loop never sees .m3u).
  • CHANGELOG.md: [Unreleased] → Fixed entry.
  • docs/DEVICE_PROFILES.md: correct the playlist-manifest paragraph to describe the flat device layout.

Manual Testing

  1. Add episodes to a playlist (so …/data/playlists/<name>/<name>.m3u exists locally).
  2. Open the Sync buffer (F8), pick the device directory, and run a sync.
  3. Before: <device>/Playlists/<name>/ held only 001-….mp3 files, no manifest.
    After: <device>/Playlists/<name>/<name>.m3u exists; open it in a media player → loads the episodes in order.
  4. Inspect the manifest: entries are flat (001-….mp3), not audio/001-….mp3; #EXTINF titles preserved.
  5. Re-run the sync → manifest is skipped (not rewritten/duplicated).
  6. Delete the playlist, sync again → its device .m3u (and audio) are removed.

Tests

  • 5 unit tests for the transform helper (file_manager.rs): strip prefix, preserve directives/order, header-only, non-audio/ passthrough, backslash prefix.
  • 5 integration tests (manager.rs): device m3u written with stripped paths, idempotent skip + not orphan-deleted, removed when playlist removed, dry-run writes nothing but reports, hard-sync regenerates.
  • Full suite green (718 lib + integration tests).

Quality

  • cargo fmt --check
  • cargo clippy --all-targets -- -D warnings
  • cargo test

Playlists copied to a device contained the audio files but no .m3u
manifest, so media players could not open a synced playlist as a unit.
The local manifests were generated correctly (#255), but the device-sync
path never copied them: scan_playlists_for_sync only scanned each
playlist's audio/ subfolder, so the sibling manifest was never added to
the sync set. A verbatim copy would also have been broken, because device
sync flattens playlists (Playlists/<name>/audio/<file> ->
Playlists/<name>/<file>) while the local manifest references audio/<file>.

sync_to_device now writes a device-layout manifest at
Playlists/<name>/<name>.m3u for every playlist with synced audio,
rewriting each path line to drop the audio/ prefix while preserving
#EXTM3U/#EXTINF titles and order. Writes are idempotent (unchanged
manifests skipped), honored in dry-run, regenerated by hard sync, and -
since .m3u files are excluded from the audio-only device scan - a
dedicated pass removes a stale device manifest once its playlist no
longer has synced audio.

Adds a pure PlaylistFileManager::transform_m3u_for_device helper (5 unit
tests) and 5 integration tests covering write/strip, idempotent skip,
orphan removal, dry-run, and hard-sync regeneration.

Closes #266

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 7, 2026 03:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

@lqdev
lqdev merged commit af7b5ff into main Jun 7, 2026
1 check passed
@lqdev
lqdev deleted the fix/issue-266-sync-playlist-m3u branch June 7, 2026 03:13
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.

[Bug] Device sync does not write playlist .m3u manifests

2 participants