diff --git a/README.rst b/README.rst
index b572cdab..f667b7db 100644
--- a/README.rst
+++ b/README.rst
@@ -2,18 +2,16 @@
Mopidy
******
-.. image:: https://secure.travis-ci.org/mopidy/mopidy.png?branch=develop
+Mopidy is a music server which can play music both from multiple sources, like
+your local hard drive, radio streams, and from Spotify and SoundCloud. Searches
+combines results from all music sources, and you can mix tracks from all
+sources in your play queue. Your playlists from Spotify or SoundCloud are also
+available for use.
-Mopidy is a music server which can play music both from your local hard drive
-and from Spotify. Searches returns results from both your local hard drive and
-from Spotify, and you can mix tracks from both sources in your play queue. Your
-Spotify playlists are also available for use, though we don't support modifying
-them yet.
-
-To control your music server, you can use the Ubuntu Sound Menu on the machine
-running Mopidy, any device on the same network which can control UPnP
-MediaRenderers, or any MPD client. MPD clients are available for most
-platforms, including Windows, Mac OS X, Linux, Android and iOS.
+To control your Mopidy music server, you can use one of Mopidy's web clients,
+the Ubuntu Sound Menu, any device on the same network which can control UPnP
+MediaRenderers, or any MPD client. MPD clients are available for many
+platforms, including Windows, OS X, Linux, Android and iOS.
To get started with Mopidy, check out `the docs `_.
@@ -21,6 +19,10 @@ To get started with Mopidy, check out `the docs `_.
- `Source code `_
- `Issue tracker `_
- `CI server `_
+- `Download development snapshot `_
+
- IRC: ``#mopidy`` at `irc.freenode.net `_
- Mailing list: `mopidy@googlegroups.com `_
-- `Download development snapshot `_
+- Twitter: `@mopidy `_
+
+.. image:: https://secure.travis-ci.org/mopidy/mopidy.png?branch=develop
diff --git a/docs/api/frontends.rst b/docs/api/frontends.rst
index 58436c03..6da5d337 100644
--- a/docs/api/frontends.rst
+++ b/docs/api/frontends.rst
@@ -13,9 +13,12 @@ The following requirements applies to any frontend implementation:
`_ actor, called the "main actor" from here
on.
-- The main actor MUST accept a constructor argument ``core``, which will be an
- :class:`ActorProxy ` for the core actor. This object
- gives access to the full :ref:`core-api`.
+- The main actor MUST accept two constructor arguments:
+
+ - ``config``, which is a dict structure with the entire Mopidy configuration.
+
+ - ``core``, which will be an :class:`ActorProxy ` for
+ the core actor. This object gives access to the full :ref:`core-api`.
- It MAY use additional actors to implement whatever it does, and using actors
in frontend implementations is encouraged.
diff --git a/docs/api/http.rst b/docs/api/http.rst
new file mode 100644
index 00000000..16546683
--- /dev/null
+++ b/docs/api/http.rst
@@ -0,0 +1,439 @@
+.. _http-api:
+
+********
+HTTP API
+********
+
+The :ref:`ext-http` extension makes Mopidy's :ref:`core-api` available over
+HTTP using WebSockets. We also provide a JavaScript wrapper, called
+:ref:`Mopidy.js ` around the HTTP API for use both from browsers and
+Node.js.
+
+.. warning:: API stability
+
+ Since the HTTP API exposes our internal core API directly it is to be
+ regarded as **experimental**. We cannot promise to keep any form of
+ backwards compatibility between releases as we will need to change the core
+ API while working out how to support new use cases. Thus, if you use this
+ API, you must expect to do small adjustments to your client for every
+ release of Mopidy.
+
+ From Mopidy 1.0 and onwards, we intend to keep the core API far more
+ stable.
+
+
+.. _websocket-api:
+
+WebSocket API
+=============
+
+The web server exposes a WebSocket at ``/mopidy/ws/``. The WebSocket gives you
+access to Mopidy's full API and enables Mopidy to instantly push events to the
+client, as they happen.
+
+On the WebSocket we send two different kind of messages: The client can send
+JSON-RPC 2.0 requests, and the server will respond with JSON-RPC 2.0 responses.
+In addition, the server will send event messages when something happens on the
+server. Both message types are encoded as JSON objects.
+
+
+Event messages
+--------------
+
+Event objects will always have a key named ``event`` whose value is the event
+type. Depending on the event type, the event may include additional fields for
+related data. The events maps directly to the :class:`mopidy.core.CoreListener`
+API. Refer to the ``CoreListener`` method names is the available event types.
+The ``CoreListener`` method's keyword arguments are all included as extra
+fields on the event objects. Example event message::
+
+ {"event": "track_playback_started", "track": {...}}
+
+
+JSON-RPC 2.0 messaging
+----------------------
+
+JSON-RPC 2.0 messages can be recognized by checking for the key named
+``jsonrpc`` with the string value ``2.0``. For details on the messaging format,
+please refer to the `JSON-RPC 2.0 spec
+`_.
+
+All methods (not attributes) in the :ref:`core-api` is made available through
+JSON-RPC calls over the WebSocket. For example,
+:meth:`mopidy.core.PlaybackController.play` is available as the JSON-RPC method
+``core.playback.play``.
+
+The core API's attributes is made available through setters and getters. For
+example, the attribute :attr:`mopidy.core.PlaybackController.current_track` is
+available as the JSON-RPC method ``core.playback.get_current_track``.
+
+Example JSON-RPC request::
+
+ {"jsonrpc": "2.0", "id": 1, "method": "core.playback.get_current_track"}
+
+Example JSON-RPC response::
+
+ {"jsonrpc": "2.0", "id": 1, "result": {"__model__": "Track", "...": "..."}}
+
+The JSON-RPC method ``core.describe`` returns a data structure describing all
+available methods. If you're unsure how the core API maps to JSON-RPC, having a
+look at the ``core.describe`` response can be helpful.
+
+
+.. _mopidy-js:
+
+Mopidy.js JavaScript library
+============================
+
+We've made a JavaScript library, Mopidy.js, which wraps the WebSocket and gets
+you quickly started with working on your client instead of figuring out how to
+communicate with Mopidy.
+
+
+Getting the library for browser use
+-----------------------------------
+
+Regular and minified versions of Mopidy.js, ready for use, is installed
+together with Mopidy. When the HTTP extension is enabled, the files are
+available at:
+
+- http://localhost:6680/mopidy/mopidy.js
+- http://localhost:6680/mopidy/mopidy.min.js
+
+You may need to adjust hostname and port for your local setup.
+
+Thus, if you use Mopidy to host your web client, like described above, you can
+load the latest version of Mopidy.js by adding the following script tag to your
+HTML file:
+
+.. code-block:: html
+
+
+
+If you don't use Mopidy to host your web client, you can find the JS files in
+the Git repo at:
+
+- ``mopidy/frontends/http/data/mopidy.js``
+- ``mopidy/frontends/http/data/mopidy.min.js``
+
+
+Getting the library for Node.js use
+-----------------------------------
+
+If you want to use Mopidy.js from Node.js instead of a browser, you can install
+Mopidy.js using npm::
+
+ npm install mopidy
+
+After npm completes, you can import Mopidy.js using ``require()``:
+
+.. code-block:: js
+
+ var Mopidy = require("mopidy").Mopidy;
+
+
+Getting the library for development on the library
+--------------------------------------------------
+
+If you want to work on the Mopidy.js library itself, you'll find a complete
+development setup in the ``js/`` dir in our repo. The instructions in
+``js/README.md`` will guide you on your way.
+
+
+Creating an instance
+--------------------
+
+Once you got Mopidy.js loaded, you need to create an instance of the wrapper:
+
+.. code-block:: js
+
+ var mopidy = new Mopidy();
+
+When you instantiate ``Mopidy()`` without arguments, it will connect to
+the WebSocket at ``/mopidy/ws/`` on the current host. Thus, if you don't host
+your web client using Mopidy's web server, or if you use Mopidy.js from a
+Node.js environment, you'll need to pass the URL to the WebSocket end point:
+
+.. code-block:: js
+
+ var mopidy = new Mopidy({
+ webSocketUrl: "ws://localhost:6680/mopidy/ws/"
+ });
+
+It is also possible to create an instance first and connect to the WebSocket
+later:
+
+.. code-block:: js
+
+ var mopidy = new Mopidy({autoConnect: false});
+ // ... do other stuff, like hooking up events ...
+ mopidy.connect();
+
+
+Hooking up to events
+--------------------
+
+Once you have a Mopidy.js object, you can hook up to the events it emits. To
+explore your possibilities, it can be useful to subscribe to all events and log
+them:
+
+.. code-block:: js
+
+ mopidy.on(console.log.bind(console));
+
+Several types of events are emitted:
+
+- You can get notified about when the Mopidy.js object is connected to the
+ server and ready for method calls, when it's offline, and when it's trying to
+ reconnect to the server by looking at the events ``state:online``,
+ ``state:offline``, ``reconnectionPending``, and ``reconnecting``.
+
+- You can get events sent from the Mopidy server by looking at the events with
+ the name prefix ``event:``, like ``event:trackPlaybackStarted``.
+
+- You can introspect what happens internally on the WebSocket by looking at the
+ events emitted with the name prefix ``websocket:``.
+
+Mopidy.js uses the event emitter library `BANE
+`_, so you should refer to BANE's
+short API documentation to see how you can hook up your listeners to the
+different events.
+
+
+Calling core API methods
+------------------------
+
+Once your Mopidy.js object has connected to the Mopidy server and emits the
+``state:online`` event, it is ready to accept core API method calls:
+
+.. code-block:: js
+
+ mopidy.on("state:online", function () {
+ mopidy.playback.next();
+ });
+
+Any calls you make before the ``state:online`` event is emitted will fail. If
+you've hooked up an errback (more on that a bit later) to the promise returned
+from the call, the errback will be called with an error message.
+
+All methods in Mopidy's :ref:`core-api` is available via Mopidy.js. The core
+API attributes is *not* available, but that shouldn't be a problem as we've
+added (undocumented) getters and setters for all of them, so you can access the
+attributes as well from JavaScript.
+
+Both the WebSocket API and the JavaScript API are based on introspection of the
+core Python API. Thus, they will always be up to date and immediately reflect
+any changes we do to the core API.
+
+The best way to explore the JavaScript API, is probably by opening your
+browser's console, and using its tab completion to navigate the API. You'll
+find the Mopidy core API exposed under ``mopidy.playback``,
+``mopidy.tracklist``, ``mopidy.playlists``, and ``mopidy.library``.
+
+All methods in the JavaScript API have an associated data structure describing
+the Python params it expects, and most methods also have the Python API
+documentation available. This is available right there in the browser console,
+by looking at the method's ``description`` and ``params`` attributes:
+
+.. code-block:: js
+
+ console.log(mopidy.playback.next.params);
+ console.log(mopidy.playback.next.description);
+
+JSON-RPC 2.0 limits method parameters to be sent *either* by-position or
+by-name. Combinations of both, like we're used to from Python, isn't supported
+by JSON-RPC 2.0. To further limit this, Mopidy.js currently only supports
+passing parameters by-position.
+
+Obviously, you'll want to get a return value from many of your method calls.
+Since everything is happening across the WebSocket and maybe even across the
+network, you'll get the results asynchronously. Instead of having to pass
+callbacks and errbacks to every method you call, the methods return "promise"
+objects, which you can use to pipe the future result as input to another
+method, or to hook up callback and errback functions.
+
+.. code-block:: js
+
+ var track = mopidy.playback.getCurrentTrack();
+ // => ``track`` isn't a track, but a "promise" object
+
+Instead, typical usage will look like this:
+
+.. code-block:: js
+
+ var printCurrentTrack = function (track) {
+ if (track) {
+ console.log("Currently playing:", track.name, "by",
+ track.artists[0].name, "from", track.album.name);
+ } else {
+ console.log("No current track");
+ }
+ };
+
+ mopidy.playback.getCurrentTrack().then(
+ printCurrentTrack, console.error.bind(console));
+
+The first function passed to ``then()``, ``printCurrentTrack``, is the callback
+that will be called if the method call succeeds. The second function,
+``console.error``, is the errback that will be called if anything goes wrong.
+If you don't hook up an errback, debugging will be hard as errors will silently
+go missing.
+
+For debugging, you may be interested in errors from function without
+interesting return values as well. In that case, you can pass ``null`` as the
+callback:
+
+.. code-block:: js
+
+ mopidy.playback.next().then(null, console.error.bind(console));
+
+The promise objects returned by Mopidy.js adheres to the `CommonJS Promises/A
+`_ standard. We use the
+implementation known as `when.js `_. Please
+refer to when.js' documentation or the standard for further details on how to
+work with promise objects.
+
+
+Cleaning up
+-----------
+
+If you for some reason want to clean up after Mopidy.js before the web page is
+closed or navigated away from, you can close the WebSocket, unregister all
+event listeners, and delete the object like this:
+
+.. code-block:: js
+
+ // Close the WebSocket without reconnecting. Letting the object be garbage
+ // collected will have the same effect, so this isn't strictly necessary.
+ mopidy.close();
+
+ // Unregister all event listeners. If you don't do this, you may have
+ // lingering references to the object causing the garbage collector to not
+ // clean up after it.
+ mopidy.off();
+
+ // Delete your reference to the object, so it can be garbage collected.
+ mopidy = null;
+
+
+Example to get started with
+---------------------------
+
+1. Make sure that you've installed all dependencies required by
+ :ref:`ext-http`.
+
+2. Create an empty directory for your web client.
+
+3. Change the :confval:`http/static_dir` config value to point to your new
+ directory.
+
+4. Start/restart Mopidy.
+
+5. Create a file in the directory named ``index.html`` containing e.g. "Hello,
+ world!".
+
+6. Visit http://localhost:6680/ to confirm that you can view your new HTML file
+ there.
+
+7. Include Mopidy.js in your web page:
+
+ .. code-block:: html
+
+
+
+8. Add one of the following Mopidy.js examples of how to queue and start
+ playback of your first playlist either to your web page or a JavaScript file
+ that you include in your web page.
+
+ "Imperative" style:
+
+ .. code-block:: js
+
+ var consoleError = console.error.bind(console);
+
+ var trackDesc = function (track) {
+ return track.name + " by " + track.artists[0].name +
+ " from " + track.album.name;
+ };
+
+ var queueAndPlayFirstPlaylist = function () {
+ mopidy.playlists.getPlaylists().then(function (playlists) {
+ var playlist = playlists[0];
+ console.log("Loading playlist:", playlist.name);
+ mopidy.tracklist.add(playlist.tracks).then(function (tlTracks) {
+ mopidy.playback.play(tlTracks[0]).then(function () {
+ mopidy.playback.getCurrentTrack().then(function (track) {
+ console.log("Now playing:", trackDesc(track));
+ }, consoleError);
+ }, consoleError);
+ }, consoleError);
+ }, consoleError);
+ };
+
+ var mopidy = new Mopidy(); // Connect to server
+ mopidy.on(console.log.bind(console)); // Log all events
+ mopidy.on("state:online", queueAndPlayFirstPlaylist);
+
+ Approximately the same behavior in a more functional style, using chaining
+ of promisies.
+
+ .. code-block:: js
+
+ var consoleError = console.error.bind(console);
+
+ var getFirst = function (list) {
+ return list[0];
+ };
+
+ var extractTracks = function (playlist) {
+ return playlist.tracks;
+ };
+
+ var printTypeAndName = function (model) {
+ console.log(model.__model__ + ": " + model.name);
+ // By returning the playlist, this function can be inserted
+ // anywhere a model with a name is piped in the chain.
+ return model;
+ };
+
+ var trackDesc = function (track) {
+ return track.name + " by " + track.artists[0].name +
+ " from " + track.album.name;
+ };
+
+ var printNowPlaying = function () {
+ // By returning any arguments we get, the function can be inserted
+ // anywhere in the chain.
+ var args = arguments;
+ return mopidy.playback.getCurrentTrack().then(function (track) {
+ console.log("Now playing:", trackDesc(track));
+ return args;
+ });
+ };
+
+ var queueAndPlayFirstPlaylist = function () {
+ mopidy.playlists.getPlaylists()
+ // => list of Playlists
+ .then(getFirst, consoleError)
+ // => Playlist
+ .then(printTypeAndName, consoleError)
+ // => Playlist
+ .then(extractTracks, consoleError)
+ // => list of Tracks
+ .then(mopidy.tracklist.add, consoleError)
+ // => list of TlTracks
+ .then(getFirst, consoleError)
+ // => TlTrack
+ .then(mopidy.playback.play, consoleError)
+ // => null
+ .then(printNowPlaying, consoleError);
+ };
+
+ var mopidy = new Mopidy(); // Connect to server
+ mopidy.on(console.log.bind(console)); // Log all events
+ mopidy.on("state:online", queueAndPlayFirstPlaylist);
+
+9. The web page should now queue and play your first playlist every time your
+ load it. See the browser's console for output from the function, any errors,
+ and all events that are emitted.
+
diff --git a/docs/api/index.rst b/docs/api/index.rst
index 5a210812..6ba44999 100644
--- a/docs/api/index.rst
+++ b/docs/api/index.rst
@@ -11,3 +11,4 @@ API reference
core
audio
frontends
+ http
diff --git a/docs/authors.rst b/docs/authors.rst
index 97a2dd2b..c740a160 100644
--- a/docs/authors.rst
+++ b/docs/authors.rst
@@ -6,11 +6,7 @@ Contributors to Mopidy in the order of appearance:
.. include:: ../AUTHORS
-
-Showing your appreciation
-=========================
-
If you already enjoy Mopidy, or don't enjoy it and want to help us making
Mopidy better, the best way to do so is to contribute back to the community.
You can contribute code, documentation, tests, bug reports, or help other
-users, spreading the word, etc.
+users, spreading the word, etc. See :ref:`contributing` for a head start.
diff --git a/docs/changes.rst b/docs/changelog.rst
similarity index 99%
rename from docs/changes.rst
rename to docs/changelog.rst
index 2bff6c67..ab97bf08 100644
--- a/docs/changes.rst
+++ b/docs/changelog.rst
@@ -1,8 +1,8 @@
-*******
-Changes
-*******
+*********
+Changelog
+*********
-This change log is used to track all major changes to Mopidy.
+This changelog is used to track all major changes to Mopidy.
v0.14.0 (UNRELEASED)
====================
@@ -333,7 +333,7 @@ We've added an HTTP frontend for those wanting to build web clients for Mopidy!
**HTTP frontend**
- Added new optional HTTP frontend which exposes Mopidy's core API through
- JSON-RPC 2.0 messages over a WebSocket. See :ref:`http-frontend` for further
+ JSON-RPC 2.0 messages over a WebSocket. See :ref:`http-api` for further
details.
- Added a JavaScript library, Mopidy.js, to make it easier to develop web based
diff --git a/docs/clients/http.rst b/docs/clients/http.rst
index 5381eaff..d67dbb7b 100644
--- a/docs/clients/http.rst
+++ b/docs/clients/http.rst
@@ -4,14 +4,14 @@
HTTP clients
************
-Mopidy added an :ref:`HTTP frontend ` in 0.10 which provides the
+Mopidy added an :ref:`HTTP frontend ` in 0.10 which provides the
building blocks needed for creating web clients for Mopidy with the help of a
WebSocket and a JavaScript library provided by Mopidy.
This page will list any HTTP/web Mopidy clients. If you've created one, please
notify us so we can include your client on this page.
-See :ref:`http-frontend` for details on how to build your own web client.
+See :ref:`http-api` for details on how to build your own web client.
woutervanwijk/Mopidy-Webclient
diff --git a/docs/clients/mpris.rst b/docs/clients/mpris.rst
index 28da63ed..141a2371 100644
--- a/docs/clients/mpris.rst
+++ b/docs/clients/mpris.rst
@@ -8,9 +8,9 @@ MPRIS clients
Specification. It's a spec that describes a standard D-Bus interface for making
media players available to other applications on the same system.
-Mopidy's :ref:`MPRIS frontend ` currently implements all
-required parts of the MPRIS spec, plus the optional playlist interface. It does
-not implement the optional tracklist interface.
+Mopidy's :ref:`MPRIS frontend ` currently implements all required
+parts of the MPRIS spec, plus the optional playlist interface. It does not
+implement the optional tracklist interface.
.. _ubuntu-sound-menu:
diff --git a/docs/clients/upnp.rst b/docs/clients/upnp.rst
index 567fb04f..c90227e2 100644
--- a/docs/clients/upnp.rst
+++ b/docs/clients/upnp.rst
@@ -37,18 +37,18 @@ How to make Mopidy available as an UPnP MediaRenderer
With the help of `the Rygel project `_ Mopidy can
be made available as an UPnP MediaRenderer. Rygel will interface with Mopidy's
-:ref:`MPRIS frontend `, and make Mopidy available as a
-MediaRenderer on the local network. Since this depends on the MPRIS frontend,
-which again depends on D-Bus being available, this will only work on Linux, and
-not OS X. MPRIS/D-Bus is only available to other applications on the same host,
-so Rygel must be running on the same machine as Mopidy.
+:ref:`MPRIS frontend `, and make Mopidy available as a MediaRenderer
+on the local network. Since this depends on the MPRIS frontend, which again
+depends on D-Bus being available, this will only work on Linux, and not OS X.
+MPRIS/D-Bus is only available to other applications on the same host, so Rygel
+must be running on the same machine as Mopidy.
-1. Start Mopidy and make sure the :ref:`MPRIS frontend ` is
- working. It is activated by default, but you may miss dependencies or be
- using OS X, in which case it will not work. Check the console output when
- Mopidy is started for any errors related to the MPRIS frontend. If you're
- unsure it is working, there are instructions for how to test it on the
- :ref:`MPRIS frontend ` page.
+1. Start Mopidy and make sure the :ref:`MPRIS frontend ` is working.
+ It is activated by default, but you may miss dependencies or be using OS X,
+ in which case it will not work. Check the console output when Mopidy is
+ started for any errors related to the MPRIS frontend. If you're unsure it is
+ working, there are instructions for how to test it on the :ref:`MPRIS
+ frontend ` page.
2. Install Rygel. On Debian/Ubuntu::
diff --git a/docs/codestyle.rst b/docs/codestyle.rst
new file mode 100644
index 00000000..4b6e7448
--- /dev/null
+++ b/docs/codestyle.rst
@@ -0,0 +1,65 @@
+.. _codestyle:
+
+**********
+Code style
+**********
+
+- Always import ``unicode_literals`` and use unicode literals for everything
+ except where you're explicitly working with bytes, which are marked with the
+ ``b`` prefix.
+
+ Do this::
+
+ from __future__ import unicode_literals
+
+ foo = 'I am a unicode string, which is a sane default'
+ bar = b'I am a bytestring'
+
+ Not this::
+
+ foo = u'I am a unicode string'
+ bar = 'I am a bytestring, but was it intentional?'
+
+- Follow :pep:`8` unless otherwise noted. `flake8
+ `_ should be used to check your code
+ against the guidelines.
+
+- Use four spaces for indentation, *never* tabs.
+
+- Use CamelCase with initial caps for class names::
+
+ ClassNameWithCamelCase
+
+- Use underscore to split variable, function and method names for
+ readability. Don't use CamelCase.
+
+ ::
+
+ lower_case_with_underscores
+
+- Use the fact that empty strings, lists and tuples are :class:`False` and
+ don't compare boolean values using ``==`` and ``!=``.
+
+- Follow whitespace rules as described in :pep:`8`. Good examples::
+
+ spam(ham[1], {eggs: 2})
+ spam(1)
+ dict['key'] = list[index]
+
+- Limit lines to 80 characters and avoid trailing whitespace. However note that
+ wrapped lines should be *one* indentation level in from level above, except
+ for ``if``, ``for``, ``with``, and ``while`` lines which should have two
+ levels of indentation::
+
+ if (foo and bar ...
+ baz and foobar):
+ a = 1
+
+ from foobar import (foo, bar, ...
+ baz)
+
+- For consistency, prefer ``'`` over ``"`` for strings, unless the string
+ contains ``'``.
+
+- Take a look at :pep:`20` for a nice peek into a general mindset useful for
+ Python coding.
diff --git a/docs/config.rst b/docs/config.rst
index cd75e6dc..07ebffc2 100644
--- a/docs/config.rst
+++ b/docs/config.rst
@@ -2,28 +2,9 @@
Configuration
*************
-Mopidy has quite a few config values to tweak. Luckily, you only need to change
-a few, and stay ignorant of the rest. Below you can find guides for typical
-configuration changes you may want to do, and a listing of the available config
-values.
-
-
-Changing configuration
-======================
-
-Mopidy primarily reads config from the file ``~/.config/mopidy/mopidy.conf``,
-where ``~`` means your *home directory*. If your username is ``alice`` and you
-are running Linux, the settings file should probably be at
-``/home/alice/.config/mopidy/mopidy.conf``.
-
-You can either create the configuration file yourself, or run the ``mopidy``
-command, and it will create an empty settings file for you.
-
-When you have created the configuration file, open it in a text editor, and add
-settings you want to change. If you want to keep the default value for a
-setting, you should *not* redefine it in your own settings file.
-
-A complete ``~/.config/mopidy/mopidy.conf`` may look as simple as this:
+Mopidy has a lot of config values you can tweak, but you only need to change a
+few to get up and running. A complete ``~/.config/mopidy/mopidy.conf`` may be
+as simple as this:
.. code-block:: ini
@@ -34,127 +15,117 @@ A complete ``~/.config/mopidy/mopidy.conf`` may look as simple as this:
username = alice
password = mysecret
+Mopidy primarily reads config from the file ``~/.config/mopidy/mopidy.conf``,
+where ``~`` means your *home directory*. If your username is ``alice`` and you
+are running Linux, the settings file should probably be at
+``/home/alice/.config/mopidy/mopidy.conf``. You can either create the
+configuration file yourself, or run the ``mopidy`` command, and it will create
+an empty settings file for you and print what config values must be set
+to successfully start Mopidy.
-.. _music-from-spotify:
+When you have created the configuration file, open it in a text editor, and add
+the config values you want to change. If you want to keep the default for a
+config value, you **should not** add it to ``~/.config/mopidy/mopidy.conf``.
-Music from Spotify
-==================
+To see what's the effective configuration for your Mopidy installation, you can
+run ``mopidy --show-config``. It will print your full effective config with
+passwords masked out so that you safely can share the output with others for
+debugging.
-If you are using the Spotify backend, which is the default, enter your Spotify
-Premium account's username and password into the file, like this:
-
-.. code-block:: ini
-
- [spotify]
- username = myusername
- password = mysecret
-
-This will only work if you have the Spotify Premium subscription. Spotify
-Unlimited will not work.
+You can find a description of all config values belonging to Mopidy's core
+below, together with their default values. In addition, all :ref:`extensions
+` got additional config values. The extension's config values and config
+defaults are documented on the :ref:`extension pages `.
-.. _music-from-local-storage:
+Default core configuration
+==========================
-Music from local storage
-========================
-
-If you want use Mopidy to play music you have locally at your machine instead
-of or in addition to using Spotify, you need to review and maybe change some of
-the local backend config values. See :ref:`local-backend`, for a complete list.
-Then you need to generate a tag cache for your local music...
+.. literalinclude:: ../mopidy/default.conf
+ :language: ini
-.. _generating-a-tag-cache:
-
-Generating a tag cache
-----------------------
-
-The program :command:`mopidy-scan` will scan the path set in the
-:confval:`local/media_dir` config value for any media files and build a MPD
-compatible ``tag_cache``.
-
-To make a ``tag_cache`` of your local music available for Mopidy:
-
-#. Ensure that the :confval:`local/media_dir` config value points to where your
- music is located. Check the current setting by running::
-
- mopidy --show-config
-
-#. Scan your media library. The command outputs the ``tag_cache`` to
- standard output, which means that you will need to redirect the output to a
- file yourself::
-
- mopidy-scan > tag_cache
-
-#. Move the ``tag_cache`` file to the location
- set in the :confval:`local/tag_cache_file` config value, or change the
- config value to point to where your ``tag_cache`` file is.
-
-#. Start Mopidy, find the music library in a client, and play some local music!
-
-
-.. _use-mpd-on-a-network:
-
-Connecting from other machines on the network
-=============================================
-
-As a secure default, Mopidy only accepts connections from ``localhost``. If you
-want to open it for connections from other machines on your network, see
-the documentation for the :confval:`mpd/hostname` config value.
-
-If you open up Mopidy for your local network, you should consider turning on
-MPD password authentication by setting the :confval:`mpd/password` config value
-to the password you want to use. If the password is set, Mopidy will require
-MPD clients to provide the password before they can do anything else. Mopidy
-only supports a single password, and do not support different permission
-schemes like the original MPD server.
-
-
-Scrobbling tracks to Last.fm
-============================
-
-If you want to submit the tracks you are playing to your `Last.fm
-`_ profile, make sure you've installed the dependencies
-found at :mod:`mopidy.frontends.scrobbler` and add the following to your
-settings file:
-
-.. code-block:: ini
-
- [scrobbler]
- username = myusername
- password = mysecret
-
-
-.. _install-desktop-file:
-
-Controlling Mopidy through the Ubuntu Sound Menu
-================================================
-
-If you are running Ubuntu and installed Mopidy using the Debian package from
-APT you should be able to control Mopidy through the `Ubuntu Sound Menu
-`_ without any changes.
-
-If you installed Mopidy in any other way and want to control Mopidy through the
-Ubuntu Sound Menu, you must install the ``mopidy.desktop`` file which can be
-found in the ``data/`` dir of the Mopidy source into the
-``/usr/share/applications`` dir by hand::
-
- cd /path/to/mopidy/source
- sudo cp data/mopidy.desktop /usr/share/applications/
-
-After you have installed the file, start Mopidy in any way, and Mopidy should
-appear in the Ubuntu Sound Menu. When you quit Mopidy, it will still be listed
-in the Ubuntu Sound Menu, and may be restarted by selecting it there.
-
-The Ubuntu Sound Menu interacts with Mopidy's MPRIS frontend,
-:mod:`mopidy.frontends.mpris`. The MPRIS frontend supports the minimum
-requirements of the `MPRIS specification `_. The
-``TrackList`` interface of the spec is not supported.
-
-
-Using a custom audio sink
+Core configuration values
=========================
+.. confval:: audio/mixer
+
+ Audio mixer to use.
+
+ Expects a GStreamer mixer to use, typical values are: ``alsamixer``,
+ ``pulsemixer``, ``ossmixer``, and ``oss4mixer``.
+
+ Setting this to blank turns off volume control. ``software`` can be used to
+ force software mixing in the application.
+
+.. confval:: audio/mixer_track
+
+ Audio mixer track to use.
+
+ Name of the mixer track to use. If this is not set we will try to find the
+ master output track. As an example, using ``alsamixer`` you would typically
+ set this to ``Master`` or ``PCM``.
+
+.. confval:: audio/output
+
+ Audio output to use.
+
+ Expects a GStreamer sink. Typical values are ``autoaudiosink``,
+ ``alsasink``, ``osssink``, ``oss4sink``, ``pulsesink``, and ``shout2send``,
+ and additional arguments specific to each sink. You can use the command
+ ``gst-inspect-0.10`` to see what output properties can be set on the sink.
+ For example: ``gst-inspect-0.10 shout2send``
+
+.. confval:: logging/console_format
+
+ The log format used for informational logging.
+
+ See `the Python logging docs
+ `_ for
+ details on the format.
+
+.. confval:: logging/debug_format
+
+ The log format used for debug logging.
+
+ See `the Python logging docs
+ `_ for
+ details on the format.
+
+.. confval:: logging/debug_file
+
+ The file to dump debug log data to when Mopidy is run with the
+ :option:`--save-debug-log` option.
+
+.. confval:: logging.levels/*
+
+ The ``logging.levels`` config section can be used to change the log level
+ for specific parts of Mopidy during development or debugging. Each key in
+ the config section should match the name of a logger. The value is the log
+ level to use for that logger, one of ``debug``, ``info``, ``warning``,
+ ``error``, or ``critical``.
+
+.. confval:: proxy/hostname
+
+ Proxy server to use for communication with the Internet.
+
+ Currently only used by the Spotify extension.
+
+.. confval:: proxy/username
+
+ Username for the proxy server, if required.
+
+.. confval:: proxy/password
+
+ Password for the proxy server, if required.
+
+
+Advanced configurations
+=======================
+
+Custom audio sink
+-----------------
+
If you have successfully installed GStreamer, and then run the ``gst-inspect``
or ``gst-inspect-0.10`` command, you should see a long listing of installed
plugins, ending in a summary line::
@@ -190,8 +161,8 @@ this work first::
gst-launch-0.10 audiotestsrc ! audioresample ! oss4sink
-Streaming audio through a SHOUTcast/Icecast server
-==================================================
+Streaming through SHOUTcast/Icecast
+-----------------------------------
If you want to play the audio on another computer than the one running Mopidy,
you can stream the audio from Mopidy through an SHOUTcast or Icecast audio
@@ -219,8 +190,8 @@ can use with the ``gst-launch-0.10`` command can be plugged into
:confval:`audio/output`.
-Custom configuration values
-===========================
+New configuration values
+------------------------
Mopidy's settings validator will stop you from defining any config values in
your settings file that Mopidy doesn't know about. This may sound obnoxious,
@@ -232,9 +203,3 @@ system, you can add new sections to the config without triggering the config
validator. We recommend that you choose a good and unique name for the config
section so that multiple extensions to Mopidy can be used at the same time
without any danger of naming collisions.
-
-
-Available settings
-==================
-
-.. note:: TODO: Document config values of the new config system
diff --git a/docs/contributing.rst b/docs/contributing.rst
new file mode 100644
index 00000000..215aea65
--- /dev/null
+++ b/docs/contributing.rst
@@ -0,0 +1,116 @@
+.. _contributing:
+
+************
+Contributing
+************
+
+If you are thinking about making Mopidy better, or you just want to hack on it,
+that’s great. Here are some tips to get you started.
+
+
+Getting started
+===============
+
+1. Make sure you have a `GitHub account `_.
+
+2. `Submit `_ a ticket for your
+ issue, assuming one does not already exist. Clearly describe the issue
+ including steps to reproduce when it is a bug.
+
+3. Fork the repository on GitHub.
+
+
+Making changes
+==============
+
+1. Clone your fork on GitHub to your computer.
+
+2. Install dependencies as described in the :ref:`installation` section.
+
+3. Checkout a new branch (usually based on develop) and name it accordingly to
+ what you intend to do.
+
+ - Features get the prefix ``feature/``
+
+ - Bug fixes get the prefix ``fix/``
+
+ - Improvements to the documentation get the prefix ``docs/``
+
+
+.. _run-from-git:
+
+Running Mopidy from Git
+=======================
+
+If you want to hack on Mopidy, you should run Mopidy directly from the Git
+repo.
+
+1. Go to the Git repo root::
+
+ cd mopidy/
+
+2. To get a ``mopidy`` executable, run::
+
+ python setup.py develop
+
+3. Now you can run the Mopidy command, and it will run using the code
+ in the Git repo::
+
+ mopidy
+
+ If you do any changes to the code, you'll just need to restart ``mopidy``
+ to see the changes take effect.
+
+
+Testing
+=======
+
+Mopidy has quite good test coverage, and we would like all new code going into
+Mopidy to come with tests.
+
+1. To run tests, you need a couple of dependencies. They can be installed using
+ ``pip``::
+
+ pip install -r requirements/tests.txt
+
+2. Then, to run all tests, go to the project directory and run::
+
+ nosetests
+
+ To run tests with test coverage statistics, remember to specify the tests
+ dir::
+
+ nosetests --with-coverage tests/
+
+3. Check the code for errors and style issues using flake8::
+
+ flake8 .
+
+For more documentation on testing, check out the `nose documentation
+`_.
+
+
+Submitting changes
+==================
+
+- One branch per feature or fix. Keep branches small and on topic.
+
+- Follow the :ref:`style guide `_, especially make sure ``flake8``
+ does not complain about anything.
+
+- Send a pull request to the ``develop`` branch.
+
+
+Additional resources
+====================
+
+- IRC channel: ``#mopidy`` at `irc.freenode.net `_
+
+- `Issue tracker `_
+
+- `Mailing List `_
+
+- `General GitHub documentation `_
+
+- `GitHub pull request documentation
+ `_
diff --git a/docs/development.rst b/docs/development.rst
deleted file mode 100644
index 776b004d..00000000
--- a/docs/development.rst
+++ /dev/null
@@ -1,360 +0,0 @@
-***********
-Development
-***********
-
-Development of Mopidy is coordinated through the IRC channel ``#mopidy`` at
-``irc.freenode.net`` and through `GitHub `_.
-
-
-Release schedule
-================
-
-We intend to have about one timeboxed feature release every month
-in periods of active development. The feature releases are numbered 0.x.0. The
-features added is a mix of what we feel is most important/requested of the
-missing features, and features we develop just because we find them fun to
-make, even though they may be useful for very few users or for a limited use
-case.
-
-Bugfix releases, numbered 0.x.y, will be released whenever we discover bugs
-that are too serious to wait for the next feature release. We will only release
-bugfix releases for the last feature release. E.g. when 0.3.0 is released, we
-will no longer provide bugfix releases for the 0.2 series. In other words,
-there will be just a single supported release at any point in time.
-
-
-Feature wishlist
-================
-
-We maintain our collection of sane or less sane ideas for future Mopidy
-features as `issues `_ at GitHub
-labeled with `the "wishlist" label
-`_. Feel free to vote
-up any feature you would love to see in Mopidy, but please refrain from adding
-a comment just to say "I want this too!". You are of course free to add
-comments if you have suggestions for how the feature should work or be
-implemented, and you may add new wishlist issues if your ideas are not already
-represented.
-
-
-.. _run-from-git:
-
-Run Mopidy from Git repo
-========================
-
-If you want to contribute to the development of Mopidy, you should run Mopidy
-directly from the Git repo.
-
-#. First of all, install Mopidy in the recommended way for your OS and/or
- distribution, like described at :ref:`installation`. You can have a
- system-wide installation of the last Mopidy release in addition to the Git
- repo which you run from when you code on Mopidy.
-
-#. Then install Git, if haven't already. For Ubuntu/Debian::
-
- sudo apt-get install git-core
-
- On OS X using Homebrew::
-
- sudo brew install git
-
-#. Clone the official Mopidy repository::
-
- git clone git://github.com/mopidy/mopidy.git
-
- or your own fork of it::
-
- git clone git@github.com:mygithubuser/mopidy.git
-
-#. You can then run Mopidy directly from the Git repository::
-
- cd mopidy/ # Move into the Git repo dir
- python mopidy # Run python on the mopidy source code dir
-
-How you update your clone depends on whether you cloned the official Mopidy
-repository or your own fork, whether you have made any changes to the clone
-or not, and whether you are currently working on a feature branch or not. In
-other words, you'll need to learn Git.
-
-For an introduction to Git, please visit `git-scm.com `_.
-Also, please read the rest of our developer documentation before you start
-contributing.
-
-
-Code style
-==========
-
-- Always import ``unicode_literals`` and use unicode literals for everything
- except where you're explicitly working with bytes, which are marked with the
- ``b`` prefix.
-
- Do this::
-
- from __future__ import unicode_literals
-
- foo = 'I am a unicode string, which is a sane default'
- bar = b'I am a bytestring'
-
- Not this::
-
- foo = u'I am a unicode string'
- bar = 'I am a bytestring, but was it intentional?'
-
-- Follow :pep:`8` unless otherwise noted. `pep8.py
- `_ or `flake8
- `_ can be used to check your code
- against the guidelines, however remember that matching the style of the
- surrounding code is also important.
-
-- Use four spaces for indentation, *never* tabs.
-
-- Use CamelCase with initial caps for class names::
-
- ClassNameWithCamelCase
-
-- Use underscore to split variable, function and method names for
- readability. Don't use CamelCase.
-
- ::
-
- lower_case_with_underscores
-
-- Use the fact that empty strings, lists and tuples are :class:`False` and
- don't compare boolean values using ``==`` and ``!=``.
-
-- Follow whitespace rules as described in :pep:`8`. Good examples::
-
- spam(ham[1], {eggs: 2})
- spam(1)
- dict['key'] = list[index]
-
-- Limit lines to 80 characters and avoid trailing whitespace. However note that
- wrapped lines should be *one* indentation level in from level above, except
- for ``if``, ``for``, ``with``, and ``while`` lines which should have two
- levels of indentation::
-
- if (foo and bar ...
- baz and foobar):
- a = 1
-
- from foobar import (foo, bar, ...
- baz)
-
-- For consistency, prefer ``'`` over ``"`` for strings, unless the string
- contains ``'``.
-
-- Take a look at :pep:`20` for a nice peek into a general mindset useful for
- Python coding.
-
-
-Commit guidelines
-=================
-
-- We follow the development process described at
- `nvie.com `_.
-
-- Keep commits small and on topic.
-
-- If a commit looks too big you should be working in a feature branch not a
- single commit.
-
-- Merge feature branches with ``--no-ff`` to keep track of the merge.
-
-
-Running tests
-=============
-
-To run tests, you need a couple of dependencies. They can be installed through
-Debian/Ubuntu package management::
-
- sudo apt-get install python-coverage python-mock python-nose
-
-Or, they can be installed using ``pip``::
-
- sudo pip install -r requirements/tests.txt
-
-Then, to run all tests, go to the project directory and run::
-
- nosetests
-
-For example::
-
- $ nosetests
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................................
- .............................................................
- -----------------------------------------------------------------------------
- 1062 tests run in 7.4 seconds (1062 tests passed)
-
-To run tests with test coverage statistics, remember to specify the tests dir::
-
- nosetests --with-coverage tests/
-
-For more documentation on testing, check out the `nose documentation
-`_.
-
-
-Continuous integration
-======================
-
-Mopidy uses the free service `Travis CI `_
-for automatically running the test suite when code is pushed to GitHub. This
-works both for the main Mopidy repo, but also for any forks. This way, any
-contributions to Mopidy through GitHub will automatically be tested by Travis
-CI, and the build status will be visible in the GitHub pull request interface,
-making it easier to evaluate the quality of pull requests.
-
-In addition, we run a Jenkins CI server at http://ci.mopidy.com/ that runs all
-test on multiple platforms (Ubuntu, OS X, x86, arm) for every commit we push to
-the ``develop`` branch in the main Mopidy repo on GitHub. Thus, new code isn't
-tested by Jenkins before it is merged into the ``develop`` branch, which is a
-bit late, but good enough to get broad testing before new code is released.
-
-In addition to running tests, the Jenkins CI server also gathers coverage
-statistics and uses pylint to check for errors and possible improvements in our
-code. So, if you're out of work, the code coverage and pylint data at the CI
-server should give you a place to start.
-
-
-Protocol debugging
-==================
-
-Since the main interface provided to Mopidy is through the MPD protocol, it is
-crucial that we try and stay in sync with protocol developments. In an attempt
-to make it easier to debug differences Mopidy and MPD protocol handling we have
-created ``tools/debug-proxy.py``.
-
-This tool is proxy that sits in front of two MPD protocol aware servers and
-sends all requests to both, returning the primary response to the client and
-then printing any diff in the two responses.
-
-Note that this tool depends on ``gevent`` unlike the rest of Mopidy at the time
-of writing. See ``--help`` for available options. Sample session::
-
- [127.0.0.1]:59714
- listallinfo
- --- Reference response
- +++ Actual response
- @@ -1,16 +1,1 @@
- -file: uri1
- -Time: 4
- -Artist: artist1
- -Title: track1
- -Album: album1
- -file: uri2
- -Time: 4
- -Artist: artist2
- -Title: track2
- -Album: album2
- -file: uri3
- -Time: 4
- -Artist: artist3
- -Title: track3
- -Album: album3
- -OK
- +ACK [2@0] {listallinfo} incorrect arguments
-
-To ensure that Mopidy and MPD have comparable state it is suggested you setup
-both to use ``tests/data/advanced_tag_cache`` for their tag cache and
-``tests/data/scanner/advanced/`` for the music folder and ``tests/data`` for
-playlists.
-
-
-Setting profiles during development
-===================================
-
-While developing Mopidy switching settings back and forth can become an all too
-frequent occurrence. As a quick hack to get around this you can structure your
-settings file in the following way::
-
- import os
- profile = os.environ.get('PROFILE', '').split(',')
-
- if 'shoutcast' in profile:
- OUTPUT = u'lame ! shout2send mount="/stream"'
- elif 'silent' in profile:
- OUTPUT = u'fakesink'
- MIXER = None
-
- SPOTIFY_USERNAME = u'xxxxx'
- SPOTIFY_PASSWORD = u'xxxxx'
-
-Using this setup you can now run Mopidy with ``PROFILE=silent mopidy``
-if you for instance want to test Spotify without any actual audio output.
-
-
-Debugging deadlocks
-===================
-
-Between the numerous Pykka threads and GStreamer interactions there can
-sometimes be a potential for deadlocks. In an effort to make these slightly
-simpler to debug Mopidy registers a ``SIGUSR1`` signal handler which logs the
-traceback of all alive threads.
-
-To trigger the signal handler, you can use the ``pkill`` command to
-send the ``SIGUSR1`` signal to any Mopidy processes::
-
- pkill -SIGUSR1 mopidy
-
-If you check the log, you should now find one log record with a full traceback
-for each of the currently alive threads in Mopidy.
-
-
-Writing documentation
-=====================
-
-To write documentation, we use `Sphinx `_. See their
-site for lots of documentation on how to use Sphinx. To generate HTML or LaTeX
-from the documentation files, you need some additional dependencies.
-
-You can install them through Debian/Ubuntu package management::
-
- sudo apt-get install python-sphinx python-pygraphviz graphviz
-
-Then, to generate docs::
-
- cd docs/
- make # For help on available targets
- make html # To generate HTML docs
-
-The documentation at http://docs.mopidy.com/ is automatically updated when a
-documentation update is pushed to ``mopidy/mopidy`` at GitHub.
-
-
-Creating releases
-=================
-
-#. Update changelog and commit it.
-
-#. Merge the release branch (``develop`` in the example) into master::
-
- git checkout master
- git merge --no-ff -m "Release v0.2.0" develop
-
-#. Tag the release::
-
- git tag -a -m "Release v0.2.0" v0.2.0
-
-#. Push to GitHub::
-
- git push
- git push --tags
-
-#. Build package and upload to PyPI::
-
- python setup.py sdist upload
-
-#. Update the Debian package.
-
-#. Spread the word.
diff --git a/docs/devtools.rst b/docs/devtools.rst
new file mode 100644
index 00000000..7b5b2f81
--- /dev/null
+++ b/docs/devtools.rst
@@ -0,0 +1,120 @@
+*****************
+Development tools
+*****************
+
+Here you'll find description of the development tools we use.
+
+
+Continuous integration
+======================
+
+Mopidy uses the free service `Travis CI `_
+for automatically running the test suite when code is pushed to GitHub. This
+works both for the main Mopidy repo, but also for any forks. This way, any
+contributions to Mopidy through GitHub will automatically be tested by Travis
+CI, and the build status will be visible in the GitHub pull request interface,
+making it easier to evaluate the quality of pull requests.
+
+In addition, we run a Jenkins CI server at http://ci.mopidy.com/ that runs all
+test on multiple platforms (Ubuntu, OS X, x86, arm) for every commit we push to
+the ``develop`` branch in the main Mopidy repo on GitHub. Thus, new code isn't
+tested by Jenkins before it is merged into the ``develop`` branch, which is a
+bit late, but good enough to get broad testing before new code is released.
+
+In addition to running tests, the Jenkins CI server also gathers coverage
+statistics and uses pylint to check for errors and possible improvements in our
+code. So, if you're out of work, the code coverage and pylint data at the CI
+server should give you a place to start.
+
+
+Protocol debugger
+=================
+
+Since the main interface provided to Mopidy is through the MPD protocol, it is
+crucial that we try and stay in sync with protocol developments. In an attempt
+to make it easier to debug differences Mopidy and MPD protocol handling we have
+created ``tools/debug-proxy.py``.
+
+This tool is proxy that sits in front of two MPD protocol aware servers and
+sends all requests to both, returning the primary response to the client and
+then printing any diff in the two responses.
+
+Note that this tool depends on ``gevent`` unlike the rest of Mopidy at the time
+of writing. See ``--help`` for available options. Sample session::
+
+ [127.0.0.1]:59714
+ listallinfo
+ --- Reference response
+ +++ Actual response
+ @@ -1,16 +1,1 @@
+ -file: uri1
+ -Time: 4
+ -Artist: artist1
+ -Title: track1
+ -Album: album1
+ -file: uri2
+ -Time: 4
+ -Artist: artist2
+ -Title: track2
+ -Album: album2
+ -file: uri3
+ -Time: 4
+ -Artist: artist3
+ -Title: track3
+ -Album: album3
+ -OK
+ +ACK [2@0] {listallinfo} incorrect arguments
+
+To ensure that Mopidy and MPD have comparable state it is suggested you setup
+both to use ``tests/data/advanced_tag_cache`` for their tag cache and
+``tests/data/scanner/advanced/`` for the music folder and ``tests/data`` for
+playlists.
+
+
+Documentation writing
+=====================
+
+To write documentation, we use `Sphinx `_. See their
+site for lots of documentation on how to use Sphinx. To generate HTML from the
+documentation files, you need some additional dependencies.
+
+You can install them through Debian/Ubuntu package management::
+
+ sudo apt-get install python-sphinx python-pygraphviz graphviz
+
+Then, to generate docs::
+
+ cd docs/
+ make # For help on available targets
+ make html # To generate HTML docs
+
+The documentation at http://docs.mopidy.com/ is automatically updated when a
+documentation update is pushed to ``mopidy/mopidy`` at GitHub.
+
+
+Creating releases
+=================
+
+#. Update changelog and commit it.
+
+#. Merge the release branch (``develop`` in the example) into master::
+
+ git checkout master
+ git merge --no-ff -m "Release v0.2.0" develop
+
+#. Tag the release::
+
+ git tag -a -m "Release v0.2.0" v0.2.0
+
+#. Push to GitHub::
+
+ git push
+ git push --tags
+
+#. Build package and upload to PyPI::
+
+ python setup.py sdist upload
+
+#. Update the Debian package.
+
+#. Spread the word.
diff --git a/docs/ext/http.rst b/docs/ext/http.rst
new file mode 100644
index 00000000..65bddb73
--- /dev/null
+++ b/docs/ext/http.rst
@@ -0,0 +1,103 @@
+.. _ext-http:
+
+***********
+Mopidy-HTTP
+***********
+
+The HTTP extension lets you control Mopidy through HTTP and WebSockets, e.g.
+from a web based client. See :ref:`http-api` for details on how to integrate
+with Mopidy over HTTP.
+
+
+Known issues
+============
+
+https://github.com/mopidy/mopidy/issues?labels=HTTP+frontend
+
+
+Dependencies
+============
+
+.. literalinclude:: ../../requirements/http.txt
+
+
+Default configuration
+=====================
+
+.. literalinclude:: ../../mopidy/frontends/http/ext.conf
+ :language: ini
+
+
+Configuration values
+====================
+
+.. confval:: http/enabled
+
+ If the HTTP extension should be enabled or not.
+
+.. confval:: http/hostname
+
+ Which address the HTTP server should bind to.
+
+ ``127.0.0.1``
+ Listens only on the IPv4 loopback interface
+ ``::1``
+ Listens only on the IPv6 loopback interface
+ ``0.0.0.0``
+ Listens on all IPv4 interfaces
+ ``::``
+ Listens on all interfaces, both IPv4 and IPv6
+
+.. confval:: http/port
+
+ Which TCP port the HTTP server should listen to.
+
+.. confval:: http/static_dir
+
+ Which directory the HTTP server should serve at "/"
+
+ Change this to have Mopidy serve e.g. files for your JavaScript client.
+ "/mopidy" will continue to work as usual even if you change this setting.
+
+
+Usage
+=====
+
+The extension is enabled by default if all dependencies are available.
+
+When it is enabled it starts a web server at the port specified by the
+:confval:`http/port` config value.
+
+.. warning:: Security
+
+ As a simple security measure, the web server is by default only available
+ from localhost. To make it available from other computers, change the
+ :confval:`http/hostname` config value. Before you do so, note that the HTTP
+ extension does not feature any form of user authentication or
+ authorization. Anyone able to access the web server can use the full core
+ API of Mopidy. Thus, you probably only want to make the web server
+ available from your local network or place it behind a web proxy which
+ takes care or user authentication. You have been warned.
+
+
+Using a web based Mopidy client
+-------------------------------
+
+The web server can also host any static files, for example the HTML, CSS,
+JavaScript, and images needed for a web based Mopidy client. To host static
+files, change the ``http/static_dir`` to point to the root directory of your
+web client, e.g.::
+
+ [http]
+ static_dir = /home/alice/dev/the-client
+
+If the directory includes a file named ``index.html``, it will be served on the
+root of Mopidy's web server.
+
+If you're making a web based client and wants to do server side development as
+well, you are of course free to run your own web server and just use Mopidy's
+web server for the APIs. But, for clients implemented purely in JavaScript,
+letting Mopidy host the files is a simpler solution.
+
+If you're looking for a web based client for Mopidy, go check out
+:ref:`http-clients`.
diff --git a/docs/ext/index.rst b/docs/ext/index.rst
new file mode 100644
index 00000000..af51e9bb
--- /dev/null
+++ b/docs/ext/index.rst
@@ -0,0 +1,44 @@
+.. _ext:
+
+**********
+Extensions
+**********
+
+Here you can find a list of packages that extend Mopidy with additional
+functionality. This list is moderated and updated on a regular basis. If you
+want your package to show up here, follow the :ref:`guide on creating
+extensions `.
+
+
+Bundled with Mopidy
+===================
+
+These extensions are maintained by Mopidy's core developers. They are installed
+together with Mopidy and are enabled by default.
+
+.. toctree::
+ :maxdepth: 1
+ :glob:
+
+ **
+
+
+External extensions
+===================
+
+These extensions are maintained outside Mopidy's core, often by other
+developers.
+
+
+Mopidy-SoundCloud
+-----------------
+
+Provides a backend for playing music from the `SoundCloud
+`_ service.
+
+Author:
+ Janez Troha
+PyPI:
+ `Mopidy-SoundCloud `_
+GitHub:
+ `dz0ny/mopidy-soundcloud `_
diff --git a/docs/ext/local.rst b/docs/ext/local.rst
new file mode 100644
index 00000000..fc89e69a
--- /dev/null
+++ b/docs/ext/local.rst
@@ -0,0 +1,86 @@
+.. _ext-local:
+
+************
+Mopidy-Local
+************
+
+Extension for playing music from a local music archive.
+
+This backend handles URIs starting with ``file:``.
+
+
+Known issues
+============
+
+https://github.com/mopidy/mopidy/issues?labels=Local+backend
+
+
+Dependencies
+============
+
+None. The extension just needs Mopidy.
+
+
+Default configuration
+=====================
+
+.. literalinclude:: ../../mopidy/backends/local/ext.conf
+ :language: ini
+
+
+Configuration values
+====================
+
+.. confval:: local/enabled
+
+ If the local extension should be enabled or not.
+
+.. confval:: local/media_dir
+
+ Path to directory with local media files.
+
+.. confval:: local/playlists_dir
+
+ Path to playlists directory with m3u files for local media.
+
+.. confval:: local/tag_cache_file
+
+ Path to tag cache for local media.
+
+
+Usage
+=====
+
+If you want use Mopidy to play music you have locally at your machine, you need
+to review and maybe change some of the local extension config values. See above
+for a complete list. Then you need to generate a tag cache for your local
+music...
+
+
+.. _generating-a-tag-cache:
+
+Generating a tag cache
+----------------------
+
+The program :command:`mopidy-scan` will scan the path set in the
+:confval:`local/media_dir` config value for any media files and build a MPD
+compatible ``tag_cache``.
+
+To make a ``tag_cache`` of your local music available for Mopidy:
+
+#. Ensure that the :confval:`local/media_dir` config value points to where your
+ music is located. Check the current setting by running::
+
+ mopidy --show-config
+
+#. Scan your media library. The command outputs the ``tag_cache`` to
+ standard output, which means that you will need to redirect the output to a
+ file yourself::
+
+ mopidy-scan > tag_cache
+
+#. Move the ``tag_cache`` file to the location
+ set in the :confval:`local/tag_cache_file` config value, or change the
+ config value to point to where your ``tag_cache`` file is.
+
+#. Start Mopidy, find the music library in a client, and play some local music!
diff --git a/docs/ext/mpd.rst b/docs/ext/mpd.rst
new file mode 100644
index 00000000..b4d0e1c8
--- /dev/null
+++ b/docs/ext/mpd.rst
@@ -0,0 +1,123 @@
+.. _ext-mpd:
+
+**********
+Mopidy-MPD
+**********
+
+This extension implements an MPD server to make Mopidy available to :ref:`MPD
+clients `.
+
+MPD stands for Music Player Daemon, which is also the name of the `original MPD
+server project `_. Mopidy does not depend on the
+original MPD server, but implements the MPD protocol itself, and is thus
+compatible with clients for the original MPD server.
+
+For more details on our MPD server implementation, see
+:mod:`mopidy.frontends.mpd`.
+
+
+Known issues
+============
+
+https://github.com/mopidy/mopidy/issues?labels=MPD+frontend
+
+
+Limitations
+===========
+
+This is a non exhaustive list of MPD features that Mopidy doesn't support.
+Items on this list will probably not be supported in the near future.
+
+- Toggling of audio outputs is not supported
+- Channels for client-to-client communication are not supported
+- Stickers are not supported
+- Crossfade is not supported
+- Replay gain is not supported
+- ``count`` does not provide any statistics
+- ``stats`` does not provide any statistics
+- ``list`` does not support listing tracks by genre
+- ``decoders`` does not provide information about available decoders
+
+The following items are currently not supported, but should be added in the
+near future:
+
+- Modifying stored playlists is not supported
+- ``tagtypes`` is not supported
+- Browsing the file system is not supported
+- Live update of the music database is not supported
+
+
+Dependencies
+============
+
+None. The extension just needs Mopidy.
+
+
+Default configuration
+=====================
+
+.. literalinclude:: ../../mopidy/frontends/mpd/ext.conf
+ :language: ini
+
+
+Configuration values
+====================
+
+.. confval:: mpd/enabled
+
+ If the MPD extension should be enabled or not.
+
+.. confval:: mpd/hostname
+
+ Which address the MPD server should bind to.
+
+ ``127.0.0.1``
+ Listens only on the IPv4 loopback interface
+ ``::1``
+ Listens only on the IPv6 loopback interface
+ ``0.0.0.0``
+ Listens on all IPv4 interfaces
+ ``::``
+ Listens on all interfaces, both IPv4 and IPv6
+
+.. confval:: mpd/port
+
+ Which TCP port the MPD server should listen to.
+
+.. confval:: mpd/password
+
+ The password required for connecting to the MPD server. If blank, no
+ password is required.
+
+.. confval:: mpd/max_connections
+
+ The maximum number of concurrent connections the MPD server will accept.
+
+.. confval:: mpd/connection_timeout
+
+ Number of seconds an MPD client can stay inactive before the connection is
+ closed by the server.
+
+
+Usage
+=====
+
+The extension is enabled by default. To connect to the server, use an :ref:`MPD
+client `.
+
+
+.. _use-mpd-on-a-network:
+
+Connecting from other machines on the network
+---------------------------------------------
+
+As a secure default, Mopidy only accepts connections from ``localhost``. If you
+want to open it for connections from other machines on your network, see
+the documentation for the :confval:`mpd/hostname` config value.
+
+If you open up Mopidy for your local network, you should consider turning on
+MPD password authentication by setting the :confval:`mpd/password` config value
+to the password you want to use. If the password is set, Mopidy will require
+MPD clients to provide the password before they can do anything else. Mopidy
+only supports a single password, and do not support different permission
+schemes like the original MPD server.
diff --git a/docs/ext/mpris.rst b/docs/ext/mpris.rst
new file mode 100644
index 00000000..125f8fec
--- /dev/null
+++ b/docs/ext/mpris.rst
@@ -0,0 +1,105 @@
+.. _ext-mpris:
+
+************
+Mopidy-MPRIS
+************
+
+This extension lets you control Mopidy through the Media Player Remote
+Interfacing Specification (`MPRIS `_) D-Bus interface.
+
+An example of an MPRIS client is the :ref:`ubuntu-sound-menu`.
+
+
+Dependencies
+============
+
+- D-Bus Python bindings. The package is named ``python-dbus`` in
+ Ubuntu/Debian.
+
+- ``libindicate`` Python bindings is needed to expose Mopidy in e.g. the
+ Ubuntu Sound Menu. The package is named ``python-indicate`` in
+ Ubuntu/Debian.
+
+- An ``.desktop`` file for Mopidy installed at the path set in the
+ :confval:`mpris/desktop_file` config value. See usage section below for
+ details.
+
+
+Default configuration
+=====================
+
+.. literalinclude:: ../../mopidy/frontends/mpris/ext.conf
+ :language: ini
+
+
+Configuration values
+====================
+
+.. confval:: mpris/enabled
+
+ If the MPRIS extension should be enabled or not.
+
+.. confval:: mpris/desktop_file
+
+ Location of the Mopidy ``.desktop`` file.
+
+
+Usage
+=====
+
+The extension is enabled by default if all dependencies are available.
+
+
+Controlling Mopidy through the Ubuntu Sound Menu
+------------------------------------------------
+
+If you are running Ubuntu and installed Mopidy using the Debian package from
+APT you should be able to control Mopidy through the :ref:`ubuntu-sound-menu`
+without any changes.
+
+If you installed Mopidy in any other way and want to control Mopidy through the
+Ubuntu Sound Menu, you must install the ``mopidy.desktop`` file which can be
+found in the ``data/`` dir of the Mopidy source repo into the
+``/usr/share/applications`` dir by hand::
+
+ cd /path/to/mopidy/source
+ sudo cp data/mopidy.desktop /usr/share/applications/
+
+If the correct path to the installed ``mopidy.desktop`` file on your system
+isn't ``/usr/share/applications/mopidy.conf``, you'll need to set the
+:confval:`mpris/desktop_file` config value.
+
+After you have installed the file, start Mopidy in any way, and Mopidy should
+appear in the Ubuntu Sound Menu. When you quit Mopidy, it will still be listed
+in the Ubuntu Sound Menu, and may be restarted by selecting it there.
+
+The Ubuntu Sound Menu interacts with Mopidy's MPRIS frontend. The MPRIS
+frontend supports the minimum requirements of the `MPRIS specification
+`_. The ``TrackList`` interface of the spec is not
+supported.
+
+
+Testing the MPRIS API directly
+------------------------------
+
+To use the MPRIS API directly, start Mopidy, and then run the following in a
+Python shell::
+
+ import dbus
+ bus = dbus.SessionBus()
+ player = bus.get_object('org.mpris.MediaPlayer2.mopidy',
+ '/org/mpris/MediaPlayer2')
+
+Now you can control Mopidy through the player object. Examples:
+
+- To get some properties from Mopidy, run::
+
+ props = player.GetAll('org.mpris.MediaPlayer2',
+ dbus_interface='org.freedesktop.DBus.Properties')
+
+- To quit Mopidy through D-Bus, run::
+
+ player.Quit(dbus_interface='org.mpris.MediaPlayer2')
+
+For details on the API, please refer to the `MPRIS specification
+`_.
diff --git a/docs/ext/scrobbler.rst b/docs/ext/scrobbler.rst
new file mode 100644
index 00000000..a0496b37
--- /dev/null
+++ b/docs/ext/scrobbler.rst
@@ -0,0 +1,53 @@
+****************
+Mopidy-Scrobbler
+****************
+
+This extension scrobbles the music you play to your `Last.fm
+`_ profile.
+
+.. note::
+
+ This extension requires a free user account at Last.fm.
+
+
+Dependencies
+============
+
+.. literalinclude:: ../../requirements/scrobbler.txt
+
+
+Default configuration
+=====================
+
+.. literalinclude:: ../../mopidy/frontends/scrobbler/ext.conf
+ :language: ini
+
+
+Configuration values
+====================
+
+.. confval:: scrobbler/enabled
+
+ If the scrobbler extension should be enabled or not.
+
+.. confval:: scrobbler/username
+
+ Your Last.fm username.
+
+.. confval:: scrobbler/password
+
+ Your Last.fm password.
+
+
+Usage
+=====
+
+The extension is enabled by default if all dependencies are available. You just
+need to add your Last.fm username and password to the
+``~/.config/mopidy/mopidy.conf`` file:
+
+.. code-block:: ini
+
+ [scrobbler]
+ username = myusername
+ password = mysecret
diff --git a/docs/ext/spotify.rst b/docs/ext/spotify.rst
new file mode 100644
index 00000000..4bb5b7a3
--- /dev/null
+++ b/docs/ext/spotify.rst
@@ -0,0 +1,83 @@
+.. _ext-spotify:
+
+**************
+Mopidy-Spotify
+**************
+
+An extension for playing music from Spotify.
+
+`Spotify `_ is a music streaming service. The backend
+uses the official `libspotify
+`_ library and the
+`pyspotify `_ Python bindings for
+libspotify. This backend handles URIs starting with ``spotify:``.
+
+.. note::
+
+ This product uses SPOTIFY(R) CORE but is not endorsed, certified or
+ otherwise approved in any way by Spotify. Spotify is the registered
+ trade mark of the Spotify Group.
+
+
+Known issues
+============
+
+https://github.com/mopidy/mopidy/issues?labels=Spotify+backend
+
+
+Dependencies
+============
+
+.. literalinclude:: ../../requirements/spotify.txt
+
+
+Default configuration
+=====================
+
+.. literalinclude:: ../../mopidy/backends/spotify/ext.conf
+ :language: ini
+
+
+Configuration values
+====================
+
+.. confval:: spotify/enabled
+
+ If the Spotify extension should be enabled or not.
+
+.. confval:: spotify/username
+
+ Your Spotify Premium username.
+
+.. confval:: spotify/password
+
+ Your Spotify Premium password.
+
+.. confval:: spotify/bitrate
+
+ The preferred audio bitrate. Valid values are 96, 160, 320.
+
+.. confval:: spotify/timeout
+
+ Max number of seconds to wait for Spotify operations to complete.
+
+.. confval:: spotify/cache_dir
+
+ Path to the Spotify data cache. Cannot be shared with other Spotify apps.
+
+
+Usage
+=====
+
+If you are using the Spotify backend, which is the default, enter your Spotify
+Premium account's username and password into ``~/.config/mopidy/mopidy.conf``,
+like this:
+
+.. code-block:: ini
+
+ [spotify]
+ username = myusername
+ password = mysecret
+
+This will only work if you have the Spotify Premium subscription. Spotify
+Unlimited will not work.
diff --git a/docs/ext/stream.rst b/docs/ext/stream.rst
new file mode 100644
index 00000000..bb30e924
--- /dev/null
+++ b/docs/ext/stream.rst
@@ -0,0 +1,56 @@
+.. _ext-stream:
+
+*************
+Mopidy-Stream
+*************
+
+Extension for playing streaming music.
+
+The stream backend will handle streaming of URIs matching the
+:confval:`stream/protocols` config value, assuming the needed GStreamer plugins
+are installed.
+
+
+Known issues
+============
+
+https://github.com/mopidy/mopidy/issues?labels=Stream+backend
+
+
+Dependencies
+============
+
+None. The extension just needs Mopidy.
+
+
+Default configuration
+=====================
+
+.. literalinclude:: ../../mopidy/backends/stream/ext.conf
+ :language: ini
+
+
+Configuration values
+====================
+
+.. confval:: stream/enabled
+
+ If the stream extension should be enabled or not.
+
+.. confval:: stream/protocols
+
+ Whitelist of URI schemas to allow streaming from.
+
+
+Usage
+=====
+
+This backend does not provide a library or similar. It simply takes any URI
+added to Mopidy's tracklist that matches any of the protocols in the
+:confval:`stream/protocols` setting and tries to play back the URI using
+GStreamer. E.g. if you're using an MPD client, you'll just have to find your
+clients "add URI" interface, and provide it with the direct URI of the stream.
+
+Currently the stream backend can only work with URIs pointing direcly at
+streams, and not intermediate playlists which is often used. See :issue:`303`
+to track the development of playlist expansion support.
diff --git a/docs/index.rst b/docs/index.rst
index aae7e675..199ba31c 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -2,56 +2,71 @@
Mopidy
******
-Mopidy is a music server which can play music both from your :ref:`local hard
-drive ` and from :ref:`Spotify `. Searches
-returns results from both your local hard drive and from Spotify, and you can
-mix tracks from both sources in your play queue. Your Spotify playlists are
-also available for use, though we don't support modifying them yet.
+Mopidy is a music server which can play music both from multiple sources, like
+your :ref:`local hard drive `, :ref:`radio streams `,
+and from :ref:`Spotify ` and SoundCloud. Searches combines results
+from all music sources, and you can mix tracks from all sources in your play
+queue. Your playlists from Spotify or SoundCloud are also available for use.
-To control your music server, you can use the :ref:`Ubuntu Sound Menu
-` on the machine running Mopidy, any device on the same
-network which can control UPnP MediaRenderers (see :ref:`upnp-clients`), or any
-:ref:`MPD client `. MPD clients are available for most platforms,
-including Windows, Mac OS X, Linux, Android, and iOS.
+To control your Mopidy music server, you can use one of Mopidy's :ref:`web
+clients `, the :ref:`Ubuntu Sound Menu `, any
+device on the same network which can control :ref:`UPnP MediaRenderers
+`, or any :ref:`MPD client `. MPD clients are
+available for many platforms, including Windows, OS X, Linux, Android and iOS.
-To install Mopidy, start by reading :ref:`installation`.
+To get started with Mopidy, start by reading :ref:`installation`.
If you get stuck, we usually hang around at ``#mopidy`` at `irc.freenode.net
-`_ and also got a `mailing list at Google Groups
+`_ and also have a `mailing list at Google Groups
`_. If you stumble
into a bug or got a feature request, please create an issue in the `issue
-tracker `_.
+tracker `_. The `source code
+`_ may also be of help. If you want to stay
+up to date on Mopidy developments, you can follow `@mopidy
+`_ on Twitter.
-Project resources
-=================
-
-- `Documentation `_
-- `Source code `_
-- `Issue tracker `_
-- `CI server `_
-- IRC: ``#mopidy`` at `irc.freenode.net `_
-- Mailing list: `mopidy@googlegroups.com `_
-
-
-User documentation
-==================
+Usage
+=====
.. toctree::
- :maxdepth: 2
+ :maxdepth: 3
installation/index
installation/raspberrypi
config
+ ext/index
running
clients/index
+ troubleshooting
+
+
+About
+=====
+
+.. toctree::
+ :maxdepth: 1
+
authors
licenses
- changes
+ changelog
+ versioning
-Reference documentation
-=======================
+Development
+===========
+
+.. toctree::
+ :maxdepth: 1
+
+ contributing
+ devtools
+ codestyle
+ extensiondev
+
+
+Reference
+=========
.. toctree::
:maxdepth: 2
@@ -60,16 +75,6 @@ Reference documentation
modules/index
-Development documentation
-=========================
-
-.. toctree::
- :maxdepth: 2
-
- development
- extensiondev
-
-
Indices and tables
==================
diff --git a/docs/modules/backends/dummy.rst b/docs/modules/backends/dummy.rst
deleted file mode 100644
index 03b2e6ce..00000000
--- a/docs/modules/backends/dummy.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-*********************************************************
-:mod:`mopidy.backends.dummy` -- Dummy backend for testing
-*********************************************************
-
-.. automodule:: mopidy.backends.dummy
- :synopsis: Dummy backend used for testing
- :members:
diff --git a/docs/modules/backends/local.rst b/docs/modules/backends/local.rst
deleted file mode 100644
index 9ac93bc8..00000000
--- a/docs/modules/backends/local.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-.. _local-backend:
-
-*********************************************
-:mod:`mopidy.backends.local` -- Local backend
-*********************************************
-
-.. automodule:: mopidy.backends.local
- :synopsis: Backend for playing music files on local storage
diff --git a/docs/modules/backends/spotify.rst b/docs/modules/backends/spotify.rst
deleted file mode 100644
index b410f272..00000000
--- a/docs/modules/backends/spotify.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-.. _spotify-backend:
-
-*************************************************
-:mod:`mopidy.backends.spotify` -- Spotify backend
-*************************************************
-
-.. automodule:: mopidy.backends.spotify
- :synopsis: Backend for the Spotify music streaming service
diff --git a/docs/modules/backends/stream.rst b/docs/modules/backends/stream.rst
deleted file mode 100644
index 73e53048..00000000
--- a/docs/modules/backends/stream.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-***********************************************
-:mod:`mopidy.backends.stream` -- Stream backend
-***********************************************
-
-.. automodule:: mopidy.backends.stream
- :synopsis: Backend for playing audio streams
- :members:
diff --git a/docs/modules/frontends/http.rst b/docs/modules/frontends/http.rst
deleted file mode 100644
index 31366bd1..00000000
--- a/docs/modules/frontends/http.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-.. _http-frontend:
-
-*********************************************
-:mod:`mopidy.frontends.http` -- HTTP frontend
-*********************************************
-
-.. automodule:: mopidy.frontends.http
- :synopsis: HTTP and WebSockets frontend
diff --git a/docs/modules/frontends/mpd.rst b/docs/modules/frontends/mpd.rst
index f25b90f2..750d19bb 100644
--- a/docs/modules/frontends/mpd.rst
+++ b/docs/modules/frontends/mpd.rst
@@ -2,6 +2,8 @@
:mod:`mopidy.frontends.mpd` -- MPD server
*****************************************
+For details on how to use Mopidy's MPD server, see :ref:`ext-mpd`.
+
.. automodule:: mopidy.frontends.mpd
:synopsis: MPD server frontend
diff --git a/docs/modules/frontends/mpris.rst b/docs/modules/frontends/mpris.rst
deleted file mode 100644
index e0ec63da..00000000
--- a/docs/modules/frontends/mpris.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-.. _mpris-frontend:
-
-***********************************************
-:mod:`mopidy.frontends.mpris` -- MPRIS frontend
-***********************************************
-
-.. automodule:: mopidy.frontends.mpris
- :synopsis: MPRIS frontend
diff --git a/docs/modules/frontends/scrobbler.rst b/docs/modules/frontends/scrobbler.rst
deleted file mode 100644
index 2af9fcff..00000000
--- a/docs/modules/frontends/scrobbler.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-***********************************************
-:mod:`mopidy.frontends.scrobbler` -- Scrobbler
-***********************************************
-
-.. automodule:: mopidy.frontends.scrobbler
- :synopsis: Music scrobbler frontend
diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst
new file mode 100644
index 00000000..4a634a99
--- /dev/null
+++ b/docs/troubleshooting.rst
@@ -0,0 +1,58 @@
+.. _troubleshooting:
+
+***************
+Troubleshooting
+***************
+
+If you run into problems with Mopidy, we usually hang around at ``#mopidy`` at
+`irc.freenode.net `_ and also have a `mailing list at
+Google Groups `_.
+If you stumble into a bug or got a feature request, please create an issue in
+the `issue tracker `_.
+
+When you're debugging yourself or asking for help, there are some tools built
+into Mopidy that you should know about.
+
+
+Effective configuration
+=======================
+
+The command :option:`mopidy --show-config` will print your full effective
+configuration the way Mopidy sees it after all defaults and all config files
+have been merged into a single config document. Any secret values like
+passwords are masked out, so the output of the command should be safe to share
+with others for debugging.
+
+
+Installed dependencies
+======================
+
+The command :option:`mopidy --list-deps` will list the paths to and versions of
+any dependency Mopidy or the extensions might need to work. This is very useful
+data for checking that you're using the right versions, and that you're using
+the right installation if you have multiple installations of a dependency on
+your system.
+
+
+Debug logging
+=============
+
+If you run :option:`mopidy -v`, Mopidy will output debug log to stdout. If you
+run :option:`mopidy --save-debug-log`, it will save the debug log to the file
+``mopidy.log`` in the directory you ran the command from.
+
+If you want to turn on more or less logging for some component, see the
+docs for the :confval:`logging.levels/*` config section.
+
+
+Debugging deadlocks
+===================
+
+If Mopidy hangs without and obvious explanation, you can send the ``SIGUSR1``
+signal to the Mopidy process. If Mopidy's main thread is still responsive, it
+will log a traceback for each running thread, showing what the threads are
+currently doing. This is a very useful tool for understanding exactly how the
+system is deadlocking. If you have the ``pkill`` command installed, you can use
+this by simply running::
+
+ pkill -SIGUSR1 mopidy
diff --git a/docs/versioning.rst b/docs/versioning.rst
new file mode 100644
index 00000000..cc7f58bc
--- /dev/null
+++ b/docs/versioning.rst
@@ -0,0 +1,23 @@
+**********
+Versioning
+**********
+
+Mopidy uses `Semantic Versioning `_, but since we're still
+pre-1.0 that doesn't mean much yet.
+
+
+Release schedule
+================
+
+We intend to have about one feature release every month in periods of active
+development. The feature releases are numbered 0.x.0. The features added is a
+mix of what we feel is most important/requested of the missing features, and
+features we develop just because we find them fun to make, even though they may
+be useful for very few users or for a limited use case.
+
+Bugfix releases, numbered 0.x.y, will be released whenever we discover bugs
+that are too serious to wait for the next feature release. We will only release
+bugfix releases for the last feature release. E.g. when 0.14.0 is released, we
+will no longer provide bugfix releases for the 0.13 series. In other words,
+there will be just a single supported release at any point in time. This is to
+not spread our limited resources too thin.
diff --git a/js/README.md b/js/README.md
index 9601b64a..27803f25 100644
--- a/js/README.md
+++ b/js/README.md
@@ -41,8 +41,8 @@ After npm completes, you can import Mopidy.js using ``require()``:
Using the library
-----------------
-See Mopidy's [HTTP frontend
-documentation](http://docs.mopidy.com/en/latest/modules/frontends/http/).
+See Mopidy's [HTTP API
+documentation](http://docs.mopidy.com/en/latest/api/http/).
Building from source
diff --git a/mopidy/audio/actor.py b/mopidy/audio/actor.py
index 5d92f3c4..af0a0c68 100644
--- a/mopidy/audio/actor.py
+++ b/mopidy/audio/actor.py
@@ -26,15 +26,6 @@ MB = 1 << 20
class Audio(pykka.ThreadingActor):
"""
Audio output through `GStreamer `_.
-
- **Default config:**
-
- .. code-block:: ini
-
- [audio]
- mixer = autoaudiomixer
- mixer_track =
- output = autoaudiosink
"""
#: The GStreamer state mapped to :class:`mopidy.audio.PlaybackState`
diff --git a/mopidy/audio/mixers/auto.py b/mopidy/audio/mixers/auto.py
index f1dde3f9..6b76e1a1 100644
--- a/mopidy/audio/mixers/auto.py
+++ b/mopidy/audio/mixers/auto.py
@@ -2,11 +2,15 @@
This is Mopidy's default mixer.
-**Dependencies**
+
+Dependencies
+============
None
-**Configuration**
+
+Configuration
+=============
If this wasn't the default, you would set the :confval:`audio/mixer` config
value to ``autoaudiomixer`` to use this mixer.
diff --git a/mopidy/audio/mixers/fake.py b/mopidy/audio/mixers/fake.py
index 98afca2a..589610ce 100644
--- a/mopidy/audio/mixers/fake.py
+++ b/mopidy/audio/mixers/fake.py
@@ -1,10 +1,13 @@
"""Fake mixer for use in tests.
-**Dependencies**
+Dependencies
+============
None
-**Configuration**
+
+Configuration
+=============
Set the :confval:`audio/mixer:` config value to ``fakemixer`` to use this
mixer.
diff --git a/mopidy/audio/mixers/nad.py b/mopidy/audio/mixers/nad.py
index 9259d291..bbbaee71 100644
--- a/mopidy/audio/mixers/nad.py
+++ b/mopidy/audio/mixers/nad.py
@@ -3,11 +3,15 @@
The NAD amplifier must be connected to the machine running Mopidy using a
serial cable.
-**Dependencies**
+
+Dependencies
+============
.. literalinclude:: ../../../../requirements/external_mixers.txt
-**Configuration**
+
+Configuration
+=============
Set the :confval:`audio/mixer` config value to ``nadmixer`` to use it. You
probably also needs to add some properties to the :confval:`audio/mixer` config
diff --git a/mopidy/backends/local/__init__.py b/mopidy/backends/local/__init__.py
index 4c5eb2a2..a6c96a3a 100644
--- a/mopidy/backends/local/__init__.py
+++ b/mopidy/backends/local/__init__.py
@@ -1,57 +1,9 @@
from __future__ import unicode_literals
+import os
+
import mopidy
from mopidy import config, ext
-from mopidy.utils import formatting
-
-
-default_config = """
-[local]
-enabled = true
-media_dir = $XDG_MUSIC_DIR
-playlists_dir = $XDG_DATA_DIR/mopidy/local/playlists
-tag_cache_file = $XDG_DATA_DIR/mopidy/local/tag_cache
-"""
-
-__doc__ = """A backend for playing music from a local music archive.
-
-This backend handles URIs starting with ``file:``.
-
-See :ref:`music-from-local-storage` for further instructions on using this
-backend.
-
-**Issues**
-
-https://github.com/mopidy/mopidy/issues?labels=Local+backend
-
-**Dependencies**
-
-None
-
-**Configuration**
-
-.. confval:: local/enabled
-
- If the local extension should be enabled or not.
-
-.. confval:: local/media_dir
-
- Path to directory with local media files.
-
-.. confval:: local/playlists_dir
-
- Path to playlists directory with m3u files for local media.
-
-.. confval:: local/tag_cache_file
-
- Path to tag cache for local media.
-
-**Default config**
-
-.. code-block:: ini
-
-%(config)s
-""" % {'config': formatting.indent(default_config)}
class Extension(ext.Extension):
@@ -61,7 +13,8 @@ class Extension(ext.Extension):
version = mopidy.__version__
def get_default_config(self):
- return default_config
+ conf_file = os.path.join(os.path.dirname(__file__), 'ext.conf')
+ return open(conf_file).read()
def get_config_schema(self):
schema = config.ExtensionConfigSchema()
diff --git a/mopidy/backends/local/ext.conf b/mopidy/backends/local/ext.conf
new file mode 100644
index 00000000..54c3ab78
--- /dev/null
+++ b/mopidy/backends/local/ext.conf
@@ -0,0 +1,5 @@
+[local]
+enabled = true
+media_dir = $XDG_MUSIC_DIR
+playlists_dir = $XDG_DATA_DIR/mopidy/local/playlists
+tag_cache_file = $XDG_DATA_DIR/mopidy/local/tag_cache
diff --git a/mopidy/backends/spotify/__init__.py b/mopidy/backends/spotify/__init__.py
index ec55888c..2860b593 100644
--- a/mopidy/backends/spotify/__init__.py
+++ b/mopidy/backends/spotify/__init__.py
@@ -1,76 +1,9 @@
from __future__ import unicode_literals
+import os
+
import mopidy
from mopidy import config, exceptions, ext
-from mopidy.utils import formatting
-
-
-default_config = """
-[spotify]
-enabled = true
-username =
-password =
-bitrate = 160
-timeout = 10
-cache_dir = $XDG_CACHE_DIR/mopidy/spotify
-"""
-
-__doc__ = """A backend for playing music from Spotify
-
-`Spotify `_ is a music streaming service. The backend
-uses the official `libspotify
-`_ library and the
-`pyspotify `_ Python bindings for
-libspotify. This backend handles URIs starting with ``spotify:``.
-
-See :ref:`music-from-spotify` for further instructions on using this backend.
-
-.. note::
-
- This product uses SPOTIFY(R) CORE but is not endorsed, certified or
- otherwise approved in any way by Spotify. Spotify is the registered
- trade mark of the Spotify Group.
-
-**Issues**
-
-https://github.com/mopidy/mopidy/issues?labels=Spotify+backend
-
-**Dependencies**
-
-.. literalinclude:: ../../../requirements/spotify.txt
-
-**Configuration**
-
-.. confval:: spotify/enabled
-
- If the Spotify extension should be enabled or not.
-
-.. confval:: spotify/username
-
- Your Spotify Premium username.
-
-.. confval:: spotify/password
-
- Your Spotify Premium password.
-
-.. confval:: spotify/bitrate
-
- The preferred audio bitrate. Valid values are 96, 160, 320.
-
-.. confval:: spotify/timeout
-
- Max number of seconds to wait for Spotify operations to complete.
-
-.. confval:: spotify/cache_dir
-
- Path to the Spotify data cache. Cannot be shared with other Spotify apps.
-
-**Default config**
-
-.. code-block:: ini
-
-%(config)s
-""" % {'config': formatting.indent(default_config)}
class Extension(ext.Extension):
@@ -80,7 +13,8 @@ class Extension(ext.Extension):
version = mopidy.__version__
def get_default_config(self):
- return default_config
+ conf_file = os.path.join(os.path.dirname(__file__), 'ext.conf')
+ return open(conf_file).read()
def get_config_schema(self):
schema = config.ExtensionConfigSchema()
diff --git a/mopidy/backends/spotify/ext.conf b/mopidy/backends/spotify/ext.conf
new file mode 100644
index 00000000..83bf191a
--- /dev/null
+++ b/mopidy/backends/spotify/ext.conf
@@ -0,0 +1,7 @@
+[spotify]
+enabled = true
+username =
+password =
+bitrate = 160
+timeout = 10
+cache_dir = $XDG_CACHE_DIR/mopidy/spotify
diff --git a/mopidy/backends/stream/__init__.py b/mopidy/backends/stream/__init__.py
index 60817030..732fd3f2 100644
--- a/mopidy/backends/stream/__init__.py
+++ b/mopidy/backends/stream/__init__.py
@@ -1,53 +1,9 @@
from __future__ import unicode_literals
+import os
+
import mopidy
from mopidy import config, ext
-from mopidy.utils import formatting
-
-
-default_config = """
-[stream]
-enabled = true
-protocols =
- http
- https
- mms
- rtmp
- rtmps
- rtsp
-"""
-
-__doc__ = """
-A backend for playing music for streaming music.
-
-This backend will handle streaming of URIs matching the
-:confval:`stream/protocols` config value, assuming the needed GStreamer plugins
-are installed.
-
-**Issues**
-
-https://github.com/mopidy/mopidy/issues?labels=Stream+backend
-
-**Dependencies**
-
-None
-
-**Configuration**
-
-.. confval:: stream/enabled
-
- If the stream extension should be enabled or not.
-
-.. confval:: stream/protocols
-
- Whitelist of URI schemas to allow streaming from.
-
-**Default config**
-
-.. code-block:: ini
-
-%(config)s
-""" % {'config': formatting.indent(default_config)}
class Extension(ext.Extension):
@@ -57,7 +13,8 @@ class Extension(ext.Extension):
version = mopidy.__version__
def get_default_config(self):
- return default_config
+ conf_file = os.path.join(os.path.dirname(__file__), 'ext.conf')
+ return open(conf_file).read()
def get_config_schema(self):
schema = config.ExtensionConfigSchema()
diff --git a/mopidy/backends/stream/ext.conf b/mopidy/backends/stream/ext.conf
new file mode 100644
index 00000000..9caafac1
--- /dev/null
+++ b/mopidy/backends/stream/ext.conf
@@ -0,0 +1,9 @@
+[stream]
+enabled = true
+protocols =
+ http
+ https
+ mms
+ rtmp
+ rtmps
+ rtsp
diff --git a/mopidy/default.conf b/mopidy/default.conf
new file mode 100644
index 00000000..1d7d7338
--- /dev/null
+++ b/mopidy/default.conf
@@ -0,0 +1,17 @@
+[logging]
+console_format = %(levelname)-8s %(message)s
+debug_format = %(levelname)-8s %(asctime)s [%(process)d:%(threadName)s] %(name)s\n %(message)s
+debug_file = mopidy.log
+
+[logging.levels]
+pykka = info
+
+[audio]
+mixer = autoaudiomixer
+mixer_track =
+output = autoaudiosink
+
+[proxy]
+hostname =
+username =
+password =
diff --git a/mopidy/frontends/http/__init__.py b/mopidy/frontends/http/__init__.py
index 1cdbc1fb..34fa065a 100644
--- a/mopidy/frontends/http/__init__.py
+++ b/mopidy/frontends/http/__init__.py
@@ -1,533 +1,9 @@
from __future__ import unicode_literals
+import os
+
import mopidy
from mopidy import config, exceptions, ext
-from mopidy.utils import formatting
-
-
-default_config = """
-[http]
-enabled = true
-hostname = 127.0.0.1
-port = 6680
-static_dir =
-
-[logging.levels]
-cherrypy = warning
-"""
-
-__doc__ = """
-The HTTP frontends lets you control Mopidy through HTTP and WebSockets, e.g.
-from a web based client.
-
-**Issues**
-
-https://github.com/mopidy/mopidy/issues?labels=HTTP+frontend
-
-**Dependencies**
-
-.. literalinclude:: ../../../requirements/http.txt
-
-**Configuration**
-
-.. confval:: http/enabled
-
- If the HTTP extension should be enabled or not.
-
-.. confval:: http/hostname
-
- Which address the HTTP server should bind to.
-
- ``127.0.0.1``
- Listens only on the IPv4 loopback interface
- ``::1``
- Listens only on the IPv6 loopback interface
- ``0.0.0.0``
- Listens on all IPv4 interfaces
- ``::``
- Listens on all interfaces, both IPv4 and IPv6
-
-.. confval:: http/port
-
- Which TCP port the HTTP server should listen to.
-
-.. confval:: http/static_dir
-
- Which directory the HTTP server should serve at "/"
-
- Change this to have Mopidy serve e.g. files for your JavaScript client.
- "/mopidy" will continue to work as usual even if you change this setting.
-
-**Default config**
-
-.. code-block:: ini
-
-%(config)s
-
-
-Setup
-=====
-
-The frontend is enabled by default if all dependencies are available.
-
-When it is enabled it starts a web server at the port specified by the
-:confval:`http/port` config value.
-
-.. warning:: Security
-
- As a simple security measure, the web server is by default only available
- from localhost. To make it available from other computers, change the
- :confval:`http/hostname` config value. Before you do so, note that the HTTP
- frontend does not feature any form of user authentication or authorization.
- Anyone able to access the web server can use the full core API of Mopidy.
- Thus, you probably only want to make the web server available from your
- local network or place it behind a web proxy which takes care or user
- authentication. You have been warned.
-
-
-Using a web based Mopidy client
-===============================
-
-The web server can also host any static files, for example the HTML, CSS,
-JavaScript, and images needed for a web based Mopidy client. To host static
-files, change the ``http/static_dir`` to point to the root directory of your
-web client, e.g.::
-
- [http]
- static_dir = /home/alice/dev/the-client
-
-If the directory includes a file named ``index.html``, it will be served on the
-root of Mopidy's web server.
-
-If you're making a web based client and wants to do server side development as
-well, you are of course free to run your own web server and just use Mopidy's
-web server for the APIs. But, for clients implemented purely in JavaScript,
-letting Mopidy host the files is a simpler solution.
-
-
-WebSocket API
-=============
-
-.. warning:: API stability
-
- Since this frontend exposes our internal core API directly it is to be
- regarded as **experimental**. We cannot promise to keep any form of
- backwards compatibility between releases as we will need to change the core
- API while working out how to support new use cases. Thus, if you use this
- API, you must expect to do small adjustments to your client for every
- release of Mopidy.
-
- From Mopidy 1.0 and onwards, we intend to keep the core API far more
- stable.
-
-The web server exposes a WebSocket at ``/mopidy/ws/``. The WebSocket gives you
-access to Mopidy's full API and enables Mopidy to instantly push events to the
-client, as they happen.
-
-On the WebSocket we send two different kind of messages: The client can send
-JSON-RPC 2.0 requests, and the server will respond with JSON-RPC 2.0 responses.
-In addition, the server will send event messages when something happens on the
-server. Both message types are encoded as JSON objects.
-
-
-Event messages
---------------
-
-Event objects will always have a key named ``event`` whose value is the event
-type. Depending on the event type, the event may include additional fields for
-related data. The events maps directly to the :class:`mopidy.core.CoreListener`
-API. Refer to the ``CoreListener`` method names is the available event types.
-The ``CoreListener`` method's keyword arguments are all included as extra
-fields on the event objects. Example event message::
-
- {"event": "track_playback_started", "track": {...}}
-
-
-JSON-RPC 2.0 messaging
-----------------------
-
-JSON-RPC 2.0 messages can be recognized by checking for the key named
-``jsonrpc`` with the string value ``2.0``. For details on the messaging format,
-please refer to the `JSON-RPC 2.0 spec
-`_.
-
-All methods (not attributes) in the :ref:`core-api` is made available through
-JSON-RPC calls over the WebSocket. For example,
-:meth:`mopidy.core.PlaybackController.play` is available as the JSON-RPC method
-``core.playback.play``.
-
-The core API's attributes is made available through setters and getters. For
-example, the attribute :attr:`mopidy.core.PlaybackController.current_track` is
-available as the JSON-RPC method ``core.playback.get_current_track``.
-
-Example JSON-RPC request::
-
- {"jsonrpc": "2.0", "id": 1, "method": "core.playback.get_current_track"}
-
-Example JSON-RPC response::
-
- {"jsonrpc": "2.0", "id": 1, "result": {"__model__": "Track", "...": "..."}}
-
-The JSON-RPC method ``core.describe`` returns a data structure describing all
-available methods. If you're unsure how the core API maps to JSON-RPC, having a
-look at the ``core.describe`` response can be helpful.
-
-
-Mopidy.js JavaScript library
-============================
-
-We've made a JavaScript library, Mopidy.js, which wraps the WebSocket and gets
-you quickly started with working on your client instead of figuring out how to
-communicate with Mopidy.
-
-
-Getting the library for browser use
------------------------------------
-
-Regular and minified versions of Mopidy.js, ready for use, is installed
-together with Mopidy. When the HTTP frontend is running, the files are
-available at:
-
-- http://localhost:6680/mopidy/mopidy.js
-- http://localhost:6680/mopidy/mopidy.min.js
-
-You may need to adjust hostname and port for your local setup.
-
-Thus, if you use Mopidy to host your web client, like described above, you can
-load the latest version of Mopidy.js by adding the following script tag to your
-HTML file:
-
-.. code-block:: html
-
-
-
-If you don't use Mopidy to host your web client, you can find the JS files in
-the Git repo at:
-
-- ``mopidy/frontends/http/data/mopidy.js``
-- ``mopidy/frontends/http/data/mopidy.min.js``
-
-
-Getting the library for Node.js use
------------------------------------
-
-If you want to use Mopidy.js from Node.js instead of a browser, you can install
-Mopidy.js using npm::
-
- npm install mopidy
-
-After npm completes, you can import Mopidy.js using ``require()``:
-
-.. code-block:: js
-
- var Mopidy = require("mopidy").Mopidy;
-
-
-Getting the library for development on the library
---------------------------------------------------
-
-If you want to work on the Mopidy.js library itself, you'll find a complete
-development setup in the ``js/`` dir in our repo. The instructions in
-``js/README.md`` will guide you on your way.
-
-
-Creating an instance
---------------------
-
-Once you got Mopidy.js loaded, you need to create an instance of the wrapper:
-
-.. code-block:: js
-
- var mopidy = new Mopidy();
-
-When you instantiate ``Mopidy()`` without arguments, it will connect to
-the WebSocket at ``/mopidy/ws/`` on the current host. Thus, if you don't host
-your web client using Mopidy's web server, or if you use Mopidy.js from a
-Node.js environment, you'll need to pass the URL to the WebSocket end point:
-
-.. code-block:: js
-
- var mopidy = new Mopidy({
- webSocketUrl: "ws://localhost:6680/mopidy/ws/"
- });
-
-It is also possible to create an instance first and connect to the WebSocket
-later:
-
-.. code-block:: js
-
- var mopidy = new Mopidy({autoConnect: false});
- // ... do other stuff, like hooking up events ...
- mopidy.connect();
-
-
-Hooking up to events
---------------------
-
-Once you have a Mopidy.js object, you can hook up to the events it emits. To
-explore your possibilities, it can be useful to subscribe to all events and log
-them:
-
-.. code-block:: js
-
- mopidy.on(console.log.bind(console));
-
-Several types of events are emitted:
-
-- You can get notified about when the Mopidy.js object is connected to the
- server and ready for method calls, when it's offline, and when it's trying to
- reconnect to the server by looking at the events ``state:online``,
- ``state:offline``, ``reconnectionPending``, and ``reconnecting``.
-
-- You can get events sent from the Mopidy server by looking at the events with
- the name prefix ``event:``, like ``event:trackPlaybackStarted``.
-
-- You can introspect what happens internally on the WebSocket by looking at the
- events emitted with the name prefix ``websocket:``.
-
-Mopidy.js uses the event emitter library `BANE
-`_, so you should refer to BANE's
-short API documentation to see how you can hook up your listeners to the
-different events.
-
-
-Calling core API methods
-------------------------
-
-Once your Mopidy.js object has connected to the Mopidy server and emits the
-``state:online`` event, it is ready to accept core API method calls:
-
-.. code-block:: js
-
- mopidy.on("state:online", function () {
- mopidy.playback.next();
- });
-
-Any calls you make before the ``state:online`` event is emitted will fail. If
-you've hooked up an errback (more on that a bit later) to the promise returned
-from the call, the errback will be called with an error message.
-
-All methods in Mopidy's :ref:`core-api` is available via Mopidy.js. The core
-API attributes is *not* available, but that shouldn't be a problem as we've
-added (undocumented) getters and setters for all of them, so you can access the
-attributes as well from JavaScript.
-
-Both the WebSocket API and the JavaScript API are based on introspection of the
-core Python API. Thus, they will always be up to date and immediately reflect
-any changes we do to the core API.
-
-The best way to explore the JavaScript API, is probably by opening your
-browser's console, and using its tab completion to navigate the API. You'll
-find the Mopidy core API exposed under ``mopidy.playback``,
-``mopidy.tracklist``, ``mopidy.playlists``, and ``mopidy.library``.
-
-All methods in the JavaScript API have an associated data structure describing
-the Python params it expects, and most methods also have the Python API
-documentation available. This is available right there in the browser console,
-by looking at the method's ``description`` and ``params`` attributes:
-
-.. code-block:: js
-
- console.log(mopidy.playback.next.params);
- console.log(mopidy.playback.next.description);
-
-JSON-RPC 2.0 limits method parameters to be sent *either* by-position or
-by-name. Combinations of both, like we're used to from Python, isn't supported
-by JSON-RPC 2.0. To further limit this, Mopidy.js currently only supports
-passing parameters by-position.
-
-Obviously, you'll want to get a return value from many of your method calls.
-Since everything is happening across the WebSocket and maybe even across the
-network, you'll get the results asynchronously. Instead of having to pass
-callbacks and errbacks to every method you call, the methods return "promise"
-objects, which you can use to pipe the future result as input to another
-method, or to hook up callback and errback functions.
-
-.. code-block:: js
-
- var track = mopidy.playback.getCurrentTrack();
- // => ``track`` isn't a track, but a "promise" object
-
-Instead, typical usage will look like this:
-
-.. code-block:: js
-
- var printCurrentTrack = function (track) {
- if (track) {
- console.log("Currently playing:", track.name, "by",
- track.artists[0].name, "from", track.album.name);
- } else {
- console.log("No current track");
- }
- };
-
- mopidy.playback.getCurrentTrack().then(
- printCurrentTrack, console.error.bind(console));
-
-The first function passed to ``then()``, ``printCurrentTrack``, is the callback
-that will be called if the method call succeeds. The second function,
-``console.error``, is the errback that will be called if anything goes wrong.
-If you don't hook up an errback, debugging will be hard as errors will silently
-go missing.
-
-For debugging, you may be interested in errors from function without
-interesting return values as well. In that case, you can pass ``null`` as the
-callback:
-
-.. code-block:: js
-
- mopidy.playback.next().then(null, console.error.bind(console));
-
-The promise objects returned by Mopidy.js adheres to the `CommonJS Promises/A
-`_ standard. We use the
-implementation known as `when.js `_. Please
-refer to when.js' documentation or the standard for further details on how to
-work with promise objects.
-
-
-Cleaning up
------------
-
-If you for some reason want to clean up after Mopidy.js before the web page is
-closed or navigated away from, you can close the WebSocket, unregister all
-event listeners, and delete the object like this:
-
-.. code-block:: js
-
- // Close the WebSocket without reconnecting. Letting the object be garbage
- // collected will have the same effect, so this isn't strictly necessary.
- mopidy.close();
-
- // Unregister all event listeners. If you don't do this, you may have
- // lingering references to the object causing the garbage collector to not
- // clean up after it.
- mopidy.off();
-
- // Delete your reference to the object, so it can be garbage collected.
- mopidy = null;
-
-
-Example to get started with
----------------------------
-
-1. Make sure that you've installed all dependencies required by the HTTP
- frontend.
-
-2. Create an empty directory for your web client.
-
-3. Change the :confval:`http/static_dir` config value to point to your new
- directory.
-
-4. Start/restart Mopidy.
-
-5. Create a file in the directory named ``index.html`` containing e.g. "Hello,
- world!".
-
-6. Visit http://localhost:6680/ to confirm that you can view your new HTML file
- there.
-
-7. Include Mopidy.js in your web page:
-
- .. code-block:: html
-
-
-
-8. Add one of the following Mopidy.js examples of how to queue and start
- playback of your first playlist either to your web page or a JavaScript file
- that you include in your web page.
-
- "Imperative" style:
-
- .. code-block:: js
-
- var consoleError = console.error.bind(console);
-
- var trackDesc = function (track) {
- return track.name + " by " + track.artists[0].name +
- " from " + track.album.name;
- };
-
- var queueAndPlayFirstPlaylist = function () {
- mopidy.playlists.getPlaylists().then(function (playlists) {
- var playlist = playlists[0];
- console.log("Loading playlist:", playlist.name);
- mopidy.tracklist.add(playlist.tracks).then(function (tlTracks) {
- mopidy.playback.play(tlTracks[0]).then(function () {
- mopidy.playback.getCurrentTrack().then(function (track) {
- console.log("Now playing:", trackDesc(track));
- }, consoleError);
- }, consoleError);
- }, consoleError);
- }, consoleError);
- };
-
- var mopidy = new Mopidy(); // Connect to server
- mopidy.on(console.log.bind(console)); // Log all events
- mopidy.on("state:online", queueAndPlayFirstPlaylist);
-
- Approximately the same behavior in a more functional style, using chaining
- of promisies.
-
- .. code-block:: js
-
- var consoleError = console.error.bind(console);
-
- var getFirst = function (list) {
- return list[0];
- };
-
- var extractTracks = function (playlist) {
- return playlist.tracks;
- };
-
- var printTypeAndName = function (model) {
- console.log(model.__model__ + ": " + model.name);
- // By returning the playlist, this function can be inserted
- // anywhere a model with a name is piped in the chain.
- return model;
- };
-
- var trackDesc = function (track) {
- return track.name + " by " + track.artists[0].name +
- " from " + track.album.name;
- };
-
- var printNowPlaying = function () {
- // By returning any arguments we get, the function can be inserted
- // anywhere in the chain.
- var args = arguments;
- return mopidy.playback.getCurrentTrack().then(function (track) {
- console.log("Now playing:", trackDesc(track));
- return args;
- });
- };
-
- var queueAndPlayFirstPlaylist = function () {
- mopidy.playlists.getPlaylists()
- // => list of Playlists
- .then(getFirst, consoleError)
- // => Playlist
- .then(printTypeAndName, consoleError)
- // => Playlist
- .then(extractTracks, consoleError)
- // => list of Tracks
- .then(mopidy.tracklist.add, consoleError)
- // => list of TlTracks
- .then(getFirst, consoleError)
- // => TlTrack
- .then(mopidy.playback.play, consoleError)
- // => null
- .then(printNowPlaying, consoleError);
- };
-
- var mopidy = new Mopidy(); // Connect to server
- mopidy.on(console.log.bind(console)); // Log all events
- mopidy.on("state:online", queueAndPlayFirstPlaylist);
-
-9. The web page should now queue and play your first playlist every time your
- load it. See the browser's console for output from the function, any errors,
- and all events that are emitted.
-""" % {'config': formatting.indent(default_config)}
class Extension(ext.Extension):
@@ -537,7 +13,8 @@ class Extension(ext.Extension):
version = mopidy.__version__
def get_default_config(self):
- return default_config
+ conf_file = os.path.join(os.path.dirname(__file__), 'ext.conf')
+ return open(conf_file).read()
def get_config_schema(self):
schema = config.ExtensionConfigSchema()
diff --git a/mopidy/frontends/http/ext.conf b/mopidy/frontends/http/ext.conf
new file mode 100644
index 00000000..8f8f2a1e
--- /dev/null
+++ b/mopidy/frontends/http/ext.conf
@@ -0,0 +1,8 @@
+[http]
+enabled = true
+hostname = 127.0.0.1
+port = 6680
+static_dir =
+
+[logging.levels]
+cherrypy = warning
diff --git a/mopidy/frontends/mpd/__init__.py b/mopidy/frontends/mpd/__init__.py
index a5e86de9..f108aec5 100644
--- a/mopidy/frontends/mpd/__init__.py
+++ b/mopidy/frontends/mpd/__init__.py
@@ -1,104 +1,9 @@
from __future__ import unicode_literals
+import os
+
import mopidy
from mopidy import config, ext
-from mopidy.utils import formatting
-
-
-default_config = """
-[mpd]
-enabled = true
-hostname = 127.0.0.1
-port = 6600
-password =
-max_connections = 20
-connection_timeout = 60
-"""
-
-__doc__ = """The MPD server frontend.
-
-MPD stands for Music Player Daemon. MPD is an independent project and server.
-Mopidy implements the MPD protocol, and is thus compatible with clients for the
-original MPD server.
-
-**Issues**
-
-https://github.com/mopidy/mopidy/issues?labels=MPD+frontend
-
-**Dependencies**
-
-None
-
-**Configuration**
-
-.. confval:: mpd/enabled
-
- If the MPD extension should be enabled or not.
-
-.. confval:: mpd/hostname
-
- Which address the MPD server should bind to.
-
- ``127.0.0.1``
- Listens only on the IPv4 loopback interface
- ``::1``
- Listens only on the IPv6 loopback interface
- ``0.0.0.0``
- Listens on all IPv4 interfaces
- ``::``
- Listens on all interfaces, both IPv4 and IPv6
-
-.. confval:: mpd/port
-
- Which TCP port the MPD server should listen to.
-
-.. confval:: mpd/password
-
- The password required for connecting to the MPD server. If blank, no
- password is required.
-
-.. confval:: mpd/max_connections
-
- The maximum number of concurrent connections the MPD server will accept.
-
-.. confval:: mpd/connection_timeout
-
- Number of seconds an MPD client can stay inactive before the connection is
- closed by the server.
-
-**Default config**
-
-.. code-block:: ini
-
-%(config)s
-
-**Usage:**
-
-The frontend is enabled by default.
-
-**Limitations:**
-
-This is a non exhaustive list of MPD features that Mopidy doesn't support.
-Items on this list will probably not be supported in the near future.
-
-- Toggling of audio outputs is not supported
-- Channels for client-to-client communication are not supported
-- Stickers are not supported
-- Crossfade is not supported
-- Replay gain is not supported
-- ``count`` does not provide any statistics
-- ``stats`` does not provide any statistics
-- ``list`` does not support listing tracks by genre
-- ``decoders`` does not provide information about available decoders
-
-The following items are currently not supported, but should be added in the
-near future:
-
-- Modifying stored playlists is not supported
-- ``tagtypes`` is not supported
-- Browsing the file system is not supported
-- Live update of the music database is not supported
-""" % {'config': formatting.indent(default_config)}
class Extension(ext.Extension):
@@ -108,7 +13,8 @@ class Extension(ext.Extension):
version = mopidy.__version__
def get_default_config(self):
- return default_config
+ conf_file = os.path.join(os.path.dirname(__file__), 'ext.conf')
+ return open(conf_file).read()
def get_config_schema(self):
schema = config.ExtensionConfigSchema()
diff --git a/mopidy/frontends/mpd/ext.conf b/mopidy/frontends/mpd/ext.conf
new file mode 100644
index 00000000..bf77100c
--- /dev/null
+++ b/mopidy/frontends/mpd/ext.conf
@@ -0,0 +1,7 @@
+[mpd]
+enabled = true
+hostname = 127.0.0.1
+port = 6600
+password =
+max_connections = 20
+connection_timeout = 60
diff --git a/mopidy/frontends/mpris/__init__.py b/mopidy/frontends/mpris/__init__.py
index d41f10fe..a2a6edf3 100644
--- a/mopidy/frontends/mpris/__init__.py
+++ b/mopidy/frontends/mpris/__init__.py
@@ -4,76 +4,6 @@ import os
import mopidy
from mopidy import config, exceptions, ext
-from mopidy.utils import formatting
-
-
-default_config = """
-[mpris]
-enabled = true
-desktop_file = /usr/share/applications/mopidy.desktop
-"""
-
-__doc__ = """
-Frontend which lets you control Mopidy through the Media Player Remote
-Interfacing Specification (`MPRIS `_) D-Bus
-interface.
-
-An example of an MPRIS client is the `Ubuntu Sound Menu
-`_.
-
-**Dependencies**
-
-- D-Bus Python bindings. The package is named ``python-dbus`` in
- Ubuntu/Debian.
-
-- ``libindicate`` Python bindings is needed to expose Mopidy in e.g. the
- Ubuntu Sound Menu. The package is named ``python-indicate`` in
- Ubuntu/Debian.
-
-- An ``.desktop`` file for Mopidy installed at the path set in the
- :confval:`mpris/desktop_file` config value. See :ref:`install-desktop-file`
- for details.
-
-**Configuration**
-
-.. confval:: mpris/enabled
-
- If the MPRIS extension should be enabled or not.
-
-.. confval:: mpris/desktop_file
-
- Location of the Mopidy ``.desktop`` file.
-
-**Default config**
-
-.. code-block:: ini
-
-%(config)s
-
-**Usage**
-
-The frontend is enabled by default if all dependencies are available.
-
-**Testing the frontend**
-
-To test, start Mopidy, and then run the following in a Python shell::
-
- import dbus
- bus = dbus.SessionBus()
- player = bus.get_object('org.mpris.MediaPlayer2.mopidy',
- '/org/mpris/MediaPlayer2')
-
-Now you can control Mopidy through the player object. Examples:
-
-- To get some properties from Mopidy, run::
-
- props = player.GetAll('org.mpris.MediaPlayer2',
- dbus_interface='org.freedesktop.DBus.Properties')
-
-- To quit Mopidy through D-Bus, run::
-
- player.Quit(dbus_interface='org.mpris.MediaPlayer2')
-""" % {'config': formatting.indent(default_config)}
class Extension(ext.Extension):
@@ -83,7 +13,8 @@ class Extension(ext.Extension):
version = mopidy.__version__
def get_default_config(self):
- return default_config
+ conf_file = os.path.join(os.path.dirname(__file__), 'ext.conf')
+ return open(conf_file).read()
def get_config_schema(self):
schema = config.ExtensionConfigSchema()
diff --git a/mopidy/frontends/mpris/ext.conf b/mopidy/frontends/mpris/ext.conf
new file mode 100644
index 00000000..b83411c2
--- /dev/null
+++ b/mopidy/frontends/mpris/ext.conf
@@ -0,0 +1,3 @@
+[mpris]
+enabled = true
+desktop_file = /usr/share/applications/mopidy.desktop
diff --git a/mopidy/frontends/scrobbler/__init__.py b/mopidy/frontends/scrobbler/__init__.py
index 55784c7e..0aa0bdc6 100644
--- a/mopidy/frontends/scrobbler/__init__.py
+++ b/mopidy/frontends/scrobbler/__init__.py
@@ -1,53 +1,9 @@
from __future__ import unicode_literals
+import os
+
import mopidy
from mopidy import config, exceptions, ext
-from mopidy.utils import formatting
-
-
-default_config = """
-[scrobbler]
-enabled = true
-username =
-password =
-"""
-
-__doc__ = """
-Frontend which scrobbles the music you play to your
-`Last.fm `_ profile.
-
-.. note::
-
- This frontend requires a free user account at Last.fm.
-
-**Dependencies**
-
-.. literalinclude:: ../../../requirements/scrobbler.txt
-
-**Configuration**
-
-.. confval:: scrobbler/enabled
-
- If the scrobbler extension should be enabled or not.
-
-.. confval:: scrobbler/username
-
- Your Last.fm username.
-
-.. confval:: scrobbler/password
-
- Your Last.fm password.
-
-**Default config**
-
-.. code-block:: ini
-
-%(config)s
-
-**Usage**
-
-The frontend is enabled by default if all dependencies are available.
-""" % {'config': formatting.indent(default_config)}
class Extension(ext.Extension):
@@ -57,7 +13,8 @@ class Extension(ext.Extension):
version = mopidy.__version__
def get_default_config(self):
- return default_config
+ conf_file = os.path.join(os.path.dirname(__file__), 'ext.conf')
+ return open(conf_file).read()
def get_config_schema(self):
schema = config.ExtensionConfigSchema()
diff --git a/mopidy/frontends/scrobbler/ext.conf b/mopidy/frontends/scrobbler/ext.conf
new file mode 100644
index 00000000..4fded92f
--- /dev/null
+++ b/mopidy/frontends/scrobbler/ext.conf
@@ -0,0 +1,4 @@
+[scrobbler]
+enabled = true
+username =
+password =
diff --git a/mopidy/scanner.py b/mopidy/scanner.py
index 0c78839b..d28d328a 100644
--- a/mopidy/scanner.py
+++ b/mopidy/scanner.py
@@ -154,8 +154,8 @@ class Scanner(object):
self.fakesink.connect('handoff', self.process_handoff)
self.uribin = gst.element_factory_make('uridecodebin')
- self.uribin.set_property('caps',
- gst.Caps(b'audio/x-raw-int; audio/x-raw-float'))
+ self.uribin.set_property(
+ 'caps', gst.Caps(b'audio/x-raw-int; audio/x-raw-float'))
self.uribin.connect('pad-added', self.process_new_pad)
self.pipe = gst.element_factory_make('pipeline')
diff --git a/mopidy/utils/log.py b/mopidy/utils/log.py
index db9a0c7c..ff593e09 100644
--- a/mopidy/utils/log.py
+++ b/mopidy/utils/log.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
import logging
import logging.handlers
-from . import deps, versioning
+from . import versioning
def setup_logging(config, verbosity_level, save_debug_log):
diff --git a/tests/exceptions_test.py b/tests/exceptions_test.py
index 12a18338..c1dd7634 100644
--- a/tests/exceptions_test.py
+++ b/tests/exceptions_test.py
@@ -29,7 +29,8 @@ class ExceptionsTest(unittest.TestCase):
exceptions.ConfigError, exceptions.MopidyException))
def test_config_error_provides_getitem(self):
- exception = exceptions.ConfigError({'field1': 'msg1', 'field2': 'msg2'})
+ exception = exceptions.ConfigError(
+ {'field1': 'msg1', 'field2': 'msg2'})
self.assertEqual('msg1', exception['field1'])
self.assertEqual('msg2', exception['field2'])
self.assertItemsEqual(['field1', 'field2'], exception)