Merge branch 'v1.0.x' into develop
This commit is contained in:
commit
10b0796bbd
@ -63,7 +63,7 @@ Internal changes
|
|||||||
:issue:`1115`)
|
:issue:`1115`)
|
||||||
|
|
||||||
|
|
||||||
v1.0.5 (UNRELEASED)
|
v1.0.5 (2015-05-19)
|
||||||
===================
|
===================
|
||||||
|
|
||||||
Bug fix release.
|
Bug fix release.
|
||||||
@ -71,6 +71,9 @@ Bug fix release.
|
|||||||
- Core: Add workaround for playlist providers that do not support
|
- Core: Add workaround for playlist providers that do not support
|
||||||
creating playlists. (Fixes: :issue:`1162`, PR :issue:`1165`)
|
creating playlists. (Fixes: :issue:`1162`, PR :issue:`1165`)
|
||||||
|
|
||||||
|
- M3U: Fix encoding error when saving playlists with non-ASCII track
|
||||||
|
titles. (Fixes: :issue:`1175`, PR :issue:`1176`)
|
||||||
|
|
||||||
|
|
||||||
v1.0.4 (2015-04-30)
|
v1.0.4 (2015-04-30)
|
||||||
===================
|
===================
|
||||||
|
|||||||
@ -14,4 +14,4 @@ if not (2, 7) <= sys.version_info < (3,):
|
|||||||
warnings.filterwarnings('ignore', 'could not open display')
|
warnings.filterwarnings('ignore', 'could not open display')
|
||||||
|
|
||||||
|
|
||||||
__version__ = '1.0.4'
|
__version__ = '1.0.5'
|
||||||
|
|||||||
@ -90,11 +90,6 @@ class M3UPlaylistsProvider(backend.PlaylistsProvider):
|
|||||||
self._playlists[playlist.uri] = playlist
|
self._playlists[playlist.uri] = playlist
|
||||||
return playlist
|
return playlist
|
||||||
|
|
||||||
def _write_m3u_extinf(self, file_handle, track):
|
|
||||||
title = track.name.encode('latin-1', 'replace')
|
|
||||||
runtime = track.length // 1000 if track.length else -1
|
|
||||||
file_handle.write('#EXTINF:' + str(runtime) + ',' + title + '\n')
|
|
||||||
|
|
||||||
def _sanitize_m3u_name(self, name, encoding=sys.getfilesystemencoding()):
|
def _sanitize_m3u_name(self, name, encoding=sys.getfilesystemencoding()):
|
||||||
name = self._invalid_filename_chars.sub('|', name.strip())
|
name = self._invalid_filename_chars.sub('|', name.strip())
|
||||||
# make sure we end up with a valid path segment
|
# make sure we end up with a valid path segment
|
||||||
@ -115,15 +110,6 @@ class M3UPlaylistsProvider(backend.PlaylistsProvider):
|
|||||||
name, _ = os.path.splitext(os.path.basename(path).decode(encoding))
|
name, _ = os.path.splitext(os.path.basename(path).decode(encoding))
|
||||||
else:
|
else:
|
||||||
raise ValueError('M3U playlist needs name or URI')
|
raise ValueError('M3U playlist needs name or URI')
|
||||||
extended = any(track.name for track in playlist.tracks)
|
translator.save_m3u(path, playlist.tracks, 'latin1')
|
||||||
|
|
||||||
with open(path, 'w') as file_handle:
|
|
||||||
if extended:
|
|
||||||
file_handle.write('#EXTM3U\n')
|
|
||||||
for track in playlist.tracks:
|
|
||||||
if extended and track.name:
|
|
||||||
self._write_m3u_extinf(file_handle, track)
|
|
||||||
file_handle.write(track.uri + '\n')
|
|
||||||
|
|
||||||
# assert playlist name matches file name/uri
|
# assert playlist name matches file name/uri
|
||||||
return playlist.replace(uri=uri, name=name)
|
return playlist.replace(uri=uri, name=name)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
|
import codecs
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@ -107,3 +108,18 @@ def parse_m3u(file_path, media_dir=None):
|
|||||||
|
|
||||||
track = Track()
|
track = Track()
|
||||||
return tracks
|
return tracks
|
||||||
|
|
||||||
|
|
||||||
|
def save_m3u(filename, tracks, encoding='latin1', errors='replace'):
|
||||||
|
extended = any(track.name for track in tracks)
|
||||||
|
# codecs.open() always uses binary mode, just being explicit here
|
||||||
|
with codecs.open(filename, 'wb', encoding, errors) as m3u:
|
||||||
|
if extended:
|
||||||
|
m3u.write('#EXTM3U' + os.linesep)
|
||||||
|
for track in tracks:
|
||||||
|
if extended and track.name:
|
||||||
|
m3u.write('#EXTINF:%d,%s%s' % (
|
||||||
|
track.length // 1000 if track.length else -1,
|
||||||
|
track.name,
|
||||||
|
os.linesep))
|
||||||
|
m3u.write(track.uri + os.linesep)
|
||||||
|
|||||||
@ -108,9 +108,28 @@ class M3UPlaylistsProviderTest(unittest.TestCase):
|
|||||||
path = playlist_uri_to_path(playlist.uri, self.playlists_dir)
|
path = playlist_uri_to_path(playlist.uri, self.playlists_dir)
|
||||||
|
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
contents = f.read().splitlines()
|
m3u = f.read().splitlines()
|
||||||
|
self.assertEqual(['#EXTM3U', '#EXTINF:60,Test', track.uri], m3u)
|
||||||
|
|
||||||
self.assertEqual(contents, ['#EXTM3U', '#EXTINF:60,Test', track.uri])
|
def test_latin1_playlist_contents_is_written_to_disk(self):
|
||||||
|
track = Track(uri=generate_song(1), name='Test\x9f', length=60000)
|
||||||
|
playlist = self.core.playlists.create('test')
|
||||||
|
playlist = self.core.playlists.save(playlist.copy(tracks=[track]))
|
||||||
|
path = playlist_uri_to_path(playlist.uri, self.playlists_dir)
|
||||||
|
|
||||||
|
with open(path, 'rb') as f:
|
||||||
|
m3u = f.read().splitlines()
|
||||||
|
self.assertEqual([b'#EXTM3U', b'#EXTINF:60,Test\x9f', track.uri], m3u)
|
||||||
|
|
||||||
|
def test_utf8_playlist_contents_is_replaced_and_written_to_disk(self):
|
||||||
|
track = Track(uri=generate_song(1), name='Test\u07b4', length=60000)
|
||||||
|
playlist = self.core.playlists.create('test')
|
||||||
|
playlist = self.core.playlists.save(playlist.copy(tracks=[track]))
|
||||||
|
path = playlist_uri_to_path(playlist.uri, self.playlists_dir)
|
||||||
|
|
||||||
|
with open(path, 'rb') as f:
|
||||||
|
m3u = f.read().splitlines()
|
||||||
|
self.assertEqual([b'#EXTM3U', b'#EXTINF:60,Test?', track.uri], m3u)
|
||||||
|
|
||||||
def test_playlists_are_loaded_at_startup(self):
|
def test_playlists_are_loaded_at_startup(self):
|
||||||
track = Track(uri='dummy:track:path2')
|
track = Track(uri='dummy:track:path2')
|
||||||
|
|||||||
@ -60,5 +60,6 @@ class VersionTest(unittest.TestCase):
|
|||||||
self.assertVersionLess('1.0.0', '1.0.1')
|
self.assertVersionLess('1.0.0', '1.0.1')
|
||||||
self.assertVersionLess('1.0.1', '1.0.2')
|
self.assertVersionLess('1.0.1', '1.0.2')
|
||||||
self.assertVersionLess('1.0.2', '1.0.3')
|
self.assertVersionLess('1.0.2', '1.0.3')
|
||||||
self.assertVersionLess('1.0.3', __version__)
|
self.assertVersionLess('1.0.3', '1.0.4')
|
||||||
self.assertVersionLess(__version__, '1.0.5')
|
self.assertVersionLess('1.0.4', __version__)
|
||||||
|
self.assertVersionLess(__version__, '1.0.6')
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user