;;; mpc.el --- A client for the Music Player Daemon -*- coding: utf-8; lexical-binding: t -*-
-;; Copyright (C) 2006-2013 Free Software Foundation, Inc.
+;; Copyright (C) 2006-2014 Free Software Foundation, Inc.
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Keywords: multimedia
(defconst mpc--proc-end-re "^\\(?:OK\\(?: MPD .*\\)?\\|ACK \\(.*\\)\\)\n")
-(put 'mpc-proc-error 'error-conditions '(mpc-proc-error error))
-(put 'mpc-proc-error 'error-message "MPD error")
+(define-error 'mpc-proc-error "MPD error")
(defun mpc--debug (format &rest args)
(if (get-buffer "*MPC-debug*")
(if tmp (push (nreverse tmp) alists))
(nreverse alists)))
-(defun mpc-proc ()
+(defun mpc-proc (&optional restart)
(unless (and mpc-proc
(buffer-live-p (process-buffer mpc-proc))
- (not (memq (process-status mpc-proc) '(closed))))
+ (not (and restart
+ (memq (process-status mpc-proc) '(closed)))))
(mpc--proc-connect mpc-host))
mpc-proc)
when the command terminates.
CMD can be a string which is passed as-is to MPD or a list of strings
which will be concatenated with proper quoting before passing them to MPD."
- (let ((proc (mpc-proc)))
+ (let ((proc (mpc-proc 'restart)))
(if (and callback (not (process-get proc 'ready)))
(let ((old (process-get proc 'callback)))
(process-put proc 'callback
(cancel-timer mpc--status-timer)
(setq mpc--status-timer nil)))
(defun mpc--status-timer-run ()
- (when (process-get (mpc-proc) 'ready)
- (condition-case err
- (with-local-quit (mpc-status-refresh))
- (error (message "MPC: %s" err)))))
+ (with-demoted-errors "MPC: %S"
+ (when (process-get (mpc-proc) 'ready)
+ (let* ((buf (mpc-proc-buffer (mpc-proc) 'status))
+ (win (get-buffer-window buf t)))
+ (if (not win)
+ (mpc--status-timer-stop)
+ (with-local-quit (mpc-status-refresh)))))))
(defvar mpc--status-idle-timer nil)
(defun mpc--status-idle-timer-start ()
;; client starts playback, we may get a chance to notice it.
(run-with-idle-timer 10 t 'mpc--status-idle-timer-run))))
(defun mpc--status-idle-timer-run ()
- (when (process-get (mpc-proc) 'ready)
- (condition-case err
- (with-local-quit (mpc-status-refresh))
- (error (message "MPC: %s" err))))
- (mpc--status-timer-start))
+ (mpc--status-timer-start)
+ (mpc--status-timer-run))
(defun mpc--status-timers-refresh ()
"Start/stop the timers according to whether a song is playing."
(`Cover
(let* ((dir (file-name-directory (cdr (assq 'file info))))
(cover (concat dir "cover.jpg"))
- (file (condition-case err
- (mpc-file-local-copy cover)
- (error (message "MPC: %s" err))))
+ (file (with-demoted-errors "MPC: %s"
+ (mpc-file-local-copy cover)))
image)
;; (debug)
(push `(equal ',dir (file-name-directory (cdr (assq 'file info)))) pred)
(when (and (null val) (eq tag 'Title))
(setq val (cdr (assq 'file info))))
(push `(equal ',val (cdr (assq ',tag info))) pred)
- val)))))
+ (cond
+ ((not (and (eq tag 'Date) (stringp val))) val)
+ ;; For "date", only keep the year!
+ ((string-match "[0-9]\\{4\\}" val)
+ (match-string 0 val))
+ (t val)))))))
(space (when size
(setq size (string-to-number size))
(propertize " " 'display
"Major mode for the features common to all buffers of MPC."
(buffer-disable-undo)
(setq buffer-read-only t)
- (setq-local tool-bar-map mpc-tool-bar-map)
+ (if (boundp 'tool-bar-map) ; not if --without-x
+ (setq-local tool-bar-map mpc-tool-bar-map))
(setq-local truncate-lines t))
;;; The mpc-status-mode buffer ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mpc-status-buffer-show ()
(interactive)
- (let* ((buf (mpc-proc-buffer (mpc-proc) 'status))
- (songs-buf (mpc-proc-buffer (mpc-proc) 'songs))
+ (let* ((proc (mpc-proc))
+ (buf (mpc-proc-buffer proc 'status))
+ (songs-buf (mpc-proc-buffer proc 'songs))
(songs-win (if songs-buf (get-buffer-window songs-buf 0))))
(unless (buffer-live-p buf)
(setq buf (get-buffer-create "*MPC-Status*"))
(with-current-buffer buf
(mpc-status-mode))
- (mpc-proc-buffer (mpc-proc) 'status buf))
+ (mpc-proc-buffer proc 'status buf))
(if (null songs-win) (pop-to-buffer buf)
(let ((_win (split-window songs-win 20 t)))
(set-window-dedicated-p songs-win nil)
(let* ((newbuf (mpc-tagbrowser-buf tag))
(win (get-buffer-window newbuf 0)))
(if win (select-window win)
- (if (with-current-buffer (window-buffer (selected-window))
+ (if (with-current-buffer (window-buffer)
(derived-mode-p 'mpc-tagbrowser-mode))
(setq win (selected-window))
;; Find a tagbrowser-mode buffer.
(mpc-event-set-point event)
(let ((name (buffer-substring (line-beginning-position)
(line-end-position)))
- (prop (intern mpc-tag)))
- (if (not (member name (process-get (mpc-proc) prop)))
- (process-put (mpc-proc) prop
- (cons name (process-get (mpc-proc) prop)))
- (let ((new (delete name (process-get (mpc-proc) prop))))
+ (prop (intern mpc-tag))
+ (proc (mpc-proc)))
+ (if (not (member name (process-get proc prop)))
+ (process-put proc prop
+ (cons name (process-get proc prop)))
+ (let ((new (delete name (process-get proc prop))))
(setq name (concat name "/"))
- (process-put (mpc-proc) prop
+ (process-put proc prop
(delq nil
(mapcar (lambda (x)
(if (string-prefix-p name x)
(char-after (posn-point posn))))
'(?◁ ?<))
(- mpc-volume-step) mpc-volume-step))
- (newvol (+ (string-to-number (cdr (assq 'volume mpc-status))) diff)))
- (mpc-proc-cmd (list "setvol" newvol) 'mpc-status-refresh)
- (message "Set MPD volume to %s%%" newvol)))
+ (curvol (string-to-number (cdr (assq 'volume mpc-status))))
+ (newvol (max 0 (min 100 (+ curvol diff)))))
+ (if (= newvol curvol)
+ (progn
+ (message "MPD volume already at %s%%" newvol)
+ (ding))
+ (mpc-proc-cmd (list "setvol" newvol) 'mpc-status-refresh)
+ (message "Set MPD volume to %s%%" newvol))))
(defun mpc-volume-widget (vol &optional size)
(unless size (setq size 12.5))
`text-property-any'.")
(defun mpc-songs-hashcons (name)
(or (gethash name mpc-songs-hashcons) (puthash name name mpc-songs-hashcons)))
-(defcustom mpc-songs-format "%2{Disc--}%3{Track} %-5{Time} %25{Title} %20{Album} %20{Artist} %10{Date}"
+(defcustom mpc-songs-format "%2{Disc--}%3{Track} %-5{Time} %25{Title} %20{Album} %20{Artist} %5{Date}"
"Format used to display each song in the list of songs."
:type 'string)
posn))))
(let* ((plbuf (mpc-proc-cmd "playlist"))
(re (if song-file
- (concat "^\\([0-9]+\\):" (regexp-quote song-file) "$")))
+ ;; Newer MPCs apparently include "file: " in the buffer.
+ (concat "^\\([0-9]+\\):\\(?:file: \\)?"
+ (regexp-quote song-file) "$")))
(sn (with-current-buffer plbuf
(goto-char (point-min))
(when (and re (re-search-forward re nil t))
(song-win (get-buffer-window song-buf 0)))
(if song-win
(select-window song-win)
- (if (or (window-dedicated-p (selected-window))
- (window-minibuffer-p))
+ (if (or (window-dedicated-p) (window-minibuffer-p))
(ignore-errors (select-frame (make-frame mpc-frame-alist)))
(with-current-buffer song-buf
(setq-local mpc-previous-window-config