Commit c95ec234c3e5
Changed files (1)
dots
config
emacs
dots/config/emacs/init.el
@@ -3431,6 +3431,7 @@ With \\[universal-argument] \\[universal-argument]: always prompt with completio
empv-subsonic-songs)
:bind (("C-c M s" . empv-subsonic-search)
("C-c M a" . empv-subsonic-albums)
+ ("C-c M P" . empv-subsonic-playlists)
("C-c M SPC" . empv-toggle)
("C-c M i" . empv-display-current)
("C-c M n" . empv-playlist-next)
@@ -3445,7 +3446,64 @@ With \\[universal-argument] \\[universal-argument]: always prompt with completio
:config
(setq empv-subsonic-url "https://music.sbr.pm"
empv-subsonic-username (passage-get "home/music.sbr.pm/username")
- empv-subsonic-password (passage-get "home/music.sbr.pm/password")))
+ empv-subsonic-password (passage-get "home/music.sbr.pm/password"))
+
+ ;; Subsonic playlist support (not yet upstream in empv.el)
+ ;; Adds formatting, act-on-candidate handling, and interactive command
+ ;; for getPlaylists/getPlaylist Subsonic API endpoints.
+
+ (defun empv--subsonic-format-playlist (cand)
+ "Format a Subsonic playlist candidate for display."
+ (format "%s %s"
+ (propertize (alist-get 'name cand) 'face 'bold)
+ (propertize (format "[%s songs]" (or (alist-get 'songCount cand) "?")) 'face 'italic)))
+
+ ;; Extend the formatter to handle playlist kind
+ (advice-add 'empv--subsonic-format-candidate :around
+ (lambda (orig cand)
+ (if (eq (alist-get 'kind cand) 'playlist)
+ (empv--with-text-properties
+ (empv--subsonic-format-playlist cand)
+ :item cand)
+ (funcall orig cand))))
+
+ ;; Extend act-on-candidate to handle playlist kind
+ ;; Fetches playlist tracks via getPlaylist and enqueues all songs
+ (advice-add 'empv--subsonic-act-on-candidate :around
+ (lambda (orig selected)
+ (if (eq (alist-get 'kind selected) 'playlist)
+ (let ((id (alist-get 'id selected))
+ (name (alist-get 'name selected)))
+ (empv--subsonic-request
+ "getPlaylist.view"
+ :id id
+ (lambda (response)
+ ;; getPlaylist returns entries under 'entry key
+ ;; but empv's processor puts them under 'results
+ ;; if they match result-fields. Since 'entry is
+ ;; not in result-fields, we extract manually.
+ (let* ((raw (alist-get 'entry response))
+ (songs (or (alist-get 'results response) raw)))
+ (if songs
+ (empv-play-or-enqueue
+ (mapcar #'empv--subsonic-item-extract-url
+ (if (alist-get 'results response)
+ songs
+ ;; raw entries need kind annotation
+ (mapcar (lambda (s)
+ (thread-first s
+ (map-insert 'kind 'song)
+ (map-insert 'type 'subsonic)))
+ songs))))
+ (message "Playlist '%s' is empty" name))))))
+ (funcall orig selected))))
+
+ (defun empv-subsonic-playlists ()
+ "List Subsonic playlists and act on selection."
+ (interactive)
+ (empv--subsonic-request
+ "getPlaylists.view"
+ (empv--subsonic-result-handler "Select playlist:"))))
(use-package ready-player
:init