Music
Playing music from Emacs.
Preamble
;;; music.el --- Cunene: My emacs configuration. -*- lexical-binding: t -*- ;; Author: Marco Craveiro <marco_craveiro@gmail.com> 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
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)) )
Postamble
;;; music.el ends here