Write more docs, using Sphinx
This commit is contained in:
parent
5ef7d17deb
commit
d471b30afe
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,8 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.swp
|
*.swp
|
||||||
.coverage
|
.coverage
|
||||||
|
.idea
|
||||||
|
docs/_build
|
||||||
local_settings.py
|
local_settings.py
|
||||||
pip-log.txt
|
pip-log.txt
|
||||||
spotify_appkey.key
|
spotify_appkey.key
|
||||||
|
|||||||
153
README.rst
153
README.rst
@ -1,147 +1,16 @@
|
|||||||
******
|
******
|
||||||
mopidy
|
Mopidy
|
||||||
******
|
******
|
||||||
|
|
||||||
mopidy is an MPD server with a Spotify backend.
|
Mopidy is an `MPD <http://mpd.wikia.com/>`_ server with a
|
||||||
|
`Spotify <http://www.spotify.com/>`_ backend. Using a standard MPD client you
|
||||||
|
can search for music in Spotify's wast archive, manage Spotify play lists and
|
||||||
|
play music from Spotify.
|
||||||
|
|
||||||
|
Mopidy is currently under development. Unless you want to contribute to the
|
||||||
|
development, you should probably wait for our first release before trying out
|
||||||
|
Mopidy.
|
||||||
|
|
||||||
Goal
|
* `Source code <http://github.com/jodal/mopidy>`_
|
||||||
====
|
* `Documentation <http://www.mopidy.com/>`_
|
||||||
|
* IRC: ``#mopidy`` at `irc.freenode.net <http://freenode.net/>`_
|
||||||
Using a standard MPD client we want to search for music in Spotify, manage
|
|
||||||
Spotify play lists and play music from Spotify.
|
|
||||||
|
|
||||||
To limit scope, we will start by implementing an MPD server which only
|
|
||||||
supports Spotify, and not playback of files from disk. We will make mopidy
|
|
||||||
modular, so we can extend it with other backends in the future, like file
|
|
||||||
playback and other online music services such as Last.fm.
|
|
||||||
|
|
||||||
|
|
||||||
Backends
|
|
||||||
========
|
|
||||||
|
|
||||||
To use the despotify backend, you first need to install despotify and spytify.
|
|
||||||
Alternatively, we are working on a libspotify backend, which requires you to
|
|
||||||
install libspotify and pyspotify.
|
|
||||||
|
|
||||||
Both backends require a Spotify premium account, while only the libspotify
|
|
||||||
backend requires you to get an application key from Spotify before use.
|
|
||||||
|
|
||||||
|
|
||||||
Installing despotify and spytify
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
Check out the despotify source code revision 497 (or possibly newer)::
|
|
||||||
|
|
||||||
svn co https://despotify.svn.sourceforge.net/svnroot/despotify@497 despotify
|
|
||||||
|
|
||||||
Install despotify's dependencies. At Debian/Ubuntu systems::
|
|
||||||
|
|
||||||
sudo aptitude install libssl-dev zlib1g-dev libvorbis-dev \
|
|
||||||
libtool libncursesw5-dev libao-dev
|
|
||||||
|
|
||||||
Build and install despotify::
|
|
||||||
|
|
||||||
cd despotify/src/
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
|
|
||||||
Build and install spytify::
|
|
||||||
|
|
||||||
cd despotify/src/bindings/python/
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
|
|
||||||
To validate that everything is working, run the ``test.py`` script which is
|
|
||||||
distributed with spytify::
|
|
||||||
|
|
||||||
python test.py
|
|
||||||
|
|
||||||
The test script should ask for your username and password (which must be for a
|
|
||||||
Spotify Premium account), ask for a search query, list all your playlists with
|
|
||||||
tracks, play 10s from a random song from the search result, pause for two
|
|
||||||
seconds, play for five more seconds, and quit.
|
|
||||||
|
|
||||||
|
|
||||||
Installing libspotify and pyspotify
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
As libspotify's installation script at the moment is somewhat broken (see this
|
|
||||||
`GetSatisfaction thread <http://getsatisfaction.com/spotify/topics/libspotify_please_fix_the_installation_script>`_
|
|
||||||
for details), it is easiest to use the libspotify files bundled with pyspotify.
|
|
||||||
The files bundled with pyspotify are for 64-bit, so if you run a 32-bit OS, you
|
|
||||||
must get libspotify from https://developer.spotify.com/en/libspotify/.
|
|
||||||
|
|
||||||
Install pyspotify's dependencies. At Debian/Ubuntu systems::
|
|
||||||
|
|
||||||
sudo aptitude install python-alsaaudio
|
|
||||||
|
|
||||||
Check out the pyspotify code, and install it::
|
|
||||||
|
|
||||||
git clone git://github.com/winjer/pyspotify.git
|
|
||||||
cd pyspotify
|
|
||||||
export LD_LIBRARY_PATH=$PWD/lib
|
|
||||||
sudo python setup.py develop
|
|
||||||
|
|
||||||
Apply for an application key at
|
|
||||||
https://developer.spotify.com/en/libspotify/application-key, download the
|
|
||||||
binary version, and place the file at ``pyspotify/spotify_appkey.key``.
|
|
||||||
|
|
||||||
Test your libspotify setup::
|
|
||||||
|
|
||||||
./example1.py -u USERNAME -p PASSWORD
|
|
||||||
|
|
||||||
Until Spotify fixes their installation script, you'll have to set
|
|
||||||
``LD_LIBRARY_PATH`` every time you are going to use libspotify (in other words
|
|
||||||
before starting mopidy).
|
|
||||||
|
|
||||||
|
|
||||||
Running mopidy
|
|
||||||
==============
|
|
||||||
|
|
||||||
Create a file name ``local_settings.py`` in the same directory as
|
|
||||||
``settings.py``. Enter your Spotify Premium account's username and password
|
|
||||||
into the file, like this::
|
|
||||||
|
|
||||||
SPOTIFY_USERNAME = u'myusername'
|
|
||||||
SPOTIFY_PASSWORD = u'mysecret'
|
|
||||||
|
|
||||||
To start mopidy, go to the root of the mopidy project, then simply run::
|
|
||||||
|
|
||||||
python mopidy
|
|
||||||
|
|
||||||
To stop mopidy, press ``CTRL+C``.
|
|
||||||
|
|
||||||
|
|
||||||
Running tests
|
|
||||||
=============
|
|
||||||
|
|
||||||
To run tests, you need a couple of dependiencies. Some can be installed through Debian/Ubuntu package management::
|
|
||||||
|
|
||||||
sudo aptitude install python-coverage
|
|
||||||
|
|
||||||
The rest can be installed using pip::
|
|
||||||
|
|
||||||
sudo aptitude install python-pip python-setuptools bzr
|
|
||||||
pip install -r test-requirements.txt
|
|
||||||
|
|
||||||
Then, to run all tests::
|
|
||||||
|
|
||||||
python tests
|
|
||||||
|
|
||||||
|
|
||||||
Resources
|
|
||||||
=========
|
|
||||||
|
|
||||||
- MPD
|
|
||||||
|
|
||||||
- `MPD protocol documentation <http://www.musicpd.org/doc/protocol/>`_
|
|
||||||
- The original `MPD server <http://mpd.wikia.com/>`_
|
|
||||||
|
|
||||||
- Spotify
|
|
||||||
|
|
||||||
- `spytify <http://despotify.svn.sourceforge.net/viewvc/despotify/src/bindings/python/>`_,
|
|
||||||
the Python bindings for `despotify <http://despotify.se/>`_
|
|
||||||
- `pyspotify <http://github.com/winjer/pyspotify/>`_,
|
|
||||||
Python bindings for the official Spotify library, libspotify
|
|
||||||
- `Spotify's official metadata API <http://developer.spotify.com/en/metadata-api/overview/>`_
|
|
||||||
|
|||||||
104
docs/Makefile
Normal file
104
docs/Makefile
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# Makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
PAPER =
|
||||||
|
|
||||||
|
# Internal variables.
|
||||||
|
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||||
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
|
ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
|
||||||
|
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
|
@echo " html to make standalone HTML files"
|
||||||
|
@echo " dirhtml to make HTML files named index.html in directories"
|
||||||
|
@echo " pickle to make pickle files"
|
||||||
|
@echo " json to make JSON files"
|
||||||
|
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||||
|
@echo " qthelp to make HTML files and a qthelp project"
|
||||||
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
|
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||||
|
@echo " linkcheck to check all external links for integrity"
|
||||||
|
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -rf _build/*
|
||||||
|
|
||||||
|
html:
|
||||||
|
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in _build/html."
|
||||||
|
|
||||||
|
dirhtml:
|
||||||
|
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in _build/dirhtml."
|
||||||
|
|
||||||
|
pickle:
|
||||||
|
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the pickle files."
|
||||||
|
|
||||||
|
json:
|
||||||
|
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the JSON files."
|
||||||
|
|
||||||
|
htmlhelp:
|
||||||
|
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||||
|
".hhp project file in _build/htmlhelp."
|
||||||
|
|
||||||
|
qthelp:
|
||||||
|
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||||
|
".qhcp project file in _build/qthelp, like this:"
|
||||||
|
@echo "# qcollectiongenerator _build/qthelp/Mopidy.qhcp"
|
||||||
|
@echo "To view the help file:"
|
||||||
|
@echo "# assistant -collectionFile _build/qthelp/Mopidy.qhc"
|
||||||
|
|
||||||
|
latex:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; the LaTeX files are in _build/latex."
|
||||||
|
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
|
||||||
|
"run these through (pdf)latex."
|
||||||
|
|
||||||
|
changes:
|
||||||
|
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes
|
||||||
|
@echo
|
||||||
|
@echo "The overview file is in _build/changes."
|
||||||
|
|
||||||
|
linkcheck:
|
||||||
|
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck
|
||||||
|
@echo
|
||||||
|
@echo "Link check complete; look for any errors in the above output " \
|
||||||
|
"or in _build/linkcheck/output.txt."
|
||||||
|
|
||||||
|
doctest:
|
||||||
|
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest
|
||||||
|
@echo "Testing of doctests in the sources finished, look at the " \
|
||||||
|
"results in _build/doctest/output.txt."
|
||||||
|
|
||||||
|
public: clean html
|
||||||
|
rm -rf /tmp/mopidy-html && cp -r _build/html /tmp/mopidy-html
|
||||||
|
git stash save
|
||||||
|
cd .. && \
|
||||||
|
git checkout gh-pages && \
|
||||||
|
git pull && \
|
||||||
|
rm -r * && \
|
||||||
|
cp -r /tmp/mopidy-html/* . && \
|
||||||
|
mv _sources sources && \
|
||||||
|
(find . -type f | xargs sed -i -e 's/_sources/sources/g') && \
|
||||||
|
mv _static static && \
|
||||||
|
(find . -type f | xargs sed -i -e 's/_static/static/g') && \
|
||||||
|
mv _images images && \
|
||||||
|
(find . -type f | xargs sed -i -e 's/_images/images/g') && \
|
||||||
|
git add *
|
||||||
229
docs/_themes/nature/static/nature.css_t
vendored
Normal file
229
docs/_themes/nature/static/nature.css_t
vendored
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
/**
|
||||||
|
* Sphinx stylesheet -- default theme
|
||||||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import url("basic.css");
|
||||||
|
|
||||||
|
/* -- page layout ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 100%;
|
||||||
|
background-color: #111;
|
||||||
|
color: #555;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.documentwrapper {
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.bodywrapper {
|
||||||
|
margin: 0 0 0 230px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr{
|
||||||
|
border: 1px solid #B1B4B6;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.document {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #3E4349;
|
||||||
|
padding: 0 30px 30px 30px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footer {
|
||||||
|
color: #555;
|
||||||
|
width: 100%;
|
||||||
|
padding: 13px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footer a {
|
||||||
|
color: #444;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related {
|
||||||
|
background-color: #6BA81E;
|
||||||
|
line-height: 32px;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0px 1px 0 #444;
|
||||||
|
font-size: 0.80em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related a {
|
||||||
|
color: #E2F3CC;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar {
|
||||||
|
font-size: 0.75em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebarwrapper{
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar h3,
|
||||||
|
div.sphinxsidebar h4 {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
color: #222;
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px 10px;
|
||||||
|
background-color: #ddd;
|
||||||
|
text-shadow: 1px 1px 0 white
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar h4{
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar h3 a {
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.sphinxsidebar p {
|
||||||
|
color: #888;
|
||||||
|
padding: 5px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar p.topless {
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar ul {
|
||||||
|
margin: 10px 20px;
|
||||||
|
padding: 0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar a {
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar input {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar input[type=text]{
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- body styles ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #005B81;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #E32E00;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body h1,
|
||||||
|
div.body h2,
|
||||||
|
div.body h3,
|
||||||
|
div.body h4,
|
||||||
|
div.body h5,
|
||||||
|
div.body h6 {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: #BED4EB;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #212224;
|
||||||
|
margin: 30px 0px 10px 0px;
|
||||||
|
padding: 5px 0 5px 10px;
|
||||||
|
text-shadow: 0px 1px 0 white
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
|
||||||
|
div.body h2 { font-size: 150%; background-color: #C8D5E3; }
|
||||||
|
div.body h3 { font-size: 120%; background-color: #D8DEE3; }
|
||||||
|
div.body h4 { font-size: 110%; background-color: #D8DEE3; }
|
||||||
|
div.body h5 { font-size: 100%; background-color: #D8DEE3; }
|
||||||
|
div.body h6 { font-size: 100%; background-color: #D8DEE3; }
|
||||||
|
|
||||||
|
a.headerlink {
|
||||||
|
color: #c60f0f;
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding: 0 4px 0 4px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.headerlink:hover {
|
||||||
|
background-color: #c60f0f;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body p, div.body dd, div.body li {
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.admonition p.admonition-title + p {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.highlight{
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.note {
|
||||||
|
background-color: #eee;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.seealso {
|
||||||
|
background-color: #ffc;
|
||||||
|
border: 1px solid #ff6;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.topic {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.warning {
|
||||||
|
background-color: #ffe4e4;
|
||||||
|
border: 1px solid #f66;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.admonition-title {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.admonition-title:after {
|
||||||
|
content: ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: White;
|
||||||
|
color: #222;
|
||||||
|
line-height: 1.2em;
|
||||||
|
border: 1px solid #C6C9CB;
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin: 1.5em 0 1.5em 0;
|
||||||
|
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
|
||||||
|
-moz-box-shadow: 1px 1px 1px #d8d8d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt {
|
||||||
|
background-color: #ecf0f3;
|
||||||
|
color: #222;
|
||||||
|
padding: 1px 2px;
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
54
docs/_themes/nature/static/pygments.css
vendored
Normal file
54
docs/_themes/nature/static/pygments.css
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
.c { color: #999988; font-style: italic } /* Comment */
|
||||||
|
.k { font-weight: bold } /* Keyword */
|
||||||
|
.o { font-weight: bold } /* Operator */
|
||||||
|
.cm { color: #999988; font-style: italic } /* Comment.Multiline */
|
||||||
|
.cp { color: #999999; font-weight: bold } /* Comment.preproc */
|
||||||
|
.c1 { color: #999988; font-style: italic } /* Comment.Single */
|
||||||
|
.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
|
||||||
|
.ge { font-style: italic } /* Generic.Emph */
|
||||||
|
.gr { color: #aa0000 } /* Generic.Error */
|
||||||
|
.gh { color: #999999 } /* Generic.Heading */
|
||||||
|
.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
|
||||||
|
.go { color: #111 } /* Generic.Output */
|
||||||
|
.gp { color: #555555 } /* Generic.Prompt */
|
||||||
|
.gs { font-weight: bold } /* Generic.Strong */
|
||||||
|
.gu { color: #aaaaaa } /* Generic.Subheading */
|
||||||
|
.gt { color: #aa0000 } /* Generic.Traceback */
|
||||||
|
.kc { font-weight: bold } /* Keyword.Constant */
|
||||||
|
.kd { font-weight: bold } /* Keyword.Declaration */
|
||||||
|
.kp { font-weight: bold } /* Keyword.Pseudo */
|
||||||
|
.kr { font-weight: bold } /* Keyword.Reserved */
|
||||||
|
.kt { color: #445588; font-weight: bold } /* Keyword.Type */
|
||||||
|
.m { color: #009999 } /* Literal.Number */
|
||||||
|
.s { color: #bb8844 } /* Literal.String */
|
||||||
|
.na { color: #008080 } /* Name.Attribute */
|
||||||
|
.nb { color: #999999 } /* Name.Builtin */
|
||||||
|
.nc { color: #445588; font-weight: bold } /* Name.Class */
|
||||||
|
.no { color: #ff99ff } /* Name.Constant */
|
||||||
|
.ni { color: #800080 } /* Name.Entity */
|
||||||
|
.ne { color: #990000; font-weight: bold } /* Name.Exception */
|
||||||
|
.nf { color: #990000; font-weight: bold } /* Name.Function */
|
||||||
|
.nn { color: #555555 } /* Name.Namespace */
|
||||||
|
.nt { color: #000080 } /* Name.Tag */
|
||||||
|
.nv { color: purple } /* Name.Variable */
|
||||||
|
.ow { font-weight: bold } /* Operator.Word */
|
||||||
|
.mf { color: #009999 } /* Literal.Number.Float */
|
||||||
|
.mh { color: #009999 } /* Literal.Number.Hex */
|
||||||
|
.mi { color: #009999 } /* Literal.Number.Integer */
|
||||||
|
.mo { color: #009999 } /* Literal.Number.Oct */
|
||||||
|
.sb { color: #bb8844 } /* Literal.String.Backtick */
|
||||||
|
.sc { color: #bb8844 } /* Literal.String.Char */
|
||||||
|
.sd { color: #bb8844 } /* Literal.String.Doc */
|
||||||
|
.s2 { color: #bb8844 } /* Literal.String.Double */
|
||||||
|
.se { color: #bb8844 } /* Literal.String.Escape */
|
||||||
|
.sh { color: #bb8844 } /* Literal.String.Heredoc */
|
||||||
|
.si { color: #bb8844 } /* Literal.String.Interpol */
|
||||||
|
.sx { color: #bb8844 } /* Literal.String.Other */
|
||||||
|
.sr { color: #808000 } /* Literal.String.Regex */
|
||||||
|
.s1 { color: #bb8844 } /* Literal.String.Single */
|
||||||
|
.ss { color: #bb8844 } /* Literal.String.Symbol */
|
||||||
|
.bp { color: #999999 } /* Name.Builtin.Pseudo */
|
||||||
|
.vc { color: #ff99ff } /* Name.Variable.Class */
|
||||||
|
.vg { color: #ff99ff } /* Name.Variable.Global */
|
||||||
|
.vi { color: #ff99ff } /* Name.Variable.Instance */
|
||||||
|
.il { color: #009999 } /* Literal.Number.Integer.Long */
|
||||||
4
docs/_themes/nature/theme.conf
vendored
Normal file
4
docs/_themes/nature/theme.conf
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[theme]
|
||||||
|
inherit = basic
|
||||||
|
stylesheet = nature.css
|
||||||
|
pygments_style = tango
|
||||||
15
docs/changes.rst
Normal file
15
docs/changes.rst
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
*******
|
||||||
|
Changes
|
||||||
|
*******
|
||||||
|
|
||||||
|
This change log is used to track all major changes to Mopidy.
|
||||||
|
|
||||||
|
|
||||||
|
0.1 (unreleased)
|
||||||
|
================
|
||||||
|
|
||||||
|
Initial version.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
* *TODO:* Fill out
|
||||||
194
docs/conf.py
Normal file
194
docs/conf.py
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Mopidy documentation build configuration file, created by
|
||||||
|
# sphinx-quickstart on Fri Feb 5 22:19:08 2010.
|
||||||
|
#
|
||||||
|
# This file is execfile()d with the current directory set to its containing dir.
|
||||||
|
#
|
||||||
|
# Note that not all possible configuration values are present in this
|
||||||
|
# autogenerated file.
|
||||||
|
#
|
||||||
|
# All configuration values have a default; values that are commented out
|
||||||
|
# serve to show the default.
|
||||||
|
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#sys.path.append(os.path.abspath('.'))
|
||||||
|
|
||||||
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
|
extensions = []
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The suffix of source filenames.
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The encoding of source files.
|
||||||
|
#source_encoding = 'utf-8'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = u'Mopidy'
|
||||||
|
copyright = u'2010, Stein Magnus Jodal'
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
# The short X.Y version.
|
||||||
|
version = '0.1'
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
release = '0.1'
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#language = None
|
||||||
|
|
||||||
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
|
# non-false value, then it is used:
|
||||||
|
#today = ''
|
||||||
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
|
#today_fmt = '%B %d, %Y'
|
||||||
|
|
||||||
|
# List of documents that shouldn't be included in the build.
|
||||||
|
#unused_docs = []
|
||||||
|
|
||||||
|
# List of directories, relative to source directory, that shouldn't be searched
|
||||||
|
# for source files.
|
||||||
|
exclude_trees = ['_build']
|
||||||
|
|
||||||
|
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||||
|
#default_role = None
|
||||||
|
|
||||||
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
|
#add_function_parentheses = True
|
||||||
|
|
||||||
|
# If true, the current module name will be prepended to all description
|
||||||
|
# unit titles (such as .. function::).
|
||||||
|
#add_module_names = True
|
||||||
|
|
||||||
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
|
# output. They are ignored by default.
|
||||||
|
#show_authors = False
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
|
# A list of ignored prefixes for module index sorting.
|
||||||
|
#modindex_common_prefix = []
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output ---------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||||
|
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||||
|
html_theme = 'nature'
|
||||||
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
#html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
|
html_theme_path = ['_themes']
|
||||||
|
|
||||||
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
|
# "<project> v<release> documentation".
|
||||||
|
#html_title = None
|
||||||
|
|
||||||
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
|
#html_short_title = None
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
|
# of the sidebar.
|
||||||
|
#html_logo = None
|
||||||
|
|
||||||
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
|
# pixels large.
|
||||||
|
#html_favicon = None
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
|
# using the given strftime format.
|
||||||
|
#html_last_updated_fmt = '%b %d, %Y'
|
||||||
|
|
||||||
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
|
# typographically correct entities.
|
||||||
|
#html_use_smartypants = True
|
||||||
|
|
||||||
|
# Custom sidebar templates, maps document names to template names.
|
||||||
|
#html_sidebars = {}
|
||||||
|
|
||||||
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
|
# template names.
|
||||||
|
#html_additional_pages = {}
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#html_use_modindex = True
|
||||||
|
|
||||||
|
# If false, no index is generated.
|
||||||
|
#html_use_index = True
|
||||||
|
|
||||||
|
# If true, the index is split into individual pages for each letter.
|
||||||
|
#html_split_index = False
|
||||||
|
|
||||||
|
# If true, links to the reST sources are added to the pages.
|
||||||
|
#html_show_sourcelink = True
|
||||||
|
|
||||||
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
|
# base URL from which the finished HTML is served.
|
||||||
|
#html_use_opensearch = ''
|
||||||
|
|
||||||
|
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
|
#html_file_suffix = ''
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'Mopidydoc'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for LaTeX output --------------------------------------------------
|
||||||
|
|
||||||
|
# The paper size ('letter' or 'a4').
|
||||||
|
#latex_paper_size = 'letter'
|
||||||
|
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#latex_font_size = '10pt'
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||||
|
latex_documents = [
|
||||||
|
('index', 'Mopidy.tex', u'Mopidy Documentation',
|
||||||
|
u'Stein Magnus Jodal', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
|
# the title page.
|
||||||
|
#latex_logo = None
|
||||||
|
|
||||||
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
|
# not chapters.
|
||||||
|
#latex_use_parts = False
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#latex_preamble = ''
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#latex_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#latex_use_modindex = True
|
||||||
@ -1,18 +0,0 @@
|
|||||||
Despotify issues
|
|
||||||
----------------
|
|
||||||
|
|
||||||
* r483: s.lookup('spotify:track:1mr3616BzLdhXfJmLmRsO8') returns error:
|
|
||||||
"SpytifyError: URI specifies invalid type: track"
|
|
||||||
Possibly fixed in r497.
|
|
||||||
* r483: When accessing an_artist.albums one get the error:
|
|
||||||
"TypeError: Cannot convert spytify.AlbumDataFull to spytify.ArtistDataFull"
|
|
||||||
* r483: Sometimes segfaults when traversing stored playlists. May work if one
|
|
||||||
try again immediately. Another example segfault::
|
|
||||||
|
|
||||||
>>> In [45]: s.lookup('spotify:user:klette:playlist:5rOGYPwwKqbAcVX8bW4k5V')
|
|
||||||
Segmentation fault
|
|
||||||
|
|
||||||
* r497: spytify fails on ``make''::
|
|
||||||
|
|
||||||
src/spytify.c: In function ‘__pyx_pf_7spytify_7Spytify___init__’:
|
|
||||||
src/spytify.c:7325: error: too few arguments to function ‘despotify_init_client’
|
|
||||||
132
docs/development.rst
Normal file
132
docs/development.rst
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
***********
|
||||||
|
Development
|
||||||
|
***********
|
||||||
|
|
||||||
|
Development of Mopidy is coordinated through the IRC channel ``#mopidy`` at
|
||||||
|
``irc.freenode.net`` and through `GitHub <http://github.com/>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Scope
|
||||||
|
=====
|
||||||
|
|
||||||
|
To limit scope, we will start by implementing an MPD server which only
|
||||||
|
supports Spotify, and not playback of files from disk. We will make Mopidy
|
||||||
|
modular, so we can extend it with other backends in the future, like file
|
||||||
|
playback and other online music services such as Last.fm.
|
||||||
|
|
||||||
|
|
||||||
|
Running tests
|
||||||
|
=============
|
||||||
|
|
||||||
|
To run tests, you need a couple of dependiencies. Some can be installed through Debian/Ubuntu package management::
|
||||||
|
|
||||||
|
sudo aptitude install python-coverage
|
||||||
|
|
||||||
|
The rest can be installed using pip::
|
||||||
|
|
||||||
|
sudo aptitude install python-pip python-setuptools bzr
|
||||||
|
pip install -r test-requirements.txt
|
||||||
|
|
||||||
|
Then, to run all tests::
|
||||||
|
|
||||||
|
python tests
|
||||||
|
|
||||||
|
|
||||||
|
Music Player Daemon (MPD)
|
||||||
|
=========================
|
||||||
|
|
||||||
|
The `MPD protocol documentation <http://www.musicpd.org/doc/protocol/>`_ is a
|
||||||
|
useful resource. It is rather incomplete with regards to data formats, both for
|
||||||
|
requests and responses. Thus we have to talk a great deal with the the original
|
||||||
|
`MPD server <http://mpd.wikia.com/>`_ using telnet to get the details we need
|
||||||
|
to implement our own MPD server which is compatible with the numerous existing
|
||||||
|
`MPD clients <http://mpd.wikia.com/wiki/Clients>`_.
|
||||||
|
|
||||||
|
|
||||||
|
spytify
|
||||||
|
=======
|
||||||
|
|
||||||
|
`spytify <http://despotify.svn.sourceforge.net/viewvc/despotify/src/bindings/python/>`_
|
||||||
|
is the Python bindings for the open source `despotify <http://despotify.se/>`_
|
||||||
|
library. It got no documentation to speak of, but a couple of examples are
|
||||||
|
available.
|
||||||
|
|
||||||
|
Issues
|
||||||
|
------
|
||||||
|
|
||||||
|
A list of the issues we currently experience with spytify, both bugs and
|
||||||
|
features we wished was there.
|
||||||
|
|
||||||
|
* r483: Track lookup support. Possibly fixed in r497. To reproduce::
|
||||||
|
|
||||||
|
>>> import spytify
|
||||||
|
>>> s = spytify.Spytify('alice', 'secret')
|
||||||
|
>>> s.lookup('spotify:track:1mr3616BzLdhXfJmLmRsO8')
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
SpytifyError Traceback (most recent call last)
|
||||||
|
|
||||||
|
/home/jodal/<ipython console> in <module>()
|
||||||
|
|
||||||
|
/usr/local/lib/python2.6/dist-packages/spytify.so in spytify.Spytify.lookup (src/spytify.c:7914)()
|
||||||
|
|
||||||
|
SpytifyError: URI specifies invalid type: track
|
||||||
|
|
||||||
|
* r483: Error when accessing an album through an artist. To reproduce::
|
||||||
|
|
||||||
|
>>> import spytify
|
||||||
|
>>> s = spytify.Spytify('alice', 'secret')
|
||||||
|
>>> result = s.search('Gorillaz')
|
||||||
|
>>> artist = result.playlist.tracks[0].artists[0]
|
||||||
|
>>> artist
|
||||||
|
<Artist: Gorillaz (75f4ed7ec8514e91abaab17306ebbbb6)>
|
||||||
|
>>> artist.albums
|
||||||
|
ERROR: An unexpected error occurred while tokenizing input
|
||||||
|
The following traceback may be corrupted or invalid
|
||||||
|
The error message is: ('EOF in multi-line statement', (1423, 0))
|
||||||
|
|
||||||
|
ERROR: An unexpected error occurred while tokenizing input
|
||||||
|
The following traceback may be corrupted or invalid
|
||||||
|
The error message is: ('EOF in multi-line statement', (1455, 0))
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
TypeError Traceback (most recent call last)
|
||||||
|
|
||||||
|
/home/jodal/<ipython console> in <module>()
|
||||||
|
|
||||||
|
/usr/local/lib/python2.6/dist-packages/spytify.so in spytify.Artist.albums.__get__ (src/spytify.c:4867)()
|
||||||
|
|
||||||
|
/usr/local/lib/python2.6/dist-packages/spytify.so in spytify.Artist.get_full_data (src/spytify.c:4539)()
|
||||||
|
|
||||||
|
TypeError: Cannot convert spytify.AlbumDataFull to spytify.ArtistDataFull
|
||||||
|
|
||||||
|
* r483: Sometimes segfaults when traversing stored playlists, their tracks,
|
||||||
|
artists, and albums. As it is not predictable, it may be a concurrency issue.
|
||||||
|
|
||||||
|
* r483: Segfaults when looking up playlists, both your own lists and other
|
||||||
|
peoples shared lists. To reproduce::
|
||||||
|
|
||||||
|
>>> import spytify
|
||||||
|
>>> s = spytify.Spytify('alice', 'secret')
|
||||||
|
>>> s.lookup('spotify:user:klette:playlist:5rOGYPwwKqbAcVX8bW4k5V')
|
||||||
|
Segmentation fault
|
||||||
|
|
||||||
|
* r497: spytify fails on ``make`` because the despotify API has changed::
|
||||||
|
|
||||||
|
src/spytify.c: In function ‘__pyx_pf_7spytify_7Spytify___init__’:
|
||||||
|
src/spytify.c:7325: error: too few arguments to function ‘despotify_init_client’
|
||||||
|
|
||||||
|
|
||||||
|
pyspotify
|
||||||
|
=========
|
||||||
|
|
||||||
|
`pyspotify <http://github.com/winjer/pyspotify/>`_ is the Python bindings for
|
||||||
|
the official Spotify library, libspotify. It got no documentation to speak of,
|
||||||
|
but multiple examples are available.
|
||||||
|
|
||||||
|
Issues
|
||||||
|
------
|
||||||
|
|
||||||
|
A list of the issues we currently experience with pyspotify, both bugs and
|
||||||
|
features we wished was there.
|
||||||
|
|
||||||
|
* None at the moment.
|
||||||
18
docs/index.rst
Normal file
18
docs/index.rst
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
.. include:: ../README.rst
|
||||||
|
|
||||||
|
Contents
|
||||||
|
========
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 3
|
||||||
|
|
||||||
|
changes
|
||||||
|
installation
|
||||||
|
development
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
||||||
135
docs/installation.rst
Normal file
135
docs/installation.rst
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
************
|
||||||
|
Installation
|
||||||
|
************
|
||||||
|
|
||||||
|
Mopidy itself is a breeze to install, as it just requires a standard Python
|
||||||
|
installation. The libraries we depend on to connect to the Spotify service is
|
||||||
|
far more tricky to get working for the time being. Until installation of these
|
||||||
|
libraries are either well documented by their developers, or the libraries are
|
||||||
|
packaged for various Linux distributions, we will supply our own installation
|
||||||
|
guides here.
|
||||||
|
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
============
|
||||||
|
|
||||||
|
* Python >= 2.5
|
||||||
|
* Dependencies for at least one Mopidy backend:
|
||||||
|
|
||||||
|
* :ref:`despotify`
|
||||||
|
* :ref:`libspotify`
|
||||||
|
|
||||||
|
|
||||||
|
.. _despotify:
|
||||||
|
|
||||||
|
despotify backend
|
||||||
|
=================
|
||||||
|
|
||||||
|
To use the despotify backend, you first need to install despotify and spytify.
|
||||||
|
|
||||||
|
*This backend requires a Spotify premium account.*
|
||||||
|
|
||||||
|
|
||||||
|
Installing despotify and spytify
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Install despotify's dependencies. At Debian/Ubuntu systems::
|
||||||
|
|
||||||
|
sudo aptitude install libssl-dev zlib1g-dev libvorbis-dev \
|
||||||
|
libtool libncursesw5-dev libao-dev
|
||||||
|
|
||||||
|
Check out revision 483 of the despotify source code::
|
||||||
|
|
||||||
|
svn co https://despotify.svn.sourceforge.net/svnroot/despotify@483 despotify
|
||||||
|
|
||||||
|
Build and install despotify::
|
||||||
|
|
||||||
|
cd despotify/src/
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
|
||||||
|
Build and install spytify::
|
||||||
|
|
||||||
|
cd despotify/src/bindings/python/
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
|
||||||
|
To validate that everything is working, run the ``test.py`` script which is
|
||||||
|
distributed with spytify::
|
||||||
|
|
||||||
|
python test.py
|
||||||
|
|
||||||
|
The test script should ask for your username and password (which must be for a
|
||||||
|
Spotify Premium account), ask for a search query, list all your playlists with
|
||||||
|
tracks, play 10s from a random song from the search result, pause for two
|
||||||
|
seconds, play for five more seconds, and quit.
|
||||||
|
|
||||||
|
.. _libspotify:
|
||||||
|
|
||||||
|
libspotify backend
|
||||||
|
==================
|
||||||
|
|
||||||
|
As an alternative to the despotify backend, we are working on a libspotify
|
||||||
|
backend. To use the libspotify backend you must install libspotify and
|
||||||
|
pyspotify.
|
||||||
|
|
||||||
|
*This backend requires a Spotify premium account.*
|
||||||
|
|
||||||
|
*This backend requires you to get an application key from Spotify before use.*
|
||||||
|
|
||||||
|
|
||||||
|
Installing libspotify and pyspotify
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
As libspotify's installation script at the moment is somewhat broken (see this
|
||||||
|
`GetSatisfaction thread <http://getsatisfaction.com/spotify/topics/libspotify_please_fix_the_installation_script>`_
|
||||||
|
for details), it is easiest to use the libspotify files bundled with pyspotify.
|
||||||
|
The files bundled with pyspotify are for 64-bit, so if you run a 32-bit OS, you
|
||||||
|
must get libspotify from https://developer.spotify.com/en/libspotify/.
|
||||||
|
|
||||||
|
Install pyspotify's dependencies. At Debian/Ubuntu systems::
|
||||||
|
|
||||||
|
sudo aptitude install python-alsaaudio
|
||||||
|
|
||||||
|
Check out the pyspotify code, and install it::
|
||||||
|
|
||||||
|
git clone git://github.com/winjer/pyspotify.git
|
||||||
|
cd pyspotify
|
||||||
|
export LD_LIBRARY_PATH=$PWD/lib
|
||||||
|
sudo python setup.py develop
|
||||||
|
|
||||||
|
Apply for an application key at
|
||||||
|
https://developer.spotify.com/en/libspotify/application-key, download the
|
||||||
|
binary version, and place the file at ``pyspotify/spotify_appkey.key``.
|
||||||
|
|
||||||
|
Test your libspotify setup::
|
||||||
|
|
||||||
|
./example1.py -u USERNAME -p PASSWORD
|
||||||
|
|
||||||
|
Until Spotify fixes their installation script, you'll have to set
|
||||||
|
``LD_LIBRARY_PATH`` every time you are going to use libspotify (in other words
|
||||||
|
before starting Mopidy).
|
||||||
|
|
||||||
|
|
||||||
|
Running Mopidy
|
||||||
|
==============
|
||||||
|
|
||||||
|
Create a file name ``local_settings.py`` in the same directory as
|
||||||
|
``settings.py``. Enter your Spotify Premium account's username and password
|
||||||
|
into the file, like this::
|
||||||
|
|
||||||
|
SPOTIFY_USERNAME = u'myusername'
|
||||||
|
SPOTIFY_PASSWORD = u'mysecret'
|
||||||
|
|
||||||
|
Currently the despotify backend is the default. If you want to use the
|
||||||
|
libspotify backend, copy the Spotify application key to
|
||||||
|
``mopidy/spotify_appkey.key``, and add the following to
|
||||||
|
``mopidy/mopidy/local_settings.py``::
|
||||||
|
|
||||||
|
BACKEND=u'mopidy.backends.libspotify.LibspotifyBackend'
|
||||||
|
|
||||||
|
To start Mopidy, go to the root of the Mopidy project, then simply run::
|
||||||
|
|
||||||
|
python mopidy
|
||||||
|
|
||||||
|
To stop Mopidy, press ``CTRL+C``.
|
||||||
@ -1,4 +0,0 @@
|
|||||||
Pyspotify issues
|
|
||||||
----------------
|
|
||||||
|
|
||||||
* None at the moment.
|
|
||||||
Loading…
Reference in New Issue
Block a user