From 5bafa0257b496f9fb2b88e3ae330541bf0e608f3 Mon Sep 17 00:00:00 2001 From: Steve Ayerhart Date: Thu, 17 Dec 2020 22:12:23 -0500 Subject: [PATCH] add musicbrainz --- musicbrainz/authors.txt | 1 + musicbrainz/entities/entities.factor | 131 ++++++++++++++++++ musicbrainz/musicbrainz-docs.factor | 10 ++ musicbrainz/musicbrainz-tests.factor | 4 + musicbrainz/musicbrainz.factor | 61 +++++++++ musicbrainz/parser/parser.factor | 195 +++++++++++++++++++++++++++ musicbrainz/summary.txt | 1 + musicbrainz/tags.txt | 1 + 8 files changed, 404 insertions(+) create mode 100644 musicbrainz/authors.txt create mode 100644 musicbrainz/entities/entities.factor create mode 100644 musicbrainz/musicbrainz-docs.factor create mode 100644 musicbrainz/musicbrainz-tests.factor create mode 100644 musicbrainz/musicbrainz.factor create mode 100644 musicbrainz/parser/parser.factor create mode 100644 musicbrainz/summary.txt create mode 100644 musicbrainz/tags.txt diff --git a/musicbrainz/authors.txt b/musicbrainz/authors.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/musicbrainz/authors.txt @@ -0,0 +1 @@ + diff --git a/musicbrainz/entities/entities.factor b/musicbrainz/entities/entities.factor new file mode 100644 index 0000000..e3149d6 --- /dev/null +++ b/musicbrainz/entities/entities.factor @@ -0,0 +1,131 @@ +USING: strings calendar sequences kernel math ; +IN: musicbrainz.entities + +SINGLETONS: + person group orchestra choir character other + album single ep broadcast + compilation soundtrack spokenword interview audiobook audio-drama live remix dj-mix mixtape/street + male female + country subdivision county municipality city district island + search-hint artist-name + official promotional bootleg pseudo-release + normal high low + ; + +UNION: primary-release-group-type + album single ep broadcast other ; + +UNION: secondary-release-group-type + compilation soundtrack spokenword interview audiobook audio-drama live remix dj-mix mixtape/street ; + +UNION: artist-type + person group orchestra choir character other ; + +UNION: area-type + country subdivision county municipality city district island ; + +UNION: alias-type search-hint artist-name ; + +UNION: artist-gender + male female ; + +UNION: release-status + official promotional bootleg pseudo-release ; + +UNION: release-quality + normal high low ; + +TUPLE: entity + { mbid string } ; + +TUPLE: alias + { name string } + { sort-name string } + { type maybe{ alias-type } } + { locale maybe{ string } } ; + +TUPLE: life-span + { begin timestamp } + { end maybe{ timestamp } } + { ended? maybe{ boolean } } ; + +TUPLE: area < entity + { name string } + { type maybe{ area-type } } + { sort-name maybe{ string } } + { iso-codes maybe{ sequence } } + { begin-date maybe{ timestamp } } ; + +TUPLE: artist < entity + { name string } + { sort-name string } + { disambiguation maybe{ string } } + { life-span maybe{ life-span } } + { country maybe{ string } } + { isnis maybe{ sequence } } + { type maybe{ artist-type } } + { gender maybe{ artist-gender } } + { area maybe{ area } } + { aliases maybe{ sequence } } + { begin-area maybe{ area } } ; + +TUPLE: text-representation + { language string } + { script string } ; + +TUPLE: cover-art-archive + { artwork? boolean } + { count number } + { front? boolean } + { back? boolean } ; + +TUPLE: release-event + { date timestamp } + { area maybe{ area } } ; + +TUPLE: release < entity + { title string } + { status maybe{ release-status } } + { quality maybe{ release-quality } } + { disambiguation maybe{ string } } + { date maybe{ timestamp } } + { country maybe{ string } } + { text-representation maybe{ text-representation } } + { barcode maybe{ string } } + { asin maybe{ string } } + { release-events maybe{ sequence } } + { packaging maybe{ string } } + { mediums maybe{ sequence } } + { artist maybe{ artist } } + { label-info maybe{ sequence } } + { cover-art-archive maybe{ cover-art-archive } } ; + +TUPLE: collection < entity + { name string } + { editor string } + { releases maybe{ sequence } } ; + +TUPLE: recording < entity + { title string } + { length integer } + { artist artist } ; + +TUPLE: track < entity + { position integer } + { number integer } + { length integer } + { recording recording } ; + +TUPLE: medium + { position integer } + { number integer } + { format string } + { dics sequence } + { tracks sequence } ; + +TUPLE: label < entity + { type string } + { name string } + { sort-name maybe{ string } } + { disambiguation maybe{ string } } + { aliases maybe{ sequence } } ; diff --git a/musicbrainz/musicbrainz-docs.factor b/musicbrainz/musicbrainz-docs.factor new file mode 100644 index 0000000..3d158ce --- /dev/null +++ b/musicbrainz/musicbrainz-docs.factor @@ -0,0 +1,10 @@ +! Copyright (C) 2020 . +! See http://factorcode.org/license.txt for BSD license. +USING: help.markup help.syntax ; +IN: musicbrainz + +ARTICLE: "musicbrainz" "musicbrainz" +{ $vocab-link "musicbrainz" } +; + +ABOUT: "musicbrainz" diff --git a/musicbrainz/musicbrainz-tests.factor b/musicbrainz/musicbrainz-tests.factor new file mode 100644 index 0000000..10586f1 --- /dev/null +++ b/musicbrainz/musicbrainz-tests.factor @@ -0,0 +1,4 @@ +! Copyright (C) 2020 . +! See http://factorcode.org/license.txt for BSD license. +USING: tools.test musicbrainz ; +IN: musicbrainz.tests diff --git a/musicbrainz/musicbrainz.factor b/musicbrainz/musicbrainz.factor new file mode 100644 index 0000000..c28c4a7 --- /dev/null +++ b/musicbrainz/musicbrainz.factor @@ -0,0 +1,61 @@ +! Copyright (C) 2020 . +! See http://factorcode.org/license.txt for BSD license. +USING: kernel io.sockets.secure http http.client urls strings alien.syntax accessors arrays sequences xml.syntax xml.traversal assocs slots calendar words calendar.parser combinators io.streams.string furnace.utilities splitting qw hashtables ; +USING: io prettyprint ; +USING: musicbrainz.entities musicbrainz.parser ; +IN: musicbrainz + +CONSTANT: mb-base-url URL" https://musicbrainz.org/ws/2/" +CONSTANT: user-agent-header { "factor-musicbrainz/0.1.0 (steve@ayerh.art)" "user-agent" } +CONSTANT: accept-header { "application/xml" "accept" } +CONSTANT: collection-links qw{ releases } + +: mb-entity>string ( entity -- str ) + word>string ":" split last ; + +: ( mbid entity inc -- url ) + [ + word>string ":" split last swap 2array "/" join + mb-base-url clone swap >url derive-url + ] dip "+" join "inc" set-query-param ; + +: ( mbid -- url ) + release qw{ artist-credits recordings labels aliases } ; + +: ( mbid -- url ) + artist qw{ aliases } ; + +: ( mbid -- url ) + "/releases" append collection qw{ artist-credits releases } ; + +: ( url -- request ) + + user-agent-header first2 set-header + accept-header first2 set-header + http-request nip parse-mb-response ; + +: add-mb-headers ( url -- url ) + user-agent-header first2 set-header + accept-header first2 set-header ; + +: ( mbid -- release ) + ; + +: ( mbid -- artist ) + ; + +: ( mbid -- collection ) + ; + +: ( mbid -- url ) + [ mb-base-url clone "release" >url derive-url ] dip + "collection" set-query-param + "100" "limit" set-query-param ; + +: ( mbid -- releases ) + ; + +: ( user -- collections ) + [ mb-base-url clone "collection" >url derive-url ] dip + "editor" set-query-param + add-mb-headers http-request nip parse-mb-response ; diff --git a/musicbrainz/parser/parser.factor b/musicbrainz/parser/parser.factor new file mode 100644 index 0000000..247867b --- /dev/null +++ b/musicbrainz/parser/parser.factor @@ -0,0 +1,195 @@ +USING: kernel xml.syntax xml.traversal accessors words sequences calendar calendar.parser combinators io.streams.string assocs xml unicode arrays splitting html.components math.parser ; +USING: musicbrainz.entities ; + +USING: prettyprint ; +IN: musicbrainz.parser + +XML-NS: mb http://musicbrainz.org/ns/mmd-2.0# + +ERROR: invalid-timestamp ; + +: string>word ( str -- word ) + "musicbrainz.entities" lookup-word ; + +: string>timestamp ( str -- timestamp ) + [ length ] keep + [ + { + { 4 [ read-0000 1 1 ] } + { 7 [ read-0000 "-" expect read-00 1 ] } + { 10 [ read-ymd ] } + [ drop invalid-timestamp ] + } case + ] with-string-reader ; + +TAGS: mb-entity ( tag -- entity ) +TAGS: entity-property ( entity tag -- entity ) + +TAG: name entity-property + children>string >>name ; + +TAG: sort-name entity-property + children>string >>sort-name ; + +TAG: disambiguation entity-property + children>string >>disambiguation ; + +TAG: country entity-property + children>string >>country ; + +TAG: packaging entity-property + children>string >>packaging ; + +TAG: gender entity-property + children>string >lower string>word >>gender ; + +TAG: iso-3166-2-code-list entity-property + children-tags [ children>string ] map >array >>iso-codes ; + +TAG: iso-3166-1-code-list entity-property + children-tags [ children>string ] map >array >>iso-codes ; + +TAG: isni-list entity-property + children-tags [ children>string ] map >array >>isnis ; + +TAG: begin entity-property + children>string string>timestamp >>begin ; +TAG: end entity-property + children>string string>timestamp >>end ; + +TAG: title entity-property + children>string >>title ; +TAG: language entity-property + children>string >>language ; +TAG: script entity-property + children>string >>script ; + +TAG: status entity-property + children>string string>word >>status ; +TAG: quality entity-property + children>string string>word >>quality ; +TAG: text-representation entity-property + children-tags text-representation new [ entity-property ] reduce + >>text-representation ; +TAG: barcode entity-property + children>string >>barcode ; + +TAG: artwork entity-property + children>string string>boolean >>artwork? ; +TAG: count entity-property + children>string string>number >>count ; +TAG: front entity-property + children>string string>boolean >>front? ; +TAG: back entity-property + children>string string>boolean >>back? ; +TAG: cover-art-archive entity-property + children-tags cover-art-archive new [ entity-property ] reduce + >>cover-art-archive ; + +TAG: release-event-list entity-property + children-tags [ mb-entity ] map >array >>release-events ; + +TAG: date entity-property + children>string string>timestamp >>date ; + +TAG: life-span entity-property + children-tags life-span new [ entity-property ] reduce + >>life-span ; + +TAG: ended entity-property + children>string string>boolean >>ended? ; + +TAG: position entity-property + children>string string>number >>position ; +TAG: length entity-property + children>string string>number >>length ; +TAG: number entity-property + children>string string>number >>number ; +TAG: format entity-property + children>string >>format ; +TAG: editor entity-property + children>string >>editor ; + +TAG: track mb-entity + [ children-tags track new [ entity-property ] reduce ] + [ attrs>> "id" of ] bi + >>mbid ; + +! TODO: turn this into an mb-entity +TAG: alias-list entity-property + children-tags + [ + [ children>string ] + [ + attrs>> + [ "sort-name" of ] + [ "type" of >lower " " split "-" join string>word ] + [ "locale" of ] tri + ] bi + alias boa + ] map >array >>aliases ; + +TAG: area entity-property + [ children-tags area new [ entity-property ] reduce ] + [ attrs>> [ "id" of ] [ "type" of string>word ] bi ] bi + [ >>mbid ] dip >>type >>area ; + +TAG: begin-area entity-property + [ children-tags area new [ entity-property ] reduce ] + [ attrs>> [ "id" of ] [ "type" of string>word ] bi ] bi + [ >>mbid ] dip >>type >>begin-area ; + +TAG: release-list mb-entity + children-tags [ mb-entity ] map >array ; +TAG: release-list entity-property + children-tags [ mb-entity ] map >array >>releases ; + +TAG: asin entity-property + children>string >>asin ; + +TAG: artist mb-entity + [ children-tags artist new [ entity-property ] reduce ] + [ attrs>> [ "id" of ] [ "type" of string>word ] bi ] bi + [ >>mbid ] dip >>type ; + +TAG: release-event mb-entity + children-tags release-event new [ entity-property ] reduce ; + +TAG: release mb-entity + [ children-tags release new [ entity-property ] reduce ] + [ attrs>> "id" of ] bi >>mbid ; + +TAG: collection mb-entity + [ children-tags collection new [ entity-property ] reduce ] + [ attrs>> "id" of ] bi >>mbid ; + +TAG: collection-list mb-entity + children-tags [ mb-entity ] map >array ; + +TAG: medium-list entity-property + children-tags [ mb-entity ] map >array >>mediums ; + +TAG: track-list entity-property + children-tags [ mb-entity ] map >array >>tracks ; + +TAG: medium mb-entity + children-tags medium new [ entity-property ] reduce ; + +TAG: artist-credit entity-property + "artist" deep-tag-named mb-entity >>artist ; + +TAG: label-info-list entity-property + children-tags [ mb-entity ] map >array >>label-info ; + +TAG: label-info mb-entity + first-child-tag + [ children-tags label new [ entity-property ] reduce ] + [ attrs>> [ "id" of ] [ "type" of ] bi ] bi + [ >>mbid ] dip >>type ; + +TAG: recording entity-property + [ children-tags recording new [ entity-property ] reduce ] + [ attrs>> "id" of ] bi >>mbid >>recording ; + +: parse-mb-response ( str -- entity ) + string>xml first-child-tag mb-entity ; diff --git a/musicbrainz/summary.txt b/musicbrainz/summary.txt new file mode 100644 index 0000000..415bf4c --- /dev/null +++ b/musicbrainz/summary.txt @@ -0,0 +1 @@ +musicbrainz api diff --git a/musicbrainz/tags.txt b/musicbrainz/tags.txt new file mode 100644 index 0000000..0ec5ed8 --- /dev/null +++ b/musicbrainz/tags.txt @@ -0,0 +1 @@ +musicbrainz music metadata