Merge commit 'adamcik/gstreamer'
This commit is contained in:
commit
e84fe6ddd7
@ -176,7 +176,8 @@ class BaseCurrentPlaylistController(object):
|
||||
assert start >= 0, 'start must be at least zero'
|
||||
assert end <= len(tracks), 'end can not be larger than playlist length'
|
||||
assert to_position >= 0, 'to_position must be at least zero'
|
||||
assert to_position <= len(tracks), 'to_position can not be larger than playlist length'
|
||||
assert to_position <= len(tracks), 'to_position can not be larger ' + \
|
||||
'than playlist length'
|
||||
|
||||
new_tracks = tracks[:start] + tracks[end:]
|
||||
for track in tracks[start:end]:
|
||||
@ -218,7 +219,8 @@ class BaseCurrentPlaylistController(object):
|
||||
assert start >= 0, 'start must be at least zero'
|
||||
|
||||
if end is not None:
|
||||
assert end <= len(tracks), 'end can not be larger than playlist length'
|
||||
assert end <= len(tracks), 'end can not be larger than ' + \
|
||||
'playlist length'
|
||||
|
||||
before = tracks[:start or 0]
|
||||
shuffled = tracks[start:end]
|
||||
|
||||
@ -16,7 +16,7 @@ import threading
|
||||
from mopidy.backends import *
|
||||
from mopidy.models import Playlist, Track
|
||||
from mopidy import settings
|
||||
from mopidy.utils import m3u_to_uris
|
||||
from mopidy.utils import parse_m3u
|
||||
|
||||
logger = logging.getLogger(u'backends.gstreamer')
|
||||
|
||||
@ -41,7 +41,7 @@ class GStreamerBackend(BaseBackend):
|
||||
self.playback = GStreamerPlaybackController(self)
|
||||
self.stored_playlists = GStreamerStoredPlaylistsController(self)
|
||||
self.current_playlist = BaseCurrentPlaylistController(self)
|
||||
self.uri_handlers = [u'file:']
|
||||
self.uri_handlers = [u'file://']
|
||||
|
||||
|
||||
class GStreamerPlaybackController(BasePlaybackController):
|
||||
@ -127,11 +127,12 @@ class GStreamerStoredPlaylistsController(BaseStoredPlaylistsController):
|
||||
|
||||
for m3u in glob.glob(os.path.join(self._folder, '*.m3u')):
|
||||
name = os.path.basename(m3u)[:len('.m3u')]
|
||||
track_uris = m3u_to_uris(m3u)
|
||||
track_uris = parse_m3u(m3u)
|
||||
tracks = map(lambda u: Track(uri=u), track_uris)
|
||||
playlist = Playlist(tracks=tracks, name=name)
|
||||
|
||||
# FIXME playlist name needs better handling
|
||||
# FIXME tracks should come from lib. lookup
|
||||
|
||||
playlists.append(playlist)
|
||||
|
||||
@ -170,8 +171,8 @@ class GStreamerStoredPlaylistsController(BaseStoredPlaylistsController):
|
||||
|
||||
with open(file_path, 'w') as file:
|
||||
for track in playlist.tracks:
|
||||
if track.uri.startswith('file:'):
|
||||
file.write(track.uri[len('file:'):] + '\n')
|
||||
if track.uri.startswith('file://'):
|
||||
file.write(track.uri[len('file://'):] + '\n')
|
||||
else:
|
||||
file.write(track.uri + '\n')
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ class DenonMixer(BaseMixer):
|
||||
self._lock = Lock()
|
||||
|
||||
def _get_volume(self):
|
||||
self._lock.acquire();
|
||||
self._lock.acquire()
|
||||
self.ensure_open_device()
|
||||
self._device.write('MV?\r')
|
||||
vol = str(self._device.readline()[2:4])
|
||||
|
||||
@ -17,7 +17,7 @@ class OsaMixer(BaseMixer):
|
||||
and (int(time.time() - self._last_update) < self.CACHE_TTL))
|
||||
|
||||
def _get_volume(self):
|
||||
if not self._valid_cache():
|
||||
if not self._valid_cache():
|
||||
try:
|
||||
self._cache = int(Popen(
|
||||
['osascript', '-e',
|
||||
|
||||
@ -10,13 +10,32 @@ class ImmutableObject(object):
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.__dict__.update(kwargs)
|
||||
for key, value in kwargs.items():
|
||||
if not hasattr(self, key):
|
||||
raise TypeError('__init__() got an unexpected keyword ' + \
|
||||
'argument \'%s\'' % key)
|
||||
self.__dict__[key] = value
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name.startswith('_'):
|
||||
return super(ImmutableObject, self).__setattr__(name, value)
|
||||
raise AttributeError('Object is immutable.')
|
||||
|
||||
def __hash__(self):
|
||||
hash_sum = 0
|
||||
for key, value in self.__dict__.items():
|
||||
hash_sum += hash(key) + hash(value)
|
||||
return hash_sum
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, self.__class__):
|
||||
return False
|
||||
|
||||
return self.__dict__ == other.__dict__
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
class Artist(ImmutableObject):
|
||||
"""
|
||||
@ -55,13 +74,13 @@ class Album(ImmutableObject):
|
||||
num_tracks = 0
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._artists = kwargs.pop('artists', [])
|
||||
self._artists = frozenset(kwargs.pop('artists', []))
|
||||
super(Album, self).__init__(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def artists(self):
|
||||
"""List of :class:`Artist` elements. Read-only."""
|
||||
return copy(self._artists)
|
||||
return list(self._artists)
|
||||
|
||||
|
||||
class Track(ImmutableObject):
|
||||
@ -111,13 +130,13 @@ class Track(ImmutableObject):
|
||||
id = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._artists = kwargs.pop('artists', [])
|
||||
self._artists = frozenset(kwargs.pop('artists', []))
|
||||
super(Track, self).__init__(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def artists(self):
|
||||
"""List of :class:`Artist`. Read-only."""
|
||||
return copy(self._artists)
|
||||
return list(self._artists)
|
||||
|
||||
def mpd_format(self, position=0, search_result=False):
|
||||
"""
|
||||
@ -151,7 +170,9 @@ class Track(ImmutableObject):
|
||||
|
||||
:rtype: string
|
||||
"""
|
||||
return u', '.join([a.name for a in self.artists])
|
||||
artists = list(self._artists)
|
||||
artists.sort(key=lambda a: a.name)
|
||||
return u', '.join([a.name for a in artists])
|
||||
|
||||
|
||||
class Playlist(ImmutableObject):
|
||||
|
||||
@ -643,7 +643,7 @@ class MpdFrontend(object):
|
||||
- capitalizes the type argument.
|
||||
"""
|
||||
type = type.lower()
|
||||
pass # TODO
|
||||
# TODO
|
||||
|
||||
@handle_pattern(r'^listall "(?P<uri>[^"]+)"')
|
||||
def _music_db_listall(self, uri):
|
||||
|
||||
@ -26,7 +26,8 @@ BACKENDS = (
|
||||
#: The log format used on the console. See
|
||||
#: http://docs.python.org/library/logging.html#formatter-objects for details on
|
||||
#: the format.
|
||||
CONSOLE_LOG_FORMAT = u'%(levelname)-8s %(asctime)s [%(process)d:%(threadName)s] %(name)s\n %(message)s'
|
||||
CONSOLE_LOG_FORMAT = u'%(levelname)-8s %(asctime)s' + \
|
||||
' [%(process)d:%(threadName)s] %(name)s\n %(message)s'
|
||||
|
||||
#: Protocol frontend to use. Default::
|
||||
#:
|
||||
@ -104,6 +105,12 @@ SPOTIFY_LIB_CACHE = u'~/.mopidy/libspotify_cache'
|
||||
#: Path to playlist folder with m3u files.
|
||||
PLAYLIST_FOLDER = u'~/.mopidy/playlists'
|
||||
|
||||
#: Path to folder with local music.
|
||||
MUSIC_FOLDER = u'~/music'
|
||||
|
||||
#: Path to MPD tag_cache for local music
|
||||
TAG_CACHE = u'~/.mopidy/tag_cache'
|
||||
|
||||
# Import user specific settings
|
||||
dotdir = os.path.expanduser(u'~/.mopidy/')
|
||||
settings_file = os.path.join(dotdir, u'settings.py')
|
||||
|
||||
@ -6,6 +6,8 @@ import urllib
|
||||
|
||||
logger = logging.getLogger('mopidy.utils')
|
||||
|
||||
from mopidy.models import Track, Artist, Album
|
||||
|
||||
def flatten(the_list):
|
||||
result = []
|
||||
for element in the_list:
|
||||
@ -93,7 +95,7 @@ def spotify_uri_to_int(uri, output_bits=31):
|
||||
full_id >>= output_bits
|
||||
return int(compressed_id)
|
||||
|
||||
def m3u_to_uris(file_path):
|
||||
def parse_m3u(file_path):
|
||||
"""
|
||||
Convert M3U file list of uris
|
||||
|
||||
@ -124,11 +126,71 @@ def m3u_to_uris(file_path):
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
|
||||
if line.startswith('file:'):
|
||||
# FIXME what about other URI types?
|
||||
if line.startswith('file://'):
|
||||
uris.append(line)
|
||||
else:
|
||||
file = os.path.join(folder, line)
|
||||
path = urllib.pathname2url(file.encode('utf-8'))
|
||||
uris.append('file:' + path)
|
||||
path = os.path.join(folder, line)
|
||||
path = urllib.pathname2url(path.encode('utf-8'))
|
||||
uris.append('file://' + path)
|
||||
|
||||
return uris
|
||||
|
||||
def parse_mpd_tag_cache(tag_cache, music_dir=''):
|
||||
"""
|
||||
Converts a MPD tag_cache into a lists of tracks, artists and albums.
|
||||
"""
|
||||
with open(tag_cache) as library:
|
||||
contents = library.read()
|
||||
|
||||
tracks = set()
|
||||
artists = set()
|
||||
albums = set()
|
||||
current = {}
|
||||
state = None
|
||||
|
||||
for line in contents.split('\n'):
|
||||
if line == 'songList begin':
|
||||
state = 'songs'
|
||||
continue
|
||||
elif line == 'songList end':
|
||||
state = None
|
||||
continue
|
||||
elif not state:
|
||||
continue
|
||||
|
||||
key, value = line.split(': ', 1)
|
||||
|
||||
if key == 'key':
|
||||
_convert_mpd_data(current, tracks, artists, albums, music_dir)
|
||||
current.clear()
|
||||
|
||||
current[key.lower()] = value
|
||||
|
||||
_convert_mpd_data(current, tracks, artists, albums, music_dir)
|
||||
|
||||
return tracks, artists, albums
|
||||
|
||||
def _convert_mpd_data(data, tracks, artists, albums, music_dir):
|
||||
if not data:
|
||||
return
|
||||
|
||||
num_tracks = int(data['track'].split('/')[1])
|
||||
track_no = int(data['track'].split('/')[0])
|
||||
path = data['file']
|
||||
|
||||
if path[0] == '/':
|
||||
path = path[1:]
|
||||
|
||||
path = os.path.join(music_dir, path)
|
||||
uri = 'file://' + urllib.pathname2url(path)
|
||||
|
||||
artist = Artist(name=data['artist'])
|
||||
artists.add(artist)
|
||||
|
||||
album = Album(name=data['album'], artists=[artist], num_tracks=num_tracks)
|
||||
albums.add(album)
|
||||
|
||||
track = Track(name=data['title'], artists=[artist], track_no=track_no,
|
||||
length=int(data['time'])*1000, uri=uri, album=album)
|
||||
tracks.add(track)
|
||||
|
||||
@ -13,7 +13,8 @@ from tests import SkipTest
|
||||
|
||||
__all__ = ['BaseCurrentPlaylistControllerTest',
|
||||
'BasePlaybackControllerTest',
|
||||
'BaseStoredPlaylistsControllerTest']
|
||||
'BaseStoredPlaylistsControllerTest',
|
||||
'BaseLibraryControllerTest']
|
||||
|
||||
def populate_playlist(func):
|
||||
def wrapper(self):
|
||||
@ -96,7 +97,7 @@ class BaseCurrentPlaylistControllerTest(object):
|
||||
|
||||
def test_load(self):
|
||||
new_playlist = Playlist()
|
||||
self.assertNotEqual(new_playlist, self.controller.playlist)
|
||||
self.assertNotEqual(id(new_playlist), id(self.controller.playlist))
|
||||
self.controller.load(new_playlist)
|
||||
# FIXME how do we test this without going into internals?
|
||||
self.assertEqual(new_playlist, self.controller._playlist)
|
||||
@ -175,7 +176,7 @@ class BaseCurrentPlaylistControllerTest(object):
|
||||
playlist1 = self.controller.playlist
|
||||
playlist2 = self.controller.playlist
|
||||
|
||||
self.assertNotEqual(playlist1, playlist2)
|
||||
self.assertNotEqual(id(playlist1), id(playlist2))
|
||||
|
||||
@populate_playlist
|
||||
def test_remove(self):
|
||||
@ -965,9 +966,59 @@ class BaseStoredPlaylistsControllerTest(object):
|
||||
|
||||
def test_rename_unknown_playlist(self):
|
||||
self.stored.rename(Playlist(), 'test2')
|
||||
test = lambda: self.stored.get(name='test2')
|
||||
self.assertRaises(LookupError, test)
|
||||
|
||||
def test_save(self):
|
||||
# FIXME should we handle playlists without names?
|
||||
playlist = Playlist(name='test')
|
||||
self.stored.save(playlist)
|
||||
self.assert_(playlist in self.stored.playlists)
|
||||
|
||||
|
||||
class BaseLibraryControllerTest(object):
|
||||
def setUp(self):
|
||||
self.backend = self.backend_class(mixer=DummyMixer())
|
||||
self.controller = self.backend.library
|
||||
|
||||
def tearDown(self):
|
||||
self.backend.destroy()
|
||||
|
||||
def test_refresh(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_lookup(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_lookup_unknown_track(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_find_exact_no_hits(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_find_exact_artist(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_find_exact_track(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_find_exact_album(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_find_search_no_hits(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_find_search_artist(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_find_search_track(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_find_search_album(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_find_search_uri(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_find_search_any(self):
|
||||
raise SkipTest
|
||||
|
||||
@ -14,7 +14,7 @@ folder = os.path.dirname(__file__)
|
||||
folder = os.path.join(folder, '..', 'data')
|
||||
folder = os.path.abspath(folder)
|
||||
song = os.path.join(folder, 'song%s.wav')
|
||||
generate_song = lambda i: 'file:' + urllib.pathname2url(song % i)
|
||||
generate_song = lambda i: 'file://' + urllib.pathname2url(song % i)
|
||||
|
||||
# FIXME can be switched to generic test
|
||||
class GStreamerCurrentPlaylistHandlerTest(BaseCurrentPlaylistControllerTest, unittest.TestCase):
|
||||
@ -28,12 +28,12 @@ class GStreamerPlaybackControllerTest(BasePlaybackControllerTest, unittest.TestC
|
||||
backend_class = GStreamerBackend
|
||||
|
||||
def add_track(self, file):
|
||||
uri = 'file:' + urllib.pathname2url(os.path.join(folder, file))
|
||||
uri = 'file://' + urllib.pathname2url(os.path.join(folder, file))
|
||||
track = Track(uri=uri, id=1, length=4464)
|
||||
self.backend.current_playlist.add(track)
|
||||
|
||||
def test_uri_handler(self):
|
||||
self.assert_('file:' in self.backend.uri_handlers)
|
||||
self.assert_('file://' in self.backend.uri_handlers)
|
||||
|
||||
def test_play_mp3(self):
|
||||
self.add_track('blank.mp3')
|
||||
@ -57,14 +57,16 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle
|
||||
backend_class = GStreamerBackend
|
||||
|
||||
def test_created_playlist_is_persisted(self):
|
||||
path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
|
||||
self.assert_(not os.path.exists(path))
|
||||
self.stored.create('test')
|
||||
file = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
|
||||
self.assert_(os.path.exists(file))
|
||||
self.assert_(os.path.exists(path))
|
||||
|
||||
def test_saved_playlist_is_persisted(self):
|
||||
path = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u')
|
||||
self.assert_(not os.path.exists(path))
|
||||
self.stored.save(Playlist(name='test2'))
|
||||
file = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u')
|
||||
self.assert_(os.path.exists(file))
|
||||
self.assert_(os.path.exists(path))
|
||||
|
||||
def test_deleted_playlist_get_removed(self):
|
||||
playlist = self.stored.create('test')
|
||||
@ -74,15 +76,16 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle
|
||||
|
||||
def test_renamed_playlist_gets_moved(self):
|
||||
playlist = self.stored.create('test')
|
||||
self.stored.rename(playlist, 'test2')
|
||||
file1 = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
|
||||
file2 = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u')
|
||||
self.assert_(not os.path.exists(file2))
|
||||
self.stored.rename(playlist, 'test2')
|
||||
self.assert_(not os.path.exists(file1))
|
||||
self.assert_(os.path.exists(file2))
|
||||
|
||||
def test_playlist_contents_get_written_to_disk(self):
|
||||
track = Track(uri=generate_song(1))
|
||||
uri = track.uri[len('file:'):]
|
||||
uri = track.uri[len('file://'):]
|
||||
playlist = Playlist(tracks=[track], name='test')
|
||||
file_path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
|
||||
|
||||
@ -95,7 +98,7 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle
|
||||
|
||||
def test_playlists_are_loaded_at_startup(self):
|
||||
track = Track(uri=generate_song(1))
|
||||
uri = track.uri[len('file:'):]
|
||||
uri = track.uri[len('file://'):]
|
||||
playlist = Playlist(tracks=[track], name='test')
|
||||
file_path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u')
|
||||
|
||||
@ -121,5 +124,12 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle
|
||||
def test_save_sets_playlist_uri(self):
|
||||
raise SkipTest
|
||||
|
||||
|
||||
class GStreamerBackendLibraryControllerTest(BaseStoredPlaylistsControllerTest,
|
||||
unittest.TestCase):
|
||||
|
||||
backend_class = GStreamerBackend
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
102
tests/data/advanced_tag_cache
Normal file
102
tests/data/advanced_tag_cache
Normal file
@ -0,0 +1,102 @@
|
||||
info_begin
|
||||
mpd_version: 0.14.2
|
||||
fs_charset: UTF-8
|
||||
info_end
|
||||
directory: subdir1
|
||||
begin: subdir1
|
||||
directory: subsubdir
|
||||
begin: subdir1/subsubdir
|
||||
songList begin
|
||||
key: song8.mp3
|
||||
file: subdir1/subsubdir/song8.mp3
|
||||
Time: 4
|
||||
Artist: name
|
||||
Title: trackname
|
||||
Album: albumname
|
||||
Track: 1/2
|
||||
Date: 2006
|
||||
mtime: 1272319626
|
||||
key: song9.mp3
|
||||
file: subdir1/subsubdir/song9.mp3
|
||||
Time: 4
|
||||
Artist: name
|
||||
Title: trackname
|
||||
Album: albumname
|
||||
Track: 1/2
|
||||
Date: 2006
|
||||
mtime: 1272319626
|
||||
songList end
|
||||
end: subdir1/subsubdir
|
||||
songList begin
|
||||
key: song4.mp3
|
||||
file: subdir1/song4.mp3
|
||||
Time: 4
|
||||
Artist: name
|
||||
Title: trackname
|
||||
Album: albumname
|
||||
Track: 1/2
|
||||
Date: 2006
|
||||
mtime: 1272319626
|
||||
key: song5.mp3
|
||||
file: subdir1/song5.mp3
|
||||
Time: 4
|
||||
Artist: name
|
||||
Title: trackname
|
||||
Album: albumname
|
||||
Track: 1/2
|
||||
Date: 2006
|
||||
mtime: 1272319626
|
||||
songList end
|
||||
end: subdir1
|
||||
directory: subdir2
|
||||
begin: subdir2
|
||||
songList begin
|
||||
key: song6.mp3
|
||||
file: subdir2/song6.mp3
|
||||
Time: 4
|
||||
Artist: name
|
||||
Title: trackname
|
||||
Album: albumname
|
||||
Track: 1/2
|
||||
Date: 2006
|
||||
mtime: 1272319626
|
||||
key: song7.mp3
|
||||
file: subdir2/song7.mp3
|
||||
Time: 4
|
||||
Artist: name
|
||||
Title: trackname
|
||||
Album: albumname
|
||||
Track: 1/2
|
||||
Date: 2006
|
||||
mtime: 1272319626
|
||||
songList end
|
||||
end: subdir2
|
||||
songList begin
|
||||
key: song1.mp3
|
||||
file: /song1.mp3
|
||||
Time: 4
|
||||
Artist: name
|
||||
Title: trackname
|
||||
Album: albumname
|
||||
Track: 1/2
|
||||
Date: 2006
|
||||
mtime: 1272319626
|
||||
key: song2.mp3
|
||||
file: /song2.mp3
|
||||
Time: 4
|
||||
Artist: name
|
||||
Title: trackname
|
||||
Album: albumname
|
||||
Track: 1/2
|
||||
Date: 2006
|
||||
mtime: 1272319626
|
||||
key: song3.mp3
|
||||
file: /song3.mp3
|
||||
Time: 4
|
||||
Artist: name
|
||||
Title: trackname
|
||||
Album: albumname
|
||||
Track: 1/2
|
||||
Date: 2006
|
||||
mtime: 1272319626
|
||||
songList end
|
||||
6
tests/data/empty_tag_cache
Normal file
6
tests/data/empty_tag_cache
Normal file
@ -0,0 +1,6 @@
|
||||
info_begin
|
||||
mpd_version: 0.14.2
|
||||
fs_charset: UTF-8
|
||||
info_end
|
||||
songList begin
|
||||
songList end
|
||||
15
tests/data/simple_tag_cache
Normal file
15
tests/data/simple_tag_cache
Normal file
@ -0,0 +1,15 @@
|
||||
info_begin
|
||||
mpd_version: 0.14.2
|
||||
fs_charset: UTF-8
|
||||
info_end
|
||||
songList begin
|
||||
key: song1.mp3
|
||||
file: /song1.mp3
|
||||
Time: 4
|
||||
Artist: name
|
||||
Title: trackname
|
||||
Album: albumname
|
||||
Track: 1/2
|
||||
Date: 2006
|
||||
mtime: 1272319626
|
||||
songList end
|
||||
@ -3,6 +3,8 @@ import unittest
|
||||
|
||||
from mopidy.models import Artist, Album, Track, Playlist
|
||||
|
||||
from tests import SkipTest
|
||||
|
||||
class ArtistTest(unittest.TestCase):
|
||||
def test_uri(self):
|
||||
uri = u'an_uri'
|
||||
@ -16,6 +18,52 @@ class ArtistTest(unittest.TestCase):
|
||||
self.assertEqual(artist.name, name)
|
||||
self.assertRaises(AttributeError, setattr, artist, 'name', None)
|
||||
|
||||
def test_invalid_kwarg(self):
|
||||
test = lambda: Artist(foo='baz')
|
||||
self.assertRaises(TypeError, test)
|
||||
|
||||
def test_eq_name(self):
|
||||
artist1 = Artist(name=u'name')
|
||||
artist2 = Artist(name=u'name')
|
||||
self.assertEqual(artist1, artist2)
|
||||
self.assertEqual(hash(artist1), hash(artist2))
|
||||
|
||||
def test_eq_uri(self):
|
||||
artist1 = Artist(uri=u'uri')
|
||||
artist2 = Artist(uri=u'uri')
|
||||
self.assertEqual(artist1, artist2)
|
||||
self.assertEqual(hash(artist1), hash(artist2))
|
||||
|
||||
def test_eq(self):
|
||||
artist1 = Artist(uri=u'uri', name=u'name')
|
||||
artist2 = Artist(uri=u'uri', name=u'name')
|
||||
self.assertEqual(artist1, artist2)
|
||||
self.assertEqual(hash(artist1), hash(artist2))
|
||||
|
||||
def test_eq_none(self):
|
||||
self.assertNotEqual(Artist(), None)
|
||||
|
||||
def test_eq_other(self):
|
||||
self.assertNotEqual(Artist(), 'other')
|
||||
|
||||
def test_ne_name(self):
|
||||
artist1 = Artist(name=u'name1')
|
||||
artist2 = Artist(name=u'name2')
|
||||
self.assertNotEqual(artist1, artist2)
|
||||
self.assertNotEqual(hash(artist1), hash(artist2))
|
||||
|
||||
def test_ne_uri(self):
|
||||
artist1 = Artist(uri=u'uri1')
|
||||
artist2 = Artist(uri=u'uri2')
|
||||
self.assertNotEqual(artist1, artist2)
|
||||
self.assertNotEqual(hash(artist1), hash(artist2))
|
||||
|
||||
def test_ne(self):
|
||||
artist1 = Artist(uri=u'uri1', name=u'name1')
|
||||
artist2 = Artist(uri=u'uri2', name=u'name2')
|
||||
self.assertNotEqual(artist1, artist2)
|
||||
self.assertNotEqual(hash(artist1), hash(artist2))
|
||||
|
||||
|
||||
class AlbumTest(unittest.TestCase):
|
||||
def test_uri(self):
|
||||
@ -42,6 +90,86 @@ class AlbumTest(unittest.TestCase):
|
||||
self.assertEqual(album.num_tracks, num_tracks)
|
||||
self.assertRaises(AttributeError, setattr, album, 'num_tracks', None)
|
||||
|
||||
def test_invalid_kwarg(self):
|
||||
test = lambda: Album(foo='baz')
|
||||
self.assertRaises(TypeError, test)
|
||||
|
||||
def test_eq_name(self):
|
||||
album1 = Album(name=u'name')
|
||||
album2 = Album(name=u'name')
|
||||
self.assertEqual(album1, album2)
|
||||
self.assertEqual(hash(album1), hash(album2))
|
||||
|
||||
def test_eq_uri(self):
|
||||
album1 = Album(uri=u'uri')
|
||||
album2 = Album(uri=u'uri')
|
||||
self.assertEqual(album1, album2)
|
||||
self.assertEqual(hash(album1), hash(album2))
|
||||
|
||||
def test_eq_artists(self):
|
||||
artists = [Artist()]
|
||||
album1 = Album(artists=artists)
|
||||
album2 = Album(artists=artists)
|
||||
self.assertEqual(album1, album2)
|
||||
self.assertEqual(hash(album1), hash(album2))
|
||||
|
||||
def test_eq_artists_order(self):
|
||||
artist1 = Artist(name=u'name1')
|
||||
artist2 = Artist(name=u'name2')
|
||||
album1 = Album(artists=[artist1, artist2])
|
||||
album2 = Album(artists=[artist2, artist1])
|
||||
self.assertEqual(album1, album2)
|
||||
self.assertEqual(hash(album1), hash(album2))
|
||||
|
||||
def test_eq_num_tracks(self):
|
||||
album1 = Album(num_tracks=2)
|
||||
album2 = Album(num_tracks=2)
|
||||
self.assertEqual(album1, album2)
|
||||
self.assertEqual(hash(album1), hash(album2))
|
||||
|
||||
def test_eq(self):
|
||||
artists = [Artist()]
|
||||
album1 = Album(name=u'name', uri=u'uri', artists=artists, num_tracks=2)
|
||||
album2 = Album(name=u'name', uri=u'uri', artists=artists, num_tracks=2)
|
||||
self.assertEqual(album1, album2)
|
||||
self.assertEqual(hash(album1), hash(album2))
|
||||
|
||||
def test_eq_none(self):
|
||||
self.assertNotEqual(Album(), None)
|
||||
|
||||
def test_eq_other(self):
|
||||
self.assertNotEqual(Album(), 'other')
|
||||
|
||||
def test_ne_name(self):
|
||||
album1 = Album(name=u'name1')
|
||||
album2 = Album(name=u'name2')
|
||||
self.assertNotEqual(album1, album2)
|
||||
self.assertNotEqual(hash(album1), hash(album2))
|
||||
|
||||
def test_ne_uri(self):
|
||||
album1 = Album(uri=u'uri1')
|
||||
album2 = Album(uri=u'uri2')
|
||||
self.assertNotEqual(album1, album2)
|
||||
self.assertNotEqual(hash(album1), hash(album2))
|
||||
|
||||
def test_ne_artists(self):
|
||||
album1 = Album(artists=[Artist(name=u'name1')])
|
||||
album2 = Album(artists=[Artist(name=u'name2')])
|
||||
self.assertNotEqual(album1, album2)
|
||||
self.assertNotEqual(hash(album1), hash(album2))
|
||||
|
||||
def test_ne_num_tracks(self):
|
||||
album1 = Album(num_tracks=1)
|
||||
album2 = Album(num_tracks=2)
|
||||
self.assertNotEqual(album1, album2)
|
||||
self.assertNotEqual(hash(album1), hash(album2))
|
||||
|
||||
def test_ne(self):
|
||||
album1 = Album(name=u'name1', uri=u'uri1', artists=[Artist(name=u'name1')], num_tracks=1)
|
||||
album2 = Album(name=u'name2', uri=u'uri2', artists=[Artist(name=u'name2')], num_tracks=2)
|
||||
self.assertNotEqual(album1, album2)
|
||||
self.assertNotEqual(hash(album1), hash(album2))
|
||||
|
||||
|
||||
class TrackTest(unittest.TestCase):
|
||||
def test_uri(self):
|
||||
@ -57,9 +185,9 @@ class TrackTest(unittest.TestCase):
|
||||
self.assertRaises(AttributeError, setattr, track, 'name', None)
|
||||
|
||||
def test_artists(self):
|
||||
artists = [Artist(), Artist()]
|
||||
artists = [Artist(name=u'name1'), Artist(name=u'name2')]
|
||||
track = Track(artists=artists)
|
||||
self.assertEqual(track.artists, artists)
|
||||
self.assertEqual(set(track.artists), set(artists))
|
||||
self.assertRaises(AttributeError, setattr, track, 'artists', None)
|
||||
|
||||
def test_album(self):
|
||||
@ -137,6 +265,157 @@ class TrackTest(unittest.TestCase):
|
||||
track = Track(artists=[Artist(name=u'ABBA'), Artist(name=u'Beatles')])
|
||||
self.assertEqual(track.mpd_format_artists(), u'ABBA, Beatles')
|
||||
|
||||
def test_invalid_kwarg(self):
|
||||
test = lambda: Track(foo='baz')
|
||||
self.assertRaises(TypeError, test)
|
||||
|
||||
def test_eq_uri(self):
|
||||
track1 = Track(uri=u'uri1')
|
||||
track2 = Track(uri=u'uri1')
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq_name(self):
|
||||
track1 = Track(name=u'name1')
|
||||
track2 = Track(name=u'name1')
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq_artists(self):
|
||||
artists = [Artist()]
|
||||
track1 = Track(artists=artists)
|
||||
track2 = Track(artists=artists)
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq_artists_order(self):
|
||||
artist1 = Artist(name=u'name1')
|
||||
artist2 = Artist(name=u'name2')
|
||||
track1 = Track(artists=[artist1, artist2])
|
||||
track2 = Track(artists=[artist2, artist1])
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq_album(self):
|
||||
album = Album()
|
||||
track1 = Track(album=album)
|
||||
track2 = Track(album=album)
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq_track_no(self):
|
||||
track1 = Track(track_no=1)
|
||||
track2 = Track(track_no=1)
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq_date(self):
|
||||
date = dt.date.today()
|
||||
track1 = Track(date=date)
|
||||
track2 = Track(date=date)
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq_length(self):
|
||||
track1 = Track(length=100)
|
||||
track2 = Track(length=100)
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq_bitrate(self):
|
||||
track1 = Track(bitrate=100)
|
||||
track2 = Track(bitrate=100)
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq_id(self):
|
||||
track1 = Track(id=100)
|
||||
track2 = Track(id=100)
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq(self):
|
||||
date = dt.date.today()
|
||||
artists = [Artist()]
|
||||
album = Album()
|
||||
track1 = Track(uri=u'uri', name=u'name', artists=artists, album=album,
|
||||
track_no=1, date=date, length=100, bitrate=100, id=2)
|
||||
track2 = Track(uri=u'uri', name=u'name', artists=artists, album=album,
|
||||
track_no=1, date=date, length=100, bitrate=100, id=2)
|
||||
self.assertEqual(track1, track2)
|
||||
self.assertEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_eq_none(self):
|
||||
self.assertNotEqual(Track(), None)
|
||||
|
||||
def test_eq_other(self):
|
||||
self.assertNotEqual(Track(), 'other')
|
||||
|
||||
def test_ne_uri(self):
|
||||
track1 = Track(uri=u'uri1')
|
||||
track2 = Track(uri=u'uri2')
|
||||
self.assertNotEqual(track1, track2)
|
||||
self.assertNotEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_ne_name(self):
|
||||
track1 = Track(name=u'name1')
|
||||
track2 = Track(name=u'name2')
|
||||
self.assertNotEqual(track1, track2)
|
||||
self.assertNotEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_ne_artists(self):
|
||||
track1 = Track(artists=[Artist(name=u'name1')])
|
||||
track2 = Track(artists=[Artist(name=u'name2')])
|
||||
self.assertNotEqual(track1, track2)
|
||||
self.assertNotEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_ne_album(self):
|
||||
track1 = Track(album=Album(name=u'name1'))
|
||||
track2 = Track(album=Album(name=u'name2'))
|
||||
self.assertNotEqual(track1, track2)
|
||||
self.assertNotEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_ne_track_no(self):
|
||||
track1 = Track(track_no=1)
|
||||
track2 = Track(track_no=2)
|
||||
self.assertNotEqual(track1, track2)
|
||||
self.assertNotEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_ne_date(self):
|
||||
track1 = Track(date=dt.date.today())
|
||||
track2 = Track(date=dt.date.today()-dt.timedelta(days=1))
|
||||
self.assertNotEqual(track1, track2)
|
||||
self.assertNotEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_ne_length(self):
|
||||
track1 = Track(length=100)
|
||||
track2 = Track(length=200)
|
||||
self.assertNotEqual(track1, track2)
|
||||
self.assertNotEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_ne_bitrate(self):
|
||||
track1 = Track(bitrate=100)
|
||||
track2 = Track(bitrate=200)
|
||||
self.assertNotEqual(track1, track2)
|
||||
self.assertNotEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_ne_id(self):
|
||||
track1 = Track(id=100)
|
||||
track2 = Track(id=200)
|
||||
self.assertNotEqual(track1, track2)
|
||||
self.assertNotEqual(hash(track1), hash(track2))
|
||||
|
||||
def test_ne(self):
|
||||
track1 = Track(uri=u'uri1', name=u'name1',
|
||||
artists=[Artist(name=u'name1')], album=Album(name=u'name1'),
|
||||
track_no=1, date=dt.date.today(), length=100, bitrate=100, id=2)
|
||||
track2 = Track(uri=u'uri2', name=u'name2',
|
||||
artists=[Artist(name=u'name2')], album=Album(name=u'name2'),
|
||||
track_no=2, date=dt.date.today()-dt.timedelta(days=1),
|
||||
length=200, bitrate=200, id=1)
|
||||
self.assertNotEqual(track1, track2)
|
||||
self.assertNotEqual(hash(track1), hash(track2))
|
||||
|
||||
|
||||
class PlaylistTest(unittest.TestCase):
|
||||
def test_uri(self):
|
||||
@ -241,3 +520,11 @@ class PlaylistTest(unittest.TestCase):
|
||||
self.assertEqual(new_playlist.name, u'a name')
|
||||
self.assertEqual(new_playlist.tracks, tracks)
|
||||
self.assertEqual(new_playlist.last_modified, new_last_modified)
|
||||
|
||||
def test_invalid_kwarg(self):
|
||||
test = lambda: Playlist(foo='baz')
|
||||
self.assertRaises(TypeError, test)
|
||||
|
||||
def test_eq(self):
|
||||
# FIXME missing all equal and hash tests
|
||||
raise SkipTest
|
||||
|
||||
@ -5,7 +5,10 @@ import tempfile
|
||||
import unittest
|
||||
import urllib
|
||||
|
||||
from mopidy.utils import m3u_to_uris
|
||||
from mopidy.utils import parse_m3u, parse_mpd_tag_cache
|
||||
from mopidy.models import Track, Artist, Album
|
||||
|
||||
from tests import SkipTest
|
||||
|
||||
def data(name):
|
||||
folder = os.path.dirname(__file__)
|
||||
@ -17,31 +20,30 @@ def data(name):
|
||||
song1_path = data('song1.mp3')
|
||||
song2_path = data('song2.mp3')
|
||||
encoded_path = data(u'æøå.mp3')
|
||||
song1_uri = 'file:' + urllib.pathname2url(song1_path)
|
||||
song2_uri = 'file:' + urllib.pathname2url(song2_path)
|
||||
encoded_uri = 'file:' + urllib.pathname2url(encoded_path.encode('utf-8'))
|
||||
song1_uri = 'file://' + urllib.pathname2url(song1_path)
|
||||
song2_uri = 'file://' + urllib.pathname2url(song2_path)
|
||||
encoded_uri = 'file://' + urllib.pathname2url(encoded_path.encode('utf-8'))
|
||||
|
||||
|
||||
class M3UToUriTest(unittest.TestCase):
|
||||
def test_empty_file(self):
|
||||
uris = m3u_to_uris(data('empty.m3u'))
|
||||
uris = parse_m3u(data('empty.m3u'))
|
||||
self.assertEqual([], uris)
|
||||
|
||||
def test_basic_file(self):
|
||||
uris = m3u_to_uris(data('one.m3u'))
|
||||
uris = parse_m3u(data('one.m3u'))
|
||||
self.assertEqual([song1_uri], uris)
|
||||
|
||||
def test_file_with_comment(self):
|
||||
uris = m3u_to_uris(data('comment.m3u'))
|
||||
uris = parse_m3u(data('comment.m3u'))
|
||||
self.assertEqual([song1_uri], uris)
|
||||
|
||||
def test_file_with_absolute_files(self):
|
||||
with tempfile.NamedTemporaryFile() as file:
|
||||
file.write(song1_path)
|
||||
file.flush()
|
||||
|
||||
uris = m3u_to_uris(file.name)
|
||||
self.assertEqual([song1_uri], uris)
|
||||
uris = parse_m3u(file.name)
|
||||
self.assertEqual([song1_uri], uris)
|
||||
|
||||
def test_file_with_multiple_absolute_files(self):
|
||||
with tempfile.NamedTemporaryFile() as file:
|
||||
@ -49,18 +51,67 @@ class M3UToUriTest(unittest.TestCase):
|
||||
file.write('# comment \n')
|
||||
file.write(song2_path)
|
||||
file.flush()
|
||||
|
||||
uris = m3u_to_uris(file.name)
|
||||
self.assertEqual([song1_uri, song2_uri], uris)
|
||||
uris = parse_m3u(file.name)
|
||||
self.assertEqual([song1_uri, song2_uri], uris)
|
||||
|
||||
def test_file_with_uri(self):
|
||||
with tempfile.NamedTemporaryFile() as file:
|
||||
file.write(song1_uri)
|
||||
file.flush()
|
||||
|
||||
uris = m3u_to_uris(file.name)
|
||||
self.assertEqual([song1_uri], uris)
|
||||
uris = parse_m3u(file.name)
|
||||
self.assertEqual([song1_uri], uris)
|
||||
|
||||
def test_encoding_is_latin1(self):
|
||||
uris = m3u_to_uris(data('encoding.m3u'))
|
||||
uris = parse_m3u(data('encoding.m3u'))
|
||||
self.assertEqual([encoded_uri], uris)
|
||||
|
||||
expected_artists = [Artist(name='name')]
|
||||
expected_albums = [Album(name='albumname', artists=expected_artists, num_tracks=2)]
|
||||
expected_tracks = []
|
||||
|
||||
def generate_track(path):
|
||||
uri = 'file://' + urllib.pathname2url(data(path))
|
||||
track = Track(name='trackname', artists=expected_artists, track_no=1,
|
||||
album=expected_albums[0], length=4000, uri=uri)
|
||||
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')
|
||||
|
||||
class MPDTagCacheToTracksTest(unittest.TestCase):
|
||||
def test_emtpy_cache(self):
|
||||
tracks, artists, albums = parse_mpd_tag_cache(data('empty_tag_cache'),
|
||||
data(''))
|
||||
self.assertEqual(set(), tracks)
|
||||
self.assertEqual(set(), artists)
|
||||
self.assertEqual(set(), albums)
|
||||
|
||||
def test_simple_cache(self):
|
||||
tracks, artists, albums = parse_mpd_tag_cache(data('simple_tag_cache'),
|
||||
data(''))
|
||||
|
||||
self.assertEqual(expected_tracks[0], list(tracks)[0])
|
||||
self.assertEqual(set(expected_artists), artists)
|
||||
self.assertEqual(set(expected_albums), albums)
|
||||
|
||||
def test_advanced_cache(self):
|
||||
tracks, artists, albums = parse_mpd_tag_cache(data('advanced_tag_cache'),
|
||||
data(''))
|
||||
|
||||
self.assertEqual(set(expected_tracks), tracks)
|
||||
self.assertEqual(set(expected_artists), artists)
|
||||
self.assertEqual(set(expected_albums), albums)
|
||||
|
||||
def test_unicode_cache(self):
|
||||
raise SkipTest
|
||||
|
||||
def test_misencoded_cache(self):
|
||||
# FIXME not sure if this can happen
|
||||
raise SkipTest
|
||||
|
||||
Loading…
Reference in New Issue
Block a user