feat: export clips, protect bookmarks and clean session storage
This commit is contained in:
@@ -262,3 +262,111 @@ active, it exits immediately. It stops discovering new games once closed,
|
||||
so there is no indefinitely running invisible app. Reopening the window and
|
||||
persistent background discovery need the future tray integration. Explicit
|
||||
Quit/Ctrl+Q stops and finalises the current recording immediately.
|
||||
|
||||
|
||||
## Clips, bookmarks and storage cleanup
|
||||
|
||||
`clipbin-media::export` copies video and selected AAC tracks to MP4 without
|
||||
re-encoding. OBS already writes system, microphone and combined tracks when the
|
||||
mic is enabled: exports default to the combined track, with a Settings option
|
||||
for the two separate tracks. A session without a mic exports its single track.
|
||||
The output is closed and synced under a `.partial.mp4` name, then renamed;
|
||||
only the completed MP4 and saved JSON appear in the Clips library.
|
||||
|
||||
Video timestamps use integer frame clocks, retaining presentation/decode
|
||||
ordering for B-frames. Each segment also persists cumulative AAC sample starts
|
||||
per stream (`audio_start_samples`, with `#[serde(default)]`). Audio uses its own
|
||||
1024-sample AAC packet clock across adjacent pieces, avoiding independently reset/rounded Matroska timestamps.
|
||||
Old session metadata defaults these audio counters to empty. Before cleanup,
|
||||
the worker reconstructs them from retained finalised files; export can also
|
||||
reconstruct an older range while its preceding files still exist. If the earlier
|
||||
files are already unavailable and no exact clock was saved, export fails
|
||||
honestly rather than guessing the A/V phase.
|
||||
Keyframes are anchored to the capture run, including its wall-clock offset.
|
||||
Outer unavailable footage is trimmed from completed ranges. Internal Missing
|
||||
and Removed spans retain a timestamp jump; players may hold the preceding
|
||||
picture or skip to the next picture, but the gap is not collapsed. Export
|
||||
ranges spanning codec, size or frame-rate changes fail honestly. Dropped-frame
|
||||
placement remains unvalidated, so these ranges fail rather than claiming exact
|
||||
CFR output.
|
||||
|
||||
One bounded export queue runs on a separate thread. Requests retain the action
|
||||
receipt timestamp while the current segment finalises; cleanup leases are
|
||||
persisted in `clips/export-requests.json`. Failed exports retain their leases
|
||||
until retry succeeds or the user releases them from the Clips screen. A crash
|
||||
between MP4 publication and JSON persistence can leave an unlisted complete MP4;
|
||||
Open folder lets the user recover it. Partial files are never listed as clips.
|
||||
|
||||
Cleanup checks the byte budget every three seconds and after session end. Its
|
||||
pure selector orders completed sessions first, then active footage, oldest
|
||||
first. It excludes bookmarks, editor selection and queued/running/failed export
|
||||
ranges, and never selects the current file. It persists Removed spans before
|
||||
deleting a segment; a deletion failure restores availability and surfaces an
|
||||
error. Bookmarks persist in session metadata, protect future post-roll, and can
|
||||
be released in the editor. Clips remain outside this budget and can be deleted
|
||||
explicitly.
|
||||
|
||||
Global bindings default to Ctrl+Shift+F9 (clip) and Ctrl+Shift+F10 (bookmark).
|
||||
Settings independently offer F11/F12 alternatives; configuration files accept
|
||||
F1–F12 (distinct bindings). Wayland uses the GlobalShortcuts portal and displays
|
||||
its returned binding descriptions; the desktop handles approval and rebinding.
|
||||
A compositor without that portal reports unavailability, with sidebar buttons
|
||||
as the fallback. X11 uses XGrabKey with Caps/Num lock variants and detectable
|
||||
auto-repeat; Windows uses RegisterHotKey with MOD_NOREPEAT on a message thread.
|
||||
Action timestamps are taken when the native event is received and retained
|
||||
while the worker queues the export. Real Hyprland first-use approval, portal
|
||||
restoration/rebinding and shortcuts while a game has focus remain unvalidated.
|
||||
Native X11 desktop behaviour and Windows registration/conflicts also remain
|
||||
unvalidated.
|
||||
|
||||
New checks:
|
||||
|
||||
- `scripts/validate/linux-clips.sh`: fake Steam session, actual sidebar button
|
||||
clicks, cross-segment MP4, codec preservation, zero-error decode, CFR packet
|
||||
PTS spacing, continuous audio, original short-clip range, capture continuing
|
||||
during export, a persisted bookmark, forced one-byte cleanup with neighbouring
|
||||
Removed spans, a new export of the bookmark after earlier files are deleted,
|
||||
and a Clips screenshot. Uses only the standard PATH tools,
|
||||
`rig-pointer` and `wtype`; no ripgrep dependency.
|
||||
- `scripts/validate/check-clip.py <saved-clip.json>`: reusable packet/decode check
|
||||
before source cleanup, including selected audio track count, cumulative source
|
||||
audio clocks and the original per-track A/V phase to within one audio sample.
|
||||
- `scripts/validate/linux-hotkeys.sh`: actual clip/bookmark X11 key grabs under
|
||||
Xwayland (`xdotool` injects native X11 keys). The wlr rig has no GlobalShortcuts
|
||||
portal, so it cannot validate the Wayland shortcut route.
|
||||
|
||||
Windows media build setup: use an FFmpeg **7.1 shared development** package
|
||||
(headers and MSVC import libraries) matching OBS's bundled avcodec-61 DLLs.
|
||||
Set `FFMPEG_DIR` to that package when building `clipbin-media`; distribute the
|
||||
matching OBS-bundled FFmpeg DLLs. FFmpeg development/import files for MSVC are
|
||||
not available in this Linux environment, so `clipbin-media` is excluded from
|
||||
the Windows cross-lint. `clipbin-core` (including the hotkey bridge),
|
||||
`clipbin-obs` and `clipbin-probe` are cross-linted. Windows export/remux, the
|
||||
default player/folder actions, clip deletion, pending-export leases, bookmark
|
||||
release, cleanup of recently closed files and every new GPUI control still
|
||||
need linking/running on Windows.
|
||||
|
||||
Step 2 validation on the Intel UHD 770 Linux rig (2026-10-08): workspace format,
|
||||
clippy with `-D warnings`, and all 49 unit tests passed. Windows cross-clippy
|
||||
passed for core, OBS and probe with the exclusions above. The end-to-end clips
|
||||
script passed for H.264 with one audio track and with separate system/mic
|
||||
tracks, and for HEVC with the combined track. The HEVC run requested the default
|
||||
120 seconds from a shorter session and correctly saved its available 14 seconds.
|
||||
All checked exports retained their codec, decoded without errors, had exact
|
||||
1/60-second video spacing and continuous audio, and retained their source A/V
|
||||
phase. Forced one-byte cleanup removed neighbouring footage while bookmarks
|
||||
and exported MP4s survived; a retained bookmark could still export after its
|
||||
preceding files had been deleted. Clips screenshots are produced as `clips.png`
|
||||
in each script's output directory.
|
||||
|
||||
To repeat the extra audio/codec cases, set `CLIPBIN_VALIDATE_MIC=1`, optionally
|
||||
`CLIPBIN_VALIDATE_SEPARATE_AUDIO=1`, `CLIPBIN_VALIDATE_CODEC=Hevc`, or
|
||||
`CLIPBIN_VALIDATE_CLIP_SECONDS=120` before `linux-clips.sh`. The original nine
|
||||
capture scenarios and automatic-session validation also passed using
|
||||
`env PATH=/usr/bin:/bin:$HOME/.cargo/bin`. Native X11 hotkey registration and
|
||||
both actions passed under Xwayland. These fake Steam tests run sequentially:
|
||||
game discovery is machine-wide, although rig teardown only kills its own PIDs.
|
||||
AV1 export is unvalidated because this GPU has no usable AV1 encoder. B-frame
|
||||
export and ranges containing an internal timestamp gap need additional media
|
||||
fixtures; dropped-frame ranges are explicitly rejected. Linux default-player
|
||||
and file-manager associations still need testing on a real desktop.
|
||||
|
||||
Reference in New Issue
Block a user