diff --git a/.gitignore b/.gitignore index 9229541f..6ef1ff32 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.egg-info *.pyc *.swp .coverage diff --git a/.mailmap b/.mailmap index 93a4aed1..b38c3f66 100644 --- a/.mailmap +++ b/.mailmap @@ -1,5 +1,6 @@ Thomas Adamcik Thomas Adamcik +Thomas Adamcik Thomas Adacmik Kristian Klette Johannes Knutsen Johannes Knutsen diff --git a/AUTHORS b/AUTHORS index d6ede848..87925152 100644 --- a/AUTHORS +++ b/AUTHORS @@ -18,3 +18,4 @@ - herrernst - Nick Steel - Zan Dobersek +- Thomas Refis diff --git a/MANIFEST.in b/MANIFEST.in index 6a64cb9a..6385e4ff 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,13 +1,15 @@ -include *.ini include *.rst include LICENSE include MANIFEST.in include data/mopidy.desktop include mopidy/backends/spotify/spotify_appkey.key include pylintrc + recursive-include docs * prune docs/_build -recursive-include mopidy/frontends/http/data/ + +recursive-include mopidy *.conf +recursive-include mopidy/frontends/http/data * recursive-include requirements * recursive-include tests *.py recursive-include tests/data * diff --git a/README.rst b/README.rst index 8598b153..f667b7db 100644 --- a/README.rst +++ b/README.rst @@ -2,25 +2,27 @@ 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 `_. - `Documentation `_ -- `Source code `_ -- `Issue tracker `_ -- `CI server `_ +- `Source code `_ +- `Issue tracker `_ +- `CI server `_ +- `Download development snapshot `_ + - IRC: ``#mopidy`` at `irc.freenode.net `_ - Mailing list: `mopidy@googlegroups.com `_ -- `Download development snapshot `_ +- Twitter: `@mopidy `_ + +.. image:: https://secure.travis-ci.org/mopidy/mopidy.png?branch=develop diff --git a/bin/mopidy b/bin/mopidy deleted file mode 100755 index 0472518e..00000000 --- a/bin/mopidy +++ /dev/null @@ -1,5 +0,0 @@ -#! /usr/bin/env python - -if __name__ == '__main__': - from mopidy.__main__ import main - main() diff --git a/bin/mopidy-scan b/bin/mopidy-scan deleted file mode 100755 index 00f51809..00000000 --- a/bin/mopidy-scan +++ /dev/null @@ -1,5 +0,0 @@ -#! /usr/bin/env python - -if __name__ == '__main__': - from mopidy.scanner import main - main() diff --git a/docs/api/backends.rst b/docs/api/backends.rst index 32c04d37..45315b27 100644 --- a/docs/api/backends.rst +++ b/docs/api/backends.rst @@ -12,6 +12,13 @@ backend. If you are working on a frontend and need to access the backend, see the :ref:`core-api`. +Backend class +============= + +.. autoclass:: mopidy.backends.base.Backend + :members: + + Playback provider ================= diff --git a/docs/api/config.rst b/docs/api/config.rst new file mode 100644 index 00000000..8b005a9d --- /dev/null +++ b/docs/api/config.rst @@ -0,0 +1,33 @@ +.. _config-api: + +********** +Config API +********** + +.. automodule:: mopidy.config + :synopsis: Config API for config loading and validation + :members: + + +Config section schemas +====================== + +.. automodule:: mopidy.config.schemas + :synopsis: Config section validation schemas + :members: + + +Config value types +================== + +.. automodule:: mopidy.config.types + :synopsis: Config value validation types + :members: + + +Config value validators +======================= + +.. automodule:: mopidy.config.validators + :synopsis: Config value validators + :members: diff --git a/docs/api/ext.rst b/docs/api/ext.rst new file mode 100644 index 00000000..11908920 --- /dev/null +++ b/docs/api/ext.rst @@ -0,0 +1,11 @@ +.. _ext-api: + +************* +Extension API +************* + +If you want to learn how to make Mopidy extensions, read :ref:`extensiondev`. + +.. automodule:: mopidy.ext + :synopsis: Extension API for extending Mopidy + :members: diff --git a/docs/api/frontends.rst b/docs/api/frontends.rst index 8488b408..6da5d337 100644 --- a/docs/api/frontends.rst +++ b/docs/api/frontends.rst @@ -13,15 +13,18 @@ The following requirements applies to any frontend implementation: `_ actor, called the "main actor" from here on. -- The main actor MUST accept a constructor argument ``core``, which will be an - :class:`ActorProxy ` for the core actor. This object - gives access to the full :ref:`core-api`. +- The main actor MUST accept two constructor arguments: + + - ``config``, which is a dict structure with the entire Mopidy configuration. + + - ``core``, which will be an :class:`ActorProxy ` for + the core actor. This object gives access to the full :ref:`core-api`. - It MAY use additional actors to implement whatever it does, and using actors in frontend implementations is encouraged. -- The frontend is activated by including its main actor in the - :attr:`mopidy.settings.FRONTENDS` setting. +- The frontend is enabled if the extension it is part of is enabled. See + :ref:`extensiondev` for more information. - The main actor MUST be able to start and stop the frontend when the main actor is started and stopped. @@ -45,6 +48,6 @@ Frontend implementations ======================== * :mod:`mopidy.frontends.http` -* :mod:`mopidy.frontends.lastfm` * :mod:`mopidy.frontends.mpd` * :mod:`mopidy.frontends.mpris` +* :mod:`mopidy.frontends.scrobbler` diff --git a/docs/api/http.rst b/docs/api/http.rst new file mode 100644 index 00000000..16546683 --- /dev/null +++ b/docs/api/http.rst @@ -0,0 +1,439 @@ +.. _http-api: + +******** +HTTP API +******** + +The :ref:`ext-http` extension makes Mopidy's :ref:`core-api` available over +HTTP using WebSockets. We also provide a JavaScript wrapper, called +:ref:`Mopidy.js ` around the HTTP API for use both from browsers and +Node.js. + +.. warning:: API stability + + Since the HTTP API exposes our internal core API directly it is to be + regarded as **experimental**. We cannot promise to keep any form of + backwards compatibility between releases as we will need to change the core + API while working out how to support new use cases. Thus, if you use this + API, you must expect to do small adjustments to your client for every + release of Mopidy. + + From Mopidy 1.0 and onwards, we intend to keep the core API far more + stable. + + +.. _websocket-api: + +WebSocket API +============= + +The web server exposes a WebSocket at ``/mopidy/ws/``. The WebSocket gives you +access to Mopidy's full API and enables Mopidy to instantly push events to the +client, as they happen. + +On the WebSocket we send two different kind of messages: The client can send +JSON-RPC 2.0 requests, and the server will respond with JSON-RPC 2.0 responses. +In addition, the server will send event messages when something happens on the +server. Both message types are encoded as JSON objects. + + +Event messages +-------------- + +Event objects will always have a key named ``event`` whose value is the event +type. Depending on the event type, the event may include additional fields for +related data. The events maps directly to the :class:`mopidy.core.CoreListener` +API. Refer to the ``CoreListener`` method names is the available event types. +The ``CoreListener`` method's keyword arguments are all included as extra +fields on the event objects. Example event message:: + + {"event": "track_playback_started", "track": {...}} + + +JSON-RPC 2.0 messaging +---------------------- + +JSON-RPC 2.0 messages can be recognized by checking for the key named +``jsonrpc`` with the string value ``2.0``. For details on the messaging format, +please refer to the `JSON-RPC 2.0 spec +`_. + +All methods (not attributes) in the :ref:`core-api` is made available through +JSON-RPC calls over the WebSocket. For example, +:meth:`mopidy.core.PlaybackController.play` is available as the JSON-RPC method +``core.playback.play``. + +The core API's attributes is made available through setters and getters. For +example, the attribute :attr:`mopidy.core.PlaybackController.current_track` is +available as the JSON-RPC method ``core.playback.get_current_track``. + +Example JSON-RPC request:: + + {"jsonrpc": "2.0", "id": 1, "method": "core.playback.get_current_track"} + +Example JSON-RPC response:: + + {"jsonrpc": "2.0", "id": 1, "result": {"__model__": "Track", "...": "..."}} + +The JSON-RPC method ``core.describe`` returns a data structure describing all +available methods. If you're unsure how the core API maps to JSON-RPC, having a +look at the ``core.describe`` response can be helpful. + + +.. _mopidy-js: + +Mopidy.js JavaScript library +============================ + +We've made a JavaScript library, Mopidy.js, which wraps the WebSocket and gets +you quickly started with working on your client instead of figuring out how to +communicate with Mopidy. + + +Getting the library for browser use +----------------------------------- + +Regular and minified versions of Mopidy.js, ready for use, is installed +together with Mopidy. When the HTTP extension is enabled, the files are +available at: + +- http://localhost:6680/mopidy/mopidy.js +- http://localhost:6680/mopidy/mopidy.min.js + +You may need to adjust hostname and port for your local setup. + +Thus, if you use Mopidy to host your web client, like described above, you can +load the latest version of Mopidy.js by adding the following script tag to your +HTML file: + +.. code-block:: html + + + +If you don't use Mopidy to host your web client, you can find the JS files in +the Git repo at: + +- ``mopidy/frontends/http/data/mopidy.js`` +- ``mopidy/frontends/http/data/mopidy.min.js`` + + +Getting the library for Node.js use +----------------------------------- + +If you want to use Mopidy.js from Node.js instead of a browser, you can install +Mopidy.js using npm:: + + npm install mopidy + +After npm completes, you can import Mopidy.js using ``require()``: + +.. code-block:: js + + var Mopidy = require("mopidy").Mopidy; + + +Getting the library for development on the library +-------------------------------------------------- + +If you want to work on the Mopidy.js library itself, you'll find a complete +development setup in the ``js/`` dir in our repo. The instructions in +``js/README.md`` will guide you on your way. + + +Creating an instance +-------------------- + +Once you got Mopidy.js loaded, you need to create an instance of the wrapper: + +.. code-block:: js + + var mopidy = new Mopidy(); + +When you instantiate ``Mopidy()`` without arguments, it will connect to +the WebSocket at ``/mopidy/ws/`` on the current host. Thus, if you don't host +your web client using Mopidy's web server, or if you use Mopidy.js from a +Node.js environment, you'll need to pass the URL to the WebSocket end point: + +.. code-block:: js + + var mopidy = new Mopidy({ + webSocketUrl: "ws://localhost:6680/mopidy/ws/" + }); + +It is also possible to create an instance first and connect to the WebSocket +later: + +.. code-block:: js + + var mopidy = new Mopidy({autoConnect: false}); + // ... do other stuff, like hooking up events ... + mopidy.connect(); + + +Hooking up to events +-------------------- + +Once you have a Mopidy.js object, you can hook up to the events it emits. To +explore your possibilities, it can be useful to subscribe to all events and log +them: + +.. code-block:: js + + mopidy.on(console.log.bind(console)); + +Several types of events are emitted: + +- You can get notified about when the Mopidy.js object is connected to the + server and ready for method calls, when it's offline, and when it's trying to + reconnect to the server by looking at the events ``state:online``, + ``state:offline``, ``reconnectionPending``, and ``reconnecting``. + +- You can get events sent from the Mopidy server by looking at the events with + the name prefix ``event:``, like ``event:trackPlaybackStarted``. + +- You can introspect what happens internally on the WebSocket by looking at the + events emitted with the name prefix ``websocket:``. + +Mopidy.js uses the event emitter library `BANE +`_, so you should refer to BANE's +short API documentation to see how you can hook up your listeners to the +different events. + + +Calling core API methods +------------------------ + +Once your Mopidy.js object has connected to the Mopidy server and emits the +``state:online`` event, it is ready to accept core API method calls: + +.. code-block:: js + + mopidy.on("state:online", function () { + mopidy.playback.next(); + }); + +Any calls you make before the ``state:online`` event is emitted will fail. If +you've hooked up an errback (more on that a bit later) to the promise returned +from the call, the errback will be called with an error message. + +All methods in Mopidy's :ref:`core-api` is available via Mopidy.js. The core +API attributes is *not* available, but that shouldn't be a problem as we've +added (undocumented) getters and setters for all of them, so you can access the +attributes as well from JavaScript. + +Both the WebSocket API and the JavaScript API are based on introspection of the +core Python API. Thus, they will always be up to date and immediately reflect +any changes we do to the core API. + +The best way to explore the JavaScript API, is probably by opening your +browser's console, and using its tab completion to navigate the API. You'll +find the Mopidy core API exposed under ``mopidy.playback``, +``mopidy.tracklist``, ``mopidy.playlists``, and ``mopidy.library``. + +All methods in the JavaScript API have an associated data structure describing +the Python params it expects, and most methods also have the Python API +documentation available. This is available right there in the browser console, +by looking at the method's ``description`` and ``params`` attributes: + +.. code-block:: js + + console.log(mopidy.playback.next.params); + console.log(mopidy.playback.next.description); + +JSON-RPC 2.0 limits method parameters to be sent *either* by-position or +by-name. Combinations of both, like we're used to from Python, isn't supported +by JSON-RPC 2.0. To further limit this, Mopidy.js currently only supports +passing parameters by-position. + +Obviously, you'll want to get a return value from many of your method calls. +Since everything is happening across the WebSocket and maybe even across the +network, you'll get the results asynchronously. Instead of having to pass +callbacks and errbacks to every method you call, the methods return "promise" +objects, which you can use to pipe the future result as input to another +method, or to hook up callback and errback functions. + +.. code-block:: js + + var track = mopidy.playback.getCurrentTrack(); + // => ``track`` isn't a track, but a "promise" object + +Instead, typical usage will look like this: + +.. code-block:: js + + var printCurrentTrack = function (track) { + if (track) { + console.log("Currently playing:", track.name, "by", + track.artists[0].name, "from", track.album.name); + } else { + console.log("No current track"); + } + }; + + mopidy.playback.getCurrentTrack().then( + printCurrentTrack, console.error.bind(console)); + +The first function passed to ``then()``, ``printCurrentTrack``, is the callback +that will be called if the method call succeeds. The second function, +``console.error``, is the errback that will be called if anything goes wrong. +If you don't hook up an errback, debugging will be hard as errors will silently +go missing. + +For debugging, you may be interested in errors from function without +interesting return values as well. In that case, you can pass ``null`` as the +callback: + +.. code-block:: js + + mopidy.playback.next().then(null, console.error.bind(console)); + +The promise objects returned by Mopidy.js adheres to the `CommonJS Promises/A +`_ standard. We use the +implementation known as `when.js `_. Please +refer to when.js' documentation or the standard for further details on how to +work with promise objects. + + +Cleaning up +----------- + +If you for some reason want to clean up after Mopidy.js before the web page is +closed or navigated away from, you can close the WebSocket, unregister all +event listeners, and delete the object like this: + +.. code-block:: js + + // Close the WebSocket without reconnecting. Letting the object be garbage + // collected will have the same effect, so this isn't strictly necessary. + mopidy.close(); + + // Unregister all event listeners. If you don't do this, you may have + // lingering references to the object causing the garbage collector to not + // clean up after it. + mopidy.off(); + + // Delete your reference to the object, so it can be garbage collected. + mopidy = null; + + +Example to get started with +--------------------------- + +1. Make sure that you've installed all dependencies required by + :ref:`ext-http`. + +2. Create an empty directory for your web client. + +3. Change the :confval:`http/static_dir` config value to point to your new + directory. + +4. Start/restart Mopidy. + +5. Create a file in the directory named ``index.html`` containing e.g. "Hello, + world!". + +6. Visit http://localhost:6680/ to confirm that you can view your new HTML file + there. + +7. Include Mopidy.js in your web page: + + .. code-block:: html + + + +8. Add one of the following Mopidy.js examples of how to queue and start + playback of your first playlist either to your web page or a JavaScript file + that you include in your web page. + + "Imperative" style: + + .. code-block:: js + + var consoleError = console.error.bind(console); + + var trackDesc = function (track) { + return track.name + " by " + track.artists[0].name + + " from " + track.album.name; + }; + + var queueAndPlayFirstPlaylist = function () { + mopidy.playlists.getPlaylists().then(function (playlists) { + var playlist = playlists[0]; + console.log("Loading playlist:", playlist.name); + mopidy.tracklist.add(playlist.tracks).then(function (tlTracks) { + mopidy.playback.play(tlTracks[0]).then(function () { + mopidy.playback.getCurrentTrack().then(function (track) { + console.log("Now playing:", trackDesc(track)); + }, consoleError); + }, consoleError); + }, consoleError); + }, consoleError); + }; + + var mopidy = new Mopidy(); // Connect to server + mopidy.on(console.log.bind(console)); // Log all events + mopidy.on("state:online", queueAndPlayFirstPlaylist); + + Approximately the same behavior in a more functional style, using chaining + of promisies. + + .. code-block:: js + + var consoleError = console.error.bind(console); + + var getFirst = function (list) { + return list[0]; + }; + + var extractTracks = function (playlist) { + return playlist.tracks; + }; + + var printTypeAndName = function (model) { + console.log(model.__model__ + ": " + model.name); + // By returning the playlist, this function can be inserted + // anywhere a model with a name is piped in the chain. + return model; + }; + + var trackDesc = function (track) { + return track.name + " by " + track.artists[0].name + + " from " + track.album.name; + }; + + var printNowPlaying = function () { + // By returning any arguments we get, the function can be inserted + // anywhere in the chain. + var args = arguments; + return mopidy.playback.getCurrentTrack().then(function (track) { + console.log("Now playing:", trackDesc(track)); + return args; + }); + }; + + var queueAndPlayFirstPlaylist = function () { + mopidy.playlists.getPlaylists() + // => list of Playlists + .then(getFirst, consoleError) + // => Playlist + .then(printTypeAndName, consoleError) + // => Playlist + .then(extractTracks, consoleError) + // => list of Tracks + .then(mopidy.tracklist.add, consoleError) + // => list of TlTracks + .then(getFirst, consoleError) + // => TlTrack + .then(mopidy.playback.play, consoleError) + // => null + .then(printNowPlaying, consoleError); + }; + + var mopidy = new Mopidy(); // Connect to server + mopidy.on(console.log.bind(console)); // Log all events + mopidy.on("state:online", queueAndPlayFirstPlaylist); + +9. The web page should now queue and play your first playlist every time your + load it. See the browser's console for output from the function, any errors, + and all events that are emitted. + diff --git a/docs/api/index.rst b/docs/api/index.rst index 5a210812..bb29890b 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -1,3 +1,5 @@ +.. _api-ref: + ************* API reference ************* @@ -11,3 +13,6 @@ API reference core audio frontends + ext + config + http diff --git a/docs/api/models.rst b/docs/api/models.rst index 4171acb6..11ec017c 100644 --- a/docs/api/models.rst +++ b/docs/api/models.rst @@ -7,6 +7,21 @@ backends and between the backends and the MPD frontend. All fields are optional and immutable. In other words, they can only be set through the class constructor during instance creation. +If you want to modify a model, use the +:meth:`~mopidy.models.ImmutableObject.copy` method. It accepts keyword +arguments for the parts of the model you want to change, and copies the rest of +the data from the model you call it on. Example:: + + >>> from mopidy.models import Track + >>> track1 = Track(name='Christmas Carol', length=171) + >>> track1 + Track(artists=[], length=171, name='Christmas Carol') + >>> track2 = track1.copy(length=37) + >>> track2 + Track(artists=[], length=37, name='Christmas Carol') + >>> track1 + Track(artists=[], length=171, name='Christmas Carol') + Data model relations ==================== diff --git a/docs/authors.rst b/docs/authors.rst index 97a2dd2b..33a25bc1 100644 --- a/docs/authors.rst +++ b/docs/authors.rst @@ -1,3 +1,5 @@ +.. _authors: + ******* Authors ******* @@ -6,11 +8,7 @@ Contributors to Mopidy in the order of appearance: .. include:: ../AUTHORS - -Showing your appreciation -========================= - If you already enjoy Mopidy, or don't enjoy it and want to help us making Mopidy better, the best way to do so is to contribute back to the community. You can contribute code, documentation, tests, bug reports, or help other -users, spreading the word, etc. +users, spreading the word, etc. See :ref:`contributing` for a head start. diff --git a/docs/changes.rst b/docs/changelog.rst similarity index 93% rename from docs/changes.rst rename to docs/changelog.rst index ee1ea5d7..fbfa2471 100644 --- a/docs/changes.rst +++ b/docs/changelog.rst @@ -1,8 +1,115 @@ -******* -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 (2013-04-28) +==================== + +The 0.14 release has a clear focus on two things: the new configuration system +and extension support. Mopidy's documentation has also been greatly extended +and improved. + +Since the last release a month ago, we've closed or merged 53 issues and pull +requests. A total of seven :ref:`authors ` have contributed, including +one new. + +**Dependencies** + +- setuptools or distribute is now required. We've introduced this dependency to + use setuptools' entry points functionality to find installed Mopidy + extensions. + +**New configuration system** + +- Mopidy has a new configuration system based on ini-style files instead of a + Python file. This makes configuration easier for users, and also makes it + possible for Mopidy extensions to have their own config sections. + + As part of this change we have cleaned up the naming of our config values. + + To ease migration we've made a tool named :option:`mopidy-convert-config` for + automatically converting the old ``settings.py`` to a new ``mopidy.conf`` + file. This tool takes care of all the renamed config values as well. See + :ref:`mopidy-convert-config` for details on how to use it. + +- A long wanted feature: You can now enable or disable specific frontends or + backends without having to redefine :attr:`~mopidy.settings.FRONTENDS` or + :attr:`~mopidy.settings.BACKENDS` in your config. Those config values are + gone completely. + +**Extension support** + +- Mopidy now supports extensions. This means that any developer now easily can + create a Mopidy extension to add new control interfaces or music backends. + This helps spread the maintenance burden across more developers, and also + makes it possible to extend Mopidy with new backends the core developers are + unable to create and/or maintain because of geo restrictions, etc. If you're + interested in creating an extension for Mopidy, read up on + :ref:`extensiondev`. + +- All of Mopidy's existing frontends and backends are now plugged into Mopidy + as extensions, but they are still distributed together with Mopidy and are + enabled by default. + +- The NAD mixer have been moved out of Mopidy core to its own project, + Mopidy-NAD. See :ref:`ext` for more information. + +- Janez Troha has made the first two external extensions for Mopidy: a backend + for playing music from Soundcloud, and a backend for playing music from a + Beets music library. See :ref:`ext` for more information. + +**Command line options** + +- The command option :option:`mopidy --list-settings` is now named + :option:`mopidy --show-config`. + +- The command option :option:`mopidy --list-deps` is now named + :option:`mopidy --show-deps`. + +- What configuration files to use can now be specified through the command + option :option:`mopidy --config`, multiple files can be specified using colon + as a separator. + +- Configuration values can now be overridden through the command option + :option:`mopidy --option`. For example: ``mopidy --option + spotify/enabled=false``. + +- The GStreamer command line options, :option:`mopidy --gst-*` and + :option:`mopidy --help-gst` are no longer supported. To set GStreamer debug + flags, you can use environment variables such as :envvar:`GST_DEBUG`. Refer + to GStreamer's documentation for details. + +**Spotify backend** + +- Add support for starred playlists, both your own and those owned by other + users. (Fixes: :issue:`326`) + +- Fix crash when a new playlist is added by another Spotify client. (Fixes: + :issue:`387`, :issue:`425`) + +**MPD frontend** + +- Playlists with identical names are now handled properly by the MPD frontend + by suffixing the duplicate names with e.g. ``[2]``. This is needed because + MPD identify playlists by name only, while Mopidy and Spotify supports + multiple playlists with the same name, and identify them using an URI. + (Fixes: :issue:`114`) + +**MPRIS frontend** + +- The frontend is now disabled if the :envvar:`DISPLAY` environment variable is + unset. This avoids some harmless error messages, that have been known to + confuse new users debugging other problems. + +**Development** + +- Developers running Mopidy from a Git clone now need to run ``python setup.py + develop`` to register the bundled extensions. If you don't do this, Mopidy + will not find any frontends or backends. Note that we highly recomend you do + this in a virtualenv, not system wide. As a bonus, the command also gives + you a ``mopidy`` executable in your search path. v0.13.0 (2013-03-31) @@ -311,7 +418,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 @@ -1471,8 +1578,7 @@ In the last two months, Mopidy's MPD frontend has gotten lots of stability fixes and error handling improvements, proper support for having the same track multiple times in a playlist, and support for IPv6. We have also fixed the choppy playback on the libspotify backend. For the road ahead of us, we got an -updated :doc:`release roadmap ` with our goals for the 0.1 to 0.3 -releases. +updated release roadmap with our goals for the 0.1 to 0.3 releases. Enjoy the best alpha relase of Mopidy ever :-) diff --git a/docs/clients/http.rst b/docs/clients/http.rst index 5381eaff..7b4ea72b 100644 --- a/docs/clients/http.rst +++ b/docs/clients/http.rst @@ -4,14 +4,15 @@ HTTP clients ************ -Mopidy added an :ref:`HTTP frontend ` in 0.10 which provides the -building blocks needed for creating web clients for Mopidy with the help of a -WebSocket and a JavaScript library provided by Mopidy. +Mopidy added an :ref:`HTTP frontend ` and an :ref:`HTTP API +` in 0.10 which together 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. +This page will list any Mopidy web clients using the HTTP frontend. 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 @@ -24,9 +25,9 @@ woutervanwijk/Mopidy-Webclient The first web client for Mopidy is still under development, but is already very usable. It targets both desktop and mobile browsers. -To try it out, get a copy of https://github.com/woutervanwijk/Mopidy-WebClient -and point the :attr:`mopidy.settings.HTTP_SERVER_STATIC_DIR` setting towards -your copy of the web client. +The web client used for the `Pi Musicbox +`_ is also available for other users +of Mopidy. See https://github.com/woutervanwijk/Mopidy-WebClient for details. Mopidy Lux @@ -47,13 +48,8 @@ New web client developed by Meantime IT in the UK for their office jukebox. See https://github.com/meantimeit/jukepi for details. -Rompr -===== +Other web clients +================= -.. image:: /_static/rompr.png - :width: 557 - :height: 600 - -`Rompr `_ is a web based MPD client. -`mrvanes `_, a Mopidy and Rompr user, said: "These -projects are a real match made in heaven." +For Mopidy web clients using Mopidy's MPD frontend instead of HTTP, see +:ref:`mpd-web-clients`. diff --git a/docs/clients/mpd.rst b/docs/clients/mpd.rst index 878b01f0..0993303d 100644 --- a/docs/clients/mpd.rst +++ b/docs/clients/mpd.rst @@ -320,7 +320,29 @@ purchased from `MPaD at iTunes Store when waiting for the connection to a server to succeed. +.. _mpd-web-clients: + Web clients =========== -See :ref:`http-clients`. +The following web clients use the MPD protocol to communicate with Mopidy. For +other web clients, see :ref:`http-clients`. + + +Rompr +----- + +.. image:: /_static/rompr.png + :width: 557 + :height: 600 + +`Rompr `_ is a web based MPD client. +`mrvanes `_, a Mopidy and Rompr user, said: "These +projects are a real match made in heaven." + + +Partify +------- + +`Partify `_ is a web based MPD client focusing on +making music playing collaborative and social. diff --git a/docs/clients/mpris.rst b/docs/clients/mpris.rst index c782fa26..141a2371 100644 --- a/docs/clients/mpris.rst +++ b/docs/clients/mpris.rst @@ -8,9 +8,9 @@ MPRIS clients Specification. It's a spec that describes a standard D-Bus interface for making media players available to other applications on the same system. -Mopidy's :ref:`MPRIS frontend ` currently implements all -required parts of the MPRIS spec, plus the optional playlist interface. It does -not implement the optional tracklist interface. +Mopidy's :ref:`MPRIS frontend ` currently implements all required +parts of the MPRIS spec, plus the optional playlist interface. It does not +implement the optional tracklist interface. .. _ubuntu-sound-menu: @@ -36,12 +36,11 @@ Mopidy executable. If this isn't in place, the sound menu will not detect that Mopidy is running. Next, Mopidy's MPRIS frontend must be running for the sound menu to be able to -control Mopidy. The frontend is activated by default, so unless you've changed -the :attr:`mopidy.settings.FRONTENDS` setting, you should be good to go. Keep -an eye out for warnings or errors from the MPRIS frontend when you start -Mopidy, since it may fail because of missing dependencies or because Mopidy is -started outside of X; the frontend won't work if ``$DISPLAY`` isn't set when -Mopidy is started. +control Mopidy. The frontend is enabled by default, so as long as you have all +its dependencies available, you should be good to go. Keep an eye out for +warnings or errors from the MPRIS frontend when you start Mopidy, since it may +fail because of missing dependencies or because Mopidy is started outside of X; +the frontend won't work if ``$DISPLAY`` isn't set when Mopidy is started. Under normal use, if Mopidy isn't running and you open the menu and click on "Mopidy Music Server", a terminal window will open and automatically start diff --git a/docs/clients/upnp.rst b/docs/clients/upnp.rst index 567fb04f..9f30bd1c 100644 --- a/docs/clients/upnp.rst +++ b/docs/clients/upnp.rst @@ -37,18 +37,18 @@ How to make Mopidy available as an UPnP MediaRenderer With the help of `the Rygel project `_ Mopidy can be made available as an UPnP MediaRenderer. Rygel will interface with Mopidy's -:ref:`MPRIS frontend `, and make Mopidy available as a -MediaRenderer on the local network. Since this depends on the MPRIS frontend, -which again depends on D-Bus being available, this will only work on Linux, and -not OS X. MPRIS/D-Bus is only available to other applications on the same host, -so Rygel must be running on the same machine as Mopidy. +:ref:`MPRIS frontend `, and make Mopidy available as a MediaRenderer +on the local network. Since this depends on the MPRIS frontend, which again +depends on D-Bus being available, this will only work on Linux, and not OS X. +MPRIS/D-Bus is only available to other applications on the same host, so Rygel +must be running on the same machine as Mopidy. -1. Start Mopidy and make sure the :ref:`MPRIS frontend ` is - working. It is activated by default, but you may miss dependencies or be - using OS X, in which case it will not work. Check the console output when - Mopidy is started for any errors related to the MPRIS frontend. If you're - unsure it is working, there are instructions for how to test it on the - :ref:`MPRIS frontend ` page. +1. Start Mopidy and make sure the :ref:`MPRIS frontend ` is working. + It is activated by default, but you may miss dependencies or be using OS X, + in which case it will not work. Check the console output when Mopidy is + started for any errors related to the MPRIS frontend. If you're unsure it is + working, there are instructions for how to test it on the :ref:`MPRIS + frontend ` page. 2. Install Rygel. On Debian/Ubuntu:: @@ -66,11 +66,10 @@ so Rygel must be running on the same machine as Mopidy. $ rygel Rygel-Message: New plugin 'MediaExport' available - Rygel-Message: New plugin 'org.mpris.MediaPlayer2.spotify' available Rygel-Message: New plugin 'org.mpris.MediaPlayer2.mopidy' available - Note that in the above example, both the official Spotify client and Mopidy - is running and made available through Rygel. + In the above example, you can see that Rygel found Mopidy, and it is now + making Mopidy available through Rygel. The UPnP-Inspector client diff --git a/docs/codestyle.rst b/docs/codestyle.rst new file mode 100644 index 00000000..4b6e7448 --- /dev/null +++ b/docs/codestyle.rst @@ -0,0 +1,65 @@ +.. _codestyle: + +********** +Code style +********** + +- Always import ``unicode_literals`` and use unicode literals for everything + except where you're explicitly working with bytes, which are marked with the + ``b`` prefix. + + Do this:: + + from __future__ import unicode_literals + + foo = 'I am a unicode string, which is a sane default' + bar = b'I am a bytestring' + + Not this:: + + foo = u'I am a unicode string' + bar = 'I am a bytestring, but was it intentional?' + +- Follow :pep:`8` unless otherwise noted. `flake8 + `_ should be used to check your code + against the guidelines. + +- Use four spaces for indentation, *never* tabs. + +- Use CamelCase with initial caps for class names:: + + ClassNameWithCamelCase + +- Use underscore to split variable, function and method names for + readability. Don't use CamelCase. + + :: + + lower_case_with_underscores + +- Use the fact that empty strings, lists and tuples are :class:`False` and + don't compare boolean values using ``==`` and ``!=``. + +- Follow whitespace rules as described in :pep:`8`. Good examples:: + + spam(ham[1], {eggs: 2}) + spam(1) + dict['key'] = list[index] + +- Limit lines to 80 characters and avoid trailing whitespace. However note that + wrapped lines should be *one* indentation level in from level above, except + for ``if``, ``for``, ``with``, and ``while`` lines which should have two + levels of indentation:: + + if (foo and bar ... + baz and foobar): + a = 1 + + from foobar import (foo, bar, ... + baz) + +- For consistency, prefer ``'`` over ``"`` for strings, unless the string + contains ``'``. + +- Take a look at :pep:`20` for a nice peek into a general mindset useful for + Python coding. diff --git a/docs/conf.py b/docs/conf.py index 55f415b4..a71c9a61 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -32,7 +32,8 @@ class Mock(object): def __getattr__(self, name): if name in ('__file__', '__path__'): return '/dev/null' - elif name[0] == name[0].upper() and not name.startswith('MIXER_TRACK'): + elif (name[0] == name[0].upper() + and not name.startswith('MIXER_TRACK_')): return type(name, (), {}) else: return Mock() @@ -53,7 +54,6 @@ MOCK_MODULES = [ 'pykka.future', 'pykka.registry', 'pylast', - 'serial', 'ws4py', 'ws4py.messaging', 'ws4py.server', @@ -98,7 +98,7 @@ master_doc = 'index' # General information about the project. project = 'Mopidy' -copyright = '2010-2012, Stein Magnus Jodal and contributors' +copyright = '2010-2013, Stein Magnus Jodal and contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -266,3 +266,12 @@ latex_documents = [ needs_sphinx = '1.0' extlinks = {'issue': ('https://github.com/mopidy/mopidy/issues/%s', '#')} + + +def setup(app): + from sphinx.ext.autodoc import cut_lines + app.connect(b'autodoc-process-docstring', cut_lines(4, what=['module'])) + app.add_object_type( + b'confval', 'confval', + objname='configuration value', + indextemplate='pair: %s; configuration value') diff --git a/docs/config.rst b/docs/config.rst new file mode 100644 index 00000000..9b3291c6 --- /dev/null +++ b/docs/config.rst @@ -0,0 +1,216 @@ +************* +Configuration +************* + +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 + + [mpd] + hostname = :: + + [spotify] + 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. + +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``. + +To see what's the effective configuration for your Mopidy installation, you can +run :option:`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. + +You can find a description of all config values belonging to Mopidy's core +below, together with their default values. In addition, all :ref:`extensions +` got additional config values. The extension's config values and config +defaults are documented on the :ref:`extension pages `. + + +Default core configuration +========================== + +.. literalinclude:: ../mopidy/config/default.conf + :language: ini + + +Core configuration values +========================= + +.. confval:: audio/mixer + + Audio mixer to use. + + Expects a GStreamer mixer to use, typical values are: ``autoaudiomixer``, + ``alsamixer``, ``pulsemixer``, ``ossmixer``, and ``oss4mixer``. + + The default is ``autoaudiomixer``, which attempts to select a sane mixer + for you automatically. When Mopidy is started, it will log what mixer + ``autoaudiomixer`` selected, for example:: + + INFO Audio mixer set to "alsamixer" using track "Master" + + Setting the config value to blank turns off volume control. ``software`` + can be used to force software mixing in the application. + +.. confval:: audio/mixer_track + + Audio mixer track to use. + + Name of the mixer track to use. If this is not set we will try to find the + master output track. As an example, using ``alsamixer`` you would typically + set this to ``Master`` or ``PCM``. + +.. confval:: audio/output + + Audio output to use. + + Expects a GStreamer sink. Typical values are ``autoaudiosink``, + ``alsasink``, ``osssink``, ``oss4sink``, ``pulsesink``, and ``shout2send``, + and additional arguments specific to each sink. You can use the command + ``gst-inspect-0.10`` to see what output properties can be set on the sink. + For example: ``gst-inspect-0.10 shout2send`` + +.. confval:: logging/console_format + + The log format used for informational logging. + + See `the Python logging docs`_ for details on the format. + +.. confval:: logging/debug_format + + The log format used for debug logging. + + See `the Python logging docs`_ for details on the format. + +.. confval:: logging/debug_file + + The file to dump debug log data to when Mopidy is run with the + :option:`mopidy --save-debug-log` option. + +.. confval:: logging/config_file + + Config file that overrides all logging settings, see `the Python logging + docs`_ for details. + +.. confval:: loglevels/* + + The ``loglevels`` 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 needed. + +.. confval:: proxy/password + + Password for the proxy server, if needed. + +.. _the Python logging docs: + + http://docs.python.org/2/library/logging.config.html + + +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:: + + $ gst-inspect-0.10 + ... long list of installed plugins ... + Total count: 254 plugins (1 blacklist entry not shown), 1156 features + +Next, you should be able to produce a audible tone by running:: + + gst-launch-0.10 audiotestsrc ! audioresample ! autoaudiosink + +If you cannot hear any sound when running this command, you won't hear any +sound from Mopidy either, as Mopidy by default uses GStreamer's +``autoaudiosink`` to play audio. Thus, make this work before you file a bug +against Mopidy. + +If you for some reason want to use some other GStreamer audio sink than +``autoaudiosink``, you can set the :confval:`audio/output` config value to a +partial GStreamer pipeline description describing the GStreamer sink you want +to use. + +Example ``mopidy.conf`` for using OSS4: + +.. code-block:: ini + + [audio] + output = oss4sink + +Again, this is the equivalent of the following ``gst-inspect`` command, so make +this work first:: + + gst-launch-0.10 audiotestsrc ! audioresample ! oss4sink + + +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 +streaming server. Multiple media players can then be connected to the streaming +server simultaneously. To use the SHOUTcast output, do the following: + +#. Install, configure and start the Icecast server. It can be found in the + ``icecast2`` package in Debian/Ubuntu. + +#. Set the :confval:`audio/output` config value to ``lame ! shout2send``. An + Ogg Vorbis encoder could be used instead of the lame MP3 encoder. + +#. You might also need to change the ``shout2send`` default settings, run + ``gst-inspect-0.10 shout2send`` to see the available settings. Most likely + you want to change ``ip``, ``username``, ``password``, and ``mount``. For + example, to set the username and password, use: + + .. code-block:: ini + + [audio] + output = lame ! shout2send username="alice" password="secret" + +Other advanced setups are also possible for outputs. Basically, anything you +can use with the ``gst-launch-0.10`` command can be plugged into +:confval:`audio/output`. + + +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, +but it helps us detect typos in your settings, and deprecated settings that +should be removed or updated. + +If you're extending Mopidy, and want to use Mopidy's configuration +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. diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 00000000..22df8ced --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1,139 @@ +.. _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 +=============== + +#. Make sure you have a `GitHub account `_. + +#. `Submit `_ a ticket for your + issue, assuming one does not already exist. Clearly describe the issue + including steps to reproduce when it is a bug. + +#. Fork the repository on GitHub. + + +Making changes +============== + +#. Clone your fork on GitHub to your computer. + +#. Consider making a Python `virtualenv `_ for + Mopidy development to wall of Mopidy and it's dependencies from the rest of + your system. If you do so, create the virtualenv with the + ``--system-site-packages`` flag so that Mopidy can use globally installed + dependencies like GStreamer. If you don't use a virtualenv, you may need to + run the following ``pip`` and ``python setup.py`` commands with ``sudo`` to + install stuff globally on your computer. + +#. Install dependencies as described in the :ref:`installation` section. + +#. 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. + +#. Go to the Git repo root:: + + cd mopidy/ + +#. To get a ``mopidy`` executable and register all bundled extensions with + setuptools, run:: + + python setup.py develop + + It still works to run ``python mopidy`` directly on the ``mopidy`` Python + package directory, but if you have never run ``python setup.py develop`` the + extensions bundled with Mopidy isn't registered with setuptools, so Mopidy + will start without any frontends or backends, making it quite useless. + +#. 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. + +#. To run tests, you need a couple of dependencies. They can be installed using + ``pip``:: + + pip install -r requirements/tests.txt + +#. 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/ + +#. Check the code for errors and style issues using flake8:: + + flake8 . + +For more documentation on testing, check out the `nose documentation +`_. + + +Submitting changes +================== + +- One branch per feature or fix. Keep branches small and on topic. + +- Follow the :ref:`code style `, especially make sure ``flake8`` + does not complain about anything. + +- Write good commit messages. Here's three blog posts on how to do it right: + + - `Writing Git commit messages + `_ + + - `A Note About Git Commit Messages + `_ + + - `On commit messages + `_ + +- Send a pull request to the ``develop`` branch. See the `GitHub pull request + docs `_ for help. + + +Additional resources +==================== + +- IRC channel: ``#mopidy`` at `irc.freenode.net `_ + +- `Issue tracker `_ + +- `Mailing List `_ + +- `GitHub documentation `_ diff --git a/docs/development.rst b/docs/development.rst deleted file mode 100644 index c1c1d291..00000000 --- a/docs/development.rst +++ /dev/null @@ -1,365 +0,0 @@ -*********** -Development -*********** - -Development of Mopidy is coordinated through the IRC channel ``#mopidy`` at -``irc.freenode.net`` and through `GitHub `_. - - -Release schedule -================ - -We intend to have about one timeboxed feature release every month -in periods of active development. The feature releases are numbered 0.x.0. The -features added is a mix of what we feel is most important/requested of the -missing features, and features we develop just because we find them fun to -make, even though they may be useful for very few users or for a limited use -case. - -Bugfix releases, numbered 0.x.y, will be released whenever we discover bugs -that are too serious to wait for the next feature release. We will only release -bugfix releases for the last feature release. E.g. when 0.3.0 is released, we -will no longer provide bugfix releases for the 0.2 series. In other words, -there will be just a single supported release at any point in time. - - -Feature wishlist -================ - -We maintain our collection of sane or less sane ideas for future Mopidy -features as `issues `_ at GitHub -labeled with `the "wishlist" label -`_. Feel free to vote -up any feature you would love to see in Mopidy, but please refrain from adding -a comment just to say "I want this too!". You are of course free to add -comments if you have suggestions for how the feature should work or be -implemented, and you may add new wishlist issues if your ideas are not already -represented. - - -.. _run-from-git: - -Run Mopidy from Git repo -======================== - -If you want to contribute to the development of Mopidy, you should run Mopidy -directly from the Git repo. - -#. First of all, install Mopidy in the recommended way for your OS and/or - distribution, like described at :ref:`installation`. You can have a - system-wide installation of the last Mopidy release in addition to the Git - repo which you run from when you code on Mopidy. - -#. Then install Git, if haven't already. For Ubuntu/Debian:: - - sudo apt-get install git-core - - On OS X using Homebrew:: - - sudo brew install git - -#. Clone the official Mopidy repository:: - - git clone git://github.com/mopidy/mopidy.git - - or your own fork of it:: - - git clone git@github.com:mygithubuser/mopidy.git - -#. You can then run Mopidy directly from the Git repository:: - - cd mopidy/ # Move into the Git repo dir - python mopidy # Run python on the mopidy source code dir - -How you update your clone depends on whether you cloned the official Mopidy -repository or your own fork, whether you have made any changes to the clone -or not, and whether you are currently working on a feature branch or not. In -other words, you'll need to learn Git. - -For an introduction to Git, please visit `git-scm.com `_. -Also, please read the rest of our developer documentation before you start -contributing. - - -Code style -========== - -- Always import ``unicode_literals`` and use unicode literals for everything - except where you're explicitly working with bytes, which are marked with the - ``b`` prefix. - - Do this:: - - from __future__ import unicode_literals - - foo = 'I am a unicode string, which is a sane default' - bar = b'I am a bytestring' - - Not this:: - - foo = u'I am a unicode string' - bar = 'I am a bytestring, but was it intentional?' - -- Follow :pep:`8` unless otherwise noted. `pep8.py - `_ or `flake8 - `_ can be used to check your code - against the guidelines, however remember that matching the style of the - surrounding code is also important. - -- Use four spaces for indentation, *never* tabs. - -- Use CamelCase with initial caps for class names:: - - ClassNameWithCamelCase - -- Use underscore to split variable, function and method names for - readability. Don't use CamelCase. - - :: - - lower_case_with_underscores - -- Use the fact that empty strings, lists and tuples are :class:`False` and - don't compare boolean values using ``==`` and ``!=``. - -- Follow whitespace rules as described in :pep:`8`. Good examples:: - - spam(ham[1], {eggs: 2}) - spam(1) - dict['key'] = list[index] - -- Limit lines to 80 characters and avoid trailing whitespace. However note that - wrapped lines should be *one* indentation level in from level above, except - for ``if``, ``for``, ``with``, and ``while`` lines which should have two - levels of indentation:: - - if (foo and bar ... - baz and foobar): - a = 1 - - from foobar import (foo, bar, ... - baz) - -- For consistency, prefer ``'`` over ``"`` for strings, unless the string - contains ``'``. - -- Take a look at :pep:`20` for a nice peek into a general mindset useful for - Python coding. - - -Commit guidelines -================= - -- We follow the development process described at - `nvie.com `_. - -- Keep commits small and on topic. - -- If a commit looks too big you should be working in a feature branch not a - single commit. - -- Merge feature branches with ``--no-ff`` to keep track of the merge. - - -Running tests -============= - -To run tests, you need a couple of dependencies. They can be installed through -Debian/Ubuntu package management:: - - sudo apt-get install python-coverage python-mock python-nose - -Or, they can be installed using ``pip``:: - - sudo pip install -r requirements/tests.txt - -Then, to run all tests, go to the project directory and run:: - - nosetests - -For example:: - - $ nosetests - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................................. - ............................................................. - ----------------------------------------------------------------------------- - 1062 tests run in 7.4 seconds (1062 tests passed) - -To run tests with test coverage statistics, remember to specify the tests dir:: - - nosetests --with-coverage tests/ - -For more documentation on testing, check out the `nose documentation -`_. - - -Continuous integration -====================== - -Mopidy uses the free service `Travis CI `_ -for automatically running the test suite when code is pushed to GitHub. This -works both for the main Mopidy repo, but also for any forks. This way, any -contributions to Mopidy through GitHub will automatically be tested by Travis -CI, and the build status will be visible in the GitHub pull request interface, -making it easier to evaluate the quality of pull requests. - -In addition, we run a Jenkins CI server at http://ci.mopidy.com/ that runs all -test on multiple platforms (Ubuntu, OS X, x86, arm) for every commit we push to -the ``develop`` branch in the main Mopidy repo on GitHub. Thus, new code isn't -tested by Jenkins before it is merged into the ``develop`` branch, which is a -bit late, but good enough to get broad testing before new code is released. - -In addition to running tests, the Jenkins CI server also gathers coverage -statistics and uses pylint to check for errors and possible improvements in our -code. So, if you're out of work, the code coverage and pylint data at the CI -server should give you a place to start. - - -Protocol debugging -================== - -Since the main interface provided to Mopidy is through the MPD protocol, it is -crucial that we try and stay in sync with protocol developments. In an attempt -to make it easier to debug differences Mopidy and MPD protocol handling we have -created ``tools/debug-proxy.py``. - -This tool is proxy that sits in front of two MPD protocol aware servers and -sends all requests to both, returning the primary response to the client and -then printing any diff in the two responses. - -Note that this tool depends on ``gevent`` unlike the rest of Mopidy at the time -of writing. See ``--help`` for available options. Sample session:: - - [127.0.0.1]:59714 - listallinfo - --- Reference response - +++ Actual response - @@ -1,16 +1,1 @@ - -file: uri1 - -Time: 4 - -Artist: artist1 - -Title: track1 - -Album: album1 - -file: uri2 - -Time: 4 - -Artist: artist2 - -Title: track2 - -Album: album2 - -file: uri3 - -Time: 4 - -Artist: artist3 - -Title: track3 - -Album: album3 - -OK - +ACK [2@0] {listallinfo} incorrect arguments - -To ensure that Mopidy and MPD have comparable state it is suggested you setup -both to use ``tests/data/advanced_tag_cache`` for their tag cache and -``tests/data/scanner/advanced/`` for the music folder and ``tests/data`` for -playlists. - - -Setting profiles during development -=================================== - -While developing Mopidy switching settings back and forth can become an all too -frequent occurrence. As a quick hack to get around this you can structure your -settings file in the following way:: - - import os - profile = os.environ.get('PROFILE', '').split(',') - - if 'spotify' in profile: - BACKENDS = (u'mopidy.backends.spotify.SpotifyBackend',) - elif 'local' in profile: - BACKENDS = (u'mopidy.backends.local.LocalBackend',) - LOCAL_MUSIC_PATH = u'~/music' - - 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,spotify mopidy`` -if you for instance want to test Spotify without any actual audio output. - - -Debugging deadlocks -=================== - -Between the numerous Pykka threads and GStreamer interactions there can -sometimes be a potential for deadlocks. In an effort to make these slightly -simpler to debug Mopidy registers a ``SIGUSR1`` signal handler which logs the -traceback of all alive threads. - -To trigger the signal handler, you can use the ``pkill`` command to -send the ``SIGUSR1`` signal to any Mopidy processes:: - - pkill -SIGUSR1 mopidy - -If you check the log, you should now find one log record with a full traceback -for each of the currently alive threads in Mopidy. - - -Writing documentation -===================== - -To write documentation, we use `Sphinx `_. See their -site for lots of documentation on how to use Sphinx. To generate HTML or LaTeX -from the documentation files, you need some additional dependencies. - -You can install them through Debian/Ubuntu package management:: - - sudo apt-get install python-sphinx python-pygraphviz graphviz - -Then, to generate docs:: - - cd docs/ - make # For help on available targets - make html # To generate HTML docs - -The documentation at http://docs.mopidy.com/ is automatically updated when a -documentation update is pushed to ``mopidy/mopidy`` at GitHub. - - -Creating releases -================= - -#. Update changelog and commit it. - -#. Merge the release branch (``develop`` in the example) into master:: - - git checkout master - git merge --no-ff -m "Release v0.2.0" develop - -#. Tag the release:: - - git tag -a -m "Release v0.2.0" v0.2.0 - -#. Push to GitHub:: - - git push - git push --tags - -#. Build package and upload to PyPI:: - - rm MANIFEST # Will be regenerated by setup.py - python setup.py sdist upload - -#. Spread the word. diff --git a/docs/devtools.rst b/docs/devtools.rst new file mode 100644 index 00000000..bc066cd0 --- /dev/null +++ b/docs/devtools.rst @@ -0,0 +1,121 @@ +***************** +Development tools +***************** + +Here you'll find description of the development tools we use. + + +Continuous integration +====================== + +Mopidy uses the free service `Travis CI `_ +for automatically running the test suite when code is pushed to GitHub. This +works both for the main Mopidy repo, but also for any forks. This way, any +contributions to Mopidy through GitHub will automatically be tested by Travis +CI, and the build status will be visible in the GitHub pull request interface, +making it easier to evaluate the quality of pull requests. + +In addition, we run a Jenkins CI server at http://ci.mopidy.com/ that runs all +test on multiple platforms (Ubuntu, OS X, x86, arm) for every commit we push to +the ``develop`` branch in the main Mopidy repo on GitHub. Thus, new code isn't +tested by Jenkins before it is merged into the ``develop`` branch, which is a +bit late, but good enough to get broad testing before new code is released. + +In addition to running tests, the Jenkins CI server also gathers coverage +statistics and uses pylint to check for errors and possible improvements in our +code. So, if you're out of work, the code coverage and pylint data at the CI +server should give you a place to start. + + +Protocol debugger +================= + +Since the main interface provided to Mopidy is through the MPD protocol, it is +crucial that we try and stay in sync with protocol developments. In an attempt +to make it easier to debug differences Mopidy and MPD protocol handling we have +created ``tools/debug-proxy.py``. + +This tool is proxy that sits in front of two MPD protocol aware servers and +sends all requests to both, returning the primary response to the client and +then printing any diff in the two responses. + +Note that this tool depends on ``gevent`` unlike the rest of Mopidy at the time +of writing. See :option:`tools/debug-proxy.py --help` for available options. +Sample session:: + + [127.0.0.1]:59714 + listallinfo + --- Reference response + +++ Actual response + @@ -1,16 +1,1 @@ + -file: uri1 + -Time: 4 + -Artist: artist1 + -Title: track1 + -Album: album1 + -file: uri2 + -Time: 4 + -Artist: artist2 + -Title: track2 + -Album: album2 + -file: uri3 + -Time: 4 + -Artist: artist3 + -Title: track3 + -Album: album3 + -OK + +ACK [2@0] {listallinfo} incorrect arguments + +To ensure that Mopidy and MPD have comparable state it is suggested you setup +both to use ``tests/data/advanced_tag_cache`` for their tag cache and +``tests/data/scanner/advanced/`` for the music folder and ``tests/data`` for +playlists. + + +Documentation writing +===================== + +To write documentation, we use `Sphinx `_. See their +site for lots of documentation on how to use Sphinx. To generate HTML from the +documentation files, you need some additional dependencies. + +You can install them through Debian/Ubuntu package management:: + + sudo apt-get install python-sphinx python-pygraphviz graphviz + +Then, to generate docs:: + + cd docs/ + make # For help on available targets + make html # To generate HTML docs + +The documentation at http://docs.mopidy.com/ is automatically updated when a +documentation update is pushed to ``mopidy/mopidy`` at GitHub. + + +Creating releases +================= + +#. Update changelog and commit it. + +#. Merge the release branch (``develop`` in the example) into master:: + + git checkout master + git merge --no-ff -m "Release v0.2.0" develop + +#. Tag the release:: + + git tag -a -m "Release v0.2.0" v0.2.0 + +#. Push to GitHub:: + + git push + git push --tags + +#. Build package and upload to PyPI:: + + python setup.py sdist upload + +#. Update the Debian package. + +#. Spread the word. diff --git a/docs/ext/http.rst b/docs/ext/http.rst new file mode 100644 index 00000000..65bddb73 --- /dev/null +++ b/docs/ext/http.rst @@ -0,0 +1,103 @@ +.. _ext-http: + +*********** +Mopidy-HTTP +*********** + +The HTTP extension lets you control Mopidy through HTTP and WebSockets, e.g. +from a web based client. See :ref:`http-api` for details on how to integrate +with Mopidy over HTTP. + + +Known issues +============ + +https://github.com/mopidy/mopidy/issues?labels=HTTP+frontend + + +Dependencies +============ + +.. literalinclude:: ../../requirements/http.txt + + +Default configuration +===================== + +.. literalinclude:: ../../mopidy/frontends/http/ext.conf + :language: ini + + +Configuration values +==================== + +.. confval:: http/enabled + + If the HTTP extension should be enabled or not. + +.. confval:: http/hostname + + Which address the HTTP server should bind to. + + ``127.0.0.1`` + Listens only on the IPv4 loopback interface + ``::1`` + Listens only on the IPv6 loopback interface + ``0.0.0.0`` + Listens on all IPv4 interfaces + ``::`` + Listens on all interfaces, both IPv4 and IPv6 + +.. confval:: http/port + + Which TCP port the HTTP server should listen to. + +.. confval:: http/static_dir + + Which directory the HTTP server should serve at "/" + + Change this to have Mopidy serve e.g. files for your JavaScript client. + "/mopidy" will continue to work as usual even if you change this setting. + + +Usage +===== + +The extension is enabled by default if all dependencies are available. + +When it is enabled it starts a web server at the port specified by the +:confval:`http/port` config value. + +.. warning:: Security + + As a simple security measure, the web server is by default only available + from localhost. To make it available from other computers, change the + :confval:`http/hostname` config value. Before you do so, note that the HTTP + extension does not feature any form of user authentication or + authorization. Anyone able to access the web server can use the full core + API of Mopidy. Thus, you probably only want to make the web server + available from your local network or place it behind a web proxy which + takes care or user authentication. You have been warned. + + +Using a web based Mopidy client +------------------------------- + +The web server can also host any static files, for example the HTML, CSS, +JavaScript, and images needed for a web based Mopidy client. To host static +files, change the ``http/static_dir`` to point to the root directory of your +web client, e.g.:: + + [http] + static_dir = /home/alice/dev/the-client + +If the directory includes a file named ``index.html``, it will be served on the +root of Mopidy's web server. + +If you're making a web based client and wants to do server side development as +well, you are of course free to run your own web server and just use Mopidy's +web server for the APIs. But, for clients implemented purely in JavaScript, +letting Mopidy host the files is a simpler solution. + +If you're looking for a web based client for Mopidy, go check out +:ref:`http-clients`. diff --git a/docs/ext/index.rst b/docs/ext/index.rst new file mode 100644 index 00000000..562766ce --- /dev/null +++ b/docs/ext/index.rst @@ -0,0 +1,77 @@ +.. _ext: + +********** +Extensions +********** + +Here you can find a list of packages that extend Mopidy with additional +functionality. This list is moderated and updated on a regular basis. If you +want your package to show up here, follow the :ref:`guide on creating +extensions `. + + +Bundled with Mopidy +=================== + +These extensions are maintained by Mopidy's core developers. They are installed +together with Mopidy and are enabled by default. + +.. toctree:: + :maxdepth: 1 + :glob: + + ** + + +External extensions +=================== + +These extensions are maintained outside Mopidy's core, often by other +developers. + + +Mopidy-Beets +------------ + +Provides a backend for playing music from your `Beets +`_ music library through Beets' web extension. + +Author: + Janez Troha +PyPI: + `Mopidy-Beets `_ +GitHub: + `dz0ny/mopidy-beets `_ +Issues: + https://github.com/dz0ny/mopidy-beets/issues + + +Mopidy-NAD +---------- + +Extension for controlling volume using an external NAD amplifier. + +Author: + Stein Magnus Jodal +PyPI: + `Mopidy-NAD `_ +GitHub: + `mopidy/mopidy-nad `_ +Issues: + https://github.com/mopidy/mopidy/issues + + +Mopidy-SoundCloud +----------------- + +Provides a backend for playing music from the `SoundCloud +`_ service. + +Author: + Janez Troha +PyPI: + `Mopidy-SoundCloud `_ +GitHub: + `dz0ny/mopidy-soundcloud `_ +Issues: + https://github.com/dz0ny/mopidy-soundcloud/issues diff --git a/docs/ext/local.rst b/docs/ext/local.rst new file mode 100644 index 00000000..fc89e69a --- /dev/null +++ b/docs/ext/local.rst @@ -0,0 +1,86 @@ +.. _ext-local: + +************ +Mopidy-Local +************ + +Extension for playing music from a local music archive. + +This backend handles URIs starting with ``file:``. + + +Known issues +============ + +https://github.com/mopidy/mopidy/issues?labels=Local+backend + + +Dependencies +============ + +None. The extension just needs Mopidy. + + +Default configuration +===================== + +.. literalinclude:: ../../mopidy/backends/local/ext.conf + :language: ini + + +Configuration values +==================== + +.. confval:: local/enabled + + If the local extension should be enabled or not. + +.. confval:: local/media_dir + + Path to directory with local media files. + +.. confval:: local/playlists_dir + + Path to playlists directory with m3u files for local media. + +.. confval:: local/tag_cache_file + + Path to tag cache for local media. + + +Usage +===== + +If you want use Mopidy to play music you have locally at your machine, you need +to review and maybe change some of the local extension config values. See above +for a complete list. Then you need to generate a tag cache for your local +music... + + +.. _generating-a-tag-cache: + +Generating a tag cache +---------------------- + +The program :command:`mopidy-scan` will scan the path set in the +:confval:`local/media_dir` config value for any media files and build a MPD +compatible ``tag_cache``. + +To make a ``tag_cache`` of your local music available for Mopidy: + +#. Ensure that the :confval:`local/media_dir` config value points to where your + music is located. Check the current setting by running:: + + mopidy --show-config + +#. Scan your media library. The command outputs the ``tag_cache`` to + standard output, which means that you will need to redirect the output to a + file yourself:: + + mopidy-scan > tag_cache + +#. Move the ``tag_cache`` file to the location + set in the :confval:`local/tag_cache_file` config value, or change the + config value to point to where your ``tag_cache`` file is. + +#. Start Mopidy, find the music library in a client, and play some local music! diff --git a/docs/ext/mpd.rst b/docs/ext/mpd.rst new file mode 100644 index 00000000..b4d0e1c8 --- /dev/null +++ b/docs/ext/mpd.rst @@ -0,0 +1,123 @@ +.. _ext-mpd: + +********** +Mopidy-MPD +********** + +This extension implements an MPD server to make Mopidy available to :ref:`MPD +clients `. + +MPD stands for Music Player Daemon, which is also the name of the `original MPD +server project `_. Mopidy does not depend on the +original MPD server, but implements the MPD protocol itself, and is thus +compatible with clients for the original MPD server. + +For more details on our MPD server implementation, see +:mod:`mopidy.frontends.mpd`. + + +Known issues +============ + +https://github.com/mopidy/mopidy/issues?labels=MPD+frontend + + +Limitations +=========== + +This is a non exhaustive list of MPD features that Mopidy doesn't support. +Items on this list will probably not be supported in the near future. + +- Toggling of audio outputs is not supported +- Channels for client-to-client communication are not supported +- Stickers are not supported +- Crossfade is not supported +- Replay gain is not supported +- ``count`` does not provide any statistics +- ``stats`` does not provide any statistics +- ``list`` does not support listing tracks by genre +- ``decoders`` does not provide information about available decoders + +The following items are currently not supported, but should be added in the +near future: + +- Modifying stored playlists is not supported +- ``tagtypes`` is not supported +- Browsing the file system is not supported +- Live update of the music database is not supported + + +Dependencies +============ + +None. The extension just needs Mopidy. + + +Default configuration +===================== + +.. literalinclude:: ../../mopidy/frontends/mpd/ext.conf + :language: ini + + +Configuration values +==================== + +.. confval:: mpd/enabled + + If the MPD extension should be enabled or not. + +.. confval:: mpd/hostname + + Which address the MPD server should bind to. + + ``127.0.0.1`` + Listens only on the IPv4 loopback interface + ``::1`` + Listens only on the IPv6 loopback interface + ``0.0.0.0`` + Listens on all IPv4 interfaces + ``::`` + Listens on all interfaces, both IPv4 and IPv6 + +.. confval:: mpd/port + + Which TCP port the MPD server should listen to. + +.. confval:: mpd/password + + The password required for connecting to the MPD server. If blank, no + password is required. + +.. confval:: mpd/max_connections + + The maximum number of concurrent connections the MPD server will accept. + +.. confval:: mpd/connection_timeout + + Number of seconds an MPD client can stay inactive before the connection is + closed by the server. + + +Usage +===== + +The extension is enabled by default. To connect to the server, use an :ref:`MPD +client `. + + +.. _use-mpd-on-a-network: + +Connecting from other machines on the network +--------------------------------------------- + +As a secure default, Mopidy only accepts connections from ``localhost``. If you +want to open it for connections from other machines on your network, see +the documentation for the :confval:`mpd/hostname` config value. + +If you open up Mopidy for your local network, you should consider turning on +MPD password authentication by setting the :confval:`mpd/password` config value +to the password you want to use. If the password is set, Mopidy will require +MPD clients to provide the password before they can do anything else. Mopidy +only supports a single password, and do not support different permission +schemes like the original MPD server. diff --git a/docs/ext/mpris.rst b/docs/ext/mpris.rst new file mode 100644 index 00000000..125f8fec --- /dev/null +++ b/docs/ext/mpris.rst @@ -0,0 +1,105 @@ +.. _ext-mpris: + +************ +Mopidy-MPRIS +************ + +This extension lets you control Mopidy through the Media Player Remote +Interfacing Specification (`MPRIS `_) D-Bus interface. + +An example of an MPRIS client is the :ref:`ubuntu-sound-menu`. + + +Dependencies +============ + +- D-Bus Python bindings. The package is named ``python-dbus`` in + Ubuntu/Debian. + +- ``libindicate`` Python bindings is needed to expose Mopidy in e.g. the + Ubuntu Sound Menu. The package is named ``python-indicate`` in + Ubuntu/Debian. + +- An ``.desktop`` file for Mopidy installed at the path set in the + :confval:`mpris/desktop_file` config value. See usage section below for + details. + + +Default configuration +===================== + +.. literalinclude:: ../../mopidy/frontends/mpris/ext.conf + :language: ini + + +Configuration values +==================== + +.. confval:: mpris/enabled + + If the MPRIS extension should be enabled or not. + +.. confval:: mpris/desktop_file + + Location of the Mopidy ``.desktop`` file. + + +Usage +===== + +The extension is enabled by default if all dependencies are available. + + +Controlling Mopidy through the Ubuntu Sound Menu +------------------------------------------------ + +If you are running Ubuntu and installed Mopidy using the Debian package from +APT you should be able to control Mopidy through the :ref:`ubuntu-sound-menu` +without any changes. + +If you installed Mopidy in any other way and want to control Mopidy through the +Ubuntu Sound Menu, you must install the ``mopidy.desktop`` file which can be +found in the ``data/`` dir of the Mopidy source repo into the +``/usr/share/applications`` dir by hand:: + + cd /path/to/mopidy/source + sudo cp data/mopidy.desktop /usr/share/applications/ + +If the correct path to the installed ``mopidy.desktop`` file on your system +isn't ``/usr/share/applications/mopidy.conf``, you'll need to set the +:confval:`mpris/desktop_file` config value. + +After you have installed the file, start Mopidy in any way, and Mopidy should +appear in the Ubuntu Sound Menu. When you quit Mopidy, it will still be listed +in the Ubuntu Sound Menu, and may be restarted by selecting it there. + +The Ubuntu Sound Menu interacts with Mopidy's MPRIS frontend. The MPRIS +frontend supports the minimum requirements of the `MPRIS specification +`_. The ``TrackList`` interface of the spec is not +supported. + + +Testing the MPRIS API directly +------------------------------ + +To use the MPRIS API directly, start Mopidy, and then run the following in a +Python shell:: + + import dbus + bus = dbus.SessionBus() + player = bus.get_object('org.mpris.MediaPlayer2.mopidy', + '/org/mpris/MediaPlayer2') + +Now you can control Mopidy through the player object. Examples: + +- To get some properties from Mopidy, run:: + + props = player.GetAll('org.mpris.MediaPlayer2', + dbus_interface='org.freedesktop.DBus.Properties') + +- To quit Mopidy through D-Bus, run:: + + player.Quit(dbus_interface='org.mpris.MediaPlayer2') + +For details on the API, please refer to the `MPRIS specification +`_. diff --git a/docs/ext/scrobbler.rst b/docs/ext/scrobbler.rst new file mode 100644 index 00000000..a0496b37 --- /dev/null +++ b/docs/ext/scrobbler.rst @@ -0,0 +1,53 @@ +**************** +Mopidy-Scrobbler +**************** + +This extension scrobbles the music you play to your `Last.fm +`_ profile. + +.. note:: + + This extension requires a free user account at Last.fm. + + +Dependencies +============ + +.. literalinclude:: ../../requirements/scrobbler.txt + + +Default configuration +===================== + +.. literalinclude:: ../../mopidy/frontends/scrobbler/ext.conf + :language: ini + + +Configuration values +==================== + +.. confval:: scrobbler/enabled + + If the scrobbler extension should be enabled or not. + +.. confval:: scrobbler/username + + Your Last.fm username. + +.. confval:: scrobbler/password + + Your Last.fm password. + + +Usage +===== + +The extension is enabled by default if all dependencies are available. You just +need to add your Last.fm username and password to the +``~/.config/mopidy/mopidy.conf`` file: + +.. code-block:: ini + + [scrobbler] + username = myusername + password = mysecret diff --git a/docs/ext/spotify.rst b/docs/ext/spotify.rst new file mode 100644 index 00000000..4bb5b7a3 --- /dev/null +++ b/docs/ext/spotify.rst @@ -0,0 +1,83 @@ +.. _ext-spotify: + +************** +Mopidy-Spotify +************** + +An extension for playing music from Spotify. + +`Spotify `_ is a music streaming service. The backend +uses the official `libspotify +`_ library and the +`pyspotify `_ Python bindings for +libspotify. This backend handles URIs starting with ``spotify:``. + +.. note:: + + This product uses SPOTIFY(R) CORE but is not endorsed, certified or + otherwise approved in any way by Spotify. Spotify is the registered + trade mark of the Spotify Group. + + +Known issues +============ + +https://github.com/mopidy/mopidy/issues?labels=Spotify+backend + + +Dependencies +============ + +.. literalinclude:: ../../requirements/spotify.txt + + +Default configuration +===================== + +.. literalinclude:: ../../mopidy/backends/spotify/ext.conf + :language: ini + + +Configuration values +==================== + +.. confval:: spotify/enabled + + If the Spotify extension should be enabled or not. + +.. confval:: spotify/username + + Your Spotify Premium username. + +.. confval:: spotify/password + + Your Spotify Premium password. + +.. confval:: spotify/bitrate + + The preferred audio bitrate. Valid values are 96, 160, 320. + +.. confval:: spotify/timeout + + Max number of seconds to wait for Spotify operations to complete. + +.. confval:: spotify/cache_dir + + Path to the Spotify data cache. Cannot be shared with other Spotify apps. + + +Usage +===== + +If you are using the Spotify backend, which is the default, enter your Spotify +Premium account's username and password into ``~/.config/mopidy/mopidy.conf``, +like this: + +.. code-block:: ini + + [spotify] + username = myusername + password = mysecret + +This will only work if you have the Spotify Premium subscription. Spotify +Unlimited will not work. diff --git a/docs/ext/stream.rst b/docs/ext/stream.rst new file mode 100644 index 00000000..bb30e924 --- /dev/null +++ b/docs/ext/stream.rst @@ -0,0 +1,56 @@ +.. _ext-stream: + +************* +Mopidy-Stream +************* + +Extension for playing streaming music. + +The stream backend will handle streaming of URIs matching the +:confval:`stream/protocols` config value, assuming the needed GStreamer plugins +are installed. + + +Known issues +============ + +https://github.com/mopidy/mopidy/issues?labels=Stream+backend + + +Dependencies +============ + +None. The extension just needs Mopidy. + + +Default configuration +===================== + +.. literalinclude:: ../../mopidy/backends/stream/ext.conf + :language: ini + + +Configuration values +==================== + +.. confval:: stream/enabled + + If the stream extension should be enabled or not. + +.. confval:: stream/protocols + + Whitelist of URI schemas to allow streaming from. + + +Usage +===== + +This backend does not provide a library or similar. It simply takes any URI +added to Mopidy's tracklist that matches any of the protocols in the +:confval:`stream/protocols` setting and tries to play back the URI using +GStreamer. E.g. if you're using an MPD client, you'll just have to find your +clients "add URI" interface, and provide it with the direct URI of the stream. + +Currently the stream backend can only work with URIs pointing direcly at +streams, and not intermediate playlists which is often used. See :issue:`303` +to track the development of playlist expansion support. diff --git a/docs/extensiondev.rst b/docs/extensiondev.rst index ff831b34..51168312 100644 --- a/docs/extensiondev.rst +++ b/docs/extensiondev.rst @@ -1,17 +1,12 @@ +.. _extensiondev: + ********************* Extension development ********************* -.. warning:: Draft - - This document is a draft open for discussion. It shows how we imagine that - development of Mopidy extensions should become in the future, not how to - currently develop an extension for Mopidy. - - Mopidy started as simply an MPD server that could play music from Spotify. Early on Mopidy got multiple "frontends" to expose Mopidy to more than just MPD -clients: for example the Last.fm frontend what scrobbles what you've listened +clients: for example the scrobbler frontend what scrobbles what you've listened to to your Last.fm account, the MPRIS frontend that integrates Mopidy into the Ubuntu Sound Menu, and the HTTP server and JavaScript player API making web based Mopidy clients possible. In Mopidy 0.9 we added support for multiple @@ -30,22 +25,21 @@ extension to behave. Anatomy of an extension ======================= -Extensions are all located in a Python package called ``mopidy_something`` -where "something" is the name of the application, library or web service you -want to integrated with Mopidy. So for example if you plan to add support for a -service named Soundspot to Mopidy, you would name your extension's Python -package ``mopidy_soundspot``. +Extensions are located in a Python package called ``mopidy_something`` where +"something" is the name of the application, library or web service you want to +integrated with Mopidy. So for example if you plan to add support for a service +named Soundspot to Mopidy, you would name your extension's Python package +``mopidy_soundspot``. -The name of the actual extension (the human readable name) however would be -something like "Mopidy-Soundspot". Make sure to include the name "Mopidy" +The extension must be shipped with a ``setup.py`` file and be registered on +`PyPI `_. The name of the distribution on PyPI would +be something like "Mopidy-Soundspot". Make sure to include the name "Mopidy" somewhere in that name and that you check the capitalization. This is the name users will use when they install your extension from PyPI. -The extension must be shipped with a ``setup.py`` file and be registered on -`PyPI `_. Also make sure the development version link -in your package details work so that people can easily install the development -version into their virtualenv simply by running e.g. ``pip install -Mopidy-Soundspot==dev``. +Also make sure the development version link in your package details work so +that people can easily install the development version into their virtualenv +simply by running e.g. ``pip install Mopidy-Soundspot==dev``. Mopidy extensions must be licensed under an Apache 2.0 (like Mopidy itself), BSD, MIT or more liberal license to be able to be enlisted in the Mopidy @@ -57,10 +51,11 @@ extension, Mopidy-Soundspot:: mopidy-soundspot/ # The Git repo root LICENSE # The license text + MANIFEST.in # List of data files to include in PyPI package README.rst # Document what it is and how to use it mopidy_soundspot/ # Your code __init__.py - config.ini # Default configuration for the extension + ext.conf # Default config for the extension ... setup.py # Installation script @@ -73,8 +68,8 @@ Example README.rst The README file should quickly tell what the extension does, how to install it, and how to configure it. The README should contain a development snapshot link to a tarball of the latest development version of the extension. It's important -that the development snapshot link ends with ``#egg=mopidy-something-dev`` for -installation using ``pip install mopidy-something==dev`` to work. +that the development snapshot link ends with ``#egg=Mopidy-Something-dev`` for +installation using ``pip install Mopidy-Something==dev`` to work. .. code-block:: rst @@ -108,7 +103,7 @@ installation using ``pip install mopidy-something==dev`` to work. - `Source code `_ - `Issue tracker `_ - - `Download development snapshot `_ + - `Download development snapshot `_ Example setup.py @@ -120,18 +115,18 @@ register themselves as available Mopidy extensions when they are installed on your system. The example below also includes a couple of convenient tricks for reading the -package version from the source code so that it it's just defined in a single -place, and to reuse the README file as the long description of the package for -the PyPI registration. +package version from the source code so that it is defined in a single place, +and to reuse the README file as the long description of the package for the +PyPI registration. The package must have ``install_requires`` on ``setuptools`` and ``Mopidy``, in addition to any other dependencies required by your extension. The -``entry_points`` part must be included. The ``mopidy.extension`` part cannot be +``entry_points`` part must be included. The ``mopidy.ext`` part cannot be changed, but the innermost string should be changed. It's format is -``my_ext_name = my_py_module:MyExtClass``. ``my_ext_name`` should be a short +``ext_name = package_name:Extension``. ``ext_name`` should be a short name for your extension, typically the part after "Mopidy-" in lowercase. This name is used e.g. to name the config section for your extension. The -``my_py_module:MyExtClass`` part is simply the Python path to the extension +``package_name:Extension`` part is simply the Python path to the extension class that will connect the rest of the dots. :: @@ -158,19 +153,15 @@ class that will connect the rest of the dots. description='Very short description', long_description=open('README.rst').read(), packages=['mopidy_soundspot'], - # If you ship package instead of a single module instead, use - # 'py_modules' instead of 'packages': - #py_modules=['mopidy_soundspot'], zip_safe=False, include_package_data=True, - platforms='any', install_requires=[ 'setuptools', 'Mopidy', 'pysoundspot', ], entry_points={ - 'mopidy.extension': [ + 'mopidy.ext': [ 'soundspot = mopidy_soundspot:Extension', ], }, @@ -184,20 +175,49 @@ class that will connect the rest of the dots. ], ) +To make sure your README, license file and default config file is included in +the package that is uploaded to PyPI, we'll also need to add a ``MANIFEST.in`` +file:: + + include LICENSE + include MANIFEST.in + include README.rst + include mopidy_soundspot/ext.conf + +For details on the ``MANIFEST.in`` file format, check out the `distuitls docs +`_. + Example __init__.py =================== The ``__init__.py`` file should be placed inside the ``mopidy_soundspot`` -Python package. The root of your Python package should have an ``__version__`` -attribute with a :pep:`386` compliant version number, for example "0.1". Next, -it should have a class named ``Extension`` which inherits from Mopidy's -extension base class. This is the class referred to in the ``entry_points`` -part of ``setup.py``. Any imports of other files in your extension should be -kept inside methods. This ensures that this file can be imported without -raising :exc:`ImportError` exceptions for missing dependencies, etc. +Python package. -:: +The root of your Python package should have an ``__version__`` attribute with a +:pep:`386` compliant version number, for example "0.1". Next, it should have a +class named ``Extension`` which inherits from Mopidy's extension base class, +:class:`mopidy.ext.Extension`. This is the class referred to in the +``entry_points`` part of ``setup.py``. Any imports of other files in your +extension should be kept inside methods. This ensures that this file can be +imported without raising :exc:`ImportError` exceptions for missing +dependencies, etc. + +The default configuration for the extension is defined by the +``get_default_config()`` method in the ``Extension`` class which returns a +:mod:`ConfigParser` compatible config section. The config section's name must +be the same as the extension's short name, as defined in the ``entry_points`` +part of ``setup.py``, for example ``soundspot``. All extensions must include +an ``enabled`` config which normally should default to ``true``. Provide good +defaults for all config values so that as few users as possible will need to +change them. The exception is if the config value has security implications; in +that case you should default to the most secure configuration. Leave any +configurations that doesn't have meaningful defaults blank, like ``username`` +and ``password``. In the example below, we've chosen to maintain the default +config as a separate file named ``ext.conf``. This makes it easy to e.g. +include the default config in documentation without duplicating it. + +This is ``mopidy_soundspot/__init__.py``:: from __future__ import unicode_literals @@ -208,8 +228,7 @@ raising :exc:`ImportError` exceptions for missing dependencies, etc. import gst import gobject - from mopidy.exceptions import ExtensionError - from mopidy.utils import ext + from mopidy import config, exceptions, ext __version__ = '0.1' @@ -217,73 +236,44 @@ raising :exc:`ImportError` exceptions for missing dependencies, etc. class Extension(ext.Extension): - name = 'Mopidy-Soundspot' + dist_name = 'Mopidy-Soundspot' + ext_name = 'soundspot' version = __version__ - @classmethod - def get_default_config(cls): - config_file = os.path.join( - os.path.dirname(__file__), 'config.ini') - return open(config_file).read() + def get_default_config(self): + conf_file = os.path.join(os.path.dirname(__file__, 'ext.conf')) + return config.read(conf_file) - @classmethod - def validate_config(cls, config): - # ``config`` is the complete config document for the Mopidy - # instance. The extension is free to check any config value it is - # interested in, not just its own config values. - - if not config.getboolean('soundspot', 'enabled'): - return - if not config.get('soundspot', 'username'): - raise ExtensionError('Config soundspot.username not set') - if not config.get('soundspot', 'password'): - raise ExtensionError('Config soundspot.password not set') - - @classmethod - def validate_environment(cls): - # This method can validate anything it wants about the environment - # the extension is running in. Examples include checking if all - # dependencies are installed. + def get_config_schema(self): + schema = super(Extension, self).get_config_schema() + schema['username'] = config.String() + schema['password'] = config.Secret() + return schema + def validate_environment(self): try: import pysoundspot except ImportError as e: - raise ExtensionError('pysoundspot library not found', e) + raise exceptions.ExtensionError('pysoundspot library not found', e) # You will typically only implement one of the next three methods # in a single extension. - @classmethod - def get_frontend_class(cls): + def get_frontend_classes(self): from .frontend import SoundspotFrontend - return SoundspotFrontend + return [SoundspotFrontend] - @classmethod - def get_backend_class(cls): + def get_backend_classes(self): from .backend import SoundspotBackend - return SoundspotBackend + return [SoundspotBackend] - @classmethod - def register_gstreamer_elements(cls): + def register_gstreamer_elements(self): from .mixer import SoundspotMixer - gobject.type_register(SoundspotMixer) gst.element_register( SoundspotMixer, 'soundspotmixer', gst.RANK_MARGINAL) - - -Example config.ini -================== - -The default configuration for the extension is located in a ``config.ini`` file -inside the Python package. It contains a single config section, with a name -matching the short name used for the extension in the ``entry_points`` part of -``setup.py``. - -All extensions should include an ``enabled`` config which should default to -``true``. Leave any configurations that doesn't have meaningful defaults blank, -like ``username`` and ``password``. +And this is ``mopidy_soundspot/ext.conf``: .. code-block:: ini @@ -292,6 +282,8 @@ like ``username`` and ``password``. username = password = +For more detailed documentation on the extension class, see the :ref:`ext-api`. + Example frontend ================ @@ -350,61 +342,57 @@ If you want to extend Mopidy's GStreamer pipeline with new custom GStreamer elements, you'll need to register them in GStreamer before they can be used. Basically, you just implement your GStreamer element in Python and then make -your :meth:`Extension.register_gstreamer_elements` method register all your -custom GStreamer elements. +your :meth:`~mopidy.ext.Extension.register_gstreamer_elements` method register +all your custom GStreamer elements. For examples of custom GStreamer elements implemented in Python, see :mod:`mopidy.audio.mixers`. -Implementation steps -==================== +Python conventions +================== -A rough plan of how to make the above document the reality of how Mopidy -extensions work. +In general, it would be nice if Mopidy extensions followed the same +:ref:`codestyle` as Mopidy itself, as they're part of the same ecosystem. Among +other things, the code style guide explains why all the above examples start +with ``from __future__ import unicode_literals``. -1. Implement :class:`mopidy.utils.ext.Extension` base class and the - :exc:`mopidy.exceptions.ExtensionError` exception class. -2. Switch from using distutils to setuptools to package and install Mopidy so - that we can register entry points for the bundled extensions and get - information about all extensions available on the system from - :mod:`pkg_resources`. +Use of Mopidy APIs +================== -3. Add :class:`Extension` classes for all existing frontends and backends. Make - sure to add default config files and config validation, even though this - will not be used at this implementation stage. +When writing an extension, you should only use APIs documented at +:ref:`api-ref`. Other parts of Mopidy, like :mod:`mopidy.utils`, may change at +any time, and is not something extensions should rely on being stable. -4. Add entry points for the existing extensions in the ``setup.py`` file. -5. Rewrite the startup procedure to find extensions and thus frontends and - backends via :mod:`pkg_resouces` instead of the ``FRONTENDS`` and - ``BACKENDS`` settings. +Logging in extensions +===================== -6. Remove the ``FRONTENDS`` and ``BACKENDS`` settings. +When making servers like Mopidy, logging is essential for understanding what's +going on. We use the :mod:`logging` module from Python's standard library. When +creating a logger, always namespace the logger using your Python package name +as this will be visible in Mopidy's debug log:: -7. Switch to ini file based configuration, using :mod:`ConfigParser`. The - default config is the combination of a core config file plus the config from - each installed extension. To find the effective config for the system, the - following config sources are added together, with the later ones overriding - the earlier ones: + import logging - - the default config built from Mopidy core and all installed extensions, + logger = logging.getLogger('mopidy_soundspot') - - ``/etc/mopidy.conf``, +When logging at logging level ``info`` or higher (i.e. ``warning``, ``error``, +and ``critical``, but not ``debug``) the log message will be displayed to all +Mopidy users. Thus, the log messages at those levels should be well written and +easy to understand. - - ``~/.config/mopidy.conf``, +As the logger name is not included in Mopidy's default logging format, you +should make it obvious from the log message who is the source of the log +message. For example:: - - any config file provided via command line arguments, and + Loaded 17 Soundspot playlists - - any config values provided via command line arguments. +Is much better than:: -8. Add command line options for: + Loaded 17 playlists - - loading an additional config file for this execution of Mopidy, - - - setting a config value for this execution of Mopidy, - - - printing the effective config and exit, and - - - write a config value permanently to ``~/.config/mopidy.conf`` and exit. +If you want to turn on debug logging for your own extension, but not for +everything else due to the amount of noise, see the docs for the +:confval:`loglevels/*` config section. diff --git a/docs/index.rst b/docs/index.rst index 54745298..199ba31c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,56 +2,71 @@ Mopidy ****** -Mopidy is a music server which can play music both from your :ref:`local hard -drive ` and from :ref:`Spotify `. Searches -returns results from both your local hard drive and from Spotify, and you can -mix tracks from both sources in your play queue. Your Spotify playlists are -also available for use, though we don't support modifying them yet. +Mopidy is a music server which can play music both from multiple sources, like +your :ref:`local hard drive `, :ref:`radio streams `, +and from :ref:`Spotify ` and SoundCloud. Searches combines results +from all music sources, and you can mix tracks from all sources in your play +queue. Your playlists from Spotify or SoundCloud are also available for use. -To control your music server, you can use the :ref:`Ubuntu Sound Menu -` on the machine running Mopidy, any device on the same -network which can control UPnP MediaRenderers (see :ref:`upnp-clients`), or any -:ref:`MPD client `. MPD clients are available for most platforms, -including Windows, Mac OS X, Linux, Android, and iOS. +To control your Mopidy music server, you can use one of Mopidy's :ref:`web +clients `, the :ref:`Ubuntu Sound Menu `, any +device on the same network which can control :ref:`UPnP MediaRenderers +`, or any :ref:`MPD client `. MPD clients are +available for many platforms, including Windows, OS X, Linux, Android and iOS. -To install Mopidy, start by reading :ref:`installation`. +To get started with Mopidy, start by reading :ref:`installation`. If you get stuck, we usually hang around at ``#mopidy`` at `irc.freenode.net -`_ and also got a `mailing list at Google Groups +`_ and also have a `mailing list at Google Groups `_. If you stumble into a bug or got a feature request, please create an issue in the `issue -tracker `_. +tracker `_. The `source code +`_ may also be of help. If you want to stay +up to date on Mopidy developments, you can follow `@mopidy +`_ on Twitter. -Project resources -================= - -- `Documentation `_ -- `Source code `_ -- `Issue tracker `_ -- `CI server `_ -- IRC: ``#mopidy`` at `irc.freenode.net `_ -- Mailing list: `mopidy@googlegroups.com `_ - - -User documentation -================== +Usage +===== .. toctree:: - :maxdepth: 2 + :maxdepth: 3 installation/index installation/raspberrypi - settings + config + ext/index running clients/index + troubleshooting + + +About +===== + +.. toctree:: + :maxdepth: 1 + authors licenses - changes + changelog + versioning -Reference documentation -======================= +Development +=========== + +.. toctree:: + :maxdepth: 1 + + contributing + devtools + codestyle + extensiondev + + +Reference +========= .. toctree:: :maxdepth: 2 @@ -60,16 +75,6 @@ Reference documentation modules/index -Development documentation -========================= - -.. toctree:: - :maxdepth: 2 - - development - extensiondev - - Indices and tables ================== diff --git a/docs/installation/index.rst b/docs/installation/index.rst index 2b9806fd..ae8f6b01 100644 --- a/docs/installation/index.rst +++ b/docs/installation/index.rst @@ -42,7 +42,7 @@ in the same way as you get updates to the rest of your distribution. sudo apt-get update sudo apt-get install mopidy -#. Finally, you need to set a couple of :doc:`settings `, and then +#. Finally, you need to set a couple of :doc:`config values `, and then you're ready to :doc:`run Mopidy `. When a new release of Mopidy is out, and you can't wait for you system to @@ -71,9 +71,10 @@ it out. Arch Linux: Install from AUR ============================ -If you are running Arch Linux, you can install a development snapshot of Mopidy +If you are running Arch Linux, you can install the latest release of Mopidy using the `mopidy-git `_ -package found in AUR. +package found in AUR. The package installs from the ``master`` branch of the +Mopidy Git repo, which always corresponds to the latest release. #. To install Mopidy with GStreamer, libspotify and pyspotify, you can use ``packer``, ``yaourt``, or do it by hand like this:: @@ -89,8 +90,8 @@ package found in AUR. install `python2-pylast `_ from AUR. -#. Finally, you need to set a couple of :doc:`settings `, and then - you're ready to :doc:`run Mopidy `. +#. Finally, you need to set a couple of :doc:`config values `, and + then you're ready to :doc:`run Mopidy `. OS X: Install from Homebrew and Pip @@ -107,13 +108,19 @@ Pip. brew update brew upgrade +#. Mopidy requires GStreamer 0.10, but Homebrew's main formula repo has + upgraded its GStreamer packages to 1.0. Thus, you'll need to add an + alternative formula repo (aka "tap") that has the old GStreamer formulas:: + + brew tap homebrew/versions + #. Install the required packages from Homebrew:: - brew install gst-python gst-plugins-good gst-plugins-ugly libspotify + brew install gst-python010 gst-plugins-good010 gst-plugins-ugly010 libspotify #. Make sure to include Homebrew's Python ``site-packages`` directory in your ``PYTHONPATH``. If you don't include this, Mopidy will not find GStreamer - and crash. + and it will crash. You can either amend your ``PYTHONPATH`` permanently, by adding the following statement to your shell's init file, e.g. ``~/.bashrc``:: @@ -135,13 +142,13 @@ Pip. sudo easy_install pip -#. Then get, build, and install the latest releast of pyspotify, pylast, pykka, +#. Then get, build, and install the latest release of pyspotify, pylast, and Mopidy using Pip:: - sudo pip install -U pyspotify pylast pykka mopidy + sudo pip install -U pyspotify pylast cherrypy ws4py mopidy -#. Finally, you need to set a couple of :doc:`settings `, and then - you're ready to :doc:`run Mopidy `. +#. Finally, you need to set a couple of :doc:`config values `, and + then you're ready to :doc:`run Mopidy `. Otherwise: Install from source using Pip @@ -171,15 +178,7 @@ can install Mopidy from PyPI using Pip. sudo yum install -y gcc python-devel python-pip -#. Then you'll need to install all of Mopidy's hard dependencies: - - - Pykka >= 1.0:: - - sudo pip install -U pykka - - On Fedora the binary is called ``pip-python``:: - - sudo pip-python install -U pykka +#. Then you'll need to install all of Mopidy's hard non-Python dependencies: - GStreamer 0.10.x, with Python bindings. GStreamer is packaged for most popular Linux distributions. Search for GStreamer in your package manager, @@ -235,7 +234,8 @@ can install Mopidy from PyPI using Pip. sudo pip install -U pyspotify - # Fedora: + On Fedora the binary is called ``pip-python``:: + sudo pip-python install -U pyspotify #. Optional: If you want to scrobble your played tracks to Last.fm, you need @@ -243,9 +243,19 @@ can install Mopidy from PyPI using Pip. sudo pip install -U pylast - # Fedora: + On Fedora the binary is called ``pip-python``:: + sudo pip-python install -U pylast +#. Optional: If you want to use the HTTP frontend and web clients, you need + cherrypy and ws4py:: + + sudo pip install -U cherrypy ws4py + + On Fedora the binary is called ``pip-python``:: + + sudo pip-python install -U cherrypy ws4py + #. Optional: To use MPRIS, e.g. for controlling Mopidy from the Ubuntu Sound Menu or from an UPnP client via Rygel, you need some additional dependencies: the Python bindings for libindicate, and the Python bindings @@ -259,7 +269,8 @@ can install Mopidy from PyPI using Pip. sudo pip install -U mopidy - # Fedora: + On Fedora the binary is called ``pip-python``:: + sudo pip-python install -U mopidy To upgrade Mopidy to future releases, just rerun this command. @@ -269,5 +280,5 @@ can install Mopidy from PyPI using Pip. sudo pip install mopidy==dev -#. Finally, you need to set a couple of :doc:`settings `, and then - you're ready to :doc:`run Mopidy `. +#. Finally, you need to set a couple of :doc:`config values `, and + then you're ready to :doc:`run Mopidy `. diff --git a/docs/installation/raspberrypi.rst b/docs/installation/raspberrypi.rst index 020b6edd..c5a4eae8 100644 --- a/docs/installation/raspberrypi.rst +++ b/docs/installation/raspberrypi.rst @@ -4,13 +4,8 @@ Installation on Raspberry Pi **************************** -As of early August, 2012, running Mopidy on a `Raspberry Pi -`_ is possible, although there are a few -significant drawbacks to doing so. This document is intended to help you get -Mopidy running on your Raspberry Pi and to document the progress made and -issues surrounding running Mopidy on the Raspberry Pi. - -As of January 2013, Mopidy will run with Spotify support on both the armel +Mopidy runs nicely on a `Raspberry Pi `_. As of +January 2013, Mopidy will run with Spotify support on both the armel (soft-float) and armhf (hard-float) architectures, which includes the Raspbian distribution. @@ -19,167 +14,28 @@ distribution. :height: 427 -.. _raspi-squeeze: - -How to for Debian 6 (Squeeze) -============================= - -The following guide illustrates how to get Mopidy running on a minimal Debian -squeeze distribution. - -1. The image used can be downloaded at - http://www.linuxsystems.it/2012/06/debian-wheezy-raspberry-pi-minimal-image/. - This image is a very minimal distribution and does not include many common - packages you might be used to having access to. If you find yourself trying - to complete instructions here and getting ``command not found``, try using - ``apt-get`` to install the relevant packages! - -2. Flash the OS image to your SD card. See - http://elinux.org/RPi_Easy_SD_Card_Setup for help. - -3. If you have an SD card that's >2 GB, resize the disk image to use some more - space (we'll need a bit more to install some packages and stuff). See - http://elinux.org/RPi_Resize_Flash_Partitions#Manually_resizing_the_SD_card_on_Raspberry_Pi - for help. - -4. To even get to the point where we can start installing software let's create - a new user and give it sudo access. - - - Install ``sudo``:: - - apt-get install sudo - - - Create a user account:: - - adduser - - - Give the user sudo access by adding it to the ``sudo`` group so we don't - have to do everything on the ``root`` account:: - - adduser sudo - - - While we're at it, give your user access to the sound card by adding it to - the audio group:: - - adduser audio - - - Log in to your Raspberry Pi again with your new user account instead of - the ``root`` account. - -5. Enable the Raspberry Pi's sound drivers: - - - To enable the Raspberry Pi's sound driver:: - - sudo modprobe snd_bcm2835 - - - To load the sound driver at boot time:: - - echo "snd_bcm2835" | sudo tee /etc/modules - -6. Let's get the Raspberry Pi up-to-date: - - - Get some tools that we need to download and run the ``rpi-update`` - script:: - - sudo apt-get install ca-certificates git-core binutils - - - Download ``rpi-update`` from Github:: - - sudo wget https://raw.github.com/Hexxeh/rpi-update/master/rpi-update - - - Move ``rpi-update`` to an appropriate location:: - - sudo mv rpi-update /usr/local/bin/rpi-update - - - Make ``rpi-update`` executable:: - - sudo chmod +x /usr/local/bin/rpi-update - - - Finally! Update your firmware:: - - sudo rpi-update - - - After firmware updating finishes, reboot your Raspberry Pi:: - - sudo reboot - -7. To avoid a couple of potential problems with Mopidy, turn on IPv6 support: - - - Load the IPv6 kernel module now:: - - sudo modprobe ipv6 - - - Add ``ipv6`` to ``/etc/modules`` to ensure the IPv6 kernel module is - loaded on boot:: - - echo ipv6 | sudo tee -a /etc/modules - -8. Installing Mopidy and its dependencies from `apt.mopidy.com - `_, as described in :ref:`installation`. In short:: - - wget -q -O - http://apt.mopidy.com/mopidy.gpg | sudo apt-key add - - sudo wget -q -O /etc/apt/sources.list.d/mopidy.list http://apt.mopidy.com/mopidy.list - sudo apt-get update - sudo apt-get install mopidy - -9. jackd2, which should be installed at this point, seems to cause some - problems. Let's install jackd1, as it seems to work a little bit better:: - - sudo apt-get install jackd1 - -You may encounter some issues with your audio configuration where sound does -not play. If that happens, edit your ``/etc/asound.conf`` to read something -like:: - - pcm.mmap0 { - type mmap_emul; - slave { - pcm "hw:0,0"; - } - } - - pcm.!default { - type plug; - slave { - pcm mmap0; - } - } - - .. _raspi-wheezy: How to for Debian 7 (Wheezy) ============================ -This is a very similar system to Debian 6.0 above, but with a bit newer -software packages, as Wheezy is going to be the next release of Debian. - -1. Download the latest wheezy disk image from +#. Download the latest wheezy disk image from http://downloads.raspberrypi.org/images/debian/7/. I used the one dated 2012-08-08. -2. Flash the OS image to your SD card. See +#. Flash the OS image to your SD card. See http://elinux.org/RPi_Easy_SD_Card_Setup for help. -3. If you have an SD card that's >2 GB, you don't have to resize the file +#. If you have an SD card that's >2 GB, you don't have to resize the file systems on another computer. Just boot up your Raspberry Pi with the unaltered partions, and it will boot right into the ``raspi-config`` tool, which will let you grow the root file system to fill the SD card. This tool will also allow you do other useful stuff, like turning on the SSH server. -4. As opposed to on Squeeze, ``sudo`` comes preinstalled. You can login to the - default user using username ``pi`` and password ``raspberry``. To become - root, just enter ``sudo -i``. +#. You can login to the default user using username ``pi`` and password + ``raspberry``. To become root, just enter ``sudo -i``. - Opposed to on Squeeze, there is no need to add your user to the ``audio`` - group, as the ``pi`` user already is a member of that group. - -5. As opposed to on Squeeze, the correct sound driver comes preinstalled. - -6. As opposed to on Squeeze, your kernel and GPU firmware is rather up to date - when running Wheezy. - -7. To avoid a couple of potential problems with Mopidy, turn on IPv6 support: +#. To avoid a couple of potential problems with Mopidy, turn on IPv6 support: - Load the IPv6 kernel module now:: @@ -190,7 +46,7 @@ software packages, as Wheezy is going to be the next release of Debian. echo ipv6 | sudo tee -a /etc/modules -8. Installing Mopidy and its dependencies from `apt.mopidy.com +#. Installing Mopidy and its dependencies from `apt.mopidy.com `_, as described in :ref:`installation`. In short:: wget -q -O - http://apt.mopidy.com/mopidy.gpg | sudo apt-key add - @@ -198,7 +54,7 @@ software packages, as Wheezy is going to be the next release of Debian. sudo apt-get update sudo apt-get install mopidy -9. Since I have a HDMI cable connected, but want the sound on the analog sound +#. Since I have a HDMI cable connected, but want the sound on the analog sound connector, I have to run:: amixer cset numid=3 1 @@ -209,34 +65,16 @@ software packages, as Wheezy is going to be the next release of Debian. aplay /usr/share/sounds/alsa/Front_Center.wav - If you hear a voice saying "Front Center", then your sound is working. Don't - be concerned if this test sound includes static. Test your sound with - GStreamer to determine the sound quality of Mopidy. + If you hear a voice saying "Front Center", then your sound is working. To make the change to analog output stick, you can add the ``amixer`` command to e.g. ``/etc/rc.local``, which will be executed when the system is booting. -Audio quality issues -==================== - -The Raspberry Pi's audio quality can be sub-par through the analog output. This -is known and unlikely to be fixed as including any higher-quality hardware -would increase the cost of the board. If you experience crackling/hissing or -skipping audio, you may want to try a USB sound card. Additionally, you could -lower your default ALSA sampling rate to 22KHz, though this will lead to a -substantial decrease in sound quality. +Fixing audio quality issues +=========================== As of January 2013, some reports also indicate that pushing the audio through PulseAudio may help. We hope to, in the future, provide a complete set of instructions here leading to acceptable analog audio quality. - - -Support -======= - -If you had trouble with the above or got Mopidy working a different way on -Raspberry Pi, please send us a pull request to update this page with your new -information. As usual, the folks at ``#mopidy`` on ``irc.freenode.net`` may be -able to help with any problems encountered. diff --git a/docs/licenses.rst b/docs/licenses.rst index 11e0a906..fc2530e5 100644 --- a/docs/licenses.rst +++ b/docs/licenses.rst @@ -8,7 +8,7 @@ contributed what, please refer to our git repository. Source code license =================== -Copyright 2009-2012 Stein Magnus Jodal and contributors +Copyright 2009-2013 Stein Magnus Jodal and contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ limitations under the License. Documentation license ===================== -Copyright 2010-2012 Stein Magnus Jodal and contributors +Copyright 2010-2013 Stein Magnus Jodal and contributors This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. To view a copy of this license, visit diff --git a/docs/modules/audio/mixers/nad.rst b/docs/modules/audio/mixers/nad.rst deleted file mode 100644 index 661dc723..00000000 --- a/docs/modules/audio/mixers/nad.rst +++ /dev/null @@ -1,6 +0,0 @@ -********************************************* -:mod:`mopidy.audio.mixers.nad` -- NAD mixer -********************************************* - -.. automodule:: mopidy.audio.mixers.nad - :synopsis: Mixer element for controlling volume on NAD amplifiers diff --git a/docs/modules/backends/dummy.rst b/docs/modules/backends/dummy.rst deleted file mode 100644 index 03b2e6ce..00000000 --- a/docs/modules/backends/dummy.rst +++ /dev/null @@ -1,7 +0,0 @@ -********************************************************* -:mod:`mopidy.backends.dummy` -- Dummy backend for testing -********************************************************* - -.. automodule:: mopidy.backends.dummy - :synopsis: Dummy backend used for testing - :members: diff --git a/docs/modules/backends/local.rst b/docs/modules/backends/local.rst deleted file mode 100644 index 9ac93bc8..00000000 --- a/docs/modules/backends/local.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _local-backend: - -********************************************* -:mod:`mopidy.backends.local` -- Local backend -********************************************* - -.. automodule:: mopidy.backends.local - :synopsis: Backend for playing music files on local storage diff --git a/docs/modules/backends/spotify.rst b/docs/modules/backends/spotify.rst deleted file mode 100644 index b410f272..00000000 --- a/docs/modules/backends/spotify.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _spotify-backend: - -************************************************* -:mod:`mopidy.backends.spotify` -- Spotify backend -************************************************* - -.. automodule:: mopidy.backends.spotify - :synopsis: Backend for the Spotify music streaming service diff --git a/docs/modules/backends/stream.rst b/docs/modules/backends/stream.rst deleted file mode 100644 index 73e53048..00000000 --- a/docs/modules/backends/stream.rst +++ /dev/null @@ -1,7 +0,0 @@ -*********************************************** -:mod:`mopidy.backends.stream` -- Stream backend -*********************************************** - -.. automodule:: mopidy.backends.stream - :synopsis: Backend for playing audio streams - :members: diff --git a/docs/modules/frontends/http.rst b/docs/modules/frontends/http.rst deleted file mode 100644 index 31366bd1..00000000 --- a/docs/modules/frontends/http.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _http-frontend: - -********************************************* -:mod:`mopidy.frontends.http` -- HTTP frontend -********************************************* - -.. automodule:: mopidy.frontends.http - :synopsis: HTTP and WebSockets frontend diff --git a/docs/modules/frontends/lastfm.rst b/docs/modules/frontends/lastfm.rst deleted file mode 100644 index 0dba922f..00000000 --- a/docs/modules/frontends/lastfm.rst +++ /dev/null @@ -1,6 +0,0 @@ -*************************************************** -:mod:`mopidy.frontends.lastfm` -- Last.fm Scrobbler -*************************************************** - -.. automodule:: mopidy.frontends.lastfm - :synopsis: Last.fm scrobbler frontend diff --git a/docs/modules/frontends/mpd.rst b/docs/modules/frontends/mpd.rst index f25b90f2..750d19bb 100644 --- a/docs/modules/frontends/mpd.rst +++ b/docs/modules/frontends/mpd.rst @@ -2,6 +2,8 @@ :mod:`mopidy.frontends.mpd` -- MPD server ***************************************** +For details on how to use Mopidy's MPD server, see :ref:`ext-mpd`. + .. automodule:: mopidy.frontends.mpd :synopsis: MPD server frontend diff --git a/docs/modules/frontends/mpris.rst b/docs/modules/frontends/mpris.rst deleted file mode 100644 index e0ec63da..00000000 --- a/docs/modules/frontends/mpris.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _mpris-frontend: - -*********************************************** -:mod:`mopidy.frontends.mpris` -- MPRIS frontend -*********************************************** - -.. automodule:: mopidy.frontends.mpris - :synopsis: MPRIS frontend diff --git a/docs/running.rst b/docs/running.rst index 6c8d0ede..fc6cc249 100644 --- a/docs/running.rst +++ b/docs/running.rst @@ -18,3 +18,124 @@ using ``kill``:: kill `ps ax | grep mopidy | grep -v grep | cut -d' ' -f1` This can be useful e.g. if you create init script for managing Mopidy. + + +mopidy command +============== + +.. program:: mopidy + +.. cmdoption:: --version + + Show Mopidy's version number and exit. + +.. cmdoption:: -h, --help + + Show help message and exit. + +.. cmdoption:: -q, --quiet + + Show less output: warning level and higher. + +.. cmdoption:: -v, --verbose + + Show more output: debug level and higher. + +.. cmdoption:: --save-debug-log + + Save debug log to the file specified in the :confval:`logging/debug_file` + config value, typically ``./mopidy.conf``. + +.. cmdoption:: --show-config + + Show the current effective config. All configuration sources are merged + together to show the effective document. Secret values like passwords are + masked out. Config for disabled extensions are not included. + +.. cmdoption:: --show-deps + + Show dependencies, their versions and installation location. + +.. cmdoption:: --config + + Specify config file to use. To use multiple config files, separate them + with colon. The later files override the earlier ones if there's a + conflict. + +.. cmdoption:: -o