Fix #1428: Add m3u/base_dir confval.

This commit is contained in:
Thomas Kemmer 2016-02-14 12:07:22 +01:00
parent 6b873816af
commit 6aef96a0d3
6 changed files with 49 additions and 2 deletions

View File

@ -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`)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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):