fordon_greeman / voidfiles

Branch: 2079ec5
Switch branches/tags
main
theidioticdev add emacs 2079ec5 21h ago
158 lines · 6.6 KB Raw Blame History
1 ;;; emms-cue.el --- Recognize cue sheet file -*- lexical-binding: t; -*-
2
3 ;; Copyright (C) 2009 Free Software Foundation, Inc.
4
5 ;; Author: William Xu <william.xwl@gmail.com>
6
7 ;; This file is part of EMMS.
8
9 ;; EMMS is free software; you can redistribute it and/or
10 ;; modify it under the terms of the GNU General Public License
11 ;; as published by the Free Software Foundation; either version 3
12 ;; of the License, or (at your option) any later version.
13
14 ;; EMMS is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with EMMS; if not, write to the Free Software Foundation,
21 ;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
22
23 ;;; Commentary:
24
25 ;; By parsing cue file, we will be able to jump to arbitary track or
26 ;; play next/previous track from a single .ape or .flac file.
27
28 ;;; Code:
29
30 (require 'emms-playing-time)
31 (require 'emms-info)
32
33 (defun emms-cue-next ()
34 "Play next track from .cue file."
35 (interactive)
36 (let ((cue-track (emms-cue-next-track)))
37 (if (cdr cue-track)
38 (progn
39 (emms-seek-to (cdr cue-track))
40 (message "Will play: %s" (car cue-track)))
41 (message "Nothing to seek or missing .cue file?"))))
42
43 (defun emms-cue-previous ()
44 "Play previous track from .cue file."
45 (interactive)
46 (let ((cue-track (emms-cue-previous-track)))
47 (if (cdr cue-track)
48 (progn
49 (emms-seek-to (cdr cue-track))
50 (message "Will play: %s" (car cue-track)))
51 (message "Nothing to seek or missing .cue file?"))))
52
53 (defun emms-cue-jump ()
54 "Select a track from .cue file to play using completion."
55 (interactive)
56 (let ((cue-track (emms-cue-select-track)))
57 (if (cdr cue-track)
58 (progn
59 (emms-seek-to (cdr cue-track))
60 (message "Will play: %s" (car cue-track)))
61 (message "Nothing to seek or missing .cue file?"))))
62
63 (defun emms-cue-next-track (&optional previous-p)
64 "Get title and offset of next track from .cue file.
65
66 When PREVIOUS-P is t, get previous track info instead."
67 (let* ((track (emms-playlist-current-selected-track))
68 (name (emms-track-get track 'name))
69 (cue (concat (file-name-sans-extension name)".cue")))
70 (when (file-exists-p cue)
71 (with-temp-buffer
72 (emms-insert-file-contents cue)
73 (save-excursion
74 (if previous-p
75 (goto-char (point-max))
76 (goto-char (point-min)))
77 (let ((offset nil)
78 (title "")
79 ;; We should search one more track far when getting previous
80 ;; track.
81 (one-more-track previous-p))
82 (while (and (not offset)
83 (funcall
84 (if previous-p 'search-backward-regexp 'search-forward-regexp)
85 "INDEX 01 \\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)" nil t 1))
86 (let* ((min (string-to-number (match-string-no-properties 1)))
87 (sec (string-to-number (match-string-no-properties 2)))
88 (msec (string-to-number (match-string-no-properties 3)))
89 (total-sec (+ (* min 60) sec (/ msec 100.0))))
90 (when (funcall (if previous-p '> '<) emms-playing-time total-sec)
91 (if (not one-more-track)
92 (progn
93 (setq offset total-sec)
94 (when (search-backward-regexp "TITLE \"\\(.*\\)\"" nil t 1)
95 (setq title (match-string-no-properties 1))))
96 (setq one-more-track nil)))))
97 (cons title offset)))))))
98
99 (defun emms-cue-previous-track ()
100 "See `emms-cue-next-track'."
101 (emms-cue-next-track t))
102
103 (defun emms-cue-select-track ()
104 "Get a list of title and offset of tracks from .cue file and call
105 completing-read to select one"
106 (let* ((track (emms-playlist-current-selected-track))
107 (name (emms-track-get track 'name))
108 (cue (concat (file-name-sans-extension name)".cue"))
109 (tracks-found '()))
110 (when (file-exists-p cue)
111 (with-temp-buffer
112 (emms-insert-file-contents cue)
113 (save-excursion
114 (goto-char (point-max)) ; search backwards
115 (while (search-backward-regexp "INDEX 01 \\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)" nil t 1)
116 (let* ((min (string-to-number (match-string-no-properties 1)))
117 (sec (string-to-number (match-string-no-properties 2)))
118 (msec (string-to-number (match-string-no-properties 3)))
119 (total-sec (+ (* min 60) sec (/ msec 100.0)))
120 (title ""))
121 (when (search-backward-regexp "TITLE \"\\(.*\\)\"" nil t 1)
122 (setq title (match-string-no-properties 1)))
123 (push (cons title total-sec) tracks-found)))))
124 (let* ((tracks-complete-table (lambda (string pred action)
125 (if (eq action 'metadata)
126 `(metadata (display-sort-function . ,#'identity)) ; don't sort
127 (complete-with-action action (mapcar #'car tracks-found) string pred))))
128 (selection (completing-read "Select a track to play: " tracks-complete-table nil t)))
129 (assoc selection tracks-found)))))
130
131 (defun emms-info-cueinfo (track)
132 "Add track information to TRACK.
133 This is a useful element for `emms-info-functions'."
134 (when (and (emms-track-file-p track)
135 (string-match "\\.\\(ape\\|flac\\)\\'" (emms-track-name track)))
136 (let ((cue (concat (file-name-sans-extension (emms-track-name track))
137 ".cue")))
138 (when (file-exists-p cue)
139 (with-temp-buffer
140 (emms-insert-file-contents cue)
141 (save-excursion
142 (mapc (lambda (i)
143 (goto-char (point-min))
144 (when (let ((case-fold-search t))
145 (search-forward-regexp
146 (concat (car i) " \\(.*\\)") nil t 1))
147 (emms-track-set track
148 (cdr i)
149 (replace-regexp-in-string
150 "\\`\"\\|\"\\'" "" (match-string 1)))))
151 '(("performer" . info-artist)
152 ("title" . info-album)
153 ("title" . info-title)
154 ("rem date" . info-year)))))))))
155
156
157 (provide 'emms-cue)
158 ;;; emms-cue.el ends here