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 bcf516b commit 2ccd8de
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 3 deletions.
4 changes: 2 additions & 2 deletions beetsplug/smartplaylist.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

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

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

from beets import ui
from beets.dbcore import OrQuery
Expand Down Expand Up @@ -327,7 +327,7 @@ 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: 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 2ccd8de

Please sign in to comment.