From 4ffdc3317f332fee97697a976c517bfe7edbc544 Mon Sep 17 00:00:00 2001 From: jao Date: Tue, 1 Jun 2021 01:31:33 +0100 Subject: mpc/mpdn split: elmd is only needed for notifications --- init.org | 14 ++--- lib/media/jao-mpc.el | 165 ++++++++++++-------------------------------------- lib/media/jao-mpdn.el | 133 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 135 deletions(-) create mode 100644 lib/media/jao-mpdn.el diff --git a/init.org b/init.org index 6909018..04a3f8d 100644 --- a/init.org +++ b/init.org @@ -2950,8 +2950,6 @@ #+end_src *** mpc #+begin_src emacs-lisp - (use-package elmpd :ensure t) - (use-package jao-mpc :demand t :commands jao-mpc-setup) @@ -2972,23 +2970,23 @@ (defalias 'jao-player-echo 'jao-mpc-echo-current) (defalias 'jao-player-list 'jao-mpc-show-playlist) (defalias 'jao-player-browse 'jao-mpc-show-albums) + + (use-package elmpd :ensure t) + (use-package jao-mpdn :demand t) + (jao-mpdn-setup) #+end_src *** mopidy #+begin_src emacs-lisp (defvar jao-mopidy-port 6669) - (defvar jao-mopidy-conn - (let ((jao-mpc-port jao-mopidy-port)) (jao-mpc--connect "jao-mopidy"))) (defmacro jao-mopidy-def (name args &rest body) `(defun ,name ,args (interactive) - (let ((jao-mpc--connection jao-mopidy-conn) - (jao-mpc-port jao-mopidy-port)) - ,@body))) + (let ((jao-mpc-port jao-mopidy-port)) ,@body))) (jao-mopidy-def jao-mopidy-show-playlist () (jao-mpc-show-playlist)) (jao-mopidy-def jao-mopidy-clear () (jao-mpc-clear)) - (jao-mopidy-def jao-mopidy-disconnect () (jao-mpc-disconnect)) + #+end_src *** hydras #+begin_src emacs-lisp diff --git a/lib/media/jao-mpc.el b/lib/media/jao-mpc.el index 89509ec..59021ca 100644 --- a/lib/media/jao-mpc.el +++ b/lib/media/jao-mpc.el @@ -1,9 +1,12 @@ -;;; jao-mpc-random-album.el --- random mpc albums -*- lexical-binding: t; -*- +;;; jao-mpc.el --- Using mpc client -*- lexical-binding: t; -*- ;; Copyright (C) 2021 jao ;; Author: jao ;; Keywords: convenience +;; Version: 0.1 +;; Package-requires: ((emacs "27.1")) +;; URL: https://codeberg.org/jao/lib/media ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -20,110 +23,23 @@ ;;; Commentary: -;; Simple mpd control using elmpd and mpc. +;; Simple mpd interaction using elmpd and mpc. ;;; Code: -(require 'elmpd) -(require 'jao-minibuffer) (require 'jao-lyrics) +(require 'jao-random-album) -(defvar jao-mpc--connection nil) -(defvar-local jao-mpc--local-connection nil) -(defvar-local jao-mpc--local-port nil) +(defconst jao-mpc--albums "*MPC Albums*") +(defconst jao-mpc--playlist "*MPC Playlist*") -(defvar jao-mpc-host "localhost") (defvar jao-mpc-port 6600) +(defvar-local jao-mpc--local-port nil) -(defun jao-mpc-disconnect () - (interactive) - (when jao-mpc--connection - (delete-process (elmpd-connection--fd jao-mpc--connection)) - (setq jao-mpc--connection nil))) - -(defun jao-mpc--connect (name &optional cb) - (elmpd-connect :name name - :host jao-mpc-host - :port jao-mpc-port - :subsystems - (when cb `((player) . ,cb)))) - -(defun jao-mpc-connect (&optional force) - (interactive) - (when force (jao-mpc-disconnect)) - (unless jao-mpc--connection - (setq jao-mpc--connection (jao-mpc--connect "jao-mpc" 'jao-mpc--watcher)) - (jao-mpc--watcher jao-mpc--connection 'player)) - jao-mpc--connection) - -(defun jao-mpc--send (cmd cb) - (elmpd-send jao-mpc--connection cmd cb )) - -(defvar jao-mpc--play-status '()) -(defvar jao-mpc--current '()) -(defvar jao-mpc-minibuffer-str "") - -(defun jao-mpc--parse-retort (txt) - (let (res) - (dolist (e (split-string txt "\n" t " ") res) - (let ((e (split-string e ": " t " "))) - (when (and (car e) (cadr e)) - (push (cons (car e) (cadr e)) res)))))) - -(defun jao-mpc--update-status (next) - (let ((cb (lambda (_c ok txt) - (when ok - (setq jao-mpc--play-status (jao-mpc--parse-retort txt)) - (when next (funcall next)))))) - (jao-mpc--send "status" cb))) - -(defun jao-mpc--current-get (x &optional def) - (alist-get x jao-mpc--current def nil #'string=)) - -(defun jao-mpc--status-get (x &optional def) - (alist-get x jao-mpc--play-status def nil #'string=)) - -(defun jao-mpc--playing-p () - (string= (jao-mpc--status-get "state" "") "play")) - -(defun jao-mpc--current-str () - (let ((title (jao-mpc--current-get "Title")) - (album (jao-mpc--current-get "Album")) - (no (string-to-number (jao-mpc--current-get "Track" "0"))) - (len (string-to-number (jao-mpc--status-get "playlistlength" "1"))) - (artist (jao-mpc--current-get "Artist")) - (composer (jao-mpc--current-get "Composer"))) - (format " %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)))) - -(defun jao-mpc--update-minibuffer () - (setq jao-mpc-minibuffer-str - (if (jao-mpc--playing-p) (jao-mpc--current-str) "")) - (jao-minibuffer-refresh)) - -(defun jao-mpc--update-current (&optional next) - (let ((cb (lambda (_c ok txt) - (when ok - (setq jao-mpc--current (jao-mpc--parse-retort txt)) - (jao-mpc--update-minibuffer) - (cond (next (funcall next)) - ((and (null jao-mpc--current) jao-random-album-p) - (jao-random-album-next))))))) - (jao-mpc--send "currentsong" cb))) - -(defun jao-mpc--watcher (_conn _subsys) - (jao-mpc--update-status #'jao-mpc--update-current)) - - - -(defconst jao-mpc--albums "*MPC Albums*") -(defconst jao-mpc--playlist "*MPC Playlist*") +(defun jao-mpc--cmd (cmd) + (shell-command-to-string (format "mpc -p %s %s" + (or jao-mpc--local-port jao-mpc-port) + cmd))) (define-derived-mode jao-mpc-albums-mode fundamental-mode "MPC Albums" "Mode to display the list of albums known by mpd." @@ -147,43 +63,39 @@ (defun jao-mpc--add-and-play (&optional album) (interactive) - (let* ((album (or album (string-trim (thing-at-point 'line)))) - (cmd (format "mpc findadd album \"%s\" && mpc play" album))) - (shell-command-to-string "mpc clear") - (shell-command-to-string cmd))) + (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"))) (define-derived-mode jao-mpc-playlist-mode fundamental-mode "MPC Playlist" "Mode to display the list of playlist known by mpd." (read-only-mode -1) (delete-region (point-min) (point-max)) - (setq-local jao-mpc--local-connecton jao-mpc--connection - jao-mpc--local-port jao-mpc-port) - (insert (shell-command-to-string (format "mpc -p %s playlist" jao-mpc-port))) + (setq-local jao-mpc--local-port jao-mpc-port) + (insert (jao-mpc--cmd "playlist")) (goto-char (point-min)) (display-line-numbers-mode) (read-only-mode 1)) (defun jao-mpc--playlist-goto-current () (interactive) - (let ((jao-mpc--connection - (or jao-mpc--local-connecton jao-mpc--local-connecton))) - (jao-mpc--update-current - (lambda () - (when-let (no (string-to-number (jao-mpc--current-get "Pos"))) - (goto-char (point-min)) - (forward-line no)))))) + (let ((c (string-trim (or (jao-mpc--cmd "current") "")))) + (unless (string-blank-p c) + (goto-char (point-min)) + (when (re-search-forward (regexp-quote c) nil t) + (beginning-of-line))))) (defun jao-mpc--playlist-play () (interactive) - (shell-command-to-string (format "mpc -p %s play %s" - (or jao-mpc--local-port jao-mpc-port) - (line-number-at-pos)))) + (jao-mpc--cmd (format "play %s" (line-number-at-pos)))) (define-key jao-mpc-playlist-mode-map (kbd "n") #'next-line) (define-key jao-mpc-playlist-mode-map (kbd "p") #'previous-line) (define-key jao-mpc-playlist-mode-map (kbd "q") #'bury-buffer) (define-key jao-mpc-playlist-mode-map (kbd ".") #'jao-mpc--playlist-goto-current) (define-key jao-mpc-playlist-mode-map (kbd "RET") #'jao-mpc--playlist-play) +(define-key jao-mpc-playlist-mode-map (kbd "C") #'jao-mpc-clear) (defun jao-mpc--playlist-buffer () (with-current-buffer (get-buffer-create jao-mpc--playlist) @@ -193,37 +105,37 @@ ;;;###autoload (defun jao-mpc-stop () (interactive) - (shell-command-to-string "mpc stop")) + (jao-mpc--cmd "stop")) ;;;###autoload (defun jao-mpc-toggle () (interactive) - (jao-mpc--send "pause" nil)) + (jao-mpc--cmd "pause")) ;;;###autoload (defun jao-mpc-play () (interactive) - (jao-mpc--send "play" nil)) + (jao-mpc--cmd "play")) ;;;###autoload (defun jao-mpc-next () (interactive) - (jao-mpc--send "next" nil)) + (jao-mpc--cmd "next")) ;;;###autoload (defun jao-mpc-previous () (interactive) - (jao-mpc--send "previous" nil)) + (jao-mpc--cmd "previous")) ;;;###autoload (defun jao-mpc-seek (delta) (interactive "nDelta") - (jao-mpc--send (format "seekcur %s%s" (if (> delta 0) "+" "") delta) nil)) + (jao-mpc--cmd (format "seekcur %s%s" (if (> delta 0) "+" "") delta))) ;;;###autoload (defun jao-mpc-clear () (interactive) - (jao-mpc--send "clear" nil)) + (jao-mpc--cmd "clear")) ;;;###autoload (defun jao-mpc-echo-current () @@ -245,18 +157,17 @@ ;;;###autoload (defun jao-mpc-lyrics-track-data () - (when-let* ((title (jao-mpc--current-get "Title")) - (artist (jao-mpc--current-get "Artist"))) - (cons (substring-no-properties title) (substring-no-properties artist)))) + (let ((c (string-trim (jao-mpc--cmd "current")))) + (unless (string-blank-p c) + (when (string-match "\\(.\\) - \\(.+\\)" c) + (cons (match-string 2 c) (match-string 1 c)))))) ;;;###autoload (defun jao-mpc-setup () (setq jao-lyrics-info-function #'jao-mpc-lyrics-track-data) (jao-random-album-setup #'jao-mpc--album-buffer #'jao-mpc--add-and-play - #'jao-mpc-stop) - (jao-mpc-connect) - (jao-minibuffer-add-msg-variable 'jao-mpc-minibuffer-str 1)) + #'jao-mpc-stop)) (provide 'jao-mpc) ;;; jao-mpc.el ends here diff --git a/lib/media/jao-mpdn.el b/lib/media/jao-mpdn.el new file mode 100644 index 0000000..d707767 --- /dev/null +++ b/lib/media/jao-mpdn.el @@ -0,0 +1,133 @@ +;;; jao-mpdn.el --- Notifications using elmpd -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 jao + +;; Author: jao +;; Keywords: convenience +;; Version: 0.1 +;; Package-requires: ((emacs "27.1") (elmpd "0.1.9")) +;; URL: https://codeberg.org/jao/lib/media + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; React to mpd player status changes. + +;;; Code: + +(require 'elmpd) +(require 'jao-minibuffer) + +(defvar jao-mpdn--connection nil) +(defvar jao-mpdn-host "localhost") +(defvar jao-mpdn-port 6600) +(defvar-local jao-mpdn--local-port nil) + +(defun jao-mpdn--disconnect (conn) + (delete-process (elmpd-connection--fd conn))) + +(defun jao-mpdn--connect (name &optional cb) + (elmpd-connect :name name + :host jao-mpdn-host + :port jao-mpdn-port + :subsystems + (when cb `((player) . ,cb)))) + +(defun jao-mpdn-disconnect () + (interactive) + (when jao-mpdn--connection + (jao-mpdn--disconnect jao-mpdn--connection) + (setq jao-mpdn--connection nil))) + +(defun jao-mpdn-connect (&optional force) + (interactive) + (when force (jao-mpdn-disconnect)) + (unless jao-mpdn--connection + (setq jao-mpdn--connection (jao-mpdn--connect "jao-mpc" 'jao-mpdn--watcher)) + (jao-mpdn--watcher jao-mpdn--connection 'player)) + jao-mpdn--connection) + +(defun jao-mpdn--send (cmd cb) + (elmpd-send jao-mpdn--connection cmd cb)) + +(defvar jao-mpdn--play-status '()) +(defvar jao-mpdn--current '()) +(defvar jao-mpdn-minibuffer-str "") + +(defun jao-mpdn--parse-retort (txt) + (let (res) + (dolist (e (split-string txt "\n" t " ") res) + (let ((e (split-string e ": " t " "))) + (when (and (car e) (cadr e)) + (push (cons (car e) (cadr e)) res)))))) + +(defun jao-mpdn--update-status (next) + (let ((cb (lambda (_c ok txt) + (when ok + (setq jao-mpdn--play-status (jao-mpdn--parse-retort txt)) + (when next (funcall next)))))) + (jao-mpdn--send "status" cb))) + +(defun jao-mpdn--current-get (x &optional def) + (alist-get x jao-mpdn--current def nil #'string=)) + +(defun jao-mpdn--status-get (x &optional def) + (alist-get x jao-mpdn--play-status def nil #'string=)) + +(defun jao-mpdn--playing-p () + (string= (jao-mpdn--status-get "state" "") "play")) + +(defun jao-mpdn--current-str () + (let ((title (jao-mpdn--current-get "Title")) + (album (jao-mpdn--current-get "Album")) + (no (string-to-number (jao-mpdn--current-get "Track" "0"))) + (len (string-to-number (jao-mpdn--status-get "playlistlength" "1"))) + (artist (jao-mpdn--current-get "Artist")) + (composer (jao-mpdn--current-get "Composer"))) + (format " %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)))) + +(defun jao-mpdn--update-minibuffer () + (setq jao-mpdn-minibuffer-str + (if (jao-mpdn--playing-p) (jao-mpdn--current-str) "")) + (jao-minibuffer-refresh)) + +(defun jao-mpdn--update-current (&optional next) + (let ((cb (lambda (_c ok txt) + (when ok + (setq jao-mpdn--current (jao-mpdn--parse-retort txt)) + (jao-mpdn--update-minibuffer) + (cond (next (funcall next)) + ((and (null jao-mpdn--current) jao-random-album-p) + (jao-random-album-next))))))) + (jao-mpdn--send "currentsong" cb))) + +(defun jao-mpdn--watcher (_conn _subsys) + (jao-mpdn--update-status #'jao-mpdn--update-current)) + + +;;;###autoload +(defun jao-mpdn-setup () + (jao-mpdn-connect t) + (jao-minibuffer-add-msg-variable 'jao-mpdn-minibuffer-str 1)) + +(provide 'jao-mpdn) +;;; jao-mpdn.el ends here -- cgit v1.2.3