def test_utf8_in_path(self): if sys.platform == 'win32': result = path.path_to_uri('C:/æøå'.encode('utf-8')) self.assertEqual(result, 'file:///C://%C3%A6%C3%B8%C3%A5') else: result = path.path_to_uri('/tmp/æøå'.encode('utf-8')) self.assertEqual(result, 'file:///tmp/%C3%A6%C3%B8%C3%A5')
def test_simple_path(self): if sys.platform == 'win32': result = path_to_uri(u'C:/WINDOWS/clock.avi') self.assertEqual(result, 'file:///C://WINDOWS/clock.avi') else: result = path_to_uri(u'/etc/fstab') self.assertEqual(result, 'file:///etc/fstab')
def test_latin1_in_path(self): if sys.platform == 'win32': result = path.path_to_uri('C:/æøå'.encode('latin-1')) self.assertEqual(result, 'file:///C://%E6%F8%E5') else: result = path.path_to_uri('/tmp/æøå'.encode('latin-1')) self.assertEqual(result, 'file:///tmp/%E6%F8%E5')
def test_unicode_in_path(self): if sys.platform == 'win32': result = path.path_to_uri(u'C:/æøå') self.assertEqual(result, 'file:///C://%C3%A6%C3%B8%C3%A5') else: result = path.path_to_uri(u'/tmp/æøå') self.assertEqual(result, u'file:///tmp/%C3%A6%C3%B8%C3%A5')
def test_folder_and_path(self): if sys.platform == 'win32': result = path_to_uri(u'C:/WINDOWS/', u'clock.avi') self.assertEqual(result, 'file:///C://WINDOWS/clock.avi') else: result = path_to_uri(u'/etc', u'fstab') self.assertEqual(result, u'file:///etc/fstab')
def test_unicode_in_path(self): if sys.platform == "win32": result = path_to_uri(u"C:/æøå") self.assertEqual(result, "file:///C://%C3%A6%C3%B8%C3%A5") else: result = path_to_uri(u"/tmp/æøå") self.assertEqual(result, u"file:///tmp/%C3%A6%C3%B8%C3%A5")
def test_space_in_path(self): if sys.platform == 'win32': result = path.path_to_uri('C:/test this') self.assertEqual(result, 'file:///C://test%20this') else: result = path.path_to_uri('/tmp/test this') self.assertEqual(result, 'file:///tmp/test%20this')
def test_space_in_path(self): if sys.platform == 'win32': result = path_to_uri(u'C:/test this') self.assertEqual(result, 'file:///C://test%20this') else: result = path_to_uri(u'/tmp/test this') self.assertEqual(result, u'file:///tmp/test%20this')
def test_folder_and_path(self): if sys.platform == "win32": result = path_to_uri(u"C:/WINDOWS/", u"clock.avi") self.assertEqual(result, "file:///C://WINDOWS/clock.avi") else: result = path_to_uri(u"/etc", u"fstab") self.assertEqual(result, u"file:///etc/fstab")
def test_space_in_path(self): if sys.platform == "win32": result = path_to_uri(u"C:/test this") self.assertEqual(result, "file:///C://test%20this") else: result = path_to_uri(u"/tmp/test this") self.assertEqual(result, u"file:///tmp/test%20this")
def test_unicode_in_path(self): if sys.platform == 'win32': result = path_to_uri(u'C:/æøå') self.assertEqual(result, 'file:///C://%C3%A6%C3%B8%C3%A5') else: result = path_to_uri(u'/tmp/æøå') self.assertEqual(result, u'file:///tmp/%C3%A6%C3%B8%C3%A5')
def test_dir_and_path(self): if sys.platform == 'win32': result = path.path_to_uri('C:/WINDOWS/', 'clock.avi') self.assertEqual(result, 'file:///C://WINDOWS/clock.avi') else: result = path.path_to_uri('/etc', 'fstab') self.assertEqual(result, 'file:///etc/fstab')
def test_simple_path(self): if sys.platform == 'win32': result = path.path_to_uri(u'C:/WINDOWS/clock.avi') self.assertEqual(result, 'file:///C://WINDOWS/clock.avi') else: result = path.path_to_uri(u'/etc/fstab') self.assertEqual(result, 'file:///etc/fstab')
def test_playlists_are_loaded_at_startup(self): playlist_path = os.path.join(settings.LOCAL_PLAYLIST_PATH, 'test.m3u') track = Track(uri=path_to_uri(path_to_data_dir('uri2'))) playlist = self.core.playlists.create('test') playlist = playlist.copy(tracks=[track]) playlist = self.core.playlists.save(playlist) backend = self.backend_class(audio=self.audio) self.assert_(backend.playlists.playlists) self.assertEqual(path_to_uri(playlist_path), backend.playlists.playlists[0].uri) self.assertEqual(playlist.name, backend.playlists.playlists[0].name) self.assertEqual(track.uri, backend.playlists.playlists[0].tracks[0].uri)
def test_albumartist_tag_cache(self): tracks = parse_mpd_tag_cache(path_to_data_dir("albumartist_tag_cache"), path_to_data_dir("")) uri = path_to_uri(path_to_data_dir("song1.mp3")) artist = Artist(name="albumartistname") album = expected_albums[0].copy(artists=[artist]) track = Track(name="trackname", artists=expected_artists, track_no=1, album=album, length=4000, uri=uri) self.assertEqual(track, list(tracks)[0])
def test_simple_cache(self): tracks = parse_mpd_tag_cache(path_to_data_dir('simple_tag_cache'), path_to_data_dir('')) uri = path_to_uri(path_to_data_dir('song1.mp3')) track = Track(name='trackname', artists=expected_artists, track_no=1, album=expected_albums[0], length=4000, uri=uri) self.assertEqual(set([track]), tracks)
def change_track(self, track): media_dir = self.backend.config['local']['media_dir'] # TODO: check that type is correct. file_path = path.uri_to_path(track.uri).split(b':', 1)[1] file_path = os.path.join(media_dir, file_path) track = track.copy(uri=path.path_to_uri(file_path)) return super(LocalPlaybackProvider, self).change_track(track)
def _convert_mpd_data(data, tracks, music_dir): if not data: return track_kwargs = {} album_kwargs = {} artist_kwargs = {} albumartist_kwargs = {} if "track" in data: album_kwargs["num_tracks"] = int(data["track"].split("/")[1]) track_kwargs["track_no"] = int(data["track"].split("/")[0]) if "artist" in data: artist_kwargs["name"] = data["artist"] albumartist_kwargs["name"] = data["artist"] if "albumartist" in data: albumartist_kwargs["name"] = data["albumartist"] if "album" in data: album_kwargs["name"] = data["album"] if "title" in data: track_kwargs["name"] = data["title"] if "musicbrainz_trackid" in data: track_kwargs["musicbrainz_id"] = data["musicbrainz_trackid"] if "musicbrainz_albumid" in data: album_kwargs["musicbrainz_id"] = data["musicbrainz_albumid"] if "musicbrainz_artistid" in data: artist_kwargs["musicbrainz_id"] = data["musicbrainz_artistid"] if "musicbrainz_albumartistid" in data: albumartist_kwargs["musicbrainz_id"] = data["musicbrainz_albumartistid"] if data["file"][0] == "/": path = data["file"][1:] else: path = data["file"] if artist_kwargs: artist = Artist(**artist_kwargs) track_kwargs["artists"] = [artist] if albumartist_kwargs: albumartist = Artist(**albumartist_kwargs) album_kwargs["artists"] = [albumartist] if album_kwargs: album = Album(**album_kwargs) track_kwargs["album"] = album track_kwargs["uri"] = path_to_uri(music_dir, path) track_kwargs["length"] = int(data.get("time", 0)) * 1000 track = Track(**track_kwargs) tracks.add(track)
def refresh(self): playlists = [] for m3u in glob.glob(os.path.join(self._playlists_dir, '*.m3u')): uri = path.path_to_uri(m3u) name = os.path.splitext(os.path.basename(m3u))[0] tracks = [] for track_uri in parse_m3u(m3u, self._media_dir): try: # TODO We must use core.library.lookup() to support tracks # from other backends tracks += self.backend.library.lookup(track_uri) except LookupError as ex: logger.warning('Playlist item could not be added: %s', ex) playlist = Playlist(uri=uri, name=name, tracks=tracks) playlists.append(playlist) self.playlists = playlists listener.BackendListener.send('playlists_loaded') logger.info( 'Loaded %d local playlists from %s', len(playlists), self._playlists_dir)
def test_simple_cache(self): tracks = parse_mpd_tag_cache( path_to_data_dir('simple_tag_cache'), path_to_data_dir('')) uri = path_to_uri(path_to_data_dir('song1.mp3')) track = Track( uri=uri, name='trackname', artists=expected_artists, track_no=1, album=expected_albums[0], date='2006', length=4000) self.assertEqual(set([track]), tracks)
def parse_m3u(file_path, media_dir): r""" Convert M3U file list of uris Example M3U data:: # This is a comment Alternative\Band - Song.mp3 Classical\Other Band - New Song.mp3 Stuff.mp3 D:\More Music\Foo.mp3 http://www.example.com:8000/Listen.pls http://www.example.com/~user/Mine.mp3 - Relative paths of songs should be with respect to location of M3U. - Paths are normaly platform specific. - Lines starting with # should be ignored. - m3u files are latin-1. - This function does not bother with Extended M3U directives. """ # TODO: uris as bytes uris = [] try: with open(file_path) as m3u: contents = m3u.readlines() except IOError as error: logger.warning('Couldn\'t open m3u: %s', locale_decode(error)) return uris for line in contents: line = line.strip().decode('latin1') if line.startswith('#'): continue if urlparse.urlsplit(line).scheme: uris.append(line) elif os.path.normpath(line) == os.path.abspath(line): path = path_to_uri(line) uris.append(path) else: path = path_to_uri(os.path.join(media_dir, line)) uris.append(path) return uris
def test_albumartist_tag_cache(self): tracks = parse_mpd_tag_cache(data_folder('albumartist_tag_cache'), data_folder('')) uri = path_to_uri(data_folder('song1.mp3')) artist = Artist(name='albumartistname') album = expected_albums[0].copy(artists=[artist]) track = Track(name='trackname', artists=expected_artists, track_no=1, album=album, length=4000, uri=uri) self.assertEqual(track, list(tracks)[0])
def generate_track(path, ident): uri = path_to_uri(path_to_data_dir(path)) track = Track(name='trackname', artists=expected_artists, track_no=1, album=expected_albums[0], length=4000, uri=uri) expected_tracks.append(track)
def scan(self, paths): scanner = scan.Scanner() for path in paths: uri = path_lib.path_to_uri(path) key = uri[len('file://'):] try: self.result[key] = scanner.scan(uri) except exceptions.ScannerError as error: self.errors[key] = error
def test_playlists_are_loaded_at_startup(self): playlist_path = os.path.join(self.playlists_dir, 'test.m3u') track = Track(uri=path_to_uri(path_to_data_dir('uri2'))) playlist = self.core.playlists.create('test') playlist = playlist.copy(tracks=[track]) playlist = self.core.playlists.save(playlist) backend = self.backend_class(config=self.config, audio=self.audio) self.assert_(backend.playlists.playlists) self.assertEqual( path_to_uri(playlist_path), backend.playlists.playlists[0].uri) self.assertEqual( playlist.name, backend.playlists.playlists[0].name) self.assertEqual( track.uri, backend.playlists.playlists[0].tracks[0].uri)
def test_unicode_cache(self): tracks = parse_mpd_tag_cache(path_to_data_dir("utf8_tag_cache"), path_to_data_dir("")) uri = path_to_uri(path_to_data_dir("song1.mp3")) artists = [Artist(name=u"æøå")] album = Album(name=u"æøå", artists=artists) track = Track(uri=uri, name=u"æøå", artists=artists, album=album, length=4000) self.assertEqual(track, list(tracks)[0])
def scan(self, paths): scanner = scan.Scanner() for path in paths: uri = path_lib.path_to_uri(path) key = uri[len('file://'):] try: self.data[key] = scanner.scan(uri) except exceptions.ScannerError as error: self.errors[key] = error
def setUp(self): config = { 'audio': { 'mixer': 'fakemixer track_max_volume=65536', 'mixer_track': None, 'output': 'fakesink', } } self.song_uri = path_to_uri(path_to_data_dir('song1.wav')) self.audio = audio.Audio.start(config=config).proxy()
def test_albumartist_tag_cache(self): tracks = parse_mpd_tag_cache( path_to_data_dir('albumartist_tag_cache'), path_to_data_dir('')) uri = path_to_uri(path_to_data_dir('song1.mp3')) artist = Artist(name='albumartistname') album = expected_albums[0].copy(artists=[artist]) track = Track( uri=uri, name='trackname', artists=expected_artists, track_no=1, album=album, date='2006', length=4000) self.assertEqual(track, list(tracks)[0])
def next_uri(self): try: uri = path_to_uri(self.files.next()) except StopIteration: self.stop() return False self.pipe.set_state(gst.STATE_NULL) self.uribin.set_property('uri', uri) self.pipe.set_state(gst.STATE_PAUSED) return True
def _rename_m3u(self, playlist): src_file_path = path.uri_to_path(playlist.uri) path.check_file_path_is_inside_base_dir(src_file_path, self._path) dst_file_path = self._get_m3u_path(playlist.name) path.check_file_path_is_inside_base_dir(dst_file_path, self._path) shutil.move(src_file_path, dst_file_path) return playlist.copy(uri=path.path_to_uri(dst_file_path))
def scan(self, path): paths = path_lib.find_files(path_to_data_dir(path)) uris = (path_lib.path_to_uri(p) for p in paths) scanner = scan.Scanner() for uri in uris: key = uri[len('file://'):] try: self.data[key] = scanner.scan(uri) except exceptions.ScannerError as error: self.errors[key] = error
def test_unicode_cache(self): tracks = parse_mpd_tag_cache(data_folder('utf8_tag_cache'), data_folder('')) uri = path_to_uri(data_folder('song1.mp3')) artists = [Artist(name=u'æøå')] album = Album(name=u'æøå', artists=artists) track = Track(uri=uri, name=u'æøå', artists=artists, album=album, length=4000) self.assertEqual(track, list(tracks)[0])
def test_unicode_cache(self): tracks = parse_mpd_tag_cache( path_to_data_dir('utf8_tag_cache'), path_to_data_dir('')) uri = path_to_uri(path_to_data_dir('song1.mp3')) artists = [Artist(name='æøå')] album = Album(name='æøå', artists=artists) track = Track( uri=uri, name='æøå', artists=artists, album=album, length=4000) self.assertEqual(track, list(tracks)[0])
def scan(self, paths): scanner = scan.Scanner() for path in paths: uri = path_lib.path_to_uri(path) key = uri[len('file://'):] try: result = scanner.scan(uri) self.tags[key] = result.tags self.durations[key] = result.duration except exceptions.ScannerError as error: self.errors[key] = error
def next_uri(self): self.data = {} try: uri = path.path_to_uri(self.files.next()) except StopIteration: self.stop() return False self.pipe.set_state(gst.STATE_NULL) self.uribin.set_property("uri", uri) self.pipe.set_state(gst.STATE_PLAYING) return True
class BaseTest(unittest.TestCase): config = { 'audio': { 'mixer': 'fakemixer track_max_volume=65536', 'mixer_track': None, 'mixer_volume': None, 'output': 'testoutput', 'visualizer': None, } } uris = [ path_to_uri(path_to_data_dir('song1.wav')), path_to_uri(path_to_data_dir('song2.wav')) ] audio_class = audio.Audio def setUp(self): # noqa: N802 config = { 'audio': { 'mixer': 'foomixer', 'mixer_volume': None, 'output': 'testoutput', 'visualizer': None, }, 'proxy': { 'hostname': '', }, } self.song_uri = path_to_uri(path_to_data_dir('song1.wav')) self.audio = self.audio_class.start(config=config, mixer=None).proxy() def tearDown(self): # noqa pykka.ActorRegistry.stop_all() def possibly_trigger_fake_playback_error(self): pass def possibly_trigger_fake_about_to_finish(self): pass
def test_playlists_are_loaded_at_startup(self): track = Track(uri=path_to_uri(path_to_data_dir('uri2'))) playlist = Playlist(tracks=[track], name='test') self.stored.save(playlist) self.backend = self.backend_class() self.stored = self.backend.stored_playlists self.assert_(self.stored.playlists) self.assertEqual('test', self.stored.playlists[0].name) self.assertEqual(track.uri, self.stored.playlists[0].tracks[0].uri)
def test_playlists_are_loaded_at_startup(self): track = Track(uri=path_to_uri(data_folder("uri2"))) playlist = Playlist(tracks=[track], name="test") self.stored.save(playlist) self.backend.destroy() self.backend = self.backend_class(mixer_class=DummyMixer) self.stored = self.backend.stored_playlists self.assert_(self.stored.playlists) self.assertEqual("test", self.stored.playlists[0].name) self.assertEqual(track.uri, self.stored.playlists[0].tracks[0].uri)
def setUp(self): config = { 'audio': { 'mixer': 'foomixer', 'mixer_volume': None, 'output': 'fakesink', 'visualizer': None, }, 'proxy': { 'hostname': '', }, } self.song_uri = path_to_uri(path_to_data_dir('song1.wav')) self.audio = audio.Audio.start(config=config, mixer=None).proxy()
def setUp(self): # noqa: N802 config = { 'audio': { 'mixer': 'foomixer', 'mixer_volume': None, 'output': 'testoutput', 'visualizer': None, }, 'proxy': { 'hostname': '', }, } self.song_uri = path_to_uri(path_to_data_dir('song1.wav')) self.audio = self.audio_class.start(config=config, mixer=None).proxy()
def parse_m3u(file_path, music_folder): """ Convert M3U file list of uris Example M3U data:: # This is a comment Alternative\Band - Song.mp3 Classical\Other Band - New Song.mp3 Stuff.mp3 D:\More Music\Foo.mp3 http://www.example.com:8000/Listen.pls http://www.example.com/~user/Mine.mp3 - Relative paths of songs should be with respect to location of M3U. - Paths are normaly platform specific. - Lines starting with # should be ignored. - m3u files are latin-1. - This function does not bother with Extended M3U directives. """ uris = [] try: with open(file_path) as m3u: contents = m3u.readlines() except IOError as error: logger.error('Couldn\'t open m3u: %s', locale_decode(error)) return uris for line in contents: line = line.strip().decode('latin1') if line.startswith('#'): continue # FIXME what about other URI types? if line.startswith('file://'): uris.append(line) else: path = path_to_uri(music_folder, line) uris.append(path) return uris
def __init__(self, folder, data_callback, error_callback=None): self.uris = [path_to_uri(f) for f in find_files(folder)] self.data_callback = data_callback self.error_callback = error_callback self.loop = gobject.MainLoop() fakesink = gst.element_factory_make('fakesink') self.uribin = gst.element_factory_make('uridecodebin') self.uribin.set_property('caps', gst.Caps('audio/x-raw-int')) self.uribin.connect('pad-added', self.process_new_pad, fakesink.get_pad('sink')) self.pipe = gst.element_factory_make('pipeline') self.pipe.add(self.uribin) self.pipe.add(fakesink) bus = self.pipe.get_bus() bus.add_signal_watch() bus.connect('message::tag', self.process_tags) bus.connect('message::error', self.process_error)
def refresh(self): logger.info('Loading playlists from %s', self._path) playlists = [] for m3u in glob.glob(os.path.join(self._path, '*.m3u')): uri = path.path_to_uri(m3u) name = os.path.splitext(os.path.basename(m3u))[0] tracks = [] for track_uri in parse_m3u(m3u, settings.LOCAL_MUSIC_PATH): try: # TODO We must use core.library.lookup() to support tracks # from other backends tracks += self.backend.library.lookup(track_uri) except LookupError as ex: logger.warning('Playlist item could not be added: %s', ex) playlist = Playlist(uri=uri, name=name, tracks=tracks) playlists.append(playlist) self.playlists = playlists listener.BackendListener.send('playlists_loaded')
def test_latin1_in_path(self): result = path.path_to_uri('/tmp/æøå'.encode('latin-1')) self.assertEqual(result, 'file:///tmp/%E6%F8%E5')
def test_file(self): uris = self.find('blank.mp3') expected = path.path_to_uri(path_to_data_dir('blank.mp3')) self.assertEqual(len(uris), 1) self.assertEqual(uris[0], expected)
def test_cache_with_blank_track_info(self): tracks = parse_mpd_tag_cache(path_to_data_dir('blank_tag_cache'), path_to_data_dir('')) uri = path_to_uri(path_to_data_dir('song1.mp3')) self.assertEqual(set([Track(uri=uri, length=4000)]), tracks)
from __future__ import unicode_literals import os import tempfile from mopidy.backends.local.translator import parse_m3u, parse_mpd_tag_cache from mopidy.models import Track, Artist, Album from mopidy.utils.path import path_to_uri from tests import unittest, path_to_data_dir data_dir = path_to_data_dir('') song1_path = path_to_data_dir('song1.mp3') song2_path = path_to_data_dir('song2.mp3') encoded_path = path_to_data_dir('æøå.mp3') song1_uri = path_to_uri(song1_path) song2_uri = path_to_uri(song2_path) encoded_uri = path_to_uri(encoded_path) # FIXME use mock instead of tempfile.NamedTemporaryFile class M3UToUriTest(unittest.TestCase): def test_empty_file(self): uris = parse_m3u(path_to_data_dir('empty.m3u'), data_dir) self.assertEqual([], uris) def test_basic_file(self): uris = parse_m3u(path_to_data_dir('one.m3u'), data_dir) self.assertEqual([song1_uri], uris)
def run(self, args, config): media_dir = config['local']['media_dir'] scan_timeout = config['local']['scan_timeout'] flush_threshold = config['local']['scan_flush_threshold'] excluded_file_extensions = config['local']['excluded_file_extensions'] excluded_file_extensions = tuple( bytes(file_ext.lower()) for file_ext in excluded_file_extensions) library = _get_library(args, config) file_mtimes, file_errors = path.find_mtimes( media_dir, follow=config['local']['scan_follow_symlinks']) logger.info('Found %d files in media_dir.', len(file_mtimes)) if file_errors: logger.warning('Encountered %d errors while scanning media_dir.', len(file_errors)) for name in file_errors: logger.debug('Scan error %r for %r', file_errors[name], name) num_tracks = library.load() logger.info('Checking %d tracks from library.', num_tracks) uris_to_update = set() uris_to_remove = set() uris_in_library = set() for track in library.begin(): abspath = translator.local_track_uri_to_path(track.uri, media_dir) mtime = file_mtimes.get(abspath) if mtime is None: logger.debug('Missing file %s', track.uri) uris_to_remove.add(track.uri) elif mtime > track.last_modified or args.force: uris_to_update.add(track.uri) uris_in_library.add(track.uri) logger.info('Removing %d missing tracks.', len(uris_to_remove)) for uri in uris_to_remove: library.remove(uri) for abspath in file_mtimes: relpath = os.path.relpath(abspath, media_dir) uri = translator.path_to_local_track_uri(relpath) if b'/.' in relpath: logger.debug('Skipped %s: Hidden directory/file.', uri) elif relpath.lower().endswith(excluded_file_extensions): logger.debug('Skipped %s: File extension excluded.', uri) elif uri not in uris_in_library: uris_to_update.add(uri) logger.info('Found %d tracks which need to be updated.', len(uris_to_update)) logger.info('Scanning...') uris_to_update = sorted(uris_to_update, key=lambda v: v.lower()) uris_to_update = uris_to_update[:args.limit] scanner = scan.Scanner(scan_timeout) progress = _Progress(flush_threshold, len(uris_to_update)) for uri in uris_to_update: try: relpath = translator.local_track_uri_to_path(uri, media_dir) file_uri = path.path_to_uri(os.path.join(media_dir, relpath)) result = scanner.scan(file_uri) tags, duration = result.tags, result.duration if not result.playable: logger.warning('Failed %s: No audio found in file.', uri) elif duration < MIN_DURATION_MS: logger.warning('Failed %s: Track shorter than %dms', uri, MIN_DURATION_MS) else: mtime = file_mtimes.get(os.path.join(media_dir, relpath)) track = utils.convert_tags_to_track(tags).copy( uri=uri, length=duration, last_modified=mtime) if library.add_supports_tags_and_duration: library.add(track, tags=tags, duration=duration) else: library.add(track) logger.debug('Added %s', track.uri) except exceptions.ScannerError as error: logger.warning('Failed %s: %s', uri, error) if progress.increment(): progress.log() if library.flush(): logger.debug('Progress flushed.') progress.log() library.close() logger.info('Done scanning.') return 0