From 69dc639ab350a9eae08c7645d55ac1a619ec6b1f Mon Sep 17 00:00:00 2001 From: Giorgos Logiotatidis Date: Fri, 29 May 2015 20:25:27 +0300 Subject: [PATCH] Support loading of m3u8 playlists. Unicode is nice, let's support it! --- mopidy/m3u/playlists.py | 2 +- mopidy/m3u/translator.py | 12 ++++++++---- tests/m3u/test_translator.py | 13 +++++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/mopidy/m3u/playlists.py b/mopidy/m3u/playlists.py index 33281129..e96c0412 100644 --- a/mopidy/m3u/playlists.py +++ b/mopidy/m3u/playlists.py @@ -63,7 +63,7 @@ class M3UPlaylistsProvider(backend.PlaylistsProvider): playlists = {} encoding = sys.getfilesystemencoding() - for path in glob.glob(os.path.join(self._playlists_dir, b'*.m3u')): + for path in glob.glob(os.path.join(self._playlists_dir, b'*.m3u*')): relpath = os.path.basename(path) uri = translator.path_to_playlist_uri(relpath) name = os.path.splitext(relpath)[0].decode(encoding, 'replace') diff --git a/mopidy/m3u/translator.py b/mopidy/m3u/translator.py index a6e006b1..908e218f 100644 --- a/mopidy/m3u/translator.py +++ b/mopidy/m3u/translator.py @@ -74,11 +74,14 @@ def parse_m3u(file_path, media_dir=None): - Lines starting with # are ignored, except for extended M3U directives. - Track.name and Track.length are set from extended M3U directives. - m3u files are latin-1. + - m3u8 files are utf-8 """ # TODO: uris as bytes + file_encoding = 'utf-8' if file_path.endswith(b'.m3u8') else 'latin1' + tracks = [] try: - with open(file_path) as m3u: + with codecs.open(file_path, 'rb', file_encoding, 'replace') as m3u: contents = m3u.readlines() except IOError as error: logger.warning('Couldn\'t open m3u: %s', locale_decode(error)) @@ -87,12 +90,13 @@ def parse_m3u(file_path, media_dir=None): if not contents: return tracks - extended = contents[0].decode('latin1').startswith('#EXTM3U') + # Strip newlines left by codecs + contents = [line.strip() for line in contents] + + extended = contents[0].startswith('#EXTM3U') track = Track() for line in contents: - line = line.strip().decode('latin1') - if line.startswith('#'): if extended and line.startswith('#EXTINF'): track = m3u_extinf_to_track(line) diff --git a/tests/m3u/test_translator.py b/tests/m3u/test_translator.py index fc7fc958..bacb589f 100644 --- a/tests/m3u/test_translator.py +++ b/tests/m3u/test_translator.py @@ -15,12 +15,15 @@ from tests import 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') +song3_path = path_to_data_dir('φοο.mp3') encoded_path = path_to_data_dir('æøå.mp3') song1_uri = path.path_to_uri(song1_path) song2_uri = path.path_to_uri(song2_path) +song3_uri = path.path_to_uri(song3_path) encoded_uri = path.path_to_uri(encoded_path) song1_track = Track(uri=song1_uri) song2_track = Track(uri=song2_uri) +song3_track = Track(uri=song3_uri) encoded_track = Track(uri=encoded_uri) song1_ext_track = song1_track.copy(name='song1') song2_ext_track = song2_track.copy(name='song2', length=60000) @@ -115,6 +118,16 @@ class M3UToUriTest(unittest.TestCase): tracks = self.parse(path_to_data_dir('encoding-ext.m3u')) self.assertEqual([encoded_ext_track], tracks) + def test_m3u8_file(self): + with tempfile.NamedTemporaryFile(suffix='.m3u8', delete=False) as tmp: + tmp.write(song3_path) + try: + tracks = self.parse(tmp.name) + self.assertEqual([song3_track], tracks) + finally: + if os.path.exists(tmp.name): + os.remove(tmp.name) + class URItoM3UTest(unittest.TestCase): pass