discstation 0.1.33 → 0.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/install-macos.sh +1 -1
- package/package.json +1 -1
- package/src/discstation_burn.py +80 -52
package/install-macos.sh
CHANGED
|
@@ -50,7 +50,7 @@ if [[ -f "$ROOT_DIR/requirements-optional.txt" ]]; then
|
|
|
50
50
|
fi
|
|
51
51
|
|
|
52
52
|
DISC_DEVICE="${DISC_DEVICE:-}"
|
|
53
|
-
DISC_PORT="${DISC_PORT:-$(ls /dev/cu.usbserial-* /dev/cu.usbmodem-* 2>/dev/null | head -1)}"
|
|
53
|
+
DISC_PORT="${DISC_PORT:-$(ls /dev/cu.usbserial-* /dev/cu.usbmodem-* 2>/dev/null | head -1 || true)}"
|
|
54
54
|
|
|
55
55
|
if [[ ! -f "$CONFIG_DIR/server.crt" || ! -f "$CONFIG_DIR/server.key" ]]; then
|
|
56
56
|
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
|
package/package.json
CHANGED
package/src/discstation_burn.py
CHANGED
|
@@ -1567,30 +1567,27 @@ def burn_audio_cd(ser, audio_files, disc_label, speed=None):
|
|
|
1567
1567
|
|
|
1568
1568
|
album_t = _cdt(album_title) or "Audio CD"
|
|
1569
1569
|
album_p = _cdt(album_artist) or "Unknown Artist"
|
|
1570
|
-
toc_lines = ["CD_DA"]
|
|
1571
|
-
toc_lines.append("CD_TEXT {")
|
|
1572
|
-
toc_lines.append(" LANGUAGE_MAP { 0: EN }")
|
|
1573
|
-
toc_lines.append(" LANGUAGE 0 {")
|
|
1574
|
-
toc_lines.append(f' TITLE "{album_t}"')
|
|
1575
|
-
toc_lines.append(f' PERFORMER "{album_p}"')
|
|
1576
|
-
toc_lines.append(" }")
|
|
1577
|
-
toc_lines.append("}")
|
|
1578
|
-
toc_lines.append("")
|
|
1579
|
-
for i, (artist, title) in enumerate(track_meta):
|
|
1580
|
-
wav = tmp_dir / f"track_{i + 1:02d}.wav"
|
|
1581
|
-
track_t = _cdt(title) or f"Track {i + 1:02d}"
|
|
1582
|
-
track_p = _cdt(artist) or album_p
|
|
1583
|
-
toc_lines.append("TRACK AUDIO")
|
|
1584
|
-
toc_lines.append("CD_TEXT {")
|
|
1585
|
-
toc_lines.append(" LANGUAGE 0 {")
|
|
1586
|
-
toc_lines.append(f' TITLE "{track_t}"')
|
|
1587
|
-
toc_lines.append(f' PERFORMER "{track_p}"')
|
|
1588
|
-
toc_lines.append(" }")
|
|
1589
|
-
toc_lines.append("}")
|
|
1590
|
-
toc_lines.append(f'FILE "{wav}" 0')
|
|
1591
|
-
toc_lines.append("")
|
|
1592
1570
|
toc_path = tmp_dir / "disc.toc"
|
|
1593
|
-
|
|
1571
|
+
|
|
1572
|
+
def _write_toc(include_cdtext):
|
|
1573
|
+
toc_lines = ["CD_DA"]
|
|
1574
|
+
if include_cdtext:
|
|
1575
|
+
toc_lines += ["CD_TEXT {", " LANGUAGE_MAP { 0: EN }", " LANGUAGE 0 {",
|
|
1576
|
+
f' TITLE "{album_t}"', f' PERFORMER "{album_p}"',
|
|
1577
|
+
" }", "}", ""]
|
|
1578
|
+
for i, (artist, title) in enumerate(track_meta):
|
|
1579
|
+
wav = tmp_dir / f"track_{i + 1:02d}.wav"
|
|
1580
|
+
toc_lines.append("TRACK AUDIO")
|
|
1581
|
+
if include_cdtext:
|
|
1582
|
+
track_t = _cdt(title) or f"Track {i + 1:02d}"
|
|
1583
|
+
track_p = _cdt(artist) or album_p
|
|
1584
|
+
toc_lines += ["CD_TEXT {", " LANGUAGE 0 {", f' TITLE "{track_t}"',
|
|
1585
|
+
f' PERFORMER "{track_p}"', " }", "}"]
|
|
1586
|
+
toc_lines.append(f'FILE "{wav}" 0')
|
|
1587
|
+
toc_lines.append("")
|
|
1588
|
+
toc_path.write_text("\n".join(toc_lines) + "\n")
|
|
1589
|
+
|
|
1590
|
+
_write_toc(include_cdtext=True)
|
|
1594
1591
|
print(f"CD-TEXT: album={album_t!r} performer={album_p!r}, "
|
|
1595
1592
|
f"{len(track_meta)} track titles")
|
|
1596
1593
|
send(ser, "PROGRESS:35%")
|
|
@@ -1607,9 +1604,8 @@ def burn_audio_cd(ser, audio_files, disc_label, speed=None):
|
|
|
1607
1604
|
return
|
|
1608
1605
|
|
|
1609
1606
|
send(ser, "STATUS:Burning audio CD...")
|
|
1610
|
-
#
|
|
1611
|
-
#
|
|
1612
|
-
# (set it empty to let cdrdao auto-pick).
|
|
1607
|
+
# DISCSTATION_CDRDAO_DRIVER forces one specific driver (set it empty for
|
|
1608
|
+
# cdrdao to auto-pick) instead of the try-in-order fallback below.
|
|
1613
1609
|
try:
|
|
1614
1610
|
cdrdao_write_dev = discstation_host.cdrdao_device(disc_device())
|
|
1615
1611
|
except RuntimeError:
|
|
@@ -1617,39 +1613,71 @@ def burn_audio_cd(ser, audio_files, disc_label, speed=None):
|
|
|
1617
1613
|
raise RuntimeError("Audio CD burning is not supported on this Mac "
|
|
1618
1614
|
"(cdrdao cannot access the optical drive)")
|
|
1619
1615
|
raise
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1616
|
+
def _run_cdrdao(driver):
|
|
1617
|
+
cmd = [tool('cdrdao'), 'write', '--buffers', '64', '--device', cdrdao_write_dev]
|
|
1618
|
+
if driver:
|
|
1619
|
+
cmd += ['--driver', driver]
|
|
1620
|
+
speed_ = speed or DISC_SPEED
|
|
1621
|
+
if speed_ and speed_.lower() != "auto":
|
|
1622
|
+
cmd += ['--speed', speed_.rstrip('x')]
|
|
1623
|
+
cmd.append(str(toc_path)) # toc-file must come after all options
|
|
1624
|
+
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
|
1625
|
+
lines = []
|
|
1626
|
+
last_prog = 0
|
|
1627
|
+
try:
|
|
1628
|
+
for line in iter_proc_or_cancel(proc, ser):
|
|
1629
|
+
lines.append(line)
|
|
1630
|
+
# "Wrote 12 of 650 MB (Buffers 99% 100%)." is the real write
|
|
1631
|
+
# progress - matching on the first bare NN% instead (as this
|
|
1632
|
+
# used to) grabs the *buffer fill* percentage, which BURN-Proof
|
|
1633
|
+
# holds near 100% for virtually the whole burn, so the OLED
|
|
1634
|
+
# jumped straight from "Converting" to 100% and sat there.
|
|
1635
|
+
m = re.search(r'Wrote\s+(\d+)\s+of\s+(\d+)\s+MB', line)
|
|
1636
|
+
if m and int(m.group(2)) > 0:
|
|
1637
|
+
frac = int(m.group(1)) / int(m.group(2))
|
|
1638
|
+
pct = 35 + int(frac * 65)
|
|
1639
|
+
now = time.time()
|
|
1640
|
+
if now - last_prog >= 0.2:
|
|
1641
|
+
send(ser, f"PROGRESS:{pct}%")
|
|
1642
|
+
last_prog = now
|
|
1643
|
+
except (KeyboardInterrupt, SystemExit):
|
|
1644
|
+
stop_process(proc)
|
|
1645
|
+
raise
|
|
1646
|
+
return proc.wait(), lines
|
|
1647
|
+
|
|
1632
1648
|
log_path = WORK / "cdrdao.log"
|
|
1633
|
-
|
|
1649
|
+
override = os.environ.get("DISCSTATION_CDRDAO_DRIVER")
|
|
1650
|
+
# generic-mmc-raw (raw P-W sub-channel writing) is what guarantees CD-TEXT,
|
|
1651
|
+
# but some drives reject raw sub-channel writing outright - confirmed live
|
|
1652
|
+
# on this drive with --simulate: it fails at the lead-in even with CD-TEXT
|
|
1653
|
+
# stripped out entirely, so it's the raw *driver* that's incompatible here,
|
|
1654
|
+
# not CD-TEXT itself. generic-mmc (cooked) writes fine on the same drive
|
|
1655
|
+
# (also confirmed with --simulate) and still carries the CD-TEXT blocks in
|
|
1656
|
+
# the TOC, so it's worth trying with labels intact before dropping them -
|
|
1657
|
+
# only the last resort actually removes CD-TEXT from the TOC.
|
|
1658
|
+
drivers_to_try = [override] if override else ["generic-mmc-raw", "generic-mmc"]
|
|
1634
1659
|
try:
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1660
|
+
rc, out_lines = -1, []
|
|
1661
|
+
for i, driver in enumerate(drivers_to_try):
|
|
1662
|
+
if i > 0:
|
|
1663
|
+
print(f"cdrdao: write failed with previous driver - retrying with --driver {driver or 'auto'}")
|
|
1664
|
+
send(ser, "STATUS:Retrying burn...")
|
|
1665
|
+
rc, lines = _run_cdrdao(driver)
|
|
1666
|
+
out_lines += ([f"--- driver {driver or 'auto'} ---"] if i else []) + lines
|
|
1667
|
+
if rc == 0 or rc == -15:
|
|
1668
|
+
break
|
|
1669
|
+
if rc != 0 and rc != -15 and not override:
|
|
1670
|
+
print("cdrdao: all driver modes failed - retrying without CD-TEXT")
|
|
1671
|
+
send(ser, "STATUS:Retrying without CD-TEXT...")
|
|
1672
|
+
_write_toc(include_cdtext=False)
|
|
1673
|
+
rc2, lines2 = _run_cdrdao(None)
|
|
1674
|
+
out_lines += ["--- retry without CD-TEXT ---"] + lines2
|
|
1675
|
+
rc = rc2
|
|
1647
1676
|
finally:
|
|
1648
1677
|
for w in tmp_dir.glob("*.wav"):
|
|
1649
1678
|
w.unlink(missing_ok=True)
|
|
1650
1679
|
toc_path.unlink(missing_ok=True)
|
|
1651
1680
|
shutil.rmtree(str(tmp_dir), ignore_errors=True)
|
|
1652
|
-
rc = proc.wait()
|
|
1653
1681
|
log_path.write_text("\n".join(out_lines) + "\n")
|
|
1654
1682
|
if rc != 0:
|
|
1655
1683
|
for line in out_lines[-10:]:
|