Merge remote branch 'adamcik/gstreamer'

Conflicts:
	mopidy/mpd/frontend.py
	tests/mpd/frontend_test.py

GstreamerBackend now raises LookupError where the other backends just
returns None. We'll probably move in the direction of using LookupError
all over, but the changes to DummyBackend and generic tests was reverted
until BaseBackend, the backend API docs and the other backends are
updated to all raise LookupError.
This commit is contained in:
Stein Magnus Jodal 2010-06-06 22:15:25 +02:00
commit a9923fcb23
10 changed files with 102 additions and 56 deletions

View File

@ -18,6 +18,7 @@ logger = logging.getLogger('mopidy.main')
def main():
options = _parse_options()
_setup_logging(options.verbosity_level, options.dump)
logger.info('-- Starting Mopidy --')
get_or_create_folder('~/.mopidy/')
core_queue = multiprocessing.Queue()
get_class(settings.SERVER)(core_queue)

View File

@ -38,10 +38,10 @@ class GStreamerBackend(BaseBackend):
def __init__(self, *args, **kwargs):
super(GStreamerBackend, self).__init__(*args, **kwargs)
self.playback = GStreamerPlaybackController(self)
self.library = GStreamerLibraryController(self)
self.stored_playlists = GStreamerStoredPlaylistsController(self)
self.current_playlist = BaseCurrentPlaylistController(self)
self.library = GStreamerLibraryController(self)
self.playback = GStreamerPlaybackController(self)
self.uri_handlers = [u'file://']
@ -120,16 +120,22 @@ class GStreamerPlaybackController(BasePlaybackController):
class GStreamerStoredPlaylistsController(BaseStoredPlaylistsController):
def __init__(self, *args):
super(GStreamerStoredPlaylistsController, self).__init__(*args)
self._folder = os.path.expanduser(settings.PLAYLIST_FOLDER)
self._folder = os.path.expanduser(settings.LOCAL_PLAYLIST_FOLDER)
self.refresh()
def refresh(self):
playlists = []
logger.info('Loading playlists from %s', self._folder)
for m3u in glob.glob(os.path.join(self._folder, '*.m3u')):
name = os.path.basename(m3u)[:len('.m3u')]
track_uris = parse_m3u(m3u)
tracks = map(lambda u: Track(uri=u), track_uris)
tracks = []
for uri in parse_m3u(m3u):
try:
tracks.append(self.backend.library.lookup(uri))
except LookupError, e:
logger.error('Playlist item could not be added: %s', e)
playlist = Playlist(tracks=tracks, name=name)
# FIXME playlist name needs better handling
@ -188,8 +194,11 @@ class GStreamerLibraryController(BaseLibraryController):
self.refresh()
def refresh(self, uri=None):
tracks = parse_mpd_tag_cache(settings.TAG_CACHE,
settings.MUSIC_FOLDER)
tracks = parse_mpd_tag_cache(settings.LOCAL_TAG_CACHE,
settings.LOCAL_MUSIC_FOLDER)
logger.info('Loading songs in %s from %s',
settings.LOCAL_MUSIC_FOLDER, settings.LOCAL_TAG_CACHE)
for track in tracks:
self._uri_mapping[track.uri] = track
@ -198,7 +207,7 @@ class GStreamerLibraryController(BaseLibraryController):
try:
return self._uri_mapping[uri]
except KeyError:
raise LookupError
raise LookupError('%s not found.' % uri)
def find_exact(self, field, query):
if not query:

View File

@ -39,6 +39,7 @@ class AlsaMixer(BaseMixer):
return [u'Master', u'PCM']
def _get_volume(self):
# FIXME does not seem to see external volume changes.
return self._mixer.getvolume()[0]
def _set_volume(self, volume):

View File

