From 76f568e0f0fba1ac9a68dbfb2f094e2f9a7cbcd4 Mon Sep 17 00:00:00 2001 From: Nick Steel Date: Sat, 26 Jul 2014 13:27:52 +0100 Subject: [PATCH 01/27] Added section on running a developed extension Also some typos and updates. --- docs/extensiondev.rst | 60 +++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/docs/extensiondev.rst b/docs/extensiondev.rst index dba0fa83..c0d36515 100644 --- a/docs/extensiondev.rst +++ b/docs/extensiondev.rst @@ -5,9 +5,9 @@ Extension development ********************* 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 scrobbler frontend what scrobbles what you've listened -to to your Last.fm account, the MPRIS frontend that integrates Mopidy into the +Early on, Mopidy got multiple "frontends" to expose Mopidy to more than just MPD +clients: for example the scrobbler frontend that scrobbles your listening +history 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 music sources without stopping and reconfiguring Mopidy: for example the local @@ -27,7 +27,7 @@ Anatomy of an extension 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 +integrate 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``. @@ -37,10 +37,6 @@ 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. -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 documentation. The license text should be included in the ``LICENSE`` file in @@ -79,11 +75,11 @@ the readme of `cookiecutter-mopidy-ext 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. +The README file should quickly explain what the extension does, how to install +it, and how to configure it. It should also contain a link to a tarball of the +latest development version of the extension. It's important that this link ends +with ``#egg=Mopidy-Something-dev`` for installation using +``pip install Mopidy-Something==dev`` to work. .. code-block:: rst @@ -124,7 +120,7 @@ installation using ``pip install Mopidy-Something==dev`` to work. - `Source code `_ - `Issue tracker `_ - - `Download development snapshot `_ + - `Development branch tarball `_ Changelog @@ -239,9 +235,9 @@ The root of your Python package should have an ``__version__`` attribute with 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. +extension, outside of Mopidy and it's core requirements, 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 @@ -252,10 +248,10 @@ 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`` +configurations that don'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. +config as a separate file named ``ext.conf``. This makes it easy to include the +default config in documentation without duplicating it. This is ``mopidy_soundspot/__init__.py``:: @@ -321,6 +317,9 @@ This is ``mopidy_soundspot/__init__.py``:: gobject.type_register(SoundspotMixer) gst.element_register( SoundspotMixer, 'soundspotmixer', gst.RANK_MARGINAL) + + # Or nothing to register e.g. command extension + pass And this is ``mopidy_soundspot/ext.conf``: @@ -393,7 +392,7 @@ such as scanning for media, adding a command is the way to go. Your top level command name will always match your extension name, but you are free to add sub-commands with names of your choosing. -The skeleton of a commands would look like this. See :ref:`commands-api` for +The skeleton of a command would look like this. See :ref:`commands-api` for more details. :: @@ -409,14 +408,14 @@ more details. self.add_argument('--foo') def run(self, args, config, extensions): - # Your backend implementation + # Your command implementation return 0 Example web application ======================= -As of Mopidy 0.19, extensions can use Mopidy's builtin web server to host +As of Mopidy 0.19, extensions can use Mopidy's built-in web server to host static web clients as well as Tornado and WSGI web applications. For several examples, see the :ref:`http-server-api` docs or explore with :ref:`http-explore-extension` extension. @@ -433,6 +432,17 @@ your :meth:`~mopidy.ext.Extension.setup` method register all your custom GStreamer elements. +Running an extension +==================== + +Once your extension is ready to go, to see it in action you'll need to register +it with Mopidy. Typically this is done by running ``python setup.py install`` +from your extension's Git repo root directory. While developing your extension +and to avoid doing this every time you make a change, you can instead run +``python setup.py develop`` to effectively link Mopidy directly with your +development files. + + Python conventions ================== @@ -447,13 +457,13 @@ Use of Mopidy APIs 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 use. +any time and are not something extensions should use. Logging in extensions ===================== -When making servers like Mopidy, logging is essential for understanding what's +For 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:: From a2128864e77934dff52ee002fae82a8f39ea7319 Mon Sep 17 00:00:00 2001 From: Nick Steel Date: Sat, 26 Jul 2014 13:38:28 +0100 Subject: [PATCH 02/27] Fixed typo in comment --- mopidy/commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy/commands.py b/mopidy/commands.py index e43f182e..f7c71d4e 100644 --- a/mopidy/commands.py +++ b/mopidy/commands.py @@ -219,7 +219,7 @@ class Command(object): def run(self, *args, **kwargs): """Run the command. - Must be implemented by sub-classes that are not simply and intermediate + Must be implemented by sub-classes that are not simply an intermediate in the command namespace. """ raise NotImplementedError From 711caa9417b1ad0c4a49a111a8e35b3b50e0126f Mon Sep 17 00:00:00 2001 From: dz0ny Date: Sat, 26 Jul 2014 14:54:21 +0200 Subject: [PATCH 03/27] avahi: Service hostname must contain, resolvable fqdn with .local appended to it. --- mopidy/http/actor.py | 4 ++-- mopidy/mpd/actor.py | 2 +- mopidy/zeroconf.py | 10 +++------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/mopidy/http/actor.py b/mopidy/http/actor.py index a477d939..57e2f46a 100644 --- a/mopidy/http/actor.py +++ b/mopidy/http/actor.py @@ -58,10 +58,10 @@ class HttpFrontend(pykka.ThreadingActor, CoreListener): if self.zeroconf_name: self.zeroconf_http = zeroconf.Zeroconf( stype='_http._tcp', name=self.zeroconf_name, - host=self.hostname, port=self.port) + port=self.port) self.zeroconf_mopidy_http = zeroconf.Zeroconf( stype='_mopidy-http._tcp', name=self.zeroconf_name, - host=self.hostname, port=self.port) + port=self.port) self.zeroconf_http.publish() self.zeroconf_mopidy_http.publish() diff --git a/mopidy/mpd/actor.py b/mopidy/mpd/actor.py index 23d88bf9..49d9556e 100644 --- a/mopidy/mpd/actor.py +++ b/mopidy/mpd/actor.py @@ -43,7 +43,7 @@ class MpdFrontend(pykka.ThreadingActor, CoreListener): if self.zeroconf_name: self.zeroconf_service = zeroconf.Zeroconf( stype='_mpd._tcp', name=self.zeroconf_name, - host=self.hostname, port=self.port) + port=self.port) self.zeroconf_service.publish() def on_stop(self): diff --git a/mopidy/zeroconf.py b/mopidy/zeroconf.py index cdd84792..0f991ba3 100644 --- a/mopidy/zeroconf.py +++ b/mopidy/zeroconf.py @@ -43,21 +43,17 @@ class Zeroconf(object): :type text: list of str """ - def __init__(self, name, port, stype=None, domain=None, - host=None, text=None): + def __init__(self, name, port, stype=None, domain=None, text=None): self.group = None self.stype = stype or '_http._tcp' self.domain = domain or '' self.port = port self.text = text or [] - if host in ('::', '0.0.0.0'): - self.host = '' - else: - self.host = host template = string.Template(name) self.name = template.safe_substitute( - hostname=self.host or socket.getfqdn(), port=self.port) + hostname=socket.getfqdn(), port=self.port) + self.host = '%s.local' % socket.getfqdn() def __str__(self): return 'Zeroconf service %s at [%s]:%d' % ( From f14519a86c5b5b835caeb1cfcff999dee0a23eba Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 26 Jul 2014 15:12:31 +0200 Subject: [PATCH 04/27] docs: Update changelog wrt PR #795 --- docs/changelog.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 0d32ae5b..865bde2f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,13 @@ Changelog This changelog is used to track all major changes to Mopidy. +v0.19.3 (UNRELEASED) +==================== + +- Fix Zeroconf discovery by adding ``.local`` to the announced hostname. (PR: + :issue:`795`) + + v0.19.2 (2014-07-26) ==================== From 22bf058c34b25e1cb802c707e38e46c3ddfa005f Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 26 Jul 2014 15:35:29 +0200 Subject: [PATCH 05/27] Update .mailmap --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index a3a35c2a..d380162e 100644 --- a/.mailmap +++ b/.mailmap @@ -15,3 +15,4 @@ Janez Troha Janez Troha Luke Giuliani Colin Montgomerie +Ignasi Fosch From 8459464f34d0eebfe3eba12bd7e68e06c938bc9b Mon Sep 17 00:00:00 2001 From: Ignasi Fosch Date: Sat, 26 Jul 2014 16:31:37 +0200 Subject: [PATCH 06/27] Fix mopidy/audio/scan.py to avoid negative values in track lengths The fix is the most elegant I found, but it might pass undetected. --- mopidy/audio/scan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy/audio/scan.py b/mopidy/audio/scan.py index e872d88c..755ab366 100644 --- a/mopidy/audio/scan.py +++ b/mopidy/audio/scan.py @@ -186,7 +186,7 @@ def audio_data_to_track(data): track_kwargs['date'] = _date(tags) track_kwargs['last_modified'] = int(data.get('mtime') or 0) - track_kwargs['length'] = (data.get(gst.TAG_DURATION) or 0) // gst.MSECOND + track_kwargs['length'] = max(0, (data.get(gst.TAG_DURATION) or 0)) // gst.MSECOND # Clear out any empty values we found track_kwargs = {k: v for k, v in track_kwargs.items() if v} From b13505ea4560c6754186ab9d3c60a0a59dbd64ca Mon Sep 17 00:00:00 2001 From: Ignasi Fosch Date: Sat, 26 Jul 2014 16:42:42 +0200 Subject: [PATCH 07/27] Fix the Line too long lint error --- mopidy/audio/scan.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mopidy/audio/scan.py b/mopidy/audio/scan.py index 755ab366..6c23e954 100644 --- a/mopidy/audio/scan.py +++ b/mopidy/audio/scan.py @@ -186,7 +186,8 @@ def audio_data_to_track(data): track_kwargs['date'] = _date(tags) track_kwargs['last_modified'] = int(data.get('mtime') or 0) - track_kwargs['length'] = max(0, (data.get(gst.TAG_DURATION) or 0)) // gst.MSECOND + track_kwargs['length'] = max( + 0, (data.get(gst.TAG_DURATION) or 0)) // gst.MSECOND # Clear out any empty values we found track_kwargs = {k: v for k, v in track_kwargs.items() if v} From 5daa95cae8b78b47105740578acc657bc2329f0a Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 26 Jul 2014 16:54:32 +0200 Subject: [PATCH 08/27] docs: Update changelog --- docs/changelog.rst | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 865bde2f..ac8084d3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,7 +8,12 @@ This changelog is used to track all major changes to Mopidy. v0.19.3 (UNRELEASED) ==================== -- Fix Zeroconf discovery by adding ``.local`` to the announced hostname. (PR: +Bug fix release. + +- Audio: Fix negative track length for radio streams. (Fixes: :issue:`662`, + PR: :issue:`796`) + +- Zeroconf: Fix discovery by adding ``.local`` to the announced hostname. (PR: :issue:`795`) @@ -18,20 +23,15 @@ v0.19.2 (2014-07-26) Bug fix release, directly from the Mopidy development sprint at EuroPython 2014 in Berlin. -**Audio** - -- Make :confval:`audio/mixer_volume` work on the software mixer again. This +- Audio: Make :confval:`audio/mixer_volume` work on the software mixer again. This was broken with the mixer changes in 0.19.0. (Fixes: :issue:`791`) -**HTTP frontend** +- HTTP frontend: When using Tornado 4.0, allow WebSocket requests from other + hosts. (Fixes: :issue:`788`) -- When using Tornado 4.0, allow WebSocket requests from other hosts. (Fixes: - :issue:`788`) - -**MPD frontend** - -- Fix crash when MPD commands are called with the wrong number of arguments. - This was broken with the MPD command changes in 0.19.0. (Fixes: :issue:`789`) +- MPD frontend: Fix crash when MPD commands are called with the wrong number of + arguments. This was broken with the MPD command changes in 0.19.0. (Fixes: + :issue:`789`) v0.19.1 (2014-07-23) @@ -39,21 +39,15 @@ v0.19.1 (2014-07-23) Bug fix release. -**Dependencies** +- Dependencies: Mopidy now requires Tornado >= 2.3, instead of >= 3.1. This + should make Mopidy continue to work on Debian/Raspbian stable, where Tornado + 2.3 is the newest version available. -- Mopidy now requires Tornado >= 2.3, instead of >= 3.1. This should make - Mopidy continue to work on Debian/Raspbian stable, where Tornado 2.3 is the - newest version available. +- HTTP frontend: Add missing string interpolation placeholder. -**HTTP frontend** - -- Add missing string interpolation placeholder. - -**Development** - -- ``mopidy --version`` and :meth:`mopidy.core.Core.get_version` now returns the - correct version when Mopidy is run from a Git repo other than Mopidy's own. - (Related to :issue:`706`) +- Development: ``mopidy --version`` and :meth:`mopidy.core.Core.get_version` + now returns the correct version when Mopidy is run from a Git repo other than + Mopidy's own. (Related to :issue:`706`) v0.19.0 (2014-07-21) From 4d5f60fd067b67132364206e4e74e69413417bcc Mon Sep 17 00:00:00 2001 From: Arjun Naik Date: Sun, 27 Jul 2014 11:41:27 +0000 Subject: [PATCH 09/27] Workaround for RasPi selecting jack server. --- mopidy/audio/actor.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mopidy/audio/actor.py b/mopidy/audio/actor.py index dcc51ea4..f3880210 100644 --- a/mopidy/audio/actor.py +++ b/mopidy/audio/actor.py @@ -72,6 +72,7 @@ class Audio(pykka.ThreadingActor): def on_start(self): try: + self._setup_preferences() self._setup_playbin() self._setup_output() self._setup_mixer() @@ -96,6 +97,12 @@ class Audio(pykka.ThreadingActor): if signal_id is not None: element.disconnect(signal_id) + def _setup_preferences(self): + registry = gst.registry_get_default() + jacksink = registry.find_feature('jackaudiosink', gst.TYPE_ELEMENT_FACTORY) + if jacksink: + jacksink.set_rank(gst.RANK_SECONDARY) + def _setup_playbin(self): playbin = gst.element_factory_make('playbin2') playbin.set_property('flags', PLAYBIN_FLAGS) From f4777e50c2b51bf10ce402fe351a381e61a35780 Mon Sep 17 00:00:00 2001 From: Arjun Naik Date: Sun, 27 Jul 2014 14:33:34 +0000 Subject: [PATCH 10/27] Fixed long line Flake8 warning. --- mopidy/audio/actor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mopidy/audio/actor.py b/mopidy/audio/actor.py index f3880210..5b4362a3 100644 --- a/mopidy/audio/actor.py +++ b/mopidy/audio/actor.py @@ -99,7 +99,8 @@ class Audio(pykka.ThreadingActor): def _setup_preferences(self): registry = gst.registry_get_default() - jacksink = registry.find_feature('jackaudiosink', gst.TYPE_ELEMENT_FACTORY) + jacksink = registry.find_feature( + 'jackaudiosink', gst.TYPE_ELEMENT_FACTORY) if jacksink: jacksink.set_rank(gst.RANK_SECONDARY) From 6367b837350bf9126130fc1ed3ad9b6600d6d916 Mon Sep 17 00:00:00 2001 From: dz0ny Date: Mon, 28 Jul 2014 20:48:06 +0200 Subject: [PATCH 11/27] Test with multiple versions of tornado. See #798 --- .travis.yml | 2 ++ tox.ini | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c838e7d0..77a8d8a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,8 @@ python: env: - TOX_ENV=py27 + - TOX_ENV=tornado2.3 + - TOX_ENV=tornado3.2 - TOX_ENV=docs - TOX_ENV=flake8 diff --git a/tox.ini b/tox.ini index e8946523..93447015 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,23 @@ [tox] -envlist = py27, docs, flake8 +envlist = tornado2.3, tornado3.2, py27, docs, flake8 [testenv] sitepackages = true +commands = nosetests -v --with-xunit --xunit-file=xunit-{envname}.xml --with-coverage --cover-package=mopidy deps = coverage mock nose -commands = nosetests -v --with-xunit --xunit-file=xunit-{envname}.xml --with-coverage --cover-package=mopidy + +[testenv:tornado2.3] +commands = nosetests -v tests/http +deps = {[testenv]deps} + tornado==2.3 + +[testenv:tornado3.2] +commands = nosetests -v tests/http +deps = {[testenv]deps} + tornado==3.1 [testenv:docs] deps = -r{toxinidir}/docs/requirements.txt From df4c5d8bcb311b88f0d1031c67c3a265b3706c49 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Mon, 28 Jul 2014 23:41:17 +0200 Subject: [PATCH 12/27] tox: Fix Tornado version mismatch in env name and deps (cherry picked from commit acef38a6c75bb46324d4a49b57552f2320f02694) --- tox.ini | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tox.ini b/tox.ini index 93447015..ed6f0271 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = tornado2.3, tornado3.2, py27, docs, flake8 +envlist = py27, py27-tornado23, py27-tornado31, docs, flake8 [testenv] sitepackages = true @@ -9,14 +9,16 @@ deps = mock nose -[testenv:tornado2.3] +[testenv:py27-tornado23] commands = nosetests -v tests/http -deps = {[testenv]deps} +deps = + {[testenv]deps} tornado==2.3 -[testenv:tornado3.2] +[testenv:py27-tornado31] commands = nosetests -v tests/http -deps = {[testenv]deps} +deps = + {[testenv]deps} tornado==3.1 [testenv:docs] From 4cb858771f334039d05fc4c0925f0fe95840aea0 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Tue, 29 Jul 2014 23:15:05 +0200 Subject: [PATCH 13/27] travis: Update tox env names (cherry picked from commit e950cf5501bf82787e202024774a4e5f6f85ed27) --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 77a8d8a3..8e14280f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,8 @@ python: env: - TOX_ENV=py27 - - TOX_ENV=tornado2.3 - - TOX_ENV=tornado3.2 + - TOX_ENV=py27-tornado23 + - TOX_ENV=py27-tornado31 - TOX_ENV=docs - TOX_ENV=flake8 From 1b8feefcdc3215f57f3ba982b5abe807cbe4a0fd Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 29 Jul 2014 23:45:22 +0200 Subject: [PATCH 14/27] audio: Link to context of why we demote jack sinks (cherry picked from commit 29019d94af42e81b478dd283a70c809f78e5f650) --- mopidy/audio/actor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mopidy/audio/actor.py b/mopidy/audio/actor.py index 5b4362a3..0d90394d 100644 --- a/mopidy/audio/actor.py +++ b/mopidy/audio/actor.py @@ -98,6 +98,7 @@ class Audio(pykka.ThreadingActor): element.disconnect(signal_id) def _setup_preferences(self): + # Fix for https://github.com/mopidy/mopidy/issues/604 registry = gst.registry_get_default() jacksink = registry.find_feature( 'jackaudiosink', gst.TYPE_ELEMENT_FACTORY) From 2b758195056f1cad6ab8827e52838969971395bd Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 29 Jul 2014 23:47:23 +0200 Subject: [PATCH 15/27] doc: Add changelog entry for jack sink fix (cherry picked from commit 0440703abbe8a96eb45a1795fdca2482f7998b9d) Conflicts: docs/changelog.rst --- docs/changelog.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index ac8084d3..3502425a 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -13,6 +13,8 @@ Bug fix release. - Audio: Fix negative track length for radio streams. (Fixes: :issue:`662`, PR: :issue:`796`) +- Audio: Tell GStreamer to not pick Jack sink. (Fixes: :issue:`604`) + - Zeroconf: Fix discovery by adding ``.local`` to the announced hostname. (PR: :issue:`795`) From 2c04d97eaf510f1b67dc70236f99c57c14c9f154 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Tue, 29 Jul 2014 23:46:16 +0200 Subject: [PATCH 16/27] docs: Update authors (cherry picked from commit 614dc93ad85e58be563f3cb7cfb4ffa3c951b202) --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 7a20f492..e36d953d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -41,3 +41,4 @@ - Thomas Scholtes - Sam Willcocks - Ignasi Fosch +- Arjun Naik From 24db560fd054b0c549d4652b54242d46582d6bbe Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Tue, 29 Jul 2014 23:41:59 +0200 Subject: [PATCH 17/27] docs: Add Mopidy-Banshee (cherry picked from commit a470e0c9147d528fa09a1fedccfe0f9f507bc433) --- docs/ext/backends.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/ext/backends.rst b/docs/ext/backends.rst index 1b0bf112..c4074a12 100644 --- a/docs/ext/backends.rst +++ b/docs/ext/backends.rst @@ -11,6 +11,15 @@ 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 `. +Mopidy-Banshee +============== + +https://github.com/tamland/mopidy-banshee + +Provides a backend for playing music from the `Banshee `_ +music player's music library. + + Mopidy-Beets ============ From 195b78a50b2a2cc5ebb4b3e4e075e47c7c5ff21e Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Tue, 29 Jul 2014 23:43:57 +0200 Subject: [PATCH 18/27] docs: Add Mopidy-Bassdrive (cherry picked from commit c51988546da16fdb1017c7411fd26b70f783e4d4) --- docs/ext/backends.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/ext/backends.rst b/docs/ext/backends.rst index c4074a12..06f6244c 100644 --- a/docs/ext/backends.rst +++ b/docs/ext/backends.rst @@ -20,6 +20,15 @@ Provides a backend for playing music from the `Banshee `_ music player's music library. +Mopidy-Bassdrive +================ + +https://github.com/felixb/mopidy-Bassdrive + +Provides a backend for playing radio streams from `BassDrive +`_. + + Mopidy-Beets ============ From 6c684e1cbed7c177575ebf1d2cd0e708b64c0edf Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 30 Jul 2014 00:24:28 +0200 Subject: [PATCH 19/27] docs: Add Mopidy-LeftAsRain (cherry picked from commit 2a28128c37732f07e6ddaa1cd712949cbad49245) --- docs/ext/backends.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/ext/backends.rst b/docs/ext/backends.rst index 06f6244c..2b516f55 100644 --- a/docs/ext/backends.rst +++ b/docs/ext/backends.rst @@ -65,6 +65,15 @@ Extension for playing music and audio from the `Internet Archive `_. +Mopidy-LeftAsRain +================= + +https://github.com/naglis/mopidy-leftasrain + +Extension for playing music from the `leftasrain.com +`_ music blog. + + Mopidy-Local ============ From 3a442483eb209e137d4ba32101898305f2592743 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 30 Jul 2014 00:27:26 +0200 Subject: [PATCH 20/27] docs: Add Mopidy-Touchscreen (cherry picked from commit 27d4c89ae98c8cf64fc3da355050c180d35ac232) --- docs/ext/frontends.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/ext/frontends.rst b/docs/ext/frontends.rst index 481ac510..1010b1f6 100644 --- a/docs/ext/frontends.rst +++ b/docs/ext/frontends.rst @@ -47,3 +47,12 @@ Mopidy-Scrobbler https://github.com/mopidy/mopidy-scrobbler Extension for scrobbling played tracks to Last.fm. + + +Mopidy-Touchscreen +================== + +https://github.com/9and3r/mopidy-touchscreen + +Extension for displaying track info and controlling Mopidy from a touch screen +using `PyGame `_/SDL. From 8376286e7e20dd5c5a595d4d6eb87bc401fb51f3 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Sun, 3 Aug 2014 11:43:28 +0200 Subject: [PATCH 21/27] zeroconf: Fix intermittent dbus/avahi exception This fixes an issue where I sometimes would get an error from dbus 'Unable to guess signature from an empty list'. After some digging and checking the avahi dbus specs I found they expect the text list to have a signature of 'aay' (an array of arrays containing bytes). So instead of using python lists we now use a 'typed' dbus array. It is not clear to me why this is a heisenbug, but this fix does seem to make it go away. (cherry picked from commit 80f5c9158d485099fac9693d7fbad74a29578a09) --- mopidy/zeroconf.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mopidy/zeroconf.py b/mopidy/zeroconf.py index 0f991ba3..9f726957 100644 --- a/mopidy/zeroconf.py +++ b/mopidy/zeroconf.py @@ -23,8 +23,11 @@ def _is_loopback_address(host): host == '::1') -def _convert_text_to_dbus_bytes(text): - return [dbus.Byte(ord(c)) for c in text] +def _convert_text_list_to_dbus_format(text_list): + array = dbus.Array(signature='ay') + for text in text_list: + array.append([dbus.Byte(ord(c)) for c in text]) + return array class Zeroconf(object): @@ -91,11 +94,11 @@ class Zeroconf(object): 'org.freedesktop.Avahi', server.EntryGroupNew()), 'org.freedesktop.Avahi.EntryGroup') - text = [_convert_text_to_dbus_bytes(t) for t in self.text] self.group.AddService( _AVAHI_IF_UNSPEC, _AVAHI_PROTO_UNSPEC, dbus.UInt32(_AVAHI_PUBLISHFLAGS_NONE), self.name, self.stype, - self.domain, self.host, dbus.UInt16(self.port), text) + self.domain, self.host, dbus.UInt16(self.port), + _convert_text_list_to_dbus_format(self.text)) self.group.Commit() logger.debug('%s: Published', self) From 2d4b447d0a0302a917cebcb64bae816f02e0cbae Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 3 Aug 2014 15:19:33 +0200 Subject: [PATCH 22/27] docs: Update changelog --- docs/changelog.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 3502425a..c5bc83f8 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,6 +18,8 @@ Bug fix release. - Zeroconf: Fix discovery by adding ``.local`` to the announced hostname. (PR: :issue:`795`) +- Zeroconf: Fix intermittent DBus/Avahi exception. + v0.19.2 (2014-07-26) ==================== From 837fb00fb7157ef789eb54b7729a8bc1b5196902 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 3 Aug 2014 23:13:12 +0200 Subject: [PATCH 23/27] Fail early if extension doesn't implement setup() Fixes #813 --- docs/changelog.rst | 4 ++++ mopidy/ext.py | 2 +- tests/test_ext.py | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index c5bc83f8..277c79ed 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -20,6 +20,10 @@ Bug fix release. - Zeroconf: Fix intermittent DBus/Avahi exception. +- Extensions: Fail early if trying to setup an extension which doesn't + implement the :meth:`mopidy.ext.Extension.setup` method. (Fixes: + :issue:`813`) + v0.19.2 (2014-07-26) ==================== diff --git a/mopidy/ext.py b/mopidy/ext.py index d259b686..3f375a69 100644 --- a/mopidy/ext.py +++ b/mopidy/ext.py @@ -99,7 +99,7 @@ class Extension(object): :param registry: the extension registry :type registry: :class:`Registry` """ - pass + raise NotImplementedError class Registry(collections.Mapping): diff --git a/tests/test_ext.py b/tests/test_ext.py index 5338c91d..428f3712 100644 --- a/tests/test_ext.py +++ b/tests/test_ext.py @@ -19,7 +19,8 @@ class ExtensionTest(unittest.TestCase): self.assertIsNone(self.ext.version) def test_get_default_config_raises_not_implemented(self): - self.assertRaises(NotImplementedError, self.ext.get_default_config) + with self.assertRaises(NotImplementedError): + self.ext.get_default_config() def test_get_config_schema_returns_extension_schema(self): schema = self.ext.get_config_schema() @@ -27,3 +28,7 @@ class ExtensionTest(unittest.TestCase): def test_validate_environment_does_nothing_by_default(self): self.assertIsNone(self.ext.validate_environment()) + + def test_setup_raises_not_implemented(self): + with self.assertRaises(NotImplementedError): + self.ext.setup(None) From 7fc89972a2b928026d5a5e5ff43f3c8dee9e97ae Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 3 Aug 2014 23:23:34 +0200 Subject: [PATCH 24/27] docs: Use text from web site and readme (cherry picked from commit 1e0569abb6e482366b6012e05604826a4df35c12) --- docs/index.rst | 67 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index aedc0fb0..bf259b08 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,25 +2,64 @@ Mopidy ****** -Mopidy is a music server which can play music both from multiple sources, like -your :ref:`local hard drive `, :ref:`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 an extensible music server written in Python. -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. +Mopidy plays music from local disk, Spotify, SoundCloud, Google Play Music, and +more. You edit the playlist from any phone, tablet, or computer using a range +of MPD and web clients. + +**Stream music from the cloud** + +Vanilla Mopidy only plays music from your :ref:`local disk ` and +:ref:`radio streams `. Through :ref:`extensions `, +Mopidy can play music from cloud services like Spotify, SoundCloud, and Google +Play Music. With Mopidy's extension support, backends for new music sources can +be easily added. + +**Mopidy is just a server** + +Mopidy is a Python application that runs in a terminal or in the background on +Linux computers or Macs that have network connectivity and audio output. Out of +the box, Mopidy is an :ref:`MPD ` and :ref:`HTTP ` server. +Additional frontends for controlling Mopidy can be installed from extensions. + +**Everybody use their favorite client** + +You and the people around you can all connect their favorite :ref:`MPD +` or :ref:`web client ` to the Mopidy server to +search for music and manage the playlist together. With a browser or MPD +client, which is available for all popular operating systems, you can control +the music from any phone, tablet, or computer. + +**Mopidy on Raspberry Pi** + +The Raspberry Pi is a popular device to run Mopidy on, either using Raspbian or +Arch Linux. It is quite slow, but it is very affordable. In fact, the +Kickstarter funded Gramofon: Modern Cloud Jukebox project used Mopidy on a +Raspberry Pi to prototype the Gramofon device. Mopidy is also a major building +block in the Pi Musicbox integrated audio jukebox system for Raspberry Pi. + +**Mopidy is hackable** + +Mopidy's extension support and Python, JSON-RPC, and JavaScript APIs makes +Mopidy perfect for building your own hacks. In one project, a Raspberry Pi was +embedded in an old cassette player. The buttons and volume control are wired up +with GPIO on the Raspberry Pi, and is used to control playback through a custom +Mopidy extension. The cassettes have NFC tags used to select playlists from +Spotify. + +**Getting started** To get started with Mopidy, start by reading :ref:`installation`. +**Getting help** + If you get stuck, we usually hang around at ``#mopidy`` at `irc.freenode.net -`_ and also have a `mailing list at Google Groups -`_. If you stumble -into a bug or got a feature request, please create an issue in the `issue -tracker `_. The `source code +`_ (with `searchable logs +`_) 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 `_. 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. From 6c08c3372469347106a63bf4fbce5a21be63a2cd Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 3 Aug 2014 23:30:47 +0200 Subject: [PATCH 25/27] docs: Add more links into the docs (cherry picked from commit 5dd2be5ec94c8691eb1051e9e78c283a2e09e764) --- docs/index.rst | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index bf259b08..71e8dee7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -21,7 +21,8 @@ be easily added. Mopidy is a Python application that runs in a terminal or in the background on Linux computers or Macs that have network connectivity and audio output. Out of the box, Mopidy is an :ref:`MPD ` and :ref:`HTTP ` server. -Additional frontends for controlling Mopidy can be installed from extensions. +:ref:`Additional frontends ` for controlling Mopidy can be +installed from extensions. **Everybody use their favorite client** @@ -33,20 +34,21 @@ the music from any phone, tablet, or computer. **Mopidy on Raspberry Pi** -The Raspberry Pi is a popular device to run Mopidy on, either using Raspbian or -Arch Linux. It is quite slow, but it is very affordable. In fact, the -Kickstarter funded Gramofon: Modern Cloud Jukebox project used Mopidy on a -Raspberry Pi to prototype the Gramofon device. Mopidy is also a major building -block in the Pi Musicbox integrated audio jukebox system for Raspberry Pi. +The :ref:`Raspberry Pi ` is a popular device to run +Mopidy on, either using Raspbian or Arch Linux. It is quite slow, but it is +very affordable. In fact, the Kickstarter funded Gramofon: Modern Cloud Jukebox +project used Mopidy on a Raspberry Pi to prototype the Gramofon device. Mopidy +is also a major building block in the Pi Musicbox integrated audio jukebox +system for Raspberry Pi. **Mopidy is hackable** -Mopidy's extension support and Python, JSON-RPC, and JavaScript APIs makes -Mopidy perfect for building your own hacks. In one project, a Raspberry Pi was -embedded in an old cassette player. The buttons and volume control are wired up -with GPIO on the Raspberry Pi, and is used to control playback through a custom -Mopidy extension. The cassettes have NFC tags used to select playlists from -Spotify. +Mopidy's extension support and :ref:`Python `, :ref:`JSON-RPC +`, and :ref:`JavaScript APIs ` makes Mopidy perfect for +building your own hacks. In one project, a Raspberry Pi was embedded in an old +cassette player. The buttons and volume control are wired up with GPIO on the +Raspberry Pi, and is used to control playback through a custom Mopidy +extension. The cassettes have NFC tags used to select playlists from Spotify. **Getting started** From 87e22eb94069f10a800298ba1f32c3bc12fd8dff Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 3 Aug 2014 23:34:18 +0200 Subject: [PATCH 26/27] docs: Update changelog --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 277c79ed..25655c98 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,7 +5,7 @@ Changelog This changelog is used to track all major changes to Mopidy. -v0.19.3 (UNRELEASED) +v0.19.3 (2014-08-03) ==================== Bug fix release. From dc80f172965d07a8a2b44ff824856b8ef2d52e61 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 3 Aug 2014 23:33:47 +0200 Subject: [PATCH 27/27] Bump version to 0.19.3 --- mopidy/__init__.py | 2 +- tests/test_version.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mopidy/__init__.py b/mopidy/__init__.py index c6593354..47e36e06 100644 --- a/mopidy/__init__.py +++ b/mopidy/__init__.py @@ -21,4 +21,4 @@ if (isinstance(pykka.__version__, basestring) warnings.filterwarnings('ignore', 'could not open display') -__version__ = '0.19.2' +__version__ = '0.19.3' diff --git a/tests/test_version.py b/tests/test_version.py index 1f0006a6..0431beae 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -48,5 +48,6 @@ class VersionTest(unittest.TestCase): self.assertLess(SV('0.18.2'), SV('0.18.3')) self.assertLess(SV('0.18.3'), SV('0.19.0')) self.assertLess(SV('0.19.0'), SV('0.19.1')) - self.assertLess(SV('0.19.1'), SV(__version__)) - self.assertLess(SV(__version__), SV('0.19.3')) + self.assertLess(SV('0.19.1'), SV('0.19.2')) + self.assertLess(SV('0.19.2'), SV(__version__)) + self.assertLess(SV(__version__), SV('0.19.4'))