Skip to content

Write the track export zip in-process (UTF-8 names, no zip binary) - #555

Open
ditschi wants to merge 3 commits into
toniebox-reverse-engineering:developfrom
ditschi:feature/in-process-track-zip
Open

ditschi wants to merge 3 commits into
toniebox-reverse-engineering:developfrom
ditschi:feature/in-process-track-zip

Conversation

@ditschi

@ditschi ditschi commented Oct 18, 2026 •

Copy link
Copy Markdown

Depends on #553. This branch is based on it, so until #553 is merged the diff also shows its commit. Only the top commit belongs to this PR.

Problem

The zip for several exported tracks was built by running the external zip binary.

Change

  • New zipWriteStored (src/zip_writer.c) writes a store-only zip itself. Ogg/Opus does not compress, so no deflate is needed. It computes the CRC32 and sets the UTF-8 flag (general purpose bit 11) on the entry names. It is limited to the classic format: 65535 entries, 4 GiB.
  • The track export uses it instead of spawning zip. The temp files get plain number names (02.ogg), the track title only becomes the name of the zip entry.
  • sanitize_track_title no longer cuts a title in the middle of a UTF-8 character when it truncates.
  • zip is dropped from the runtime Docker images. The build stage still needs it for make zip.

Tests

  • New C unit test tests/c/test_zip_writer.c: known CRC32, UTF-8 flag, UTF-8 name preserved byte for byte, entry count, and a missing source file leaves no partial archive.
  • New integration test test_zip_entry_names_are_utf8 in tests/py/test_track_export.py: the tracks get titles through the custom tonies API (typographic quotes from Track split ZIP corrupts filenames containing special characters #552, a /, and a title longer than the name buffer). It checks that the entries have the UTF-8 flag and the expected names, cut at a character boundary. It fails when the flag is not set.
  • The existing track export tests still pass (Python's zipfile.testzip() verifies the CRCs), also with a failing zip shim first in PATH.
  • Checked by hand: the web UI download of 4 tracks with these titles opens correctly with unzip, 7z and Python, also under LC_ALL=C.

Not tested on Windows. The windows-latest CI job should show that it builds.

Fixes #552

🤖 Generated with Claude Code

Christian Ditscher and others added 3 commits October 17, 2026 21:20
The web UI's tonie card builds the track download from the tag's audioUrl
(/content/download/<ruid>), but only /content/<path> handled tracks=, so
the whole TAF was served as Ogg instead of a zip. Resolve the tag's source
(e.g. lib://) and use the same track export as /content/.

Refs toniebox-reverse-engineering/teddycloud_web#350

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The zip of several exported tracks was built by spawning the external
zip binary. That needs zip on the host (not available on native
Windows) and Info-ZIP only marks entry names as UTF-8 when the server
runs in a UTF-8 locale, so titles with non-ASCII characters showed up
garbled (toniebox-reverse-engineering#552).

zipWriteStored writes a store-only archive itself (Opus does not
compress) and flags the entry names as UTF-8. The temp files get plain
number names, the title only becomes the name of the zip entry. A
truncated title no longer ends in half a UTF-8 character. zip is no
longer installed in the runtime images.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Names the tracks of the generated TAF through the custom tonies API and
checks the names in the exported zip: UTF-8 flag set, typographic quotes
from toniebox-reverse-engineering#552 intact, a path separator replaced, and a title longer than the
name buffer cut at a character boundary.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant