Once more the fortress of pure numbers
This commit is contained in:
parent
1d2c153d5e
commit
91a3524869
2 changed files with 346 additions and 76 deletions
78
README.org
78
README.org
|
@ -3,32 +3,73 @@
|
|||
#+author:
|
||||
#+title: MusicBrainz & ListenBrainz & other
|
||||
|
||||
* MusicBrainz
|
||||
|
||||
[[file:img/musicbrainz-logo.svg]]
|
||||
|
||||
MusicBrainz is a community-maintained open source encyclopedia of [[https://musicbrainz.org/doc/About][music information]]. The REST-based [[https://musicbrainz.org/doc/MusicBrainz_API][webservice API]] can be used for direct access to MusicBrainz data with output in XML and JSON.
|
||||
|
||||
This code provides a simple, incomplete yet possibly useful interface to some of the MusicBrainz and ListenBrainz APIs from emacs for exploratory use in =org-mode= or behind the scenes sending listening metadata.
|
||||
|
||||
* MusicBrainz API
|
||||
|
||||
- Recording documentation: https://musicbrainz.org/doc/Recording
|
||||
- Release documentation: https://musicbrainz.org/doc/Release
|
||||
- Artist documentation: https://musicbrainz.org/doc/Artist
|
||||
|
||||
** searching & browsing
|
||||
|
||||
Search supports the full [[https://lucene.apache.org/core/7_7_2/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package.description][Lucene search syntax]].
|
||||
|
||||
** some examples
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(musicbrainz-search "recording" "taema")
|
||||
#+END_SRC
|
||||
|
||||
Autechre albums & eps
|
||||
|
||||
docs provide the example URL https://musicbrainz.org/ws/2/release-group?artist=410c9baf-5469-44f6-9852-826524b80c61&type=album|ep
|
||||
The API docs provide an example search for “Autechre albums & eps” using the URL https://musicbrainz.org/ws/2/release-group?artist=410c9baf-5469-44f6-9852-826524b80c61&type=album|ep
|
||||
|
||||
The equivalent function (which returns a raw response as an alist) would be…
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(musicbrainz-browse "release-group" "artist" "410c9baf-5469-44f6-9852-826524b80c61" "album|ep")
|
||||
#+END_SRC
|
||||
|
||||
For slightly more legible output wrap with =musicbrainz-format=
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(musicbrainz-search-artist "Autechre")
|
||||
(musicbrainz-format (musicbrainz-browse "release-group" "artist" "410c9baf-5469-44f6-9852-826524b80c61" "album|ep"))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
| Autechre | 410c9baf-5469-44f6-9852-826524b80c61 |
|
||||
A more interactive approach could start with =(musicbrainz-search "artist" "Autechre")= or =(musicbrainz-search-artist "Autechre")= Which returns the MBID required for the lookup → =410c9baf-5469-44f6-9852-826524b80c61=
|
||||
|
||||
The MBID can be checked if needed, with =(musicbrainz-mbid-p "410c9baf-5469-44f6-9852-826524b80c61")=
|
||||
|
||||
The MBID can then be used for specific lookups…
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(musicbrainz-lookup "artist" "410c9baf-5469-44f6-9852-826524b80c61" "releases")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(musicbrainz-lookup-artist "410c9baf-5469-44f6-9852-826524b80c61")
|
||||
#+END_SRC
|
||||
|
||||
| Autechre | electronic music duo | Group | [[https://musicbrainz.org/artist/410c9baf-5469-44f6-9852-826524b80c61][410c9baf-5469-44f6-9852-826524b80c61]] |
|
||||
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(musicbrainz-lookup-artist-releases "410c9baf-5469-44f6-9852-826524b80c61")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(musicbrainz-lookup-artist-recordings "410c9baf-5469-44f6-9852-826524b80c61")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(musicbrainz-lookup-release "ec1ecfcc-f529-43d1-8aa6-2c7051ede00c")
|
||||
#+END_SRC
|
||||
|
||||
| 1990 | Autechre / Saw You | Cassette Case | [[https://musicbrainz.org/release/ec1ecfcc-f529-43d1-8aa6-2c7051ede00c][ec1ecfcc-f529-43d1-8aa6-2c7051ede00c]] |
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(musicbrainz-lookup-recording "83730176-89ec-41a5-a4b6-476998f6291c")
|
||||
#+END_SRC
|
||||
|
||||
| [untitled] | [[https://musicbrainz.org/recording/83730176-89ec-41a5-a4b6-476998f6291c][83730176-89ec-41a5-a4b6-476998f6291c]] |
|
||||
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
|
@ -85,7 +126,7 @@ John Williams, the classical guitar player, has an artist MBID of 8b8a38a9-a290-
|
|||
=7feb02f2-51fa-422d-838e-2c14ecb4c7b8= → Tomorrows Bad Seeds
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(musicbrainz-disambiguate-artist "Bad Seeds")
|
||||
(musicbrainz-disambiguate-artist "Bad Seeds" 7)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
|
@ -96,11 +137,15 @@ John Williams, the classical guitar player, has an artist MBID of 8b8a38a9-a290-
|
|||
| 98 | The Bad Seeds, backing band for Nick Cave | [[https://musicbrainz.org/artist/eb2a8edc-5670-4896-82be-87db38de9583][eb2a8edc-5670-4896-82be-87db38de9583]] |
|
||||
| 86 | Nick Cave & the Bad Seeds, nil | [[https://musicbrainz.org/artist/172e1f1a-504d-4488-b053-6344ba63e6d0][172e1f1a-504d-4488-b053-6344ba63e6d0]] |
|
||||
| 50 | The Lightning Seeds, nil | [[https://musicbrainz.org/artist/1ba601a0-3401-4b28-8ddd-9af8203661e8][1ba601a0-3401-4b28-8ddd-9af8203661e8]] |
|
||||
| 49 | Seeds, UK dancehall | [[https://musicbrainz.org/artist/a03cf587-a3d3-4847-ac41-e488f779a313][a03cf587-a3d3-4847-ac41-e488f779a313]] |
|
||||
|
||||
|
||||
|
||||
* ListenBrainz
|
||||
|
||||
|
||||
[[file:img/listenbrainz-logo.svg]]
|
||||
|
||||
* listening
|
||||
|
||||
- https://listenbrainz.org
|
||||
|
@ -125,11 +170,11 @@ John Williams, the classical guitar player, has an artist MBID of 8b8a38a9-a290-
|
|||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(listenbrainz-submit-single-listen "farmersmanual" "808808008088 (11)")
|
||||
(listenbrainz-submit-single-listen "Matthew Thomas" "Taema" "Architecture")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(listenbrainz-submit-single-listen "Matthew Thomas" "Taema" "Architecture")
|
||||
(listenbrainz-submit-single-listen "farmersmanual" "808808008088 (11)")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
|
@ -141,7 +186,7 @@ John Williams, the classical guitar player, has an artist MBID of 8b8a38a9-a290-
|
|||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(listenbrainz-stats-artists "zzzkt") ;; defaults to ’all time’
|
||||
(listenbrainz-stats-artists "zzzkt")
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
|
@ -246,6 +291,11 @@ https://listenbrainz.readthedocs.io/en/production/dev/api/#pinned-recording-api-
|
|||
| GET /1/(user_name)/pins | - |
|
||||
|
||||
|
||||
* otherBrainz
|
||||
- [[https://critiquebrainz.org/][CritiqueBrainz]]
|
||||
- [[https://bookbrainz.org/][BookBrainz]] → https://api.test.bookbrainz.org/1/docs/
|
||||
- [[https://listenbrainz.org/messybrainz/][MessyBrainz]]
|
||||
- [[https://coverartarchive.org/][Cover art archive]]
|
||||
|
||||
* further
|
||||
- https://listenbrainz.org/user/troi-bot/playlists/
|
||||
|
|
256
musicbrainz.el
256
musicbrainz.el
|
@ -5,7 +5,7 @@
|
|||
;; Author: nik gaffney <nik@fo.am>
|
||||
;; Created: 2023-05-05
|
||||
;; Version: 0.1
|
||||
;; Package-Requires: ((emacs "27.1") (request "0.3"))
|
||||
;; Package-Requires: ((emacs "28.1") (request "0.3"))
|
||||
;; Keywords: music, scrobbling, multimedia
|
||||
;; URL: https://github.com/zzkt/metabrainz
|
||||
|
||||
|
@ -97,6 +97,31 @@ Documentation available at https://musicbrainz.org/doc/MusicBrainz_API"
|
|||
"recording" "release" "release-group" "series" "work" "url")
|
||||
"API resources for linked entites in the MusicBrainz database.")
|
||||
|
||||
(defconst musicbrainz-search-types
|
||||
(list "annotation" "area" "artist" "cdstub" "event" "instrument"
|
||||
"label" "place" "recording" "release" "release-group"
|
||||
"series" "tag" "work" "url")
|
||||
"Valid TYPE parameters for MusicBrainz searches.")
|
||||
|
||||
|
||||
;; entity checks
|
||||
|
||||
(defun musicbrainz-core-entity-p (entity)
|
||||
"Check if ENTITY is a core entity."
|
||||
(if (member entity musicbrainz-entities-core) t nil))
|
||||
|
||||
(defun musicbrainz-non-core-entity-p (entity)
|
||||
"Check if ENTITY is a non-core entity."
|
||||
(if (member entity musicbrainz-entities-non-core) t nil))
|
||||
|
||||
(defun musicbrainz-uid-entity-p (entity)
|
||||
"Check if ENTITY is a unique identifier entity."
|
||||
(if (member entity musicbrainz-entities-uids) t nil))
|
||||
|
||||
(defun musicbrainz-search-type-p (type)
|
||||
"Check if TYPE is a valid search type."
|
||||
(if (member type musicbrainz-search-types) t nil))
|
||||
|
||||
|
||||
;; Linked entities
|
||||
|
||||
|
@ -129,7 +154,8 @@ The following list shows which linked entities you can use in a browse request:
|
|||
(defun musicbrainz-mbid-p (mbid)
|
||||
"Check (permissive) if MBID is valid and/or well formatted.
|
||||
An MBID is a 36 character Universally Unique Identifier, see https://musicbrainz.org/doc/MusicBrainz_Identifier for details."
|
||||
(if (and (length= mbid 36)
|
||||
|
||||
(if (and (length= mbid 36) ;; length= requires emacs > 28.1
|
||||
(string-match-p
|
||||
(rx (repeat 8 hex) ;; [A-F0-9]{8}
|
||||
"-" (repeat 4 hex) ;; -[A-F0-9]{4}
|
||||
|
@ -140,43 +166,99 @@ An MBID is a 36 character Universally Unique Identifier, see https://musicbrainz
|
|||
t nil))
|
||||
|
||||
|
||||
(defun musicbrainz-format (response)
|
||||
"Format a generic RESPONSE."
|
||||
(format "%s" (pp response)))
|
||||
|
||||
|
||||
;;; ;; ;; ; ; ; ; ; ;
|
||||
;;
|
||||
;; Search API
|
||||
;; https://musicbrainz.org/doc/MusicBrainz_API/Search
|
||||
;;
|
||||
;; The MusicBrainz API search requests provide a way to search for MusicBrainz
|
||||
;; entities based on different sorts of queries and are provided by a search
|
||||
;; server built using Lucene technology.
|
||||
;;
|
||||
;; Parameters common to all resources
|
||||
;;
|
||||
;; type Selects the entity index to be searched: annotation, area, artist,
|
||||
;; cdstub, event, instrument, label, place, recording, release,
|
||||
;; release-group, series, tag, work, url
|
||||
;;
|
||||
;; query Lucene search query. This is mandatory
|
||||
;;
|
||||
;; limit An integer value defining how many entries should be returned.
|
||||
;; Only values between 1 and 100 (both inclusive) are allowed.
|
||||
;; If not given, this defaults to 25.
|
||||
;;
|
||||
;; offset Return search results starting at a given offset.
|
||||
;; Used for paging through more than one page of results.
|
||||
;;
|
||||
;; dismax If set to "true", switches the Solr query parser from edismax to dismax,
|
||||
;; which will escape certain special query syntax characters by default
|
||||
;; for ease of use. This is equivalent to switching from the "Indexed search
|
||||
;; with advanced query syntax" method to the plain "Indexed search" method
|
||||
;; on the website. Defaults to "false".
|
||||
;;
|
||||
;; ;; ; ; ;
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(defun musicbrainz-search (entity query &optional limit)
|
||||
"Search the MusicBrainz database for ENTITY matching QUERY.
|
||||
Optionally return only LIMIT number of results.
|
||||
(defun musicbrainz-search (type query &optional limit offset)
|
||||
"Search the MusicBrainz database for TYPE matching QUERY.
|
||||
Optionally return only LIMIT number of results from OFFSET.
|
||||
|
||||
The QUERY field supports the full Lucene Search syntax, some details
|
||||
can be found near https://musicbrainz.org/doc/MusicBrainz_API/Search
|
||||
or in the Lucene docs."
|
||||
|
||||
(message "musicbrainz: searching %s=%s" entity query)
|
||||
(message "musicbrainz: searching %s=%s" type query)
|
||||
(let* ((max (if limit limit 1))
|
||||
(from (if offset offset ""))
|
||||
(response
|
||||
(request-response-data
|
||||
(request
|
||||
(url-encode-url
|
||||
(format "%s/%s?query=%s&fmt=json&limit=%s"
|
||||
musicbrainz-api-url entity query max))
|
||||
(format "%s/%s?query=%s&fmt=json&limit=%s&offset=%s"
|
||||
musicbrainz-api-url type query max from))
|
||||
:type "GET"
|
||||
:parser 'json-read
|
||||
:sync t
|
||||
:success (cl-function
|
||||
(lambda (&key data &allow-other-keys)
|
||||
(if (eq t (assoc-default 'valid data))
|
||||
(message "Token is valid for user: %s"
|
||||
(assoc-default 'user_name data))
|
||||
(message "Not a valid user token"))))))))
|
||||
(message "ok")))))))
|
||||
response))
|
||||
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(defun musicbrainz-find (query &rest extras)
|
||||
"Search the MusicBrainz database for QUERY or recommend a more specific search.
|
||||
MusicBrainz makes a distinction between `search' and `browse' this a more general
|
||||
entry point to searching/browsing the database.
|
||||
|
||||
Heuristics.
|
||||
- if QUERY is an MBID, check artist, recording, etc
|
||||
- if QUERY is text, search for artists or recordings, etc"
|
||||
|
||||
(message "musicbrainz: finding: %s" query)
|
||||
(if (musicbrainz-mbid-p query)
|
||||
;; search (lookup) for things that could have an mbid
|
||||
(let ((mbid query))
|
||||
(message "searching mbid: %s" mbid))
|
||||
;; search (query) for other things
|
||||
(progn
|
||||
(message "searching other: %s" mbid)
|
||||
;; (message "searching artist: %s" query)
|
||||
;; (musicbrainz-format (musicbrainz-search "artist" query))
|
||||
;; (message "searching label: %s" query)
|
||||
;; (musicbrainz-format (musicbrainz-search "label" query))
|
||||
;; (message "searching release: %s" query)
|
||||
;; (musicbrainz-format (musicbrainz-search "release" query))
|
||||
)))
|
||||
|
||||
|
||||
|
||||
;; various specific searches
|
||||
|
||||
;;;###autoload
|
||||
|
@ -214,7 +296,8 @@ See `musicbrainz-disambiguate-artist' if there are multiple matches."
|
|||
(defun musicbrainz-disambiguate-artist (artist &optional limit)
|
||||
"More ARTIST data. less ambiguity (with optional LIMIT).
|
||||
Outputs an `org-mode' table with descriptions and MBID link to artists pages."
|
||||
(let ((data (musicbrainz-search "artist" artist limit)))
|
||||
(let* ((max (if limit limit 11))
|
||||
(data (musicbrainz-search "artist" artist max)))
|
||||
(let-alist data
|
||||
(cons (format "| Artist: %s| MBID |\n" artist)
|
||||
(seq-map
|
||||
|
@ -249,6 +332,143 @@ Optionally return LIMIT number of results."
|
|||
.labels))))
|
||||
|
||||
|
||||
;;;###autoload
|
||||
(defun musicbrainz-search-recording (query &optional limit)
|
||||
"Search for a recording using QUERY and show matches.
|
||||
Optionally return LIMIT number of results."
|
||||
(let ((data (musicbrainz-search "recording" query limit)))
|
||||
(let-alist
|
||||
data
|
||||
(seq-map
|
||||
(lambda (i)
|
||||
(let-alist i
|
||||
(format "%s | %s, %s | [[https://musicbrainz.org/release/%s][%s]] |\n"
|
||||
.score .title (musicbrainz--unwrap-0 .artist-credit) .id .id)))
|
||||
.recordings))))
|
||||
|
||||
|
||||
(defun musicbrainz--unwrap-0 (entity)
|
||||
"Unwrap (fragile) .artist-credit ENTITY -> .name more or less."
|
||||
(format "%s" (cdar (aref entity 0))))
|
||||
|
||||
;;;###autoload
|
||||
(defun musicbrainz-search-release (query &optional limit)
|
||||
"Search for a release using QUERY and show matches.
|
||||
Optionally return LIMIT number of results."
|
||||
(let ((data (musicbrainz-search "release" query limit)))
|
||||
(let-alist
|
||||
data
|
||||
(seq-map
|
||||
(lambda (i)
|
||||
(let-alist i
|
||||
(format "%s | %s, %s | [[https://musicbrainz.org/release/%s][%s]] |\n"
|
||||
.score .title (musicbrainz--unwrap-0 .artist-credit) .id .id)))
|
||||
.releases))))
|
||||
|
||||
|
||||
;;; ;; ;; ; ; ; ; ; ;
|
||||
;;
|
||||
;; Lookups
|
||||
;; https://musicbrainz.org/doc/MusicBrainz_API#Lookups
|
||||
;;
|
||||
;;; ;; ;; ; ;
|
||||
|
||||
;;;###autoload
|
||||
(defun musicbrainz-lookup (entity mbid &optional inc)
|
||||
"Search (lookup not browse) the MusicBrainz database for ENTITY with MBID.
|
||||
Optionally add an INC list.
|
||||
|
||||
Subqueries
|
||||
/ws/2/area
|
||||
/ws/2/artist recordings, releases, release-groups, works
|
||||
/ws/2/collection user-collections (includes private collections, requires authentication)
|
||||
/ws/2/event
|
||||
/ws/2/genre
|
||||
/ws/2/instrument
|
||||
/ws/2/label releases
|
||||
/ws/2/place
|
||||
/ws/2/recording artists, releases, isrcs, url-rels
|
||||
/ws/2/release artists, collections, labels, recordings, release-groups
|
||||
/ws/2/release-group artists, releases
|
||||
/ws/2/series
|
||||
/ws/2/work
|
||||
/ws/2/url"
|
||||
|
||||
(message "musicbrainz: lookup: %s/%s" entity mbid)
|
||||
(if (and (musicbrainz-core-entity-p entity)
|
||||
(musicbrainz-mbid-p mbid))
|
||||
(let* ((add (if inc inc ""))
|
||||
(response
|
||||
(request-response-data
|
||||
(request
|
||||
(url-encode-url
|
||||
(format "%s/%s/%s?inc=%s&fmt=json"
|
||||
musicbrainz-api-url entity mbid add))
|
||||
:type "GET"
|
||||
:parser 'json-read
|
||||
:sync t
|
||||
:success (cl-function
|
||||
(lambda (&key data &allow-other-keys)
|
||||
(message "%s data: %s" entity mbid)))))))
|
||||
response)
|
||||
(error "MusicBrainz: search requires a valid MBID and entity (i.e. one of %s)"
|
||||
musicbrainz-entities-core)))
|
||||
|
||||
|
||||
;; specific MBID subrequests (limited to 25 results?)
|
||||
|
||||
(defun musicbrainz-lookup-artist (mbid)
|
||||
"MusicBrainz lookup for artist with MBID."
|
||||
(let ((response
|
||||
(musicbrainz-lookup "artist" mbid)))
|
||||
(let-alist response
|
||||
(format "| %s | %s | %s | [[https://musicbrainz.org/artist/%s][%s]] |\n"
|
||||
.name .disambiguation .type .id .id))))
|
||||
|
||||
|
||||
(defun musicbrainz-lookup-release (mbid)
|
||||
"MusicBrainz lookup for release with MBID."
|
||||
(let ((response
|
||||
(musicbrainz-lookup "release" mbid)))
|
||||
(let-alist response
|
||||
(format "| %s | %s | %s | [[https://musicbrainz.org/release/%s][%s]] |\n"
|
||||
.date .title .packaging .id .id))))
|
||||
|
||||
(defun musicbrainz-lookup-recording (mbid)
|
||||
"MusicBrainz lookup for recording with MBID."
|
||||
(let ((response
|
||||
(musicbrainz-lookup "recording" mbid)))
|
||||
(let-alist response
|
||||
(format "%s | [[https://musicbrainz.org/recording/%s][%s]] |\n"
|
||||
.title .id .id))))
|
||||
|
||||
|
||||
(defun musicbrainz-lookup-artist-releases (mbid)
|
||||
"MusicBrainz lookup for releases from artist with MBID."
|
||||
(let ((response
|
||||
(musicbrainz-lookup "artist" mbid "releases")))
|
||||
(let-alist response
|
||||
(seq-map
|
||||
(lambda (i)
|
||||
(let-alist i
|
||||
(format "%s | %s | %s | [[https://musicbrainz.org/release/%s][%s]] |\n"
|
||||
.date .title .packaging .id .id)))
|
||||
.releases))))
|
||||
|
||||
|
||||
(defun musicbrainz-lookup-artist-recordings (mbid)
|
||||
"MusicBrainz lookup for recordings from artist with MBID."
|
||||
(let ((response
|
||||
(musicbrainz-lookup "artist" mbid "recordings")))
|
||||
(let-alist response
|
||||
(seq-map
|
||||
(lambda (i)
|
||||
(let-alist i
|
||||
(format "%s | [[https://musicbrainz.org/recording/%s][%s]] |\n"
|
||||
.title .id .id)))
|
||||
.recordings))))
|
||||
|
||||
|
||||
|
||||
;;;;;; ; ; ;; ; ; ; ; ; ;; ;
|
||||
;;
|
||||
|
@ -278,16 +498,16 @@ Optionally return LIMIT number of results."
|
|||
|
||||
|
||||
;;;###autoload
|
||||
(defun musicbrainz-browse (entity link lookup &optional type)
|
||||
"Search the MusicBrainz database for ENTITY with LINK matching LOOKUP.
|
||||
(defun musicbrainz-browse (entity link query &optional type)
|
||||
"Search the MusicBrainz database for ENTITY with LINK matching QUERY.
|
||||
Optionally limit the search to TYPE results for ENTITY."
|
||||
(message "musicbrainz: browsing %s linked to %s" entity link)
|
||||
(message "url: %s/%s?%s=%s&type=%s&fmt=json" musicbrainz-api-url entity link lookup type)
|
||||
(message "url: %s/%s?%s=%s&type=%s&fmt=json" musicbrainz-api-url entity link query type)
|
||||
(let ((response
|
||||
(request-response-data
|
||||
(request
|
||||
(url-encode-url
|
||||
(format "%s/%s?%s=%s&type=%s&fmt=json" musicbrainz-api-url entity link lookup type))
|
||||
(format "%s/%s?%s=%s&type=%s&fmt=json" musicbrainz-api-url entity link query type))
|
||||
:type "GET"
|
||||
:parser 'json-read
|
||||
:sync t
|
||||
|
|
Loading…
Reference in a new issue