90 lines
2.9 KiB
Python
90 lines
2.9 KiB
Python
from __future__ import unicode_literals
|
|
|
|
import logging
|
|
import functools
|
|
|
|
from spotify import Link, SpotifyError
|
|
|
|
from mopidy import audio
|
|
from mopidy.backends import base
|
|
|
|
|
|
logger = logging.getLogger('mopidy.backends.spotify')
|
|
|
|
|
|
def need_data_callback(spotify_backend, length_hint):
|
|
spotify_backend.playback.on_need_data(length_hint)
|
|
|
|
|
|
def enough_data_callback(spotify_backend):
|
|
spotify_backend.playback.on_enough_data()
|
|
|
|
|
|
def seek_data_callback(spotify_backend, time_position):
|
|
spotify_backend.playback.on_seek_data(time_position)
|
|
|
|
|
|
class SpotifyPlaybackProvider(base.BasePlaybackProvider):
|
|
# These GStreamer caps matches the audio data provided by libspotify
|
|
_caps = (
|
|
'audio/x-raw-int, endianness=(int)1234, channels=(int)2, '
|
|
'width=(int)16, depth=(int)16, signed=(boolean)true, '
|
|
'rate=(int)44100')
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(SpotifyPlaybackProvider, self).__init__(*args, **kwargs)
|
|
self._first_seek = False
|
|
|
|
def change_track(self, track):
|
|
spotify_backend = self.backend.actor_ref.proxy()
|
|
|
|
need_data_callback_bound = functools.partial(
|
|
need_data_callback, spotify_backend)
|
|
enough_data_callback_bound = functools.partial(
|
|
enough_data_callback, spotify_backend)
|
|
seek_data_callback_bound = functools.partial(
|
|
seek_data_callback, spotify_backend)
|
|
|
|
self._first_seek = True
|
|
|
|
self.audio.set_appsrc(
|
|
self._caps,
|
|
need_data=need_data_callback_bound,
|
|
enough_data=enough_data_callback_bound,
|
|
seek_data=seek_data_callback_bound)
|
|
self.audio.set_metadata(track)
|
|
|
|
try:
|
|
self.backend.spotify.session.load(
|
|
Link.from_string(track.uri).as_track())
|
|
self.backend.spotify.buffer_timestamp = 0
|
|
self.backend.spotify.session.play(1)
|
|
return True
|
|
except SpotifyError as e:
|
|
logger.info('Playback of %s failed: %s', track.uri, e)
|
|
return False
|
|
|
|
def stop(self):
|
|
self.backend.spotify.session.play(0)
|
|
return super(SpotifyPlaybackProvider, self).stop()
|
|
|
|
def on_need_data(self, length_hint):
|
|
logger.debug('playback.on_need_data(%d) called', length_hint)
|
|
self.backend.spotify.push_audio_data = True
|
|
|
|
def on_enough_data(self):
|
|
logger.debug('playback.on_enough_data() called')
|
|
self.backend.spotify.push_audio_data = False
|
|
|
|
def on_seek_data(self, time_position):
|
|
logger.debug('playback.on_seek_data(%d) called', time_position)
|
|
|
|
if time_position == 0 and self._first_seek:
|
|
self._first_seek = False
|
|
logger.debug('Skipping seek due to issue #300')
|
|
return
|
|
|
|
self.backend.spotify.buffer_timestamp = audio.millisecond_to_clocktime(
|
|
time_position)
|
|
self.backend.spotify.session.seek(time_position)
|