@ -432,11 +432,14 @@ class MpdFrontend(object):
argument is given, displays information only for the song
``SONGPOS`` or the range of songs ``START:END``.
*ncmpc:*
*ncmpc and mpc:*
- uses negative indexes, like ``playlistinfo "-1"``, to request
information on the last track in the playlist.
the entire playlist
"""
if songpos == "-1":
songpos = None
if songpos is not None:
songpos = int(songpos)
start = songpos
@ -1420,7 +1423,7 @@ class MpdFrontend(object):
matches = self.backend.stored_playlists.search(name)
if matches:
self.backend.current_playlist.load(matches[0])
self.backend.playback.new_playlist_loaded_callback()
self.backend.playback.new_playlist_loaded_callback() # FIXME not needed?
@handle_pattern(r'^playlistadd "(?P<name>[^"]+)" "(?P<uri>[^"]+)"$')
def _stored_playlist_playlistadd(self, name, uri):

View File

@ -119,13 +119,16 @@ SPOTIFY_LIB_APPKEY = u'~/.mopidy/spotify_appkey.key'
SPOTIFY_LIB_CACHE = u'~/.mopidy/libspotify_cache'
#: Path to playlist folder with m3u files.
PLAYLIST_FOLDER = u'~/.mopidy/playlists'
#: LOCAL_PLAYLIST_FOLDER = u'~/.mopidy/playlists'
LOCAL_PLAYLIST_FOLDER = u'~/.mopidy/playlists'
#: Path to folder with local music.
MUSIC_FOLDER = u'~/music'
#: LOCAL_MUSIC_FOLDER = u'~/music'
LOCAL_MUSIC_FOLDER = u'~/music'
#: Path to MPD tag_cache for local music.
TAG_CACHE = u'~/.mopidy/tag_cache'
#: Path to MPD tag_cache for local music
#: LOCAL_TAG_CACHE = u'~/.mopidy/tag_cache'
LOCAL_TAG_CACHE = u'~/.mopidy/tag_cache'
# Import user specific settings
dotdir = os.path.expanduser(u'~/.mopidy/')

View File

@ -35,6 +35,7 @@ def get_or_create_folder(folder):
def path_to_uri(*paths):
path = os.path.join(*paths)
#path = os.path.expanduser(path) # FIXME
path = path.encode('utf-8')
if sys.platform == 'win32':
return 'file:' + urllib.pathname2url(path)
@ -212,12 +213,13 @@ def _convert_mpd_data(data, tracks, music_dir):
track_kwargs['name'] = data['title']
if data['file'][0] == '/':
path = os.path.join(music_dir, data['file'][1:])
path = data['file'][1:]
else:
path = os.path.join(music_dir, data['file'])
path = data['file']
track_kwargs['uri'] = path_to_uri(path)
track_kwargs['uri'] = path_to_uri(music_dir, path)
track_kwargs['length'] = int(data.get('time', 0)) * 1000
track_kwargs['id'] = len(tracks)
track = Track(**track_kwargs)
tracks.add(track)

View File

@ -960,16 +960,26 @@ class BaseStoredPlaylistsControllerTest(object):
backend_class = None
def setUp(self):
self.original_folder = settings.PLAYLIST_FOLDER
settings.PLAYLIST_FOLDER = tempfile.mkdtemp()
self.original_playlist_folder = settings.LOCAL_PLAYLIST_FOLDER
self.original_tag_cache = settings.LOCAL_TAG_CACHE
self.original_music_folder = settings.LOCAL_MUSIC_FOLDER
settings.LOCAL_PLAYLIST_FOLDER = tempfile.mkdtemp()
settings.LOCAL_TAG_CACHE = data_folder('library_tag_cache')
settings.LOCAL_MUSIC_FOLDER = data_folder('')
self.backend = self.backend_class(mixer=DummyMixer())
self.stored = self.backend.stored_playlists
def tearDown(self):
self.backend.destroy()
if os.path.exists(settings.PLAYLIST_FOLDER):
shutil.rmtree(settings.PLAYLIST_FOLDER)
settings.PLAYLIST_FOLDER = self.original_folder
if os.path.exists(settings.LOCAL_PLAYLIST_FOLDER):
shutil.rmtree(settings.LOCAL_PLAYLIST_FOLDER)
settings.LOCAL_PLAYLIST_FOLDER = self.original_playlist_folder
settings.LOCAL_TAG_CACHE = self.original_tag_cache
settings.LOCAL_MUSIC_FOLDER = self.original_music_folder
def test_create(self):
playlist = self.stored.create('test')
@ -1064,6 +1074,9 @@ class BaseStoredPlaylistsControllerTest(object):
self.stored.save(playlist)
self.assert_(playlist in self.stored.playlists)
def test_playlist_with_unknown_track(self):
raise SkipTest
class BaseLibraryControllerTest(object):
artists = [Artist(name='artist1'), Artist(name='artist2'), Artist()]
@ -1071,10 +1084,10 @@ class BaseLibraryControllerTest(object):
Album(name='album2', artists=artists[1:2]),
Album()]
tracks = [Track(name='track1', length=4000, artists=artists[:1],
album=albums[0], uri='file://' + data_folder('uri1')),
album=albums[0], uri='file://' + data_folder('uri1'), id=0),
Track(name='track2', length=4000, artists=artists[1:2],
album=albums[1], uri='file://' + data_folder('uri2')),
Track()]
album=albums[1], uri='file://' + data_folder('uri2'), id=1),
Track(id=3)]
def setUp(self):
self.backend = self.backend_class(mixer=DummyMixer())

View File

@ -58,13 +58,13 @@ class GStreamerStoredPlaylistsControllerTest(BaseStoredPlaylistsControllerTest,
backend_class = GStreamerBackend
def test_created_playlist_is_persisted(self):
path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
path = os.path.join(settings.LOCAL_PLAYLIST_FOLDER, 'test.m3u')
self.assert_(not os.path.exists(path))
self.stored.create('test')
self.assert_(os.path.exists(path))
def test_saved_playlist_is_persisted(self):
path = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u')
path = os.path.join(settings.LOCAL_PLAYLIST_FOLDER, 'test2.m3u')
self.assert_(not os.path.exists(path))
self.stored.save(Playlist(name='test2'))
self.assert_(os.path.exists(path))
@ -72,13 +72,13 @@ class GStreamerStoredPlaylistsControllerTest(BaseStoredPlaylistsControllerTest,
def test_deleted_playlist_get_removed(self):
playlist = self.stored.create('test')
self.stored.delete(playlist)
path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
path = os.path.join(settings.LOCAL_PLAYLIST_FOLDER, 'test.m3u')
self.assert_(not os.path.exists(path))
def test_renamed_playlist_gets_moved(self):
playlist = self.stored.create('test')
file1 = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
file2 = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u')
file1 = os.path.join(settings.LOCAL_PLAYLIST_FOLDER, 'test.m3u')
file2 = os.path.join(settings.LOCAL_PLAYLIST_FOLDER, 'test2.m3u')
self.assert_(not os.path.exists(file2))
self.stored.rename(playlist, 'test2')
self.assert_(not os.path.exists(file1))
@ -88,7 +88,7 @@ class GStreamerStoredPlaylistsControllerTest(BaseStoredPlaylistsControllerTest,
track = Track(uri=generate_song(1))
uri = track.uri[len('file://'):]
playlist = Playlist(tracks=[track], name='test')
path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
path = os.path.join(settings.LOCAL_PLAYLIST_FOLDER, 'test.m3u')
self.stored.save(playlist)
@ -98,7 +98,7 @@ class GStreamerStoredPlaylistsControllerTest(BaseStoredPlaylistsControllerTest,
self.assertEqual(uri, contents.strip())
def test_playlists_are_loaded_at_startup(self):
track = Track(uri=generate_song(1))
track = Track(uri=path_to_uri(data_folder('uri2')))
playlist = Playlist(tracks=[track], name='test')
self.stored.save(playlist)
@ -130,15 +130,18 @@ class GStreamerLibraryControllerTest(BaseLibraryControllerTest,
backend_class = GStreamerBackend
def setUp(self):
self.original_tag_cache = settings.TAG_CACHE
self.original_music_folder = settings.MUSIC_FOLDER
settings.TAG_CACHE = data_folder('library_tag_cache')
settings.MUSIC_FOLDER = data_folder('')
self.original_tag_cache = settings.LOCAL_TAG_CACHE
self.original_music_folder = settings.LOCAL_MUSIC_FOLDER
settings.LOCAL_TAG_CACHE = data_folder('library_tag_cache')
settings.LOCAL_MUSIC_FOLDER = data_folder('')
super(GStreamerLibraryControllerTest, self).setUp()
def tearDown(self):
settings.TAG_CACHE = self.original_tag_cache
settings.MUSIC_FOLDER = self.original_music_folder
settings.LOCAL_TAG_CACHE = self.original_tag_cache
settings.LOCAL_MUSIC_FOLDER = self.original_music_folder
super(GStreamerLibraryControllerTest, self).tearDown()
if __name__ == '__main__':

View File

@ -523,6 +523,10 @@ class CurrentPlaylistHandlerTest(unittest.TestCase):
self.assertEqual(self.b.current_playlist.playlist.tracks[5], needle)
self.assert_(u'OK' in result)
def test_add_with_uri_not_found_in_library_should_ack(self):
result = self.h.handle_request(u'add "dummy://foo"')
self.assert_(u'ACK No such song' in result)
def test_addid_without_songpos(self):
needle = Track(uri='dummy://foo', id=137)
self.b.library._library = [Track(), Track(), needle, Track()]
@ -557,7 +561,6 @@ class CurrentPlaylistHandlerTest(unittest.TestCase):
self.assert_(u'ACK Position out of bounds' in result)
def test_addid_with_uri_not_found_in_library_should_ack(self):
self.b.library._library = [Track(), Track(), Track()]
result = self.h.handle_request(u'addid "dummy://foo"')
self.assert_(u'ACK No such song' in result)
@ -727,22 +730,27 @@ class CurrentPlaylistHandlerTest(unittest.TestCase):
self.assert_(u'ACK "id=25" match no tracks' in result)
def test_playlistinfo_without_songpos_or_range(self):
# FIXME testing just ok is not enough
result = self.h.handle_request(u'playlistinfo')
self.assert_(u'OK' in result)
def test_playlistinfo_with_songpos(self):
# FIXME testing just ok is not enough
result = self.h.handle_request(u'playlistinfo "5"')
self.assert_(u'OK' in result)
def test_playlistinfo_with_negative_songpos(self):
result = self.h.handle_request(u'playlistinfo "-1"')
self.assert_(u'OK' in result)
def test_playlistinfo_with_negative_songpos_same_as_playlistinfo(self):
result1 = self.h.handle_request(u'playlistinfo "-1"')
result2 = self.h.handle_request(u'playlistinfo')
self.assertEqual(result1, result2)
def test_playlistinfo_with_open_range(self):
# FIXME testing just ok is not enough
result = self.h.handle_request(u'playlistinfo "10:"')
self.assert_(u'OK' in result)
def test_playlistinfo_with_closed_range(self):
# FIXME testing just ok is not enough
result = self.h.handle_request(u'playlistinfo "10:20"')
self.assert_(u'OK' in result)

View File

@ -144,21 +144,21 @@ expected_albums = [Album(name='albumname', artists=expected_artists,
num_tracks=2)]
expected_tracks = []
def generate_track(path):
def generate_track(path, ident):
uri = path_to_uri(data_folder(path))
track = Track(name='trackname', artists=expected_artists, track_no=1,
album=expected_albums[0], length=4000, uri=uri)
album=expected_albums[0], length=4000, uri=uri, id=ident)
expected_tracks.append(track)
generate_track('song1.mp3')
generate_track('song2.mp3')
generate_track('song3.mp3')
generate_track('subdir1/song4.mp3')
generate_track('subdir1/song5.mp3')
generate_track('subdir2/song6.mp3')
generate_track('subdir2/song7.mp3')
generate_track('subdir1/subsubdir/song8.mp3')
generate_track('subdir1/subsubdir/song9.mp3')
generate_track('song1.mp3', 6)
generate_track('song2.mp3', 7)
generate_track('song3.mp3', 8)
generate_track('subdir1/song4.mp3', 2)
generate_track('subdir1/song5.mp3', 3)
generate_track('subdir2/song6.mp3', 4)
generate_track('subdir2/song7.mp3', 5)
generate_track('subdir1/subsubdir/song8.mp3', 0)
generate_track('subdir1/subsubdir/song9.mp3', 1)
class MPDTagCacheToTracksTest(unittest.TestCase):
def test_emtpy_cache(self):
@ -169,7 +169,10 @@ class MPDTagCacheToTracksTest(unittest.TestCase):
def test_simple_cache(self):
tracks = parse_mpd_tag_cache(data_folder('simple_tag_cache'),
data_folder(''))
self.assertEqual(expected_tracks[0], list(tracks)[0])
uri = path_to_uri(data_folder('song1.mp3'))
track = Track(name='trackname', artists=expected_artists, track_no=1,
album=expected_albums[0], length=4000, uri=uri, id=0)
self.assertEqual(set([track]), tracks)
def test_advanced_cache(self):
tracks = parse_mpd_tag_cache(data_folder('advanced_tag_cache'),
@ -187,4 +190,4 @@ class MPDTagCacheToTracksTest(unittest.TestCase):
tracks = parse_mpd_tag_cache(data_folder('blank_tag_cache'),
data_folder(''))
uri = path_to_uri(data_folder('song1.mp3'))
self.assertEqual(set([Track(uri=uri, length=4000)]), tracks)
self.assertEqual(set([Track(uri=uri, length=4000, id=0)]), tracks)