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:
commit
a9923fcb23
@ -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)
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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/')
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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__':
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user