Skip to content

Commit

Permalink
smartplaylist: change encoding of additional field
Browse files Browse the repository at this point in the history
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 quotation marks and spaces).

I introduced the generation of additional EXTM3U item fields earlier this year and I want to make it right 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 M3U item attributes in the web where the attribute value contains a 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).
  • Loading branch information
mgoltzsche committed Dec 26, 2024
1 parent 2277e2a commit 2a48922
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 3 deletions.
5 changes: 3 additions & 2 deletions beetsplug/smartplaylist.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

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

import json
import os
from urllib.parse import quote
from urllib.request import pathname2url

from beets import ui
Expand Down Expand Up @@ -327,7 +327,8 @@ def update_playlists(self, lib, pretend=False):
if extm3u:
attr = [(k, entry.item[k]) for k in keys]
al = [
f" {a[0]}={json.dumps(str(a[1]))}" for a in attr
f" {a[0]}=\"{quote(str(a[1]), safe='/:')}\""
for a in attr
]
attrs = "".join(al)
comment = "#EXTINF:{}{},{} - {}\n".format(
Expand Down
2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ Other changes:
wrong (outdated) commit. Now the tag is created in the same workflow step
right after committing the version update.
:bug:`5539`
* :doc:`/plugins/smartplaylist`: URL-encode additional item `fields` within generated
EXTM3U playlists instead of JSON-encoding them.

2.2.0 (December 02, 2024)
-------------------------
Expand Down
2 changes: 1 addition & 1 deletion test/plugins/test_smartplaylist.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def test_playlist_update_output_extm3u_fields(self):
assert (
content
== b"#EXTM3U\n"
+ b'#EXTINF:300 id="456" genre="Fake Genre",Fake Artist - fake Title\n'
+ b'#EXTINF:300 id="456" genre="Fake%20Genre",Fake Artist - fake Title\n'
+ b"/tagada.mp3\n"
)

Expand Down

0 comments on commit 2a48922

Please sign in to comment.