summaryrefslogtreecommitdiff
path: root/bongo.el
diff options
context:
space:
mode:
Diffstat (limited to 'bongo.el')
-rw-r--r--bongo.el1074
1 files changed, 514 insertions, 560 deletions
diff --git a/bongo.el b/bongo.el
index a0a6753..7ea7347 100644
--- a/bongo.el
+++ b/bongo.el
@@ -1,115 +1,263 @@
-;;; -*- lexical-binding: t; -*-
-
-(use-package "bongo" 'bongo
-
- (require 'json)
- (setq bongo-track-mark-icon-file-name nil)
- (setq volume-electric-mode nil)
- (setq bongo-default-directory (expand-file-name "~/Desktop/Centre/Musique"))
- (setq bongo-prefer-library-buffers nil)
- (setq bongo-insert-whole-directory-trees t)
- (setq bongo-logo nil)
- (setq bongo-action-track-icon nil)
- (setq bongo-display-track-icons nil)
- (setq bongo-display-track-lengths nil)
- (setq bongo-display-header-icons nil)
- (setq bongo-display-playback-mode-indicator t)
- (setq bongo-display-inline-playback-progress nil)
- (setq bongo-mark-played-tracks nil)
- (setq bongo-header-line-mode t)
- (setq bongo-header-line-function #'bongo-default-header-line-function)
- (setq bongo-mode-line-indicator-mode nil)
- (setq bongo-enabled-backends '(mpv))
- (setq bongo-seek-electric-mode nil)
- (setq bongo-custom-backend-matchers
- '((mpv local-file "webm" "m4a")
- ;; NOTE
- ;; For a regular expression as a matcher, it is supposed to
- ;; be a string, instead of a list of strings.
- (mpv "https:" . "youtube")))
- (setq-default bongo-next-action 'durand-bongo-play-next-or-first)
-
- ;; Bongo info path
+;;; bongo.el --- My configurations of Bongo -*- lexical-binding: t; -*-
-;;;###autoload
- (eval-after-load 'info
- '(cond
- ((null Info-directory-list)
- (setq Info-directory-list (append Info-default-directory-list
- (list (expand-file-name "bongo/" package-dir)))))
- ((add-to-list 'Info-directory-list (expand-file-name "bongo/" package-dir)))))
+;; Copyright (C) 2022 Jean Sévère Durand
-;;;###autoload
- (defvar durand-bongo-music-dir nil
- "Directories to store my songs.
-This is used since my music directories used to contain symbolic links.")
-
- (setq durand-bongo-music-dir
- (cons bongo-default-directory
- (delq
- nil
- (mapcar
- (lambda (file)
- (cond
- ((let ((attr (car (file-attributes file))))
- (and (stringp attr)
- (file-directory-p attr)))
- file)))
- (directory-files-recursively
- bongo-default-directory
- ".*" t nil t)))
- ;; (cl-loop for file in (directory-files-recursively
- ;; bongo-default-directory
- ;; ".*" t nil t)
- ;; for attr = (car (file-attributes file))
- ;; if (and (stringp attr)
- ;; (file-directory-p attr))
- ;; collect attr)
- ))
-
- (define-key global-map (vector ?\C-c ?b) #'bongo)
- (define-key bongo-playlist-mode-map [?n] #'bongo-next-object-line)
- (define-key bongo-playlist-mode-map [?p] #'bongo-previous-object-line)
- (define-key bongo-playlist-mode-map [?j] #'durand-bongo-save-playlist)
- (define-key bongo-playlist-mode-map [tab] #'bongo-show)
- (define-key bongo-playlist-mode-map [?\C-c ?n] #'durand-bongo-play-next-or-first)
- (define-key bongo-playlist-mode-map [?\C-c ?p] #'durand-bongo-play-previous-or-last)
- (define-key bongo-dired-library-mode-map [?\C-j] #'durand-bongo-dired-ivy-find-to-add)
- (define-key bongo-dired-library-mode-map [?\C-c ?n] #'durand-bongo-play-next-or-first)
- (define-key bongo-dired-library-mode-map [?\C-c ?p] #'durand-bongo-play-previous-or-last)
- (define-key bongo-playlist-mode-map [?\C-d] #'prot/bongo-clear-playlist-and-stop)
- (define-key bongo-playlist-mode-map [?x] #'durand-bongo-stop-and-exit)
- (define-key bongo-playlist-mode-map [?I] #'durand-bongo-insert-delete-playlist)
- (define-key bongo-dired-library-mode-map [C-return] #'prot/bongo-library-insert-and-play-random)
-
- (add-hook 'dired-mode-hook #'durand-bongo-dired-library)
-
- ;; seek mode map additions
-
- (define-key bongo-seek-mode-map [?t] 'bongo-seek-to)
-
- ;;; functions
+;; Author: Jean Sévère Durand <durand@jsdurand.xyz>
+;; Keywords: files, games, hardware, hypermedia, multimedia
-;;;###autoload
- (defun contrib/bongo-add-dired-files ()
- "Add marked files inside of a Dired buffer to the Bongo library."
- (interactive)
- (require 'dired)
- (let (file-point file files)
- (dired-map-over-marks
- (setq file-point (dired-move-to-filename)
- file (dired-get-filename)
- files (append files (list file)))
- nil t)
- (ignore file-point)
- (with-current-buffer (bongo-playlist-buffer)
- (let ((beg (point)))
- (mapc 'bongo-insert-file files)
- (bongo-maybe-join-inserted-tracks beg (point))))))
+;; 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.
-;;;###autoload
- (defun durand-bongo-dired-library ()
- "Set `bongo-dired-library-mode' when accessing `bongo-default-directory'.
+;; 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 <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is my configuration file for Bongo.
+
+;;; Code:
+
+;;; First require bongo
+
+(use-package "bongo" 'bongo)
+
+;;; Basic customizations
+
+;;;; No electric modes
+
+;; I just don't like those.
+
+(setq bongo-seek-electric-mode nil)
+(setq volume-electric-mode nil)
+
+;;;; No icons
+
+(setq bongo-track-mark-icon-file-name nil)
+(setq bongo-action-track-icon nil)
+(setq bongo-display-track-icons nil)
+(setq bongo-display-header-icons nil)
+
+;;;; No special handling of tracks
+
+;; I do not distinguish tracks especially.
+;;
+;; Maybe this will change in the future.
+
+(setq bongo-display-track-lengths nil)
+
+;;;; Default directory to find music
+
+(setq bongo-default-directory
+ (expand-file-name "~/Desktop/Centre/Musique"))
+
+;;;; Prefer playlist buffer
+
+(setq bongo-prefer-library-buffers nil)
+
+;;;; Insert whose directory tree
+
+(setq bongo-insert-whole-directory-trees t)
+
+;;;; No logo
+
+(setq bongo-logo nil)
+
+;;;; No inline playback indication
+
+;; But no inline indication
+(setq bongo-display-inline-playback-progress nil)
+
+;;;; Do not mark played tracks
+
+(setq bongo-mark-played-tracks nil)
+
+;;;; Display song name in the header line
+
+(setq bongo-header-line-mode t)
+(setq bongo-header-line-function #'bongo-default-header-line-function)
+
+;;;; Disable mode line indication by default
+
+(setq bongo-mode-line-indicator-mode nil)
+
+(setq bongo-display-playback-mode-indicator t)
+
+;;;; Backend
+
+(setq bongo-enabled-backends (list 'mpv))
+
+(setq bongo-custom-backend-matchers
+ '((mpv local-file "webm" "m4a")
+ ;; NOTE
+ ;;
+ ;; For a regular expression as a matcher, it is supposed to be
+ ;; a string, instead of a list of strings.
+ (mpv "https:" . "youtube")))
+
+;;; Circular playing
+
+(setq-default bongo-next-action #'durand-bongo-play-next-or-first)
+
+(defun durand-bongo-play-next-or-first (&optional n)
+ "Start playing the next track in the nearest Bongo playlist buffer.
+If there is no next track to play, signal an error.
+With numerical prefix argument N, skip that many tracks.
+With \\[universal-argument] as prefix argument, just switch to \
+progressive playback mode.
+With \\[universal-argument] \\[universal-argument] as prefix argument, \
+insert an action track at point."
+ (interactive "P")
+ (cond
+ ((equal n '(16))
+ (bongo-insert-line 'bongo-action '(bongo-progressive-playback-mode)))
+ ((equal n '(4))
+ (bongo-progressive-playback-mode))
+ ((consp n)
+ (user-error "This prefix argument %S is not supported."
+ n))
+ ((< (prefix-numeric-value n) 0)
+ (durand-bongo-play-previous-or-last (- (prefix-numeric-value n))))
+ (t
+ (with-imminent-bongo-player-start
+ (bongo-stop)
+ (when bongo-mark-played-tracks
+ (bongo-mark-current-track-line-as-played))
+ (durand-bongo-next-or-first n)
+ (bongo-start)))))
+
+(defun durand-bongo-play-previous-or-last (&optional n)
+ "Start playing the previous track in the nearest playlist buffer.
+If there is no previous track to play, play the last track.
+
+With numerical prefix argument N, skip that many tracks.
+
+With \\[universal-argument] as prefix argument, just switch to
+regressive playback mode.
+
+With \\[universal-argument] \\[universal-argument] as prefix
+argument, insert an action track at point."
+ (interactive "P")
+ (cond
+ ((equal n '(16))
+ (bongo-insert-line 'bongo-action '(bongo-regressive-playback-mode)))
+ ((equal n '(4))
+ (bongo-regressive-playback-mode))
+ ((consp n)
+ (user-error "This prefix argument %S is not supported."
+ n))
+ ((< (prefix-numeric-value n) 0)
+ (durand-bongo-play-next-or-first (- (prefix-numeric-value n))))
+ (t
+ (with-imminent-bongo-player-start
+ (bongo-stop)
+ (when bongo-mark-played-tracks
+ (bongo-mark-current-track-line-as-played))
+ (durand-bongo-previous-or-last n)
+ (bongo-start)))))
+
+(defun durand-bongo-play-first ()
+ "Play the first song."
+ (interactive)
+ (with-bongo-playlist-buffer
+ (with-imminent-bongo-player-start
+ (bongo-stop)
+ (when bongo-mark-played-tracks
+ (bongo-mark-current-track-line-as-played))
+ (goto-char (or (bongo-point-at-first-track-line)
+ (prog1 (point)
+ (message "No track in the playlist buffer."))))
+ (bongo-set-current-track-position)
+ (bongo-start))))
+
+(defun durand-bongo-play-last ()
+ "Play the last song."
+ (interactive)
+ (with-bongo-playlist-buffer
+ (with-imminent-bongo-player-start
+ (bongo-stop)
+ (when bongo-mark-played-tracks
+ (bongo-mark-current-track-line-as-played))
+ (goto-char (or (bongo-point-at-last-track-line)
+ (prog1 (point)
+ (message "No track in the playlist buffer."))))
+ (bongo-set-current-track-position)
+ (bongo-start))))
+
+;;; Bongo info path
+
+;; I place bongo in a custom path, so I need to provide the path to
+;; its info files.
+
+(eval-after-load 'info
+ '(cond
+ ((null Info-directory-list)
+ (setq Info-directory-list
+ (append Info-default-directory-list
+ (list (expand-file-name "bongo/" package-dir)))))
+ ((add-to-list 'Info-directory-list
+ (expand-file-name "bongo/" package-dir)))))
+
+;;; Custom music directory
+
+;; This is not needed anymore, but is still preserved, in case of
+;; future needs.
+
+(defvar durand-bongo-music-dir nil
+ "Directories to store my songs.
+This is used since my music directories used to contain symbolic
+links.")
+
+(setq durand-bongo-music-dir
+ (cons bongo-default-directory
+ (delq
+ nil
+ (mapcar
+ (lambda (file)
+ (cond
+ ((let ((attr (car (file-attributes file))))
+ (and (stringp attr)
+ (file-directory-p attr)))
+ file)))
+ (directory-files-recursively
+ bongo-default-directory
+ ".*" t nil t)))))
+
+;;; Key bindings
+
+(define-key global-map (vector 3 ?b) #'bongo)
+
+;; to avoid repetitions
+(let ((map bongo-playlist-mode-map))
+ (define-key map [?n] #'bongo-next-object-line)
+ (define-key map [?p] #'bongo-previous-object-line)
+ (define-key map [?j] #'durand-bongo-save-playlist)
+ (define-key map [tab] #'bongo-show)
+ (define-key map [?\C-c ?n] #'durand-bongo-play-next-or-first)
+ (define-key map [?\C-c ?p] #'durand-bongo-play-previous-or-last)
+ (define-key map [?\C-d] #'prot/bongo-clear-playlist-and-stop)
+ (define-key map [?x] #'durand-bongo-stop-and-exit)
+ (define-key map [?I] #'durand-bongo-insert-delete-playlist))
+
+(let ((map bongo-dired-library-mode-map))
+ (define-key map [?\C-c ?n] #'durand-bongo-play-next-or-first)
+ (define-key map [?\C-c ?p] #'durand-bongo-play-previous-or-last)
+ (define-key map [C-return]
+ #'prot/bongo-library-insert-and-play-random))
+
+(define-key bongo-seek-mode-map [?t] 'bongo-seek-to)
+
+;;; dired library mode
+
+(defun durand-bongo-dired-library ()
+ "Set `bongo-dired-library-mode' when accessing \
+`bongo-default-directory'.
This is meant to be hooked to `dired-mode'.
Upon activation, the directory and all its sub-directories become
@@ -130,496 +278,296 @@ Adapted from Protesilaos' dotemacs."
((file-in-directory-p default-directory dir)
(setq found t))))
found)
- (bongo-dired-library-mode 1)
- ;; (set (make-local-variable 'bongo-dired-library-mode) 't)
- )))
+ (bongo-dired-library-mode 1))))
-;;;###autoload
- (defun prot/bongo-clear-playlist-and-stop ()
- "Stop playback and clear the entire `bongo' playlist buffer.
+(add-hook 'dired-mode-hook #'durand-bongo-dired-library)
+
+(defun contrib/bongo-add-dired-files ()
+ "Add marked files inside of a Dired buffer to the Bongo library."
+ (interactive)
+ (require 'dired)
+ (let (file-point file files)
+ (dired-map-over-marks
+ (setq file-point (dired-move-to-filename)
+ file (dired-get-filename)
+ files (append files (list file)))
+ nil t)
+ (ignore file-point)
+ (with-current-buffer (bongo-playlist-buffer)
+ (let ((beg (point)))
+ (mapc 'bongo-insert-file files)
+ (bongo-maybe-join-inserted-tracks beg (point))))))
+
+;;; Clear playlist and stop
+
+(defun prot/bongo-clear-playlist-and-stop ()
+ "Stop playback and clear the entire `bongo' playlist buffer.
Contrary to the standard `bongo-erase-buffer', this also removes
the currently-playing track.
Modified by Durand so that this also runs while not in a bongo
buffer."
- (interactive)
- (with-bongo-playlist-buffer
- (bongo-stop)
- (bongo-erase-buffer)))
+ (interactive)
+ (with-bongo-playlist-buffer (bongo-stop) (bongo-erase-buffer)))
-
+;;; Random playing
-;;;###autoload
- (defun prot/bongo-play-random ()
- "Play a random track with `bongo' and set random playback."
- (interactive)
- (when (or (bongo-playlist-buffer-p)
- (bongo-library-buffer-p))
- (bongo-play-random)
- (setf bongo-next-action 'durand-bongo-play-next-or-first)
- ;; (bongo-random-playback-mode 1)
- ))
+(defun prot/bongo-play-random ()
+ "Play a random track with `bongo'."
+ (interactive)
+ (when (or (bongo-playlist-buffer-p)
+ (bongo-library-buffer-p))
+ (bongo-play-random)
+ (setf bongo-next-action #'durand-bongo-play-next-or-first)))
-;;;###autoload
- (defun prot/bongo-library-insert-and-play-random ()
- "Add directory tree or marked items to the `bongo' playlist.
+(defun prot/bongo-library-insert-and-play-random ()
+ "Add directory tree or marked items to the `bongo' playlist.
Create the playlist buffer if necessary.
+
This is meant to work while inside a `dired' buffer that doubles
as a library buffer (see `prot/bongo-dired-library')."
- (interactive)
- (when (bongo-library-buffer-p)
- (unless (bongo-playlist-buffer-p)
- (bongo-playlist-buffer))
- (contrib/bongo-add-dired-files)
- ;; (prot/bongo-play-random)
- ))
+ (interactive)
+ (when (bongo-library-buffer-p)
+ (unless (bongo-playlist-buffer-p)
+ (bongo-playlist-buffer))
+ (contrib/bongo-add-dired-files)))
-;;;###autoload
- (defun durand-bongo-insert-delete-playlist ()
- "Insert or delete a `bongo' playlist.
+;;; Playlist
+
+;;;; Insert or delete a playlist
+
+(defun durand-bongo-insert-delete-playlist ()
+ "Insert or delete a `bongo' playlist.
The files are stored in a predetermined path inside the Music
directory. Upon insertion, playback starts immediately, in
accordance with `prot/bongo-play-random'.
Adapted from Protesilaos' dotemacs by Durand."
- (interactive)
- (let* ((path (file-name-as-directory
- (expand-file-name
- "playlists"
- bongo-default-directory)))
- (dotless directory-files-no-dot-files-regexp)
- (playlist (directory-files path t dotless)))
- (with-bongo-playlist-buffer
- (bongo-insert-playlist-contents
- (completing-read "Select playlist: " playlist nil t path)))))
+ (interactive)
+ (let* ((path (file-name-as-directory
+ (expand-file-name
+ "playlists"
+ bongo-default-directory)))
+ (dotless directory-files-no-dot-files-regexp)
+ (playlist (directory-files path t dotless)))
+ (with-bongo-playlist-buffer
+ (bongo-insert-playlist-contents
+ (completing-read "Select playlist: " playlist nil t path)))))
-;;;###autoload
- ;; (defun durand-bongo-dired-ivy-find-to-add ()
- ;; "Use `durand-choose-list' to find files to add to bongo."
- ;; (interactive)
- ;; ;; (require 'counsel)
- ;; (require 'grep)
- ;; ;; (counsel-require-program find-program)
- ;; ;; (cl-assert
- ;; ;; (and (derived-mode-p 'dired-mode)
- ;; ;; (file-in-directory-p default-directory bongo-default-directory)))
- ;; (let* ((default-directory
- ;; (cond
- ;; ((and (derived-mode-p 'dired-mode)
- ;; (file-in-directory-p default-directory bongo-default-directory))
- ;; default-directory)
- ;; (t
- ;; bongo-default-directory)))
- ;; (all-files (counsel--find-return-list counsel-file-jump-args))
- ;; (base default-directory)
- ;; (chosen-files (durand-choose-list (mapcar 'list all-files) nil "Choose music to add: " t
- ;; nil nil t nil t)))
- ;; (cl-loop for song in chosen-files
- ;; do
- ;; (with-bongo-playlist-buffer
- ;; (bongo-insert-file
- ;; (file-truename (expand-file-name song base)))))
- ;; ;; (ivy-read "Choose music to add: " all-files
- ;; ;; :require-match t
- ;; ;; :action (lambda (f)
- ;; ;; (with-current-buffer bongo-default-playlist-buffer-name
- ;; ;; (bongo-insert-file
- ;; ;; (file-truename (expand-file-name f base))))))
- ;; ))
-
- ;; REVIEW: This is oft not overriding the original function, to the effect that
- ;; the first time bongo starts, this function does not work, and I have to
- ;; define this function again, in order to play the music. So I decided to make
- ;; this into an overriding advice.
-;;;###autoload
- (defun durand-bongo-compose-remote-option (socket-file)
- "Get the command line argument for starting mpv's remote interface at SOCKET-FILE.
-This has to be fixed for mpv to work, since its argument parsing
-convention is changed."
- ;; :override 'bongo-compose-remote-option
- (when (equal bongo-mpv-remote-option 'unknown)
- (setq bongo-mpv-remote-option (bongo--mpv-get-remote-option)))
- (list (concat bongo-mpv-remote-option "=" socket-file)))
+;;;; Save playlist
- (advice-add #'bongo-compose-remote-option :override 'durand-bongo-compose-remote-option)
+(defvar durand-bongo-save-playlist-hist nil
+ "A variable that holds the history values for saving playlist \
+names.")
-;;;###autoload
- (defvar durand-bongo-save-playlist-hist nil
- "A variable that holds the history values for saving playlist names.")
+(defun durand-bongo-save-playlist ()
+ "Save the current playlist into a file."
+ (interactive)
+ (let ((playlist-name
+ (expand-file-name
+ (read-string
+ "Playlist name:" nil 'durand-bongo-save-playlist-hist)
+ (expand-file-name "playlists"
+ bongo-default-directory)))
+ (append-p (y-or-n-p "Append? "))
+ files end)
+ (with-current-buffer bongo-default-playlist-buffer-name
+ (save-excursion
+ (goto-char (or (bongo-point-at-first-track-line)
+ (user-error
+ "No tracks in the playlist!")))
+ (push (bongo-line-file-name) files)
+ (while (not end)
+ (if-let ((next-pos (bongo-point-at-next-track-line)))
+ (progn
+ (goto-char next-pos)
+ (push (bongo-line-file-name) files))
+ (setf end t)))))
+ (with-temp-buffer
+ (cl-loop for file in files
+ do (progn
+ (insert file)
+ (newline)))
+ (write-region nil nil playlist-name append-p))))
+
+;;; Fix remote syntax
+
+;; REVIEW:
+;;
+;; This is oft not overriding the original function, to the effect
+;; that the first time bongo starts, this function does not work, and
+;; I have to define this function again, in order to play the
+;; music. So I decided to make this into an overriding advice.
+
+(defun durand-bongo-compose-remote-option (socket-file)
+ "Get the command line argument for starting mpv's remote interface \
+at SOCKET-FILE.
-;;;###autoload
- (defun durand-bongo-save-playlist ()
- "Save the current playlist into a file."
- (interactive)
- (let ((playlist-name
- (expand-file-name
- (read-string "Playlist name:" nil 'durand-bongo-save-playlist-hist)
- (expand-file-name "playlists"
- bongo-default-directory)))
- (append-p (y-or-n-p "Append? "))
- files end)
- (with-current-buffer bongo-default-playlist-buffer-name
- (save-excursion
- (goto-char (or (bongo-point-at-first-track-line)
- (user-error
- "No tracks in the playlist!")))
- (push (bongo-line-file-name) files)
- (while (not end)
- (if-let ((next-pos (bongo-point-at-next-track-line)))
- (progn
- (goto-char next-pos)
- (push (bongo-line-file-name) files))
- (setf end t)))))
- (with-temp-buffer
- (cl-loop for file in files
- do (progn
- (insert file)
- (newline)))
- (write-region nil nil playlist-name append-p))))
+This has to be fixed for mpv to work, since its argument parsing
+convention is changed."
+ (when (equal bongo-mpv-remote-option 'unknown)
+ (setq bongo-mpv-remote-option (bongo--mpv-get-remote-option)))
+ (list (concat bongo-mpv-remote-option "=" socket-file)))
-;;;###autoload
- (defun durand-bongo-next-or-first (&optional n)
- "Make the next track current in the nearest playlist buffer.
-If there is no next track, go to the first track.
-With prefix argument N, skip that many tracks."
- (interactive "P")
- (if (bongo-playing-p)
- (durand-bongo-play-next-or-first n)
- (with-bongo-playlist-buffer
- (let ((line-move-ignore-invisible nil))
- (save-excursion
- (goto-char (or (bongo-point-at-current-track-line)
- (bongo-point-at-first-track-line)
- (user-error "No tracks in playlist")))
- (dotimes (_dummy (prefix-numeric-value n))
- (goto-char (or (bongo-point-at-next-track-line)
- (bongo-point-at-first-track-line))))
- (bongo-set-current-track-position))))))
+(advice-add #'bongo-compose-remote-option :override 'durand-bongo-compose-remote-option)
-;;;###autoload
- (defun durand-bongo-play-next-or-first (&optional n)
- "Start playing the next track in the nearest Bongo playlist buffer.
-If there is no next track to play, signal an error.
-With numerical prefix argument N, skip that many tracks.
-With \\[universal-argument] as prefix argument, just switch to \
-progressive playback mode.
-With \\[universal-argument] \\[universal-argument] as prefix argument, \
-insert an action track at point."
- (interactive "P")
- (cond
- ((equal n '(16))
- (bongo-insert-line 'bongo-action '(bongo-progressive-playback-mode)))
- ((equal n '(4))
- (bongo-progressive-playback-mode))
- ((consp n)
- (user-error "This prefix argument %S is not supported."
- n))
- ((< (prefix-numeric-value n) 0)
- (durand-bongo-play-previous-or-last (- (prefix-numeric-value n))))
- (t
- (with-imminent-bongo-player-start
- (bongo-stop)
- (when bongo-mark-played-tracks
- (bongo-mark-current-track-line-as-played))
- (durand-bongo-next-or-first n)
- (bongo-start)))))
-
-;;;###autoload
- (defun durand-bongo-previous-or-last (&optional n)
- "Make the previous track current in the nearest playlist buffer.
-If there is no previous track, go to the last track.
-With prefix argument N, skip that many tracks."
- (interactive "p")
- (if (bongo-playing-p)
- (durand-bongo-play-previous-or-last n)
- (with-bongo-playlist-buffer
- (let ((line-move-ignore-invisible nil))
- (save-excursion
- (goto-char (or (bongo-point-at-current-track-line)
- (bongo-point-at-last-track-line)
- (user-error "No tracks in playlist")))
- (dotimes (_dummy (prefix-numeric-value n))
- (goto-char (or (bongo-point-at-previous-track-line)
- (bongo-point-at-last-track-line))))
- (bongo-set-current-track-position))))))
+;;; Custom seek function
-;;;###autoload
- (defun durand-bongo-play-previous-or-last (&optional n)
- "Start playing the previous track in the nearest playlist buffer.
-If there is no previous track to play, play the last track.
-With numerical prefix argument N, skip that many tracks.
-With \\[universal-argument] as prefix argument, just switch to \
-regressive playback mode.
-With \\[universal-argument] \\[universal-argument] as prefix argument, \
-insert an action track at point."
- (interactive "P")
+;; NOTE: Fix a bug: there is no face called `modeline'; it should be
+;; `mode-line'.
+(defun durand-bongo-seek ()
+ "Interactively seek in the current Bongo track."
+ ;; :override 'bongo-seek
+ (interactive)
+ (setq bongo-seek-buffer (get-buffer-create "*Bongo Seek*"))
+ (if bongo-seek-electric-mode
+ (unwind-protect
+ (save-window-excursion
+ (require 'electric)
+ (message nil)
+ (let ((garbage-collection-messages nil)
+ (bongo-seeking-electrically t))
+ (ignore bongo-seeking-electrically)
+ (set-window-buffer
+ (minibuffer-window) bongo-seek-buffer)
+ (select-window (minibuffer-window))
+ (let ((old-local-map (current-local-map))
+ (old-global-map (current-global-map)))
+ (use-local-map nil)
+ (use-global-map bongo-seek-mode-map)
+ (setq major-mode 'bongo-seek-mode)
+ (unwind-protect
+ (progn
+ (bongo-seek-redisplay)
+ (run-hooks 'bongo-seek-mode-hook)
+ (catch 'bongo-seek-done
+ (Electric-command-loop
+ 'bongo-seek-done
+ ;; Avoid `noprompt' due to
+ ;; a bug in electric.el.
+ '(lambda () 'noprompt)
+ nil
+ (lambda (_x _y) (bongo-seek-redisplay)))))
+ (use-local-map old-local-map)
+ (use-global-map old-global-map)))))
+ (when bongo-seek-buffer
+ (kill-buffer bongo-seek-buffer)
+ (setq bongo-seek-buffer nil)))
(cond
- ((equal n '(16))
- (bongo-insert-line 'bongo-action '(bongo-regressive-playback-mode)))
- ((equal n '(4))
- (bongo-regressive-playback-mode))
- ((consp n)
- (user-error "This prefix argument %S is not supported."
- n))
- ((< (prefix-numeric-value n) 0)
- (durand-bongo-play-next-or-first (- (prefix-numeric-value n))))
- (t
- (with-imminent-bongo-player-start
- (bongo-stop)
- (when bongo-mark-played-tracks
- (bongo-mark-current-track-line-as-played))
- (durand-bongo-previous-or-last n)
- (bongo-start)))))
+ ((null (get-buffer-window bongo-seek-buffer))
+ (let ((window-min-height 2)
+ (split-window-keep-point nil))
+ (select-window
+ (split-window-vertically
+ (if (and (fboundp 'face-attr-construct)
+ ;; NOTE: bug occurs here.
+ (plist-get (face-attr-construct 'mode-line) :box))
+ -3 -2)))
+ (switch-to-buffer bongo-seek-buffer)))
+ ((not (eq (current-buffer) bongo-seek-buffer))
+ (select-window (get-buffer-window bongo-seek-buffer))))
+ (bongo-seek-mode)
+ (setq buffer-read-only t)
+ (setq cursor-type nil)
+ (bongo-seek-redisplay)
+ (durand-bongo-seek-start-timer-maybe)))
+
+(advice-add #'bongo-seek :override #'durand-bongo-seek)
+
+;;; Go to the bongo-default-directory when no track is under point
+
+(defun durand-bongo-dired-line (&optional point)
+ "Open a Dired buffer containing the track at POINT.
+Modified by Durand."
+ (interactive)
+ ;;; NOTE: The body-form inside condition-case is the original
+ ;;; function body.
+ (condition-case nil
+ (save-excursion
+ (bongo-goto-point point)
+ (bongo-snap-to-object-line)
+ (dired (file-name-directory
+ (save-excursion
+ (while (bongo-header-line-p)
+ (bongo-down-section))
+ (if (bongo-local-file-track-line-p)
+ (bongo-line-file-name)
+ (error "No local file track here")))))
+ (bongo-dired-library-mode 1))
+ ('error (dired bongo-default-directory))))
+
+(advice-add 'bongo-dired-line :override #'durand-bongo-dired-line)
+
+;;; Jump to playlist buffer immediately
+
+(defun durand-bongo-buffer ()
+ "Return the buffer (bongo-playlist-buffer)."
+ (interactive)
+ (bongo-playlist-buffer))
-;;;###autoload
- (defun durand-bongo-play-first ()
- "Play the first song."
- (interactive)
- (with-bongo-playlist-buffer
- (with-imminent-bongo-player-start
- (bongo-stop)
- (when bongo-mark-played-tracks
- (bongo-mark-current-track-line-as-played))
- (goto-char (or (bongo-point-at-first-track-line)
- (prog1 (point)
- (message "No track in the playlist buffer."))))
- (bongo-set-current-track-position)
- (bongo-start))))
+(advice-add #'bongo-buffer :override #'durand-bongo-buffer)
-;;;###autoload
- (defun durand-bongo-play-last ()
- "Play the first song."
- (interactive)
- (with-bongo-playlist-buffer
- (with-imminent-bongo-player-start
- (bongo-stop)
- (when bongo-mark-played-tracks
- (bongo-mark-current-track-line-as-played))
- (goto-char (or (bongo-point-at-last-track-line)
- (prog1 (point)
- (message "No track in the playlist buffer."))))
- (bongo-set-current-track-position)
- (bongo-start))))
-
- ;; NOTE: Fix a bug: there is no face called `modeline'; it should be
- ;; `mode-line'.
-;;;###autoload
- (defun durand-bongo-seek ()
- "Interactively seek in the current Bongo track."
- ;; :override 'bongo-seek
- (interactive)
- (setq bongo-seek-buffer (get-buffer-create "*Bongo Seek*"))
- (if bongo-seek-electric-mode
- (unwind-protect
- (save-window-excursion
- (require 'electric)
- (message nil)
- (let ((garbage-collection-messages nil)
- (bongo-seeking-electrically t))
- (ignore bongo-seeking-electrically)
- (set-window-buffer (minibuffer-window) bongo-seek-buffer)
- (select-window (minibuffer-window))
- (let ((old-local-map (current-local-map))
- (old-global-map (current-global-map)))
- (use-local-map nil)
- (use-global-map bongo-seek-mode-map)
- (setq major-mode 'bongo-seek-mode)
- (unwind-protect
- (progn
- (bongo-seek-redisplay)
- (run-hooks 'bongo-seek-mode-hook)
- (catch 'bongo-seek-done
- (Electric-command-loop
- 'bongo-seek-done
- ;; Avoid `noprompt' due to
- ;; a bug in electric.el.
- '(lambda () 'noprompt)
- nil
- (lambda (_x _y) (bongo-seek-redisplay)))))
- (use-local-map old-local-map)
- (use-global-map old-global-map)))))
- (when bongo-seek-buffer
- (kill-buffer bongo-seek-buffer)
- (setq bongo-seek-buffer nil)))
- (cond
- ((null (get-buffer-window bongo-seek-buffer))
- (let ((window-min-height 2)
- (split-window-keep-point nil))
- (select-window
- (split-window-vertically
- (if (and (fboundp 'face-attr-construct)
- ;; NOTE: bug occurs here.
- (plist-get (face-attr-construct 'mode-line) :box))
- -3 -2)))
- (switch-to-buffer bongo-seek-buffer)))
- ((not (eq (current-buffer) bongo-seek-buffer))
- (select-window (get-buffer-window bongo-seek-buffer))))
- (bongo-seek-mode)
- (setq buffer-read-only t)
- (setq cursor-type nil)
- (bongo-seek-redisplay)
- (durand-bongo-seek-start-timer-maybe)))
-
- (advice-add 'bongo-seek :override #'durand-bongo-seek)
-
-;;; HACK: Redefine a function to go to the bongo-default-directory when no track
-;;; is under point.
-;;;
-;;;###autoload
- (defun durand-bongo-dired-line (&optional point)
- "Open a Dired buffer containing the track at POINT.
-Modified by Durand."
- ;; :override 'bongo-dired-line
- (interactive)
- ;;; NOTE: The body-form inside condition-case is the original function body.
- (condition-case nil
- (save-excursion
- (bongo-goto-point point)
- (bongo-snap-to-object-line)
- (dired (file-name-directory
- (save-excursion
- (while (bongo-header-line-p)
- (bongo-down-section))
- (if (bongo-local-file-track-line-p)
- (bongo-line-file-name)
- (error "No local file track here")))))
- (bongo-dired-library-mode 1))
- ('error (dired bongo-default-directory))))
-
- (advice-add 'bongo-dired-line :override #'durand-bongo-dired-line)
-
-;;; NOTE: I would like bongo to jump to bongo-playlist-buffer immediately,
-;;; otherwise sometimes it jumps to the dired buffer, which is annoying.
+;;; Some navigation functions
-;;;###autoload
- (defun durand-bongo-buffer ()
- "Return the buffer (bongo-playlist-buffer)."
- (interactive)
- (bongo-playlist-buffer))
+;; These are mostly deprecated, but still kept here.
- (advice-add #'bongo-buffer :override #'durand-bongo-buffer)
+(defun durand-bongo-next-song (&optional n)
+ "Play the next N song."
+ (interactive "p")
+ (with-bongo-playlist-buffer
+ (durand-bongo-play-next-or-first n)))
-;;; hydra
+(defun durand-bongo-previous-song (&optional n)
+ "Play the previous N song."
+ (interactive "p")
+ (with-bongo-playlist-buffer
+ (durand-bongo-play-previous-or-last n)))
- ;; NOTE: I would like to have a hydra to do some basic bongo commands, like go
- ;; to the next song, or control the volume.
+(defun durand-bongo-seek-anywhere ()
+ "A wrapper around `durand-bongo-seek'."
+ (interactive)
+ (with-bongo-playlist-buffer
+ (durand-bongo-seek)
+ (setf durand-bongo-hydra-volume-return-p t)))
-;;;###autoload
- (defun durand-bongo-next-song (&optional n)
- "Play the next N song."
- (interactive "p")
- (with-bongo-playlist-buffer
- (durand-bongo-play-next-or-first n)))
+(defun bongo-seek-forward-5 (&optional n)
+ "Seek 5 N seconds forward in the currently playing track."
+ (interactive "p")
+ (bongo-seek-forward (* 5 (or n 1))))
-;;;###autoload
- (defun durand-bongo-previous-song (&optional n)
- "Play the previous N song."
- (interactive "p")
- (with-bongo-playlist-buffer
- (durand-bongo-play-previous-or-last n)))
+(defun bongo-seek-backward-5 (&optional n)
+ "Seek 5 N seconds backward in the currently playing track."
+ (interactive "p")
+ (bongo-seek-backward (* 5 (or n 1))))
-;;;###autoload
- (defun durand-bongo-seek-anywhere ()
- "A wrapper around `durand-bongo-seek'."
- (interactive)
- (with-bongo-playlist-buffer
- (durand-bongo-seek)
- (setf durand-bongo-hydra-volume-return-p t)))
+(defun durand-bongo-kill-line ()
+ "Kill the currently playing bongo line."
+ (interactive)
+ (with-bongo-playlist-buffer
+ (bongo-recenter)
+ (bongo-kill-line)))
-;;;###autoload
- (defun bongo-seek-forward-5 (&optional n)
- "Seek 5 N seconds forward in the currently playing track."
- (interactive "p")
- (bongo-seek-forward (* 5 (or n 1))))
+;;; Fix volume redisplay
-;;;###autoload
- (defun bongo-seek-backward-5 (&optional n)
- "Seek 5 N seconds backward in the currently playing track."
- (interactive "p")
- (bongo-seek-backward (* 5 (or n 1))))
+(defun durand-bongo-refresh-after-set-a (&rest _args)
+ "Refresh the display after we set the volume."
+ (volume-redisplay))
-;;;###autoload
- (defun durand-bongo-kill-line ()
- "Kill the currently playing bongo line."
- (interactive)
- (with-bongo-playlist-buffer
- (bongo-recenter)
- (bongo-kill-line)))
+(advice-add #'volume-set :after #'durand-bongo-refresh-after-set-a)
- ;; NOTE: I would like to stay in my hydra after setting the volume, so I wrote
- ;; this hacky workaround.
+;;; Custom default playlist buffer function
-;;;###autoload
- ;; (defvar durand-bongo-hydra-volume-return-p nil
- ;; "Whether to return to the hydra after quitting the volume buffer.")
-
- ;; ;;;###autoload
- ;; (defun durand-bongo-volume ()
- ;; "Stay in the hydra after adjusting the volume."
- ;; (interactive)
- ;; (volume)
- ;; (setf durand-bongo-hydra-volume-return-p t))
-
- ;; ;;;###autoload
- ;; (defadvice! durand-bongo-volume-call-hydra-a (&rest _args)
- ;; "Call `durand-bongo-hydra/body' if `durand-bongo-hydra-volume-return-p' is non-nil."
- ;; :after '(volume-quit bongo-seek-quit)
- ;; (when durand-bongo-hydra-volume-return-p
- ;; (durand-bongo-hydra/body)))
-
- ;; ;;;###autoload
- ;; (defhydra durand-bongo-hydra (nil
- ;; nil
- ;; :hint nil
- ;; :color blue
- ;; :pre (setf durand-bongo-hydra-volume-return-p nil))
- ;; "
- ;; _q_: quit _n_: next song _f_ : forward 5 _F_: forward 10 _<tab>_: show
- ;; _v_: volume _p_: previous song _b_ : backward 5 _B_: backward 10
- ;; _s_: seek _d_: clear _SPC_: pause / resume _<_: first
- ;; _m_: bongo _i_: insert _I_ : playlist _>_: last
- ;; "
- ;; ("q" nil)
- ;; ("v" durand-bongo-volume)
- ;; ("s" durand-bongo-seek-anywhere)
- ;; ("m" bongo)
- ;; ("n" durand-bongo-next-song :color amaranth)
- ;; ("p" durand-bongo-previous-song :color amaranth)
- ;; ("d" prot/bongo-clear-playlist-and-stop :color amaranth)
- ;; ("i" durand-bongo-dired-ivy-find-to-add :color amaranth)
- ;; ("f" bongo-seek-forward-5 :color amaranth)
- ;; ("b" bongo-seek-backward-5 :color amaranth)
- ;; ("SPC" bongo-pause/resume :color amaranth)
- ;; ("I" durand-bongo-insert-delete-playlist :color amaranth)
- ;; ("F" bongo-seek-forward-10 :color amaranth)
- ;; ("B" bongo-seek-backward-10 :color amaranth)
- ;; ("<" durand-bongo-play-first :color amaranth)
- ;; (">" durand-bongo-play-last :color amaranth)
- ;; ("<tab>" bongo-show :color amaranth))
-
- ;; ;;; NOTE: volume-set does not refresh the display, so let's fix that.
-
- (defun durand-bongo-refresh-after-set-a (&rest _args)
- "Refresh the display after we set the volume."
- ;; :after 'volume-set
- (volume-redisplay))
-
- (advice-add #'volume-set :after #'durand-bongo-refresh-after-set-a)
-
-;;; Don't insert text in the playlist buffer.
+(defun durand-bongo-default-playlist-buffer-a ()
+ "Don't insert text in the playlist buffer."
+ (or (get-buffer bongo-default-playlist-buffer-name)
+ (let ((buffer
+ (get-buffer-create bongo-default-playlist-buffer-name)))
+ (prog1 buffer
+ (with-current-buffer buffer
+ (bongo-playlist-mode))))))
-;;;###autoload
- (defun durand-bongo-default-playlist-buffer-a ()
- "Don't insert text in the playlist buffer."
- ;; :override #'bongo-default-playlist-buffer
- (or (get-buffer bongo-default-playlist-buffer-name)
- (let ((buffer (get-buffer-create bongo-default-playlist-buffer-name)))
- (prog1 buffer
- (with-current-buffer buffer
- (bongo-playlist-mode))))))
-
- (advice-add #'bongo-default-playlist-buffer :override #'durand-bongo-default-playlist-buffer-a)
- )
+(advice-add #'bongo-default-playlist-buffer
+ :override #'durand-bongo-default-playlist-buffer-a)
;;; Stop playing and exit and kill the buffer
@@ -775,10 +723,13 @@ will do the right renaming."
(if (or (null durand-bongo-sub-buffer)
(not (bongo-player-running-p player))
(and (bongo-player-get player 'socket)
- (not (equal (process-status (bongo-player-get player 'socket))
- 'open))))
+ (not (equal
+ (process-status
+ (bongo-player-get player 'socket))
+ 'open))))
(durand-bongo-sub-stop-timer player)
- (bongo--run-mpv-command player "sub-pos" "get_property" "time-pos")
+ (bongo--run-mpv-command
+ player "sub-pos" "get_property" "time-pos")
(bongo-sub-redisplay)))
(defun durand-bongo-sub-start-timer (player)
@@ -1147,3 +1098,6 @@ TIME must be a list of two to four elements."
(define-key bongo-playlist-mode-map (vector ?/)
#'durand-bongo-search-insert)
+
+(provide 'durand-bongo)
+;;; durand-bongo.el ends here