Merge branch 'develop' into feature/reshuffle-config
Conflicts: mopidy/backends/local/__init__.py mopidy/backends/spotify/__init__.py mopidy/backends/stream/__init__.py mopidy/config.py mopidy/frontends/http/__init__.py mopidy/frontends/mpd/__init__.py mopidy/frontends/mpris/__init__.py mopidy/frontends/scrobbler/__init__.py mopidy/utils/config.py tests/config/types_test.py
This commit is contained in:
commit
1ebc265235
26
README.rst
26
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 <http://docs.mopidy.com/>`_.
|
||||
|
||||
@ -21,6 +19,10 @@ To get started with Mopidy, check out `the docs <http://docs.mopidy.com/>`_.
|
||||
- `Source code <https://github.com/mopidy/mopidy>`_
|
||||
- `Issue tracker <https://github.com/mopidy/mopidy/issues>`_
|
||||
- `CI server <https://travis-ci.org/mopidy/mopidy>`_
|
||||
- `Download development snapshot <https://github.com/mopidy/mopidy/tarball/develop#egg=mopidy-dev>`_
|
||||
|
||||
- IRC: ``#mopidy`` at `irc.freenode.net <http://freenode.net/>`_
|
||||
- Mailing list: `mopidy@googlegroups.com <https://groups.google.com/forum/?fromgroups=#!forum/mopidy>`_
|
||||
- `Download development snapshot <https://github.com/mopidy/mopidy/tarball/develop#egg=mopidy-dev>`_
|
||||
- Twitter: `@mopidy <https://twitter.com/mopidy/>`_
|
||||
|
||||
.. image:: https://secure.travis-ci.org/mopidy/mopidy.png?branch=develop
|
||||
|
||||
@ -13,9 +13,12 @@ The following requirements applies to any frontend implementation:
|
||||
<http://pykka.readthedocs.org/>`_ actor, called the "main actor" from here
|
||||
on.
|
||||
|
||||
- The main actor MUST accept a constructor argument ``core``, which will be an
|
||||
:class:`ActorProxy <pykka.proxy.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 <pykka.proxy.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.
|
||||
|
||||
439
docs/api/http.rst
Normal file
439
docs/api/http.rst
Normal file
@ -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 <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
|
||||
<http://www.jsonrpc.org/specification>`_.
|
||||
|
||||
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
|
||||
|
||||
<script type="text/javascript" src="/mopidy/mopidy.min.js"></script>
|
||||
|
||||
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
|
||||
<https://github.com/busterjs/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
|
||||
<http://wiki.commonjs.org/wiki/Promises/A>`_ standard. We use the
|
||||
implementation known as `when.js <https://github.com/cujojs/when>`_. 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
|
||||
|
||||
<script type="text/javascript" src="/mopidy/mopidy.min.js"></script>
|
||||
|
||||
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.
|
||||
|
||||
@ -11,3 +11,4 @@ API reference
|
||||
core
|
||||
audio
|
||||
frontends
|
||||
http
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
@ -4,14 +4,14 @@
|
||||
HTTP clients
|
||||
************
|
||||
|
||||
Mopidy added an :ref:`HTTP frontend <http-frontend>` in 0.10 which provides the
|
||||
Mopidy added an :ref:`HTTP frontend <ext-http>` 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
|
||||
|
||||
@ -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 <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 <ext-mpris>` 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:
|
||||
|
||||
@ -37,18 +37,18 @@ How to make Mopidy available as an UPnP MediaRenderer
|
||||
|
||||
With the help of `the Rygel project <https://live.gnome.org/Rygel>`_ Mopidy can
|
||||
be made available as an UPnP MediaRenderer. Rygel will interface with Mopidy's
|
||||
:ref:`MPRIS frontend <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 <ext-mpris>`, 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 <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 <mpris-frontend>` page.
|
||||
1. Start Mopidy and make sure the :ref:`MPRIS frontend <ext-mpris>` 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 <ext-mpris>` page.
|
||||
|
||||
2. Install Rygel. On Debian/Ubuntu::
|
||||
|
||||
|
||||
65
docs/codestyle.rst
Normal file
65
docs/codestyle.rst
Normal file
@ -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
|
||||
<http://pypi.python.org/pypi/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.
|
||||
251
docs/config.rst
251
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
|
||||
<ext>` got additional config values. The extension's config values and config
|
||||
defaults are documented on the :ref:`extension pages <ext>`.
|
||||
|
||||
|
||||
.. _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
|
||||
<http://www.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
|
||||
<https://wiki.ubuntu.com/SoundMenu>`_ 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 <http://www.mpris.org/>`_. 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
|
||||
<http://docs.python.org/2/library/logging.html#formatter-objects>`_ for
|
||||
details on the format.
|
||||
|
||||
.. confval:: logging/debug_format
|
||||
|
||||
The log format used for debug logging.
|
||||
|
||||
See `the Python logging docs
|
||||
<http://docs.python.org/2/library/logging.html#formatter-objects>`_ 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
|
||||
|
||||
116
docs/contributing.rst
Normal file
116
docs/contributing.rst
Normal file
@ -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 <https://github.com/signup/free>`_.
|
||||
|
||||
2. `Submit <https://github.com/mopidy/mopidy/issues/new>`_ 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
|
||||
<http://nose.readthedocs.org/>`_.
|
||||
|
||||
|
||||
Submitting changes
|
||||
==================
|
||||
|
||||
- One branch per feature or fix. Keep branches small and on topic.
|
||||
|
||||
- Follow the :ref:`style guide <codestyle>`_, 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 <http://freenode.net/>`_
|
||||
|
||||
- `Issue tracker <https://github.com/mopidy/mopidy/issues>`_
|
||||
|
||||
- `Mailing List <https://groups.google.com/forum/?fromgroups=#!forum/mopidy>`_
|
||||
|
||||
- `General GitHub documentation <https://help.github.com/>`_
|
||||
|
||||
- `GitHub pull request documentation
|
||||
<https://help.github.com/articles/using-pull-requests>`_
|
||||
@ -1,360 +0,0 @@
|
||||
***********
|
||||
Development
|
||||
***********
|
||||
|
||||
Development of Mopidy is coordinated through the IRC channel ``#mopidy`` at
|
||||
``irc.freenode.net`` and through `GitHub <https://github.com/>`_.
|
||||
|
||||
|
||||
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 <https://github.com/mopidy/mopidy/issues>`_ at GitHub
|
||||
labeled with `the "wishlist" label
|
||||
<https://github.com/mopidy/mopidy/issues?labels=wishlist>`_. 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 <http://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
|
||||
<http://pypi.python.org/pypi/pep8/>`_ or `flake8
|
||||
<http://pypi.python.org/pypi/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 <http://nvie.com/posts/a-successful-git-branching-model/>`_.
|
||||
|
||||
- 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
|
||||
<http://nose.readthedocs.org/>`_.
|
||||
|
||||
|
||||
Continuous integration
|
||||
======================
|
||||
|
||||
Mopidy uses the free service `Travis CI <https://travis-ci.org/mopidy/mopidy>`_
|
||||
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 <http://sphinx-doc.org/>`_. 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.
|
||||
120
docs/devtools.rst
Normal file
120
docs/devtools.rst
Normal file
@ -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 <https://travis-ci.org/mopidy/mopidy>`_
|
||||
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 <http://sphinx-doc.org/>`_. 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.
|
||||
103
docs/ext/http.rst
Normal file
103
docs/ext/http.rst
Normal file
@ -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`.
|
||||
44
docs/ext/index.rst
Normal file
44
docs/ext/index.rst
Normal file
@ -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 <extensiondev>`.
|
||||
|
||||
|
||||
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
|
||||
<http://www.soundcloud.com/>`_ service.
|
||||
|
||||
Author:
|
||||
Janez Troha
|
||||
PyPI:
|
||||
`Mopidy-SoundCloud <https://pypi.python.org/pypi/Mopidy-SoundCloud>`_
|
||||
GitHub:
|
||||
`dz0ny/mopidy-soundcloud <https://github.com/dz0ny/mopidy-soundcloud>`_
|
||||
86
docs/ext/local.rst
Normal file
86
docs/ext/local.rst
Normal file
@ -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!
|
||||
123
docs/ext/mpd.rst
Normal file
123
docs/ext/mpd.rst
Normal file
@ -0,0 +1,123 @@
|
||||
.. _ext-mpd:
|
||||
|
||||
**********
|
||||
Mopidy-MPD
|
||||
**********
|
||||
|
||||
This extension implements an MPD server to make Mopidy available to :ref:`MPD
|
||||
clients <mpd-clients>`.
|
||||
|
||||
MPD stands for Music Player Daemon, which is also the name of the `original MPD
|
||||
server project <http://mpd.wikia.com/>`_. 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 <mpd-clients>`.
|
||||
|
||||
|
||||
.. _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.
|
||||
105
docs/ext/mpris.rst
Normal file
105
docs/ext/mpris.rst
Normal file
@ -0,0 +1,105 @@
|
||||
.. _ext-mpris:
|
||||
|
||||
************
|
||||
Mopidy-MPRIS
|
||||
************
|
||||
|
||||
This extension lets you control Mopidy through the Media Player Remote
|
||||
Interfacing Specification (`MPRIS <http://www.mpris.org/>`_) 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
|
||||
<http://www.mpris.org/>`_. 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
|
||||
<http://www.mpris.org/>`_.
|
||||
53
docs/ext/scrobbler.rst
Normal file
53
docs/ext/scrobbler.rst
Normal file
@ -0,0 +1,53 @@
|
||||
****************
|
||||
Mopidy-Scrobbler
|
||||
****************
|
||||
|
||||
This extension scrobbles the music you play to your `Last.fm
|
||||
<http://www.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
|
||||
83
docs/ext/spotify.rst
Normal file
83
docs/ext/spotify.rst
Normal file
@ -0,0 +1,83 @@
|
||||
.. _ext-spotify:
|
||||
|
||||
**************
|
||||
Mopidy-Spotify
|
||||
**************
|
||||
|
||||
An extension for playing music from Spotify.
|
||||
|
||||
`Spotify <http://www.spotify.com/>`_ is a music streaming service. The backend
|
||||
uses the official `libspotify
|
||||
<http://developer.spotify.com/en/libspotify/overview/>`_ library and the
|
||||
`pyspotify <http://github.com/mopidy/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.
|
||||
56
docs/ext/stream.rst
Normal file
56
docs/ext/stream.rst
Normal file
@ -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.
|
||||
@ -2,56 +2,71 @@
|
||||
Mopidy
|
||||
******
|
||||
|
||||
Mopidy is a music server which can play music both from your :ref:`local hard
|
||||
drive <local-backend>` and from :ref:`Spotify <spotify-backend>`. 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 <ext-local>`, :ref:`radio streams <ext-stream>`,
|
||||
and from :ref:`Spotify <ext-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
|
||||
<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>`. 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 <http-clients>`, the :ref:`Ubuntu Sound Menu <ubuntu-sound-menu>`, any
|
||||
device on the same network which can control :ref:`UPnP MediaRenderers
|
||||
<upnp-clients>`, or any :ref:`MPD client <mpd-clients>`. 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
|
||||
<http://freenode.net/>`_ and also got a `mailing list at Google Groups
|
||||
<http://freenode.net/>`_ and also have a `mailing list at Google Groups
|
||||
<https://groups.google.com/forum/?fromgroups=#!forum/mopidy>`_. If you stumble
|
||||
into a bug or got a feature request, please create an issue in the `issue
|
||||
tracker <https://github.com/mopidy/mopidy/issues>`_.
|
||||
tracker <https://github.com/mopidy/mopidy/issues>`_. The `source code
|
||||
<https://github.com/mopidy/mopidy>`_ may also be of help. If you want to stay
|
||||
up to date on Mopidy developments, you can follow `@mopidy
|
||||
<https://twitter.com/mopidy/>`_ on Twitter.
|
||||
|
||||
|
||||
Project resources
|
||||
=================
|
||||
|
||||
- `Documentation <http://docs.mopidy.com/>`_
|
||||
- `Source code <https://github.com/mopidy/mopidy>`_
|
||||
- `Issue tracker <https://github.com/mopidy/mopidy/issues>`_
|
||||
- `CI server <https://travis-ci.org/mopidy/mopidy>`_
|
||||
- IRC: ``#mopidy`` at `irc.freenode.net <http://freenode.net/>`_
|
||||
- Mailing list: `mopidy@googlegroups.com <https://groups.google.com/forum/?fromgroups=#!forum/mopidy>`_
|
||||
|
||||
|
||||
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
|
||||
==================
|
||||
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
*********************************************************
|
||||
:mod:`mopidy.backends.dummy` -- Dummy backend for testing
|
||||
*********************************************************
|
||||
|
||||
.. automodule:: mopidy.backends.dummy
|
||||
:synopsis: Dummy backend used for testing
|
||||
:members:
|
||||
@ -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
|
||||
@ -1,8 +0,0 @@
|
||||
.. _spotify-backend:
|
||||
|
||||
*************************************************
|
||||
:mod:`mopidy.backends.spotify` -- Spotify backend
|
||||
*************************************************
|
||||
|
||||
.. automodule:: mopidy.backends.spotify
|
||||
:synopsis: Backend for the Spotify music streaming service
|
||||
@ -1,7 +0,0 @@
|
||||
***********************************************
|
||||
:mod:`mopidy.backends.stream` -- Stream backend
|
||||
***********************************************
|
||||
|
||||
.. automodule:: mopidy.backends.stream
|
||||
:synopsis: Backend for playing audio streams
|
||||
:members:
|
||||
@ -1,8 +0,0 @@
|
||||
.. _http-frontend:
|
||||
|
||||
*********************************************
|
||||
:mod:`mopidy.frontends.http` -- HTTP frontend
|
||||
*********************************************
|
||||
|
||||
.. automodule:: mopidy.frontends.http
|
||||
:synopsis: HTTP and WebSockets frontend
|
||||
@ -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
|
||||
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
.. _mpris-frontend:
|
||||
|
||||
***********************************************
|
||||
:mod:`mopidy.frontends.mpris` -- MPRIS frontend
|
||||
***********************************************
|
||||
|
||||
.. automodule:: mopidy.frontends.mpris
|
||||
:synopsis: MPRIS frontend
|
||||
@ -1,6 +0,0 @@
|
||||
***********************************************
|
||||
:mod:`mopidy.frontends.scrobbler` -- Scrobbler
|
||||
***********************************************
|
||||
|
||||
.. automodule:: mopidy.frontends.scrobbler
|
||||
:synopsis: Music scrobbler frontend
|
||||
58
docs/troubleshooting.rst
Normal file
58
docs/troubleshooting.rst
Normal file
@ -0,0 +1,58 @@
|
||||
.. _troubleshooting:
|
||||
|
||||
***************
|
||||
Troubleshooting
|
||||
***************
|
||||
|
||||
If you run into problems with Mopidy, we usually hang around at ``#mopidy`` at
|
||||
`irc.freenode.net <http://freenode.net/>`_ and also have a `mailing list at
|
||||
Google Groups <https://groups.google.com/forum/?fromgroups=#!forum/mopidy>`_.
|
||||
If you stumble into a bug or got a feature request, please create an issue in
|
||||
the `issue tracker <https://github.com/mopidy/mopidy/issues>`_.
|
||||
|
||||
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
|
||||
23
docs/versioning.rst
Normal file
23
docs/versioning.rst
Normal file
@ -0,0 +1,23 @@
|
||||
**********
|
||||
Versioning
|
||||
**********
|
||||
|
||||
Mopidy uses `Semantic Versioning <http://semver.org/>`_, 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.
|
||||
@ -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
|
||||
|
||||
@ -26,15 +26,6 @@ MB = 1 << 20
|
||||
class Audio(pykka.ThreadingActor):
|
||||
"""
|
||||
Audio output through `GStreamer <http://gstreamer.freedesktop.org/>`_.
|
||||
|
||||
**Default config:**
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[audio]
|
||||
mixer = autoaudiomixer
|
||||
mixer_track =
|
||||
output = autoaudiosink
|
||||
"""
|
||||
|
||||
#: The GStreamer state mapped to :class:`mopidy.audio.PlaybackState`
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
5
mopidy/backends/local/ext.conf
Normal file
5
mopidy/backends/local/ext.conf
Normal file
@ -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
|
||||
@ -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 <http://www.spotify.com/>`_ is a music streaming service. The backend
|
||||
uses the official `libspotify
|
||||
<http://developer.spotify.com/en/libspotify/overview/>`_ library and the
|
||||
`pyspotify <http://github.com/mopidy/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()
|
||||
|
||||
7
mopidy/backends/spotify/ext.conf
Normal file
7
mopidy/backends/spotify/ext.conf
Normal file
@ -0,0 +1,7 @@
|
||||
[spotify]
|
||||
enabled = true
|
||||
username =
|
||||
password =
|
||||
bitrate = 160
|
||||
timeout = 10
|
||||
cache_dir = $XDG_CACHE_DIR/mopidy/spotify
|
||||
@ -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()
|
||||
|
||||
9
mopidy/backends/stream/ext.conf
Normal file
9
mopidy/backends/stream/ext.conf
Normal file
@ -0,0 +1,9 @@
|
||||
[stream]
|
||||
enabled = true
|
||||
protocols =
|
||||
http
|
||||
https
|
||||
mms
|
||||
rtmp
|
||||
rtmps
|
||||
rtsp
|
||||
17
mopidy/default.conf
Normal file
17
mopidy/default.conf
Normal file
@ -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 =
|
||||
@ -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
|
||||
<http://www.jsonrpc.org/specification>`_.
|
||||
|
||||
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
|
||||
|
||||
<script type="text/javascript" src="/mopidy/mopidy.min.js"></script>
|
||||
|
||||
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
|
||||
<https://github.com/busterjs/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
|
||||
<http://wiki.commonjs.org/wiki/Promises/A>`_ standard. We use the
|
||||
implementation known as `when.js <https://github.com/cujojs/when>`_. 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
|
||||
|
||||
<script type="text/javascript" src="/mopidy/mopidy.min.js"></script>
|
||||
|
||||
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()
|
||||
|
||||
8
mopidy/frontends/http/ext.conf
Normal file
8
mopidy/frontends/http/ext.conf
Normal file
@ -0,0 +1,8 @@
|
||||
[http]
|
||||
enabled = true
|
||||
hostname = 127.0.0.1
|
||||
port = 6680
|
||||
static_dir =
|
||||
|
||||
[logging.levels]
|
||||
cherrypy = warning
|
||||
@ -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()
|
||||
|
||||
7
mopidy/frontends/mpd/ext.conf
Normal file
7
mopidy/frontends/mpd/ext.conf
Normal file
@ -0,0 +1,7 @@
|
||||
[mpd]
|
||||
enabled = true
|
||||
hostname = 127.0.0.1
|
||||
port = 6600
|
||||
password =
|
||||
max_connections = 20
|
||||
connection_timeout = 60
|
||||
@ -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 <http://www.mpris.org/>`_) D-Bus
|
||||
interface.
|
||||
|
||||
An example of an MPRIS client is the `Ubuntu Sound Menu
|
||||
<https://wiki.ubuntu.com/SoundMenu>`_.
|
||||
|
||||
**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()
|
||||
|
||||
3
mopidy/frontends/mpris/ext.conf
Normal file
3
mopidy/frontends/mpris/ext.conf
Normal file
@ -0,0 +1,3 @@
|
||||
[mpris]
|
||||
enabled = true
|
||||
desktop_file = /usr/share/applications/mopidy.desktop
|
||||
@ -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 <http://www.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()
|
||||
|
||||
4
mopidy/frontends/scrobbler/ext.conf
Normal file
4
mopidy/frontends/scrobbler/ext.conf
Normal file
@ -0,0 +1,4 @@
|
||||
[scrobbler]
|
||||
enabled = true
|
||||
username =
|
||||
password =
|
||||
@ -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')
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user