commit
adb260af05
1
AUTHORS
1
AUTHORS
@ -76,3 +76,4 @@
|
|||||||
- Jelle van der Waa <jelle@vdwaa.nl>
|
- Jelle van der Waa <jelle@vdwaa.nl>
|
||||||
- Alex Malone <jalexmalone@gmail.com>
|
- Alex Malone <jalexmalone@gmail.com>
|
||||||
- Daniel Hahler <git@thequod.de>
|
- Daniel Hahler <git@thequod.de>
|
||||||
|
- Bryan Bennett <bbenne10@gmail.com>
|
||||||
|
|||||||
@ -55,20 +55,28 @@ Data model API
|
|||||||
:synopsis: Data model API
|
:synopsis: Data model API
|
||||||
|
|
||||||
.. autoclass:: mopidy.models.Ref
|
.. autoclass:: mopidy.models.Ref
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: mopidy.models.Track
|
.. autoclass:: mopidy.models.Track
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: mopidy.models.Album
|
.. autoclass:: mopidy.models.Album
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: mopidy.models.Artist
|
.. autoclass:: mopidy.models.Artist
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: mopidy.models.Playlist
|
.. autoclass:: mopidy.models.Playlist
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: mopidy.models.Image
|
.. autoclass:: mopidy.models.Image
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: mopidy.models.TlTrack
|
.. autoclass:: mopidy.models.TlTrack
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: mopidy.models.SearchResult
|
.. autoclass:: mopidy.models.SearchResult
|
||||||
|
:members:
|
||||||
|
|
||||||
|
|
||||||
Data model helpers
|
Data model helpers
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
Authors
|
Authors
|
||||||
*******
|
*******
|
||||||
|
|
||||||
Mopidy is copyright 2009-2015 Stein Magnus Jodal and contributors. Mopidy is
|
Mopidy is copyright 2009-2016 Stein Magnus Jodal and contributors. Mopidy is
|
||||||
licensed under the `Apache License, Version 2.0
|
licensed under the `Apache License, Version 2.0
|
||||||
<http://www.apache.org/licenses/LICENSE-2.0>`_.
|
<http://www.apache.org/licenses/LICENSE-2.0>`_.
|
||||||
|
|
||||||
|
|||||||
@ -141,11 +141,28 @@ Gapless
|
|||||||
cases. (Fixes: :issue:`1305` PR: :issue:`1346`)
|
cases. (Fixes: :issue:`1305` PR: :issue:`1346`)
|
||||||
|
|
||||||
|
|
||||||
v1.1.2 (UNRELEASED)
|
v1.1.2 (2016-01-18)
|
||||||
===================
|
===================
|
||||||
|
|
||||||
Bug fix release.
|
Bug fix release.
|
||||||
|
|
||||||
|
- Main: Catch errors when loading the :confval:`logging/config_file` file.
|
||||||
|
(Fixes: :issue:`1320`)
|
||||||
|
|
||||||
|
- Core: If changing to another track while the player is paused, the new track
|
||||||
|
would not be added to the history or marked as currently playing. (Fixes:
|
||||||
|
:issue:`1352`, PR: :issue:`1356`)
|
||||||
|
|
||||||
|
- Core: Skips over unplayable tracks if the user attempts to change tracks
|
||||||
|
while paused, like we already did if in playing state. (Fixes :issue:`1378`,
|
||||||
|
PR: :issue:`1379`)
|
||||||
|
|
||||||
|
- Core: Make :meth:`~mopidy.core.LibraryController.lookup` ignore tracks with
|
||||||
|
empty URIs. (Partly fixes: :issue:`1340`, PR: :issue:`1381`)
|
||||||
|
|
||||||
|
- Core: Fix crash if backends emits events with wrong names or arguments.
|
||||||
|
(Fixes: :issue:`1383`)
|
||||||
|
|
||||||
- Stream: If an URI is considered playable, don't consider it as a candidate
|
- Stream: If an URI is considered playable, don't consider it as a candidate
|
||||||
for playlist parsing. Just looking at MIME type prefixes isn't enough, as for
|
for playlist parsing. Just looking at MIME type prefixes isn't enough, as for
|
||||||
example Ogg Vorbis has the MIME type ``application/ogg``. (Fixes:
|
example Ogg Vorbis has the MIME type ``application/ogg``. (Fixes:
|
||||||
@ -154,6 +171,18 @@ Bug fix release.
|
|||||||
- Local: If the scan or clear commands are used on a library that does not
|
- Local: If the scan or clear commands are used on a library that does not
|
||||||
exist, exit with an error. (Fixes: :issue:`1298`)
|
exist, exit with an error. (Fixes: :issue:`1298`)
|
||||||
|
|
||||||
|
- MPD: Notify idling clients when a seek is performed. (Fixes: :issue:`1331`)
|
||||||
|
|
||||||
|
- MPD: Don't return tracks with empty URIs. (Partly fixes: :issue:`1340`, PR:
|
||||||
|
:issue:`1343`)
|
||||||
|
|
||||||
|
- MPD: Add ``volume`` command that was reintroduced, though still as a
|
||||||
|
deprecated command, in MPD 0.18 and is in use by some clients like mpc.
|
||||||
|
(Fixes: :issue:`1393`, PR: :issue:`1397`)
|
||||||
|
|
||||||
|
- Proxy: Handle case where :confval:`proxy/port` is either missing from config
|
||||||
|
or set to an empty string. (PR: :issue:`1371`)
|
||||||
|
|
||||||
|
|
||||||
v1.1.1 (2015-09-14)
|
v1.1.1 (2015-09-14)
|
||||||
===================
|
===================
|
||||||
|
|||||||
@ -167,5 +167,5 @@ projects are a real match made in heaven."
|
|||||||
Partify
|
Partify
|
||||||
-------
|
-------
|
||||||
|
|
||||||
`Partify <https://github.com/fhats/partify>`_ is a web based MPD client focussing on
|
`Partify <https://github.com/fhats/partify>`_ is a web based MPD client
|
||||||
making music playing collaborative and social.
|
focussing on making music playing collaborative and social.
|
||||||
|
|||||||
@ -93,14 +93,14 @@ source_suffix = '.rst'
|
|||||||
master_doc = 'index'
|
master_doc = 'index'
|
||||||
|
|
||||||
project = 'Mopidy'
|
project = 'Mopidy'
|
||||||
copyright = '2009-2015, Stein Magnus Jodal and contributors'
|
copyright = '2009-2016, Stein Magnus Jodal and contributors'
|
||||||
|
|
||||||
from mopidy.internal.versioning import get_version
|
from mopidy.internal.versioning import get_version
|
||||||
release = get_version()
|
release = get_version()
|
||||||
version = '.'.join(release.split('.')[:2])
|
version = '.'.join(release.split('.')[:2])
|
||||||
|
|
||||||
# To make the build reproducible, avoid using today's date in the manpages
|
# To make the build reproducible, avoid using today's date in the manpages
|
||||||
today = '2015'
|
today = '2016'
|
||||||
|
|
||||||
exclude_trees = ['_build']
|
exclude_trees = ['_build']
|
||||||
|
|
||||||
|
|||||||
129
docs/debian.rst
129
docs/debian.rst
@ -1,129 +0,0 @@
|
|||||||
.. _debian:
|
|
||||||
|
|
||||||
***************
|
|
||||||
Debian packages
|
|
||||||
***************
|
|
||||||
|
|
||||||
The Mopidy Debian package, ``mopidy``, is available from `apt.mopidy.com
|
|
||||||
<http://apt.mopidy.com/>`__ as well as from Debian, Ubuntu and other
|
|
||||||
Debian-based Linux distributions.
|
|
||||||
|
|
||||||
Some extensions are also available from all of these sources, while others,
|
|
||||||
like Mopidy-Spotify and its dependencies, are only available from
|
|
||||||
apt.mopidy.com. This may either be temporary until the package is uploaded to
|
|
||||||
Debian and with time propagates to the other distributions. It may also be more
|
|
||||||
long term, like in the Mopidy-Spotify case where there is uncertainities around
|
|
||||||
licensing and distribution of non-free packages.
|
|
||||||
|
|
||||||
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
See :ref:`debian-install`.
|
|
||||||
|
|
||||||
|
|
||||||
Running as a system service
|
|
||||||
===========================
|
|
||||||
|
|
||||||
The Debian package comes with an init script. It starts Mopidy as a system
|
|
||||||
service running as the ``mopidy`` user, which is created by the package.
|
|
||||||
|
|
||||||
The Debian package version 0.18.3-1 and older starts Mopidy as a system
|
|
||||||
service by default. Version 0.18.3-2 and newer asks if you want to run Mopidy
|
|
||||||
as a system service, defaulting to not doing so.
|
|
||||||
|
|
||||||
If you're running 0.18.3-2 or newer, and you've changed your mind about whether
|
|
||||||
or not to run Mopidy as a system service, just run the following command to
|
|
||||||
reconfigure the package::
|
|
||||||
|
|
||||||
sudo dpkg-reconfigure mopidy
|
|
||||||
|
|
||||||
If you're running 0.18.3-1 or older, and don't want to use the init script to
|
|
||||||
run Mopidy as a system service, but instead just run Mopidy manually using your
|
|
||||||
own user, you need to disable the init script and stop Mopidy by running::
|
|
||||||
|
|
||||||
sudo update-rc.d mopidy disable
|
|
||||||
sudo service mopidy stop
|
|
||||||
|
|
||||||
This way of disabling the system service is compatible with the improved
|
|
||||||
0.18.3-2 or newer version of the Debian package, so if you later upgrade to a
|
|
||||||
newer version, you can change your mind using the ``dpkg-reconfigure`` command
|
|
||||||
above.
|
|
||||||
|
|
||||||
|
|
||||||
Differences when running as a system service
|
|
||||||
============================================
|
|
||||||
|
|
||||||
If you want to run Mopidy using the init script, there's a few differences
|
|
||||||
from a regular Mopidy setup you'll want to know about.
|
|
||||||
|
|
||||||
- All configuration is in :file:`/etc/mopidy`, not in your user's home
|
|
||||||
directory. The main configuration file is :file:`/etc/mopidy/mopidy.conf`.
|
|
||||||
You can do all your changes in this file.
|
|
||||||
|
|
||||||
- Mopidy extensions installed from Debian packages will sometimes install
|
|
||||||
additional configuration files in :file:`/usr/share/mopidy/conf.d/`. These
|
|
||||||
files just provide different defaults for the extension when run as a system
|
|
||||||
service. You can override anything from :file:`/usr/share/mopidy/conf.d/` in
|
|
||||||
the :file:`/etc/mopidy/mopidy.conf` configuration file.
|
|
||||||
|
|
||||||
Previously, the extension's default config was installed in
|
|
||||||
:file:`/etc/mopidy/extensions.d/`. This was removed with the Debian
|
|
||||||
package mopidy 0.19.4-3. If you have modified any files in
|
|
||||||
:file:`/etc/mopidy/extensions.d/`, you should redo your modifications in
|
|
||||||
:file:`/etc/mopidy/mopidy.conf` and delete the
|
|
||||||
:file:`/etc/mopidy/extensions.d/` directory.
|
|
||||||
|
|
||||||
- The init script runs Mopidy as the ``mopidy`` user. The ``mopidy`` user will
|
|
||||||
need read access to any local music you want Mopidy to play.
|
|
||||||
|
|
||||||
- To run Mopidy subcommands with the same user and config files as the init
|
|
||||||
script uses, you can use ``sudo mopidyctl <subcommand>``. In other words,
|
|
||||||
where you'll usually run::
|
|
||||||
|
|
||||||
mopidy config
|
|
||||||
|
|
||||||
You should instead run the following to inspect the system service's
|
|
||||||
configuration::
|
|
||||||
|
|
||||||
sudo mopidyctl config
|
|
||||||
|
|
||||||
The same applies to scanning your local music collection. Where you'll
|
|
||||||
normally run::
|
|
||||||
|
|
||||||
mopidy local scan
|
|
||||||
|
|
||||||
You should instead run::
|
|
||||||
|
|
||||||
sudo mopidyctl local scan
|
|
||||||
|
|
||||||
Previously, you used ``sudo service mopidy run <subcommand>`` instead of
|
|
||||||
``mopidyctl``. This was deprecated in Debian package version 0.19.4-3 in
|
|
||||||
favor of ``mopidyctl``, which also work for systems using systemd instead of
|
|
||||||
sysvinit and traditional init scripts.
|
|
||||||
|
|
||||||
- Mopidy is started, stopped, and restarted just like any other system
|
|
||||||
service::
|
|
||||||
|
|
||||||
sudo service mopidy start
|
|
||||||
sudo service mopidy stop
|
|
||||||
sudo service mopidy restart
|
|
||||||
|
|
||||||
- You can check if Mopidy is currently running as a system service by running::
|
|
||||||
|
|
||||||
sudo service mopidy status
|
|
||||||
|
|
||||||
- Mopidy installed from a Debian package can use Mopidy extensions installed
|
|
||||||
both from Debian packages and with pip. This has always been the case.
|
|
||||||
|
|
||||||
Mopidy installed with pip can use extensions installed with pip, but
|
|
||||||
not extensions installed from a Debian package released before August 2015.
|
|
||||||
This is because the Debian packages used to install extensions into
|
|
||||||
:file:`/usr/share/mopidy` which is normally not on your ``PYTHONPATH``.
|
|
||||||
Thus, your pip-installed Mopidy would not find the Debian package-installed
|
|
||||||
extensions.
|
|
||||||
|
|
||||||
In August 2015, all Mopidy extension Debian packages was modified to install
|
|
||||||
into :file:`/usr/lib/python2.7/dist-packages`, like any other Python Debian
|
|
||||||
package. Thus, Mopidy installed with pip can now use extensions installed
|
|
||||||
from Debian.
|
|
||||||
BIN
docs/ext/spotmop.jpg
Normal file
BIN
docs/ext/spotmop.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
@ -164,6 +164,22 @@ To install, run::
|
|||||||
pip install Mopidy-Simple-Webclient
|
pip install Mopidy-Simple-Webclient
|
||||||
|
|
||||||
|
|
||||||
|
Mopidy-Spotmop
|
||||||
|
==============
|
||||||
|
|
||||||
|
https://github.com/jaedb/spotmop
|
||||||
|
|
||||||
|
A client targeted at Spotify users. Made by James Barnsley.
|
||||||
|
|
||||||
|
.. image:: /ext/spotmop.jpg
|
||||||
|
:width: 720
|
||||||
|
:height: 455
|
||||||
|
|
||||||
|
To install, run::
|
||||||
|
|
||||||
|
pip install Mopidy-Spotmop
|
||||||
|
|
||||||
|
|
||||||
Mopidy-WebSettings
|
Mopidy-WebSettings
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
|||||||
@ -81,8 +81,8 @@ announcements related to Mopidy and Mopidy extensions.
|
|||||||
installation/index
|
installation/index
|
||||||
config
|
config
|
||||||
running
|
running
|
||||||
|
service
|
||||||
troubleshooting
|
troubleshooting
|
||||||
debian
|
|
||||||
|
|
||||||
|
|
||||||
.. _ext:
|
.. _ext:
|
||||||
|
|||||||
@ -16,7 +16,8 @@ If you are running Arch Linux, you can install Mopidy using the
|
|||||||
pacman -Syu
|
pacman -Syu
|
||||||
|
|
||||||
#. Finally, you need to set a couple of :doc:`config values </config>`, and
|
#. Finally, you need to set a couple of :doc:`config values </config>`, and
|
||||||
then you're ready to :doc:`run Mopidy </running>`.
|
then you're ready to :doc:`run Mopidy </running>` or run Mopidy as a
|
||||||
|
:ref:`service <service>`.
|
||||||
|
|
||||||
|
|
||||||
Installing extensions
|
Installing extensions
|
||||||
|
|||||||
@ -48,12 +48,9 @@ and armhf (compatible with Raspberry Pi 1 and 2).
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install mopidy
|
sudo apt-get install mopidy
|
||||||
|
|
||||||
#. Before continuing, make sure you've read the :ref:`debian` section to learn
|
|
||||||
about the differences between running Mopidy as a system service and
|
|
||||||
manually as your own system user.
|
|
||||||
|
|
||||||
#. Finally, you need to set a couple of :doc:`config values </config>`, and then
|
#. Finally, you need to set a couple of :doc:`config values </config>`, and then
|
||||||
you're ready to :doc:`run Mopidy </running>`.
|
you're ready to :doc:`run Mopidy </running>` or run Mopidy as a
|
||||||
|
:ref:`service <service>`.
|
||||||
|
|
||||||
When a new release of Mopidy is out, and you can't wait for you system to
|
When a new release of Mopidy is out, and you can't wait for you system to
|
||||||
figure it out for itself, run the following to upgrade right away::
|
figure it out for itself, run the following to upgrade right away::
|
||||||
@ -87,44 +84,3 @@ about any other requirements needed for the extension to work properly.
|
|||||||
|
|
||||||
For a full list of available Mopidy extensions, including those not
|
For a full list of available Mopidy extensions, including those not
|
||||||
installable from apt.mopidy.com, see :ref:`ext`.
|
installable from apt.mopidy.com, see :ref:`ext`.
|
||||||
|
|
||||||
|
|
||||||
Missing extensions
|
|
||||||
==================
|
|
||||||
|
|
||||||
If you've installed a Mopidy extension with pip, restarted Mopidy, and Mopidy
|
|
||||||
doesn't find the extension, there's probably a simple explanation and solution.
|
|
||||||
|
|
||||||
Mopidy installed with APT can detect and use Mopidy extensions installed with
|
|
||||||
both APT and pip. APT installs Mopidy as :file:`/usr/bin/mopidy`.
|
|
||||||
|
|
||||||
Mopidy installed with pip can only detect Mopidy extensions installed with pip.
|
|
||||||
pip usually installs Mopidy as :file:`/usr/local/bin/mopidy`.
|
|
||||||
|
|
||||||
If you have Mopidy installed from both APT and pip, then the pip-installed
|
|
||||||
Mopidy will probably shadow the APT-installed Mopidy because
|
|
||||||
:file:`/usr/local/bin` usually has precedence over :file:`/usr/bin` in the
|
|
||||||
``PATH`` environment variable. To check if this is the case on your system, you
|
|
||||||
can use ``which`` to see what installation of Mopidy you use when you run
|
|
||||||
``mopidy`` in your shell::
|
|
||||||
|
|
||||||
$ which mopidy
|
|
||||||
/usr/local/bin/mopidy
|
|
||||||
|
|
||||||
If this is the case on your system, the recommended solution is to check that
|
|
||||||
you have Mopidy installed from APT too::
|
|
||||||
|
|
||||||
$ /usr/bin/mopidy --version
|
|
||||||
Mopidy 0.19.5
|
|
||||||
|
|
||||||
And then uninstall the pip-installed Mopidy::
|
|
||||||
|
|
||||||
sudo pip uninstall mopidy
|
|
||||||
|
|
||||||
Depending on what shell you use, the shell may still try to use
|
|
||||||
:file:`/usr/local/bin/mopidy` even if it no longer exists. Check again with
|
|
||||||
``which mopidy`` what your shell believes is the right ``mopidy`` executable to
|
|
||||||
run. If the shell is still confused, you may need to restart it, or in the case
|
|
||||||
of zsh, run ``rehash`` to update the shell.
|
|
||||||
|
|
||||||
For more details on why this works this way, see :ref:`debian`.
|
|
||||||
|
|||||||
@ -86,6 +86,8 @@ For a full list of available Mopidy extensions, including those not installable
|
|||||||
from Homebrew, see :ref:`ext`.
|
from Homebrew, see :ref:`ext`.
|
||||||
|
|
||||||
|
|
||||||
|
.. _osx-service:
|
||||||
|
|
||||||
Running Mopidy automatically on login
|
Running Mopidy automatically on login
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 51 KiB |
@ -1,75 +1,68 @@
|
|||||||
.. _raspberrypi-installation:
|
.. _raspberrypi-installation:
|
||||||
|
|
||||||
*************************************
|
************
|
||||||
Raspberry Pi: Mopidy on a credit card
|
Raspberry Pi
|
||||||
*************************************
|
************
|
||||||
|
|
||||||
Mopidy runs nicely on a `Raspberry Pi <https://www.raspberrypi.org/>`_. As of
|
Mopidy runs on all versions of `Raspberry Pi <https://www.raspberrypi.org/>`_.
|
||||||
January 2013, Mopidy will run with Spotify support on both the armel
|
However, note that Raspberry Pi 2 B's CPU is approximately six times as
|
||||||
(soft-float) and armhf (hard-float) architectures, which includes the Raspbian
|
powerful as Raspberry Pi 1 and Raspberry Pi Zero, so Mopidy will be more joyful
|
||||||
distribution.
|
to use on a Raspberry Pi 2.
|
||||||
|
|
||||||
.. image:: raspberry-pi-by-jwrodgers.jpg
|
.. image:: raspberrypi2.jpg
|
||||||
:width: 640
|
:width: 640
|
||||||
:height: 427
|
:height: 363
|
||||||
|
|
||||||
|
|
||||||
.. _raspi-wheezy:
|
.. _raspi-wheezy:
|
||||||
|
|
||||||
How to for Raspbian "wheezy" and Debian "wheezy"
|
How to for Raspbian Jessie
|
||||||
================================================
|
==========================
|
||||||
|
|
||||||
This guide applies for both:
|
#. Download the latest Jessie or Jessie Lite disk image from
|
||||||
|
http://www.raspberrypi.org/downloads/raspbian/.
|
||||||
|
|
||||||
- Raspbian "wheezy" for armhf (hard-float), and
|
If you're only using your Pi for Mopidy, go with Jessie Lite as you won't
|
||||||
- Debian "wheezy" for armel (soft-float)
|
need the full graphical desktop included in the Jessie image.
|
||||||
|
|
||||||
If you don't know which one to select, go for the armhf variant, as it'll give
|
#. Flash the Raspbian image you downloaded to your SD card.
|
||||||
you a lot better performance.
|
|
||||||
|
|
||||||
#. Download the latest "wheezy" disk image from
|
See the `Raspberry Pi installation docs
|
||||||
https://www.raspberrypi.org/downloads/. This was last tested with the images
|
<https://www.raspberrypi.org/documentation/installation/installing-images/README.md>`_
|
||||||
from 2013-05-25 for armhf and 2013-05-29 for armel.
|
for instructions.
|
||||||
|
|
||||||
#. Flash the OS image to your SD card. See
|
#. If you connect a monitor and a keyboard, you'll see that the Pi boots right
|
||||||
http://elinux.org/RPi_Easy_SD_Card_Setup for help.
|
into the ``raspi-config`` tool.
|
||||||
|
|
||||||
#. If you have an SD card that's >2 GB, you don't have to resize the file
|
If you boot with only a network cable connected, you'll have to find the IP
|
||||||
systems on another computer. Just boot up your Raspberry Pi with the
|
address of the Pi yourself, e.g. by looking in the client list on your
|
||||||
unaltered partions, and it will boot right into the ``raspi-config`` tool,
|
router/DHCP server. When you have found the Pi's IP address, you can SSH to
|
||||||
which will let you grow the root file system to fill the SD card. This tool
|
the IP address and login with the user ``pi`` and password ``raspberry``.
|
||||||
will also allow you do other useful stuff, like turning on the SSH server.
|
Once logged in, run ``sudo raspi-config`` to start the config tool as the
|
||||||
|
``root`` user.
|
||||||
|
|
||||||
#. You can login to the default user using username ``pi`` and password
|
#. Use the ``raspi-config`` tool to setup the basics of your Pi. You might want
|
||||||
``raspberry``. To become root, just enter ``sudo -i``.
|
to do one or more of the following:
|
||||||
|
|
||||||
#. To avoid a couple of potential problems with Mopidy, turn on IPv6 support:
|
- Expand the file system to fill the SD card.
|
||||||
|
- Change the password of the ``pi`` user.
|
||||||
|
- Change the time zone.
|
||||||
|
|
||||||
- Load the IPv6 kernel module now::
|
Under "Advanced Options":
|
||||||
|
|
||||||
sudo modprobe ipv6
|
- Set a hostname.
|
||||||
|
- Enable SSH if not already enabled.
|
||||||
|
- If your will use HDMI for display and 3.5mm jack for audio, force the
|
||||||
|
audio output to the 3.5mm jack. By default it will use HDMI for audio
|
||||||
|
output if an HDMI cable is connected and the 3.5mm jack if not.
|
||||||
|
|
||||||
- Add ``ipv6`` to ``/etc/modules`` to ensure the IPv6 kernel module is
|
Once done, select "Finish" and restart your Pi.
|
||||||
loaded on boot::
|
|
||||||
|
|
||||||
echo ipv6 | sudo tee -a /etc/modules
|
If you want to change any settings later, you can simply rerun ``sudo
|
||||||
|
raspi-config``.
|
||||||
|
|
||||||
#. Since I have a HDMI cable connected, but want the sound on the analog sound
|
#. Once you've rebooted and has logged in as the ``pi`` user, you can enter
|
||||||
connector, I have to run::
|
``sudo -i`` to become ``root``.
|
||||||
|
|
||||||
sudo amixer cset numid=3 1
|
|
||||||
|
|
||||||
to force it to use analog output. ``1`` means analog, ``0`` means auto, and
|
|
||||||
is the default, while ``2`` means HDMI. You can test sound output
|
|
||||||
independent of Mopidy by running::
|
|
||||||
|
|
||||||
aplay /usr/share/sounds/alsa/Front_Center.wav
|
|
||||||
|
|
||||||
If you hear a voice saying "Front Center", then your sound is working.
|
|
||||||
|
|
||||||
To make the change to analog output stick, you can add the ``amixer``
|
|
||||||
command to e.g. ``/etc/rc.local``, which will be executed when the system is
|
|
||||||
booting.
|
|
||||||
|
|
||||||
#. Install Mopidy and its dependencies as described in :ref:`debian-install`.
|
#. Install Mopidy and its dependencies as described in :ref:`debian-install`.
|
||||||
|
|
||||||
@ -79,114 +72,19 @@ you a lot better performance.
|
|||||||
starting at boot.
|
starting at boot.
|
||||||
|
|
||||||
|
|
||||||
Appendix A: Fixing audio quality issues
|
Testing sound output
|
||||||
=======================================
|
====================
|
||||||
|
|
||||||
As of about April 2013 the following steps should resolve any audio
|
You can test sound output independent of Mopidy by running::
|
||||||
issues for HDMI and analog without the use of an external USB sound
|
|
||||||
card.
|
|
||||||
|
|
||||||
#. Ensure your system is up to date. On Debian based systems run::
|
aplay /usr/share/sounds/alsa/Front_Center.wav
|
||||||
|
|
||||||
sudo apt-get update
|
If you hear a voice saying "Front Center", then your sound is working.
|
||||||
sudo apt-get dist-upgrade
|
|
||||||
|
|
||||||
#. Ensure you have a new enough firmware. On Debian based systems
|
If you want to change your audio output setting, simply rerun ``sudo
|
||||||
`rpi-update <https://github.com/Hexxeh/rpi-update>`_
|
raspi-config``. Alternatively, you can change the audio output setting
|
||||||
can be used.
|
directly by running:
|
||||||
|
|
||||||
#. Update either ``~/.asoundrc`` or ``/etc/asound.conf`` to the
|
- Auto (HDMI if connected, else 3.5mm jack): ``sudo amixer cset numid=3 0``
|
||||||
following::
|
- Use 3.5mm jack: ``sudo amixer cset numid=3 1``
|
||||||
|
- Use HDMI: ``sudo amixer cset numid=3 2``
|
||||||
pcm.!default {
|
|
||||||
type hw
|
|
||||||
card 0
|
|
||||||
}
|
|
||||||
ctl.!default {
|
|
||||||
type hw
|
|
||||||
card 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Note that if you have an ``~/.asoundrc`` it will overide any global
|
|
||||||
settings from ``/etc/asound.conf``.
|
|
||||||
|
|
||||||
#. For Mopidy to output audio directly to ALSA, instead of Jack which
|
|
||||||
GStreamer usually defaults to on Raspberry Pi, install the
|
|
||||||
``gstreamer0.10-alsa`` package::
|
|
||||||
|
|
||||||
sudo apt-get install gstreamer0.10-alsa
|
|
||||||
|
|
||||||
Then update your ``~/.config/mopidy/mopidy.conf`` to contain::
|
|
||||||
|
|
||||||
[audio]
|
|
||||||
output = alsasink
|
|
||||||
|
|
||||||
Following these steps you should be able to get crackle free sound on either
|
|
||||||
HDMI or analog. Note that you might need to ensure that PulseAudio is no longer
|
|
||||||
running to get this working nicely.
|
|
||||||
|
|
||||||
This recipe has been confirmed as working by a number of users on our issue
|
|
||||||
tracker and IRC. As a reference, the following versions where used for testing
|
|
||||||
this, however all newer and some older version are likely to work as we have
|
|
||||||
not determined the exact revision that fixed this::
|
|
||||||
|
|
||||||
$ uname -a
|
|
||||||
Linux raspberrypi 3.6.11+ #408 PREEMPT Wed Apr 10 20:33:39 BST 2013 armv6l GNU/Linux
|
|
||||||
|
|
||||||
$ /opt/vc/bin/vcgencmd version
|
|
||||||
Apr 25 2013 01:07:36
|
|
||||||
Copyright (c) 2012 Broadcom
|
|
||||||
version 386589 (release)
|
|
||||||
|
|
||||||
The only remaining known issue is a slight gap in playback at track changes
|
|
||||||
this is likely due to gapless playback not being implemented and is being
|
|
||||||
worked on irrespective of Raspberry Pi related work.
|
|
||||||
|
|
||||||
|
|
||||||
Appendix B: Raspbmc not booting
|
|
||||||
===============================
|
|
||||||
|
|
||||||
Due to a dependency version problem where XBMC uses another version of libtag
|
|
||||||
than what Debian originally ships with, you might have to make some minor
|
|
||||||
changes for Raspbmc to start properly after installing Mopidy.
|
|
||||||
|
|
||||||
If you notice that XBMC is not starting but gets stuck in a loop,
|
|
||||||
you need to make the following changes::
|
|
||||||
|
|
||||||
sudo ln -sf /home/pi/.xbmc-current/xbmc-bin/lib/xbmc/system/libtag.so.1 \
|
|
||||||
/usr/lib/arm-linux-gnueabihf/libtag.so.1
|
|
||||||
|
|
||||||
However, this will not persist the changes. To persist the changes edit
|
|
||||||
:file:`/etc/ld.so.conf.d/arm-linux-gnueabihf.conf` and add the following at the
|
|
||||||
top::
|
|
||||||
|
|
||||||
/home/pi/.xbmc-current/xbmc-bin/lib/xbmc/system
|
|
||||||
|
|
||||||
It's very important to add it at the top of the file as this indicates the
|
|
||||||
priority of the folder in which to look for shared libraries.
|
|
||||||
|
|
||||||
XBMC doesn't play nicely with the system wide installed version of libtag that
|
|
||||||
got installed together with Mopidy, but rather vendors in its own version.
|
|
||||||
|
|
||||||
More info about this issue can be found in `this post
|
|
||||||
<http://geeks.noeit.com/xbmc-library-dependency-error/>`_.
|
|
||||||
|
|
||||||
Please note that if you're running Xbian or another XBMC distribution these
|
|
||||||
instructions might vary for your system.
|
|
||||||
|
|
||||||
|
|
||||||
Appendix C: Installation on XBian
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Similar to the Raspbmc issue outlined in Appendix B, it's not possible to
|
|
||||||
install Mopidy on XBian without first resolving a dependency problem between
|
|
||||||
``gstreamer0.10-plugins-good`` and ``libtag1c2a``. More information can be
|
|
||||||
found in `this issue
|
|
||||||
<https://github.com/xbianonpi/xbian/issues/378#issuecomment-37723392>`_.
|
|
||||||
|
|
||||||
Run the following commands to remedy this and then install Mopidy as normal::
|
|
||||||
|
|
||||||
cd /tmp
|
|
||||||
wget http://apt.xbian.org/pool/stable/rpi-wheezy/l/libtag1c2a/libtag1c2a_1.7.2-1_armhf.deb
|
|
||||||
sudo dpkg -i libtag1c2a_1.7.2-1_armhf.deb
|
|
||||||
rm libtag1c2a_1.7.2-1_armhf.deb
|
|
||||||
|
|||||||
BIN
docs/installation/raspberrypi2.jpg
Normal file
BIN
docs/installation/raspberrypi2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
@ -39,17 +39,8 @@ using ``pkill``::
|
|||||||
pkill mopidy
|
pkill mopidy
|
||||||
|
|
||||||
|
|
||||||
Init scripts
|
Running as a service
|
||||||
============
|
====================
|
||||||
|
|
||||||
- The ``mopidy`` package at `apt.mopidy.com <http://apt.mopidy.com/>`__ comes
|
Once you're done exploring Mopidy and want to run it as a proper service, check
|
||||||
with an `sysvinit init script
|
out :ref:`service`.
|
||||||
<https://github.com/mopidy/mopidy/blob/debian/debian/mopidy.init>`_. For
|
|
||||||
more details, see the :ref:`debian` section of the docs.
|
|
||||||
|
|
||||||
- The ``mopidy`` package in `Arch Linux
|
|
||||||
<https://www.archlinux.org/packages/community/any/mopidy/>`__ comes with a systemd init
|
|
||||||
script.
|
|
||||||
|
|
||||||
- Issue :issue:`266` contains a bunch of init scripts for Mopidy, including
|
|
||||||
Upstart init scripts.
|
|
||||||
|
|||||||
94
docs/service.rst
Normal file
94
docs/service.rst
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
.. _service:
|
||||||
|
|
||||||
|
********************
|
||||||
|
Running as a service
|
||||||
|
********************
|
||||||
|
|
||||||
|
If you want to run Mopidy as a service using either an init script or a systemd
|
||||||
|
service, there's a few differences from running Mopidy as your own user you'll
|
||||||
|
want to know about. The following applies to Debian, Ubuntu, Raspbian, and
|
||||||
|
Arch. Hopefully, other distributions packaging Mopidy will make sure this works
|
||||||
|
the same way on their distribution.
|
||||||
|
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
=============
|
||||||
|
|
||||||
|
All configuration is in :file:`/etc/mopidy/mopidy.conf`, not in your user's
|
||||||
|
home directory.
|
||||||
|
|
||||||
|
|
||||||
|
mopidy user
|
||||||
|
===========
|
||||||
|
|
||||||
|
The Mopidy service runs as the ``mopidy`` user, which is automatically created
|
||||||
|
when you install the Mopidy package. The ``mopidy`` user will need read access
|
||||||
|
to any local music you want Mopidy to play.
|
||||||
|
|
||||||
|
|
||||||
|
Subcommands
|
||||||
|
===========
|
||||||
|
|
||||||
|
To run Mopidy subcommands with the same user and config files as the service
|
||||||
|
uses, you can use ``sudo mopidyctl <subcommand>``. In other words, where you'll
|
||||||
|
usually run::
|
||||||
|
|
||||||
|
mopidy config
|
||||||
|
|
||||||
|
You should instead run the following to inspect the service's configuration::
|
||||||
|
|
||||||
|
sudo mopidyctl config
|
||||||
|
|
||||||
|
The same applies to scanning your local music collection. Where you'll normally
|
||||||
|
run::
|
||||||
|
|
||||||
|
mopidy local scan
|
||||||
|
|
||||||
|
You should instead run::
|
||||||
|
|
||||||
|
sudo mopidyctl local scan
|
||||||
|
|
||||||
|
|
||||||
|
Service management with systemd
|
||||||
|
===============================
|
||||||
|
|
||||||
|
On modern systems using systemd you can enable the Mopidy service by running::
|
||||||
|
|
||||||
|
sudo systemctl enable mopidy
|
||||||
|
|
||||||
|
This will make Mopidy start when the system boots.
|
||||||
|
|
||||||
|
Mopidy is started, stopped, and restarted just like any other systemd service::
|
||||||
|
|
||||||
|
sudo systemctl start mopidy
|
||||||
|
sudo systemctl stop mopidy
|
||||||
|
sudo systemctl restart mopidy
|
||||||
|
|
||||||
|
You can check if Mopidy is currently running as a service by running::
|
||||||
|
|
||||||
|
sudo systemctl status mopidy
|
||||||
|
|
||||||
|
|
||||||
|
Service management on Debian
|
||||||
|
============================
|
||||||
|
|
||||||
|
On Debian systems (both those using systemd and not) you can enable the Mopidy
|
||||||
|
service by running::
|
||||||
|
|
||||||
|
sudo dpkg-reconfigure mopidy
|
||||||
|
|
||||||
|
Mopidy can be started, stopped, and restarted using the ``service`` command::
|
||||||
|
|
||||||
|
sudo service mopidy start
|
||||||
|
sudo service mopidy stop
|
||||||
|
sudo service mopidy restart
|
||||||
|
|
||||||
|
You can check if Mopidy is currently running as a service by running::
|
||||||
|
|
||||||
|
sudo service mopidy status
|
||||||
|
|
||||||
|
|
||||||
|
Service on OS X
|
||||||
|
===============
|
||||||
|
|
||||||
|
If you're installing Mopidy on OS X, see :ref:`osx-service`.
|
||||||
@ -14,4 +14,4 @@ if not (2, 7) <= sys.version_info < (3,):
|
|||||||
warnings.filterwarnings('ignore', 'could not open display')
|
warnings.filterwarnings('ignore', 'could not open display')
|
||||||
|
|
||||||
|
|
||||||
__version__ = '1.1.1'
|
__version__ = '1.1.2'
|
||||||
|
|||||||
@ -236,7 +236,9 @@ class LibraryController(object):
|
|||||||
result = future.get()
|
result = future.get()
|
||||||
if result is not None:
|
if result is not None:
|
||||||
validation.check_instances(result, models.Track)
|
validation.check_instances(result, models.Track)
|
||||||
results[u] = result
|
# TODO Consider making Track.uri field mandatory, and
|
||||||
|
# then remove this filtering of tracks without URIs.
|
||||||
|
results[u] = [r for r in result if r.uri]
|
||||||
|
|
||||||
if uri:
|
if uri:
|
||||||
return results[uri]
|
return results[uri]
|
||||||
|
|||||||
@ -353,14 +353,14 @@ class SearchResult(ValidatedImmutableObject):
|
|||||||
:type albums: list of :class:`Album` elements
|
:type albums: list of :class:`Album` elements
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The search result URI. Read-only.
|
#: The search result URI. Read-only.
|
||||||
uri = fields.URI()
|
uri = fields.URI()
|
||||||
|
|
||||||
# The tracks matching the search query. Read-only.
|
#: The tracks matching the search query. Read-only.
|
||||||
tracks = fields.Collection(type=Track, container=tuple)
|
tracks = fields.Collection(type=Track, container=tuple)
|
||||||
|
|
||||||
# The artists matching the search query. Read-only.
|
#: The artists matching the search query. Read-only.
|
||||||
artists = fields.Collection(type=Artist, container=tuple)
|
artists = fields.Collection(type=Artist, container=tuple)
|
||||||
|
|
||||||
# The albums matching the search query. Read-only.
|
#: The albums matching the search query. Read-only.
|
||||||
albums = fields.Collection(type=Album, container=tuple)
|
albums = fields.Collection(type=Album, container=tuple)
|
||||||
|
|||||||
@ -426,3 +426,27 @@ def stop(context):
|
|||||||
Stops playing.
|
Stops playing.
|
||||||
"""
|
"""
|
||||||
context.core.playback.stop()
|
context.core.playback.stop()
|
||||||
|
|
||||||
|
|
||||||
|
@protocol.commands.add('volume', change=protocol.INT)
|
||||||
|
def volume(context, change):
|
||||||
|
"""
|
||||||
|
*musicpd.org, playback section:*
|
||||||
|
|
||||||
|
``volume {CHANGE}``
|
||||||
|
|
||||||
|
Changes volume by amount ``CHANGE``.
|
||||||
|
|
||||||
|
Note: ``volume`` is deprecated, use ``setvol`` instead.
|
||||||
|
"""
|
||||||
|
if change < -100 or change > 100:
|
||||||
|
raise exceptions.MpdArgError('Invalid volume value')
|
||||||
|
|
||||||
|
old_volume = context.core.mixer.get_volume().get()
|
||||||
|
if old_volume is None:
|
||||||
|
raise exceptions.MpdSystemError('problems setting volume')
|
||||||
|
|
||||||
|
new_volume = min(max(0, old_volume + change), 100)
|
||||||
|
success = context.core.mixer.set_volume(new_volume).get()
|
||||||
|
if not success:
|
||||||
|
raise exceptions.MpdSystemError('problems setting volume')
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from mopidy.models import TlTrack
|
from mopidy.models import TlTrack
|
||||||
from mopidy.mpd.protocol import tagtype_list
|
from mopidy.mpd.protocol import tagtype_list
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# TODO: special handling of local:// uri scheme
|
# TODO: special handling of local:// uri scheme
|
||||||
normalize_path_re = re.compile(r'[^/]+')
|
normalize_path_re = re.compile(r'[^/]+')
|
||||||
|
|
||||||
@ -34,8 +38,12 @@ def track_to_mpd_format(track, position=None, stream_title=None):
|
|||||||
else:
|
else:
|
||||||
(tlid, track) = (None, track)
|
(tlid, track) = (None, track)
|
||||||
|
|
||||||
|
if not track.uri:
|
||||||
|
logger.warning('Ignoring track without uri')
|
||||||
|
return []
|
||||||
|
|
||||||
result = [
|
result = [
|
||||||
('file', track.uri or ''),
|
('file', track.uri),
|
||||||
('Time', track.length and (track.length // 1000) or 0),
|
('Time', track.length and (track.length // 1000) or 0),
|
||||||
('Artist', concat_multi_values(track.artists, 'name')),
|
('Artist', concat_multi_values(track.artists, 'name')),
|
||||||
('Album', track.album and track.album.name or ''),
|
('Album', track.album and track.album.name or ''),
|
||||||
@ -164,7 +172,9 @@ def tracks_to_mpd_format(tracks, start=0, end=None):
|
|||||||
assert len(tracks) == len(positions)
|
assert len(tracks) == len(positions)
|
||||||
result = []
|
result = []
|
||||||
for track, position in zip(tracks, positions):
|
for track, position in zip(tracks, positions):
|
||||||
result.append(track_to_mpd_format(track, position))
|
formatted_track = track_to_mpd_format(track, position)
|
||||||
|
if formatted_track:
|
||||||
|
result.append(formatted_track)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -153,8 +153,8 @@ class CoreLibraryTest(BaseCoreLibraryTest):
|
|||||||
self.core.library.lookup('dummy1:a', ['dummy2:a'])
|
self.core.library.lookup('dummy1:a', ['dummy2:a'])
|
||||||
|
|
||||||
def test_lookup_can_handle_uris(self):
|
def test_lookup_can_handle_uris(self):
|
||||||
track1 = Track(name='abc')
|
track1 = Track(uri='dummy1:a', name='abc')
|
||||||
track2 = Track(name='def')
|
track2 = Track(uri='dummy2:a', name='def')
|
||||||
|
|
||||||
self.library1.lookup().get.return_value = [track1]
|
self.library1.lookup().get.return_value = [track1]
|
||||||
self.library2.lookup().get.return_value = [track2]
|
self.library2.lookup().get.return_value = [track2]
|
||||||
@ -169,6 +169,15 @@ class CoreLibraryTest(BaseCoreLibraryTest):
|
|||||||
self.assertFalse(self.library1.lookup.called)
|
self.assertFalse(self.library1.lookup.called)
|
||||||
self.assertFalse(self.library2.lookup.called)
|
self.assertFalse(self.library2.lookup.called)
|
||||||
|
|
||||||
|
def test_lookup_ignores_tracks_without_uri_set(self):
|
||||||
|
track1 = Track(uri='dummy1:a', name='abc')
|
||||||
|
track2 = Track()
|
||||||
|
|
||||||
|
self.library1.lookup().get.return_value = [track1, track2]
|
||||||
|
|
||||||
|
result = self.core.library.lookup(uris=['dummy1:a'])
|
||||||
|
self.assertEqual(result, {'dummy1:a': [track1]})
|
||||||
|
|
||||||
def test_refresh_with_uri_selects_dummy1_backend(self):
|
def test_refresh_with_uri_selects_dummy1_backend(self):
|
||||||
self.core.library.refresh('dummy1:a')
|
self.core.library.refresh('dummy1:a')
|
||||||
|
|
||||||
|
|||||||
@ -80,41 +80,6 @@ class PlaybackOptionsHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertTrue(self.core.tracklist.repeat.get())
|
self.assertTrue(self.core.tracklist.repeat.get())
|
||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
def test_setvol_below_min(self):
|
|
||||||
self.send_request('setvol "-10"')
|
|
||||||
self.assertEqual(0, self.core.mixer.get_volume().get())
|
|
||||||
self.assertInResponse('OK')
|
|
||||||
|
|
||||||
def test_setvol_min(self):
|
|
||||||
self.send_request('setvol "0"')
|
|
||||||
self.assertEqual(0, self.core.mixer.get_volume().get())
|
|
||||||
self.assertInResponse('OK')
|
|
||||||
|
|
||||||
def test_setvol_middle(self):
|
|
||||||
self.send_request('setvol "50"')
|
|
||||||
self.assertEqual(50, self.core.mixer.get_volume().get())
|
|
||||||
self.assertInResponse('OK')
|
|
||||||
|
|
||||||
def test_setvol_max(self):
|
|
||||||
self.send_request('setvol "100"')
|
|
||||||
self.assertEqual(100, self.core.mixer.get_volume().get())
|
|
||||||
self.assertInResponse('OK')
|
|
||||||
|
|
||||||
def test_setvol_above_max(self):
|
|
||||||
self.send_request('setvol "110"')
|
|
||||||
self.assertEqual(100, self.core.mixer.get_volume().get())
|
|
||||||
self.assertInResponse('OK')
|
|
||||||
|
|
||||||
def test_setvol_plus_is_ignored(self):
|
|
||||||
self.send_request('setvol "+10"')
|
|
||||||
self.assertEqual(10, self.core.mixer.get_volume().get())
|
|
||||||
self.assertInResponse('OK')
|
|
||||||
|
|
||||||
def test_setvol_without_quotes(self):
|
|
||||||
self.send_request('setvol 50')
|
|
||||||
self.assertEqual(50, self.core.mixer.get_volume().get())
|
|
||||||
self.assertInResponse('OK')
|
|
||||||
|
|
||||||
def test_single_off(self):
|
def test_single_off(self):
|
||||||
self.send_request('single "0"')
|
self.send_request('single "0"')
|
||||||
self.assertFalse(self.core.tracklist.single.get())
|
self.assertFalse(self.core.tracklist.single.get())
|
||||||
@ -455,9 +420,83 @@ class PlaybackControlHandlerTest(protocol.BaseTestCase):
|
|||||||
self.assertInResponse('OK')
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
|
||||||
class PlaybackOptionsHandlerNoneMixerTest(protocol.BaseTestCase):
|
class VolumeTest(protocol.BaseTestCase):
|
||||||
|
|
||||||
|
def test_setvol_below_min(self):
|
||||||
|
self.send_request('setvol "-10"')
|
||||||
|
self.assertEqual(0, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_setvol_min(self):
|
||||||
|
self.send_request('setvol "0"')
|
||||||
|
self.assertEqual(0, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_setvol_middle(self):
|
||||||
|
self.send_request('setvol "50"')
|
||||||
|
self.assertEqual(50, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_setvol_max(self):
|
||||||
|
self.send_request('setvol "100"')
|
||||||
|
self.assertEqual(100, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_setvol_above_max(self):
|
||||||
|
self.send_request('setvol "110"')
|
||||||
|
self.assertEqual(100, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_setvol_plus_is_ignored(self):
|
||||||
|
self.send_request('setvol "+10"')
|
||||||
|
self.assertEqual(10, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_setvol_without_quotes(self):
|
||||||
|
self.send_request('setvol 50')
|
||||||
|
self.assertEqual(50, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_volume_plus(self):
|
||||||
|
self.core.mixer.set_volume(50)
|
||||||
|
|
||||||
|
self.send_request('volume +20')
|
||||||
|
|
||||||
|
self.assertEqual(70, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_volume_minus(self):
|
||||||
|
self.core.mixer.set_volume(50)
|
||||||
|
|
||||||
|
self.send_request('volume -20')
|
||||||
|
|
||||||
|
self.assertEqual(30, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('OK')
|
||||||
|
|
||||||
|
def test_volume_less_than_minus_100(self):
|
||||||
|
self.core.mixer.set_volume(50)
|
||||||
|
|
||||||
|
self.send_request('volume -110')
|
||||||
|
|
||||||
|
self.assertEqual(50, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('ACK [2@0] {volume} Invalid volume value')
|
||||||
|
|
||||||
|
def test_volume_more_than_plus_100(self):
|
||||||
|
self.core.mixer.set_volume(50)
|
||||||
|
|
||||||
|
self.send_request('volume +110')
|
||||||
|
|
||||||
|
self.assertEqual(50, self.core.mixer.get_volume().get())
|
||||||
|
self.assertInResponse('ACK [2@0] {volume} Invalid volume value')
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeWithNoMixerTest(protocol.BaseTestCase):
|
||||||
enable_mixer = False
|
enable_mixer = False
|
||||||
|
|
||||||
def test_setvol_max_error(self):
|
def test_setvol_without_mixer_fails(self):
|
||||||
self.send_request('setvol "100"')
|
self.send_request('setvol "100"')
|
||||||
self.assertInResponse('ACK [52@0] {setvol} problems setting volume')
|
self.assertInResponse('ACK [52@0] {setvol} problems setting volume')
|
||||||
|
|
||||||
|
def test_volume_without_mixer_failes(self):
|
||||||
|
self.send_request('volume +100')
|
||||||
|
self.assertInResponse('ACK [52@0] {volume} problems setting volume')
|
||||||
|
|||||||
@ -56,7 +56,7 @@ class TrackMpdFormatTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_track_to_mpd_format_with_position_and_tlid(self):
|
def test_track_to_mpd_format_with_position_and_tlid(self):
|
||||||
result = translator.track_to_mpd_format(
|
result = translator.track_to_mpd_format(
|
||||||
TlTrack(2, Track()), position=1)
|
TlTrack(2, Track(uri='a uri')), position=1)
|
||||||
self.assertIn(('Pos', 1), result)
|
self.assertIn(('Pos', 1), result)
|
||||||
self.assertIn(('Id', 2), result)
|
self.assertIn(('Id', 2), result)
|
||||||
|
|
||||||
@ -153,13 +153,17 @@ class PlaylistMpdFormatTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test_mpd_format(self):
|
def test_mpd_format(self):
|
||||||
playlist = Playlist(tracks=[
|
playlist = Playlist(tracks=[
|
||||||
Track(track_no=1), Track(track_no=2), Track(track_no=3)])
|
Track(uri='foo', track_no=1),
|
||||||
|
Track(uri='bar', track_no=2),
|
||||||
|
Track(uri='baz', track_no=3)])
|
||||||
result = translator.playlist_to_mpd_format(playlist)
|
result = translator.playlist_to_mpd_format(playlist)
|
||||||
self.assertEqual(len(result), 3)
|
self.assertEqual(len(result), 3)
|
||||||
|
|
||||||
def test_mpd_format_with_range(self):
|
def test_mpd_format_with_range(self):
|
||||||
playlist = Playlist(tracks=[
|
playlist = Playlist(tracks=[
|
||||||
Track(track_no=1), Track(track_no=2), Track(track_no=3)])
|
Track(uri='foo', track_no=1),
|
||||||
|
Track(uri='bar', track_no=2),
|
||||||
|
Track(uri='baz', track_no=3)])
|
||||||
result = translator.playlist_to_mpd_format(playlist, 1, 2)
|
result = translator.playlist_to_mpd_format(playlist, 1, 2)
|
||||||
self.assertEqual(len(result), 1)
|
self.assertEqual(len(result), 1)
|
||||||
self.assertEqual(dict(result[0])['Track'], 2)
|
self.assertEqual(dict(result[0])['Track'], 2)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user