aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-08-03 14:38:20 -0500
committerCraig Jennings <c@cjennings.net>2026-08-03 14:38:20 -0500
commita457ade9207be48f6bfaa519046d7acea390ff1b (patch)
treea0584cabe422b2f918627a6bb73a9e6a1dab2345 /modules
parent90aa02c5cd7dc78729d4362d4962005627069e60 (diff)
downloaddotemacs-a457ade9207be48f6bfaa519046d7acea390ff1b.tar.gz
dotemacs-a457ade9207be48f6bfaa519046d7acea390ff1b.zip
feat(music): write an m3u path absolute when it leaves the playlist's directory
A track under the playlist's own directory still writes relative. Anything outside it now writes the absolute path instead of a ../ chain. Playlists in the mpd directory point into ~/music, so the relative form there was four levels of .. and broke the moment anything moved. I took the trade knowingly. ambience.m3u is the only playlist anywhere using ../ lines, and it reaches its audio through a sibling directory. So a newly appended track there writes absolute while its hand-written lines stay relative, and its header comment needs a matching edit. The alternative was an exception for tracks inside the deployed tree, which would be a rule serving exactly one file. The comment I wrote for the earlier half of this argued one direction only. Absolute survives the playlist moving, which I said. Relative survives the library moving, which I didn't, and for a track in the same tree the ../ form survives strictly more moves rather than fewer. Rewritten to name the trade instead of implying there isn't one. The boundary case is a directory whose name begins with two dots. The check looks for a leading "../", so a real subdirectory called ..hidden sits under the playlist and must stay relative. It has a test now, because loosening that check to ".." would break that case and nothing else.
Diffstat (limited to 'modules')
-rw-r--r--modules/music-config.el29
1 files changed, 19 insertions, 10 deletions
diff --git a/modules/music-config.el b/modules/music-config.el
index 075ed49b..0834aae8 100644
--- a/modules/music-config.el
+++ b/modules/music-config.el
@@ -677,16 +677,25 @@ M3U-FILE should be an existing, writable M3U file path."
(unless (file-writable-p m3u-file)
(error "M3U file is not writable: %s" m3u-file))
- ;; Write the path relative to the playlist's own directory, which is the base
- ;; `cj/music--m3u-file-tracks' and EMMS both resolve against. This used to be
- ;; `cj/music-root'. For a playlist inside the music root the two are the same
- ;; directory, so the disagreement stayed invisible until a playlist lived
- ;; somewhere else -- then the appended line resolved against the wrong base and
- ;; pointed at a file that was never there.
- (let ((relative-path (if (file-name-absolute-p track-path)
- (file-relative-name track-path
- (file-name-directory m3u-file))
- track-path)))
+ ;; Relative when the track sits under the playlist's own directory, absolute
+ ;; otherwise.
+ ;;
+ ;; The base is the playlist rather than `cj/music-root' because that is what
+ ;; both readers resolve against -- `cj/music--m3u-file-tracks' and EMMS's
+ ;; `emms-source-playlist-parse-m3u'. Inside the music root the two are the
+ ;; same directory, which is why basing on the root went unnoticed: it only
+ ;; wrote an unresolvable line once a playlist lived somewhere else.
+ ;;
+ ;; Falling back to absolute keeps a cross-tree reference readable, and it
+ ;; survives the playlist being moved again. A playlist in the mpd directory
+ ;; pointing into ~/music would otherwise carry a four-level ../ chain that
+ ;; breaks the moment anything moves.
+ (let* ((dir (file-name-directory m3u-file))
+ (relative-path
+ (if (not (file-name-absolute-p track-path))
+ track-path
+ (let ((rel (file-relative-name track-path dir)))
+ (if (string-prefix-p "../" rel) track-path rel)))))
;; Determine if we need a leading newline
(let ((needs-prefix-newline nil)
(file-size (file-attribute-size (file-attributes m3u-file))))