See the windows in your hand

This commit is contained in:
nik gaffney 2023-05-20 13:45:28 +02:00
parent 21ade49d85
commit 6a27268134
2 changed files with 311 additions and 100 deletions

View file

@ -1,7 +1,7 @@
# -*- mode: org; coding: utf-8; -*- # -*- mode: org; coding: utf-8; -*-
#+OPTIONS: toc:2 num:nil html-style:nil #+OPTIONS: toc:2 num:nil html-style:nil
#+author: #+author:
#+title: MusicBrainz & ListenBrainz & other #+title: MusicBrainz & ListenBrainz & others
* MusicBrainz * MusicBrainz
@ -11,7 +11,7 @@ MusicBrainz is a community-maintained open source encyclopedia of [[https://musi
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. 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 ** MusicBrainz API
- Recording documentation: https://musicbrainz.org/doc/Recording - Recording documentation: https://musicbrainz.org/doc/Recording
- Release documentation: https://musicbrainz.org/doc/Release - Release documentation: https://musicbrainz.org/doc/Release
@ -92,9 +92,7 @@ The MBID can be used for specific lookups (and checked if needed using =musicbra
** MBID ** MBID
“One of MusicBrainz' aims is to be the universal lingua franca for music by providing a reliable and unambiguous form of music identification; this music identification is performed through the use of MusicBrainz Identifiers (MBIDs). An MBID is a 36 character Universally Unique Identifier that is permanently assigned to each entity in the database, i.e. artists, release groups, releases, recordings, works, labels, areas, places and URLs. MBIDs are also assigned to Tracks, though tracks do not share many other properties of entities.” “One of MusicBrainz' aims is to be the universal lingua franca for music by providing a reliable and unambiguous form of music identification; this music identification is performed through the use of MusicBrainz Identifiers (MBIDs). An MBID is a 36 character Universally Unique Identifier that is permanently assigned to each entity in the database, i.e. artists, release groups, releases, recordings, works, labels, areas, places and URLs. MBIDs are also assigned to Tracks, though tracks do not share many other properties of entities.” https://musicbrainz.org/doc/MusicBrainz_Identifier
https://musicbrainz.org/doc/MusicBrainz_Identifier
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(musicbrainz-artist-to-mbid "Autechre") (musicbrainz-artist-to-mbid "Autechre")
@ -136,7 +134,6 @@ Which returns the MBID =7feb02f2-51fa-422d-838e-2c14ecb4c7b8= for “Tomorrows B
(musicbrainz-disambiguate-artist "Bad Seeds" 7) (musicbrainz-disambiguate-artist "Bad Seeds" 7)
#+END_SRC #+END_SRC
#+RESULTS:
| | Artist: Bad Seeds | MBID | | | Artist: Bad Seeds | MBID |
| 100 | Tomorrows Bad Seeds, nil | [[https://musicbrainz.org/artist/7feb02f2-51fa-422d-838e-2c14ecb4c7b8][7feb02f2-51fa-422d-838e-2c14ecb4c7b8]] | | 100 | Tomorrows Bad Seeds, nil | [[https://musicbrainz.org/artist/7feb02f2-51fa-422d-838e-2c14ecb4c7b8][7feb02f2-51fa-422d-838e-2c14ecb4c7b8]] |
| 98 | The Bad Seeds, 60s Texas rock band | [[https://musicbrainz.org/artist/3e593712-9f70-4b7a-b21b-466016998a3d][3e593712-9f70-4b7a-b21b-466016998a3d]] | | 98 | The Bad Seeds, 60s Texas rock band | [[https://musicbrainz.org/artist/3e593712-9f70-4b7a-b21b-466016998a3d][3e593712-9f70-4b7a-b21b-466016998a3d]] |
@ -146,6 +143,64 @@ Which returns the MBID =7feb02f2-51fa-422d-838e-2c14ecb4c7b8= for “Tomorrows B
| 50 | The Lightning Seeds, nil | [[https://musicbrainz.org/artist/1ba601a0-3401-4b28-8ddd-9af8203661e8][1ba601a0-3401-4b28-8ddd-9af8203661e8]] | | 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]] | | 49 | Seeds, UK dancehall | [[https://musicbrainz.org/artist/a03cf587-a3d3-4847-ac41-e488f779a313][a03cf587-a3d3-4847-ac41-e488f779a313]] |
#+BEGIN_SRC emacs-lisp
(musicbrainz-lookup-artist "172e1f1a-504d-4488-b053-6344ba63e6d0")
#+END_SRC
** incompleteness
general, specific and partial API coverage
*** 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]] in queries.
| (musicbrainz-search /type/ /query/ &optional /limit/ /offset/) | see =musicbrainz-search-types= |
| (musicbrainz-browse /entity/ /link/ /query/ &optional /type/) | and =musicbrainz-entities-*= |
| (musicbrainz-search-artist /artist/ &optional /limit/) | |
| (musicbrainz-artist-to-mbid /artist/) | |
| (musicbrainz-disambiguate-artist /artist/ &optional /limit/) | |
| (musicbrainz-search-label /label/ &optional /limit/) | |
| (musicbrainz-search-recording /query/ &optional /limit/) | |
| (musicbrainz-search-release /query/ &optional /limit/) | |
*** Lookup queries & subqueries
| (musicbrainz-lookup /entity/ /MBID/ &optional /inc/) | valid entities listed in =musicbrainz-entities-core= |
| *Functions & formatted output* | example MBID |
| (musicbrainz-lookup-area /MBID/) | [[https://musicbrainz.org/area/c9ac1239-e832-41bc-9930-e252a1fd1105][c9ac1239-e832-41bc-9930-e252a1fd1105]] |
| (musicbrainz-lookup-artist /MBID/) | [[https://musicbrainz.org/artist/410c9baf-5469-44f6-9852-826524b80c61][410c9baf-5469-44f6-9852-826524b80c61]] |
| (musicbrainz-lookup-artist-recordings /MBID/) | … |
| (musicbrainz-lookup-artist-releases /MBID/) | … |
| (musicbrainz-lookup-artist-release-groups /MBID/) | … |
| (musicbrainz-lookup-artist-works /MBID/) | … |
| (musicbrainz-lookup-collection /MBID/) | … |
| (musicbrainz-lookup-collection-user-collections /MBID/) | … |
| (musicbrainz-lookup-event /MBID/) | [[https://musicbrainz.org/event/7c132556-e902-4481-b9cb-ec76a175628a][7c132556-e902-4481-b9cb-ec76a175628a]] |
| (musicbrainz-lookup-genre /MBID/) | [[https://musicbrainz.org/genre/68c81274-5770-4e7b-a4bf-ab0d7d425d99][68c81274-5770-4e7b-a4bf-ab0d7d425d99]] |
| (musicbrainz-lookup-instrument /MBID/) | [[https://musicbrainz.org/instrument/303d4f1a-f799-4c42-9bac-dbedd9139e91][303d4f1a-f799-4c42-9bac-dbedd9139e91]] |
| (musicbrainz-lookup-label /MBID/) | [[https://musicbrainz.org/label/8943d408-940c-403b-a01d-9036c227d50f][8943d408-940c-403b-a01d-9036c227d50f]] |
| (musicbrainz-lookup-label-releases /MBID/) | … |
| (musicbrainz-lookup-place /MBID/) | [[https://musicbrainz.org/place/73cba8a4-cacb-45b9-8e02-654f716e2e7a][73cba8a4-cacb-45b9-8e02-654f716e2e7a]] |
| (musicbrainz-lookup-recording /MBID/) | [[https://musicbrainz.org/recording/ef8b34c1-8548-472c-872f-03e0d8d3bb37][ef8b34c1-8548-472c-872f-03e0d8d3bb37]] |
| (musicbrainz-lookup-recording-artists /MBID/) | … |
| (musicbrainz-lookup-recording-releases /MBID/) | … |
| (musicbrainz-lookup-recording-isrcs /MBID/) | … |
| (musicbrainz-lookup-recording-url-rels /MBID/) | … |
| (musicbrainz-lookup-release /MBID/) | … |
| (musicbrainz-lookup-release-artists /MBID/) | … |
| (musicbrainz-lookup-release-collections /MBID/) | … |
| (musicbrainz-lookup-release-labels /MBID/) | … |
| (musicbrainz-lookup-release-recordings /MBID/) | … |
| (musicbrainz-lookup-release-release-groups /MBID/) | … |
| (musicbrainz-lookup-release-group /MBID/) | [[https://musicbrainz.org/release-group/fe4acfe9-6d1e-3565-8857-fb16ddc492ab][fe4acfe9-6d1e-3565-8857-fb16ddc492ab]] |
| (musicbrainz-lookup-release-group-artists /MBID/) | … |
| (musicbrainz-lookup-release-group-releases /MBID/) | … |
| (musicbrainz-lookup-series /MBID/) | … |
| (musicbrainz-lookup-work /MBID/) | … |
| (musicbrainz-lookup-url /MBID/) | … |
* ListenBrainz * ListenBrainz
@ -153,12 +208,12 @@ Which returns the MBID =7feb02f2-51fa-422d-838e-2c14ecb4c7b8= for “Tomorrows B
[[file:img/listenbrainz-logo.svg]] [[file:img/listenbrainz-logo.svg]]
* listening ** listening
- https://listenbrainz.org - https://listenbrainz.org
- https://listenbrainz.readthedocs.io/ - https://listenbrainz.readthedocs.io/
* examples ** examples
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(setq listenbrainz-api-token "000-000-000") (setq listenbrainz-api-token "000-000-000")
@ -204,9 +259,8 @@ Which returns the MBID =7feb02f2-51fa-422d-838e-2c14ecb4c7b8= for “Tomorrows B
(listenbrainz-stats-recordings "zzzkt" 13 "month") (listenbrainz-stats-recordings "zzzkt" 13 "month")
#+END_SRC #+END_SRC
* incompleteness ** incompleteness
*** Core API endpoints
** Core API endpoints
https://listenbrainz.readthedocs.io/en/production/dev/api/#core-api-endpoints https://listenbrainz.readthedocs.io/en/production/dev/api/#core-api-endpoints
@ -227,7 +281,7 @@ https://listenbrainz.readthedocs.io/en/production/dev/api/#core-api-endpoints
| GET /1/latest-import | - | | GET /1/latest-import | - |
| POST /1/latest-import | - | | POST /1/latest-import | - |
** Feedback API Endpoints *** Feedback API Endpoints
https://listenbrainz.readthedocs.io/en/production/dev/api/#feedback-api-endpoints https://listenbrainz.readthedocs.io/en/production/dev/api/#feedback-api-endpoints
@ -236,13 +290,13 @@ https://listenbrainz.readthedocs.io/en/production/dev/api/#feedback-api-endpoint
| GET /1/feedback/user/(user_name)/get-feedback-for-recordings | | | GET /1/feedback/user/(user_name)/get-feedback-for-recordings | |
| GET /1/feedback/user/(user_name)/get-feedback | - | | GET /1/feedback/user/(user_name)/get-feedback | - |
** Recording Recommendation API Endpoints *** Recording Recommendation API Endpoints
https://listenbrainz.readthedocs.io/en/production/dev/api/#core-api-endpoints https://listenbrainz.readthedocs.io/en/production/dev/api/#core-api-endpoints
| GET /1/cf/recommendation/user/(user_name)/recording | - | | GET /1/cf/recommendation/user/(user_name)/recording | - |
** Recording Recommendation Feedback API Endpoints *** Recording Recommendation Feedback API Endpoints
https://listenbrainz.readthedocs.io/en/production/dev/api/#recording-recommendation-feedback-api-endpoints https://listenbrainz.readthedocs.io/en/production/dev/api/#recording-recommendation-feedback-api-endpoints
@ -251,7 +305,7 @@ https://listenbrainz.readthedocs.io/en/production/dev/api/#recording-recommendat
| GET /1/recommendation/feedback/user/(user_name)/recordings | - | | GET /1/recommendation/feedback/user/(user_name)/recordings | - |
| GET /1/recommendation/feedback/user/(user_name) | - | | GET /1/recommendation/feedback/user/(user_name) | - |
** Statistics API Endpoints *** Statistics API Endpoints
https://listenbrainz.readthedocs.io/en/production/dev/api/#statistics-api-endpoints https://listenbrainz.readthedocs.io/en/production/dev/api/#statistics-api-endpoints
@ -263,13 +317,13 @@ https://listenbrainz.readthedocs.io/en/production/dev/api/#statistics-api-endpoi
| GET /1/stats/user/(user_name)/releases | listenbrainz-stats-releases | | GET /1/stats/user/(user_name)/releases | listenbrainz-stats-releases |
| GET /1/stats/user/(user_name)/artists | listenbrainz-stats-artists | | GET /1/stats/user/(user_name)/artists | listenbrainz-stats-artists |
** Status API Endpoints *** Status API Endpoints
https://listenbrainz.readthedocs.io/en/production/dev/api/#status-api-endpoints https://listenbrainz.readthedocs.io/en/production/dev/api/#status-api-endpoints
| GET /1/status/get-dump-info | - | | GET /1/status/get-dump-info | - |
** User Timeline API Endpoints *** User Timeline API Endpoints
https://listenbrainz.readthedocs.io/en/production/dev/api/#user-timeline-api-endpoints https://listenbrainz.readthedocs.io/en/production/dev/api/#user-timeline-api-endpoints
@ -278,7 +332,7 @@ https://listenbrainz.readthedocs.io/en/production/dev/api/#user-timeline-api-end
| POST /1/user/(user_name)/feed/events/delete | - | | POST /1/user/(user_name)/feed/events/delete | - |
| GET /1/user/(user_name)/feed/events | - | | GET /1/user/(user_name)/feed/events | - |
** Social API Endpoints *** Social API Endpoints
https://listenbrainz.readthedocs.io/en/production/dev/api/#social-api-endpoints https://listenbrainz.readthedocs.io/en/production/dev/api/#social-api-endpoints
@ -287,7 +341,7 @@ https://listenbrainz.readthedocs.io/en/production/dev/api/#social-api-endpoints
| POST /1/user/(user_name)/unfollow | - | | POST /1/user/(user_name)/unfollow | - |
| POST /1/user/(user_name)/follow | - | | POST /1/user/(user_name)/follow | - |
** Pinned Recording API Endpoints *** Pinned Recording API Endpoints
https://listenbrainz.readthedocs.io/en/production/dev/api/#pinned-recording-api-endpoints https://listenbrainz.readthedocs.io/en/production/dev/api/#pinned-recording-api-endpoints
@ -305,5 +359,7 @@ https://listenbrainz.readthedocs.io/en/production/dev/api/#pinned-recording-api-
- [[https://coverartarchive.org/][Cover art archive]] - [[https://coverartarchive.org/][Cover art archive]]
* further * further
- https://labs.api.listenbrainz.org/
- https://troi.readthedocs.io/en/latest/
- https://listenbrainz.org/user/troi-bot/playlists/ - https://listenbrainz.org/user/troi-bot/playlists/
- https://github.com/metabrainz/bono-data-sets/blob/main/top_discoveries.py - https://github.com/metabrainz/bono-data-sets/blob/main/top_discoveries.py

View file

@ -38,6 +38,10 @@
(require 'request) (require 'request)
(require 'json) (require 'json)
;; debug level for http requests
(setq request-log-level 'warn
request-message-level 'warn)
;;; ;; ;; ; ; ; ; ; ; ;;; ;; ;; ; ; ; ; ; ;
;; ;;
@ -56,6 +60,12 @@ Documentation available at https://musicbrainz.org/doc/MusicBrainz_API"
:type 'string :type 'string
:group 'musicbrainz) :group 'musicbrainz)
(defcustom musicbrainz-user-agent "musicbrainz.el/0.1"
"A User-Agent header to identify source of API requests.
As seen in https://wiki.musicbrainz.org/MusicBrainz_API/Rate_Limiting"
:type 'string
:group 'musicbrainz)
;;; ; ; ;;; ; ; ;;; ; ; ;;; ; ;
;; ;;
;; API entities ;; API entities
@ -159,7 +169,7 @@ An MBID is a 36 character Universally Unique Identifier, see https://musicbrainz
(string-match-p (string-match-p
(rx (repeat 8 hex) ;; [A-F0-9]{8} (rx (repeat 8 hex) ;; [A-F0-9]{8}
"-" (repeat 4 hex) ;; -[A-F0-9]{4} "-" (repeat 4 hex) ;; -[A-F0-9]{4}
"-4" (repeat 3 hex) ;; -4[A-F0-9]{3} "-" (repeat 4 hex) ;; -[34][A-F0-9]{3}
"-" (repeat 4 hex) ;; -[89AB][A-F0-9]{3} "-" (repeat 4 hex) ;; -[89AB][A-F0-9]{3}
"-" (repeat 12 hex)) ;; -[A-F0-9]{12} "-" (repeat 12 hex)) ;; -[A-F0-9]{12}
mbid)) mbid))
@ -171,6 +181,11 @@ An MBID is a 36 character Universally Unique Identifier, see https://musicbrainz
(format "%s" (pp response))) (format "%s" (pp response)))
(defun musicbrainz--unwrap-0 (entity)
"Unwrap (fragile) .artist-credit ENTITY -> .name more or less."
(format "%s" (cdar (aref entity 0))))
;;; ;; ;; ; ; ; ; ; ; ;;; ;; ;; ; ; ; ; ; ;
;; ;;
;; Search API ;; Search API
@ -212,7 +227,7 @@ The QUERY field supports the full Lucene Search syntax, some details
can be found near https://musicbrainz.org/doc/MusicBrainz_API/Search can be found near https://musicbrainz.org/doc/MusicBrainz_API/Search
or in the Lucene docs." or in the Lucene docs."
(message "musicbrainz: searching %s=%s" type query) (message "MusicBrainz: searching %s=%s" type query)
(let* ((max (if limit limit 1)) (let* ((max (if limit limit 1))
(from (if offset offset "")) (from (if offset offset ""))
(response (response
@ -222,6 +237,7 @@ or in the Lucene docs."
(format "%s/%s?query=%s&fmt=json&limit=%s&offset=%s" (format "%s/%s?query=%s&fmt=json&limit=%s&offset=%s"
musicbrainz-api-url type query max from)) musicbrainz-api-url type query max from))
:type "GET" :type "GET"
:headers (list `("User-Agent" . ,musicbrainz-user-agent))
:parser 'json-read :parser 'json-read
:sync t :sync t
:success (cl-function :success (cl-function
@ -230,38 +246,30 @@ or in the Lucene docs."
response)) response))
;;;###autoload ;;;###autoload
(defun musicbrainz-find (query &rest extras) (defun musicbrainz-find (query &rest extras)
"Search the MusicBrainz database for QUERY or recommend a more specific search. "Search MusicBrainz for QUERY (and EXTRAS) or recommend a more specific search.
MusicBrainz makes a distinction between `search' and `browse' this a more general MusicBrainz makes a distinction between `search', `lookup' and `browse' this
entry point to searching/browsing the database. provides a more general entry point to searching/browsing the database.
Heuristics. Heuristics.
- not yet
- if QUERY is an MBID, check artist, recording, etc - if QUERY is an MBID, check artist, recording, etc
- if QUERY is text, search for artists or recordings, etc" - if QUERY is text, search for artists or recordings, etc"
(message "musicbrainz: finding: %s" query) (message "MusicBrainz: query %s" query)
(if (musicbrainz-mbid-p query) (if (musicbrainz-mbid-p query)
;; search (lookup) for things that could have an mbid ;; search (lookup) for things that could have an mbid
(let ((mbid query)) (let ((mbid query))
(message "searching mbid: %s" mbid)) (message "searching mbid: %s" mbid))
;; search (query) for other things ;; search (search/browse/query) for other things
(progn (progn
(message "searching other: %s" mbid) (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 ;; various specific searches
;;;###autoload
(defun musicbrainz-search-artist (artist &optional limit) (defun musicbrainz-search-artist (artist &optional limit)
"Search for an ARTIST and show matches. "Search for an ARTIST and show matches.
Optionally return LIMIT number of results." Optionally return LIMIT number of results."
@ -278,7 +286,6 @@ Optionally return LIMIT number of results."
.artists)))) .artists))))
;;;###autoload
(defun musicbrainz-artist-to-mbid (artist) (defun musicbrainz-artist-to-mbid (artist)
"Find an MBID for ARTIST (with 100% match). "Find an MBID for ARTIST (with 100% match).
See `musicbrainz-disambiguate-artist' if there are multiple matches." See `musicbrainz-disambiguate-artist' if there are multiple matches."
@ -292,7 +299,6 @@ See `musicbrainz-disambiguate-artist' if there are multiple matches."
.artists)))))) .artists))))))
;;;###autoload
(defun musicbrainz-disambiguate-artist (artist &optional limit) (defun musicbrainz-disambiguate-artist (artist &optional limit)
"More ARTIST data. less ambiguity (with optional LIMIT). "More ARTIST data. less ambiguity (with optional LIMIT).
Outputs an `org-mode' table with descriptions and MBID link to artists pages." Outputs an `org-mode' table with descriptions and MBID link to artists pages."
@ -308,7 +314,6 @@ Outputs an `org-mode' table with descriptions and MBID link to artists pages."
.artists))))) .artists)))))
;;;###autoload
(defun musicbrainz-search-label (label &optional limit) (defun musicbrainz-search-label (label &optional limit)
"Search for a LABEL and show matches. "Search for a LABEL and show matches.
Optionally return LIMIT number of results." Optionally return LIMIT number of results."
@ -332,7 +337,6 @@ Optionally return LIMIT number of results."
.labels)))) .labels))))
;;;###autoload
(defun musicbrainz-search-recording (query &optional limit) (defun musicbrainz-search-recording (query &optional limit)
"Search for a recording using QUERY and show matches. "Search for a recording using QUERY and show matches.
Optionally return LIMIT number of results." Optionally return LIMIT number of results."
@ -347,11 +351,6 @@ Optionally return LIMIT number of results."
.recordings)))) .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) (defun musicbrainz-search-release (query &optional limit)
"Search for a release using QUERY and show matches. "Search for a release using QUERY and show matches.
Optionally return LIMIT number of results." Optionally return LIMIT number of results."
@ -375,13 +374,13 @@ Optionally return LIMIT number of results."
;;;###autoload ;;;###autoload
(defun musicbrainz-lookup (entity mbid &optional inc) (defun musicbrainz-lookup (entity mbid &optional inc)
"Search (lookup not browse) the MusicBrainz database for ENTITY with MBID. "Search (lookup not browse) MusicBrainz for ENTITY with MBID.
Optionally add an INC list. Optionally add an INC list.
Subqueries Subqueries
/ws/2/area /ws/2/area
/ws/2/artist recordings, releases, release-groups, works /ws/2/artist recordings, releases, release-groups, works
/ws/2/collection user-collections (includes private collections, requires authentication) /ws/2/collection user-collections (requires authentication)
/ws/2/event /ws/2/event
/ws/2/genre /ws/2/genre
/ws/2/instrument /ws/2/instrument
@ -394,7 +393,7 @@ Subqueries
/ws/2/work /ws/2/work
/ws/2/url" /ws/2/url"
(message "musicbrainz: lookup: %s/%s" entity mbid) (message "MusicBrainz: lookup: %s/%s" entity mbid)
(if (and (musicbrainz-core-entity-p entity) (if (and (musicbrainz-core-entity-p entity)
(musicbrainz-mbid-p mbid)) (musicbrainz-mbid-p mbid))
(let* ((add (if inc inc "")) (let* ((add (if inc inc ""))
@ -415,58 +414,213 @@ Subqueries
musicbrainz-entities-core))) musicbrainz-entities-core)))
;; specific MBID subrequests (limited to 25 results?) ;; specific MBID lookup requests & subrequests (limited to 25 results?)
(defun musicbrainz-lookup-artist (mbid) (defmacro musicbrainz--deflookup-1 (name format-string format-args)
"MusicBrainz lookup for artist with MBID." "Generate lookup function to format a single item.
NAME FORMAT-STRING FORMAT-ARGS
See listenbrainz--deformatter for details."
(let ((f (intern (concat "musicbrainz-lookup-" name)))
(doc "MusicBrainz lookup."))
`(defun ,f (mbid) ,doc
(let ((response (let ((response
(musicbrainz-lookup "artist" mbid))) (musicbrainz-lookup ,name mbid)))
(let-alist response (let-alist response
(format "| %s | %s | %s | [[https://musicbrainz.org/artist/%s][%s]] |\n" (format ,format-string ,@format-args))))))
.name .disambiguation .type .id .id))))
(defun musicbrainz-lookup-release (mbid) (defmacro musicbrainz--deflookup-2 (query subquery format-string format-args alist)
"MusicBrainz lookup for release with MBID." "Generate lookup function to format multiple items.
QUERY SUBQUERY FORMAT-STRING FORMAT-ARGS ALIST
See listenbrainz--deformatter for details."
(let ((f (intern (format "musicbrainz-lookup-%s-%s" query subquery)))
(doc "MusicBrainz lookup."))
`(defun ,f (mbid) ,doc
(let ((response (let ((response
(musicbrainz-lookup "release" mbid))) (musicbrainz-lookup ,query mbid ,subquery)))
(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 (let-alist response
(seq-map (seq-map
(lambda (i) (lambda (i)
(let-alist i (let-alist i
(format "%s | %s | %s | [[https://musicbrainz.org/release/%s][%s]] |\n" (format ,format-string ,@format-args)))
.date .title .packaging .id .id))) ,alist))))))
.releases))))
(defun musicbrainz-lookup-artist-recordings (mbid) ;; (defun musicbrainz-lookup-artist (mbid)
"MusicBrainz lookup for recordings from artist with MBID." ;; "MusicBrainz lookup for artist with MBID."
(let ((response ;; (let ((response
(musicbrainz-lookup "artist" mbid "recordings"))) ;; (musicbrainz-lookup "artist" mbid)))
(let-alist response ;; (let-alist response
(seq-map ;; (format "| %s | %s | %s | [[https://musicbrainz.org/artist/%s][%s]] |\n"
(lambda (i) ;; .name .disambiguation .type .id .id))))
(let-alist i
(format "%s | [[https://musicbrainz.org/recording/%s][%s]] |\n"
.title .id .id))) ;; (defun musicbrainz-lookup-artist-recordings (mbid)
.recordings)))) ;; "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))))
;; lookup -> musicbrainz-lookup-area
(musicbrainz--deflookup-1 "area"
"| %s | [[https://musicbrainz.org/area/%s][%s]] |\n"
(.name .id .id))
;; lookup -> musicbrainz-lookup-artist
(musicbrainz--deflookup-1 "artist"
"| %s | %s | %s | [[https://musicbrainz.org/artist/%s][%s]] |\n"
(.name .disambiguation .type .id .id))
;; lookup -> musicbrainz-lookup-artist-recordings
(musicbrainz--deflookup-2 "artist" "recordings"
"%s | [[https://musicbrainz.org/recording/%s][%s]] |\n"
(.title .id .id)
.recordings)
;; lookup -> musicbrainz-lookup-artist-releases
(musicbrainz--deflookup-2 "artist" "releases"
"%s | %s | %s | [[https://musicbrainz.org/release/%s][%s]] |\n"
(.date .title .packaging .id .id)
.releases)
;; lookup -> musicbrainz-lookup-artist-release-groups
(musicbrainz--deflookup-2 "artist" "release-groups"
"%s | %s | %s | [[https://musicbrainz.org/release-group/%s][%s]] |\n"
(.first-release-date .title .primary-type .id .id)
.release-groups)
;; lookup -> musicbrainz-lookup-artist-works
(musicbrainz--deflookup-2 "artist" "works"
" %s | [[https://musicbrainz.org/work/%s][%s]] |\n"
(.title .id .id)
.works)
;; lookup -> musicbrainz-lookup-collection
(musicbrainz--deflookup-1 "collection"
"| %s | [[https://musicbrainz.org/collection/%s][%s]] |\n"
(.name .id .id))
;; lookup -> musicbrainz-lookup-collection-user-collections (requires authentication)
(musicbrainz--deflookup-2 "collection" "user-collections"
" %s | [[https://musicbrainz.org/collection/%s][%s]] |\n"
(.name .id .id)
.collection)
;; lookup -> musicbrainz-lookup-event
(musicbrainz--deflookup-1 "event"
"| %s | [[https://musicbrainz.org/event/%s][%s]] |\n"
(.name .id .id))
;; lookup -> musicbrainz-lookup-genre
(musicbrainz--deflookup-1 "genre"
"| %s | [[https://musicbrainz.org/genre/%s][%s]] |\n"
(.name .id .id))
;; lookup -> musicbrainz-lookup-instrument
(musicbrainz--deflookup-1 "instrument"
"| %s | %s | [[https://musicbrainz.org/instrument/%s][%s]] |\n"
(.name .type .id .id))
;; lookup -> musicbrainz-lookup-label
(musicbrainz--deflookup-1 "label"
"| %s | %s | [[https://musicbrainz.org/label/%s][%s]] |\n"
(.name .disambiguation .id .id))
;; lookup -> musicbrainz-lookup-label-releases
(musicbrainz--deflookup-2 "label" "releases"
"%s | %s | [[https://musicbrainz.org/release/%s][%s]] |\n"
(.date .title .id .id)
.releases)
;; lookup -> musicbrainz-lookup-place
(musicbrainz--deflookup-1 "place"
"| %s | [[https://musicbrainz.org/place/%s][%s]] |\n"
(.name .id .id))
;; lookup -> musicbrainz-lookup-recording
(musicbrainz--deflookup-1 "recording"
"| %s | %s | [[https://musicbrainz.org/recording/%s][%s]] |\n"
(.first-release-date .title .id .id))
;; lookup -> musicbrainz-lookup-recording-artists
(musicbrainz--deflookup-2 "recording" "artists"
"%s | [[https://musicbrainz.org/artist/%s][%s]] |\n"
(.artist.name .artist.id .artist.id)
.artist-credit)
;; lookup -> musicbrainz-lookup-recording-releases
(musicbrainz--deflookup-2 "recording" "releases"
"%s | %s | %s | [[https://musicbrainz.org/release/%s][%s]] |\n"
(.date .title .packaging .id .id)
.releases)
;; lookup -> musicbrainz-lookup-recording-isrcs
(musicbrainz--deflookup-2 "recording" "isrcs"
"%s | [[https://musicbrainz.org/isrc/%s][%s]] |\n"
(.name .id .id)
.isrcs)
;; lookup -> musicbrainz-lookup-recording-url-rels
(musicbrainz--deflookup-2 "recording" "url-rels"
"%s | [[https://musicbrainz.org/recording/%s][%s]] |\n"
(.name .id .id)
.relations)
;; lookup -> musicbrainz-lookup-release
(musicbrainz--deflookup-1 "release"
"| %s | %s | %s | [[https://musicbrainz.org/release/%s][%s]] |\n"
(.date .title .packaging .id .id))
;; lookup -> musicbrainz-lookup-release-artists
(musicbrainz--deflookup-2 "release" "artists"
"%s | [[https://musicbrainz.org/artist/%s][%s]] |\n"
(.artist.name .artist.id .artist.id)
.artist-credit)
;; lookup -> musicbrainz-lookup-release-collections
;; lookup -> musicbrainz-lookup-release-labels
;; lookup -> musicbrainz-lookup-release-recordings
;; lookup -> musicbrainz-lookup-release-release-groups
;; lookup -> musicbrainz-lookup-release-group
(musicbrainz--deflookup-1 "release-group"
"| %s | %s | %s | [[https://musicbrainz.org/release-group/%s][%s]] |\n"
(.first-release-date .title .primary-type .id .id))
;; lookup -> musicbrainz-lookup-release-group-artists
(musicbrainz--deflookup-2 "release-group" "artists"
"%s | [[https://musicbrainz.org/artist/%s][%s]] |\n"
(.artist.name .artist.id .artist.id)
.artist-credit)
;; lookup -> musicbrainz-lookup-release-group-releases
;; lookup -> musicbrainz-lookup-series
(musicbrainz--deflookup-1 "series"
"| %s | [[https://musicbrainz.org/series/%s][%s]] |\n"
(.name .id .id))
;; lookup -> musicbrainz-lookup-work
(musicbrainz--deflookup-1 "work"
"| %s | [[https://musicbrainz.org/work/%s][%s]] |\n"
(.name .id .id))
;; lookup -> musicbrainz-lookup-url
(musicbrainz--deflookup-1 "url"
"| %s | [[https://musicbrainz.org/url/%s][%s]] |\n"
(.name .id .id))
@ -501,7 +655,7 @@ Subqueries
(defun musicbrainz-browse (entity link query &optional type) (defun musicbrainz-browse (entity link query &optional type)
"Search the MusicBrainz database for ENTITY with LINK matching QUERY. "Search the MusicBrainz database for ENTITY with LINK matching QUERY.
Optionally limit the search to TYPE results for ENTITY." Optionally limit the search to TYPE results for ENTITY."
(message "musicbrainz: browsing %s linked to %s" entity link) (message "MusicBrainz: browsing %s linked to %s" entity link)
(message "url: %s/%s?%s=%s&type=%s&fmt=json" musicbrainz-api-url entity link query type) (message "url: %s/%s?%s=%s&type=%s&fmt=json" musicbrainz-api-url entity link query type)
(let ((response (let ((response
(request-response-data (request-response-data
@ -509,6 +663,7 @@ Optionally limit the search to TYPE results for ENTITY."
(url-encode-url (url-encode-url
(format "%s/%s?%s=%s&type=%s&fmt=json" musicbrainz-api-url entity link query type)) (format "%s/%s?%s=%s&type=%s&fmt=json" musicbrainz-api-url entity link query type))
:type "GET" :type "GET"
:header (list `("User-Agent" . ,musicbrainz-user-agent))
:parser 'json-read :parser 'json-read
:sync t :sync t
:success (cl-function :success (cl-function