All uris given to lookup should be in the result even if there is no
backend to handle the uri, and the lookup result thus is an empty list.
As a side effect, future.get() is now called in the order of the URIs
in the `uris` list, making it easier to mock out
backend.library.lookup() in core layer tests.
While trying to remove traces of stop calls in core to get gapless working I
found we had no way to switch to switch tracks without triggering a play. This
change fixes this by changing the backends playback provider API.
- play() now _only_ starts playback and does not take any arguments.
- prepare_change() has been added, this could have been avoided with a kwarg to
change_track(track), but that would break more backends.
- core has been updated to call prepare_change+change_track+play as needed.
- tests have been updated to handle this change.
Longer term I hope to completely rework the playback API in backends, as 99% of
our backends only use change_track(track) to translate URIs. So we should make
simple case simple, and handle mopidy-spotify / appsrc in some other way.
Cherry picked from the WIP gapless branch.
Instead of changing the signature to add(uri, name) I opted for
renaming it to _add_track(track).
Since it's internal we may change it whenever we like to. Since you need
different logic for extracting an interesting name from a track and from
a ref or a stream title, it makes sense to add another method for adding
refs/stream titles to the history when that time comes.
Fixes#1056
The default was insane. For one, because overriding e.g. just the
getter would make the property have a pair of working getter and
setter that are entirely disconnected.
For now this doesn't add any corresponding APIs to backends, or for that matter
tracklist.add(uris). This is just to get the API in for clients in 0.20.
This is done by checking for the presence of the organization tag typically set
by web streams. This might be a bit to strict and a bad heuristic, but it's
currently better than wrongly emitting stream titles for non streams IMO.
Seeks will now fail when the duration is None, this is an approximation to if
the track is seekable or not. This check is need as otherwise seeking a radio
stream will trigger the next track.
If the track truly isn't seekable despite having a duration we should still
fail as GStreamer will reject the seek.
The API I really want for this to support regular tracks, stream updates and
dynamic playlists is still unclear to me. As such I'm taking the KISS approach
and reducing this to just the stream title and nothing else.
If all goes as planed this will be replaced by playback_track_changed(tlid, ref)
style events and other improvements in a later version.
...and not False, because the mute state is unknown (None) and not
unmuted (False) when there is no mixer.
Note that this change does not affect the MPD responses.
Return type of scanner changed to a named tuple with (uri, tags, duration,
seekable). This should help with #872 and the related "live" issues.
Tests, local scan and stream metadata lookup have been updated to account for
the changes.
- Adds tests for new behaviors in core.
- Adds stream name to MPD format (fixes#944)
- Adds 'stream_changed' core event (needs a new name/event)
- Adds 'get_stream_reference' (which I'm also unsure about)
The bits I'm unsure about are mostly with respect to #270, but I'm going ahead
with this commit so we can discuss the details in PR with this code as an
example.
Adds some WebSocketHandler tests that actually connect using a WS client and
plugs a potential race condition.
Any call to write_message could fail, either due to WebSocketClosedError like
in the log below, or simply due to socket errors. To play it safe we catch all
errors and debug log that a broadcast failed.
2015-02-26 21:24:02,266 ERROR [HttpServer] /home/adamcik/dev/mopidy/mopidy/http/handlers.py:116
mopidy.http.handlers WebSocket request error: deque index out of range
2015-02-26 21:24:10,098 ERROR [HttpFrontend-11] build/bdist.linux-x86_64/egg/pykka/actor.py:268
pykka Unhandled exception in HttpFrontend (urn:uuid:e376bd95-c32e-4e17-ad20-7d0b3c0cf2b2):
Traceback (most recent call last):
File "build/bdist.linux-x86_64/egg/pykka/actor.py", line 200, in _actor_loop
response = self._handle_receive(message)
File "build/bdist.linux-x86_64/egg/pykka/actor.py", line 294, in _handle_receive
return callee(*message['args'], **message['kwargs'])
File ".../dev/mopidy/mopidy/http/actor.py", line 77, in on_event
on_event(name, **data)
File ".../dev/mopidy/mopidy/http/actor.py", line 84, in on_event
handlers.WebSocketHandler.broadcast(message)
File ".../dev/mopidy/mopidy/http/handlers.py", line 78, in broadcast
client.write_message(msg)
File ".../dev/mopidy-virtualenv/local/lib/python2.7/site-packages/tornado/websocket.py", line 183, in write_message
raise WebSocketClosedError()
WebSocketClosedError