-;;; mpc.el --- A client for the Music Player Daemon -*- coding: utf-8; lexical-binding: t -*-
+;;; mpc.el --- A client for the Music Player Daemon -*- lexical-binding: t -*-
-;; Copyright (C) 2006-2013 Free Software Foundation, Inc.
+;; Copyright (C) 2006-2015 Free Software Foundation, Inc.
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Keywords: multimedia
(cancel-timer mpc--status-timer)
(setq mpc--status-timer nil)))
(defun mpc--status-timer-run ()
- (with-demoted-errors "MPC: %s"
+ (with-demoted-errors "MPC: %S"
(when (process-get (mpc-proc) 'ready)
- (with-local-quit (mpc-status-refresh)))))
+ (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)
- (with-demoted-errors "MPC: %s"
- (with-local-quit (mpc-status-refresh))))
- (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."
:type '(choice (const nil) directory))
(defcustom mpc-data-directory
- (if (and (not (file-directory-p "~/.mpc"))
- (file-directory-p "~/.emacs.d"))
- "~/.emacs.d/mpc" "~/.mpc")
+ (locate-user-emacs-file "mpc" ".mpc")
"Directory where MPC.el stores auxiliary data."
:type 'directory)
(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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq active
(if (listp active) (mpc-intersection active vals) vals))))
- (when (and (listp active))
+ (when (listp active)
;; Remove the selections if they are all in conflict with
;; other constraints.
(let ((deactivate t))
(setq selection nil)
(mapc 'delete-overlay mpc-select)
(setq mpc-select nil)
- (mpc-tagbrowser-all-select)))))
-
+ (mpc-tagbrowser-all-select))))
+
+ ;; Don't bother splitting the "active" elements to the first part if
+ ;; they're the same as the selection.
+ (when (equal (sort (copy-sequence active) #'string-lessp)
+ (sort (copy-sequence selection) #'string-lessp))
+ (setq active 'all)))
+
;; FIXME: This `mpc-sort' takes a lot of time. Maybe we should
;; be more clever and presume the buffer is mostly sorted already.
(mpc-sort (if (listp active) active))
;; Maintain the volume.
(setq mpc-volume
(mpc-volume-widget
- (string-to-number (cdr (assq 'volume mpc-status))))))
+ (string-to-number (cdr (assq 'volume mpc-status)))))
+ (let ((status-buf (mpc-proc-buffer (mpc-proc) 'status)))
+ (when status-buf (with-current-buffer status-buf (force-mode-line-update)))))
(defvar mpc-volume-step 5)
(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))
(match-string 1)))))
(cond
((null re) (posn-set-point posn))
- ((null sn) (error "This song is not in the playlist"))
+ ((null sn) (user-error "This song is not in the playlist"))
((null (with-current-buffer plbuf (re-search-forward re nil t)))
;; song-file only appears once in the playlist: no ambiguity,
;; we're good to go!
(if (mpc-playlist-add)
(if (member (cdr (assq 'state (mpc-cmd-status))) '("stop"))
(mpc-cmd-play))
- (error "Don't know what to play"))))
+ (user-error "Don't know what to play"))))
(defun mpc-next ()
"Jump to the next song in the queue."
(mpc-cmd-move (let ((poss '()))
(dotimes (i (length songs))
(push (+ i (length pl)) poss))
- (nreverse poss)) dest-pos mpc-songs-playlist)
+ (nreverse poss))
+ dest-pos mpc-songs-playlist)
(message "Added %d songs" (length songs)))))
(mpc-songs-refresh))
(t