├── .gitignore ├── docs ├── requirements.txt ├── serve.py ├── conf.py ├── index.rst ├── Makefile └── api.rst ├── ref ├── package.json ├── webclient │ ├── index.html │ └── webclient.js └── server.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | docs/_build 2 | ref/node_modules 3 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinxcontrib-httpdomain >= 1.3.0 2 | -------------------------------------------------------------------------------- /docs/serve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from livereload import Server, shell 3 | server = Server() 4 | server.watch('*.rst', shell('make html')) 5 | server.serve(root='_build/html') 6 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | source_suffix = '.rst' 2 | master_doc = 'index' 3 | exclude_patterns = ['_build'] 4 | extensions = ['sphinxcontrib.httpdomain'] 5 | 6 | project = u'AURA' 7 | copyright = u'2014, Adrian Sampson' 8 | 9 | version = '0.2' 10 | release = '0.2.0' 11 | 12 | html_theme = 'default' 13 | 14 | # HTTP domain config. 15 | primary_domain = 'http' 16 | http_index_shortname = 'reference' 17 | http_index_localname = 'API Reference' 18 | http_index_ignore_prefixes = ['/aura'] 19 | -------------------------------------------------------------------------------- /ref/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auraref", 3 | "description": "AURA reference implementations", 4 | "version": "0.1.0", 5 | "author": "Adrian Sampson ", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/sampsyo/aura" 9 | }, 10 | "dependencies": { 11 | "musicmetadata": "^2.0.5", 12 | "walk": "^2.3.13", 13 | "express": "^4.16.3", 14 | "cors": "^2.8.4" 15 | }, 16 | "bin": { 17 | "aura-server": "./server.js" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ref/webclient/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AURA Reference Client 5 | 6 | 7 | 8 |

AURA Reference Client

9 |

Server Information

10 | 16 |

Tracks

