From d5fa86062b31179c268cb914266f0e646a244229 Mon Sep 17 00:00:00 2001 From: jao Date: Mon, 31 May 2021 04:43:10 +0100 Subject: losing weight: elmpd instead of emms not only simpler, but also asynchronous --- lib/media/jao-mpc.el | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 lib/media/jao-mpc.el (limited to 'lib/media/jao-mpc.el') diff --git a/lib/media/jao-mpc.el b/lib/media/jao-mpc.el new file mode 100644 index 0000000..512d21b --- /dev/null +++ b/lib/media/jao-mpc.el @@ -0,0 +1,224 @@ +;;; jao-mpc-random-album.el --- random mpc albums -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 jao + +;; Author: jao +;; Keywords: convenience + +;; 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: + +;; Simple mpd control using mpc commands. + +;;; Code: + +(require 'elmpd) +(require 'jao-minibuffer) +(require 'jao-lyrics) + +(defvar jao-mpc--connection nil) +(defvar jao-mpc-host "localhost") +(defvar jao-mpc-port 6600) + +(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 (&optional force) + (interactive) + (when force (jao-mpc-disconnect)) + (unless jao-mpc--connection + (setq jao-mpc--connection + (elmpd-connect :name "jao-mpc" + :host jao-mpc-host + :port jao-mpc-port + :subsystems '((player) . 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--update-status (next) + (let ((cb (lambda (_c ok txt) + (when ok + (setq jao-mpc--play-status '()) + (dolist (e (split-string txt "\n" t " ")) + (let ((e (split-string e ": " t " "))) + (when (and (car e) (cadr e)) + (push (cons (car e) (cadr e)) jao-mpc--play-status)))) + (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 () + (let ((cb (lambda (_c ok txt) + (when ok + (setq jao-mpc--current '()) + (dolist (e (split-string txt "\n" t " ")) + (let ((e (split-string e ": " t " "))) + (when (and (car e) (cadr e)) + (push (cons (car e) (cadr e)) jao-mpc--current)))) + (jao-mpc--update-minibuffer))))) + (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*") + +(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 (shell-command-to-string "mpc list album")) + (goto-char (point-min)) + (read-only-mode 1)) + +(define-key jao-mpc-albums-mode-map (kbd "n") #'next-line) +(define-key jao-mpc-albums-mode-map (kbd "p") #'previous-line) +(define-key jao-mpc-albums-mode-map (kbd "RET") #'jao-mpc-add-and-play) +(define-key jao-mpc-albums-mode-map (kbd "q") #'bury-buffer) + +(defun jao-mpc--album-buffer () + (if-let (b (get-buffer jao-mpc--albums)) + b + (with-current-buffer (get-buffer-create jao-mpc--albums) + (jao-mpc-albums-mode) + (current-buffer)))) + +(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))) + +(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)) + (insert (shell-command-to-string "mpc playlist")) + (goto-char (point-min)) + (read-only-mode 1)) + +(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) + +(defun jao-mpc--playlist-buffer () + (if-let (b (get-buffer jao-mpc--playlist)) + b + (with-current-buffer (get-buffer-create jao-mpc--playlist) + (jao-mpc-playlist-mode) + (current-buffer)))) + +;;;###autoload +(defun jao-mpc-stop () + (interactive) + (shell-command-to-string "mpc stop")) + +;;;###autoload +(defun jao-mpc-toggle () + (interactive) + (jao-mpc--send "pause" nil)) + +;;;###autoload +(defun jao-mpc-play () + (interactive) + (jao-mpc--send "play" nil)) + +;;;###autoload +(defun jao-mpc-next () + (interactive) + (jao-mpc--send "next" nil)) + +;;;###autoload +(defun jao-mpc-previous () + (interactive) + (jao-mpc--send "previous" nil)) + +;;;###autoload +(defun jao-mpc-echo-current () + (interactive) + (jao-notify (jao-mpc--current-str))) + +;;;###autoload +(defun jao-mpc-show-albums () + "Show album list." + (interactive) + (pop-to-buffer (jao-mpc--album-buffer))) + +;;;###autoload +(defun jao-mpc-show-playlist () + "Show current playlist." + (interactive) + (pop-to-buffer (jao-mpc--playlist-buffer))) + +;;;###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)))) + +;;;###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)) + +(provide 'jao-mpc) +;;; jao-mpc.el ends here -- cgit v1.2.3