Fix #1428: Add m3u/base_dir confval.
This commit is contained in:
parent
6b873816af
commit
6aef96a0d3
@ -55,6 +55,9 @@ Local backend
|
|||||||
M3U backend
|
M3U backend
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
- Add :confval:`m3u/base_dir` for resolving relative paths in M3U
|
||||||
|
files. (Fixes: :issue:`1428`, PR: :issue:`1442`)
|
||||||
|
|
||||||
- Derive track name from file name for non-extended M3U
|
- Derive track name from file name for non-extended M3U
|
||||||
playlists. (Fixes: :issue:`1364`, PR: :issue:`1369`)
|
playlists. (Fixes: :issue:`1364`, PR: :issue:`1369`)
|
||||||
|
|
||||||
|
|||||||
@ -55,6 +55,12 @@ See :ref:`config` for general help on configuring Mopidy.
|
|||||||
Path to directory with M3U files. Unset by default, in which case the
|
Path to directory with M3U files. Unset by default, in which case the
|
||||||
extension's data dir is used to store playlists.
|
extension's data dir is used to store playlists.
|
||||||
|
|
||||||
|
.. confval:: m3u/base_dir
|
||||||
|
|
||||||
|
Path to base directory for resolving relative paths in M3U files.
|
||||||
|
If not set, relative paths are resolved based on the M3U file's
|
||||||
|
location.
|
||||||
|
|
||||||
.. confval:: m3u/default_encoding
|
.. confval:: m3u/default_encoding
|
||||||
|
|
||||||
Text encoding used for files with extension ``.m3u``. Default is
|
Text encoding used for files with extension ``.m3u``. Default is
|
||||||
|
|||||||
@ -21,6 +21,7 @@ class Extension(ext.Extension):
|
|||||||
|
|
||||||
def get_config_schema(self):
|
def get_config_schema(self):
|
||||||
schema = super(Extension, self).get_config_schema()
|
schema = super(Extension, self).get_config_schema()
|
||||||
|
schema['base_dir'] = config.Path(optional=True)
|
||||||
schema['default_encoding'] = config.String()
|
schema['default_encoding'] = config.String()
|
||||||
schema['default_extension'] = config.String(choices=['.m3u', '.m3u8'])
|
schema['default_extension'] = config.String(choices=['.m3u', '.m3u8'])
|
||||||
schema['playlists_dir'] = config.Path(optional=True)
|
schema['playlists_dir'] = config.Path(optional=True)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
[m3u]
|
[m3u]
|
||||||
enabled = true
|
enabled = true
|
||||||
playlists_dir =
|
playlists_dir =
|
||||||
|
base_dir = $XDG_MUSIC_DIR
|
||||||
default_encoding = latin-1
|
default_encoding = latin-1
|
||||||
default_extension = .m3u8
|
default_extension = .m3u8
|
||||||
|
|||||||
@ -60,6 +60,7 @@ class M3UPlaylistsProvider(backend.PlaylistsProvider):
|
|||||||
self._playlists_dir = Extension.get_data_dir(config)
|
self._playlists_dir = Extension.get_data_dir(config)
|
||||||
else:
|
else:
|
||||||
self._playlists_dir = ext_config['playlists_dir']
|
self._playlists_dir = ext_config['playlists_dir']
|
||||||
|
self._base_dir = ext_config['base_dir'] or self._playlists_dir
|
||||||
self._default_encoding = ext_config['default_encoding']
|
self._default_encoding = ext_config['default_encoding']
|
||||||
self._default_extension = ext_config['default_extension']
|
self._default_extension = ext_config['default_extension']
|
||||||
|
|
||||||
@ -97,7 +98,7 @@ class M3UPlaylistsProvider(backend.PlaylistsProvider):
|
|||||||
path = translator.uri_to_path(uri)
|
path = translator.uri_to_path(uri)
|
||||||
try:
|
try:
|
||||||
with self._open(path, 'r') as fp:
|
with self._open(path, 'r') as fp:
|
||||||
items = translator.load_items(fp, self._playlists_dir)
|
items = translator.load_items(fp, self._base_dir)
|
||||||
except EnvironmentError as e:
|
except EnvironmentError as e:
|
||||||
log_environment_error('Error reading playlist %s' % uri, e)
|
log_environment_error('Error reading playlist %s' % uri, e)
|
||||||
else:
|
else:
|
||||||
@ -107,7 +108,7 @@ class M3UPlaylistsProvider(backend.PlaylistsProvider):
|
|||||||
path = translator.uri_to_path(uri)
|
path = translator.uri_to_path(uri)
|
||||||
try:
|
try:
|
||||||
with self._open(path, 'r') as fp:
|
with self._open(path, 'r') as fp:
|
||||||
items = translator.load_items(fp, self._playlists_dir)
|
items = translator.load_items(fp, self._base_dir)
|
||||||
mtime = os.path.getmtime(self._abspath(path))
|
mtime = os.path.getmtime(self._abspath(path))
|
||||||
except EnvironmentError as e:
|
except EnvironmentError as e:
|
||||||
log_environment_error('Error reading playlist %s' % uri, e)
|
log_environment_error('Error reading playlist %s' % uri, e)
|
||||||
|
|||||||
@ -24,6 +24,7 @@ class M3UPlaylistsProviderTest(unittest.TestCase):
|
|||||||
config = {
|
config = {
|
||||||
'm3u': {
|
'm3u': {
|
||||||
'enabled': True,
|
'enabled': True,
|
||||||
|
'base_dir': None,
|
||||||
'default_encoding': 'latin-1',
|
'default_encoding': 'latin-1',
|
||||||
'default_extension': '.m3u',
|
'default_extension': '.m3u',
|
||||||
'playlists_dir': path_to_data_dir(''),
|
'playlists_dir': path_to_data_dir(''),
|
||||||
@ -33,6 +34,7 @@ class M3UPlaylistsProviderTest(unittest.TestCase):
|
|||||||
def setUp(self): # noqa: N802
|
def setUp(self): # noqa: N802
|
||||||
self.config['m3u']['playlists_dir'] = tempfile.mkdtemp()
|
self.config['m3u']['playlists_dir'] = tempfile.mkdtemp()
|
||||||
self.playlists_dir = self.config['m3u']['playlists_dir']
|
self.playlists_dir = self.config['m3u']['playlists_dir']
|
||||||
|
self.base_dir = self.config['m3u']['base_dir'] or self.playlists_dir
|
||||||
|
|
||||||
audio = dummy_audio.create_proxy()
|
audio = dummy_audio.create_proxy()
|
||||||
backend = M3UBackend.start(
|
backend = M3UBackend.start(
|
||||||
@ -261,6 +263,32 @@ class M3UPlaylistsProviderTest(unittest.TestCase):
|
|||||||
self.assertEqual(playlist.name, result.name)
|
self.assertEqual(playlist.name, result.name)
|
||||||
self.assertEqual(track.uri, result.tracks[0].uri)
|
self.assertEqual(track.uri, result.tracks[0].uri)
|
||||||
|
|
||||||
|
def test_playlist_with_absolute_path(self):
|
||||||
|
track = Track(uri='/tmp/test.mp3')
|
||||||
|
filepath = b'/tmp/test.mp3'
|
||||||
|
playlist = self.core.playlists.create('test')
|
||||||
|
playlist = playlist.replace(tracks=[track])
|
||||||
|
playlist = self.core.playlists.save(playlist)
|
||||||
|
|
||||||
|
self.assertEqual(len(self.core.playlists.as_list()), 1)
|
||||||
|
result = self.core.playlists.lookup('m3u:test.m3u')
|
||||||
|
self.assertEqual('m3u:test.m3u', result.uri)
|
||||||
|
self.assertEqual(playlist.name, result.name)
|
||||||
|
self.assertEqual('file://' + filepath, result.tracks[0].uri)
|
||||||
|
|
||||||
|
def test_playlist_with_relative_path(self):
|
||||||
|
track = Track(uri='test.mp3')
|
||||||
|
filepath = os.path.join(self.base_dir, b'test.mp3')
|
||||||
|
playlist = self.core.playlists.create('test')
|
||||||
|
playlist = playlist.replace(tracks=[track])
|
||||||
|
playlist = self.core.playlists.save(playlist)
|
||||||
|
|
||||||
|
self.assertEqual(len(self.core.playlists.as_list()), 1)
|
||||||
|
result = self.core.playlists.lookup('m3u:test.m3u')
|
||||||
|
self.assertEqual('m3u:test.m3u', result.uri)
|
||||||
|
self.assertEqual(playlist.name, result.name)
|
||||||
|
self.assertEqual('file://' + filepath, result.tracks[0].uri)
|
||||||
|
|
||||||
def test_playlist_sort_order(self):
|
def test_playlist_sort_order(self):
|
||||||
def check_order(playlists, names):
|
def check_order(playlists, names):
|
||||||
self.assertEqual(names, [playlist.name for playlist in playlists])
|
self.assertEqual(names, [playlist.name for playlist in playlists])
|
||||||
@ -303,6 +331,13 @@ class M3UPlaylistsProviderTest(unittest.TestCase):
|
|||||||
self.assertIsNone(item_refs)
|
self.assertIsNone(item_refs)
|
||||||
|
|
||||||
|
|
||||||
|
class M3UPlaylistsProviderBaseDirectoryTest(M3UPlaylistsProviderTest):
|
||||||
|
|
||||||
|
def setUp(self): # noqa: N802
|
||||||
|
self.config['m3u']['base_dir'] = tempfile.mkdtemp()
|
||||||
|
super(M3UPlaylistsProviderBaseDirectoryTest, self).setUp()
|
||||||
|
|
||||||
|
|
||||||
class DeprecatedM3UPlaylistsProviderTest(M3UPlaylistsProviderTest):
|
class DeprecatedM3UPlaylistsProviderTest(M3UPlaylistsProviderTest):
|
||||||
|
|
||||||
def run(self, result=None):
|
def run(self, result=None):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user