Playing music from Emacs.
;;; music.el --- Cunene: My emacs configuration. -*- lexical-binding: t -*-
;; Author: Marco Craveiro <[email protected]> URL:
;; https://github.com/mcraveiro/prelude Version: 0.0.3 Keywords: convenience
;; This file is not part of GNU Emacs.
;;; Commentary:
;; General editor configuration
;;; License:
;; 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Code:
bongo | https://github.com/dbrock/bongo |
Source:
(use-package bongo
:ensure t
:config
;; (setq bongo-default-directory "~/Music") ;; causes problems
(setq bongo-prefer-library-buffers nil
bongo-insert-whole-directory-trees t
bongo-logo nil
bongo-display-track-icons nil
bongo-display-track-lengths nil
bongo-display-header-icons nil
bongo-display-playback-mode-indicator t
bongo-display-inline-playback-progress t
bongo-join-inserted-tracks nil
bongo-field-separator (propertize " · " 'face 'shadow)
bongo-mark-played-tracks t
bongo-header-line-mode nil
bongo-mode-line-indicator-mode nil
bongo-enabled-backends '(vlc mpv)
bongo-vlc-program-name "cvlc")
;; ;;; Bongo playlist buffer
;; (defvar cunene/bongo-playlist-delimiter
;; "\n******************************\n\n"
;; "Delimiter for inserted items in `bongo' playlist buffers.")
;; (defun cunene/bongo-playlist-section ()
;; (bongo-insert-comment-text
;; cunene/bongo-playlist-delimiter))
;; (defun cunene/bongo-paylist-section-next ()
;; "Move to next `bongo' playlist custom section delimiter."
;; (interactive)
;; (let ((section "^\\*+$"))
;; (if (save-excursion (re-search-forward section nil t))
;; (progn
;; (goto-char (point-at-eol))
;; (re-search-forward section nil t))
;; (goto-char (point-max)))))
;; (defun cunene/bongo-paylist-section-previous ()
;; "Move to previous `bongo' playlist custom section delimiter."
;; (interactive)
;; (let ((section "^\\*+$"))
;; (if (save-excursion (re-search-backward section nil t))
;; (progn
;; (goto-char (point-at-bol))
;; (re-search-backward section nil t))
;; (goto-char (point-min)))))
;; (defun cunene/bongo-playlist-mark-section ()
;; "Mark `bongo' playlist section, delimited by custom markers.
;; The marker is `cunene/bongo-playlist-delimiter'."
;; (interactive)
;; (let ((section "^\\*+$"))
;; (search-forward-regexp section nil t)
;; (push-mark nil t)
;; (forward-line -1)
;; ;; REVIEW any predicate to replace this `save-excursion'?
;; (if (save-excursion (re-search-backward section nil t))
;; (progn
;; (search-backward-regexp section nil t)
;; (forward-line 1))
;; (goto-char (point-min)))
;; (activate-mark)))
;; (defun cunene/bongo-playlist-kill-section ()
;; "Kill `bongo' playlist-section at point.
;; This operates on a custom delimited section of the buffer. See
;; `cunene/bongo-playlist-kill-section'."
;; (interactive)
;; (cunene/bongo-playlist-mark-section)
;; (bongo-kill))
;; (defun cunene/bongo-playlist-play-random ()
;; "Play random `bongo' track and determine further conditions."
;; (interactive)
;; (unless (bongo-playlist-buffer)
;; (bongo-playlist-buffer))
;; (when (or (bongo-playlist-buffer-p)
;; (bongo-library-buffer-p))
;; (unless (bongo-playing-p)
;; (with-current-buffer (bongo-playlist-buffer)
;; (bongo-play-random)
;; (bongo-random-playback-mode 1)
;; (bongo-recenter)))))
;; (defun cunene/bongo-playlist-random-toggle ()
;; "Toggle `bongo-random-playback-mode' in playlist buffers."
;; (interactive)
;; (if (eq bongo-next-action 'bongo-play-random-or-stop)
;; (bongo-progressive-playback-mode)
;; (bongo-random-playback-mode)))
;; (defun cunene/bongo-playlist-reset ()
;; "Stop playback and reset `bongo' playlist marks.
;; To reset the playlist is to undo the marks produced by non-nil
;; `bongo-mark-played-tracks'."
;; (interactive)
;; (when (bongo-playlist-buffer-p)
;; (bongo-stop)
;; (bongo-reset-playlist)))
;; (defun cunene/bongo-playlist-terminate ()
;; "Stop playback and clear the entire `bongo' playlist buffer.
;; Contrary to the standard `bongo-erase-buffer', this also removes
;; the currently-playing track."
;; (interactive)
;; (when (bongo-playlist-buffer-p)
;; (bongo-stop)
;; (bongo-erase-buffer)))
;; (defun cunene/bongo-playlist-insert-playlist-file ()
;; "Insert contents of playlist file to a `bongo' playlist.
;; Upon insertion, playback starts immediately, in accordance with
;; `cunene/bongo-play-random'.
;; The available options at the completion prompt point to files
;; that hold filesystem paths of media items. Think of them as
;; 'directories of directories' that mix manually selected media
;; items.
;; Also see `cunene/bongo-dired-make-playlist-file'."
;; (interactive)
;; (let* ((path "~/Music/playlists/")
;; (dotless directory-files-no-dot-files-regexp)
;; (playlists (mapcar
;; 'abbreviate-file-name
;; (directory-files path nil dotless)))
;; (choice (completing-read "Insert playlist: " playlists nil t)))
;; (if (bongo-playlist-buffer-p)
;; (progn
;; (save-excursion
;; (goto-char (point-max))
;; (bongo-insert-playlist-contents
;; (format "%s%s" path choice))
;; (cunene/bongo-playlist-section))
;; (cunene/bongo-playlist-play-random))
;; (user-error "Not in a `bongo' playlist buffer"))))
;; ;;; Bongo + Dired (bongo library buffer)
;; (defmacro cunene/bongo-dired-library (name doc val)
;; "Create `bongo' library function NAME with DOC and VAL."
;; `(defun ,name ()
;; ,doc
;; (when (string-match-p "\\`~/Music/" default-directory)
;; (bongo-dired-library-mode ,val))))
;; (cunene/bongo-dired-library
;; cunene/bongo-dired-library-enable
;; "Set `bongo-dired-library-mode' when accessing ~/Music.
;; Add this to `dired-mode-hook'. Upon activation, the directory
;; and all its sub-directories become a valid library buffer for
;; Bongo, from where we can, among others, add tracks to playlists.
;; The added benefit is that Dired will continue to behave as
;; normal, making this a superior alternative to a purpose-specific
;; library buffer.
;; Note, though, that this will interfere with `wdired-mode'. See
;; `cunene/bongo-dired-library-disable'."
;; 1)
;; ;; NOTE `cunene/bongo-dired-library-enable' does not get reactivated
;; ;; upon exiting `wdired-mode'.
;; ;;
;; ;; TODO reactivate bongo dired library upon wdired exit
;; (cunene/bongo-dired-library
;; cunene/bongo-dired-library-disable
;; "Unset `bongo-dired-library-mode' when accessing ~/Music.
;; This should be added `wdired-mode-hook'. For more, refer to
;; `cunene/bongo-dired-library-enable'."
;; -1)
;; (defun cunene/bongo-dired-insert-files ()
;; "Add files in a `dired' buffer to the `bongo' playlist."
;; (let ((media (dired-get-marked-files)))
;; (with-current-buffer (bongo-playlist-buffer)
;; (goto-char (point-max))
;; (mapc 'bongo-insert-file media)
;; (cunene/bongo-playlist-section))
;; (with-current-buffer (bongo-library-buffer)
;; (dired-next-line 1))))
;; (defun cunene/bongo-dired-insert ()
;; "Add `dired' item at point or marks to `bongo' playlist.
;; The playlist is created, if necessary, while some other tweaks
;; are introduced. See `cunene/bongo-dired-insert-files' as well as
;; `cunene/bongo-playlist-play-random'.
;; Meant to work while inside a `dired' buffer that doubles as a
;; library buffer (see `cunene/bongo-dired-library')."
;; (interactive)
;; (when (bongo-library-buffer-p)
;; (unless (bongo-playlist-buffer-p)
;; (bongo-playlist-buffer))
;; (cunene/bongo-dired-insert-files)
;; (cunene/bongo-playlist-play-random)))
;; (defun cunene/bongo-dired-make-playlist-file ()
;; "Add `dired' marked items to playlist file using completion.
;; These files are meant to reference filesystem paths. They ease
;; the task of playing media from closely related directory trees,
;; without having to interfere with the user's directory
;; structure (e.g. a playlist file 'rock' can include the paths of
;; ~/Music/Scorpions and ~/Music/Queen).
;; This works by appending the absolute filesystem path of each item
;; to the selected playlist file. If no marks are available, the
;; item at point will be used instead.
;; Selecting a non-existent file at the prompt will create a new
;; entry whose name matches user input. Depending on the completion
;; framework, such as with `icomplete-mode', this may require a
;; forced exit (e.g. \\[exit-minibuffer] to parse the input without
;; further questions).
;; Also see `cunene/bongo-playlist-insert-playlist-file'."
;; (interactive)
;; (let* ((dotless directory-files-no-dot-files-regexp)
;; (pldir "~/Music/playlists")
;; (playlists (mapcar
;; 'abbreviate-file-name
;; (directory-files pldir nil dotless)))
;; (plname (completing-read "Select playlist: " playlists nil nil))
;; (plfile (format "%s/%s" pldir plname))
;; (media-paths
;; (if (derived-mode-p 'dired-mode)
;; ;; TODO more efficient way to do ensure newline ending?
;; ;;
;; ;; The issue is that we need to have a newline at the
;; ;; end of the file, so that when we append again we
;; ;; start on an empty line.
;; (concat
;; (mapconcat #'identity
;; (dired-get-marked-files)
;; "\n")
;; "\n")
;; (user-error "Not in a `dired' buffer"))))
;; ;; The following `when' just checks for an empty string. If we
;; ;; wanted to make this more robust we should also check for names
;; ;; that contain only spaces and/or invalid characters… This is
;; ;; good enough for me.
;; (when (string-empty-p plname)
;; (user-error "No playlist file has been specified"))
;; (unless (file-directory-p pldir)
;; (make-directory pldir))
;; (unless (and (file-exists-p plfile)
;; (file-readable-p plfile)
;; (not (file-directory-p plfile)))
;; (make-empty-file plfile))
;; (append-to-file media-paths nil plfile)
;; (with-current-buffer (find-file-noselect plfile)
;; (delete-duplicate-lines (point-min) (point-max))
;; (sort-lines nil (point-min) (point-max))
;; (save-buffer)
;; (kill-buffer))))
;; :hook ((dired-mode-hook . cunene/bongo-dired-library-enable)
;; (wdired-mode-hook . cunene/bongo-dired-library-disable))
;; :bind (
;; ("<C-XF86AudioPlay>" . bongo-pause/resume)
;; ("<C-XF86AudioNext>" . bongo-next)
;; ("<C-XF86AudioPrev>" . bongo-previous)
;; ("<M-XF86AudioPlay>" . bongo-show)
;; ("<S-XF86AudioNext>" . bongo-seek-forward-10)
;; ("<S-XF86AudioPrev>" . bongo-seek-backward-10)
;; :map bongo-playlist-mode-map
;; ("n" . bongo-next-object)
;; ("p" . bongo-previous-object)
;; ("M-n" . cunene/bongo-paylist-section-next)
;; ("M-p" . cunene/bongo-paylist-section-previous)
;; ("M-h" . cunene/bongo-playlist-mark-section)
;; ("M-d" . cunene/bongo-playlist-kill-section)
;; ("g" . cunene/bongo-playlist-reset)
;; ("D" . cunene/bongo-playlist-terminate)
;; ("r" . cunene/bongo-playlist-random-toggle)
;; ("R" . bongo-rename-line)
;; ("j" . bongo-dired-line) ; Jump to dir of file at point
;; ("J" . dired-jump) ; Jump to library buffer
;; ("i" . cunene/bongo-playlist-insert-playlist-file)
;; ("I" . bongo-insert-special)
;; :map bongo-dired-library-mode-map
;; ("<C-return>" . cunene/bongo-dired-insert)
;; ("C-c SPC" . cunene/bongo-dired-insert)
;; ("C-c +" . cunene/bongo-dired-make-playlist-file))
)
;;; music.el ends here