Merge pull request #5048 from mgoltzsche/smartplaylist-track-path-template

smartplaylist: add --uri-format option
This commit is contained in:
Adrian Sampson 2023-12-16 10:49:55 -05:00 committed by GitHub
commit 3165d5dec0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 15 deletions

View file

@ -45,6 +45,7 @@ class SmartPlaylistPlugin(BeetsPlugin):
"playlist_dir": ".",
"auto": True,
"playlists": [],
"uri_format": None,
"forward_slash": False,
"prefix": "",
"urlencode": False,
@ -109,6 +110,12 @@ class SmartPlaylistPlugin(BeetsPlugin):
action="store_true",
help="URL-encode all paths.",
)
spl_update.parser.add_option(
"--uri-format",
dest="uri_format",
type="string",
help="playlist item URI template, e.g. http://beets:8337/item/$id/file.",
)
spl_update.parser.add_option(
"--output",
type="string",
@ -247,6 +254,8 @@ class SmartPlaylistPlugin(BeetsPlugin):
playlist_dir = self.config["playlist_dir"].as_filename()
playlist_dir = bytestring_path(playlist_dir)
tpl = self.config["uri_format"].get()
prefix = bytestring_path(self.config["prefix"].as_str())
relative_to = self.config["relative_to"].get()
if relative_to:
relative_to = normpath(relative_to)
@ -275,18 +284,26 @@ class SmartPlaylistPlugin(BeetsPlugin):
m3u_name = sanitize_path(m3u_name, lib.replacements)
if m3u_name not in m3us:
m3us[m3u_name] = []
item_path = item.path
if relative_to:
item_path = os.path.relpath(item.path, relative_to)
if item_path not in m3us[m3u_name]:
m3us[m3u_name].append({"item": item, "path": item_path})
item_uri = item.path
if tpl:
item_uri = tpl.replace("$id", str(item.id)).encode("utf-8")
else:
if relative_to:
item_uri = os.path.relpath(item_uri, relative_to)
if self.config["forward_slash"].get():
item_uri = path_as_posix(item_uri)
if self.config["urlencode"]:
item_uri = bytestring_path(pathname2url(item_uri))
item_uri = prefix + item_uri
if item_uri not in m3us[m3u_name]:
m3us[m3u_name].append({"item": item, "uri": item_uri})
if pretend and self.config["pretend_paths"]:
print(displayable_path(item_path))
print(displayable_path(item_uri))
elif pretend:
print(item)
if not pretend:
prefix = bytestring_path(self.config["prefix"].as_str())
# Write all of the accumulated track lists to files.
for m3u in m3us:
m3u_path = normpath(
@ -303,18 +320,13 @@ class SmartPlaylistPlugin(BeetsPlugin):
if m3u8:
f.write(b"#EXTM3U\n")
for entry in m3us[m3u]:
path = entry["path"]
item = entry["item"]
if self.config["forward_slash"].get():
path = path_as_posix(path)
if self.config["urlencode"]:
path = bytestring_path(pathname2url(path))
comment = ""
if m3u8:
comment = "#EXTINF:{},{} - {}\n".format(
int(item.length), item.artist, item.title
)
f.write(comment.encode("utf-8") + prefix + path + b"\n")
f.write(comment.encode("utf-8") + entry["uri"] + b"\n")
# Send an event when playlists were updated.
send_event("smartplaylist_update")

View file

@ -148,8 +148,9 @@ New features:
`synced` option to prefer synced lyrics over plain lyrics.
* :ref:`import-cmd`: Expose import.quiet_fallback as CLI option.
* :ref:`import-cmd`: Expose `import.incremental_skip_later` as CLI option.
* :doc:`/plugins/smartplaylist`: Add new config option `smartplaylist.output`.
* :doc:`/plugins/smartplaylist`: Expose config options as CLI options.
* :doc:`/plugins/smartplaylist`: Add new option `smartplaylist.output`.
* :doc:`/plugins/smartplaylist`: Add new option `smartplaylist.uri_format`.
Bug fixes:

View file

@ -118,9 +118,13 @@ other configuration options are:
- **urlencode**: URL-encode all paths. Default: ``no``.
- **pretend_paths**: When running with ``--pretend``, show the actual file
paths that will be written to the m3u file. Default: ``false``.
- **uri_format**: Template with an ``$id`` placeholder used generate a
playlist item URI, e.g. ``http://beets:8337/item/$id/file``.
When this option is specified, the local path-related options ``prefix``,
``relative_to``, ``forward_slash`` and ``urlencode`` are ignored.
- **output**: Specify the playlist format: m3u|m3u8. Default ``m3u``.
For many configuration options, there is a corresponding CLI option, e.g.
``--playlist-dir``, ``--relative-to``, ``--prefix``, ``--forward-slash``,
``--urlencode``, ``--output``, ``--pretend-paths``.
``--urlencode``, ``--uri-format``, ``--output``, ``--pretend-paths``.
CLI options take precedence over those specified within the configuration file.

View file

@ -241,6 +241,51 @@ class SmartPlaylistTest(_common.TestCase):
+ b"http://beets:8337/files/tagada.mp3\n",
)
def test_playlist_update_uri_format(self):
spl = SmartPlaylistPlugin()
i = MagicMock()
type(i).id = PropertyMock(return_value=3)
type(i).path = PropertyMock(return_value=b"/tagada.mp3")
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 = []
q = Mock()
a_q = Mock()
pl = b"$title-my<playlist>.m3u", (q, None), (a_q, None)
spl._matched_playlists = [pl]
dir = bytestring_path(mkdtemp())
tpl = "http://beets:8337/item/$id/file"
config["smartplaylist"]["uri_format"] = tpl
config["smartplaylist"]["playlist_dir"] = py3_path(dir)
# The following options should be ignored when uri_format is set
config["smartplaylist"]["relative_to"] = "/data"
config["smartplaylist"]["prefix"] = "/prefix"
config["smartplaylist"]["urlencode"] = True
try:
spl.update_playlists(lib)
except Exception:
rmtree(syspath(dir))
raise
lib.items.assert_called_once_with(q, None)
lib.albums.assert_called_once_with(a_q, None)
m3u_filepath = path.join(dir, b"ta_ga_da-my_playlist_.m3u")
self.assertExists(m3u_filepath)
with open(syspath(m3u_filepath), "rb") as f:
content = f.read()
rmtree(syspath(dir))
self.assertEqual(content, b"http://beets:8337/item/3/file\n")
class SmartPlaylistCLITest(_common.TestCase, TestHelper):
def setUp(self):