diff options
Diffstat (limited to 'lib/media/jao-mpc.el')
-rw-r--r-- | lib/media/jao-mpc.el | 180 |
1 files changed, 123 insertions, 57 deletions
diff --git a/lib/media/jao-mpc.el b/lib/media/jao-mpc.el index dc8ff6d..0f000da 100644 --- a/lib/media/jao-mpc.el +++ b/lib/media/jao-mpc.el @@ -1,6 +1,6 @@ ;;; jao-mpc.el --- Using mpc to interact with mpd -*- lexical-binding: t; -*- -;; Copyright (C) 2021, 2022 jao +;; Copyright (C) 2021, 2022, 2024 jao ;; Author: jao <mail@jao.io> ;; Keywords: convenience @@ -38,62 +38,88 @@ (defvar-local jao-mpc--port nil) (defun jao-mpc--cmd (cmd &optional port) - (let ((port (or port jao-mpc--port jao-mpc-port))) - (shell-command-to-string (format "mpc -p %s %s" port cmd)))) + (let* ((port (or port jao-mpc--port jao-mpc-port)) + (r (shell-command-to-string (format "mpc -p %s %s" port cmd)))) + (replace-regexp-in-string "^\\(warning: \\)?MPD .+\n" "" r))) + +(defun jao-mpc--fformat (fields) + (mapconcat (lambda (f) (format "%s:::%%%s%%" f f)) fields "\n")) (defconst jao-mpc--fields '(artist album composer originaldate genre title track position time name)) (defconst jao-mpc--stfmt - (mapconcat (lambda (f) (format "%s:::%%%s%%" f f)) jao-mpc--fields "\n")) + (jao-mpc--fformat + '(artist album composer originaldate genre title track name))) + +(defconst jao-mpc--stfmtt + (jao-mpc--fformat '(currenttime totaltime percenttime songpos length))) + +(defmacro jao-mpc--parse-fields (res-str res) + `(dolist (s (split-string ,res-str "\n" t " ") ,res) + (when (string-match "\\(.+\\):::\\(.+\\)" s) + (push (cons (intern (match-string 1 s)) (match-string 2 s)) ,res)))) (defun jao-mpc--current (&optional port) (let ((s (jao-mpc--cmd (format "-f '%s' current" jao-mpc--stfmt) port)) + (st (jao-mpc--cmd (format "status '%s'" jao-mpc--stfmtt))) (res)) - (dolist (s (split-string s "\n" t " ") res) - (when (string-match "\\(.+\\):::\\(.+\\)" s) - (push (cons (intern (match-string 1 s)) (match-string 2 s)) res))))) + (jao-mpc--parse-fields s res) + (jao-mpc--parse-fields st res))) + +(defsubst jao-mpc-status (&optional port) + (string-trim (jao-mpc--cmd "status %state%" port))) -(defun jao-mpc--playing-p (&optional port) - (not (string-blank-p (jao-mpc--cmd "status|grep '\\[playing\\]'" port)))) +(defsubst jao-mpc-playing-p (&optional port) + (string-prefix-p "playing" (jao-mpc-status port))) -(defun jao-mpc--queue-len (&optional port) - (string-to-number (jao-mpc--cmd "playlist|wc -l" port))) +(defsubst jao-mpc--queue-len (&optional port) + (string-to-number (jao-mpc--cmd "status %length%" port))) (defsubst jao--put-face (str face) (put-text-property 0 (length str) 'face face str) str) -(defun jao-mpc--current-str (&optional port current len) - (let* ((current (or current (jao-mpc--current port))) - (len (or len (jao-mpc--queue-len port))) - (title (alist-get 'title current (alist-get 'name current ""))) - (album (alist-get 'album current)) - (artist (alist-get 'artist current)) - (composer (alist-get 'composer current)) - (no (string-to-number (alist-get 'position current "0"))) - (time (alist-get 'time current ""))) - (format "> %s%s %s%s%s%s" ;; - (jao--put-face (if (zerop no) "" (format "%02d/%s " no len)) - 'jao-themes-f02) - (jao--put-face title 'jao-themes-f00) - (jao--put-face artist 'jao-themes-f01) - (jao--put-face (if composer (format " [%s]" composer) "") - 'jao-themes-f01) - (jao--put-face (if album (format " (%s)" album) "") 'jao-themes-f11) - (if (string-blank-p time) - "" - (jao--put-face (format " [%s]" time) 'jao-themes-dimm))))) +(defun jao-mpc--current-timestr (playing-times &optional current) + (let* ((current (or current (jao-mpc--current))) + (time (alist-get 'totaltime current ""))) + (if playing-times + (format "%s/%s%s" + (alist-get 'currenttime current "") + time + (alist-get 'percenttime current "")) + (format "%s" time)))) + +(defun jao-mpc--current-str (&optional port times) + (if-let* ((current (jao-mpc--current port)) + (title (alist-get 'title current (alist-get 'name current)))) + (let ((len (alist-get 'length current "0")) + (album (alist-get 'album current)) + (artist (alist-get 'artist current)) + (composer (alist-get 'composer current)) + (no (string-to-number (alist-get 'songpos current "0"))) + (tims (concat " [" (jao-mpc--current-timestr times current) "]"))) + (format "%s%s %s%s%s%s" ;; + (jao--put-face (if (zerop no) "" (format "%d/%s " no len)) + 'jao-themes-f02) + (jao--put-face (or title "") 'jao-themes-f00) + (jao--put-face (or artist "") 'jao-themes-f01) + (jao--put-face (if composer (format " [%s]" composer) "") + 'jao-themes-f01) + (jao--put-face (if album (format " (%s)" album) "") 'jao-themes-f11) + (jao--put-face tims (if times 'jao-themes-f00 'jao-themes-dimm)))) + "")) (defvar jao-mpc-minibuffer-str "") (defun jao-mpc--set-current-str (&optional port) - (setq jao-mpc-minibuffer-str - (if (jao-mpc--playing-p port) - (jao-mpc--current-str port) - (when (and (null port) jao-random-album-p (not (jao-mpc--current))) - (jao-random-album-next)) - "")) + (let ((status (or (jao-mpc-status port) ""))) + (setq jao-mpc-minibuffer-str + (if (string= "playing" status) (jao-mpc--current-str port) "")) + (when (and jao-random-album-active + (or (string= status "stopped") (string= status "paused")) + (string= "0\n" (jao-mpc--cmd "status %songpos%" port))) + (jao-random-album-next))) (jao-minibuffer-refresh)) (defvar jao-mpc--idle-procs nil) @@ -109,11 +135,13 @@ "idleloop" "player") :filter (lambda (_p _s) (jao-mpc--set-current-str port))))) +(defvar jao-mpc--browser-port nil) + (define-derived-mode jao-mpc-albums-mode fundamental-mode "MPC Albums" "Mode to display the list of albums known by mpd." (read-only-mode -1) (delete-region (point-min) (point-max)) - (insert (jao-mpc--cmd "list album")) + (insert (jao-mpc--cmd "list album" jao-mpc--browser-port)) (goto-char (point-min)) (read-only-mode 1)) @@ -124,12 +152,13 @@ (jao-mpc-albums-mode) (current-buffer)))) -(defun jao-mpc--add-and-play (&optional album) +(defun jao-mpc--add-and-play (&optional album port idp) (interactive) - (let ((album (or album (string-trim (thing-at-point 'line))))) - (jao-mpc--cmd "clear") - (jao-mpc--cmd (format "findadd album \"%s\"" album)) - (jao-mpc--cmd "play"))) + (let ((a (or album (string-trim (thing-at-point 'line)))) + (p (or port jao-mpc--browser-port))) + (jao-mpc--cmd "clear" p) + (jao-mpc--cmd (if idp (concat "add " a) (format "findadd album \"%s\"" a)) p) + (jao-mpc--cmd "play" p))) (define-key jao-mpc-albums-mode-map (kbd "n") #'next-line) (define-key jao-mpc-albums-mode-map (kbd "p") #'previous-line) @@ -170,15 +199,22 @@ (let ((jao-mpc-port (or port jao-mpc-port))) (jao-mpc-playlist-mode)) (current-buffer))) +(defun jao-mpc--with-delayed-random-album (cmd port) + (let ((st jao-random-album-active)) + (setq jao-random-album-active nil) + (jao-mpc--cmd cmd port) + (accept-process-output nil 0.5) + (setq jao-random-album-active st))) + ;;;###autoload (defun jao-mpc-stop (&optional port) (interactive) - (jao-mpc--cmd "stop" port)) + (jao-mpc--with-delayed-random-album "stop" port)) ;;;###autoload (defun jao-mpc-toggle (&optional port) (interactive) - (jao-mpc--cmd "toggle" port)) + (jao-mpc--with-delayed-random-album "toggle" port)) ;;;###autoload (defun jao-mpc-play (&optional port) @@ -208,7 +244,12 @@ ;;;###autoload (defun jao-mpc-echo-current (&optional port) (interactive) - (jao-notify (jao-mpc--current-str port))) + (message "%s" (jao-mpc--current-str port t))) + +;;;###autoload +(defun jao-mpc-echo-current-times (&optional port) + (interactive) + (message "Playing time: %s" (jao-mpc--current-timestr t))) ;;;###autoload (defun jao-mpc-add-url (url) @@ -216,9 +257,33 @@ (jao-mpc--cmd (format "add %s" url))) ;;;###autoload -(defun jao-mpc-show-albums () +(defun jao-mpc-add-or-play-url (url &optional play) + "Add the given URL to mpc's playing list, or just play it." + (let ((p (or play (yes-or-no-p (format "Play %s right now?" url))))) + (when p (jao-mpc-clear)) + (jao-mpc-add-url url) + (if p (jao-mpc-play) (message "%s added to mpc queue" url)))) + +(defvar jao-mpc-stream-urls + '(("classic fm" . "http://media-ice.musicradio.com:80/ClassicFMMP3") + ("wcpe" . "http://audio-mp3.ibiblio.org:8000/wcpe.mp3") + ("davide of mimic" . "http://streaming01.zfast.co.uk:8018/stream") + ("cinemix" . "http://94.23.51.96:8000") ;; 209.9.238.4:6022 209.9.238.4:6046 + ("bbc gold" . "http://media-ice.musicradio.com:80/GoldMP3") + ("irish gold" . "http://icecast2.rte.ie/gold"))) + +;;;###autoload +(defun jao-mpc-play-stream () + "Select a predefined stream URL and add or play it in mpc." + (interactive) + (let ((s (completing-read "Stream: " jao-mpc-stream-urls))) + (jao-mpc-add-or-play-url (cdr (assoc s jao-mpc-stream-urls)) t))) + +;;;###autoload +(defun jao-mpc-show-albums (&optional port) "Show album list." (interactive) + (setq jao-mpc--browser-port port) (pop-to-buffer (jao-mpc--album-buffer))) ;;;###autoload @@ -239,7 +304,7 @@ (defun jao-mpc-connect (&optional port) (interactive) (jao-mpc--idle-loop port) - (when (jao-mpc--playing-p port) (jao-mpc--set-current-str port))) + (when (jao-mpc-playing-p port) (jao-mpc--set-current-str port))) ;;;###autoload (defun jao-mpc-setup (&optional secondary-port priority) @@ -248,26 +313,27 @@ #'jao-mpc--add-and-play #'jao-mpc-stop jao-notify-audio-icon) - (jao-mpc-connect) + (let ((jao-random-album-active nil)) (jao-mpc-connect)) (when secondary-port (jao-mpc-connect secondary-port)) (when priority (if (> priority 0) (jao-minibuffer-add-variable 'jao-mpc-minibuffer-str priority) (jao-minibuffer-add-msg-variable 'jao-mpc-minibuffer-str (- priority))))) -(defvar jao-mpc--album-titles nil) (defconst jao-mpc--albums-cmd "-f '%album% - %artist%' find \"(ALBUM =~ '.*')\" | uniq") +(defconst jao-mpc--simple-albums-cmd "list album") ;;;###autoload -(defun jao-mpc-select-album (refresh) - (interactive "P") - (let ((albums (or (and (not refresh) jao-mpc--album-titles) - (setq jao-mpc--album-titles - (split-string (jao-mpc--cmd jao-mpc--albums-cmd) - "\n" t))))) +(defun jao-mpc-select-album (&optional port) + (interactive) + (let* ((albums-str (jao-mpc--cmd jao-mpc--albums-cmd port)) + (albums-str (if (string= "" albums-str) + (jao-mpc--cmd jao-mpc--simple-albums-cmd port) + albums-str)) + (albums (split-string albums-str "\n" t))) (when-let (album (completing-read "Play album: " albums nil t)) - (jao-mpc--add-and-play (car (split-string album "-" t " ")))))) + (jao-mpc--add-and-play (car (split-string album "-" t " ")) port)))) (provide 'jao-mpc) ;;; jao-mpc.el ends here |