~breatheoutbreathein/emacs-simple-mpc-breatheoutbreathein

4cc5ae2f63d3a48de504d8c2267518a2c7029418 — Joseph Turner 1 year, 9 months ago 9c963d3
Use regex capture groups to extract parts of `mpc status'

This is more robust and easier than using buffer movements.
2 files changed, 54 insertions(+), 48 deletions(-)

M simple-mpc-utils.el
M simple-mpc.el
M simple-mpc-utils.el => simple-mpc-utils.el +48 -42
@@ 30,6 30,42 @@

(require 'simple-mpc-vars)

(defconst simple-mpc-status-re
  (rx
   (group (one-or-more not-newline))          ; Artist - Song title
   "\n"
   (group "[" (or "playing" "paused") "]")    ; Playing/paused status
   (one-or-more blank)
   "#" (group (one-or-more digit))            ; Playlist position
   "/"
   (group (one-or-more digit))                ; Playlist length
   (one-or-more blank)
   (group (one-or-more not-newline))          ; Song position
   "\n"
   (group "volume:" (zero-or-one blank) (one-or-more digit) "%") ; Volume
   (one-or-more blank)
   (group "repeat: " (or "on" "off"))         ; Repeat status
   (one-or-more blank)
   (group "random: " (or "on" "off"))         ; Random status
   (one-or-more blank)
   (group "single: " (or "on" "off"))         ; Single status
   (one-or-more blank)
   (group "consume: " (or "on" "off")))       ; Consume status
  "Regular expression to capture parts of `mpc status'. This regex will not match if `mpd' is not running.")

(defconst simple-mpc-status-re-groups
  '((artist-song       . 1)
    (playing-paused    . 2)
    (playlist-position . 3)
    (playlist-length   . 4)
    (song-position     . 5)
    (volume            . 6)
    (repeat            . 7)
    (random            . 8)
    (single            . 9)
    (consume           . 10))
  "Alist mapping mpc data types to `simple-mpc-status-re' capture group.")

(defvar simple-mpc-arguments ""
  "Extra arguments that will be given to mpc.



@@ 82,48 118,18 @@ output as a string."
  ;; interpret the percent symbol in mpc's output as an
  ;; incomplete format specifier.
  (message "%s"
   (with-temp-buffer
     (simple-mpc-call-mpc t "volume")
     (delete-char -1)  ;; delete trailing \n
     (buffer-string))))

(defmacro simple-mpc-extract-status (&rest args)
  `(let (start end)
     (with-temp-buffer (simple-mpc-call-mpc t "status")
                       ,@args
                       (buffer-substring start end))))

(defun simple-mpc-current-artist-and-song ()
  "Return the currently playing artist and song."
  (simple-mpc-extract-status
   (beginning-of-buffer)
   (setq start (point))
   (setq end (line-end-position))))

(defun simple-mpc-playing-status ()
  "Return either `playing' or `paused'."
  (simple-mpc-extract-status
   (beginning-of-buffer)
   (next-line)
   (setq start (point))
   (forward-sexp)
   (setq end (point))))

(defun simple-mpc-repeat-status ()
  "Return repeat status."
  (simple-mpc-extract-status
   (search-backward "repeat")
   (setq start (point))
   (forward-sexp 2)
   (setq end (point))))

(defun simple-mpc-song-position ()
  "Return song position."
  (simple-mpc-extract-status
   (search-backward-regexp " [0-9]+:")
   (forward-char)
   (setq start (point))
   (setq end (line-end-position))))
           (with-temp-buffer
             (simple-mpc-call-mpc t "volume")
             (delete-char -1)  ;; delete trailing \n
             (buffer-string))))

(defun simple-mpc-extract-status (type)
  "Return the mpc data corresponding to TYPE of current song. TYPE may be one of the keys of `simple-mpc-status-re-groups'."
  (with-temp-buffer
    (simple-mpc-call-mpc t "status")
    (let ((status (buffer-string)))
      (string-match simple-mpc-status-re status)
      (match-string (alist-get type simple-mpc-status-re-groups) status))))

(defun simple-mpc-goto-line (line-number)
  "Go to beginning of line LINE-NUMBER.

M simple-mpc.el => simple-mpc.el +6 -6
@@ 54,33 54,33 @@
  "Toggle the playing / pause state."
  (interactive)
  (simple-mpc-call-mpc nil "toggle")
  (message "%s" (concat (simple-mpc-playing-status) " " (simple-mpc-current-artist-and-song))))
  (message "%s" (concat (simple-mpc-extract-status 'playing-paused) " " (simple-mpc-extract-status 'artist-song))))

(defun simple-mpc-next ()
  "Play the next song."
  (interactive)
  (simple-mpc-call-mpc nil "next")
  (simple-mpc-maybe-refresh-playlist t)
  (message "%s" (simple-mpc-current-artist-and-song)))
  (message "%s" (simple-mpc-extract-status 'artist-song)))

(defun simple-mpc-prev ()
  "Play the previous song."
  (interactive)
  (simple-mpc-call-mpc nil "prev")
  (simple-mpc-maybe-refresh-playlist t)
  (message "%s" (simple-mpc-current-artist-and-song)))
  (message "%s" (simple-mpc-extract-status 'artist-song)))

(defun simple-mpc-seek-forward ()
  "Does a relative seek forward by `simple-mpc-seek-time-in-s' seconds."
  (interactive)
  (simple-mpc-seek-internal simple-mpc-seek-time-in-s)
  (message "%s" (concat (simple-mpc-song-position) " " (simple-mpc-current-artist-and-song))))
  (message "%s" (concat (simple-mpc-extract-status 'song-position) " " (simple-mpc-extract-status 'artist-song))))

(defun simple-mpc-seek-backward ()
  "Does a relative seek backward by -`simple-mpc-seek-time-in-s' seconds."
  (interactive)
  (simple-mpc-seek-internal (- simple-mpc-seek-time-in-s))
  (message "%s" (concat (simple-mpc-song-position) " " (simple-mpc-current-artist-and-song))))
  (message "%s" (concat (simple-mpc-extract-status 'song-position) " " (simple-mpc-extract-status 'artist-song))))

(defun simple-mpc-seek-internal (time-in-seconds)
  "Seek current song by TIME-IN-SECONDS."


@@ 114,7 114,7 @@
  "Toggle repeat mode."
  (interactive)
  (simple-mpc-call-mpc nil "repeat")
  (message "%s" (simple-mpc-repeat-status)))
  (message "%s" (simple-mpc-extract-status 'repeat)))

(defun simple-mpc-shuffle-current-playlist ()
  "Shuffle the current playlist."