#:use-module (gnu packages emacs-xyz)
#:use-module (gnu packages freedesktop)
#:use-module (gnu packages gnupg)
+ #:use-module (gnu packages linux)
#:use-module (gnu packages mail)
#:use-module (gnu packages password-utils)
#:use-module (gnu packages pdf)
#:use-module (gnu packages rust-apps)
+ #:use-module (gnu packages video)
#:use-module (gnu services)
#:use-module (guix gexp)
#:export (emacs-services))
(dotfiles
(list "emacs/.config/emacs/conf/conf-minibuffer.el")))))
+(define emacs-music-service
+ (service home-program-service-type
+ (home-program-configuration
+ (packages
+ (list alsa-utils
+ mpv
+ emacs-alsamixer-el
+ emacs-bongo))
+ (dotfiles
+ (list "bash/.config/profile.d/50-alsa.sh"
+ "emacs/.config/emacs/conf/conf-music.el")))))
+
(define emacs-package-service
(service home-program-service-type
(home-program-configuration
emacs-keys-service
emacs-language-service
emacs-minibuffer-service
+ emacs-music-service
emacs-package-service
emacs-pass-service
emacs-service))
--- /dev/null
+;; Copyright (c) 2022 Jakub Czajka <jakub@ekhem.eu.org>
+;; License: GPL-3.0 or later.
+;;
+;; conf-music.el - configuration for the music player.
+
+(require 'conf-package)
+(require 'conf-variables)
+
+(defcustom conf:music-directory
+ (expand-file-name "~/Music")
+ "Directory with music playlists."
+ :type 'directory
+ :group 'conf:configuration)
+
+(use-package alsamixer
+ :when
+ (conf:executables-p '("alsamixer"))
+ :ensure t
+ :bind
+ ("C-c v" . alsamixer-set-volume))
+
+(use-package bongo
+ :requires
+ (conf-keys)
+ :when
+ (conf:executables-p (list "mpv"))
+ :ensure t
+ :bind
+ ("C-c b" . conf:bongo-transient)
+ :custom
+ (bongo-default-directory conf:music-directory)
+ ;; Insert tracks from directories without asking.
+ (bongo-insert-whole-directory-trees t)
+ ;; Show playlist information in the mode line.
+ (bongo-mode-line-indicator-mode t)
+ (bongo-mode-line-indicator-function
+ #'conf:bongo-mode-line-indicator-with-track-name)
+ :config
+ (defun conf:bongo--find-file (file)
+ "Returns the position of the line with track `file' in the playlist buffer. \
+If no matching line is found, return nil."
+ (with-bongo-playlist-buffer
+ (save-excursion
+ (bongo-point-at-first-line-satisfying
+ (lambda ()
+ (equal (bongo-line-file-name) file))
+ nil))))
+
+ (defun conf:bongo-play-with-completion ()
+ "Inserts and plays a file from `bongo-default-directory', with completion.
+Selects a file from `bongo-default-directory' with `completing-read'. \
+If the selected item is already present in the playlist, plays the track. \
+Otherwise, if the selected item is a regular file, inserts the file to the \
+playlist and plays it. Otherwise, if the selected item is a directory, inserts \
+all the files from the directory and plays the first track."
+ (interactive)
+ (let* ((files (directory-files bongo-default-directory t "^[a-zA-Z0-9\-_]+"))
+ (names (mapcar #'file-name-base files))
+ (name (completing-read "Play: " names))
+ (file (seq-find
+ (lambda (file)
+ (string= (file-name-base file) name))
+ files)))
+ (with-bongo-playlist-buffer
+ (unless (conf:bongo--find-file file)
+ (bongo-insert-file file))
+ (if (file-directory-p file)
+ (bongo-play-line (bongo-point-at-first-track-line))
+ (bongo-play-line (conf:bongo--find-file file))))))
+
+ (defun conf:bongo-restart-playlist ()
+ "Restarts the current playlist."
+ (interactive)
+ (with-bongo-playlist-buffer
+ (save-excursion
+ (goto-char (bongo-point-at-first-track-line))
+ (bongo-play-line))))
+
+ (defun conf:bongo-quit ()
+ "Kills the current playlist."
+ (interactive)
+ (with-bongo-playlist-buffer
+ (kill-buffer bongo-default-playlist-buffer-name)))
+
+ (defun conf:bongo-mode-line-indicator-with-track-name ()
+ "Mode line indicator which appends the name of the current track to \
+`bongo-default-mode-line-indicator-function'."
+ (with-bongo-playlist-buffer
+ (save-excursion
+ (goto-char (bongo-point-at-current-track-line))
+ (if (bongo-current-track-line-p)
+ (concat (bongo-default-mode-line-indicator-function)
+ (file-name-base (bongo-line-file-name)))
+ (bongo-default-mode-line-indicator-function)))))
+
+ ;; Put `bongo' commands under a single keymap.
+ (transient-define-prefix conf:bongo-transient ()
+ "Transient keymap with usefeul commands for `bongo'."
+ [["State"
+ ("i" "play" conf:bongo-play-with-completion)
+ ("s" "pause" bongo-pause/resume)
+ ("r" "restart" conf:bongo-restart-playlist)
+ ("q" "quit" conf:bongo-quit)]
+ ["Song"
+ ("p" "previous" bongo-play-previous)
+ ("n" "next" bongo-play-next)]]))
+
+(provide 'conf-music)