Merge branch 'master' of git://github.com/jodal/mopidy
This commit is contained in:
commit
7cb3e8e7da
@ -4,7 +4,7 @@ Mopidy
|
|||||||
|
|
||||||
Mopidy is an `MPD <http://mpd.wikia.com/>`_ server with a
|
Mopidy is an `MPD <http://mpd.wikia.com/>`_ server with a
|
||||||
`Spotify <http://www.spotify.com/>`_ backend. Using a standard MPD client you
|
`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
|
can search for music in Spotify's vast archive, manage Spotify play lists and
|
||||||
play music from Spotify.
|
play music from Spotify.
|
||||||
|
|
||||||
Mopidy is currently under development. Unless you want to contribute to the
|
Mopidy is currently under development. Unless you want to contribute to the
|
||||||
|
|||||||
0
docs/_static/.placeholder
vendored
Normal file
0
docs/_static/.placeholder
vendored
Normal file
115
docs/_themes/nature/static/nature.css_t
vendored
115
docs/_themes/nature/static/nature.css_t
vendored
@ -10,8 +10,8 @@
|
|||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
background-color: #111;
|
background-color: #111111;
|
||||||
color: #555;
|
color: #555555;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@ div.documentwrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.bodywrapper {
|
div.bodywrapper {
|
||||||
margin: 0 0 0 230px;
|
margin: 0 0 0 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr{
|
hr{
|
||||||
@ -30,14 +30,14 @@ hr{
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.document {
|
div.document {
|
||||||
background-color: #eee;
|
background-color: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.body {
|
div.body {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
color: #3E4349;
|
color: #3E4349;
|
||||||
padding: 0 30px 30px 30px;
|
padding: 1em 30px 30px 30px;
|
||||||
font-size: 0.8em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.footer {
|
div.footer {
|
||||||
@ -49,25 +49,29 @@ div.footer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.footer a {
|
div.footer a {
|
||||||
color: #444;
|
color: #444444;
|
||||||
text-decoration: underline;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div.related {
|
div.related {
|
||||||
background-color: #6BA81E;
|
background-color: #6BA81E;
|
||||||
line-height: 32px;
|
line-height: 36px;
|
||||||
color: #fff;
|
color: #ffffff;
|
||||||
text-shadow: 0px 1px 0 #444;
|
text-shadow: 0px 1px 0 #444444;
|
||||||
font-size: 0.80em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.related a {
|
div.related a {
|
||||||
color: #E2F3CC;
|
color: #E2F3CC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.related .right {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
div.sphinxsidebar {
|
div.sphinxsidebar {
|
||||||
font-size: 0.75em;
|
font-size: 0.9em;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
|
width: 300px
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebarwrapper{
|
div.sphinxsidebarwrapper{
|
||||||
@ -77,46 +81,46 @@ div.sphinxsidebarwrapper{
|
|||||||
div.sphinxsidebar h3,
|
div.sphinxsidebar h3,
|
||||||
div.sphinxsidebar h4 {
|
div.sphinxsidebar h4 {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
color: #222;
|
color: #222222;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
font-weight: normal;
|
font-weight: bold;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
background-color: #ddd;
|
|
||||||
text-shadow: 1px 1px 0 white
|
text-shadow: 1px 1px 0 white
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar h4{
|
|
||||||
font-size: 1.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar h3 a {
|
div.sphinxsidebar h3 a {
|
||||||
color: #444;
|
color: #444444;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
div.sphinxsidebar p {
|
div.sphinxsidebar p {
|
||||||
color: #888;
|
color: #888888;
|
||||||
padding: 5px 20px;
|
padding: 5px 20px;
|
||||||
|
margin: 0.5em 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar p.topless {
|
div.sphinxsidebar p.topless {
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar ul {
|
div.sphinxsidebar ul {
|
||||||
margin: 10px 20px;
|
margin: 10px 10px 10px 20px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: #000;
|
color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar a {
|
div.sphinxsidebar a {
|
||||||
color: #444;
|
color: #444444;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar a:hover {
|
||||||
|
color: #E32E00;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar input {
|
div.sphinxsidebar input {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #cccccc;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 1em;
|
font-size: 1.1em;
|
||||||
|
padding: 0.15em 0.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar input[type=text]{
|
div.sphinxsidebar input[type=text]{
|
||||||
@ -132,7 +136,6 @@ a {
|
|||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
color: #E32E00;
|
color: #E32E00;
|
||||||
text-decoration: underline;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div.body h1,
|
div.body h1,
|
||||||
@ -142,20 +145,20 @@ div.body h4,
|
|||||||
div.body h5,
|
div.body h5,
|
||||||
div.body h6 {
|
div.body h6 {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
background-color: #BED4EB;
|
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #212224;
|
color: #212224;
|
||||||
margin: 30px 0px 10px 0px;
|
margin: 30px 0px 10px 0px;
|
||||||
padding: 5px 0 5px 10px;
|
padding: 5px 0 5px 0px;
|
||||||
text-shadow: 0px 1px 0 white
|
text-shadow: 0px 1px 0 white;
|
||||||
|
border-bottom: 1px solid #C8D5E3;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
|
div.body h1 { margin-top: 0; font-size: 200%; }
|
||||||
div.body h2 { font-size: 150%; background-color: #C8D5E3; }
|
div.body h2 { font-size: 150%; }
|
||||||
div.body h3 { font-size: 120%; background-color: #D8DEE3; }
|
div.body h3 { font-size: 120%; }
|
||||||
div.body h4 { font-size: 110%; background-color: #D8DEE3; }
|
div.body h4 { font-size: 110%; }
|
||||||
div.body h5 { font-size: 100%; background-color: #D8DEE3; }
|
div.body h5 { font-size: 100%; }
|
||||||
div.body h6 { font-size: 100%; background-color: #D8DEE3; }
|
div.body h6 { font-size: 100%; }
|
||||||
|
|
||||||
a.headerlink {
|
a.headerlink {
|
||||||
color: #c60f0f;
|
color: #c60f0f;
|
||||||
@ -170,7 +173,7 @@ a.headerlink:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.body p, div.body dd, div.body li {
|
div.body p, div.body dd, div.body li {
|
||||||
line-height: 1.5em;
|
line-height: 1.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.admonition p.admonition-title + p {
|
div.admonition p.admonition-title + p {
|
||||||
@ -182,22 +185,23 @@ div.highlight{
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.note {
|
div.note {
|
||||||
background-color: #eee;
|
background-color: #eeeeee;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #cccccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.seealso {
|
div.seealso {
|
||||||
background-color: #ffc;
|
background-color: #ffffcc;
|
||||||
border: 1px solid #ff6;
|
border: 1px solid #ffff66;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.topic {
|
div.topic {
|
||||||
background-color: #eee;
|
background-color: #fafafa;
|
||||||
|
border-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.warning {
|
div.warning {
|
||||||
background-color: #ffe4e4;
|
background-color: #ffe4e4;
|
||||||
border: 1px solid #f66;
|
border: 1px solid #ff6666;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.admonition-title {
|
p.admonition-title {
|
||||||
@ -210,20 +214,23 @@ p.admonition-title:after {
|
|||||||
|
|
||||||
pre {
|
pre {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: White;
|
background-color: #fafafa;
|
||||||
color: #222;
|
color: #222222;
|
||||||
line-height: 1.2em;
|
line-height: 1.5em;
|
||||||
border: 1px solid #C6C9CB;
|
font-size: 1.1em;
|
||||||
font-size: 1.2em;
|
|
||||||
margin: 1.5em 0 1.5em 0;
|
margin: 1.5em 0 1.5em 0;
|
||||||
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
|
-webkit-box-shadow: 0px 0px 4px #d8d8d8;
|
||||||
-moz-box-shadow: 1px 1px 1px #d8d8d8;
|
-moz-box-shadow: 0px 0px 4px #d8d8d8;
|
||||||
|
box-shadow: 0px 0px 4px #d8d8d8;
|
||||||
}
|
}
|
||||||
|
|
||||||
tt {
|
tt {
|
||||||
background-color: #ecf0f3;
|
color: #222222;
|
||||||
color: #222;
|
|
||||||
padding: 1px 2px;
|
padding: 1px 2px;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#table-of-contents ul {
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|||||||
298
docs/api/backends.rst
Normal file
298
docs/api/backends.rst
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
*************************************
|
||||||
|
:mod:`mopidy.backends` -- Backend API
|
||||||
|
*************************************
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
This is our *planned* backend API, and not the current API.
|
||||||
|
|
||||||
|
.. module:: mopidy.backends
|
||||||
|
:synopsis: Interface between Mopidy and its various backends.
|
||||||
|
|
||||||
|
.. class:: BaseBackend()
|
||||||
|
|
||||||
|
.. attribute:: current_playlist
|
||||||
|
|
||||||
|
The current playlist controller. An instance of
|
||||||
|
:class:`BaseCurrentPlaylistController`.
|
||||||
|
|
||||||
|
.. attribute:: library
|
||||||
|
|
||||||
|
The library controller. An instance of :class:`BaseLibraryController`.
|
||||||
|
|
||||||
|
.. attribute:: playback
|
||||||
|
|
||||||
|
The playback controller. An instance of :class:`BasePlaybackController`.
|
||||||
|
|
||||||
|
.. attribute:: stored_playlists
|
||||||
|
|
||||||
|
The stored playlists controller. An instance of
|
||||||
|
:class:`BaseStoredPlaylistsController`.
|
||||||
|
|
||||||
|
.. attribute:: uri_handlers
|
||||||
|
|
||||||
|
List of URI prefixes this backend can handle.
|
||||||
|
|
||||||
|
|
||||||
|
.. class:: BaseCurrentPlaylistController(backend)
|
||||||
|
|
||||||
|
:param backend: backend the controller is a part of
|
||||||
|
:type backend: :class:`BaseBackend`
|
||||||
|
|
||||||
|
.. method:: add(track, at_position=None)
|
||||||
|
|
||||||
|
Add the track to the end of, or at the given position in the current
|
||||||
|
playlist.
|
||||||
|
|
||||||
|
:param track: track to add
|
||||||
|
:type track: :class:`mopidy.models.Track`
|
||||||
|
:param at_position: position in current playlist to add track
|
||||||
|
:type at_position: int or :class:`None`
|
||||||
|
|
||||||
|
.. method:: clear()
|
||||||
|
|
||||||
|
Clear the current playlist.
|
||||||
|
|
||||||
|
.. method:: load(playlist)
|
||||||
|
|
||||||
|
Replace the current playlist with the given playlist.
|
||||||
|
|
||||||
|
:param playlist: playlist to load
|
||||||
|
:type playlist: :class:`mopidy.models.Playlist`
|
||||||
|
|
||||||
|
.. method:: move(start, end, to_position)
|
||||||
|
|
||||||
|
Move the tracks at positions in [``start``, ``end``] to
|
||||||
|
``to_position``.
|
||||||
|
|
||||||
|
:param start: position of first track to move
|
||||||
|
:type start: int
|
||||||
|
:param end: position of last track to move
|
||||||
|
:type end: int
|
||||||
|
:param to_position: new position for the tracks
|
||||||
|
:type to_position: int
|
||||||
|
|
||||||
|
.. attribute:: playlist
|
||||||
|
|
||||||
|
The currently loaded :class:`mopidy.models.Playlist`.
|
||||||
|
|
||||||
|
.. method:: remove(position)
|
||||||
|
|
||||||
|
Remove the track at ``position`` from the current playlist.
|
||||||
|
|
||||||
|
:param position: position of track to remove
|
||||||
|
:type position: int
|
||||||
|
|
||||||
|
.. method:: shuffle(start=None, end=None)
|
||||||
|
|
||||||
|
Shuffles the playlist, optionally a part of the playlist given by
|
||||||
|
``start`` and ``end``.
|
||||||
|
|
||||||
|
:param start: position of first track to shuffle
|
||||||
|
:type start: int or :class:`None`
|
||||||
|
:param end: position of last track to shuffle
|
||||||
|
:type end: int or :class:`None`
|
||||||
|
|
||||||
|
.. attribute:: version
|
||||||
|
|
||||||
|
The current playlist version. Integer which is increased every time the
|
||||||
|
current playlist is changed.
|
||||||
|
|
||||||
|
|
||||||
|
.. class:: BasePlaybackController(backend)
|
||||||
|
|
||||||
|
:param backend: backend the controller is a part of
|
||||||
|
:type backend: :class:`BaseBackend`
|
||||||
|
|
||||||
|
.. attribute:: consume
|
||||||
|
|
||||||
|
:class:`True`
|
||||||
|
Tracks are removed from the playlist when they have been played.
|
||||||
|
:class:`False`
|
||||||
|
Tracks are not removed from the playlist.
|
||||||
|
|
||||||
|
.. attribute:: current_track
|
||||||
|
|
||||||
|
The currently playing or selected :class:`mopidy.models.Track`.
|
||||||
|
|
||||||
|
.. method:: next()
|
||||||
|
|
||||||
|
Play the next track.
|
||||||
|
|
||||||
|
.. method:: pause()
|
||||||
|
|
||||||
|
Pause playblack.
|
||||||
|
|
||||||
|
.. attribute:: PAUSED
|
||||||
|
|
||||||
|
Constant representing the paused state.
|
||||||
|
|
||||||
|
.. method:: play(id=None, position=None)
|
||||||
|
|
||||||
|
Play either the track with the given ID, the given position, or the
|
||||||
|
currently active track.
|
||||||
|
|
||||||
|
:param id: ID of track to play
|
||||||
|
:type id: int
|
||||||
|
:param position: position in current playlist of track to play
|
||||||
|
:type position: int
|
||||||
|
|
||||||
|
.. attribute:: PLAYING
|
||||||
|
|
||||||
|
Constant representing the playing state.
|
||||||
|
|
||||||
|
.. attribute:: playlist_position
|
||||||
|
|
||||||
|
The position in the current playlist.
|
||||||
|
|
||||||
|
.. method:: previous()
|
||||||
|
|
||||||
|
Play the previous track.
|
||||||
|
|
||||||
|
.. attribute:: random
|
||||||
|
|
||||||
|
:class:`True`
|
||||||
|
Tracks are selected at random from the playlist.
|
||||||
|
:class:`False`
|
||||||
|
Tracks are played in the order of the playlist.
|
||||||
|
|
||||||
|
.. attribute:: repeat
|
||||||
|
|
||||||
|
:class:`True`
|
||||||
|
The current track is played repeatedly.
|
||||||
|
:class:`False`
|
||||||
|
The current track is played once.
|
||||||
|
|
||||||
|
.. method:: resume()
|
||||||
|
|
||||||
|
If paused, resume playing the current track.
|
||||||
|
|
||||||
|
.. method:: seek(time_position)
|
||||||
|
|
||||||
|
Seeks to time position given in milliseconds.
|
||||||
|
|
||||||
|
:param time_position: time position in milliseconds
|
||||||
|
:type time_position: int
|
||||||
|
|
||||||
|
.. attribute:: state
|
||||||
|
|
||||||
|
The playback state. Must be :attr:`PLAYING`, :attr:`PAUSED`, or
|
||||||
|
:attr:`STOPPED`.
|
||||||
|
|
||||||
|
.. method:: stop()
|
||||||
|
|
||||||
|
Stop playing.
|
||||||
|
|
||||||
|
.. attribute:: STOPPED
|
||||||
|
|
||||||
|
Constant representing the stopped state.
|
||||||
|
|
||||||
|
.. attribute:: time_position
|
||||||
|
|
||||||
|
Time position in milliseconds.
|
||||||
|
|
||||||
|
.. attribute:: volume
|
||||||
|
|
||||||
|
The audio volume as an int in the range [0, 100]. :class:`None` if
|
||||||
|
unknown.
|
||||||
|
|
||||||
|
|
||||||
|
.. class:: BaseLibraryController(backend)
|
||||||
|
|
||||||
|
:param backend: backend the controller is a part of
|
||||||
|
:type backend: :class:`BaseBackend`
|
||||||
|
|
||||||
|
.. method:: find_exact(type, query)
|
||||||
|
|
||||||
|
Find tracks in the library where ``type`` matches ``query`` exactly.
|
||||||
|
|
||||||
|
:param type: 'title', 'artist', or 'album'
|
||||||
|
:type type: string
|
||||||
|
:param query: the search query
|
||||||
|
:type query: string
|
||||||
|
:rtype: list of :class:`mopidy.models.Track`
|
||||||
|
|
||||||
|
.. method:: lookup(uri)
|
||||||
|
|
||||||
|
Lookup track with given URI.
|
||||||
|
|
||||||
|
:param uri: track URI
|
||||||
|
:type uri: string
|
||||||
|
:rtype: :class:`mopidy.models.Track`
|
||||||
|
|
||||||
|
.. method:: refresh(uri=None)
|
||||||
|
|
||||||
|
Refresh library. Limit to URI and below if an URI is given.
|
||||||
|
|
||||||
|
:param uri: directory or track URI
|
||||||
|
:type uri: string
|
||||||
|
|
||||||
|
.. method:: search(type, query)
|
||||||
|
|
||||||
|
Search the library for tracks where ``type`` contains ``query``.
|
||||||
|
|
||||||
|
:param type: 'title', 'artist', 'album', or 'uri'
|
||||||
|
:type type: string
|
||||||
|
:param query: the search query
|
||||||
|
:type query: string
|
||||||
|
:rtype: list of :class:`mopidy.models.Track`
|
||||||
|
|
||||||
|
|
||||||
|
.. class:: BaseStoredPlaylistsController(backend)
|
||||||
|
|
||||||
|
:param backend: backend the controller is a part of
|
||||||
|
:type backend: :class:`BaseBackend`
|
||||||
|
|
||||||
|
.. method:: add(uri)
|
||||||
|
|
||||||
|
Add existing playlist with the given URI.
|
||||||
|
|
||||||
|
:param uri: URI of existing playlist
|
||||||
|
:type uri: string
|
||||||
|
|
||||||
|
.. method:: create(name)
|
||||||
|
|
||||||
|
Create a new playlist.
|
||||||
|
|
||||||
|
:param name: name of the new playlist
|
||||||
|
:type name: string
|
||||||
|
:rtype: :class:`mopidy.models.Playlist`
|
||||||
|
|
||||||
|
.. attribute:: playlists
|
||||||
|
|
||||||
|
List of :class:`mopidy.models.Playlist`.
|
||||||
|
|
||||||
|
.. method:: delete(playlist)
|
||||||
|
|
||||||
|
Delete playlist.
|
||||||
|
|
||||||
|
:param playlist: the playlist to delete
|
||||||
|
:type playlist: :class:`mopidy.models.Playlist`
|
||||||
|
|
||||||
|
.. method:: lookup(uri)
|
||||||
|
|
||||||
|
Lookup playlist with given URI.
|
||||||
|
|
||||||
|
:param uri: playlist URI
|
||||||
|
:type uri: string
|
||||||
|
:rtype: :class:`mopidy.models.Playlist`
|
||||||
|
|
||||||
|
.. method:: refresh()
|
||||||
|
|
||||||
|
Refresh stored playlists.
|
||||||
|
|
||||||
|
.. method:: rename(playlist, new_name)
|
||||||
|
|
||||||
|
Rename playlist.
|
||||||
|
|
||||||
|
:param playlist: the playlist
|
||||||
|
:type playlist: :class:`mopidy.models.Playlist`
|
||||||
|
:param new_name: the new name
|
||||||
|
:type new_name: string
|
||||||
|
|
||||||
|
.. method:: search(query)
|
||||||
|
|
||||||
|
Search for playlists whose name contains ``query``.
|
||||||
|
|
||||||
|
:param query: query to search for
|
||||||
|
:type query: string
|
||||||
|
:rtype: list of :class:`mopidy.models.Playlist`
|
||||||
8
docs/api/models.rst
Normal file
8
docs/api/models.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
*********************************************
|
||||||
|
:mod:`mopidy.models` -- Immutable data models
|
||||||
|
*********************************************
|
||||||
|
|
||||||
|
.. automodule:: mopidy.models
|
||||||
|
:synopsis: Immutable data models.
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
@ -16,13 +16,13 @@ import sys, os
|
|||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# 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
|
# 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.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
#sys.path.append(os.path.abspath('.'))
|
sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/../'))
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = []
|
extensions = ['sphinx.ext.autodoc']
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
@ -147,7 +147,7 @@ html_static_path = ['_static']
|
|||||||
#html_split_index = False
|
#html_split_index = False
|
||||||
|
|
||||||
# If true, links to the reST sources are added to the pages.
|
# If true, links to the reST sources are added to the pages.
|
||||||
#html_show_sourcelink = True
|
html_show_sourcelink = False
|
||||||
|
|
||||||
# If true, an OpenSearch description file will be output, and all pages will
|
# 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
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
|
|||||||
@ -6,6 +6,15 @@ Development of Mopidy is coordinated through the IRC channel ``#mopidy`` at
|
|||||||
``irc.freenode.net`` and through `GitHub <http://github.com/>`_.
|
``irc.freenode.net`` and through `GitHub <http://github.com/>`_.
|
||||||
|
|
||||||
|
|
||||||
|
API documentation
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:glob:
|
||||||
|
|
||||||
|
api/*
|
||||||
|
|
||||||
|
|
||||||
Scope
|
Scope
|
||||||
=====
|
=====
|
||||||
|
|
||||||
|
|||||||
@ -14,5 +14,6 @@ Indices and tables
|
|||||||
==================
|
==================
|
||||||
|
|
||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
* :ref:`search`
|
* :ref:`search`
|
||||||
|
|
||||||
|
|||||||
@ -123,10 +123,6 @@ class BaseBackend(object):
|
|||||||
return self.state
|
return self.state
|
||||||
|
|
||||||
def status_time(self):
|
def status_time(self):
|
||||||
# XXX This is only called when a client is connected, and is thus not a
|
|
||||||
# complete solution
|
|
||||||
if self._play_time_elapsed >= self.status_time_total() > 0:
|
|
||||||
self.end_of_track()
|
|
||||||
return u'%s:%s' % (self._play_time_elapsed, self.status_time_total())
|
return u'%s:%s' % (self._play_time_elapsed, self.status_time_total())
|
||||||
|
|
||||||
def status_time_total(self):
|
def status_time_total(self):
|
||||||
@ -205,13 +201,13 @@ class BaseBackend(object):
|
|||||||
|
|
||||||
# Current/single playlist methods
|
# Current/single playlist methods
|
||||||
|
|
||||||
def playlist_changes_since(self, version):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def playlist_load(self, name):
|
def playlist_load(self, name):
|
||||||
|
self._current_song_pos = None
|
||||||
matches = filter(lambda p: p.name == name, self._playlists)
|
matches = filter(lambda p: p.name == name, self._playlists)
|
||||||
if matches:
|
if matches:
|
||||||
self._current_playlist = matches[0]
|
self._current_playlist = matches[0]
|
||||||
|
if self.state == self.PLAY:
|
||||||
|
self.play(songpos=0)
|
||||||
else:
|
else:
|
||||||
self._current_playlist = None
|
self._current_playlist = None
|
||||||
|
|
||||||
|
|||||||
@ -120,4 +120,5 @@ class DespotifyBackend(BaseBackend):
|
|||||||
def search(self, type, what):
|
def search(self, type, what):
|
||||||
query = u'%s:%s' % (type, what)
|
query = u'%s:%s' % (type, what)
|
||||||
result = self.spotify.search(query.encode(ENCODING))
|
result = self.spotify.search(query.encode(ENCODING))
|
||||||
return self._to_mopidy_playlist(result.playlist).mpd_format()
|
if result is not None:
|
||||||
|
return self._to_mopidy_playlist(result.playlist).mpd_format()
|
||||||
|
|||||||
@ -1,20 +1,40 @@
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
|
|
||||||
class Artist(object):
|
class Artist(object):
|
||||||
|
"""
|
||||||
|
:param uri: artist URI
|
||||||
|
:type uri: string
|
||||||
|
:param name: artist name
|
||||||
|
:type name: string
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, uri=None, name=None):
|
def __init__(self, uri=None, name=None):
|
||||||
self._uri = None
|
self._uri = None
|
||||||
self._name = name
|
self._name = name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def uri(self):
|
def uri(self):
|
||||||
|
"""The artist URI. Read-only."""
|
||||||
return self._uri
|
return self._uri
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
"""The artist name. Read-only."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
|
|
||||||
class Album(object):
|
class Album(object):
|
||||||
|
"""
|
||||||
|
:param uri: album URI
|
||||||
|
:type uri: string
|
||||||
|
:param name: album name
|
||||||
|
:type name: string
|
||||||
|
:param artists: album artists
|
||||||
|
:type artists: list of :class:`Artist`
|
||||||
|
:param num_tracks: number of tracks in album
|
||||||
|
:type num_tracks: integer
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, uri=None, name=None, artists=None, num_tracks=0):
|
def __init__(self, uri=None, name=None, artists=None, num_tracks=0):
|
||||||
self._uri = uri
|
self._uri = uri
|
||||||
self._name = name
|
self._name = name
|
||||||
@ -23,24 +43,49 @@ class Album(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def uri(self):
|
def uri(self):
|
||||||
|
"""The album URI. Read-only."""
|
||||||
return self._uri
|
return self._uri
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
"""The album name. Read-only."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def artists(self):
|
def artists(self):
|
||||||
|
"""List of :class:`Artist` elements. Read-only."""
|
||||||
return copy(self._artists)
|
return copy(self._artists)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def num_tracks(self):
|
def num_tracks(self):
|
||||||
|
"""The number of tracks in the album. Read-only."""
|
||||||
return self._num_tracks
|
return self._num_tracks
|
||||||
|
|
||||||
|
|
||||||
class Track(object):
|
class Track(object):
|
||||||
|
"""
|
||||||
|
:param uri: track URI
|
||||||
|
:type uri: string
|
||||||
|
:param title: track title
|
||||||
|
:type title: string
|
||||||
|
:param artists: track artists
|
||||||
|
:type artists: list of :class:`Artist`
|
||||||
|
:param album: track album
|
||||||
|
:type album: :class:`Album`
|
||||||
|
:param track_no: track number in album
|
||||||
|
:type track_no: integer
|
||||||
|
:param date: track release date
|
||||||
|
:type date: :class:`datetime.date`
|
||||||
|
:param length: track length in milliseconds
|
||||||
|
:type length: integer
|
||||||
|
:param bitrate: bitrate in kbit/s
|
||||||
|
:type bitrate: integer
|
||||||
|
:param id: track ID (unique and non-changing as long as the process lives)
|
||||||
|
:type id: integer
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, uri=None, title=None, artists=None, album=None,
|
def __init__(self, uri=None, title=None, artists=None, album=None,
|
||||||
track_no=0, date=None, length=None, id=None):
|
track_no=0, date=None, length=None, bitrate=None, id=None):
|
||||||
self._uri = uri
|
self._uri = uri
|
||||||
self._title = title
|
self._title = title
|
||||||
self._artists = artists or []
|
self._artists = artists or []
|
||||||
@ -48,41 +93,62 @@ class Track(object):
|
|||||||
self._track_no = track_no
|
self._track_no = track_no
|
||||||
self._date = date
|
self._date = date
|
||||||
self._length = length
|
self._length = length
|
||||||
|
self._bitrate = bitrate
|
||||||
self._id = id
|
self._id = id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def uri(self):
|
def uri(self):
|
||||||
|
"""The track URI. Read-only."""
|
||||||
return self._uri
|
return self._uri
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
|
"""The track title. Read-only."""
|
||||||
return self._title
|
return self._title
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def artists(self):
|
def artists(self):
|
||||||
|
"""List of :class:`Artist`. Read-only."""
|
||||||
return copy(self._artists)
|
return copy(self._artists)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def album(self):
|
def album(self):
|
||||||
|
"""The track :class:`Album`. Read-only."""
|
||||||
return self._album
|
return self._album
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def track_no(self):
|
def track_no(self):
|
||||||
|
"""The track number in album. Read-only."""
|
||||||
return self._track_no
|
return self._track_no
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def date(self):
|
def date(self):
|
||||||
|
"""The track release date. Read-only."""
|
||||||
return self._date
|
return self._date
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def length(self):
|
def length(self):
|
||||||
|
"""The track length in milliseconds. Read-only."""
|
||||||
return self._length
|
return self._length
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bitrate(self):
|
||||||
|
"""The track's bitrate in kbit/s. Read-only."""
|
||||||
|
return self._bitrate
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
|
"""The track ID. Read-only."""
|
||||||
return self._id
|
return self._id
|
||||||
|
|
||||||
def mpd_format(self, position=0):
|
def mpd_format(self, position=0):
|
||||||
|
"""
|
||||||
|
Format track for output to MPD client.
|
||||||
|
|
||||||
|
:param position: track's position in playlist
|
||||||
|
:type position: integer
|
||||||
|
:rtype: list of two-tuples
|
||||||
|
"""
|
||||||
return [
|
return [
|
||||||
('file', self.uri),
|
('file', self.uri),
|
||||||
('Time', self.length // 1000),
|
('Time', self.length // 1000),
|
||||||
@ -96,10 +162,24 @@ class Track(object):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def mpd_format_artists(self):
|
def mpd_format_artists(self):
|
||||||
|
"""
|
||||||
|
Format track artists for output to MPD client.
|
||||||
|
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
return u', '.join([a.name for a in self.artists])
|
return u', '.join([a.name for a in self.artists])
|
||||||
|
|
||||||
|
|
||||||
class Playlist(object):
|
class Playlist(object):
|
||||||
|
"""
|
||||||
|
:param uri: playlist URI
|
||||||
|
:type uri: string
|
||||||
|
:param name: playlist name
|
||||||
|
:type name: string
|
||||||
|
:param tracks: playlist's tracks
|
||||||
|
:type tracks: list of :class:`Track` elements
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, uri=None, name=None, tracks=None):
|
def __init__(self, uri=None, name=None, tracks=None):
|
||||||
self._uri = uri
|
self._uri = uri
|
||||||
self._name = name
|
self._name = name
|
||||||
@ -107,21 +187,30 @@ class Playlist(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def uri(self):
|
def uri(self):
|
||||||
|
"""The playlist URI. Read-only."""
|
||||||
return self._uri
|
return self._uri
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
"""The playlist name. Read-only."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tracks(self):
|
def tracks(self):
|
||||||
|
"""List of :class:`Track` elements. Read-only."""
|
||||||
return copy(self._tracks)
|
return copy(self._tracks)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def length(self):
|
def length(self):
|
||||||
|
"""The number of tracks in the playlist. Read-only."""
|
||||||
return len(self._tracks)
|
return len(self._tracks)
|
||||||
|
|
||||||
def mpd_format(self, start=0, end=None):
|
def mpd_format(self, start=0, end=None):
|
||||||
|
"""
|
||||||
|
Format playlist for output to MPD client.
|
||||||
|
|
||||||
|
:rtype: list of lists of two-tuples
|
||||||
|
"""
|
||||||
if end is None:
|
if end is None:
|
||||||
end = self.length
|
end = self.length
|
||||||
tracks = []
|
tracks = []
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user