Web Plugin¶
The web
plugin is a very basic alternative interface to beets that
supplements the CLI. It can't do much right now, and the interface is a little
clunky, but you can use it to query and browse your music and---in browsers that
support HTML5 Audio---you can even play music.
While it's not meant to replace the CLI, a graphical interface has a number of advantages in certain situations. For example, when editing a tag, a natural CLI makes you retype the whole thing---common GUI conventions can be used to just edit the part of the tag you want to change. A graphical interface could also drastically increase the number of people who can use beets.
Install¶
The Web interface depends on Flask. To get it, just run pip install
flask
. Then enable the web
plugin in your configuration (see
Using Plugins).
If you need CORS (it's disabled by default---see Cross-Origin Resource Sharing (CORS), below), then
you also need flask-cors. Just type pip install flask-cors
.
Run the Server¶
Then just type beet web
to start the server and go to
http://localhost:8337/. This is what it looks like:

You can also specify the hostname and port number used by the Web server. These
can be specified on the command line or in the [web]
section of your
configuration file.
On the command line, use beet web [HOSTNAME] [PORT]
. Or the configuration
options below.
Usage¶
Type queries into the little search box. Double-click a track to play it with HTML5 Audio.
Configuration¶
To configure the plugin, make a web:
section in your
configuration file. The available options are:
- host: The server hostname. Set this to 0.0.0.0 to bind to all interfaces. Default: Bind to 127.0.0.1.
- port: The server port. Default: 8337.
- cors: The CORS allowed origin (see Cross-Origin Resource Sharing (CORS), below). Default: CORS is disabled.
- cors_supports_credentials: Support credentials when using CORS (see Cross-Origin Resource Sharing (CORS), below). Default: CORS_SUPPORTS_CREDENTIALS is disabled.
- reverse_proxy: If true, enable reverse proxy support (see Reverse Proxy Support, below). Default: false.
- include_paths: If true, includes paths in item objects. Default: false.
Implementation¶
The Web backend is built using a simple REST+JSON API with the excellent Flask library. The frontend is a single-page application written with Backbone.js. This allows future non-Web clients to use the same backend API.
Eventually, to make the Web player really viable, we should use a Flash fallback for unsupported formats/browsers. There are a number of options for this:
Cross-Origin Resource Sharing (CORS)¶
The web
plugin's API can be used as a backend for an in-browser client. By
default, browsers will only allow access from clients running on the same
server as the API. (You will get an arcane error about XMLHttpRequest
otherwise.) A technology called CORS lets you relax this restriction.
If you want to use an in-browser client hosted elsewhere (or running from a
different server on your machine), first install the flask-cors plugin by
typing pip install flask-cors
. Then set the cors
configuration option to
the "origin" (protocol, host, and optional port number) where the client is
served. Or set it to '*'
to enable access from all origins. Note that there
are security implications if you set the origin to '*'
, so please research
this before using it.
If the web
server is behind a proxy that uses credentials, you might want
to set the cors_supports_credentials
configuration option to true to let
in-browser clients log in.
For example:
web:
host: 0.0.0.0
cors: 'http://example.com'
Reverse Proxy Support¶
When the server is running behind a reverse proxy, you can tell the plugin to
respect forwarded headers. Specifically, this can help when you host the
plugin at a base URL other than the root /
or when you use the proxy to
handle secure connections. Enable the reverse_proxy
configuration option
if you do this.
Technically, this option lets the proxy provide X-Script-Name
and
X-Scheme
HTTP headers to control the plugin's the SCRIPT_NAME
and its
wsgi.url_scheme
parameter.
Here's a sample Nginx configuration that serves the web plugin under the /beets directory:
location /beets {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Script-Name /beets;
}
JSON API¶
GET /item/
¶
Responds with a list of all tracks in the beets library.
{
"items": [
{
"id": 6,
"title": "A Song",
...
}, {
"id": 12,
"title": "Another Song",
...
}
...
]
}
GET /item/6
¶
Looks for an item with id 6 in the beets library and responds with its JSON representation.
{
"id": 6,
"title": "A Song",
...
}
If there is no item with that id responds with a 404 status code.
GET /item/6,12,13
¶
Response with a list of tracks with the ids 6, 12 and 13. The format of the response is the same as for GET /item/. It is not guaranteed that the response includes all the items requested. If a track is not found it is silently dropped from the response.
GET /item/path/...
¶
Look for an item at the given absolute path on the server. If it corresponds to
a track, return the track in the same format as /item/*
.
If the server runs UNIX, you'll need to include an extra leading slash:
http://localhost:8337/item/path//Users/beets/Music/Foo/Bar/Baz.mp3
GET /item/query/querystring
¶
Returns a list of tracks matching the query. The querystring must be a valid query as described in Queries.
{
"results": [
{ "id" : 6, "title": "A Song" },
{ "id" : 12, "title": "Another Song" }
]
}
GET /item/6/file
¶
Sends the media file for the track. If the item or its corresponding file do not exist a 404 status code is returned.
Albums¶
For albums, the following endpoints are provided:
GET /album/
GET /album/5
GET /album/5,7
GET /album/query/querystring
The interface and response format is similar to the item API, except replacing
the encapsulation key "items"
with "albums"
when requesting /album/
or /album/5,7
. In addition we can request the cover art of an album with
GET /album/5/art
.
You can also add the '?expand' flag to get the individual items of an album.
GET /stats
¶
Responds with the number of tracks and albums in the database.
{
"items": 5,
"albums": 3
}