refactor: one Range-capable file sender; HEAD support; assorted hygiene
web.py * _download and _stream each had their own copy loop; _download had no Range support at all, so an interrupted download of a multi-hundred-MB recording had to restart. Both now go through _serve_bytes(), which keeps _stream's live-header `prefix` trick (the patched bytes are the same length as the header they replace, so Range math is unaffected). * do_HEAD answers / , /stream/ and /download/ as a body-less do_GET. /api/clip and /api/cut return 405 instead — generating a clip or shelling out to ffmpeg only to discard the result is worse than not answering. * _api_delete drops the deleted file's _DURATION_CACHE entry, which was never evicted. * WAV durations are rounded to 2dp like FLAC's already were. isr.py * _open_output_file flushed the buffer and then called close_current_file(), which is overridden to flush again. * log_level/log_file were merged into the dict copied into every source's config; no recorder reads them. Read them where they are used. webui.html * scoreOrder() is memoised on the section array's identity — U/I otherwise re-sorted a whole day (thousands of sections) per keypress. Verified with a byte-level harness: full/partial/open-ended/unsatisfiable ranges byte-identical to disk, download Range, HEAD on all three supported paths returning headers with an empty body, 405 on /api/clip, and live-header patching still correct both whole-file and for a range straddling the patched/disk boundary. Not done from the audit: BaseRecorder.generate_filename's mkdir per file open. It runs once per split (once an hour by default), so "once at startup suffices" was not worth a behaviour change. `nul` stays in .gitignore — it guards against a Windows shell artifact on a Windows box. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -190,12 +190,14 @@ Everything the UI does goes through these endpoints, so they can also be scripte
|
||||
| `GET /api/clip?file=&start=&end=` | Section of a WAV/FLAC decoded server-side, returned as a standalone WAV (max 600 s) |
|
||||
| `GET /api/cut?file=&start=&end=` | ffmpeg-trimmed copy of the file as a download |
|
||||
| `GET /stream/<name>` | Inline playback with HTTP Range support; live files get an on-the-fly patched header |
|
||||
| `GET /download/<name>` | Raw file download |
|
||||
| `GET /download/<name>` | Raw file download, with HTTP Range support so an interrupted transfer can resume |
|
||||
| `GET /api/status` | Currently recording files (`status.json` passthrough) |
|
||||
| `GET /api/storage` | Disk free/total |
|
||||
| `GET /api/config` | Server-side defaults for margin, min-gap, and min-duration (seeds the UI controls) |
|
||||
| `DELETE /api/files/<name>` | Delete a recording and its analysis cache |
|
||||
|
||||
`HEAD` is answered for `/`, `/stream/<name>` and `/download/<name>` (headers only, no body) — the generated endpoints (`/api/clip`, `/api/cut`) return `405` rather than doing the work and discarding it.
|
||||
|
||||
Analysis, clips, cut, and delete return `409` for files that are still being recorded.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user