mopidy/mopidy/backends/libspotify.py
2010-02-01 11:37:00 +01:00

185 lines
5.5 KiB
Python

from copy import deepcopy
import datetime as dt
import logging
import threading
from spotify import Link
from spotify.manager import SpotifySessionManager
from spotify.alsahelper import AlsaController
from mopidy import config
from mopidy.backends import BaseBackend
from mopidy.models import Artist, Album, Track, Playlist
logger = logging.getLogger(u'backends.libspotify')
ENCODING = 'utf-8'
class LibspotifyBackend(BaseBackend):
def __init__(self, *args, **kwargs):
super(LibspotifyBackend, self).__init__(*args, **kwargs)
self._next_id = 0
self._id_to_uri_map = {}
self._uri_to_id_map = {}
logger.info(u'Connecting to Spotify')
self.spotify = LibspotifySessionManager(
config.SPOTIFY_USERNAME, config.SPOTIFY_PASSWORD, backend=self)
self.spotify.start()
def update_stored_playlists(self):
logger.info(u'Updating stored playlists')
playlists = []
for spotify_playlist in self.spotify.playlists:
playlists.append(self._to_mopidy_playlist(spotify_playlist))
self._playlists = playlists
logger.debug(u'Available playlists: %s',
u', '.join([u'<%s>' % p.name for p in self._playlists]))
# Model translation
def _to_mopidy_id(self, spotify_uri):
if spotify_uri in self._uri_to_id_map:
return self._uri_to_id_map[spotify_uri]
else:
id = self._next_id
self._next_id += 1
self._id_to_uri_map[id] = spotify_uri
self._uri_to_id_map[spotify_uri] = id
return id
def _to_mopidy_artist(self, spotify_artist):
return Artist(
uri=str(Link.from_artist(spotify_artist)),
name=spotify_artist.name().decode(ENCODING),
)
def _to_mopidy_album(self, spotify_album):
# TODO pyspotify got much more data on albums than this
return Album(name=spotify_album.name().decode(ENCODING))
def _to_mopidy_track(self, spotify_track):
return Track(
uri=str(Link.from_track(spotify_track, 0)),
title=spotify_track.name().decode(ENCODING),
artists=[self._to_mopidy_artist(a)
for a in spotify_track.artists()],
album=self._to_mopidy_album(spotify_track.album()),
track_no=spotify_track.index(),
date=dt.date(spotify_track.album().year(), 1, 1),
length=spotify_track.duration(),
id=self._to_mopidy_id(str(Link.from_track(spotify_track, 0))),
)
def _to_mopidy_playlist(self, spotify_playlist):
return Playlist(
uri=str(Link.from_playlist(spotify_playlist)),
name=spotify_playlist.name().decode(ENCODING),
tracks=[self._to_mopidy_track(t) for t in spotify_playlist],
)
# Playback control
def _play_current_track(self):
self.spotify.session.load(
Link.from_string(self._current_track.uri).as_track())
self.spotify.session.play(1)
def _next(self):
self._current_song_pos += 1
self._play_current_track()
return True
def _pause(self):
# TODO
return False
def _play(self):
if self._current_track is not None:
self._play_current_track()
return True
else:
return False
def _play_id(self, songid):
matches = filter(lambda t: t.id == songid, self._current_playlist)
if matches:
self._current_song_pos = self._current_playlist.index(matches[0])
self._play_current_track()
return True
else:
return False
def _play_pos(self, songpos):
self._current_song_pos = songpos
self._play_current_track()
return True
def _previous(self):
self._current_song_pos -= 1
self._play_current_track()
return True
def _resume(self):
# TODO
return False
def _stop(self):
self.spotify.session.play(0)
return True
# Status querying
def status_bitrate(self):
return 320
def url_handlers(self):
return [u'spotify:', u'http://open.spotify.com/']
class LibspotifySessionManager(SpotifySessionManager, threading.Thread):
def __init__(self, username, password, backend):
SpotifySessionManager.__init__(self, username, password)
threading.Thread.__init__(self)
self.backend = backend
self.audio = AlsaController()
def run(self):
self.connect()
def logged_in(self, session, error):
logger.info('Logged in')
self.session = session
try:
self.playlists = session.playlist_container()
logger.debug('Got playlist container')
except Exception, e:
logger.exception(e)
def logged_out(self, session):
logger.info('Logged out')
def metadata_updated(self, session):
logger.debug('Metadata updated')
self.backend.update_stored_playlists()
def connection_error(self, session, error):
logger.error('Connection error: %s', error)
def message_to_user(self, session, message):
logger.info(message)
def notify_main_thread(self, session):
logger.debug('Notify main thread')
def music_delivery(self, *args, **kwargs):
self.audio.music_delivery(*args, **kwargs)
def play_token_lost(self, session):
logger.debug('Play token lost')
def log_message(self, session, data):
logger.debug(data)
def end_of_track(self, session):
logger.debug('End of track')