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. Claude-Session: https://claude.ai/code/session_01JBSM2bFC6UToiEg8BE4dqj
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
"""LinTunes — iTunes-style music library manager and player for Linux."""
|
||||
|
||||
__version__ = "0.11.0"
|
||||
__version__ = "0.11.1"
|
||||
|
||||
+15
-10
@@ -11,8 +11,9 @@ Two invariants worth keeping:
|
||||
* **Local music files are only ever read.** Like sync, this never moves,
|
||||
rewrites or deletes anything in the library.
|
||||
* **The manifest is written last** — ``index.html`` for a web mix, the
|
||||
``.m3u`` for a folder. An interrupted export therefore never leaves behind
|
||||
a playlist promising files that aren't there.
|
||||
``.m3u`` for a folder (a web mix gets no m3u: it is a page to upload, not a
|
||||
music folder to open in a player). An interrupted export therefore never
|
||||
leaves behind a page or playlist promising files that aren't there.
|
||||
"""
|
||||
|
||||
import html
|
||||
@@ -103,7 +104,7 @@ class ExportPlan:
|
||||
playlist_name: str
|
||||
dest_dir: Path # the folder that gets created
|
||||
audio_dir: Path # dest_dir, or dest_dir/"audios" for a web mix
|
||||
m3u_name: str
|
||||
m3u_name: str # "" for a web mix, which writes no m3u
|
||||
title: str = ""
|
||||
description: str = ""
|
||||
image: Path | None = None # None = ship the gray placeholder
|
||||
@@ -135,7 +136,7 @@ def plan_export(playlist_name: str, tracks: list, dest_parent: Path,
|
||||
playlist_name=playlist_name,
|
||||
dest_dir=dest_dir,
|
||||
audio_dir=dest_dir / "audios" if kind == WEB else dest_dir,
|
||||
m3u_name=folder + ".m3u",
|
||||
m3u_name="" if kind == WEB else folder + ".m3u",
|
||||
title=playlist_name,
|
||||
description=DEFAULT_DESCRIPTION,
|
||||
)
|
||||
@@ -369,14 +370,18 @@ class ExportWorker(QObject):
|
||||
self.failed.emit(f"Export failed: {e}")
|
||||
|
||||
def _write_manifest(self, completed: list):
|
||||
"""The .m3u, plus the page and its assets for a web mix. Written last."""
|
||||
"""The page for a web mix, the .m3u for a folder. Written last.
|
||||
|
||||
A web mix gets no m3u. It used to ship one on the theory that it cost
|
||||
nothing and let the folder double as a plain music folder — but the
|
||||
folder is a page you upload, and a stray playlist file next to
|
||||
index.html is one more thing to explain to whoever receives it.
|
||||
"""
|
||||
plan = self._plan
|
||||
entries = [(item.dest_name, item.secs, item.display) for item in completed]
|
||||
|
||||
if plan.kind == WEB:
|
||||
for name in _WEB_ASSETS:
|
||||
shutil.copyfile(templates() / name, plan.dest_dir / name)
|
||||
image_name = None
|
||||
if plan.image is not None and Path(plan.image).is_file():
|
||||
image_name = sanitize_name(Path(plan.image).stem) \
|
||||
+ Path(plan.image).suffix.lower()
|
||||
@@ -385,11 +390,11 @@ class ExportWorker(QObject):
|
||||
image_name = "placeholder.png"
|
||||
shutil.copyfile(templates() / "placeholder.png",
|
||||
plan.dest_dir / image_name)
|
||||
# An m3u alongside the page costs nothing and lets the folder
|
||||
# double as a plain music folder.
|
||||
entries = [("audios/" + n, s, d) for n, s, d in entries]
|
||||
(plan.dest_dir / "index.html").write_text(
|
||||
build_index_html(plan, image_name), encoding="utf-8")
|
||||
return
|
||||
|
||||
entries = [(item.dest_name, item.secs, item.display)
|
||||
for item in completed]
|
||||
(plan.dest_dir / plan.m3u_name).write_text(
|
||||
build_m3u(entries), encoding="utf-8")
|
||||
|
||||
Reference in New Issue
Block a user