17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | AURA Universal REST API 2 | ======================= 3 | 4 | AURA is an API specification for music libraries. Music players---from HTML5 5 | applications to mobile apps to embedded devices---use AURA to access servers 6 | that host catalogs of music. An AURA server can act as a personal alternative 7 | to centralized cloud services like Spotify or Rdio. 8 | 9 | The AURA protocol is a lightweight and open alternative to `DLNA`_ or `DAAP`_. 10 | 11 | The API specification is organized as a *core API* that reflects the basic 12 | concepts and optional *extensions*. While not every sever will implement the 13 | same extensions, clients can assume that those that do will implement them in 14 | the same way. 15 | 16 | .. _dlna: http://www.dlna.org 17 | .. _daap: http://en.wikipedia.org/wiki/Digital_Audio_Access_Protocol 18 | 19 | Contents: 20 | 21 | .. toctree:: 22 | :maxdepth: 2 23 | 24 | api 25 | 26 | Also see the `complete list of endpoints `_. 27 | -------------------------------------------------------------------------------- /ref/webclient/webclient.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function() { 2 | var ajax = function (url, success) { 3 | var xhr = new XMLHttpRequest(); 4 | xhr.onload = function () { 5 | var res = JSON.parse(this.responseText); 6 | success(res); 7 | }; 8 | xhr.open("get", url); 9 | xhr.send(); 10 | }; 11 | 12 | var tracklist = document.getElementById('tracklist'); 13 | var baseurl = 'http://0.0.0.0:8338/aura'; 14 | 15 | ajax(baseurl + '/server', function (json) { 16 | var attr = json["attributes"]; 17 | for (var a in attr) 18 | document.getElementById(a).textContent = a + ': ' + attr[a]; 19 | }); 20 | 21 | ajax(baseurl + '/tracks', function (json) { 22 | for (var i = 0; i < json.tracks.length; ++i) { 23 | var track = json.tracks[i]; 24 | 25 | var link = document.createElement('a'); 26 | link.textContent = track.title; 27 | link.href = baseurl + '/tracks/' + track.id + '/audio'; 28 | 29 | var li = document.createElement('li'); 30 | li.appendChild(document.createTextNode( 31 | track.artist + ' - ' + track.album + ' - ' 32 | )); 33 | li.appendChild(link); 34 | 35 | tracklist.appendChild(li); 36 | } 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AURA Universal REST API 2 | ======================= 3 | 4 | AURA is a design for simple, REST API for music libraries. It's the glue between music players and libraries of music. 5 | 6 | ## Specification 7 | 8 | See [the evolving spec](http://auraspec.readthedocs.org/) online. The source for this documentation is under the `docs/` directory in this repository. 9 | 10 | ## Reference Implementation 11 | 12 | This repository also hosts a very simple reference server and client implemented in JavaScript. Here's how to use them: 13 | 14 | $ cd ref/ 15 | $ npm install # Get the dependencies for the server. 16 | $ node server.js /path/to/music/dir # Run the server. 17 | $ open webclient/index.html # Open the client in a browser. 18 | 19 | The reference implementation is incomplete and extremely preliminary. It demonstrates listing tracks and sending audio files. 20 | 21 | ## Get Involved 22 | 23 | This is an experimental project! We'd like to create an API that's suited to a broad range of music players and music libraries---it should be a good basis for any networked music project idea you have. 24 | 25 | If you're interested in helping guide the direction of the AURA project, we'd love to collaborate. Please [get in touch][email]. 26 | 27 | [email]: mailto:adrian@radbox.org 28 | -------------------------------------------------------------------------------- /ref/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var musicmetadata = require('musicmetadata'); 5 | var walk = require('walk'); 6 | var path = require('path'); 7 | var express = require('express'); 8 | var cors = require('cors'); 9 | 10 | // Global information about this server resource 11 | const serverInformation = { 12 | "type": "server", 13 | "id": "0", 14 | "attributes": { 15 | "aura-version": "0.2.0", 16 | "server": "aura-ref", 17 | "server-version": "0.2.1", 18 | "auth-required": true, 19 | } 20 | }; 21 | 22 | // Read a track dictionary for a music file. 23 | var trackDict = function(path, func) { 24 | musicmetadata(fs.createReadStream(path), function (err, metadata) { 25 | if (err) { 26 | return; 27 | } 28 | func({ 29 | 'path': path, 30 | 'artist': metadata.artist[0], 31 | 'title': metadata.title, 32 | 'album': metadata.album, 33 | }); 34 | }); 35 | }; 36 | 37 | // Read all the music files in a directory (recursively) and record all of 38 | // their metadata dictionaries in a giant array. 39 | var readMetadata = function (basedir, func) { 40 | var md = []; 41 | var walker = walk.walk(basedir); 42 | walker.on("file", function (root, stats, next) { 43 | var p = path.join(root, stats.name); 44 | trackDict(p, function (d) { 45 | console.log('read: ' + p); 46 | md.push(d); 47 | }); 48 | next(); 49 | }).on("end", function () { 50 | // Add IDs to each. 51 | for (var i = 0; i < md.length; ++i) { 52 | md[i].id = i.toString(); 53 | } 54 | func(md); 55 | }); 56 | }; 57 | 58 | // Read the metadata and start the server. 59 | readMetadata(process.argv[2] || '.', function (tracks) { 60 | var loadTrack = function (req, res, next) { 61 | var id = parseInt(req.params.id); 62 | if (isNaN(id) || id < 0 || id > tracks.length) { 63 | res.status(404).end(); 64 | } else { 65 | req.track = tracks[id]; 66 | next(); 67 | } 68 | }; 69 | 70 | // The Express Router contains all the AURA endpoints. 71 | var aura = express.Router(); 72 | // Enable cross-origin resource sharing. 73 | aura.use(cors()); 74 | 75 | // Utility for JSON endpoints to set the content type. 76 | var jtype = function(req, res, next) { 77 | res.set('Content-Type', 'application/vnd.api+json'); 78 | next(); 79 | }; 80 | 81 | // AURA API endpoints. 82 | aura.get('/server', jtype, function (req, res) { 83 | res.json( serverInformation ); 84 | }); 85 | aura.get('/tracks', jtype, function (req, res) { 86 | res.json({ 'tracks': tracks }); 87 | }); 88 | aura.get('/tracks/:id', jtype, loadTrack, function (req, res) { 89 | res.json({ 'tracks': req.track }); 90 | }); 91 | aura.get('/tracks/:id/audio', loadTrack, function (req, res) { 92 | var fname = path.basename(req.track.path); 93 | res.sendFile(req.track.path, { 94 | 'headers': { 95 | 'Content-Disposition': 'attachment; filename="' + fname + '"' 96 | } 97 | }); 98 | }); 99 | 100 | // An Express Application to host the API under the /aura prefix. 101 | var app = express(); 102 | app.use('/aura', aura); 103 | 104 | var server = app.listen(8338, function () { 105 | var host = server.address().address; 106 | var port = server.address().port; 107 | console.log('http://%s:%s', host, port); 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext auto 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/AURA.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/AURA.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/AURA" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/AURA" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | Core API Specification 2 | ====================== 3 | 4 | This document describes the core AURA protocol, which is a simple `REST`_ API 5 | built on `JSON`_ resources. The core protocol includes basic, read-only 6 | access to *tracks* and, optionally, organization into *albums* and *artists*. 7 | It exposes both metadata and audio. 8 | 9 | The API adheres to the `JSON API`_ 1.0 specification. 10 | 11 | This description uses words like "SHOULD" and "MUST" in all caps to invoke 12 | their meaning according to `RFC 2119`_. 13 | 14 | .. _RFC 2119: http://tools.ietf.org/html/rfc2119 15 | .. _JSON: http://www.json.org 16 | .. _JSON API: http://jsonapi.org 17 | .. _REST: http://en.wikipedia.org/wiki/Representational_state_transfer 18 | 19 | 20 | Organization 21 | ------------ 22 | 23 | The API root **SHOULD** appear under a prefix named ``/aura/``. This 24 | facilitates servers with multiple APIs, allows for human-readable content at 25 | the root on the same server, and provides for forward compatibility: future 26 | versions of this spec may recommend ``/aura2/``, for example. 27 | 28 | Response Format and Errors 29 | '''''''''''''''''''''''''' 30 | 31 | The MIME type for all responses **MUST** be ``application/vnd.api+json``. 32 | Every response is a `JSON`_ object. 33 | When a request is successful, the document has a top-level key ``data`` 34 | corresponding to the response's "primary data." 35 | When it fails, the document has an ``errors`` key, which maps to an array of 36 | JSON API `error objects`_. 37 | Other keys may also be present, as described below. 38 | 39 | .. _error objects: http://jsonapi.org/format/#errors 40 | .. _server-info: 41 | 42 | 43 | Server Information 44 | ------------------ 45 | 46 | .. http:get:: /aura/server 47 | :synopsis: Server information and status. 48 | 49 | The "root" endpoint exposes global information and status for the AURA 50 | server. The response's ``data`` key maps to a `resource object`_ 51 | dictionary representing the server. The object's ``attributes`` key 52 | **MUST** contain these keys: 53 | 54 | * **aura-version**, string: The version of the AURA spec implemented. 55 | * **server**, string: The name of the server software. 56 | * **server-version**, string: The version number of the server. 57 | * **auth-required**, bool: Whether the user has access to the server. For 58 | unsecured servers, this may be true even before authenticating. 59 | 60 | It **MAY** also contain these keys: 61 | 62 | * **features**, string array: A list of optional features the server 63 | supports. 64 | 65 | .. _resource object: http://jsonapi.org/format/#document-resource-objects 66 | 67 | .. sourcecode:: http 68 | 69 | GET /aura/server HTTP/1.1 70 | 71 | .. sourcecode:: http 72 | 73 | HTTP/1.1 200 OK 74 | Content-Type: application/vnd.api+json 75 | 76 | { 77 | "data": { 78 | "type": "server", 79 | "id": "0", 80 | "attributes": { 81 | "aura-version": "0.2.0", 82 | "server": "aura-ref", 83 | "server-version": "0.2.1", 84 | "auth-required": false, 85 | "features": ["albums"] 86 | } 87 | } 88 | } 89 | 90 | 91 | Resources and Collections 92 | ------------------------- 93 | 94 | The core resource in AURA is the *track*, which represents a single audio 95 | file and its associated metadata. 96 | 97 | The server may also optionally group tracks into *albums* and *artists*. Since 98 | tracks represent the music itself, albums and artists are not 99 | required---clients **SHOULD** disable features that depend on browsing by 100 | album, for example, when the server only exposes individual tracks. 101 | Clients can still filter tracks by metadata that indicates the album or artist 102 | they belong to. AURA's optional concepts of *albums* and *artists* are 103 | appropriate when the server supports metadata that is independent of the 104 | constituent tracks: cover art for albums, for example, or home towns for 105 | artists. 106 | 107 | Every resource is represented as a JSON object. Each resource type has a list 108 | of keys that are *required* on each object and a list of *optional* fields 109 | that the server may support. Servers may also provide other, non-standard 110 | fields not listed in this specification. The optional fields are included in 111 | an effort to standardize the name and format of common (albeit not universal) 112 | metadata. 113 | 114 | Names of attributes, including non-standard attributes, **SHOULD** only contain 115 | characters matched by the regular expression ``[a-zA-Z0-9_-]``. 116 | 117 | .. _relationships: 118 | 119 | Relationships 120 | ''''''''''''' 121 | 122 | In AURA, there are `relationships`_ among resources. For example, a track can 123 | have a relationship to its containing album and, conversely, an album has 124 | relationships to its tracks. 125 | 126 | `JSON API relationships`_ appear under the ``relationships`` key within the resource 127 | object, which maps to an object. 128 | Values in that object are JSON API "relationship objects": in AURA, these are 129 | wrappers for `resource linkages`_, which indicate the ID of another resource. 130 | For example, a track object links to its album like this: 131 | 132 | .. sourcecode:: http 133 | 134 | GET /aura/tracks/42 HTTP/1.1 135 | 136 | .. sourcecode:: http 137 | 138 | HTTP/1.1 200 OK 139 | Content-Type: application/vnd.api+json 140 | 141 | { 142 | "data": { 143 | "type": "track", 144 | "id": "42", 145 | "attributes": { 146 | // ... 147 | }, 148 | "relationships": { 149 | "albums": { 150 | "data": [ { "type": "album", "id": "84" } ] 151 | } 152 | } 153 | } 154 | } 155 | 156 | This means that the client can get more information about the album at 157 | ``/aura/albums/84``. 158 | 159 | The client can request `inclusion`_ of related resources. The client provides an 160 | ``include`` request parameter containing a comma-separated list of resources. 161 | The response then **MUST** include any such objects referenced in 162 | ``relationships`` under an ``included`` key in the top-level response object. 163 | That ``included`` key maps to an array of resource objects. 164 | (This kind of response is called a `compound document`_ in JSON API.) 165 | For example: 166 | 167 | .. sourcecode:: http 168 | 169 | GET /aura/tracks/42?include=album HTTP/1.1 170 | 171 | .. sourcecode:: http 172 | 173 | HTTP/1.1 200 OK 174 | Content-Type: application/vnd.api+json 175 | 176 | { 177 | "data": { 178 | "type": "track", 179 | "id": "42", 180 | "attributes": { 181 | // ... 182 | }, 183 | "relationships": { 184 | "albums": { 185 | "data": [ { "type": "album", "id": "84" } ] 186 | } 187 | } 188 | }, 189 | "included": [ 190 | { 191 | "type": "album", 192 | "id": "84", 193 | // ... 194 | } 195 | ] 196 | } 197 | 198 | .. _compound document: http://jsonapi.org/format/#document-compound-documents 199 | .. _JSON API relationships: http://jsonapi.org/format/#document-resource-object-relationships 200 | .. _resource linkages: http://jsonapi.org/format/#document-resource-object-linkage 201 | .. _inclusion: http://jsonapi.org/format/#fetching-includes 202 | 203 | Filtering 204 | ''''''''' 205 | 206 | Servers provide filtered lists of resources according to metadata. 207 | To request a subset of a collection, the client uses request parameters 208 | specifying the fields or links to filter on. 209 | If the client sends a parameter ``filter[key]=value``, the server **MUST** 210 | respond with only those resources whose ``key`` field exactly matches 211 | ``value``. 212 | 213 | For example, the request ``/aura/tracks?filter[title]=Blackbird`` finds the 214 | track titled "Blackbird". 215 | 216 | Filtering is by exact match only (i.e., no substring or case-insensitive 217 | matching is performed). More flexible queries may be eventually be specified 218 | in an AURA extension. 219 | 220 | If there are no exact matches, or if the server does not support filtering by 221 | the given key, then the ``data`` key of the response should be an empty array. 222 | 223 | Sorting 224 | ''''''' 225 | 226 | Sorting of collections and subsets of collections follows the 227 | `JSON API sorting`_ specification. Sort fields correspond to keys in a 228 | resource's ``attributes`` member. 229 | 230 | This example shows albums sorted by descending release date (newest first): 231 | 232 | .. sourcecode:: http 233 | 234 | GET /aura/albums?sort=-year,-month,-day HTTP/1.1 235 | 236 | .. sourcecode:: http 237 | 238 | HTTP/1.1 200 OK 239 | Content-Type: application/vnd.api+json 240 | 241 | { 242 | "data": [ 243 | { 244 | "type": "album", 245 | "id": "42", 246 | "attributes": { 247 | // ... 248 | "year": 2019, 249 | "month": 3, 250 | "day": 24, 251 | // ... 252 | } 253 | }, 254 | { 255 | "type": "album", 256 | "id": "39", 257 | "attributes": { 258 | // ... 259 | "year": 2018, 260 | "month": 12, 261 | "day": 6, 262 | // ... 263 | } 264 | }, 265 | // ... 266 | ] 267 | } 268 | 269 | If not all resources in the collection have the attribute specified by the sort 270 | parameter, then the server **SHOULD** return only those resources with the 271 | attribute. For example, the request ``/aura/tracks?sort=composer`` should 272 | return only those tracks with a ``composer`` attribute. 273 | 274 | .. _JSON API sorting: https://jsonapi.org/format/#fetching-sorting 275 | 276 | Pagination 277 | '''''''''' 278 | 279 | Collection endpoints can return truncated results to avoid potential 280 | performance issues on both the client and the server. Pagination works using 281 | a *pagination token* that describes how to retrieve the next chunk 282 | of results. (In practice, the token could be the offset in the collection, the 283 | id of the next item to return, or a reference to a database cursor.) 284 | Truncation can be requested by the client or unilaterally imposed by the 285 | server. 286 | 287 | `Pagination`_ applies to the three collection endpoints (``/aura/tracks``, 288 | ``/aura/albums``, and ``/aura/artists``). 289 | A server **MAY** truncate its responses. If it does so, it **MUST** provide 290 | pagination information in the ``links`` object of its response. 291 | That object **MUST** have a ``next`` member with a URL to the next page if one 292 | is available---otherwise, the ``next`` member may be null or missing 293 | altogether. 294 | The URL for the next page **MUST** be the same as the original, except that 295 | the ``page`` request holds a different value. 296 | 297 | .. _Pagination: http://jsonapi.org/format/#fetching-pagination 298 | 299 | A pagination token is not guaranteed to be useful indefinitely. If a token 300 | expires, the server **MAY** respond to subsequent requests 301 | with the same token with an HTTP 410 "Gone" error. 302 | (This is critical for servers that retain state for each in-progress 303 | pagination sequence.) 304 | 305 | The client **MAY** include a ``limit`` parameter (an integer) with a 306 | collection ``GET`` request. The server **MUST** respond with *at most* that 307 | number of resources, although it may return fewer. (A ``next`` link must 308 | be supplied if there are more results, as above.) 309 | 310 | For example, a client could request a "page" of results with a single result: 311 | 312 | .. sourcecode:: http 313 | 314 | GET /aura/tracks?limit=1 315 | 316 | .. sourcecode:: http 317 | 318 | HTTP/1.1 200 OK 319 | Content-Type: application/vnd.api+json 320 | 321 | { 322 | "data": [ ... ], 323 | "links": { 324 | "next": "http://example.org/aura/tracks?limit=1&page=sometoken" 325 | } 326 | } 327 | 328 | The client can then issue another request for the next chunk: 329 | 330 | .. sourcecode:: http 331 | 332 | GET /aura/tracks?limit=1&page=sometoken 333 | 334 | .. sourcecode:: http 335 | 336 | HTTP/1.1 200 OK 337 | Content-Type: application/vnd.api+json 338 | 339 | { 340 | "data": [ ... ] 341 | } 342 | 343 | The absence of a ``links.next`` URL indicates that the sequence is finished 344 | (there are only two tracks in the library). 345 | 346 | 347 | Tracks 348 | ------ 349 | 350 | An AURA server **MUST** expose a collection of tracks (i.e., individual songs). 351 | Information about a track is provided in a track resource object, which is 352 | in the form of a JSON API `resource object`_. The top-level key ``type`` of all 353 | track resource objects **MUST** be the string ``"track"``. 354 | 355 | .. http:get:: /aura/tracks 356 | :synopsis: All tracks in the library. 357 | 358 | The collection of all tracks in the library. The reponse is a JSON object 359 | whose ``data`` key maps to an array of track resource objects. 360 | 361 | .. http:get:: /aura/tracks/(id) 362 | :synopsis: A specific track. 363 | 364 | An individual track resource. The response is a JSON object whose ``data`` 365 | key maps to a single track resource object. 366 | 367 | Required Attributes 368 | ''''''''''''''''''' 369 | 370 | Track resource objects **MUST** have these attributes: 371 | 372 | * ``title``, string: The song's name. 373 | * ``artist``, string: The recording artist. 374 | 375 | Optional Attributes 376 | ''''''''''''''''''' 377 | 378 | Tracks resource objects **MAY** have these attributes: 379 | 380 | * ``album``, string: The name of the release the track appears on. 381 | * ``track``, integer: The index of the track on its album. 382 | * ``tracktotal``, integer: The number of tracks on the album. 383 | * ``disc``, integer: The index of the medium in the album. 384 | * ``disctotal``, integer: The number of media in the album. 385 | * ``year``, integer: The year the track was released. 386 | * ``month``, integer: The release date's month. 387 | * ``day``, integer: The release date's day of the month. 388 | * ``bpm``, integer: Tempo, in beats per minute. 389 | * ``genre``, string: The track's musical genre. 390 | * ``recording-mbid``, string: A `MusicBrainz`_ recording id. 391 | * ``track-mbid``, string: A MusicBrainz track id. 392 | * ``composer``, string: The name of the music's composer. 393 | * ``albumartist``, string: The artist for the release the track appears 394 | on. 395 | * ``comments``, string: Free-form, user-specified information. 396 | 397 | These optional attributes reflect audio metadata: 398 | 399 | * ``mimetype``, string: The MIME type of the associated audio file. 400 | * ``duration``, float: The (approximate) length of the audio in seconds. 401 | * ``framerate``, integer: The number of frames per second in the audio. 402 | * ``framecount``, integer: The total number of frames in the audio. 403 | (The exact length can be calculated as the product of the frame rate and 404 | frame count.) 405 | * ``channels``, integer: The number of audio channels. (A frame consists of one 406 | sample per channel.) 407 | * ``bitrate``, integer: The number of bits per second in the encoding. 408 | * ``bitdepth``, integer: The number of bits per sample. 409 | * ``size``, integer: The size of the audio file in bytes. 410 | 411 | Support for multi-valued attributes like ``artists`` and ``genres`` may be 412 | specified in a future AURA extension. 413 | 414 | Relationships 415 | ''''''''''''' 416 | 417 | Track resources **MAY** have relationships to albums they appear on, their 418 | recording artists and any associated images using the ``albums``, ``artists`` 419 | and ``images`` fields respectively. These keys are also the valid values for 420 | the ``include`` parameter (see :ref:`relationships`). 421 | 422 | 423 | Albums 424 | ------ 425 | 426 | Album resources are optional. If a server supports artists, it **MUST** 427 | indicate the support by including the string ``"albums"`` in its ``features`` 428 | list (see :ref:`server-info`). If the server does not support albums, it 429 | **MUST** respond with an HTTP 404 error for all ``/aura/albums`` URLs. 430 | Information about an album is provided in an album resource object, which is 431 | in the form of a JSON API `resource object`_. The top-level key ``type`` of all 432 | album resource objects **MUST** be the string ``"album"``. 433 | 434 | 435 | .. http:get:: /aura/albums 436 | :synopsis: All albums in the library. 437 | 438 | The collection of all albums in the library. The response is a JSON 439 | object whose ``data`` key maps to an array of album resource objects. 440 | 441 | .. http:get:: /aura/albums/(id) 442 | :synopsis: A specific album. 443 | 444 | An individual album resource. The response is a JSON object whose ``data`` 445 | key maps to a single album resource object. 446 | 447 | Required Attributes 448 | ''''''''''''''''''' 449 | 450 | Album resource objects **MUST** have these attributes: 451 | 452 | * ``title``, string: The album's name. 453 | * ``artist``, string: The names of the artist responsible for the 454 | release (or another indicator such as "Various Artists" when no specific 455 | artist is relevant). 456 | 457 | Optional Attributes 458 | ''''''''''''''''''' 459 | 460 | Album resource objects **MAY** have these attributes: 461 | 462 | * ``tracktotal``, integer: The number of tracks on the album. 463 | * ``disctotal``, integer: The number of media in the album. 464 | * ``year``, integer: The year the album was released. 465 | * ``month``, integer: The release date's month. 466 | * ``day``, integer: The release date's day of the month. 467 | * ``genre``, string: The album's musical genres. 468 | * ``release-mbid``, string: A `MusicBrainz`_ release id. 469 | * ``release-group-mbid``, string: A MusicBrainz release group id. 470 | 471 | Support for multi-valued attributes like ``artists`` and ``genres`` may be 472 | specified in a future AURA extension. 473 | 474 | Relationships 475 | ''''''''''''' 476 | 477 | Album resources **MUST** link to their constituent tracks via the ``tracks`` 478 | field. They **MAY** also link their performing artists and associated images 479 | under the ``artists`` and ``images`` fields. These keys are also the valid 480 | values for the ``include`` parameter (see :ref:`relationships`). 481 | 482 | 483 | Artists 484 | ------- 485 | 486 | Artist resources are optional. If a server supports artists, it **MUST** 487 | indicate the support by including the string ``"artists"`` in its ``features`` 488 | list (see :ref:`server-info`). If the server does not support artists, it 489 | **MUST** respond with an HTTP 404 error for all ``/aura/artists`` URLs. 490 | Information about an artist is provided in an artist resource object, which 491 | is in the form of a JSON API `resource object`_. The top-level key ``type`` of 492 | all artist resource objects **MUST** be the string ``"artist"``. 493 | 494 | 495 | .. http:get:: /aura/artists 496 | :synopsis: All artists in the library. 497 | 498 | The collection of all artists in the library. The response is a JSON 499 | object whose ``data`` key maps to an array of artist resource objects. 500 | 501 | .. http:get:: /aura/artists/(id) 502 | :synopsis: A specific artist. 503 | 504 | An individual artist resource. The response is a JSON object whose ``data`` 505 | key maps to a single artist resource object. 506 | 507 | Required Attributes 508 | ''''''''''''''''''' 509 | 510 | Artist resource objects **MUST** have these attributes: 511 | 512 | * ``name``, string: The artist's name. 513 | 514 | Optional Attributes 515 | ''''''''''''''''''' 516 | 517 | Artist resource objects **MAY** have these attributes: 518 | 519 | * ``artist-mbid``, string: A `MusicBrainz`_ artist id. 520 | 521 | .. _musicbrainz: http://musicbrainz.org 522 | 523 | Relationships 524 | ''''''''''''' 525 | 526 | Artist resources **MUST** have relationships to their associated tracks under 527 | the ``tracks`` field. They **MAY** also link to their albums and associated 528 | images under the ``albums`` and ``images`` fields. These keys are also the 529 | valid values for the ``include`` parameter (see :ref:`relationships`). 530 | 531 | 532 | Images 533 | ------ 534 | 535 | Image resources are optional. If a server supports images, it **MUST** 536 | indicate the support by including the string ``"images"`` in its ``features`` 537 | list (see :ref:`server-info`). If the server does not support images, it 538 | **MUST** respond with an HTTP 404 error for all ``/aura/images`` URLs. 539 | Information about an image is provided in an image resource object, which 540 | is in the form of a JSON API `resource object`_. The top-level key ``type`` of 541 | all image resource objects **MUST** be the string ``"image"``. 542 | 543 | Images can be associated with tracks, albums, and artists. Most pertinently, 544 | albums may have associated cover art. 545 | 546 | In contrast to the other resource types, servers **SHOULD** respond with an 547 | HTTP 404 error for the URL ``/aura/images``. This is because enumerating all 548 | images may be difficult for the server, and a large collection of image 549 | metadata is not generally useful to music browsers and players. 550 | 551 | The flexible string nature of resources' ``id`` field can be used to easily 552 | give images globally unique ids. For example, ``"album-3-cover.jpg"`` could be 553 | used to identify the cover image of the album with id ``"3"``. This type of id 554 | may be useful if image information is not stored in a database. 555 | 556 | .. http:get:: /aura/images/(id) 557 | :synopsis: Metadata about a specific image. 558 | 559 | Get metadata about a specific image. The response is a JSON object where 560 | the ``data`` key maps to a single image resource object. 561 | 562 | .. http:get:: /aura/images/(id)/file 563 | :synopsis: Download an image file. 564 | 565 | Download an image file. The response's ``Content-Type`` header **MUST** 566 | indicate the mimetype of the image file returned. 567 | 568 | Required Attributes 569 | ''''''''''''''''''' 570 | 571 | Image resource objects have no required attributes. 572 | 573 | Optional Attributes 574 | ''''''''''''''''''' 575 | 576 | These fields on image resource objects are optional: 577 | 578 | * ``role``, string: A description of the image's purpose: "cover" for primary 579 | album art, etc. 580 | * ``mimetype``, string: The MIME type of the image. 581 | * ``width``, integer: The image's width in pixels. 582 | * ``height``, integer: The image's height in pixels. 583 | * ``size``, integer: The size of the image data in bytes. 584 | 585 | Relationships 586 | ''''''''''''' 587 | 588 | Images **MAY** have relationships to any associated tracks, albums or artists 589 | using the ``tracks``, ``albums`` and ``artists`` fields. These keys are also 590 | the valid values for the ``include`` parameter (see :ref:`relationships`). 591 | Each image resource **MUST** have at least one relationship. 592 | 593 | 594 | Audio 595 | ----- 596 | 597 | The server supplies audio files for each track. 598 | 599 | .. http:get:: /aura/tracks/(id)/audio 600 | :synopsis: Download the audio file for a track. 601 | 602 | Download the audio file for a track. 603 | 604 | The file is returned in an arbitrary audio file format. The server 605 | **MUST** set the ``Content-Type`` header to indicate the format. 606 | 607 | The server **SHOULD** use the HTTP `Content-Disposition`_ header to supply 608 | a filename. 609 | 610 | The server **SHOULD** support HTTP `range requests`_ to facilitate seeking 611 | in the file. 612 | 613 | Audio Formats and Quality 614 | ''''''''''''''''''''''''' 615 | 616 | The server can provide multiple encodings of the same audio---i.e., by 617 | transcoding the file. This can help when the client supports a limited range 618 | of audio codecs (e.g., in browser environments) and when bandwidth is limited 619 | (e.g., to avoid streaming lossless audio over a mobile connection). 620 | 621 | The server decides which version of the file to send using `HTTP content 622 | negotiation`_. Specifically, the client **MAY** specify the kinds of content 623 | it requests in the HTTP ``Accept`` header. The header is a comma-separated 624 | list of types, which consist of a MIME type and (optionally) some parameters. 625 | To request audio under a maximum bitrate, the client uses a ``bitrate`` 626 | parameter to specify the maximum bits per second it is willing to accept. 627 | 628 | For example, the header ``Accept: audio/ogg, audio/mpeg`` requests audio in 629 | either MP3 or `Ogg`_ (Vorbis, Opus, etc.) format with no quality constraints. 630 | Similarly, ``Accept: audio/ogg;bitrate=128000`` requests Ogg audio at a bitrate 631 | of 128kbps or lower. 632 | 633 | The server **SHOULD** respond with one of the requested types or a 406 Not 634 | Acceptable status (i.e., if it does not support transcoding). An omitted 635 | ``Accept`` header is considered equivalent to ``audio/*``. 636 | 637 | .. _range requests: https://tools.ietf.org/html/rfc7233 638 | .. _HTTP content negotiation: https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation#The_Accept.3a_header 639 | .. _Content-Disposition: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1 640 | .. _Ogg: https://wiki.xiph.org/Ogg 641 | --------------------------------------------------------------------------------