From 6f8c0abb82c922a46e48864a4a7c2b3bc45e5f35 Mon Sep 17 00:00:00 2001 From: JSDurand Date: Wed, 16 Nov 2022 17:27:13 +0800 Subject: bongo: Reformat * bongo.el: * init.el: Reformat the codes in a consistent manner. --- bongo.el | 1074 ++++++++++++++++++++++++++++++-------------------------------- init.el | 2 +- 2 files changed, 515 insertions(+), 561 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 +;; 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 . + +;;; 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 __: 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) - ;; ("" 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 diff --git a/init.el b/init.el index 08465e6..96340c2 100644 --- a/init.el +++ b/init.el @@ -200,7 +200,7 @@ no effect." ;;; bongo ;;;###autoload -(load-after-function bongo "bongo.el" +(load-after-function bongo "durand-bongo.el" "Listen to music in Emacs." nil (bongo)) ;;; My PDF facilities -- cgit v1.2.3-18-g5258