branch: externals/emms commit cead7b435a679690fd4bbe91fa2f57739a1e0077 Author: Yoni Rabkin <y...@gnu.org> Commit: Yoni Rabkin <y...@gnu.org>
emms-idapi: track (recording) features and debug buffers --- emms-idapi-browser.el | 88 ++++++++++++++++++++++++++++++++++++-------- emms-idapi-musicbrainz.el | 93 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 139 insertions(+), 42 deletions(-) diff --git a/emms-idapi-browser.el b/emms-idapi-browser.el index 84b6386893..d89a32666b 100644 --- a/emms-idapi-browser.el +++ b/emms-idapi-browser.el @@ -26,6 +26,14 @@ ;;; Commentary: ;; +(defvar emms-idapi-browser-debug-name + " *Emms Search Debug Browser*" + "Name of the search browser debug buffer") + +(defvar emms-idapi-browser-debug-buffer + nil + "Search browser debug buffer") + (defvar emms-idapi-browser-name "Emms Search Browser" "Name of the search browser buffer") @@ -91,6 +99,21 @@ (error "could not read Emms track at point")) track)) +(defun emms-idapi-browser-search-recording-artist (track) + "Search for the recording and artist of TRACK." + (let ((recording (alist-get 'info-title track)) + (artist (or (alist-get 'info-artist track) + (alist-get 'info-albumartist track)))) + (list + (cons 'info-title (read-string "search for recording (track): " recording)) + (cons 'info-artist (read-string "search for artist: " artist))))) + +(defun emms-idapi-browser-search-recording (track) + "Search for the recording of TRACK." + (let ((recording (alist-get 'info-title track))) + (list + (cons 'info-title (read-string "search for recording (track): " recording))))) + (defun emms-idapi-browser-search-artist (track) "Search for the artist of TRACK." (let ((artist (or (alist-get 'info-artist track) @@ -117,6 +140,22 @@ (format "search for album \"%s\" by artist: " search-album) artist))))) +(defun emms-idapi-browser-search-recording-artist-at () + "Search for the recording and artist of the track at point." + (interactive) + (emms-idapi-browser-show + (emms-idapi-search emms-idapi-service + (emms-idapi-browser-search-recording-artist + (emms-playlist-track-at (point)))))) + +(defun emms-idapi-browser-search-recording-at () + "Search for the recording of the track at point." + (interactive) + (emms-idapi-browser-show + (emms-idapi-search emms-idapi-service + (emms-idapi-browser-search-recording + (emms-playlist-track-at (point)))))) + (defun emms-idapi-browser-search-artist-at () "Search for the artist of the track at point." (interactive) @@ -144,12 +183,21 @@ ;;; ------------------------------------------------------------------ ;;; Response ;;; ------------------------------------------------------------------ +(defun emms-idapi-browser-write-debug (response) + "Write RESPONSE to the browser debug buffer." + (let ((buffer (get-buffer-create emms-idapi-browser-debug-name))) + (with-current-buffer buffer + (erase-buffer) + (insert (format "%s" response)) + (setq emms-idapi-browser-debug-buffer buffer)))) + (defun emms-idapi-browser-print-header (header) "Print the material for the search HEADER." (let ((artist (alist-get 'info-artist header)) - (album (alist-get 'info-album header)) + (album (alist-get 'info-album header)) + (title (alist-get 'info-title header)) (service (alist-get emms-idapi-service emms-idapi-services-alist))) - (when (not (or artist album)) + (when (not (or artist album title)) (error "could not read header: %s" header)) (insert (format "service: %s (%s)\n" (alist-get 'name service) @@ -158,6 +206,8 @@ (insert (format "artist: %s\n" artist))) (when album (insert (format "album: %s\n" album))) + (when title + (insert (format "title: %s\n" title))) (insert "\n"))) (defun emms-idapi-browser-entry-packaging (entry) @@ -168,36 +218,44 @@ (format ", %s" packaging) ""))) +(defun emms-idapi-browser-print-entry-artist (entry) + "Return artist ENTRY." + (format "%s%s%s\n\n" + (alist-get 'info-artist entry) + (if (alist-get 'info-country entry) + (format " (%s) " (alist-get 'info-country entry)) + "") + (let ((begin (alist-get 'begin (alist-get 'info-time entry))) + (end (alist-get 'end (alist-get 'info-time entry)))) + (format "%s%s" + (if begin begin "") + (if end (format " - %s, " end) ""))))) + (defun emms-idapi-browser-print-entry (entry) "Print ENTRY." - (cond ((equal 'info-release (alist-get 'type entry)) + (cond ((equal 'idapi-release (alist-get 'type entry)) (insert (format "\"%s\" by %s%s\n" (alist-get 'info-album entry) (alist-get 'info-artist entry) (if (alist-get 'info-date entry) (format ", released on %s" (alist-get 'info-date entry)) ""))) + (insert (format "%s tracks%s%s\n\n" (alist-get 'info-track-count entry) (emms-idapi-browser-entry-packaging entry) (if (alist-get 'info-country entry) (format ", (%s)" (alist-get 'info-country entry)) "")))) - ((equal 'info-track-artist (alist-get 'type entry)) - (insert (format "%s%s%s\n\n" - (alist-get 'info-artist entry) - (if (alist-get 'info-country entry) - (format " (%s) " (alist-get 'info-country entry)) - "") - (let ((begin (alist-get 'begin (alist-get 'info-time entry))) - (end (alist-get 'end (alist-get 'info-time entry)))) - (format "%s%s" - (if begin begin "") - (if end (format " - %s, " end) "")))))) - (t (insert (format "%s\n" entry))))) + + ((equal 'idapi-artist (alist-get 'type entry)) + (insert (emms-idapi-browser-print-entry-artist entry))) + + (t (insert (format "unhandled entry:\n\n%s\n" entry))))) (defun emms-idapi-browser-show (response) "Display RESPONSE in a search buffer." + (emms-idapi-browser-write-debug response) (let ((buffer (emms-idapi-browser-get-buffer))) (pop-to-buffer buffer) (let ((inhibit-read-only t)) diff --git a/emms-idapi-musicbrainz.el b/emms-idapi-musicbrainz.el index 4a5554979b..b07f1bc38f 100644 --- a/emms-idapi-musicbrainz.el +++ b/emms-idapi-musicbrainz.el @@ -39,7 +39,7 @@ (defvar emms-idapi-musicbrainz-url-buffer nil "Buffer to store `url' response.") -(defvar emms-idapi-musicbrainz-response-limit 30 +(defvar emms-idapi-musicbrainz-response-limit 100 "Maximum number of responses to ask for. Maximum is 100.") (defconst emms-idapi-musicbrainz-root-url "https://musicbrainz.org/ws/2/" @@ -49,6 +49,14 @@ "Cross-call storage for search query.") (make-variable-buffer-local 'emms-idapi-query-local) +(defvar emms-idapi-musicbrainz-debug-buffer-name + " *Emms MusicBrainz Debug Buffer*" + "Name of debug buffer for MusicBrainz url responses.") + +(defvar emms-idapi-musicbrainz-debug-buffer nil + "Debug buffer for MusicBrainz url responses.") + + (defconst emms-idapi-musicbrainz-search-string-map '((info-artist . "artist") (info-albumartist . "artist") @@ -72,23 +80,38 @@ "Return a track from the MusicBrainz ARTIST." (when (not (alist-get 'id artist)) (error "could not parse from: %s" artist)) - `(*track* (search-backend . musicbrainz) - (type . info-track-artist) - (name . nil) - (info-arid . ,(alist-get 'id artist)) - (info-artist . ,(alist-get 'name artist)) - (info-type . ,(alist-get 'type artist)) - (info-country . ,(alist-get 'country artist)) - (info-time . ,(alist-get 'life-span artist)))) + `(*track* (search-backend . musicbrainz) + (type . idapi-artist) + (name . nil) + (idapi-artist-id . ,(list (cons 'musicbrainz (alist-get 'id artist)))) + (info-artist . ,(alist-get 'name artist)) + (info-gender . ,(alist-get 'gender artist)) + (info-type . ,(alist-get 'type artist)) + (info-country . ,(alist-get 'country artist)) + (info-area-type . ,(alist-get 'type (cddr (assoc 'area artist)))) + (info-area-country . ,(alist-get 'name (cddr (assoc 'area artist)))) + (info-aliases . ,(list + (seq-map + (lambda (elt) + (mm-decode-string + (alist-get 'sort-name elt) 'utf-8)) + (alist-get 'aliases artist)))) + (info-tags . ,(list + (seq-map + (lambda (elt) + (mm-decode-string + (alist-get 'name elt) 'utf-8)) + (alist-get 'tags artist)))) + (info-time . ,(alist-get 'life-span artist)))) (defun emms-idapi-musicbrainz-read-release (release) "Return a track from the MusicBrainz RELEASE." (when (not (alist-get 'id release)) (error "could not parse from: %s" release)) `(*track* (search-backend . musicbrainz) - (type . info-release) + (type . idapi-release) (name . nil) - (info-release-id . ,(alist-get 'id release)) + (idapi-release-id . ,(list (cons 'musicbrainz (alist-get 'id release)))) (info-artist . ,(alist-get 'name (elt (alist-get 'artist-credit release) 0))) (info-album . ,(alist-get 'title release)) (info-status . ,(alist-get 'status release)) @@ -102,15 +125,18 @@ "Return a track from the MusicBrainz RECORDING." (when (not (alist-get 'id recording)) (error "could not parse from: %s" recording)) - (let ((length-ms (alist-get 'length recording))) + (let ((length-ms (or (alist-get 'length recording) 0))) `(*track* (search-backend . musicbrainz) - (type . info-recording) + (type . idapi-recording) (name . ,(alist-get 'title recording)) (info-playing-time . ,(floor (/ length-ms 1000))) (info-playing-time-min . ,(floor (/ (/ length-ms 1000) 60))) (info-playing-time-sec . ,(% (floor (/ length-ms 1000)) 60)) (info-recording-id . ,(alist-get 'id recording)) - (info-album . ,(alist-get 'title recording)) + (idapi-releases . ,(seq-map + (lambda (elt) + (emms-idapi-musicbrainz-read-release elt)) + (alist-get 'releases recording))) (info-length-ms . ,length-ms)))) (defun emms-idapi-musicbrainz-process-type-dispatch (response) @@ -120,7 +146,12 @@ ((alist-get 'recordings response) #'emms-idapi-musicbrainz-read-recording) (t (error "unhandled response type %s" response)))) ;; the actual items without header data - (elements (cdr (nth 3 response)))) + (elements (cdr (nth 3 response))) + (debug-buffer (get-buffer-create emms-idapi-musicbrainz-debug-buffer-name))) + (setq emms-idapi-musicbrainz-debug-buffer debug-buffer) + (with-current-buffer debug-buffer + (erase-buffer) + (insert (format "%s" response))) (append (alist-get 'query response) (mapcar #'(lambda (e) @@ -188,24 +219,32 @@ (let ((artist (or (alist-get 'info-artist term-alist) (alist-get 'info-albumartist term-alist))) (release (alist-get 'info-album term-alist)) - (track (alist-get 'info-title term-alist)) + (title (alist-get 'info-title term-alist)) (reid (alist-get 'reid term-alist)) (arid (alist-get 'arid term-alist))) (concat emms-idapi-musicbrainz-root-url - (cond ((and artist (not release)) + (cond ((and title + artist) + (format "recording/?query=recording:%s%sartist:%s" + (url-encode-url (concat "\"" title "\"")) + (url-encode-url " AND ") + (url-encode-url (concat "\"" artist "\"")))) + + ((and artist + (not release) + (not title)) (format "artist/?query=%s" (url-encode-url (concat "\"" artist "\"")))) - (release - (format "release/?query=release:%s%s%s" - (url-encode-url (concat "\"" release "\"")) - (if artist (url-encode-url (concat " AND artist:\"" artist "\"")) "") - (if arid (concat (url-encode-url " AND ") "arid:" arid) ""))) - (track - (format "recording?query=%sreid:%s" - (url-encode-url (concat "\"" track "\"")) - reid)) - (t (error "unhandled field %s" term-alist))) + ;; Will only work if the browser supplies a meaningful musicbrainz ARID + ;; + ;; (release + ;; (format "release/?query=release:%s%s%s" + ;; (url-encode-url (concat "\"" release "\"")) + ;; (if artist (url-encode-url (concat " AND artist:\"" artist "\"")) "") + ;; (if arid (concat (url-encode-url " AND ") "arid:" arid) ""))) + + (t (error "unhandled field %s" term-alist))) (format "&limit=%d&fmt=json" emms-idapi-musicbrainz-response-limit))))