Update playback controller to support backends without playback support
This commit is contained in:
parent
6f32d72792
commit
d748c07daf
@ -90,7 +90,7 @@ class PlaybackController(object):
|
||||
return None
|
||||
uri = self.current_cp_track.track.uri
|
||||
uri_scheme = urlparse.urlparse(uri).scheme
|
||||
return self.backends.by_uri_scheme[uri_scheme]
|
||||
return self.backends.with_playback_by_uri_scheme.get(uri_scheme, None)
|
||||
|
||||
def _get_cpid(self, cp_track):
|
||||
if cp_track is None:
|
||||
@ -298,9 +298,10 @@ class PlaybackController(object):
|
||||
def time_position(self):
|
||||
"""Time position in milliseconds."""
|
||||
backend = self._get_backend()
|
||||
if backend is None:
|
||||
if backend:
|
||||
return backend.playback.get_time_position().get()
|
||||
else:
|
||||
return 0
|
||||
return backend.playback.get_time_position().get()
|
||||
|
||||
@property
|
||||
def volume(self):
|
||||
@ -387,7 +388,7 @@ class PlaybackController(object):
|
||||
def pause(self):
|
||||
"""Pause playback."""
|
||||
backend = self._get_backend()
|
||||
if backend is None or backend.playback.pause().get():
|
||||
if not backend or backend.playback.pause().get():
|
||||
self.state = PlaybackState.PAUSED
|
||||
self._trigger_track_playback_paused()
|
||||
|
||||
@ -419,7 +420,8 @@ class PlaybackController(object):
|
||||
if cp_track is not None:
|
||||
self.current_cp_track = cp_track
|
||||
self.state = PlaybackState.PLAYING
|
||||
if not self._get_backend().playback.play(cp_track.track).get():
|
||||
backend = self._get_backend()
|
||||
if not backend or not backend.playback.play(cp_track.track).get():
|
||||
# Track is not playable
|
||||
if self.random and self._shuffled:
|
||||
self._shuffled.remove(cp_track)
|
||||
@ -445,8 +447,10 @@ class PlaybackController(object):
|
||||
|
||||
def resume(self):
|
||||
"""If paused, resume playing the current track."""
|
||||
if (self.state == PlaybackState.PAUSED and
|
||||
self._get_backend().playback.resume().get()):
|
||||
if self.state != PlaybackState.PAUSED:
|
||||
return
|
||||
backend = self._get_backend()
|
||||
if backend and backend.playback.resume().get():
|
||||
self.state = PlaybackState.PLAYING
|
||||
self._trigger_track_playback_resumed()
|
||||
|
||||
@ -472,7 +476,11 @@ class PlaybackController(object):
|
||||
self.next()
|
||||
return True
|
||||
|
||||
success = self._get_backend().playback.seek(time_position).get()
|
||||
backend = self._get_backend()
|
||||
if not backend:
|
||||
return False
|
||||
|
||||
success = backend.playback.seek(time_position).get()
|
||||
if success:
|
||||
self._trigger_seeked(time_position)
|
||||
return success
|
||||
@ -486,7 +494,8 @@ class PlaybackController(object):
|
||||
:type clear_current_track: boolean
|
||||
"""
|
||||
if self.state != PlaybackState.STOPPED:
|
||||
if self._get_backend().playback.stop().get():
|
||||
backend = self._get_backend()
|
||||
if not backend or backend.playback.stop().get():
|
||||
self._trigger_track_playback_ended()
|
||||
self.state = PlaybackState.STOPPED
|
||||
if clear_current_track:
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import mock
|
||||
|
||||
from mopidy.backends import base
|
||||
from mopidy.core import Core
|
||||
from mopidy.core import Core, PlaybackState
|
||||
from mopidy.models import Track
|
||||
|
||||
from tests import unittest
|
||||
@ -19,17 +19,24 @@ class CorePlaybackTest(unittest.TestCase):
|
||||
self.playback2 = mock.Mock(spec=base.BasePlaybackProvider)
|
||||
self.backend2.playback = self.playback2
|
||||
|
||||
# A backend without the optional playback provider
|
||||
self.backend3 = mock.Mock()
|
||||
self.backend3.uri_schemes.get.return_value = ['dummy3']
|
||||
self.backend3.has_playback().get.return_value = False
|
||||
|
||||
self.tracks = [
|
||||
Track(uri='dummy1://foo', length=40000),
|
||||
Track(uri='dummy1://bar', length=40000),
|
||||
Track(uri='dummy2://foo', length=40000),
|
||||
Track(uri='dummy2://bar', length=40000),
|
||||
Track(uri='dummy1:a', length=40000),
|
||||
Track(uri='dummy2:a', length=40000),
|
||||
Track(uri='dummy3:a', length=40000), # Unplayable
|
||||
Track(uri='dummy1:b', length=40000),
|
||||
]
|
||||
|
||||
self.core = Core(audio=None, backends=[self.backend1, self.backend2])
|
||||
self.core = Core(audio=None, backends=[
|
||||
self.backend1, self.backend2, self.backend3])
|
||||
self.core.current_playlist.append(self.tracks)
|
||||
|
||||
self.cp_tracks = self.core.current_playlist.cp_tracks
|
||||
self.unplayable_cp_track = self.cp_tracks[2]
|
||||
|
||||
def test_play_selects_dummy1_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[0])
|
||||
@ -38,10 +45,19 @@ class CorePlaybackTest(unittest.TestCase):
|
||||
self.assertFalse(self.playback2.play.called)
|
||||
|
||||
def test_play_selects_dummy2_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[2])
|
||||
self.core.playback.play(self.cp_tracks[1])
|
||||
|
||||
self.assertFalse(self.playback1.play.called)
|
||||
self.playback2.play.assert_called_once_with(self.tracks[2])
|
||||
self.playback2.play.assert_called_once_with(self.tracks[1])
|
||||
|
||||
def test_play_skips_to_next_on_unplayable_track(self):
|
||||
self.core.playback.play(self.unplayable_cp_track)
|
||||
|
||||
self.playback1.play.assert_called_once_with(self.tracks[3])
|
||||
self.assertFalse(self.playback2.play.called)
|
||||
|
||||
self.assertEqual(self.core.playback.current_cp_track,
|
||||
self.cp_tracks[3])
|
||||
|
||||
def test_pause_selects_dummy1_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[0])
|
||||
@ -51,12 +67,20 @@ class CorePlaybackTest(unittest.TestCase):
|
||||
self.assertFalse(self.playback2.pause.called)
|
||||
|
||||
def test_pause_selects_dummy2_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[2])
|
||||
self.core.playback.play(self.cp_tracks[1])
|
||||
self.core.playback.pause()
|
||||
|
||||
self.assertFalse(self.playback1.pause.called)
|
||||
self.playback2.pause.assert_called_once_with()
|
||||
|
||||
def test_pause_changes_state_even_if_track_is_unplayable(self):
|
||||
self.core.playback.current_cp_track = self.unplayable_cp_track
|
||||
self.core.playback.pause()
|
||||
|
||||
self.assertEqual(self.core.playback.state, PlaybackState.PAUSED)
|
||||
self.assertFalse(self.playback1.pause.called)
|
||||
self.assertFalse(self.playback2.pause.called)
|
||||
|
||||
def test_resume_selects_dummy1_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[0])
|
||||
self.core.playback.pause()
|
||||
@ -66,13 +90,22 @@ class CorePlaybackTest(unittest.TestCase):
|
||||
self.assertFalse(self.playback2.resume.called)
|
||||
|
||||
def test_resume_selects_dummy2_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[2])
|
||||
self.core.playback.play(self.cp_tracks[1])
|
||||
self.core.playback.pause()
|
||||
self.core.playback.resume()
|
||||
|
||||
self.assertFalse(self.playback1.resume.called)
|
||||
self.playback2.resume.assert_called_once_with()
|
||||
|
||||
def test_resume_does_nothing_if_track_is_unplayable(self):
|
||||
self.core.playback.current_cp_track = self.unplayable_cp_track
|
||||
self.core.playback.state = PlaybackState.PAUSED
|
||||
self.core.playback.resume()
|
||||
|
||||
self.assertEqual(self.core.playback.state, PlaybackState.PAUSED)
|
||||
self.assertFalse(self.playback1.resume.called)
|
||||
self.assertFalse(self.playback2.resume.called)
|
||||
|
||||
def test_stop_selects_dummy1_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[0])
|
||||
self.core.playback.stop()
|
||||
@ -81,12 +114,21 @@ class CorePlaybackTest(unittest.TestCase):
|
||||
self.assertFalse(self.playback2.stop.called)
|
||||
|
||||
def test_stop_selects_dummy2_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[2])
|
||||
self.core.playback.play(self.cp_tracks[1])
|
||||
self.core.playback.stop()
|
||||
|
||||
self.assertFalse(self.playback1.stop.called)
|
||||
self.playback2.stop.assert_called_once_with()
|
||||
|
||||
def test_stop_changes_state_even_if_track_is_unplayable(self):
|
||||
self.core.playback.current_cp_track = self.unplayable_cp_track
|
||||
self.core.playback.state = PlaybackState.PAUSED
|
||||
self.core.playback.stop()
|
||||
|
||||
self.assertEqual(self.core.playback.state, PlaybackState.STOPPED)
|
||||
self.assertFalse(self.playback1.stop.called)
|
||||
self.assertFalse(self.playback2.stop.called)
|
||||
|
||||
def test_seek_selects_dummy1_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[0])
|
||||
self.core.playback.seek(10000)
|
||||
@ -95,12 +137,21 @@ class CorePlaybackTest(unittest.TestCase):
|
||||
self.assertFalse(self.playback2.seek.called)
|
||||
|
||||
def test_seek_selects_dummy2_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[2])
|
||||
self.core.playback.play(self.cp_tracks[1])
|
||||
self.core.playback.seek(10000)
|
||||
|
||||
self.assertFalse(self.playback1.seek.called)
|
||||
self.playback2.seek.assert_called_once_with(10000)
|
||||
|
||||
def test_seek_fails_for_unplayable_track(self):
|
||||
self.core.playback.current_cp_track = self.unplayable_cp_track
|
||||
self.core.playback.state = PlaybackState.PLAYING
|
||||
success = self.core.playback.seek(1000)
|
||||
|
||||
self.assertFalse(success)
|
||||
self.assertFalse(self.playback1.seek.called)
|
||||
self.assertFalse(self.playback2.seek.called)
|
||||
|
||||
def test_time_position_selects_dummy1_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[0])
|
||||
self.core.playback.seek(10000)
|
||||
@ -110,9 +161,18 @@ class CorePlaybackTest(unittest.TestCase):
|
||||
self.assertFalse(self.playback2.get_time_position.called)
|
||||
|
||||
def test_time_position_selects_dummy2_backend(self):
|
||||
self.core.playback.play(self.cp_tracks[2])
|
||||
self.core.playback.play(self.cp_tracks[1])
|
||||
self.core.playback.seek(10000)
|
||||
self.core.playback.time_position
|
||||
|
||||
self.assertFalse(self.playback1.get_time_position.called)
|
||||
self.playback2.get_time_position.assert_called_once_with()
|
||||
|
||||
def test_time_position_returns_0_if_track_is_unplayable(self):
|
||||
self.core.playback.current_cp_track = self.unplayable_cp_track
|
||||
|
||||
result = self.core.playback.time_position
|
||||
|
||||
self.assertEqual(result, 0)
|
||||
self.assertFalse(self.playback1.get_time_position.called)
|
||||
self.assertFalse(self.playback2.get_time_position.called)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user