Skip to content

Commit efd9ece

Browse files
committed
smartplaylist: change encoding of additional field
URL-encode additional item `fields` within generated EXTM3U playlists instead of JSON-encoding them. This is because JSON-encoding additional fields/attributes made it difficult to parse the `EXTINF` line but using URL-encoding for these values makes parsing easy (because URL-encoded values cannot contain commas, quotation marks and spaces). I introduced the generation of additional EXTM3U item fields earlier this year and I want to correct that now. **Design/definition background:** Unfortunately, I didn't find a clear definition of how additional playlist item attributes should be encoded - apparently there is none. Given that item URIs within an M3U playlist can be URL-encoded already, defining the values of additional attributes to be URL-encoded is consistent design. I didn't find examples of additional EXTM3U item attributes in the web where the attribute value contains a comma, space or quotation mark but examples that specified numeric IDs and URLs as attribute values. Because the URL attribute examples I found didn't contain URL-encoded characters and because it is more readable and unproblematic for parsing, I've let the attribute URL encoding treat `:` and `/` as safe characters. **Breaking change:** While this is a breaking change in theory, in practice it is not since afaik all integrations of the smartplaylist plugin's additional EXTM3U item attribute generation feature (beets-webm3u) work with simple attribute values such as the item ID (numeric) whose formatting/encoding is not affected when changing from JSON to URL-encoding. In other words the change is backward-compatible with the beets-webm3u plugin (which I'll adjust correspondingly after this beets PR was merged).
1 parent 2277e2a commit efd9ece

File tree

3 files changed

+6
-3
lines changed

3 files changed

+6
-3
lines changed

beetsplug/smartplaylist.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414

1515
"""Generates smart playlists based on beets queries."""
1616

17-
import json
1817
import os
18+
from urllib.parse import quote
1919
from urllib.request import pathname2url
2020

2121
from beets import ui
@@ -327,7 +327,8 @@ def update_playlists(self, lib, pretend=False):
327327
if extm3u:
328328
attr = [(k, entry.item[k]) for k in keys]
329329
al = [
330-
f" {a[0]}={json.dumps(str(a[1]))}" for a in attr
330+
f" {key}=\"{quote(str(value), safe='/:')}\""
331+
for key, value in attr
331332
]
332333
attrs = "".join(al)
333334
comment = "#EXTINF:{}{},{} - {}\n".format(

docs/changelog.rst

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ Other changes:
3838
wrong (outdated) commit. Now the tag is created in the same workflow step
3939
right after committing the version update.
4040
:bug:`5539`
41+
* :doc:`/plugins/smartplaylist`: URL-encode additional item `fields` within generated
42+
EXTM3U playlists instead of JSON-encoding them.
4143

4244
2.2.0 (December 02, 2024)
4345
-------------------------

test/plugins/test_smartplaylist.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ def test_playlist_update_output_extm3u_fields(self):
283283
assert (
284284
content
285285
== b"#EXTM3U\n"
286-
+ b'#EXTINF:300 id="456" genre="Fake Genre",Fake Artist - fake Title\n'
286+
+ b'#EXTINF:300 id="456" genre="Fake%20Genre",Fake Artist - fake Title\n'
287287
+ b"/tagada.mp3\n"
288288
)
289289

0 commit comments

Comments
 (0)