diff options
-rw-r--r-- | AUTHORS | 7 | ||||
-rw-r--r-- | emms-player-mpd.el | 842 |
2 files changed, 425 insertions, 424 deletions
@@ -42,14 +42,15 @@ Fran Burstall <fran.burstall@gmail.com> The following is a list of people who contributed trivial patches, -which is to say very simple patches and those with total of 12 lines -or fewer. We started recording trivial patches this way in June of -2017, so trivial patches before that date would not appear below. +which is to say, simple patches and those with total of 12 lines or +fewer. We started recording trivial patches this way in June of 2017, +so trivial patches before that date would not appear below. David Michael tumashu Maxim Cournoyer Ian Dunn +Pavel Korytov ;; Local variables: diff --git a/emms-player-mpd.el b/emms-player-mpd.el index e7a61a0..5ac48fa 100644 --- a/emms-player-mpd.el +++ b/emms-player-mpd.el @@ -113,8 +113,8 @@ (eval-when-compile (condition-case nil (progn - (require 'url) ; load if available - (require 'emms-url)) + (require 'url) ; load if available + (require 'emms-url)) (error nil))) (defgroup emms-player-mpd nil @@ -123,8 +123,8 @@ :prefix "emms-player-mpd-") (defcustom emms-player-mpd (emms-player #'emms-player-mpd-start - #'emms-player-mpd-stop - #'emms-player-mpd-playable-p) + #'emms-player-mpd-stop + #'emms-player-mpd-playable-p) "Parameters for the MusicPD player." :type '(cons symbol alist)) @@ -137,8 +137,8 @@ config." ;; The :format part ensures that entering directories happens on the ;; next line, where there is more space to work with :type '(choice :format "%{%t%}:\n %[Value Menu%] %v" - (const nil) - directory)) + (const nil) + directory)) (defun emms-player-mpd-get-supported-regexp () "Returns a regexp of file extensions that MusicPD supports, @@ -146,55 +146,55 @@ or nil if we cannot figure it out." (let ((out (shell-command-to-string "mpd --version"))) ;; 0.17.x (if (string-match "Decoders plugins:$" out) - (let* ((b (match-end 0)) - (e (string-match "Output plugins:$" out)) - (plugs (split-string (substring out b e) "\n" t)) - (plugs (cl-mapcan (lambda (x) - (and (string-match " +\\[.*\\] +\\(.+\\)$" x) - (split-string (match-string 1 x) nil t))) - plugs)) - (b (and (string-match "Protocols:$" out) (match-end 0))) - (prots (and b (substring out (+ 2 b) -1))) - (prots (split-string (or prots "") nil t))) - (concat "\\(\\.\\(m3u\\|pls\\|" - (regexp-opt (delq nil plugs)) - "\\)\\'\\)\\|\\(\\`" - (regexp-opt (delete "file://" prots)) "\\)")) + (let* ((b (match-end 0)) + (e (string-match "Output plugins:$" out)) + (plugs (split-string (substring out b e) "\n" t)) + (plugs (cl-mapcan (lambda (x) + (and (string-match " +\\[.*\\] +\\(.+\\)$" x) + (split-string (match-string 1 x) nil t))) + plugs)) + (b (and (string-match "Protocols:$" out) (match-end 0))) + (prots (and b (substring out (+ 2 b) -1))) + (prots (split-string (or prots "") nil t))) + (concat "\\(\\.\\(m3u\\|pls\\|" + (regexp-opt (delq nil plugs)) + "\\)\\'\\)\\|\\(\\`" + (regexp-opt (delete "file://" prots)) "\\)")) (let ((found-start nil) - (supported nil)) - (if (string-match "Supported decoders:\\([^0]+?\\)Supported outputs:" out) - ;; 0.15.x - (setq supported (replace-regexp-in-string "\\[.+?\\]" "" - (match-string 1 out))) - ;; < 0.15 - (setq out (split-string out "\n")) - (while (car out) - (cond ((string= (car out) "Supported formats:") - (setq found-start t)) - ((string= (car out) "") - (setq found-start nil)) - (found-start - (setq supported (concat supported (car out))))) - (setq out (cdr out)))) - ;; Create regexp - (when (and (stringp supported) - (not (string= supported ""))) - (concat "\\`http://\\|\\.\\(m3u\\|pls\\|" - (regexp-opt (delq nil (split-string supported))) - "\\)\\'")))))) + (supported nil)) + (if (string-match "Supported decoders:\\([^0]+?\\)Supported outputs:" out) + ;; 0.15.x + (setq supported (replace-regexp-in-string "\\[.+?\\]" "" + (match-string 1 out))) + ;; < 0.15 + (setq out (split-string out "\n")) + (while (car out) + (cond ((string= (car out) "Supported formats:") + (setq found-start t)) + ((string= (car out) "") + (setq found-start nil)) + (found-start + (setq supported (concat supported (car out))))) + (setq out (cdr out)))) + ;; Create regexp + (when (and (stringp supported) + (not (string= supported ""))) + (concat "\\`http://\\|\\.\\(m3u\\|pls\\|" + (regexp-opt (delq nil (split-string supported))) + "\\)\\'")))))) (defcustom emms-player-mpd-supported-regexp ;; Use a sane default, just in case (or (emms-player-mpd-get-supported-regexp) (concat "\\`http://\\|" - (emms-player-simple-regexp - "m3u" "ogg" "flac" "mp3" "wav" "mod" "au" "aiff"))) + (emms-player-simple-regexp + "m3u" "ogg" "flac" "mp3" "wav" "mod" "au" "aiff"))) "Formats supported by MusicPD." :type 'regexp :set (function - (lambda (sym value) - (set sym value) - (emms-player-set emms-player-mpd 'regex value)))) + (lambda (sym value) + (set sym value) + (emms-player-set emms-player-mpd 'regex value)))) (defcustom emms-player-mpd-connect-function 'open-network-stream "Function used to initiate the connection to MusicPD. @@ -212,7 +212,7 @@ It should take same arguments as `open-network-stream' does." (defcustom emms-player-mpd-server-password nil "The password for the MusicPD server that we should connect to." :type '(choice (const :tag "None" nil) - string)) + string)) (defcustom emms-player-mpd-check-interval 1 "How often to check to see whether MusicPD has advanced to the @@ -223,7 +223,7 @@ performed. This variable is used only if `emms-player-mpd-sync-playlist' is non-nil." :type '(choice (const :tag "Disable check" nil) - number)) + number)) (defcustom emms-player-mpd-verbose nil "Whether to provide notifications for server connection events @@ -240,24 +240,24 @@ If your EMMS playlist contains stored playlists, set this to nil." :type 'boolean) (emms-player-set emms-player-mpd - 'regex - emms-player-mpd-supported-regexp) + 'regex + emms-player-mpd-supported-regexp) (emms-player-set emms-player-mpd - 'pause - 'emms-player-mpd-pause) + 'pause + 'emms-player-mpd-pause) (emms-player-set emms-player-mpd - 'resume - 'emms-player-mpd-pause) + 'resume + 'emms-player-mpd-pause) (emms-player-set emms-player-mpd - 'seek - 'emms-player-mpd-seek) + 'seek + 'emms-player-mpd-seek) (emms-player-set emms-player-mpd - 'seek-to - 'emms-player-mpd-seek-to) + 'seek-to + 'emms-player-mpd-seek-to) ;;; Dealing with the MusicPD network process @@ -280,51 +280,51 @@ return at the end of a request.") "The process sentinel for MusicPD." (let ((status (process-status proc))) (cond ((string-match "^deleted" event) - (when emms-player-mpd-verbose - (message "MusicPD process was deleted"))) - ((memq status '(exit signal closed)) - (emms-player-mpd-close-process t) - (when emms-player-mpd-verbose - (message "Closed MusicPD process"))) - ((memq status '(run open)) - (when emms-player-mpd-verbose - (message "MusicPD process started successfully"))) - (t - (when emms-player-mpd-verbose - (message "Other MusicPD status change: %s, %s" status event)))))) + (when emms-player-mpd-verbose + (message "MusicPD process was deleted"))) + ((memq status '(exit signal closed)) + (emms-player-mpd-close-process t) + (when emms-player-mpd-verbose + (message "Closed MusicPD process"))) + ((memq status '(run open)) + (when emms-player-mpd-verbose + (message "MusicPD process started successfully"))) + (t + (when emms-player-mpd-verbose + (message "Other MusicPD status change: %s, %s" status event)))))) (defun emms-player-mpd-ensure-process () "Make sure that a MusicPD process is currently active." (unless (and emms-player-mpd-process - (processp emms-player-mpd-process) - (memq (process-status emms-player-mpd-process) '(run open))) + (processp emms-player-mpd-process) + (memq (process-status emms-player-mpd-process) '(run open))) (setq emms-player-mpd-process (if emms-player-mpd-server-port (funcall emms-player-mpd-connect-function "mpd" - nil - emms-player-mpd-server-name - emms-player-mpd-server-port) + nil + emms-player-mpd-server-name + emms-player-mpd-server-port) (make-network-process :name "emms-mpd" - :service emms-player-mpd-server-name - :family 'local))) + :service emms-player-mpd-server-name + :family 'local))) (set-process-sentinel emms-player-mpd-process - #'emms-player-mpd-sentinel) + #'emms-player-mpd-sentinel) (setq emms-player-mpd-queue - (tq-create emms-player-mpd-process)) + (tq-create emms-player-mpd-process)) (set-process-query-on-exit-flag emms-player-mpd-process nil) ;; send password (when (stringp emms-player-mpd-server-password) (tq-enqueue emms-player-mpd-queue - (concat "password " emms-player-mpd-server-password "\n") - emms-player-mpd-status-regexp nil #'ignore t)))) + (concat "password " emms-player-mpd-server-password "\n") + emms-player-mpd-status-regexp nil #'ignore t)))) (defun emms-player-mpd-close-process (&optional from-sentinel) "Terminate the current MusicPD client process. FROM-SENTINEL indicates whether this was called by the process sentinel, in which case certain checks should not be made." (when (or from-sentinel - (and (processp emms-player-mpd-process) - (memq (process-status emms-player-mpd-process) '(run open)))) + (and (processp emms-player-mpd-process) + (memq (process-status emms-player-mpd-process) '(run open)))) (tq-close emms-player-mpd-queue) (setq emms-player-mpd-queue nil) (setq emms-player-mpd-process nil))) @@ -336,8 +336,8 @@ When a reply comes, call FN with CLOSURE and the result." (unless (string= (substring question -1) "\n") (setq question (concat question "\n"))) (tq-enqueue emms-player-mpd-queue question - emms-player-mpd-status-regexp - closure fn t)) + emms-player-mpd-status-regexp + closure fn t)) ;;; Helper functions @@ -346,8 +346,8 @@ When a reply comes, call FN with CLOSURE and the result." This usually means removing a prefix." (if (or (not emms-player-mpd-music-directory) - (not (eq (aref file 0) ?/)) - (string-match "\\`http://" file)) + (not (eq (aref file 0) ?/)) + (string-match "\\`http://" file)) file (file-relative-name file emms-player-mpd-music-directory))) @@ -356,8 +356,8 @@ This usually means removing a prefix." This usually means adding a prefix." (if (or (not emms-player-mpd-music-directory) - (eq (aref file 0) ?/) - (string-match "\\`http://" file)) + (eq (aref file 0) ?/) + (string-match "\\`http://" file)) file (expand-file-name file emms-player-mpd-music-directory))) @@ -371,21 +371,21 @@ Otherwise, it will be nil." (when (stringp response) (save-match-data (let* ((data (split-string response "\n")) - (cruft (last data 3)) - (status (if (string= (cadr cruft) "") - (car cruft) - (cadr cruft)))) - (setcdr cruft nil) - (when (and (stringp (car data)) - (string-match "^OK\\( MPD \\)?" (car data))) - (setq data (cdr data))) - (if (and (stringp status) - (string-match "^ACK \\[\\([0-9]+\\)@[0-9]+\\] \\(.+\\)" - status)) - (cons (cons (match-string 1 status) - (match-string 2 status)) - data) - (cons nil data)))))) + (cruft (last data 3)) + (status (if (string= (cadr cruft) "") + (car cruft) + (cadr cruft)))) + (setcdr cruft nil) + (when (and (stringp (car data)) + (string-match "^OK\\( MPD \\)?" (car data))) + (setq data (cdr data))) + (if (and (stringp status) + (string-match "^ACK \\[\\([0-9]+\\)@[0-9]+\\] \\(.+\\)" + status)) + (cons (cons (match-string 1 status) + (match-string 2 status)) + data) + (cons nil data)))))) (defun emms-player-mpd-parse-line (line) "Turn the given LINE from MusicPD into a cons cell. @@ -393,25 +393,25 @@ Otherwise, it will be nil." The format of the cell is (name . value)." (when (string-match "\\`\\([^:\n]+\\):\\s-*\\(.+\\)" line) (let ((name (match-string 1 line)) - (value (match-string 2 line))) + (value (match-string 2 line))) (if (and name value) - (progn - (setq name (downcase name)) - (cons name value)) - nil)))) + (progn + (setq name (downcase name)) + (cons name value)) + nil)))) (defun emms-player-mpd-get-alist (info) "Turn the given parsed INFO from MusicPD into an alist." (when (and info - (null (car info)) ; no error has occurred - (cdr info)) ; data exists + (null (car info)) ; no error has occurred + (cdr info)) ; data exists (let ((alist nil) - cell old-cell) + cell old-cell) (dolist (line (cdr info)) - (when (setq cell (emms-player-mpd-parse-line line)) - (if (setq old-cell (assoc (car cell) alist)) - (setcdr old-cell (cdr cell)) - (setq alist (cons cell alist))))) + (when (setq cell (emms-player-mpd-parse-line line)) + (if (setq old-cell (assoc (car cell) alist)) + (setcdr old-cell (cdr cell)) + (setq alist (cons cell alist))))) alist))) (defun emms-player-mpd-get-alists (info) @@ -419,37 +419,37 @@ The format of the cell is (name . value)." The list will be in reverse order." (when (and info - (null (car info)) ; no error has occurred - (cdr info)) ; data exists + (null (car info)) ; no error has occurred + (cdr info)) ; data exists (let ((alists nil) - (alist nil) - cell) + (alist nil) + cell) (dolist (line (cdr info)) - (when (setq cell (emms-player-mpd-parse-line line)) - (if (assoc (car cell) alist) - (setq alists (cons alist alists) - alist (list cell)) - (setq alist (cons cell alist))))) + (when (setq cell (emms-player-mpd-parse-line line)) + (if (member (car cell) '("file" "directory" "playlist")) + (setq alists (cons alist alists) + alist (list cell)) + (setq alist (cons cell alist))))) (when alist - (setq alists (cons alist alists))) + (setq alists (cons alist alists))) alists))) (defun emms-player-mpd-get-tracks-1 (closure response) (let ((songs (emms-player-mpd-get-alists - (emms-player-mpd-parse-response response))) - (tracks nil)) + (emms-player-mpd-parse-response response))) + (tracks nil)) (when songs (dolist (song-info songs) - (let ((file (cdr (assoc "file" song-info)))) - (when file - (setq file (emms-player-mpd-get-emms-filename file)) - (let* ((type (if (string-match "\\`http://" file) - 'url - 'file)) - (track (emms-track type file))) - (emms-info-mpd track song-info) - (run-hook-with-args 'emms-track-info-filters track) - (setq tracks (cons track tracks))))))) + (let ((file (cdr (assoc "file" song-info)))) + (when file + (setq file (emms-player-mpd-get-emms-filename file)) + (let* ((type (if (string-match "\\`http://" file) + 'url + 'file)) + (track (emms-track type file))) + (emms-info-mpd track song-info) + (run-hook-with-args 'emms-track-info-filters track) + (setq tracks (cons track tracks))))))) (funcall (car closure) (cdr closure) tracks))) (defun emms-player-mpd-get-tracks (closure callback) @@ -457,13 +457,13 @@ The list will be in reverse order." EMMS tracks. Call CALLBACK with CLOSURE and result when the request is complete." (emms-player-mpd-send "playlistinfo" (cons callback closure) - #'emms-player-mpd-get-tracks-1)) + #'emms-player-mpd-get-tracks-1)) (defun emms-player-mpd-get-status-1 (closure response) (funcall (car closure) - (cdr closure) - (emms-player-mpd-get-alist - (emms-player-mpd-parse-response response)))) + (cdr closure) + (emms-player-mpd-get-alist + (emms-player-mpd-parse-response response)))) (defun emms-player-mpd-get-status (closure callback) "Get status information from MusicPD. @@ -471,7 +471,7 @@ It will be returned in the form of an alist by calling CALLBACK with CLOSURE as its first argument, and the status as the second." (emms-player-mpd-send "status" (cons callback closure) - #'emms-player-mpd-get-status-1)) + #'emms-player-mpd-get-status-1)) (defun emms-player-mpd-get-status-part (closure callback item &optional info) "Get ITEM from the current MusicPD status. @@ -484,9 +484,9 @@ info from MusicPD." (cons callback (cons closure item)) (lambda (closure info) (let ((fn (car closure)) - (close (cadr closure)) - (item (cddr closure))) - (funcall fn close (cdr (assoc item info)))))))) + (close (cadr closure)) + (item (cddr closure))) + (funcall fn close (cdr (assoc item info)))))))) (defun emms-player-mpd-get-playlist-id (closure callback &optional info) "Get the current playlist ID from MusicPD. @@ -541,18 +541,18 @@ info from MusicPD." nil (lambda (closure time) (ignore closure) - (and time - (string-match "\\`\\([0-9]+\\):" time) - (string-to-number (match-string 1 time)))) + (and time + (string-match "\\`\\([0-9]+\\):" time) + (string-to-number (match-string 1 time)))) "time" info) (emms-player-mpd-get-status-part (cons callback closure) (lambda (closure time) (funcall (car closure) - (cdr closure) - (and time - (string-match "\\`\\([0-9]+\\):" time) - (string-to-number (match-string 1 time))))) + (cdr closure) + (and time + (string-match "\\`\\([0-9]+\\):" time) + (string-to-number (match-string 1 time))))) "time" info))) (defun emms-player-mpd-select-song (prev-song new-song) @@ -566,41 +566,41 @@ buffer and move to NEW-SONG." (with-current-emms-playlist ;; move to current track (goto-char (if (and (stringp prev-song) - emms-playlist-selected-marker - (marker-position emms-playlist-selected-marker)) - emms-playlist-selected-marker - (point-min))) + emms-playlist-selected-marker + (marker-position emms-playlist-selected-marker)) + emms-playlist-selected-marker + (point-min))) ;; seek forward or backward (let ((diff (if (stringp prev-song) - (- (string-to-number new-song) - (string-to-number prev-song)) - (string-to-number new-song)))) + (- (string-to-number new-song) + (string-to-number prev-song)) + (string-to-number new-song)))) (condition-case nil - (progn - ;; skip to first track if not on one - (when (and (> diff 0) - (not (emms-playlist-track-at (point)))) - (emms-playlist-next)) - ;; move to new track - (while (> diff 0) - (emms-playlist-next) - (setq diff (- diff 1))) - (while (< diff 0) - (emms-playlist-previous) - (setq diff (+ diff 1))) - ;; select track at point - (unless (emms-playlist-selected-track-at-p) - (emms-playlist-select (point)))) - (error (concat "Could not move to position " new-song)))))) + (progn + ;; skip to first track if not on one + (when (and (> diff 0) + (not (emms-playlist-track-at (point)))) + (emms-playlist-next)) + ;; move to new track + (while (> diff 0) + (emms-playlist-next) + (setq diff (- diff 1))) + (while (< diff 0) + (emms-playlist-previous) + (setq diff (+ diff 1))) + ;; select track at point + (unless (emms-playlist-selected-track-at-p) + (emms-playlist-select (point)))) + (error (concat "Could not move to position " new-song)))))) (defun emms-player-mpd-sync-from-emms-1 (closure) (emms-player-mpd-get-playlist-id closure (lambda (closure id) (let ((buffer (car closure)) - (fn (cdr closure))) + (fn (cdr closure))) (when (functionp fn) - (funcall fn buffer id)))))) + (funcall fn buffer id)))))) (defun emms-player-mpd-sync-from-emms (&optional callback) "Synchronize the MusicPD playlist with the contents of the @@ -613,9 +613,9 @@ errors." (with-current-emms-playlist (let (tracks) (save-excursion - (setq tracks (nreverse - (emms-playlist-tracks-in-region - (point-min) (point-max))))) + (setq tracks (nreverse + (emms-playlist-tracks-in-region + (point-min) (point-max))))) (emms-player-mpd-add-several-tracks tracks (cons (current-buffer) callback) @@ -623,31 +623,31 @@ errors." (defun emms-player-mpd-sync-from-mpd-2 (closure info) (let ((buffer (car closure)) - (fn (cadr closure)) - (close (cddr closure)) - (id (emms-player-mpd-get-playlist-id nil #'ignore info)) - (song (emms-player-mpd-get-current-song nil #'ignore info))) + (fn (cadr closure)) + (close (cddr closure)) + (id (emms-player-mpd-get-playlist-id nil #'ignore info)) + (song (emms-player-mpd-get-current-song nil #'ignore info))) (when (buffer-live-p buffer) (let ((emms-playlist-buffer buffer)) - (with-current-emms-playlist - (setq emms-player-mpd-playlist-id id) - (set-buffer-modified-p nil) - (if song - (emms-player-mpd-select-song nil song) - (goto-char (point-min))))) + (with-current-emms-playlist + (setq emms-player-mpd-playlist-id id) + (set-buffer-modified-p nil) + (if song + (emms-player-mpd-select-song nil song) + (goto-char (point-min))))) (when (functionp fn) - (funcall fn close info))))) + (funcall fn close info))))) (defun emms-player-mpd-sync-from-mpd-1 (closure tracks) (let ((buffer (car closure))) (when (and tracks - (buffer-live-p buffer)) + (buffer-live-p buffer)) (let ((emms-playlist-buffer buffer)) - (with-current-emms-playlist - (emms-playlist-clear) - (mapc #'emms-playlist-insert-track tracks))) + (with-current-emms-playlist + (emms-playlist-clear) + (mapc #'emms-playlist-insert-track tracks))) (emms-player-mpd-get-status closure - #'emms-player-mpd-sync-from-mpd-2)))) + #'emms-player-mpd-sync-from-mpd-2)))) (defun emms-player-mpd-sync-from-mpd (&optional closure callback) "Synchronize the EMMS playlist with the contents of the current @@ -657,7 +657,7 @@ tracks to it that are present in the MusicPD playlist. If the current buffer is an EMMS playlist buffer, make it the main EMMS playlist buffer." (when (and emms-playlist-buffer-p - (not (eq (current-buffer) emms-playlist-buffer))) + (not (eq (current-buffer) emms-playlist-buffer))) (emms-playlist-set-playlist-buffer (current-buffer))) (with-current-emms-playlist (emms-player-mpd-get-tracks @@ -675,49 +675,49 @@ main EMMS playlist buffer." (defun emms-player-mpd-detect-song-change-1 (closure info) (ignore closure) (let ((song (emms-player-mpd-get-current-song nil #'ignore info)) - (state (emms-player-mpd-get-mpd-state nil #'ignore info)) - (time (emms-player-mpd-get-playing-time nil #'ignore info)) - (err-msg (cdr (assoc "error" info)))) + (state (emms-player-mpd-get-mpd-state nil #'ignore info)) + (time (emms-player-mpd-get-playing-time nil #'ignore info)) + (err-msg (cdr (assoc "error" info)))) (if (stringp err-msg) - (progn - (message "MusicPD error: %s" err-msg) - (emms-player-mpd-send - "clearerror" - nil #'ignore)) + (progn + (message "MusicPD error: %s" err-msg) + (emms-player-mpd-send + "clearerror" + nil #'ignore)) (cond ((string= state "stop") - (if song - ;; a track remains: the user probably stopped MusicPD - ;; manually, so we'll stop EMMS completely - (let ((emms-player-stopped-p t)) - (setq emms-player-mpd-last-state "stop") - (emms-player-stopped)) - ;; no more tracks are left: we probably ran out of things - ;; to play, so let EMMS do something further if it wants - (unless (string= emms-player-mpd-last-state "stop") - (setq emms-player-mpd-last-state "stop") - (emms-player-stopped)))) - ((and emms-player-mpd-last-state - (string= emms-player-mpd-last-state "stop")) - ;; resume from a stop that occurred outside of EMMS - (setq emms-player-mpd-last-state nil) - (emms-player-mpd-sync-from-mpd - state - #'emms-player-mpd-detect-song-change-2)) - ((string= state "pause") - nil) - ((string= state "play") - (setq emms-player-mpd-last-state "play") - (unless (or (null song) - (and (stringp emms-player-mpd-current-song) - (string= song emms-player-mpd-current-song))) - (let ((emms-player-stopped-p t)) - (emms-player-stopped)) - (emms-player-mpd-select-song emms-player-mpd-current-song song) - (setq emms-player-mpd-current-song song) - (emms-player-started 'emms-player-mpd) - (when time - (run-hook-with-args 'emms-player-time-set-functions - time)))))))) + (if song + ;; a track remains: the user probably stopped MusicPD + ;; manually, so we'll stop EMMS completely + (let ((emms-player-stopped-p t)) + (setq emms-player-mpd-last-state "stop") + (emms-player-stopped)) + ;; no more tracks are left: we probably ran out of things + ;; to play, so let EMMS do something further if it wants + (unless (string= emms-player-mpd-last-state "stop") + (setq emms-player-mpd-last-state "stop") + (emms-player-stopped)))) + ((and emms-player-mpd-last-state + (string= emms-player-mpd-last-state "stop")) + ;; resume from a stop that occurred outside of EMMS + (setq emms-player-mpd-last-state nil) + (emms-player-mpd-sync-from-mpd + state + #'emms-player-mpd-detect-song-change-2)) + ((string= state "pause") + nil) + ((string= state "play") + (setq emms-player-mpd-last-state "play") + (unless (or (null song) + (and (stringp emms-player-mpd-current-song) + (string= song emms-player-mpd-current-song))) + (let ((emms-player-stopped-p t)) + (emms-player-stopped)) + (emms-player-mpd-select-song emms-player-mpd-current-song song) + (setq emms-player-mpd-current-song song) + (emms-player-started 'emms-player-mpd) + (when time + (run-hook-with-args 'emms-player-time-set-functions + time)))))))) (defun emms-player-mpd-detect-song-change (&optional info) "Detect whether a song change has occurred. @@ -732,10 +732,10 @@ info from MusicPD." (defun emms-player-mpd-quote-file (file) "Escape special characters in FILE and surround in double-quotes." (concat "\"" - (emms-replace-regexp-in-string - "\"" "\\\\\"" - (emms-replace-regexp-in-string "\\\\" "\\\\\\\\" file)) - "\"")) + (emms-replace-regexp-in-string + "\"" "\\\\\"" + (emms-replace-regexp-in-string "\\\\" "\\\\\\\\" file)) + "\"")) ;;;###autoload (defun emms-player-mpd-clear () @@ -762,13 +762,13 @@ If an error occurs, display a relevant message." (cons file (cons callback closure)) (lambda (closure response) (let ((output (emms-player-mpd-parse-response response)) - (file (car closure)) - (callback (cadr closure)) - (close (cddr closure))) + (file (car closure)) + (callback (cadr closure)) + (close (cddr closure))) (if (car output) - (message "MusicPD error: %s: %s" file (cdar output)) - (when (functionp callback) - (funcall callback close))))))) + (message "MusicPD error: %s: %s" file (cdar output)) + (when (functionp callback) + (funcall callback close))))))) (defun emms-player-mpd-add-buffer-contents (buffer closure callback) "Load contents of BUFFER into MusicPD by adding each line. @@ -779,9 +779,9 @@ This handles both m3u and pls type playlists." (goto-char (point-min)) (let ((format (emms-source-playlist-determine-format))) (when format - (emms-player-mpd-add-several-files - (emms-source-playlist-files format) - closure callback))))) + (emms-player-mpd-add-several-files + (emms-source-playlist-files format) + closure callback))))) (defun emms-player-mpd-add-playlist (playlist closure callback) "Load contents of PLAYLIST into MusicPD by adding each line. @@ -799,30 +799,30 @@ Execute CALLBACK with CLOSURE as its first argument when done." ;; This is useful with emms-streams.el (if (fboundp 'url-insert-file-contents) (progn - (require 'emms-url) - (with-temp-buffer - (url-insert-file-contents (emms-url-quote-entire url)) - (emms-http-decode-buffer (current-buffer)) - (emms-player-mpd-add-buffer-contents (current-buffer) - closure callback))) + (require 'emms-url) + (with-temp-buffer + (url-insert-file-contents (emms-url-quote-entire url)) + (emms-http-decode-buffer (current-buffer)) + (emms-player-mpd-add-buffer-contents (current-buffer) + closure callback))) (error (message (concat "You need to install url.el so that" - " Emms can retrieve this stream"))))) + " Emms can retrieve this stream"))))) (defun emms-player-mpd-add (track closure callback) "Add TRACK to the MusicPD playlist. Execute CALLBACK with CLOSURE as its first argument when done." (let ((name (emms-track-get track 'name)) - (type (emms-track-get track 'type))) + (type (emms-track-get track 'type))) (cond ((eq type 'url) - (emms-player-mpd-add-file name closure callback)) - ((eq type 'streamlist) - (emms-player-mpd-add-streamlist name closure callback)) - ((or (eq type 'playlist) - (string-match "\\.\\(m3u\\|pls\\)\\'" name)) - (emms-player-mpd-add-playlist name closure callback)) - ((and (eq type 'file) - (string-match emms-player-mpd-supported-regexp name)) - (emms-player-mpd-add-file name closure callback))))) + (emms-player-mpd-add-file name closure callback)) + ((eq type 'streamlist) + (emms-player-mpd-add-streamlist name closure callback)) + ((or (eq type 'playlist) + (string-match "\\.\\(m3u\\|pls\\)\\'" name)) + (emms-player-mpd-add-playlist name closure callback)) + ((and (eq type 'file) + (string-match emms-player-mpd-supported-regexp name)) + (emms-player-mpd-add-file name closure callback))))) (defun emms-player-mpd-add-several-tracks (tracks closure callback) "Add TRACKS to the MusicPD playlist. @@ -850,11 +850,11 @@ Execute CALLBACK with CLOSURE as its first argument when done." "Return non-nil when we can play this track." (and (memq (emms-track-type track) '(file url playlist streamlist)) (string-match (emms-player-get emms-player-mpd 'regex) - (emms-track-name track)) + (emms-track-name track)) (condition-case nil - (progn (emms-player-mpd-ensure-process) - t) - (error nil)))) + (progn (emms-player-mpd-ensure-process) + t) + (error nil)))) (defun emms-player-mpd-play (&optional id) "Play whatever is in the current MusicPD playlist. @@ -863,19 +863,19 @@ playlist." (interactive) (if id (progn - (unless (stringp id) - (setq id (number-to-string id))) - (emms-player-mpd-send - (concat "play " id) - nil - (lambda (closure response) + (unless (stringp id) + (setq id (number-to-string id))) + (emms-player-mpd-send + (concat "play " id) + nil + (lambda (closure response) (ignore closure response) - (setq emms-player-mpd-current-song nil) - (if emms-player-mpd-check-interval - (setq emms-player-mpd-status-timer - (run-at-time t emms-player-mpd-check-interval - #'emms-player-mpd-detect-song-change)) - (emms-player-mpd-detect-song-change))))) + (setq emms-player-mpd-current-song nil) + (if emms-player-mpd-check-interval + (setq emms-player-mpd-status-timer + (run-at-time t emms-player-mpd-check-interval + #'emms-player-mpd-detect-song-change)) + (emms-player-mpd-detect-song-change))))) ;; we only want to play one track, so don't start the timer (emms-player-mpd-send "play" @@ -888,30 +888,30 @@ playlist." (when (buffer-live-p buffer) (let ((emms-playlist-buffer buffer)) (with-current-emms-playlist - (setq emms-player-mpd-playlist-id id) - (set-buffer-modified-p nil) - (let ((track-cnt 0)) - (save-excursion - (goto-char - (if (and emms-playlist-selected-marker - (marker-position emms-playlist-selected-marker)) - emms-playlist-selected-marker - (point-min))) - (condition-case nil - (while t - (emms-playlist-previous) - (setq track-cnt (1+ track-cnt))) - (error nil))) - (emms-player-mpd-play track-cnt)))))) + (setq emms-player-mpd-playlist-id id) + (set-buffer-modified-p nil) + (let ((track-cnt 0)) + (save-excursion + (goto-char + (if (and emms-playlist-selected-marker + (marker-position emms-playlist-selected-marker)) + emms-playlist-selected-marker + (point-min))) + (condition-case nil + (while t + (emms-playlist-previous) + (setq track-cnt (1+ track-cnt))) + (error nil))) + (emms-player-mpd-play track-cnt)))))) (defun emms-player-mpd-start-and-sync-1 (closure id) (ignore closure) (let ((buf-id (with-current-emms-playlist - emms-player-mpd-playlist-id))) + emms-player-mpd-playlist-id))) (if (and (not (buffer-modified-p emms-playlist-buffer)) - (stringp buf-id) - (string= buf-id id)) - (emms-player-mpd-start-and-sync-2 emms-playlist-buffer id) + (stringp buf-id) + (string= buf-id id)) + (emms-player-mpd-start-and-sync-2 emms-playlist-buffer id) (emms-player-mpd-sync-from-emms #'emms-player-mpd-start-and-sync-2)))) @@ -943,9 +943,9 @@ This is called if `emms-player-mpd-sync-playlist' is non-nil." (unless (string= state "stop") (emms-player-mpd-detect-song-change info) (when emms-player-mpd-check-interval - (setq emms-player-mpd-status-timer - (run-at-time t emms-player-mpd-check-interval - #'emms-player-mpd-detect-song-change)))))) + (setq emms-player-mpd-status-timer + (run-at-time t emms-player-mpd-check-interval + #'emms-player-mpd-detect-song-change)))))) ;;;###autoload (defun emms-player-mpd-connect () @@ -968,7 +968,7 @@ buffer get out-of-sync for some reason." "Starts a process playing TRACK." (interactive) (if (and emms-player-mpd-sync-playlist - (not (memq (emms-track-get track 'type) '(streamlist playlist)))) + (not (memq (emms-track-get track 'type) '(streamlist playlist)))) (emms-player-mpd-start-and-sync) (emms-player-mpd-clear) ;; if we have loaded the item successfully, play it @@ -1012,11 +1012,11 @@ from other functions." amount (lambda (amount info) (let ((song (emms-player-mpd-get-current-song nil #'ignore info)) - (secs (emms-player-mpd-get-playing-time nil #'ignore info))) + (secs (emms-player-mpd-get-playing-time nil #'ignore info))) (when (and song secs) - (emms-player-mpd-send - (concat "seek " song " " (number-to-string (round (+ secs amount)))) - nil #'ignore)))))) + (emms-player-mpd-send + (concat "seek " song " " (number-to-string (round (+ secs amount)))) + nil #'ignore)))))) (defun emms-player-mpd-seek-to (pos) "Seek to POS seconds from the start of the current track." @@ -1026,8 +1026,8 @@ from other functions." (lambda (pos song) (when (and song pos) (emms-player-mpd-send - (concat "seek " song " " (number-to-string (round pos))) - nil #'ignore))))) + (concat "seek " song " " (number-to-string (round pos))) + nil #'ignore))))) (defun emms-player-mpd-next () "Move forward by one track in MusicPD's internal playlist." @@ -1050,57 +1050,57 @@ positive or negative." (lambda (change volume) (let ((new-volume (+ (string-to-number volume) change))) (emms-player-mpd-send - (concat "setvol \"" (number-to-string new-volume) "\"") - nil #'ignore))))) + (concat "setvol \"" (number-to-string new-volume) "\"") + nil #'ignore))))) ;;; Now playing (defun emms-player-mpd-show-1 (closure response) (let* ((info (emms-player-mpd-get-alist - (emms-player-mpd-parse-response response))) - (insertp (car closure)) - (callback (cadr closure)) - (buffer (cddr closure)) - (name (cdr (assoc "name" info))) ; radio feeds sometimes set this - (file (cdr (assoc "file" info))) - (desc nil)) + (emms-player-mpd-parse-response response))) + (insertp (car closure)) + (callback (cadr closure)) + (buffer (cddr closure)) + (name (cdr (assoc "name" info))) ; radio feeds sometimes set this + (file (cdr (assoc "file" info))) + (desc nil)) ;; if we are playing lastfm radio, use its show function instead (if (and (boundp 'emms-lastfm-radio-stream-url) - (stringp emms-lastfm-radio-stream-url) - (string= emms-lastfm-radio-stream-url file)) - (with-current-buffer buffer - (and (fboundp 'emms-lastfm-np) - (emms-lastfm-np insertp callback))) + (stringp emms-lastfm-radio-stream-url) + (string= emms-lastfm-radio-stream-url file)) + (with-current-buffer buffer + (and (fboundp 'emms-lastfm-np) + (emms-lastfm-np insertp callback))) ;; otherwise build and show the description (when info - (when name - (setq desc name)) - (when file - (let ((track (emms-dictionary '*track*)) - track-desc) - (if (string-match "\\`http://" file) - (emms-track-set track 'type 'url) - (emms-track-set track 'type 'file)) - (emms-track-set track 'name file) - (emms-info-mpd track info) - (run-hook-with-args 'emms-track-info-filters track) - (setq track-desc (emms-track-description track)) - (when (and (stringp track-desc) (not (string= track-desc ""))) - (setq desc (if desc - (concat desc ": " track-desc) - track-desc)))))) + (when name + (setq desc name)) + (when file + (let ((track (emms-dictionary '*track*)) + track-desc) + (if (string-match "\\`http://" file) + (emms-track-set track 'type 'url) + (emms-track-set track 'type 'file)) + (emms-track-set track 'name file) + (emms-info-mpd track info) + (run-hook-with-args 'emms-track-info-filters track) + (setq track-desc (emms-track-description track)) + (when (and (stringp track-desc) (not (string= track-desc ""))) + (setq desc (if desc + (concat desc ": " track-desc) + track-desc)))))) (if (not desc) - (unless (functionp callback) - (message "Nothing playing right now")) - (setq desc (format emms-show-format desc)) - (cond ((functionp callback) - (funcall callback buffer desc)) - (insertp - (when (buffer-live-p buffer) - (with-current-buffer buffer - (insert desc)))) - (t - (message "%s" desc))))))) + (unless (functionp callback) + (message "Nothing playing right now")) + (setq desc (format emms-show-format desc)) + (cond ((functionp callback) + (funcall callback buffer desc)) + (insertp + (when (buffer-live-p buffer) + (with-current-buffer buffer + (insert desc)))) + (t + (message "%s" desc))))))) ;;;###autoload (defun emms-player-mpd-show (&optional insertp callback) @@ -1118,34 +1118,34 @@ It differs from `emms-show' in that it asks MusicPD for the current track, rather than EMMS." (interactive "P") (emms-player-mpd-send "currentsong" - (cons insertp (cons callback (current-buffer))) - #'emms-player-mpd-show-1)) + (cons insertp (cons callback (current-buffer))) + #'emms-player-mpd-show-1)) ;;; Track info (defun emms-info-mpd-process (track info) (dolist (data info) (let ((name (car data)) - (value (cdr data))) + (value (cdr data))) (setq name (cond ((string= name "artist") 'info-artist) - ((string= name "composer") 'info-composer) - ((string= name "performer") 'info-performer) - ((string= name "title") 'info-title) - ((string= name "album") 'info-album) - ((string= name "track") 'info-tracknumber) - ((string= name "disc") 'info-discnumber) - ((string= name "date") 'info-year) - ((string= name "genre") 'info-genre) - ((string= name "time") - (setq value (string-to-number value)) - 'info-playing-time) - (t nil))) + ((string= name "composer") 'info-composer) + ((string= name "performer") 'info-performer) + ((string= name "title") 'info-title) + ((string= name "album") 'info-album) + ((string= name "track") 'info-tracknumber) + ((string= name "disc") 'info-discnumber) + ((string= name "date") 'info-year) + ((string= name "genre") 'info-genre) + ((string= name "time") + (setq value (string-to-number value)) + 'info-playing-time) + (t nil))) (when name - (emms-track-set track name value))))) + (emms-track-set track name value))))) (defun emms-info-mpd-1 (track response) (let ((info (emms-player-mpd-get-alist - (emms-player-mpd-parse-response response)))) + (emms-player-mpd-parse-response response)))) (when info (emms-info-mpd-process track info) (emms-track-updated track)))) @@ -1159,18 +1159,18 @@ This is a useful addition to `emms-info-functions'." (if info (emms-info-mpd-process track info) (when (and (emms-track-file-p track) - (not (string-match "\\`http://" (emms-track-name track)))) + (not (string-match "\\`http://" (emms-track-name track)))) (let ((file (emms-player-mpd-get-mpd-filename (emms-track-name track)))) - (when (or emms-player-mpd-music-directory - (and file - (string-match emms-player-mpd-supported-regexp file))) - (condition-case nil - (emms-player-mpd-send - (concat "find filename " - (emms-player-mpd-quote-file file)) - track - #'emms-info-mpd-1) - (error nil))))))) + (when (or emms-player-mpd-music-directory + (and file + (string-match emms-player-mpd-supported-regexp file))) + (condition-case nil + (emms-player-mpd-send + (concat "find filename " + (emms-player-mpd-quote-file file)) + track + #'emms-info-mpd-1) + (error nil))))))) ;;; Caching @@ -1180,20 +1180,20 @@ This is a useful addition to `emms-info-functions'." The track should be an alist as per `emms-player-mpd-get-alist'." (when emms-cache-set-function (let ((track (emms-dictionary '*track*)) - (name (cdr (assoc "file" track-info)))) + (name (cdr (assoc "file" track-info)))) (when name - (setq name (emms-player-mpd-get-emms-filename name)) - (emms-track-set track 'type 'file) - (emms-track-set track 'name name) - (emms-info-mpd-process track track-info) - (funcall emms-cache-set-function 'file name track))))) + (setq name (emms-player-mpd-get-emms-filename name)) + (emms-track-set track 'type 'file) + (emms-track-set track 'name name) + (emms-info-mpd-process track track-info) + (funcall emms-cache-set-function 'file name track))))) (defun emms-cache--info-cleanup (info) (let ((xs (mapcar (lambda (x) - (and (stringp x) - (not (string-match-p "\\`\\(Last-\\|direct\\)" x)) - x)) - info))) + (and (stringp x) + (not (string-match-p "\\`\\(Last-\\|direct\\)" x)) + x)) + info))) (cons nil (delq nil xs)))) (defun emms-cache-set-from-mpd-directory (dir) @@ -1202,32 +1202,32 @@ The track should be an alist as per `emms-player-mpd-get-alist'." This is useful to do when you have recently acquired new music." (interactive (list (if emms-player-mpd-music-directory - (emms-read-directory-name "Directory: " - emms-player-mpd-music-directory) - (read-string "Directory: ")))) + (emms-read-directory-name "Directory: " + emms-player-mpd-music-directory) + (read-string "Directory: ")))) (unless (string= dir "") (setq dir (emms-player-mpd-get-mpd-filename dir))) (if emms-cache-set-function (progn - (message "Dumping MusicPD data to cache...") - (emms-player-mpd-send - (concat "listallinfo " dir) - nil - (lambda (closure response) + (message "Dumping MusicPD data to cache...") + (emms-player-mpd-send + (concat "listallinfo " dir) + nil + (lambda (closure response) (ignore closure response) - (message "Dumping MusicPD data to cache...processing") - (let ((info (emms-player-mpd-parse-response response))) - (when (null (car info)) - (let* ((info (emms-cache--info-cleanup info)) - (info (emms-player-mpd-get-alists info)) - (track 1) - (total (length info))) - (dolist (track-info info) - (message "Dumping MusicPD data to cache...%d/%d" track total) - (emms-cache-set-from-mpd-track track-info) - (setq track (+ 1 track))) - (message "Dumping MusicPD data to cache... %d tracks processed" - total))))))) + (message "Dumping MusicPD data to cache...processing") + (let ((info (emms-player-mpd-parse-response response))) + (when (null (car info)) + (let* ((info (emms-cache--info-cleanup info)) + (info (emms-player-mpd-get-alists info)) + (track 1) + (total (length info))) + (dolist (track-info info) + (message "Dumping MusicPD data to cache...%d/%d" track total) + (emms-cache-set-from-mpd-track track-info) + (setq track (+ 1 track))) + (message "Dumping MusicPD data to cache... %d tracks processed" + total))))))) (error "Caching is not enabled"))) (defun emms-cache-set-from-mpd-all () @@ -1244,9 +1244,9 @@ order to prime the cache." "Cause the tracks in DIR to be updated in the MusicPD database." (interactive (list (if emms-player-mpd-music-directory - (emms-read-directory-name "Directory: " - emms-player-mpd-music-directory) - (read-string "Directory: ")))) + (emms-read-directory-name "Directory: " + emms-player-mpd-music-directory) + (read-string "Directory: ")))) (unless (string= dir "") (setq dir (emms-player-mpd-get-mpd-filename dir))) (emms-player-mpd-send @@ -1254,11 +1254,11 @@ order to prime the cache." (lambda (closure response) (ignore closure) (let ((id (cdr (assoc "updating_db" - (emms-player-mpd-get-alist - (emms-player-mpd-parse-response response)))))) + (emms-player-mpd-get-alist + (emms-player-mpd-parse-response response)))))) (if id - (message "Updating DB with ID %s" id) - (message "Could not update the DB")))))) + (message "Updating DB with ID %s" id) + (message "Could not update the DB")))))) (defun emms-player-mpd-update-all () "Cause all tracks in the MusicPD music directory to be updated in |