v0.11.1: a web mix stops shipping an .m3u

It was there on the theory that it cost nothing and let the folder double as a
plain music folder. But a web mix is a folder you upload, and a stray playlist
file next to index.html is one more thing to explain to whoever receives it.

plan.m3u_name is now "" for WEB, so the plan doesn't name a file it won't
write, and index.html is simply the last thing written — which is what the
manifest-last invariant always meant for that branch. Folder exports keep
their m3u unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JBSM2bFC6UToiEg8BE4dqj
This commit is contained in:
2026-08-22 15:22:01 -04:00
co-authored by Claude Opus 5
parent 800e8ffb5d
commit a61cbaa369
5 changed files with 37 additions and 18 deletions
+6 -5
View File
@@ -12,7 +12,8 @@ The load-bearing claims under test:
* a conversion is always to FLAC, so it can never lose a bit;
* DRM'd tracks are reported, never silently dropped and never attempted;
* the manifest is written last, so a cancelled export leaves no page or m3u
promising files that aren't there.
promising files that aren't there. Since Round 42 the web variant's only
manifest is the page — a folder you upload has no use for a playlist file.
"""
import hashlib
@@ -236,7 +237,7 @@ class TestWebExport:
dest, _ = self._export(
tmp_path, [_track(1, "S", "A", _audio(tmp_path, "a.mp3"))])
for name in ("index.html", "player.js", "player.css",
"player-graphics.gif", "placeholder.png", "My Mix.m3u"):
"player-graphics.gif", "placeholder.png"):
assert (dest / name).is_file(), f"missing {name}"
assert (dest / "audios" / "A - S.mp3").is_file()
@@ -314,10 +315,11 @@ class TestWebExport:
assert (dest / "friend.png").read_bytes() == image.read_bytes()
assert 'src="friend.png"' in (dest / "index.html").read_text()
def test_m3u_paths_point_into_audios(self, tmp_path):
def test_no_m3u_beside_the_page(self, tmp_path):
"""A web mix is a folder you upload, not one you open in a player."""
dest, _ = self._export(
tmp_path, [_track(1, "S", "A", _audio(tmp_path, "a.mp3"))])
assert "audios/A - S.mp3" in (dest / "My Mix.m3u").read_text()
assert not list(dest.glob("*.m3u"))
def test_drm_track_is_reported_not_dropped_silently(self, tmp_path):
tracks = [
@@ -411,7 +413,6 @@ class TestCancel:
_run(plan, cancel_on_emit=1)
dest = tmp_path / "out" / "Mix"
assert not (dest / "index.html").exists()
assert not (dest / "Mix.m3u").exists()
def test_cancel_removes_the_partial_file(self, tmp_path):
plan = plan_export("Mix", self._many(tmp_path), tmp_path / "out",