Merge branch 'develop' into feature/multi-backend
This commit is contained in:
commit
a9461df4a0
@ -13,7 +13,7 @@ To install Mopidy, check out
|
||||
|
||||
* `Documentation (latest release) <http://www.mopidy.com/docs/master/>`_
|
||||
* `Documentation (development version) <http://www.mopidy.com/docs/develop/>`_
|
||||
* `Source code <http://github.com/jodal/mopidy>`_
|
||||
* `Issue tracker <http://github.com/jodal/mopidy/issues>`_
|
||||
* `Source code <http://github.com/mopidy/mopidy>`_
|
||||
* `Issue tracker <http://github.com/mopidy/mopidy/issues>`_
|
||||
* IRC: ``#mopidy`` at `irc.freenode.net <http://freenode.net/>`_
|
||||
* `Download development snapshot <http://github.com/jodal/mopidy/tarball/develop#egg=mopidy-dev>`_
|
||||
* `Download development snapshot <http://github.com/mopidy/mopidy/tarball/develop#egg=mopidy-dev>`_
|
||||
|
||||
@ -7,4 +7,4 @@ Icon=audio-x-generic
|
||||
TryExec=mopidy
|
||||
Exec=mopidy
|
||||
Terminal=true
|
||||
Categories=AudioVideo;Audio;Player;ConsoleOnly
|
||||
Categories=AudioVideo;Audio;Player;ConsoleOnly;
|
||||
|
||||
14
debian/TODO
vendored
14
debian/TODO
vendored
@ -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
|
||||
5
debian/changelog
vendored
5
debian/changelog
vendored
@ -1,5 +0,0 @@
|
||||
mopidy (0.2.0-1) unstable; urgency=low
|
||||
|
||||
* Initial release
|
||||
|
||||
-- Stein Magnus Jodal <stein.magnus@jodal.no> Sun, 31 Oct 2010 13:07:04 +0100
|
||||
1
debian/compat
vendored
1
debian/compat
vendored
@ -1 +0,0 @@
|
||||
7
|
||||
22
debian/control
vendored
22
debian/control
vendored
@ -1,22 +0,0 @@
|
||||
Source: mopidy
|
||||
Section: sound
|
||||
Priority: optional
|
||||
Maintainer: Stein Magnus Jodal <stein.magnus@jodal.no>
|
||||
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.
|
||||
38
debian/copyright
vendored
38
debian/copyright
vendored
@ -1,38 +0,0 @@
|
||||
This work was packaged for Debian by:
|
||||
|
||||
Stein Magnus Jodal <stein.magnus@jodal.no> 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 <stein.magnus@jodal.no>
|
||||
|
||||
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 <stein.magnus@jodal.no>
|
||||
|
||||
and is licensed under the Apache License, Version 2.0, see above.
|
||||
2
debian/docs
vendored
2
debian/docs
vendored
@ -1,2 +0,0 @@
|
||||
README.rst
|
||||
docs/_build/html/
|
||||
2
debian/menu
vendored
2
debian/menu
vendored
@ -1,2 +0,0 @@
|
||||
?package(mopidy):needs="text" section="Applications/Sound"\
|
||||
title="Mopidy" command="/usr/bin/mopidy"
|
||||
1
debian/pyversions
vendored
1
debian/pyversions
vendored
@ -1 +0,0 @@
|
||||
2.6-
|
||||
27
debian/rules
vendored
27
debian/rules
vendored
@ -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
|
||||
1
debian/source/format
vendored
1
debian/source/format
vendored
@ -1 +0,0 @@
|
||||
3.0 (quilt)
|
||||
2
debian/watch
vendored
2
debian/watch
vendored
@ -1,2 +0,0 @@
|
||||
version=3
|
||||
http://pypi.python.org/packages/source/M/Mopidy/Mopidy-(.*)\.tar\.gz
|
||||
2
docs/_themes/nature/static/nature.css_t
vendored
2
docs/_themes/nature/static/nature.css_t
vendored
@ -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;
|
||||
|
||||
@ -37,5 +37,5 @@ Backend provider implementations
|
||||
================================
|
||||
|
||||
* :mod:`mopidy.backends.dummy`
|
||||
* :mod:`mopidy.backends.libspotify`
|
||||
* :mod:`mopidy.backends.spotify`
|
||||
* :mod:`mopidy.backends.local`
|
||||
|
||||
@ -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
|
||||
<http://github.com/jodal/mopidy/issues>`_. Thanks!
|
||||
<http://github.com/mopidy/mopidy/issues>`_. Thanks!
|
||||
|
||||
**Changes**
|
||||
|
||||
|
||||
@ -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-')}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
<http://github.com/mxcl/homebrew/issues/issue/1612>`_.
|
||||
- **[WIP]** Create `Debian packages
|
||||
- **[DONE]** Create `Debian packages
|
||||
<http://www.debian.org/doc/maint-guide/>`_ 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.
|
||||
|
||||
@ -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
|
||||
<http://github.com/mxcl/homebrew/issues/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.
|
||||
|
||||
@ -2,10 +2,9 @@
|
||||
Installation
|
||||
************
|
||||
|
||||
To get a basic version of Mopidy running, you need Python and the
|
||||
:doc:`GStreamer library <gstreamer>`. To use Spotify with Mopidy, you also need
|
||||
:doc:`libspotify and pyspotify <libspotify>`. 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 <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 <libspotify>`
|
||||
|
||||
- :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 </settings>`, and then you're
|
||||
ready to :doc:`run Mopidy </running>`.
|
||||
|
||||
|
||||
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 </settings>`, and then you're
|
||||
ready to :doc:`run Mopidy </running>`.
|
||||
|
||||
|
||||
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 </settings>`, and then
|
||||
you're ready to :doc:`run Mopidy </running>`.
|
||||
|
||||
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 </settings>`, and then
|
||||
you're ready to :doc:`run Mopidy </running>`.
|
||||
|
||||
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 </settings>`, and then
|
||||
you're ready to :doc:`run Mopidy </running>`.
|
||||
|
||||
|
||||
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 </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
|
||||
<http://git-scm.com/>`_. Also, please read our :doc:`developer documentation
|
||||
</development/index>`.
|
||||
|
||||
|
||||
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 </settings>`, and then
|
||||
you're ready to :doc:`run Mopidy </running>`.
|
||||
|
||||
@ -7,9 +7,9 @@ Mopidy uses `libspotify
|
||||
the Spotify music service. To use :mod:`mopidy.backends.libspotify` you must
|
||||
install libspotify and `pyspotify <http://github.com/mopidy/pyspotify>`_.
|
||||
|
||||
.. warning::
|
||||
.. note::
|
||||
|
||||
This backend requires a `Spotify premium account
|
||||
This backend requires a paid `Spotify premium account
|
||||
<http://www.spotify.com/no/get-spotify/premium/>`_.
|
||||
|
||||
.. note::
|
||||
@ -19,8 +19,25 @@ install libspotify and `pyspotify <http://github.com/mopidy/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 <http://developer.apple.com/tools/xcode/>`_ and
|
||||
`Homebrew <http://mxcl.github.com/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.
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
*******************************************************
|
||||
:mod:`mopidy.backends.libspotify` -- Libspotify backend
|
||||
*******************************************************
|
||||
|
||||
.. automodule:: mopidy.backends.libspotify
|
||||
:synopsis: Spotify backend using the libspotify library
|
||||
:members:
|
||||
7
docs/modules/backends/spotify.rst
Normal file
7
docs/modules/backends/spotify.rst
Normal file
@ -0,0 +1,7 @@
|
||||
*************************************************
|
||||
:mod:`mopidy.backends.spotify` -- Spotify backend
|
||||
*************************************************
|
||||
|
||||
.. automodule:: mopidy.backends.spotify
|
||||
:synopsis: Backend for the Spotify music streaming service
|
||||
:members:
|
||||
@ -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:**
|
||||
|
||||
|
||||
@ -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 <http://www.spotify.com/>`_ backend which uses the official
|
||||
`libspotify <http://developer.spotify.com/en/libspotify/overview/>`_
|
||||
library and the `pyspotify <http://github.com/winjer/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 <http://www.spotify.com/>`_
|
||||
music streaming service. The backend uses the official `libspotify
|
||||
<http://developer.spotify.com/en/libspotify/overview/>`_ library and the
|
||||
`pyspotify <http://github.com/winjer/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)
|
||||
@ -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
|
||||
@ -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')
|
||||
|
||||
@ -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()
|
||||
@ -1,6 +1,6 @@
|
||||
from mopidy.backends.base import BaseStoredPlaylistsProvider
|
||||
|
||||
class LibspotifyStoredPlaylistsProvider(BaseStoredPlaylistsProvider):
|
||||
class SpotifyStoredPlaylistsProvider(BaseStoredPlaylistsProvider):
|
||||
def create(self, name):
|
||||
pass # TODO
|
||||
|
||||
@ -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)
|
||||
@ -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 <http://code.google.com/p/pylast/>`_ >= 0.4.30
|
||||
- `pylast <http://code.google.com/p/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)
|
||||
|
||||
@ -293,6 +293,7 @@ def replay_gain_status(frontend):
|
||||
"""
|
||||
return u'off' # TODO
|
||||
|
||||
@handle_pattern(r'^seek (?P<songpos>\d+) (?P<seconds>\d+)$')
|
||||
@handle_pattern(r'^seek "(?P<songpos>\d+)" "(?P<seconds>\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<volume>[-+]*\d+)$')
|
||||
@handle_pattern(r'^setvol "(?P<volume>[-+]*\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:
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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::
|
||||
#:
|
||||
|
||||
@ -1 +1 @@
|
||||
pylast >= 0.4.30
|
||||
pylast >= 0.5
|
||||
|
||||
2
setup.py
2
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'],
|
||||
|
||||
@ -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"')
|
||||
|
||||
@ -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:
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user