summaryrefslogtreecommitdiffhomepage
path: root/lib/media/jao-mpc.el
diff options
context:
space:
mode:
Diffstat (limited to 'lib/media/jao-mpc.el')
-rw-r--r--lib/media/jao-mpc.el180
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