fordon_greeman / voidfiles

Branch: 2079ec5
Switch branches/tags
main
theidioticdev add emacs 2079ec5 21h ago
228 lines · 8.7 KB Raw Blame History
1 ;;; emms-playlist-limit.el --- Limit playlist by various info -*- lexical-binding: t -*-
2
3 ;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
4
5 ;; Author: William Xu <william.xwl@gmail.com>
6 ;; Author: Fran Burstall <fran.burstall@gmail.com>
7 ;; Keywords: emms, limit
8
9 ;; EMMS is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 3, or (at your option)
12 ;; 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; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 ;; Boston, MA 02110-1301, USA.
23
24 ;;; Commentary:
25
26 ;; This code allows you to "limit" a playlist in the current buffer
27 ;; by creating, and switching to, a derived playlist containing only
28 ;; those tracks with a type (info-artist and the like) matching a
29 ;; regexp.
30
31 ;; If the current buffer is the current playlist then the derived
32 ;; playlist is made current.
33
34 ;; Usage:
35 ;; ------------------------------------------------------------------
36
37 ;; This code is activated by (emms-all). Otherwise simply do:
38
39 ;; (require 'emms-playlist-limit)
40
41 ;; Key bindings
42 ;; ------------------------------------------------------------------
43
44 ;; / / emms-playlist-limit-to-all
45 ;; / A emms-playlist-limit-to-info-albumartist
46 ;; / a emms-playlist-limit-to-info-artist
47 ;; / b emms-playlist-limit-to-info-album
48 ;; / c emms-playlist-limit-to-info-composer
49 ;; / d emms-playlist-limit-to-description
50 ;; / g emms-playlist-limit-to-info-genre
51 ;; / n emms-playlist-limit-to-name
52 ;; / p emms-playlist-limit-to-info-performer
53 ;; / t emms-playlist-limit-to-info-title
54 ;; / y emms-playlist-limit-to-info-year
55
56 ;;; Code:
57
58 (require 'seq)
59 (require 'emms-playlist-mode)
60
61 ;; User Interfaces
62
63 (defgroup emms-playlist-limit nil
64 "Playlist limit module for EMMS."
65 :group 'emms)
66
67 (defcustom emms-playlist-limit-hook nil
68 "Hooks to run after each limit operation."
69 :type 'symbol)
70
71 (defmacro define-emms-playlist-limit (attribute)
72 "Macro for defining emms playlist limit to ATTRIBUTE function."
73 `(defun ,(intern (format "emms-playlist-limit-to-%s" attribute)) (regexp)
74 ,(format "Switch to a playlist comprising tracks with %s matching REGEXP.
75
76 REGEXP defaults to the value of %s for the track at point.
77
78 When the current buffer is the current playlist, make the derived playlist
79 the current playlist." attribute attribute)
80 (interactive
81 (list
82 (let* ((curr
83 (or (emms-playlist-limit-track-get
84 (or (emms-playlist-track-at)
85 (emms-playlist-track-at (max 1 (1- (point))))) ; at eol
86 (quote ,attribute))
87 (emms-playlist-limit-track-get
88 (emms-playlist-selected-track) (quote ,attribute))))
89 (attr-name ,(emms-replace-regexp-in-string
90 "info-" "" (symbol-name attribute)))
91 (fmt (if curr
92 (format "Limit to %s (regexp = %s): " attr-name curr)
93 (format "Limit to %s (regexp): " attr-name))))
94 (read-string fmt))))
95 (when (string= regexp "")
96 (setq regexp (or (emms-playlist-limit-track-get
97 (or (emms-playlist-track-at)
98 (emms-playlist-track-at (max 1 (1- (point))))) ; at eol
99 (quote ,attribute))
100 (emms-playlist-limit-track-get
101 (emms-playlist-selected-track) (quote ,attribute)))))
102 (if regexp
103 (emms-playlist-limit-do (quote ,attribute) regexp)
104 (message "Limit cancelled: no regexp."))))
105
106 (define-emms-playlist-limit info-albumartist)
107 (define-emms-playlist-limit info-artist)
108 (define-emms-playlist-limit info-composer)
109 (define-emms-playlist-limit info-performer)
110 (define-emms-playlist-limit info-title)
111 (define-emms-playlist-limit info-album)
112 (define-emms-playlist-limit info-year)
113 (define-emms-playlist-limit info-genre)
114 (define-emms-playlist-limit info-note)
115 (define-emms-playlist-limit name)
116 (define-emms-playlist-limit description)
117
118 (defvar-local emms-playlist-limit--original-playlist nil
119 "Playlist buffer from which we derive the limited playlist.")
120
121 (defun emms-playlist-limit-to-all ()
122 "Switch to playlist from which this playlist was derived (if it still exists)
123 and bury this playlist.
124
125 If this playlist is current, make the playlist we switch to current."
126 (interactive)
127 (when (and emms-playlist-limit--original-playlist
128 (buffer-live-p emms-playlist-limit--original-playlist))
129 (let* ((old-buf (current-buffer))
130 (old-buf-is-current-playlist (eq old-buf emms-playlist-buffer)))
131 (switch-to-buffer emms-playlist-limit--original-playlist)
132 (when old-buf-is-current-playlist
133 (emms-playlist-set-playlist-buffer))
134 (bury-buffer old-buf))))
135
136 (define-key emms-playlist-mode-map (kbd "/ n") #'emms-playlist-limit-to-name)
137 (define-key emms-playlist-mode-map (kbd "/ A") #'emms-playlist-limit-to-info-albumartist)
138 (define-key emms-playlist-mode-map (kbd "/ a") #'emms-playlist-limit-to-info-artist)
139 (define-key emms-playlist-mode-map (kbd "/ c") #'emms-playlist-limit-to-info-composer)
140 (define-key emms-playlist-mode-map (kbd "/ p") #'emms-playlist-limit-to-info-performer)
141 (define-key emms-playlist-mode-map (kbd "/ t") #'emms-playlist-limit-to-info-title)
142 (define-key emms-playlist-mode-map (kbd "/ b") #'emms-playlist-limit-to-info-album)
143 (define-key emms-playlist-mode-map (kbd "/ y") #'emms-playlist-limit-to-info-year)
144 (define-key emms-playlist-mode-map (kbd "/ g") #'emms-playlist-limit-to-info-genre)
145 (define-key emms-playlist-mode-map (kbd "/ N") #'emms-playlist-limit-to-info-note)
146 (define-key emms-playlist-mode-map (kbd "/ d") #'emms-playlist-limit-to-description)
147 (define-key emms-playlist-mode-map (kbd "/ /") #'emms-playlist-limit-to-all)
148
149
150 ;;; Low Level Functions
151
152 (defun emms-playlist-limit-track-get (track type)
153 "Return the value of TYPE from TRACK.
154
155 Here TYPE is a field available to `emms-track-get\\=' or
156 \\='description which gives the result of
157 `emms-track-description-function\\='.
158
159 When type is \\='info-year, also tries \\='info-originalyear,
160 \\='info-originaldate and \\='info-date to get a usable date."
161 (cond ((eq type 'info-year)
162 (let ((date (or (emms-track-get track 'info-originaldate)
163 (emms-track-get track 'info-originalyear)
164 (emms-track-get track 'info-date)
165 (emms-track-get track 'info-year))))
166 (or (emms-format-date-to-year date)
167 "<unknown year>")))
168 ((eq type 'description) (funcall emms-track-description-function track))
169 (t (emms-track-get track type))))
170
171 (defun emms-playlist-limit--derive-playlist (playlist pred name)
172 "Return a new playlist NAME of tracks in PLAYLIST for which (PRED track)
173 is non-nil."
174 (let* ((tracks (nreverse (with-current-buffer playlist
175 (save-excursion (emms-playlist-tracks-in-region (point-min) (point-max))))))
176 (filtered-tracks (seq-filter pred tracks))
177 (new-playlist (or (get-buffer name)
178 (emms-playlist-new name))))
179 (with-current-buffer new-playlist
180 (emms-with-inhibit-read-only-t (erase-buffer))
181 (mapc #'emms-playlist-insert-track filtered-tracks))
182 new-playlist))
183
184 (defun emms-playlist-limit--limit-playlist (playlist type regexp)
185 "Return a new playlist of tracks in PLAYLIST with TYPE matching REGEXP."
186 (let* ((bufname (format "%s/%s=%s"
187 (buffer-name playlist)
188 (emms-replace-regexp-in-string "info-" ""
189 (symbol-name type))
190 regexp)))
191 (emms-playlist-limit--derive-playlist
192 playlist
193 (lambda (track) (let ((field (emms-playlist-limit-track-get track type)))
194 (and field (string-match regexp field))))
195 bufname)))
196
197 (defun emms-playlist-limit-do (type regexp)
198 "Switch to a derived playlist containing the tracks with TYPE matching REGEXP.
199 e.g.,
200 (emms-playlist-limit-do \\='info-artist \"Jane Zhang\")
201
202 See `emms-info-mp3find-arguments\\=' for possible options for TYPE."
203 (emms-playlist-ensure-playlist-buffer)
204 (let* ((curr (emms-playlist-selected-track))
205 (old-buf (current-buffer))
206 (old-buf-is-current-playlist (eq old-buf emms-playlist-buffer))
207 (buf (emms-playlist-limit--limit-playlist old-buf type regexp)))
208 (with-current-buffer buf
209 (if (= (point-min) (point-max))
210 (progn
211 (message "No matching tracks found!")
212 (kill-buffer))
213 (let ((pos (when curr (text-property-any (point-min) (point-max)
214 'emms-track curr))))
215 (if pos
216 (emms-playlist-select pos)
217 (emms-playlist-select-first)))
218 (emms-playlist-mode-center-current)
219 (setq emms-playlist-limit--original-playlist old-buf)
220 (when old-buf-is-current-playlist
221 (emms-playlist-set-playlist-buffer))
222 (run-hooks 'emms-playlist-limit-hook)
223 (switch-to-buffer buf)))))
224
225
226 (provide 'emms-playlist-limit)
227
228 ;;; emms-playlist-limit.el ends here