Directly use empc-object in several functions.

This commit is contained in:
Renaud Casenave-Péré 2011-08-25 12:59:37 +09:00
parent 3962b7de8f
commit 5671d41659

207
empc.el
View file

@ -186,7 +186,8 @@ SERVICE is the name of the service desired, or an integer specifying
(defun empc-process-sentinel (proc event) (defun empc-process-sentinel (proc event)
"Process sentinel for `empc-process'." "Process sentinel for `empc-process'."
(let ((status (process-status proc))) (let ((debug-on-error t)
(status (process-status proc)))
(cond ((eq status 'closed) (cond ((eq status 'closed)
(when empc-verbose (when empc-verbose
(message "empc: connection closed")))))) (message "empc: connection closed"))))))
@ -235,14 +236,15 @@ SERVICE is the name of the service desired, or an integer specifying
(empc-queue-pop object)) (empc-queue-pop object))
(empc-process-buffer object)))) (empc-process-buffer object))))
(defun empc-stream-process-sentinel (object event) (defun empc-stream-process-sentinel (proc event)
"Process sentinel for `empc-stream-process'." "Process sentinel for `empc-stream-process'."
(let ((process (empc-process object))) (let ((debug-on-error t)
(process (empc-process empc-object)))
(when (and (eq (process-status proc) 'exit) (when (and (eq (process-status proc) 'exit)
process process
(processp process) (processp process)
(eq (process-status process) 'open) (eq (process-status process) 'open)
(eq (empc-status-get object :state) 'play)) (eq (empc-status-get empc-object :state) 'play))
(empc-toggle-pause 1))) (empc-toggle-pause 1)))
(setq empc-stream-process nil)) (setq empc-stream-process nil))
@ -262,14 +264,13 @@ SERVICE is the name of the service desired, or an integer specifying
(defun empc-echo-song (&optional song) (defun empc-echo-song (&optional song)
"Notify SONG in the echo area." "Notify SONG in the echo area."
(interactive) (interactive)
(let ((object empc-object)) (unless song
(unless song (setq song (empc-current-song empc-object)))
(setq song (empc-current-song object))) (empc-echo-notify (concat "[" (int-to-string (+ (plist-get song :pos) 1))
(empc-echo-notify (concat "[" (int-to-string (+ (plist-get song :pos) 1)) "/" (int-to-string (empc-status-get empc-object :playlistlength)) "] "
"/" (int-to-string (empc-status-get object :playlistlength)) "] " (if (and (plist-get song :artist) (plist-get song :title))
(if (and (plist-get song :artist) (plist-get song :title)) (concat (plist-get song :artist) " - " (plist-get song :title))
(concat (plist-get song :artist) " - " (plist-get song :title)) (plist-get song :file)))))
(plist-get song :file))))))
(defun empc-mode-line-notify (msg) (defun empc-mode-line-notify (msg)
"Change the string to write in the mode-line and force-update it." "Change the string to write in the mode-line and force-update it."
@ -278,14 +279,13 @@ SERVICE is the name of the service desired, or an integer specifying
(defun empc-mode-line-song (&optional song) (defun empc-mode-line-song (&optional song)
"Notify SONG in the mode-line." "Notify SONG in the mode-line."
(let ((object empc-object)) (unless song
(unless song (setq song (empc-current-song empc-object)))
(setq song (empc-current-song object))) (empc-mode-line-notify (concat "[" (int-to-string (+ (plist-get song :pos) 1))
(empc-mode-line-notify (concat "[" (int-to-string (+ (plist-get song :pos) 1)) "/" (int-to-string (empc-status-get empc-object :playlistlength)) "] "
"/" (int-to-string (empc-status-get object :playlistlength)) "] " (if (and (plist-get song :artist) (plist-get song :title))
(if (and (plist-get song :artist) (plist-get song :title)) (concat (plist-get song :artist) " - " (plist-get song :title))
(concat (plist-get song :artist) " - " (plist-get song :title)) (plist-get song :file)))))
(plist-get song :file))))))
(defun empc-response-parse-line (line) (defun empc-response-parse-line (line)
"Turn the given line into a cons cell. "Turn the given line into a cons cell.
@ -322,11 +322,10 @@ form '('error (error-code . error-message))."
(defun empc-response-get-commands (data) (defun empc-response-get-commands (data)
"Parse DATA to get the available commands." "Parse DATA to get the available commands."
(let ((object empc-object) (let ((commands))
(commands))
(dolist (cell data) (dolist (cell data)
(setq commands (cons (cdr cell) commands))) (setq commands (cons (cdr cell) commands)))
(empc-commands-set object commands))) (empc-commands-set empc-object commands)))
(defun empc-status-on/off-stringify (status key) (defun empc-status-on/off-stringify (status key)
"Return `on' or `off' if KEY is active or inactive in STATUS." "Return `on' or `off' if KEY is active or inactive in STATUS."
@ -338,31 +337,30 @@ form '('error (error-code . error-message))."
According to what is in the diff, several actions can be performed: According to what is in the diff, several actions can be performed:
if :state or :songid is changed, report it to the user, if :state or :songid is changed, report it to the user,
if :state is set to 'play, start the streaming process." if :state is set to 'play, start the streaming process."
(let ((object empc-object) (let ((status-diff (empc-diff-status data))
(status-diff (empc-diff-status data))
(notify nil)) (notify nil))
(when (plist-get status-diff :songid) (when (plist-get status-diff :songid)
(setq notify '(lambda () (when (empc-playlist-songs object) (setq notify '(lambda () (when (empc-playlist-songs empc-object)
(empc-mode-line-song (gethash (plist-get status-diff :songid) (empc-mode-line-song (gethash (plist-get status-diff :songid)
(empc-playlist-songs object)))))) (empc-playlist-songs empc-object))))))
(empc-playlist-goto-current-song)) (empc-playlist-goto-current-song))
(when (plist-get status-diff :state) (when (plist-get status-diff :state)
(if (eq (plist-get status-diff :state) 'play) (if (eq (plist-get status-diff :state) 'play)
(progn (progn
(unless notify (unless notify
(setq notify '(lambda () (when (empc-playlist-songs object) (setq notify '(lambda () (when (empc-playlist-songs empc-object)
(empc-mode-line-song))))) (empc-mode-line-song)))))
(empc-stream-start object)) (empc-stream-start))
(setq notify '(lambda () (empc-mode-line-notify (symbol-name (plist-get status-diff :state))))))) (setq notify '(lambda () (empc-mode-line-notify (symbol-name (plist-get status-diff :state)))))))
(when (or (plist-member status-diff :repeat) (plist-member status-diff :random) (when (or (plist-member status-diff :repeat) (plist-member status-diff :random)
(plist-member status-diff :single) (plist-member status-diff :consume) (plist-member status-diff :single) (plist-member status-diff :consume)
(plist-member status-diff :xfade)) (plist-member status-diff :xfade))
(setq notify '(lambda () (empc-echo-notify (format "repeat: %s, random: %s, single: %s, consume: %s, crossfade: %s" (setq notify '(lambda () (empc-echo-notify (format "repeat: %s, random: %s, single: %s, consume: %s, crossfade: %s"
(empc-status-on/off-stringify (empc-status object) :repeat) (empc-status-on/off-stringify (empc-status empc-object) :repeat)
(empc-status-on/off-stringify (empc-status object) :random) (empc-status-on/off-stringify (empc-status empc-object) :random)
(empc-status-on/off-stringify (empc-status object) :single) (empc-status-on/off-stringify (empc-status empc-object) :single)
(empc-status-on/off-stringify (empc-status object) :consume) (empc-status-on/off-stringify (empc-status empc-object) :consume)
(empc-status-on/off-stringify (empc-status object) :xfade)))))) (empc-status-on/off-stringify (empc-status empc-object) :xfade))))))
(when notify (when notify
(funcall notify)))) (funcall notify))))
@ -383,65 +381,61 @@ According to what is in the diff, several actions can be performed:
(defun empc-diff-status (data) (defun empc-diff-status (data)
"Get the diff from `empc-current-status' and server response." "Get the diff from `empc-current-status' and server response."
(let ((object empc-object) (let ((status-diff nil)
(status-diff nil)
(attributes '(:volume :repeat :random :single :consume :playlist :playlistlength :state (attributes '(:volume :repeat :random :single :consume :playlist :playlistlength :state
:song :songid :nextsong :nextsongid :time :elapsed :bitrate :xfade :song :songid :nextsong :nextsongid :time :elapsed :bitrate :xfade
:mixrampdb :mixrampdelay :audio :updating_db :error))) :mixrampdb :mixrampdelay :audio :updating_db :error)))
(dolist (attr attributes status-diff) (dolist (attr attributes status-diff)
(let ((value (empc-parse-status-attr attr (cdr (assoc (substring (symbol-name attr) 1) data))))) (let ((value (empc-parse-status-attr attr (cdr (assoc (substring (symbol-name attr) 1) data)))))
(unless (equal (empc-status-get object attr) value) (unless (equal (empc-status-get empc-object attr) value)
(setq status-diff (plist-put status-diff attr value)) (setq status-diff (plist-put status-diff attr value))
(empc-status-put object attr value)))))) (empc-status-put empc-object attr value))))))
(defun empc-playlist-goto-current-song () (defun empc-playlist-goto-current-song ()
"Put point at currently playing song." "Put point at currently playing song."
(interactive) (interactive)
(let ((object empc-object)) (when (get-buffer "*empc*")
(when (get-buffer "*empc*") (let ((buffer nil))
(let ((buffer nil)) (unless (called-interactively-p)
(unless (called-interactively-p) (dolist (frame (frame-list))
(dolist (frame (frame-list)) (with-selected-frame frame
(with-selected-frame frame (let ((bwindow (get-buffer-window "*empc*")))
(let ((bwindow (get-buffer-window "*empc*"))) (when bwindow
(when bwindow (with-selected-window bwindow
(with-selected-window bwindow (goto-char (point-min))
(goto-char (point-min)) (forward-line (empc-status-get empc-object :song))
(forward-line (empc-status-get object :song)) (when (and (not buffer) empc-may-pulse)
(when (and (not buffer) empc-may-pulse) (pulse-momentary-highlight-one-line (point))))
(pulse-momentary-highlight-one-line (point)))) (setq buffer bwindow))))))
(setq buffer bwindow)))))) (unless buffer
(unless buffer (with-current-buffer "*empc*"
(with-current-buffer "*empc*" (goto-char (point-min))
(goto-char (point-min)) (forward-line (empc-status-get empc-object :song))
(forward-line (empc-status-get object :song)) (when (and (called-interactively-p) empc-may-pulse)
(when (and (called-interactively-p) empc-may-pulse) (pulse-momentary-highlight-one-line (point))))))))
(pulse-momentary-highlight-one-line (point)))))))))
(defun empc-populate-playlist-buffer () (defun empc-populate-playlist-buffer ()
"Write playlist into the *empc* buffer." "Write playlist into the *empc* buffer."
(let ((object empc-object)) (save-window-excursion
(save-window-excursion (empc-switch-to-playlist)
(empc-switch-to-playlist) (let ((buffer-read-only nil))
(let ((buffer-read-only nil)) (erase-buffer)
(erase-buffer) (when (empc-playlist-songs empc-object)
(when (empc-playlist-songs object) (dotimes (pos (length (empc-playlist empc-object)))
(dotimes (pos (length (empc-playlist object))) (let ((song (empc-song empc-object pos)))
(let ((song (empc-song object pos))) (insert (if (and (plist-member song :artist) (plist-member song :title))
(insert (if (and (plist-member song :artist) (plist-member song :title)) (concat (plist-get song :artist) " - " (plist-get song :title))
(concat (plist-get song :artist) " - " (plist-get song :title)) (plist-get song :file)) "\n"))))))
(plist-get song :file)) "\n")))))) (empc-playlist-goto-current-song))
(empc-playlist-goto-current-song)))
(defun empc-response-get-playlist (data) (defun empc-response-get-playlist (data)
"Parse information regarding songs in current playlist and arrange it into a "Parse information regarding songs in current playlist and arrange it into a
hash table `empc-current-playlist-songs'sorted by songid. hash table `empc-current-playlist-songs'sorted by songid.
songs order is kept into an avector `empc-current-playlist'." songs order is kept into an avector `empc-current-playlist'."
(let* ((object empc-object) (let* ((playlist-songs (make-hash-table :rehash-threshold 1.0 :size (empc-status-get empc-object :playlistlength)))
(playlist-songs (make-hash-table :rehash-threshold 1.0 :size (empc-status-get object :playlistlength))) (playlist (make-vector (empc-status-get empc-object :playlistlength) nil))
(playlist (make-vector (empc-status-get object :playlistlength) nil)) (song nil)
(song nil) (index (- (length playlist) 1)))
(index (- (length playlist) 1)))
(dolist (cell data) (dolist (cell data)
(let ((field (intern (concat ":" (car cell))))) (let ((field (intern (concat ":" (car cell)))))
(when (and (eq field :id) song) (when (and (eq field :id) song)
@ -458,8 +452,8 @@ songs order is kept into an avector `empc-current-playlist'."
(when (and song (>= index 0)) (when (and song (>= index 0))
(puthash (plist-get song :id) song playlist-songs) (puthash (plist-get song :id) song playlist-songs)
(aset playlist index (plist-get song :id))) (aset playlist index (plist-get song :id)))
(empc-playlist-set object playlist) (empc-playlist-set empc-object playlist)
(empc-playlist-songs-set object playlist-songs)) (empc-playlist-songs-set empc-object playlist-songs))
(empc-populate-playlist-buffer)) (empc-populate-playlist-buffer))
(defun empc-response-idle (data) (defun empc-response-idle (data)
@ -513,11 +507,11 @@ ARG is nil."
(setq global-mode-string (append global-mode-string '(empc-mode-line-string))) (setq global-mode-string (append global-mode-string '(empc-mode-line-string)))
(setq global-mode-string (remove 'empc-mode-line-string global-mode-string)))) (setq global-mode-string (remove 'empc-mode-line-string global-mode-string))))
(defun empc-initialize (object) (defun empc-initialize ()
"Initialize the client after connection. "Initialize the client after connection.
Send the password or retrieve available commands." Send the password or retrieve available commands."
(empc-send-list object (when empc-server-password (empc-send-list (when empc-server-password
`(,(concat "password " empc-server-password))) `(,(concat "password " empc-server-password)))
'("commands" . empc-response-get-commands) '("commands" . empc-response-get-commands)
'("status" . empc-response-get-status) '("status" . empc-response-get-status)
'("playlistinfo" . empc-response-get-playlist)) '("playlistinfo" . empc-response-get-playlist))
@ -532,7 +526,7 @@ Send the password or retrieve available commands."
(processp process) (processp process)
(eq (process-status process) 'open)) (eq (process-status process) 'open))
(setq empc-object (empc-create "empc" empc-buffer-name empc-server-host empc-server-port)) (setq empc-object (empc-create "empc" empc-buffer-name empc-server-host empc-server-port))
(empc-initialize empc-object)))) (empc-initialize))))
(defun empc-bury-buffers () (defun empc-bury-buffers ()
"Bury all empc related buffers." "Bury all empc related buffers."
@ -579,17 +573,17 @@ enter idle state to accept notifications from the server."
(process-send-string (empc-process empc-object) "noidle\n") (process-send-string (empc-process empc-object) "noidle\n")
(setq empc-idle-state nil))) (setq empc-idle-state nil)))
(defun empc-send (object command &optional closure handler) (defun empc-send (command &optional closure handler)
"Send COMMAND to the mpd server. "Send COMMAND to the mpd server.
CLOSURE will be called on the parsed response." CLOSURE will be called on the parsed response."
(empc-ensure-connected) (empc-ensure-connected)
(empc-leave-idle-state) (empc-leave-idle-state)
(unless (string= (substring command -1) "\n") (unless (string= (substring command -1) "\n")
(setq command (concat command "\n"))) (setq command (concat command "\n")))
(empc-queue-push object command closure (empc-queue-push empc-object command closure
(if handler handler 'empc-handle-response))) (if handler handler 'empc-handle-response)))
(defun empc-send-list (object &rest commands) (defun empc-send-list (&rest commands)
"Send COMMANDS to the mpd server using command_list. "Send COMMANDS to the mpd server using command_list.
COMMANDS is a list of cons of the form: '(COMMAND . CLOSURE), COMMANDS is a list of cons of the form: '(COMMAND . CLOSURE),
where CLOSURE (may be a list of functions) will be called on the parsed response." where CLOSURE (may be a list of functions) will be called on the parsed response."
@ -599,17 +593,16 @@ where CLOSURE (may be a list of functions) will be called on the parsed response
(setq command (concat command (car cell) "\n")) (setq command (concat command (car cell) "\n"))
(setq closures (cons (cdr cell) closures)))) (setq closures (cons (cdr cell) closures))))
(setq command (concat command "command_list_end\n")) (setq command (concat command "command_list_end\n"))
(empc-send object command closures 'empc-handle-response-list))) (empc-send command closures 'empc-handle-response-list)))
(defun empc-stream-start (object) (defun empc-stream-start ()
"Start the stream process if the command to mpd returned successfully. "Start the stream process if the command to mpd returned successfully.
If the stream process is killed for whatever the reason, pause mpd if possible." If the stream process is killed for whatever the reason, pause mpd if possible."
(let ((stream-process (empc-stream object))) (let ((stream-process (empc-stream empc-object)))
(when (and (not stream-process) (when (and (not stream-process)
empc-stream-url empc-stream-program) empc-stream-url empc-stream-program)
(setq stream-process (start-process "empc-stream" nil empc-stream-program empc-stream-url)) (setq stream-process (start-process "empc-stream" nil empc-stream-program empc-stream-url))
(set-process-sentinel stream-process `(lambda (proc event) (set-process-sentinel stream-process 'empc-stream-process-sentinel)
(empc-stream-process-sentinel ',object event)))
(setq empc-stream-process stream-process)))) (setq empc-stream-process stream-process))))
(defun empc-playlist-mode () (defun empc-playlist-mode ()
@ -628,21 +621,20 @@ If the stream process is killed for whatever the reason, pause mpd if possible."
(switch-to-buffer "*empc*"))) (switch-to-buffer "*empc*")))
(empc-playlist-mode)) (empc-playlist-mode))
(defmacro with-updated-status (object &rest body) (defmacro with-updated-status (&rest body)
"Update the status and execute the forms in BODY." "Update the status and execute the forms in BODY."
`(if (empc-status empc-object) `(if (empc-status empc-object)
,@body ,@body
(empc-send object "status\n" '(empc-response-get-status (lambda (data) ,@body))))) (empc-send "status\n" '(empc-response-get-status (lambda (data) ,@body)))))
(defmacro empc-define-simple-command (command &optional closure) (defmacro empc-define-simple-command (command &optional closure)
"Define a simple command that doesn't need an argument." "Define a simple command that doesn't need an argument."
`(defun ,(intern (concat "empc-send-" command)) (&optional arg) `(defun ,(intern (concat "empc-send-" command)) (&optional arg)
,(concat "Send " command " to the server.") ,(concat "Send " command " to the server.")
(interactive) (interactive)
(let ((debug-on-error t) (let ((debug-on-error t))
(object empc-object))
(empc-leave-idle-state) (empc-leave-idle-state)
(empc-send object (concat ,command (when arg (concat " " (if (stringp arg) (empc-send (concat ,command (when arg (concat " " (if (stringp arg)
arg (number-to-string arg)))) "\n") arg (number-to-string arg)))) "\n")
,closure)))) ,closure))))
@ -651,20 +643,19 @@ If the stream process is killed for whatever the reason, pause mpd if possible."
`(defun ,(intern (concat "empc-toggle-" command)) (&optional state) `(defun ,(intern (concat "empc-toggle-" command)) (&optional state)
,(concat "Toggle " command ".") ,(concat "Toggle " command ".")
(interactive) (interactive)
(let ((debug-on-error t) (let ((debug-on-error t))
(object empc-object))
(empc-leave-idle-state) (empc-leave-idle-state)
(if state (if state
(empc-send object (concat ,(concat command " ") (int-to-string state) "\n")) (empc-send (concat ,(concat command " ") (int-to-string state) "\n"))
(with-updated-status object (with-updated-status
(let ((,(if attr attr (let ((,(if attr attr
(intern command)) (intern command))
(empc-status-get object (quote ,(intern (concat ":" (if state-name (empc-status-get empc-object (quote ,(intern (concat ":" (if state-name
state-name state-name
command))))))) command)))))))
,(if body ,(if body
`(progn ,@body) `(progn ,@body)
`(empc-send object (concat ,command (if (= ,(if attr attr `(empc-send (concat ,command (if (= ,(if attr attr
(intern command)) 1) " 0" " 1") "\n"))))))))) (intern command)) 1) " 0" " 1") "\n")))))))))
(defmacro empc-define-command-with-pos (command &optional closure) (defmacro empc-define-command-with-pos (command &optional closure)
@ -674,25 +665,23 @@ computed using point in buffer."
,(concat "Send " command " to the server together with an ID ,(concat "Send " command " to the server together with an ID
parameter computed using pos or cursor position.") parameter computed using pos or cursor position.")
(interactive) (interactive)
(let ((debug-on-error t) (let ((debug-on-error t))
(object empc-object))
(empc-leave-idle-state) (empc-leave-idle-state)
(unless pos (unless pos
(setq pos (count-lines (point-min) (point)))) (setq pos (count-lines (point-min) (point))))
(let ((id (elt (empc-playlist object) pos))) (let ((id (elt (empc-playlist empc-object) pos)))
(empc-send object (concat ,(concat command "id ") (number-to-string id) "\n") ,closure))))) (empc-send (concat ,(concat command "id ") (number-to-string id) "\n") ,closure)))))
(defmacro empc-define-command-with-current-id (command &optional closure) (defmacro empc-define-command-with-current-id (command &optional closure)
"Define a command that uses the current song as a parameter." "Define a command that uses the current song as a parameter."
`(defun ,(intern (concat "empc-send-" command)) (&optional arg) `(defun ,(intern (concat "empc-send-" command)) (&optional arg)
,(concat "Send " command " to the server with the ID of the currently playing song.") ,(concat "Send " command " to the server with the ID of the currently playing song.")
(interactive) (interactive)
(let ((debug-on-error t) (let ((debug-on-error t))
(object empc-object))
(empc-leave-idle-state) (empc-leave-idle-state)
(empc-send object (concat ,(concat command "id ") (empc-send (concat ,(concat command "id ")
(number-to-string (empc-status-get object :songid)) (number-to-string (empc-status-get empc-object :songid))
(when arg (concat " " (if (stringp arg) arg (number-to-string arg)))) "\n") (when arg (concat " " (if (stringp arg) arg (number-to-string arg)))) "\n")
,closure)))) ,closure))))
;; Querying MPD's status ;; Querying MPD's status