diff --git a/beetsplug/smartplaylist.py b/beetsplug/smartplaylist.py index 416dc37f5..514e74acc 100644 --- a/beetsplug/smartplaylist.py +++ b/beetsplug/smartplaylist.py @@ -20,7 +20,8 @@ from __future__ import division, absolute_import, print_function from beets.plugins import BeetsPlugin from beets import ui -from beets.util import mkdirall, normpath, syspath, bytestring_path +from beets.util import (mkdirall, normpath, sanitize_path, syspath, + bytestring_path) from beets.library import Item, Album, parse_query_string from beets.dbcore import OrQuery from beets.dbcore.query import MultipleSort, ParsingError @@ -187,6 +188,7 @@ class SmartPlaylistPlugin(BeetsPlugin): # the items and generate the correct m3u file names. for item in items: m3u_name = item.evaluate_template(name, True) + m3u_name = sanitize_path(m3u_name, lib.replacements) if m3u_name not in m3us: m3us[m3u_name] = [] item_path = item.path diff --git a/docs/changelog.rst b/docs/changelog.rst index dd012285b..02054e87c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,6 +32,8 @@ Deprecated configuration optional removals: The are a couple of small new features: +* :doc:`/plugins/smartplaylist`: Playlist names will be sanitized to + ensure valid filenames. :bug:`2258` * :doc:`/plugins/mpdupdate`, :doc:`/plugins/mpdstats`: When the ``host`` option is not set, these plugins will now look for the ``$MPD_HOST`` environment variable before falling back to ``localhost``. Thanks to :user:`tarruda`. diff --git a/test/test_smartplaylist.py b/test/test_smartplaylist.py index 071ff390b..fa8658ad3 100644 --- a/test/test_smartplaylist.py +++ b/test/test_smartplaylist.py @@ -25,7 +25,7 @@ from beetsplug.smartplaylist import SmartPlaylistPlugin from beets.library import Item, Album, parse_query_string from beets.dbcore import OrQuery from beets.dbcore.query import NullSort, MultipleSort, FixedFieldSort -from beets.util import syspath, bytestring_path, py3_path +from beets.util import syspath, bytestring_path, py3_path, CHAR_REPLACE from beets.ui import UserError from beets import config @@ -150,13 +150,17 @@ class SmartPlaylistTest(unittest.TestCase): spl = SmartPlaylistPlugin() i = Mock(path=b'/tagada.mp3') - i.evaluate_template.side_effect = lambda x, _: x - q = Mock() - a_q = Mock() + i.evaluate_template.side_effect = \ + lambda pl, _: pl.replace(b'$title', b'ta:ga:da').decode() + lib = Mock() + lib.replacements = CHAR_REPLACE lib.items.return_value = [i] lib.albums.return_value = [] - pl = b'my_playlist.m3u', (q, None), (a_q, None) + + q = Mock() + a_q = Mock() + pl = b'$title-my.m3u', (q, None), (a_q, None) spl._matched_playlists = [pl] dir = bytestring_path(mkdtemp()) @@ -171,7 +175,7 @@ class SmartPlaylistTest(unittest.TestCase): lib.items.assert_called_once_with(q, None) lib.albums.assert_called_once_with(a_q, None) - m3u_filepath = path.join(dir, pl[0]) + m3u_filepath = path.join(dir, b'ta_ga_da-my_playlist_.m3u') self.assertTrue(path.exists(m3u_filepath)) with open(syspath(m3u_filepath), 'rb') as f: content = f.read()