diff --git a/README.rst b/README.rst index c6187119..4f31fb59 100644 --- a/README.rst +++ b/README.rst @@ -13,7 +13,7 @@ To install Mopidy, check out * `Documentation (latest release) `_ * `Documentation (development version) `_ -* `Source code `_ -* `Issue tracker `_ +* `Source code `_ +* `Issue tracker `_ * IRC: ``#mopidy`` at `irc.freenode.net `_ -* `Download development snapshot `_ +* `Download development snapshot `_ diff --git a/data/mopidy.desktop b/data/mopidy.desktop index f5ca43bb..70257d58 100644 --- a/data/mopidy.desktop +++ b/data/mopidy.desktop @@ -7,4 +7,4 @@ Icon=audio-x-generic TryExec=mopidy Exec=mopidy Terminal=true -Categories=AudioVideo;Audio;Player;ConsoleOnly +Categories=AudioVideo;Audio;Player;ConsoleOnly; diff --git a/debian/TODO b/debian/TODO deleted file mode 100644 index 4551dc55..00000000 --- a/debian/TODO +++ /dev/null @@ -1,14 +0,0 @@ -To do for Mopidy's Debian packaging -=================================== - -- Install data/mopidy.desktop into /usr/share/applications/ -- Add manpages for all commands. Build the manpages with Sphinx -- Make init script run Mopidy as a daemon -- Make init script run Mopidy with its own user -- Add support for reading settings from /etc/mopidy/settings.py -- Log to /var/log -- Cache files in /var/cache -- Package pyspotify and add it to Recommends -- Package pylast and add it to Recommends -- Create GPG key for signing the package -- Host the packages at PPA or apt.mopidy.com diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index a04f2e78..00000000 --- a/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -mopidy (0.2.0-1) unstable; urgency=low - - * Initial release - - -- Stein Magnus Jodal Sun, 31 Oct 2010 13:07:04 +0100 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 7f8f011e..00000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -7 diff --git a/debian/control b/debian/control deleted file mode 100644 index c2755717..00000000 --- a/debian/control +++ /dev/null @@ -1,22 +0,0 @@ -Source: mopidy -Section: sound -Priority: optional -Maintainer: Stein Magnus Jodal -Build-Depends: debhelper (>= 7.0.50~), python-support, python (>= 2.6), - python-sphinx (>= 1.0), python-pygraphviz -Standards-Version: 3.9.1 -Homepage: http://www.mopidy.com/ -Vcs-Git: git://github.com/jodal/mopidy.git -Vcs-Browser: http://github.com/jodal/mopidy - -Package: mopidy -Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, python-gst0.10 -Recommends: gstreamer0.10-plugins-good, gstreamer0.10-plugins-ugly -Suggests: python-alsaaudio (>= 0.2), python-serial -Description: music server with MPD client support - Mopidy is a music server which can play music from Spotify or from your - local hard drive. To search for music in Spotify’s vast archive, manage - playlists, and play music, you can use most MPD clients. MPD clients are - available for most platforms, including Windows, Mac OS X, Linux, and - iPhone and Android phones. diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index c29416d6..00000000 --- a/debian/copyright +++ /dev/null @@ -1,38 +0,0 @@ -This work was packaged for Debian by: - - Stein Magnus Jodal on Sun, 31 Oct 2010 09:50:28 +0100 - -It was downloaded from: - - http://pypi.python.org/packages/source/M/Mopidy/Mopidy-0.2.0.tar.gz - -Upstream Author(s): - - Stein Magnus Jodal - -Copyright: - - Copyright 2009-2010 Stein Magnus Jodal and contributors - -License: - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - -On Debian systems, the complete text of the Apache version 2.0 license -can be found in "/usr/share/common-licenses/Apache-2.0". - -The Debian packaging is: - - Copyright 2010 Stein Magnus Jodal - -and is licensed under the Apache License, Version 2.0, see above. diff --git a/debian/docs b/debian/docs deleted file mode 100644 index a4b46448..00000000 --- a/debian/docs +++ /dev/null @@ -1,2 +0,0 @@ -README.rst -docs/_build/html/ diff --git a/debian/menu b/debian/menu deleted file mode 100644 index 6376a81e..00000000 --- a/debian/menu +++ /dev/null @@ -1,2 +0,0 @@ -?package(mopidy):needs="text" section="Applications/Sound"\ - title="Mopidy" command="/usr/bin/mopidy" diff --git a/debian/pyversions b/debian/pyversions deleted file mode 100644 index 0c043f18..00000000 --- a/debian/pyversions +++ /dev/null @@ -1 +0,0 @@ -2.6- diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 926a81b1..00000000 --- a/debian/rules +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- -# Sample debian/rules that uses debhelper. -# This file was originally written by Joey Hess and Craig Small. -# As a special exception, when this file is copied by dh-make into a -# dh-make output file, you may use that output file without restriction. -# This special exception was added by Craig Small in version 0.37 of dh-make. - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -%: - dh $@ - -override_dh_clean: - make -C docs/ clean - dh_clean - -override_dh_installchangelogs: - dh_installchangelogs docs/changes.rst - -override_dh_installdocs: - make -C docs/ clean html - dh_installdocs - -.PHONY: override_dh_clean override_dh_installchangelogs \ - override_dh_installdocs override_dh_installinit diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 163aaf8d..00000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debian/watch b/debian/watch deleted file mode 100644 index 3d4d3a41..00000000 --- a/debian/watch +++ /dev/null @@ -1,2 +0,0 @@ -version=3 -http://pypi.python.org/packages/source/M/Mopidy/Mopidy-(.*)\.tar\.gz diff --git a/docs/_themes/nature/static/nature.css_t b/docs/_themes/nature/static/nature.css_t index 63ef80d6..b6c0f22e 100644 --- a/docs/_themes/nature/static/nature.css_t +++ b/docs/_themes/nature/static/nature.css_t @@ -214,7 +214,7 @@ p.admonition-title:after { pre { padding: 10px; - background-color: #fafafa; + background-color: #eeeeee; color: #222222; line-height: 1.5em; font-size: 1.1em; diff --git a/docs/api/backends/providers.rst b/docs/api/backends/providers.rst index 9289dd06..903e220b 100644 --- a/docs/api/backends/providers.rst +++ b/docs/api/backends/providers.rst @@ -37,5 +37,5 @@ Backend provider implementations ================================ * :mod:`mopidy.backends.dummy` -* :mod:`mopidy.backends.libspotify` +* :mod:`mopidy.backends.spotify` * :mod:`mopidy.backends.local` diff --git a/docs/changes.rst b/docs/changes.rst index 3a030145..ddb46bb8 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -12,9 +12,30 @@ No description yet. **Important changes** -- If you use the Spotify backend, you need to upgrade to libspotify 0.0.6 and - the latest pyspotify from the Mopidy developers. Follow the instructions at - :ref:`/installation/libspotify/`. +- Spotify backend: + + - If you use the Spotify backend, you need to upgrade to libspotify 0.0.6 and + the latest pyspotify from the Mopidy developers. Follow the instructions at + :doc:`/installation/libspotify/`. + + - Support high bitrate (320k) audio. See + :attr:`mopidy.settings.SPOTIFY_HIGH_BITRATE` for details. + + - Rename :mod:`mopidy.backends.libspotify` to :mod:`mopidy.backends.spotify`. + If you have set :attr:`mopidy.settings.BACKENDS` explicitly, you may need + to update the setting's value. + + - Catch and log error caused by playlist folder boundaries being threated as + normal playlists. More permanent fix requires support for checking playlist + types in pyspotify. + +- Last.fm frontend: + + - If you use the Last.fm frontend, you need to upgrade to pylast 0.5. + + - Update to use Last.fm's new Scrobbling 2.0 API, as the old Submissions + Protocol 1.2.1 is deprecated. (Fixes: :issue:`33`) + **Changes** @@ -37,10 +58,12 @@ No description yet. application menus. - Create infrastructure for creating Debian packages of Mopidy. -- Spotify backend: +- MPD frontend: - - Support high bitrate (320k). See - :attr:`mopidy.settings.SPOTIFY_HIGH_BITRATE` for details. + - Support ``setvol 50`` without quotes around the argument. Fixes volume + control in Droid MPD. + - Support ``seek 1 120`` without quotes around the arguments. Fixes seek in + Droid MPD. - Local backend: @@ -80,6 +103,19 @@ No description yet. :class:`mopidy.outputs.base.BaseOutput`. +0.2.1 (2011-01-07) +================== + +This is a maintenance release without any new features. + +**Bugfixes** + +- Fix crash in :mod:`mopidy.frontends.lastfm` which occurred at playback if + either :mod:`pylast` was not installed or the Last.fm scrobbling was not + correctly configured. The scrobbling thread now shuts properly down at + failure. + + 0.2.0 (2010-10-24) ================== @@ -426,7 +462,7 @@ Mopidy is working and usable. 0.1.0a0 is an alpha release, which basicly means we will still change APIs, add features, etc. before the final 0.1.0 release. But the software is usable as is, so we release it. Please give it a try and give us feedback, either at our IRC channel or through the `issue tracker -`_. Thanks! +`_. Thanks! **Changes** diff --git a/docs/conf.py b/docs/conf.py index 16a85975..9e7ff1fb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -202,4 +202,4 @@ latex_documents = [ needs_sphinx = '1.0' -extlinks = {'issue': ('http://github.com/jodal/mopidy/issues#issue/%s', 'GH-')} +extlinks = {'issue': ('http://github.com/mopidy/mopidy/issues#issue/%s', 'GH-')} diff --git a/docs/development/contributing.rst b/docs/development/contributing.rst index 4adde637..a9cd8dc3 100644 --- a/docs/development/contributing.rst +++ b/docs/development/contributing.rst @@ -137,7 +137,7 @@ Then, to generate docs:: .. note:: The documentation at http://www.mopidy.com/ is automatically updated when a - documentation update is pushed to ``jodal/mopidy`` at GitHub. + documentation update is pushed to ``mopidy/mopidy`` at GitHub. Documentation generated from the ``master`` branch is published at http://www.mopidy.com/docs/master/, and will always be valid for the latest diff --git a/docs/development/roadmap.rst b/docs/development/roadmap.rst index 175c62ac..9db74a4d 100644 --- a/docs/development/roadmap.rst +++ b/docs/development/roadmap.rst @@ -27,7 +27,7 @@ Possible targets for the next version - Write-support for Spotify, i.e. playlist management. - Virtual directories with e.g. starred tracks from Spotify. - - **[WIP: possibly v0.3]** Support for 320 kbps audio. + - **[DONE: v0.3]** Support for 320 kbps audio. - Local backend: @@ -47,7 +47,7 @@ Stuff we want to do, but not right now, and maybe never recipies for all our dependencies and Mopidy itself to make OS X installation a breeze. See `Homebrew's issue #1612 `_. - - **[WIP]** Create `Debian packages + - **[DONE]** Create `Debian packages `_ of all our dependencies and Mopidy itself (hosted in our own Debian repo until we get stuff into the various distros) to make Debian/Ubuntu installation a breeze. diff --git a/docs/installation/gstreamer.rst b/docs/installation/gstreamer.rst index ef66c673..72d55908 100644 --- a/docs/installation/gstreamer.rst +++ b/docs/installation/gstreamer.rst @@ -5,23 +5,32 @@ GStreamer installation To use the Mopidy, you first need to install GStreamer and its Python bindings. -Installing GStreamer on Linux -============================= +Installing GStreamer +==================== -GStreamer is packaged for most popular Linux distributions. If you use -Debian/Ubuntu you can install GStreamer with Aptitude:: +On Linux +-------- - sudo aptitude install python-gst0.10 gstreamer0.10-plugins-good \ +GStreamer is packaged for most popular Linux distributions. Search for +GStreamer in your package manager, and make sure to install the Python +bindings, and the "good" and "ugly" plugin sets. + +If you use Debian/Ubuntu you can install GStreamer like this:: + + sudo apt-get install python-gst0.10 gstreamer0.10-plugins-good \ gstreamer0.10-plugins-ugly +If you install Mopidy from our APT archive, you don't need to install GStreamer +yourself. The Mopidy Debian package will handle it for you. -Installing GStreamer on OS X -============================ + +On OS X from Homebrew +--------------------- .. note:: We have created GStreamer formulas for Homebrew to make the GStreamer - installation easy for you, but our formulas has not been merged into + installation easy for you, but not all our formulas have been merged into Homebrew's master branch yet. You should either fetch the formula files from `Homebrew's issue #1612 `_ yourself, or fall @@ -31,6 +40,10 @@ To install GStreamer on OS X using Homebrew:: brew install gst-python gst-plugins-good gst-plugins-ugly + +On OS X from MacPorts +--------------------- + To install GStreamer on OS X using MacPorts:: sudo port install py26-gst-python gstreamer-plugins-good \ @@ -46,3 +59,19 @@ 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: 218 plugins (1 blacklist entry not shown), 1031 features + +You should be able to produce a audible tone by running:: + + gst-launch-0.10 audiotestsrc ! autoaudiosink + +If you cannot hear any sound when running this command, you won't hear any +sound from Mopidy either, as Mopidy uses GStreamer's ``autoaudiosink`` to play +audio. Thus, make this work before you continue installing Mopidy. + + +Using a custom audio sink +========================= + +If you for some reason want to use some other GStreamer audio sink than +``autoaudiosink``, you can change :attr:`mopidy.settings.GSTREAMER_AUDIO_SINK` +in your ``settings.py`` file. diff --git a/docs/installation/index.rst b/docs/installation/index.rst index 580ecd6d..26b50994 100644 --- a/docs/installation/index.rst +++ b/docs/installation/index.rst @@ -2,10 +2,9 @@ Installation ************ -To get a basic version of Mopidy running, you need Python and the -:doc:`GStreamer library `. To use Spotify with Mopidy, you also need -:doc:`libspotify and pyspotify `. Mopidy itself can either be -installed from the Python package index, PyPI, or from git. +There are several ways to install Mopidy. What way is best depends upon your +setup and whether you want to use stable releases or less stable development +versions. Install dependencies @@ -17,97 +16,155 @@ Install dependencies gstreamer libspotify -Make sure you got the required dependencies installed. +If you install Mopidy from the APT archive, as described below, you can skip +the dependency installation part. + +Otherwise, make sure you got the required dependencies installed. - Python >= 2.6, < 3 -- :doc:`GStreamer ` >= 0.10, with Python bindings -- Dependencies for at least one Mopidy mixer: - - :mod:`mopidy.mixers.alsa` (Linux only) +- GStreamer >= 0.10, with Python bindings. See :doc:`gstreamer`. - - pyalsaaudio >= 0.2 (Debian/Ubuntu package: python-alsaaudio) - - - :mod:`mopidy.mixers.denon` (Linux, OS X, and Windows) - - - pyserial (Debian/Ubuntu package: python-serial) - - - *Default:* :mod:`mopidy.mixers.gstreamer_software` (Linux, OS X, and - Windows) - - - No additional dependencies. - - - :mod:`mopidy.mixers.nad` (Linux, OS X, and Windows) - - - pyserial (Debian/Ubuntu package: python-serial) - - - :mod:`mopidy.mixers.osa` (OS X only) - - - No additional dependencies. +- Mixer dependencies: The default mixer does not require any additional + dependencies. If you use another mixer, see the mixer's docs for any + additional requirements. - Dependencies for at least one Mopidy backend: - - *Default:* :mod:`mopidy.backends.libspotify` (Linux, OS X, and Windows) + - The default backend, :mod:`mopidy.backends.spotify`, requires libspotify + and pyspotify. See :doc:`libspotify`. - - :doc:`libspotify and pyspotify ` - - - :mod:`mopidy.backends.local` (Linux, OS X, and Windows) - - - No additional dependencies. + - The local backend, :mod:`mopidy.backends.local`, requires no additional + dependencies. - Optional dependencies: - - :mod:`mopidy.frontends.lastfm` - - - pylast >= 4.3.0 + - To use the Last.FM scrobbler, see :mod:`mopidy.frontends.lastfm` for + additional requirements. -Install latest release -====================== - -To install the currently latest release of Mopidy using ``pip``:: - - sudo aptitude install python-setuptools python-pip # On Ubuntu/Debian - sudo brew install pip # On OS X - sudo pip install mopidy - -To later upgrade to the latest release:: - - sudo pip install -U mopidy - -If you for some reason can't use ``pip``, try ``easy_install``. - -Next, you need to set a couple of :doc:`settings `, and then you're -ready to :doc:`run Mopidy `. - - -Install development snapshot -============================ - -If you want to follow Mopidy development closer, you may install a snapshot of -Mopidy's ``develop`` branch:: - - sudo aptitude install python-setuptools python-pip # On Ubuntu/Debian - sudo brew install pip # On OS X - sudo pip install mopidy==dev - -Next, you need to set a couple of :doc:`settings `, and then you're -ready to :doc:`run Mopidy `. - - -Run from source code checkout +Install latest stable release ============================= -If you may want to contribute to Mopidy, and want access to other branches as -well, you can checkout the Mopidy source from Git and run it directly from the -ckeckout:: - sudo aptitude install git-core # On Ubuntu/Debian - sudo brew install git # On OS X - git clone git://github.com/jodal/mopidy.git - cd mopidy/ - python mopidy # Yes, 'mopidy' is a dir +From APT archive +---------------- -To later update to the very latest version:: +If you run a Debian based Linux distribution, like Ubuntu, the easiest way to +install Mopidy is from the Mopidy APT archive. When installing from the APT +archive, you will automatically get updates to Mopidy in the same way as you +get updates to the rest of your distribution. + +#. Add the archive's GPG key:: + + wget -q -O - http://apt.mopidy.com/mopidy.gpg | sudo apt-key add - + +#. Add the following to ``/etc/apt/sources.list``, or if you have the directory + ``/etc/apt/sources.list.d/``, add it to a file called ``mopidy.list`` in + that directory:: + + # Mopidy APT archive + deb http://apt.mopidy.com/ stable main contrib non-free + deb-src http://apt.mopidy.com/ stable main contrib non-free + +#. Install Mopidy and all dependencies:: + + sudo apt-get update + sudo apt-get install mopidy + +#. Next, you need to set a couple of :doc:`settings `, and then + you're ready to :doc:`run Mopidy `. + +When a new release is out, and you can't wait for you system to figure it out +for itself, run the following to force an upgrade:: + + sudo apt-get update + sudo apt-get dist-upgrade + + +From PyPI using Pip +------------------- + +If you are on OS X or on Linux, but can't install from the APT archive, you can +install Mopidy from PyPI using Pip. + +#. When you install using Pip, you first need to ensure that all of Mopidy's + dependencies have been installed. See the section on dependencies above. + +#. Then, you need to install Pip:: + + sudo aptitude install python-setuptools python-pip # On Ubuntu/Debian + sudo brew install pip # On OS X + +#. To install the currently latest stable release of Mopidy:: + + sudo pip install -U Mopidy + + To upgrade Mopidy to future releases, just rerun this command. + +#. Next, you need to set a couple of :doc:`settings `, and then + you're ready to :doc:`run Mopidy `. + +If you for some reason can't use Pip, try ``easy_install`` instead. + + +Install development version +=========================== + +If you want to follow the development of Mopidy closer, you may install a +development version of Mopidy. These are not as stable as the releases, but +you'll get access to new features earlier and may help us by reporting issues. + + +From snapshot using Pip +----------------------- + +If you want to follow Mopidy development closer, you may install a snapshot of +Mopidy's ``develop`` branch. + +#. When you install using Pip, you first need to ensure that all of Mopidy's + dependencies have been installed. See the section on dependencies above. + +#. Then, you need to install Pip:: + + sudo aptitude install python-setuptools python-pip # On Ubuntu/Debian + sudo brew install pip # On OS X + +#. To install the latest snapshot of Mopidy, run:: + + sudo pip install mopidy==dev + + To upgrade Mopidy to future releases, just rerun this command. + +#. Next, you need to set a couple of :doc:`settings `, and then + you're ready to :doc:`run Mopidy `. + + +From Git +-------- + +If you want to contribute to Mopidy, you should install Mopidy using Git. + +#. When you install from Git, you first need to ensure that all of Mopidy's + dependencies have been installed. See the section on dependencies above. + +#. Then install Git, if haven't already:: + + sudo aptitude install git-core # On Ubuntu/Debian + sudo brew install git # On OS X + +#. Clone the official Mopidy repository, or your own fork of it:: + + git clone git://github.com/mopidy/mopidy.git + +#. Next, you need to set a couple of :doc:`settings `. + +#. 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 + +#. Later, to get the latest changes to Mopidy:: cd mopidy/ git pull @@ -115,3 +172,26 @@ To later update to the very latest version:: For an introduction to ``git``, please visit `git-scm.com `_. Also, please read our :doc:`developer documentation `. + + +From AUR on ArchLinux +--------------------- + +If you are running ArchLinux, you can install a development snapshot of Mopidy +using the package found at http://aur.archlinux.org/packages.php?ID=44026. + +#. First, you should consider installing any optional dependencies not included + by the AUR package, like required for e.g. Last.fm scrobbling. + +#. To install Mopidy with GStreamer, libspotify and pyspotify, you can use + ``packer``, ``yaourt``, or do it by hand like this:: + + wget http://aur.archlinux.org/packages/mopidy-git/mopidy-git.tar.gz + tar xf mopidy-git.tar.gz + cd mopidy-git/ + makepkg -si + + To upgrade Mopidy to future releases, just rerun ``makepkg``. + +#. Next, you need to set a couple of :doc:`settings `, and then + you're ready to :doc:`run Mopidy `. diff --git a/docs/installation/libspotify.rst b/docs/installation/libspotify.rst index 9dc91066..5d278fe2 100644 --- a/docs/installation/libspotify.rst +++ b/docs/installation/libspotify.rst @@ -7,9 +7,9 @@ Mopidy uses `libspotify the Spotify music service. To use :mod:`mopidy.backends.libspotify` you must install libspotify and `pyspotify `_. -.. warning:: +.. note:: - This backend requires a `Spotify premium account + This backend requires a paid `Spotify premium account `_. .. note:: @@ -19,8 +19,25 @@ install libspotify and `pyspotify `_. Spotify Group. -Installing libspotify on Linux -============================== +Installing libspotify +===================== + + +On Linux from APT archive +------------------------- + +If you run a Debian based Linux distribution, like Ubuntu, see +http://apt.mopidy.com/ for how to the Mopidy APT archive as a software source +on your installation. Then, simply run:: + + sudo apt-get install libspotify6 + +When libspotify has been installed, continue with +:ref:`pyspotify_installation`. + + +On Linux from source +-------------------- Download and install libspotify 0.0.6 for your OS and CPU architecture from https://developer.spotify.com/en/libspotify/. @@ -37,8 +54,8 @@ When libspotify has been installed, continue with :ref:`pyspotify_installation`. -Installing libspotify on OS X -============================= +On OS X from Homebrew +--------------------- In OS X you need to have `XCode `_ and `Homebrew `_ installed. Then, to install @@ -55,34 +72,45 @@ When libspotify has been installed, continue with :ref:`pyspotify_installation`. -Install libspotify on Windows -============================= - -**TODO** Test and document installation on Windows. - - .. _pyspotify_installation: Installing pyspotify ==================== -Install pyspotify's dependencies. At Debian/Ubuntu systems:: +When you've installed libspotify, it's time for making it available from Python +by installing pyspotify. - sudo aptitude install python-dev -In OS X no additional dependencies are needed. +On Linux from APT archive +------------------------- -Check out the pyspotify code, and install it:: +Assuming that you've already set up http://apt.mopidy.com/ as a software +source, run:: + + sudo apt-get install python-spotify + +If you haven't already installed libspotify, this command will install both +libspotify and pyspotify for you. + + +On Linux/OS X from source +------------------------- + +On Linux, you need to get the Python development files installed. On +Debian/Ubuntu systems run:: + + sudo apt-get install python-dev + +On OS X no additional dependencies are needed. + +Get the pyspotify code, and install it:: wget --no-check-certificate -O pyspotify.tar.gz https://github.com/mopidy/pyspotify/tarball/mopidy tar zxfv pyspotify.tar.gz - cd pyspotify/pyspotify/ - sudo rm -rf build/ # If you are upgrading pyspotify + cd pyspotify/ sudo python setup.py install -.. note:: - - The ``sudo rm -rf build/`` step is needed if you are upgrading pyspotify. - Simply running ``python setup.py clean`` will *not* clean out the C parts - of the ``build/`` directory, and you will thus not get any changes to the C - code included in your installation. +It is important that you install pyspotify from the ``mopidy`` branch of the +``mopidy/pyspotify`` repository, as the upstream repository at +``winjer/pyspotify`` is not updated with changes needed to support e.g. +libspotify 0.0.6 and high bitrate audio. diff --git a/docs/modules/backends/libspotify.rst b/docs/modules/backends/libspotify.rst deleted file mode 100644 index e7528757..00000000 --- a/docs/modules/backends/libspotify.rst +++ /dev/null @@ -1,7 +0,0 @@ -******************************************************* -:mod:`mopidy.backends.libspotify` -- Libspotify backend -******************************************************* - -.. automodule:: mopidy.backends.libspotify - :synopsis: Spotify backend using the libspotify library - :members: diff --git a/docs/modules/backends/spotify.rst b/docs/modules/backends/spotify.rst new file mode 100644 index 00000000..938d6337 --- /dev/null +++ b/docs/modules/backends/spotify.rst @@ -0,0 +1,7 @@ +************************************************* +:mod:`mopidy.backends.spotify` -- Spotify backend +************************************************* + +.. automodule:: mopidy.backends.spotify + :synopsis: Backend for the Spotify music streaming service + :members: diff --git a/mopidy/backends/local/__init__.py b/mopidy/backends/local/__init__.py index 578e0b5e..bff5cb61 100644 --- a/mopidy/backends/local/__init__.py +++ b/mopidy/backends/local/__init__.py @@ -20,7 +20,7 @@ class LocalBackend(Backend): """ A backend for playing music from a local music archive. - **Issues:** http://github.com/jodal/mopidy/issues/labels/backend-local + **Issues:** http://github.com/mopidy/mopidy/issues/labels/backend-local **Settings:** diff --git a/mopidy/backends/libspotify/__init__.py b/mopidy/backends/spotify/__init__.py similarity index 60% rename from mopidy/backends/libspotify/__init__.py rename to mopidy/backends/spotify/__init__.py index 4d8b67d5..d36f6250 100644 --- a/mopidy/backends/libspotify/__init__.py +++ b/mopidy/backends/spotify/__init__.py @@ -4,53 +4,55 @@ from mopidy import settings from mopidy.backends.base import (Backend, CurrentPlaylistController, LibraryController, PlaybackController, StoredPlaylistsController) -logger = logging.getLogger('mopidy.backends.libspotify') +logger = logging.getLogger('mopidy.backends.spotify') ENCODING = 'utf-8' -class LibspotifyBackend(Backend): +class SpotifyBackend(Backend): """ - A `Spotify `_ backend which uses the official - `libspotify `_ - library and the `pyspotify `_ Python - bindings for libspotify. - - **Issues:** http://github.com/jodal/mopidy/issues/labels/backend-libspotify - - **Settings:** - - - :attr:`mopidy.settings.SPOTIFY_CACHE_PATH` - - :attr:`mopidy.settings.SPOTIFY_USERNAME` - - :attr:`mopidy.settings.SPOTIFY_PASSWORD` + A backend for playing music from the `Spotify `_ + music streaming service. The backend uses the official `libspotify + `_ library and the + `pyspotify `_ Python bindings for + libspotify. .. note:: This product uses SPOTIFY(R) CORE but is not endorsed, certified or otherwise approved in any way by Spotify. Spotify is the registered trade mark of the Spotify Group. + + **Issues:** + http://github.com/mopidy/mopidy/issues/labels/backend-spotify + + **Settings:** + + - :attr:`mopidy.settings.SPOTIFY_CACHE_PATH` + - :attr:`mopidy.settings.SPOTIFY_USERNAME` + - :attr:`mopidy.settings.SPOTIFY_PASSWORD` """ # Imports inside methods are to prevent loading of __init__.py to fail on # missing spotify dependencies. def __init__(self, *args, **kwargs): - from .library import LibspotifyLibraryProvider - from .playback import LibspotifyPlaybackProvider - from .stored_playlists import LibspotifyStoredPlaylistsProvider + from .library import SpotifyLibraryProvider + from .playback import SpotifyPlaybackProvider + from .stored_playlists import SpotifyStoredPlaylistsProvider - super(LibspotifyBackend, self).__init__(*args, **kwargs) + super(SpotifyBackend, self).__init__(*args, **kwargs) self.current_playlist = CurrentPlaylistController(backend=self) - library_provider = LibspotifyLibraryProvider(backend=self) + library_provider = SpotifyLibraryProvider(backend=self) self.library = LibraryController(backend=self, provider=library_provider) - playback_provider = LibspotifyPlaybackProvider(backend=self) + playback_provider = SpotifyPlaybackProvider(backend=self) self.playback = PlaybackController(backend=self, provider=playback_provider) - stored_playlists_provider = LibspotifyStoredPlaylistsProvider( + stored_playlists_provider = SpotifyStoredPlaylistsProvider( backend=self) self.stored_playlists = StoredPlaylistsController(backend=self, provider=stored_playlists_provider) @@ -60,11 +62,11 @@ class LibspotifyBackend(Backend): self.spotify = self._connect() def _connect(self): - from .session_manager import LibspotifySessionManager + from .session_manager import SpotifySessionManager logger.info(u'Mopidy uses SPOTIFY(R) CORE') logger.debug(u'Connecting to Spotify') - spotify = LibspotifySessionManager( + spotify = SpotifySessionManager( settings.SPOTIFY_USERNAME, settings.SPOTIFY_PASSWORD, core_queue=self.core_queue, output=self.output) diff --git a/mopidy/backends/libspotify/library.py b/mopidy/backends/spotify/library.py similarity index 87% rename from mopidy/backends/libspotify/library.py rename to mopidy/backends/spotify/library.py index 948c69b2..16391473 100644 --- a/mopidy/backends/libspotify/library.py +++ b/mopidy/backends/spotify/library.py @@ -4,13 +4,13 @@ import multiprocessing from spotify import Link, SpotifyError from mopidy.backends.base import BaseLibraryProvider -from mopidy.backends.libspotify import ENCODING -from mopidy.backends.libspotify.translator import LibspotifyTranslator +from mopidy.backends.spotify import ENCODING +from mopidy.backends.spotify.translator import SpotifyTranslator from mopidy.models import Playlist -logger = logging.getLogger('mopidy.backends.libspotify.library') +logger = logging.getLogger('mopidy.backends.spotify.library') -class LibspotifyLibraryProvider(BaseLibraryProvider): +class SpotifyLibraryProvider(BaseLibraryProvider): def find_exact(self, **query): return self.search(**query) @@ -20,7 +20,7 @@ class LibspotifyLibraryProvider(BaseLibraryProvider): # TODO Block until metadata_updated callback is called. Before that # the track will be unloaded, unless it's already in the stored # playlists. - return LibspotifyTranslator.to_mopidy_track(spotify_track) + return SpotifyTranslator.to_mopidy_track(spotify_track) except SpotifyError as e: logger.warning(u'Failed to lookup: %s', uri, e) return None diff --git a/mopidy/backends/libspotify/playback.py b/mopidy/backends/spotify/playback.py similarity index 91% rename from mopidy/backends/libspotify/playback.py rename to mopidy/backends/spotify/playback.py index 29409ff4..a066d90e 100644 --- a/mopidy/backends/libspotify/playback.py +++ b/mopidy/backends/spotify/playback.py @@ -4,9 +4,9 @@ from spotify import Link, SpotifyError from mopidy.backends.base import BasePlaybackProvider -logger = logging.getLogger('mopidy.backends.libspotify.playback') +logger = logging.getLogger('mopidy.backends.spotify.playback') -class LibspotifyPlaybackProvider(BasePlaybackProvider): +class SpotifyPlaybackProvider(BasePlaybackProvider): def pause(self): return self.backend.output.set_state('PAUSED') diff --git a/mopidy/backends/libspotify/session_manager.py b/mopidy/backends/spotify/session_manager.py similarity index 76% rename from mopidy/backends/libspotify/session_manager.py rename to mopidy/backends/spotify/session_manager.py index 8a79088f..9736f2eb 100644 --- a/mopidy/backends/libspotify/session_manager.py +++ b/mopidy/backends/spotify/session_manager.py @@ -2,28 +2,29 @@ import logging import os import threading -from spotify.manager import SpotifySessionManager +import spotify.manager from mopidy import get_version, settings -from mopidy.backends.libspotify.translator import LibspotifyTranslator +from mopidy.backends.spotify.translator import SpotifyTranslator from mopidy.models import Playlist from mopidy.utils.process import BaseThread -logger = logging.getLogger('mopidy.backends.libspotify.session_manager') +logger = logging.getLogger('mopidy.backends.spotify.session_manager') # pylint: disable = R0901 -# LibspotifySessionManager: Too many ancestors (9/7) +# SpotifySessionManager: Too many ancestors (9/7) -class LibspotifySessionManager(SpotifySessionManager, BaseThread): +class SpotifySessionManager(spotify.manager.SpotifySessionManager, BaseThread): cache_location = settings.SPOTIFY_CACHE_PATH settings_location = settings.SPOTIFY_CACHE_PATH appkey_file = os.path.join(os.path.dirname(__file__), 'spotify_appkey.key') user_agent = 'Mopidy %s' % get_version() def __init__(self, username, password, core_queue, output): - SpotifySessionManager.__init__(self, username, password) + spotify.manager.SpotifySessionManager.__init__( + self, username, password) BaseThread.__init__(self, core_queue) - self.name = 'LibspotifySMThread' + self.name = 'SpotifySMThread' self.output = output self.connected = threading.Event() self.session = None @@ -36,10 +37,10 @@ class LibspotifySessionManager(SpotifySessionManager, BaseThread): logger.info(u'Connected to Spotify') self.session = session if settings.SPOTIFY_HIGH_BITRATE: - logger.debug(u'Prefer high bitrate') + logger.debug(u'Preferring high bitrate from Spotify') self.session.set_preferred_bitrate(1) else: - logger.debug(u'Prefer normal bitrate') + logger.debug(u'Preferring normal bitrate from Spotify') self.session.set_preferred_bitrate(0) self.connected.set() @@ -49,15 +50,8 @@ class LibspotifySessionManager(SpotifySessionManager, BaseThread): def metadata_updated(self, session): """Callback used by pyspotify""" - logger.debug(u'Metadata updated, refreshing stored playlists') - playlists = [] - for spotify_playlist in session.playlist_container(): - playlists.append( - LibspotifyTranslator.to_mopidy_playlist(spotify_playlist)) - self.core_queue.put({ - 'command': 'set_stored_playlists', - 'playlists': playlists, - }) + logger.debug(u'Metadata updated') + self.refresh_stored_playlists() def connection_error(self, session, error): """Callback used by pyspotify""" @@ -105,12 +99,26 @@ class LibspotifySessionManager(SpotifySessionManager, BaseThread): logger.debug(u'End of data stream reached') self.output.end_of_data_stream() + def refresh_stored_playlists(self): + """Refresh the stored playlists in the backend with fresh meta data + from Spotify""" + playlists = [] + for spotify_playlist in self.session.playlist_container(): + playlists.append( + SpotifyTranslator.to_mopidy_playlist(spotify_playlist)) + playlists = filter(None, playlists) + self.core_queue.put({ + 'command': 'set_stored_playlists', + 'playlists': playlists, + }) + logger.debug(u'Refreshed %d stored playlist(s)', len(playlists)) + def search(self, query, connection): """Search method used by Mopidy backend""" def callback(results, userdata=None): # TODO Include results from results.albums(), etc. too playlist = Playlist(tracks=[ - LibspotifyTranslator.to_mopidy_track(t) + SpotifyTranslator.to_mopidy_track(t) for t in results.tracks()]) connection.send(playlist) self.connected.wait() diff --git a/mopidy/backends/libspotify/spotify_appkey.key b/mopidy/backends/spotify/spotify_appkey.key similarity index 100% rename from mopidy/backends/libspotify/spotify_appkey.key rename to mopidy/backends/spotify/spotify_appkey.key diff --git a/mopidy/backends/libspotify/stored_playlists.py b/mopidy/backends/spotify/stored_playlists.py similarity index 84% rename from mopidy/backends/libspotify/stored_playlists.py rename to mopidy/backends/spotify/stored_playlists.py index 6f2a7aad..054e2bd1 100644 --- a/mopidy/backends/libspotify/stored_playlists.py +++ b/mopidy/backends/spotify/stored_playlists.py @@ -1,6 +1,6 @@ from mopidy.backends.base import BaseStoredPlaylistsProvider -class LibspotifyStoredPlaylistsProvider(BaseStoredPlaylistsProvider): +class SpotifyStoredPlaylistsProvider(BaseStoredPlaylistsProvider): def create(self, name): pass # TODO diff --git a/mopidy/backends/libspotify/translator.py b/mopidy/backends/spotify/translator.py similarity index 62% rename from mopidy/backends/libspotify/translator.py rename to mopidy/backends/spotify/translator.py index ff8f3c5c..50ee07d1 100644 --- a/mopidy/backends/libspotify/translator.py +++ b/mopidy/backends/spotify/translator.py @@ -1,11 +1,15 @@ import datetime as dt +import logging -from spotify import Link +from spotify import Link, SpotifyError +from mopidy import settings +from mopidy.backends.spotify import ENCODING from mopidy.models import Artist, Album, Track, Playlist -from mopidy.backends.libspotify import ENCODING -class LibspotifyTranslator(object): +logger = logging.getLogger('mopidy.backends.spotify.translator') + +class SpotifyTranslator(object): @classmethod def to_mopidy_artist(cls, spotify_artist): if not spotify_artist.is_loaded(): @@ -39,15 +43,22 @@ class LibspotifyTranslator(object): track_no=spotify_track.index(), date=date, length=spotify_track.duration(), - bitrate=160, + bitrate=(settings.SPOTIFY_HIGH_BITRATE and 320 or 160), ) @classmethod def to_mopidy_playlist(cls, spotify_playlist): if not spotify_playlist.is_loaded(): return Playlist(name=u'[loading...]') - return Playlist( - uri=str(Link.from_playlist(spotify_playlist)), - name=spotify_playlist.name().decode(ENCODING), - tracks=[cls.to_mopidy_track(t) for t in spotify_playlist], - ) + # FIXME Replace this try-except with a check on the playlist type, + # which is currently not supported by pyspotify, to avoid handling + # playlist folder boundaries like normal playlists. + try: + return Playlist( + uri=str(Link.from_playlist(spotify_playlist)), + name=spotify_playlist.name().decode(ENCODING), + tracks=[cls.to_mopidy_track(t) for t in spotify_playlist], + ) + except SpotifyError, e: + logger.warning(u'Failed translating Spotify playlist ' + '(probably a playlist folder boundary): %s', e) diff --git a/mopidy/frontends/lastfm.py b/mopidy/frontends/lastfm.py index 0cf534af..60c2d708 100644 --- a/mopidy/frontends/lastfm.py +++ b/mopidy/frontends/lastfm.py @@ -15,13 +15,8 @@ from mopidy.utils.process import BaseThread logger = logging.getLogger('mopidy.frontends.lastfm') -CLIENT_ID = u'mop' -CLIENT_VERSION = get_version() - -# pylast raises UnicodeEncodeError on conversion from unicode objects to -# ascii-encoded bytestrings, so we explicitly encode as utf-8 before passing -# strings to pylast. -ENCODING = u'utf-8' +API_KEY = '2236babefa8ebb3d93ea467560d00d04' +API_SECRET = '94d9a09c0cd5be955c4afaeaffcaefcd' class LastfmFrontend(BaseFrontend): """ @@ -34,7 +29,7 @@ class LastfmFrontend(BaseFrontend): **Dependencies:** - - `pylast `_ >= 0.4.30 + - `pylast `_ >= 0.5 **Settings:** @@ -54,7 +49,8 @@ class LastfmFrontend(BaseFrontend): self.thread.destroy() def process_message(self, message): - self.connection.send(message) + if self.thread.is_alive(): + self.connection.send(message) class LastfmFrontendThread(BaseThread): @@ -63,12 +59,11 @@ class LastfmFrontendThread(BaseThread): self.name = u'LastfmFrontendThread' self.connection = connection self.lastfm = None - self.scrobbler = None self.last_start_time = None def run_inside_try(self): self.setup() - while True: + while self.lastfm is not None: self.connection.poll(None) message = self.connection.recv() self.process_message(message) @@ -77,10 +72,9 @@ class LastfmFrontendThread(BaseThread): try: username = settings.LASTFM_USERNAME password_hash = pylast.md5(settings.LASTFM_PASSWORD) - self.lastfm = pylast.get_lastfm_network( + self.lastfm = pylast.LastFMNetwork( + api_key=API_KEY, api_secret=API_SECRET, username=username, password_hash=password_hash) - self.scrobbler = self.lastfm.get_scrobbler( - CLIENT_ID, CLIENT_VERSION) logger.info(u'Connected to Last.fm') except SettingsError as e: logger.info(u'Last.fm scrobbler not started') @@ -102,12 +96,13 @@ class LastfmFrontendThread(BaseThread): self.last_start_time = int(time.time()) logger.debug(u'Now playing track: %s - %s', artists, track.name) try: - self.scrobbler.report_now_playing( - artists.encode(ENCODING), - track.name.encode(ENCODING), - album=track.album.name.encode(ENCODING), - duration=duration, - track_number=track.track_no) + self.lastfm.update_now_playing( + artists, + track.name, + album=track.album.name, + duration=str(duration), + track_number=str(track.track_no), + mbid=(track.musicbrainz_id or '')) except (pylast.ScrobblingError, socket.error) as e: logger.warning(u'Last.fm now playing error: %s', e) @@ -126,14 +121,13 @@ class LastfmFrontendThread(BaseThread): self.last_start_time = int(time.time()) - duration logger.debug(u'Scrobbling track: %s - %s', artists, track.name) try: - self.scrobbler.scrobble( - artists.encode(ENCODING), - track.name.encode(ENCODING), - time_started=self.last_start_time, - source=pylast.SCROBBLE_SOURCE_USER, - mode=pylast.SCROBBLE_MODE_PLAYED, - duration=duration, - album=track.album.name.encode(ENCODING), - track_number=track.track_no) + self.lastfm.scrobble( + artists, + track.name, + str(self.last_start_time), + album=track.album.name, + track_number=str(track.track_no), + duration=str(duration), + mbid=(track.musicbrainz_id or '')) except (pylast.ScrobblingError, socket.error) as e: logger.warning(u'Last.fm scrobbling error: %s', e) diff --git a/mopidy/frontends/mpd/protocol/playback.py b/mopidy/frontends/mpd/protocol/playback.py index 2f5dd29e..19922bc3 100644 --- a/mopidy/frontends/mpd/protocol/playback.py +++ b/mopidy/frontends/mpd/protocol/playback.py @@ -293,6 +293,7 @@ def replay_gain_status(frontend): """ return u'off' # TODO +@handle_pattern(r'^seek (?P\d+) (?P\d+)$') @handle_pattern(r'^seek "(?P\d+)" "(?P\d+)"$') def seek(frontend, songpos, seconds): """ @@ -302,6 +303,10 @@ def seek(frontend, songpos, seconds): Seeks to the position ``TIME`` (in seconds) of entry ``SONGPOS`` in the playlist. + + *Droid MPD:* + + - issues ``seek 1 120`` without quotes around the arguments. """ if frontend.backend.playback.current_playlist_position != songpos: playpos(frontend, songpos) @@ -320,6 +325,7 @@ def seekid(frontend, cpid, seconds): playid(frontend, cpid) frontend.backend.playback.seek(int(seconds) * 1000) +@handle_pattern(r'^setvol (?P[-+]*\d+)$') @handle_pattern(r'^setvol "(?P[-+]*\d+)"$') def setvol(frontend, volume): """ @@ -328,6 +334,10 @@ def setvol(frontend, volume): ``setvol {VOL}`` Sets volume to ``VOL``, the range of volume is 0-100. + + *Droid MPD:* + + - issues ``setvol 50`` without quotes around the argument. """ volume = int(volume) if volume < 0: diff --git a/mopidy/mixers/alsa.py b/mopidy/mixers/alsa.py index f90060ce..4aa5952f 100644 --- a/mopidy/mixers/alsa.py +++ b/mopidy/mixers/alsa.py @@ -11,6 +11,10 @@ class AlsaMixer(BaseMixer): Mixer which uses the Advanced Linux Sound Architecture (ALSA) to control volume. + **Dependencies:** + + - pyalsaaudio >= 0.2 (python-alsaaudio on Debian/Ubuntu) + **Settings:** - :attr:`mopidy.settings.MIXER_ALSA_CONTROL` diff --git a/mopidy/mixers/denon.py b/mopidy/mixers/denon.py index e6d752b6..f0712f95 100644 --- a/mopidy/mixers/denon.py +++ b/mopidy/mixers/denon.py @@ -1,8 +1,6 @@ import logging from threading import Lock -from serial import Serial - from mopidy import settings from mopidy.mixers.base import BaseMixer @@ -33,8 +31,11 @@ class DenonMixer(BaseMixer): """ super(DenonMixer, self).__init__(*args, **kwargs) device = kwargs.get('device', None) - self._device = device or Serial(port=settings.MIXER_EXT_PORT, - timeout=0.2) + if device: + self._device = device + else: + from serial import Serial + self._device = Serial(port=settings.MIXER_EXT_PORT, timeout=0.2) self._levels = ['99'] + ["%(#)02d" % {'#': v} for v in range(0, 99)] self._volume = 0 self._lock = Lock() diff --git a/mopidy/mixers/osa.py b/mopidy/mixers/osa.py index 8d69eb47..2ea04cf2 100644 --- a/mopidy/mixers/osa.py +++ b/mopidy/mixers/osa.py @@ -4,7 +4,18 @@ import time from mopidy.mixers.base import BaseMixer class OsaMixer(BaseMixer): - """Mixer which uses ``osascript`` on OS X to control volume.""" + """ + Mixer which uses ``osascript`` on OS X to control volume. + + **Dependencies:** + + - None + + **Settings:** + + - None + + """ CACHE_TTL = 30 diff --git a/mopidy/settings.py b/mopidy/settings.py index 1aaa4318..23aa7cb6 100644 --- a/mopidy/settings.py +++ b/mopidy/settings.py @@ -12,12 +12,12 @@ Available settings and their default values. #: #: Default:: #: -#: BACKENDS = (u'mopidy.backends.libspotify.LibspotifyBackend',) +#: BACKENDS = (u'mopidy.backends.spotify.SpotifyBackend',) #: #: .. note:: #: Currently only the first backend in the list is used. BACKENDS = ( - u'mopidy.backends.libspotify.LibspotifyBackend', + u'mopidy.backends.spotify.SpotifyBackend', ) #: The log format used for informational logging. @@ -169,24 +169,24 @@ MPD_SERVER_HOSTNAME = u'127.0.0.1' #: Default: 6600 MPD_SERVER_PORT = 6600 -#: Path to the libspotify cache. +#: Path to the Spotify cache. #: -#: Used by :mod:`mopidy.backends.libspotify`. -SPOTIFY_CACHE_PATH = u'~/.mopidy/libspotify_cache' +#: Used by :mod:`mopidy.backends.spotify`. +SPOTIFY_CACHE_PATH = u'~/.mopidy/spotify_cache' #: Your Spotify Premium username. #: -#: Used by :mod:`mopidy.backends.libspotify`. +#: Used by :mod:`mopidy.backends.spotify`. SPOTIFY_USERNAME = u'' #: Your Spotify Premium password. #: -#: Used by :mod:`mopidy.backends.libspotify`. +#: Used by :mod:`mopidy.backends.spotify`. SPOTIFY_PASSWORD = u'' #: Do you prefer high bitrate (320k)? #: -#: Used by :mod:`mopidy.backends.libspotify`. +#: Used by :mod:`mopidy.backends.spotify`. # #: Default:: #: diff --git a/requirements/lastfm.txt b/requirements/lastfm.txt index 642735be..887a0f0d 100644 --- a/requirements/lastfm.txt +++ b/requirements/lastfm.txt @@ -1 +1 @@ -pylast >= 0.4.30 +pylast >= 0.5 diff --git a/setup.py b/setup.py index d77be3cd..d9d6af42 100644 --- a/setup.py +++ b/setup.py @@ -77,7 +77,7 @@ setup( author='Stein Magnus Jodal', author_email='stein.magnus@jodal.no', packages=packages, - package_data={'mopidy': ['backends/libspotify/spotify_appkey.key']}, + package_data={'mopidy': ['backends/spotify/spotify_appkey.key']}, cmdclass=cmdclasses, data_files=data_files, scripts=['bin/mopidy', 'bin/mopidy-scan'], diff --git a/tests/frontends/mpd/playback_test.py b/tests/frontends/mpd/playback_test.py index 45aaaf83..70309d66 100644 --- a/tests/frontends/mpd/playback_test.py +++ b/tests/frontends/mpd/playback_test.py @@ -103,6 +103,11 @@ class PlaybackOptionsHandlerTest(unittest.TestCase): self.assert_(u'OK' in result) self.assertEqual(10, self.b.mixer.volume) + def test_setvol_without_quotes(self): + result = self.h.handle_request(u'setvol 50') + self.assert_(u'OK' in result) + self.assertEqual(50, self.b.mixer.volume) + def test_single_off(self): result = self.h.handle_request(u'single "0"') self.assertFalse(self.b.playback.single) @@ -319,6 +324,13 @@ class PlaybackControlHandlerTest(unittest.TestCase): result = self.h.handle_request(u'seek "1" "30"') self.assertEqual(self.b.playback.current_track, seek_track) + def test_seek_without_quotes(self): + self.b.current_playlist.append([Track(length=40000)]) + self.h.handle_request(u'seek 0') + result = self.h.handle_request(u'seek 0 30') + self.assert_(u'OK' in result) + self.assert_(self.b.playback.time_position >= 30000) + def test_seekid(self): self.b.current_playlist.append([Track(length=40000)]) result = self.h.handle_request(u'seekid "0" "30"') diff --git a/tests/frontends/mpd/regression_test.py b/tests/frontends/mpd/regression_test.py index 63dc5ae4..79ca88c9 100644 --- a/tests/frontends/mpd/regression_test.py +++ b/tests/frontends/mpd/regression_test.py @@ -7,7 +7,7 @@ from mopidy.models import Track class IssueGH17RegressionTest(unittest.TestCase): """ - The issue: http://github.com/jodal/mopidy/issues#issue/17 + The issue: http://github.com/mopidy/mopidy/issues#issue/17 How to reproduce: @@ -41,7 +41,7 @@ class IssueGH17RegressionTest(unittest.TestCase): class IssueGH18RegressionTest(unittest.TestCase): """ - The issue: http://github.com/jodal/mopidy/issues#issue/18 + The issue: http://github.com/mopidy/mopidy/issues#issue/18 How to reproduce: @@ -78,7 +78,7 @@ class IssueGH18RegressionTest(unittest.TestCase): class IssueGH22RegressionTest(unittest.TestCase): """ - The issue: http://github.com/jodal/mopidy/issues/#issue/22 + The issue: http://github.com/mopidy/mopidy/issues/#issue/22 How to reproduce: