[PATCH] Use completing-read to jump to tracks in cue file

Akito Mikami <[email protected]> Sat, 02 Mar 2024 11:53:35 +0000
Newsgroups gmane.emacs.emms.user
Message-ID <[email protected]>
Hi,

Currently emms-cue.el supports navigating only to the previous/next
track. It would be nice to have emms behave like other music players
where each track is an individual entry in the playlist, but that would
require major changes. I think a simple emms-cue-jump command using
completing-read should be a nice compromise.

Regards,
Mikami
0001-emms-cue.el-add-command-to-jump-to-a-track-using-com.patch (text/x-patch, 3.2 KB)
From 187dafa766012971bb40872d203b443bd0c3f51e Mon Sep 17 00:00:00 2001
From: Akito Mikami <[email protected]>
Date: Sat, 2 Mar 2024 14:51:49 +0900
Subject: [PATCH] * emms-cue.el: add command to jump to a track using
 completing-read

---
 emms-cue.el | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/emms-cue.el b/emms-cue.el
index 880d2d8..0bc2bf7 100644
--- a/emms-cue.el
+++ b/emms-cue.el
@@ -22,8 +22,8 @@
 
 ;;; Commentary:
 
-;; By parsing cue file, we will be able to play next/previous track from a
-;; single .ape or .flac file.
+;; By parsing cue file, we will be able to jump to arbitary track or
+;; play next/previous track from a single .ape or .flac file.
 
 ;;; Code:
 
@@ -50,6 +50,16 @@
           (message "Will play: %s" (car cue-track)))
       (message "Nothing to seek or missing .cue file?"))))
 
+(defun emms-cue-jump ()
+  "Select a track from .cue file to play using completion."
+  (interactive)
+  (let ((cue-track (emms-cue-select-track)))
+    (if (cdr cue-track)
+        (progn
+          (emms-seek-to (cdr cue-track))
+          (message "Will play: %s" (car cue-track)))
+      (message "Nothing to seek or missing .cue file?"))))
+
 (defun emms-cue-next-track (&optional previous-p)
   "Get title and offset of next track from .cue file.
 
@@ -90,6 +100,34 @@ When PREVIOUS-P is t, get previous track info instead."
   "See `emms-cue-next-track'."
   (emms-cue-next-track t))
 
+(defun emms-cue-select-track ()
+  "Get a list of title and offset of tracks from .cue file and call
+completing-read to select one"
+  (let* ((track (emms-playlist-current-selected-track))
+         (name (emms-track-get track 'name))
+         (cue (concat (file-name-sans-extension name)".cue"))
+         (tracks-found '()))
+    (when (file-exists-p cue)
+      (with-temp-buffer
+        (emms-insert-file-contents cue)
+        (save-excursion
+          (goto-char (point-max))       ; search backwards
+          (while (search-backward-regexp "INDEX 01 \\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)" nil t 1)
+            (let* ((min (string-to-number (match-string-no-properties 1)))
+                   (sec (string-to-number (match-string-no-properties 2)))
+                   (msec (string-to-number (match-string-no-properties 3)))
+                   (total-sec (+ (* min 60) sec (/ msec 100.0)))
+                   (title ""))
+              (when (search-backward-regexp "TITLE \"\\(.*\\)\"" nil t 1)
+                (setq title (match-string-no-properties 1)))
+              (push (cons title total-sec) tracks-found)))))
+      (let* ((tracks-complete-table (lambda (string pred action)
+                                      (if (eq action 'metadata)
+                                          `(metadata (display-sort-function . ,#'identity)) ; don't sort
+                                        (complete-with-action action (mapcar #'car tracks-found) string pred))))
+             (selection (completing-read "Select a track to play: " tracks-complete-table nil t)))
+        (assoc selection tracks-found)))))
+
 (defun emms-info-cueinfo (track)
   "Add track information to TRACK.
 This is a useful element for `emms-info-functions'."
-- 
2.43.1
publickey - [email protected] - 0x3B7D3380.asc (application/pgp-keys, 677 B)
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GopenPGP 2.7.4
Comment: https://gopenpgp.org

xjMEZXwjERYJKwYBBAHaRw8BAQdAwhBhdW2C5deoQ/qkLH0DsddvFt32H3p60BpU
61dyKnLNGW1lQGE2NC53b3JrIDxtZUBhNjQud29yaz7CjAQQFgoAPgWCZXwjEQQL
CQcICZALGAaaXvf7NgMVCAoEFgACAQIZAQKbAwIeARYhBDt9M4CWAwAxY7IPXgsY
Bppe9/s2AACjJAEAurAUAr+6V+ZfO8NluHVWADYd6/SDJELpeh2qkaEukFcBAIaf
zHWTIMjH3J0TICqKYZFWAMl+Nvn28GZErviyVr0FzjgEZXwjERIKKwYBBAGXVQEF
AQEHQByRj3bKOvDJrs+tMweod41EYZz1gcPuqHZDcj1FDwdaAwEIB8J4BBgWCgAq
BYJlfCMRCZALGAaaXvf7NgKbDBYhBDt9M4CWAwAxY7IPXgsYBppe9/s2AACVnwD8
C/LTHffTXjvV71yfhCV0bYA36M1YMbY7KrTT3SmsvvEA/RhCW17qxy+5a42Xkc5Y
AXVlcxY3jlILMxzBnddWL50G
=R5FO
-----END PGP PUBLIC KEY BLOCK-----
signature.asc (application/pgp-signature, 249 B)
-----BEGIN PGP SIGNATURE-----
Version: ProtonMail

wnUEARYIACcFAmXjEz4JEAsYBppe9/s2FiEEO30zgJYDADFjsg9eCxgGml73
+zYAAIT4AP9S1s85UJVW4zvyMRuySOQqugc9SV7aDQoQbEMpQtT3mAEAs3Gu
hwHEVznfRm42l/IGP1RtUSrPckxtUYsFMwJjCgg=
=WsjP
-----END PGP SIGNATURE-----