<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/modules/video-audio-recording.el, branch main</title>
<subtitle>My Emacs configuration
</subtitle>
<id>https://git.cjennings.net/dotemacs/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/dotemacs/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/'/>
<updated>2026-05-25T00:59:28+00:00</updated>
<entry>
<title>refactor(load-graph): route C-; registration through the keymap API</title>
<updated>2026-05-25T00:59:28+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-25T00:59:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=08014b2f15e099a1c5e662a17a41290f37aeebf4'/>
<id>urn:sha1:08014b2f15e099a1c5e662a17a41290f37aeebf4</id>
<content type='text'>
Migrated all 31 cj/custom-keymap registration sites across 24 modules from direct (keymap-set cj/custom-keymap ...) calls to cj/register-prefix-map and cj/register-command. Consumers no longer reference cj/custom-keymap directly, so keybindings.el is the sole owner of the C-; prefix and modules reach it only through the API (each already requires keybindings from Phase 2).

Behavior-preserving: I dumped every C-; binding before and after the migration and they're identical: 279 bindings, each resolving to the same command. The which-key label blocks are untouched, since they use string key descriptions and never assumed the keymap existed. I byte-compiled all 24 files (no new free-variable warnings, because the cj/custom-keymap references are gone), and make test, validate-modules, and an init load all pass.
</content>
</entry>
<entry>
<title>refactor(load-graph): make hidden module dependencies explicit</title>
<updated>2026-05-24T23:36:19+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T23:36:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=36a453d2c1237b49f594b23433858a0146dbf31e'/>
<id>urn:sha1:36a453d2c1237b49f594b23433858a0146dbf31e</id>
<content type='text'>
Phase 2 of the load-graph project. I fixed the seven hidden dependencies the classification surfaced, so each module declares what it uses instead of relying on init order.

- system-defaults now requires host-environment and user-constants at runtime. They were eval-when-compile only, but env-bsd-p and user-home-dir are read at load, so the compiled module couldn't load standalone.
- custom-buffer-file, dev-fkeys, calendar-sync, and video-audio-recording require keybindings and drop their (when (boundp 'cj/custom-keymap) ...) shims. The shim silently dropped the C-; binding when the module loaded before keybindings. The explicit require makes the dependency real.
- flycheck-config and mail-config require keybindings for their cj/custom-keymap bindings (a use-package :map and a direct keymap-set).
- Removed a dead eval-when-compile (defvar cj/custom-keymap) in transcription-config; nothing there used the variable.

No init.el load-order change. keybindings and the foundation modules already load before these, so the requires are no-ops at startup and only fix standalone and test loading.

I verified each fix with a fresh emacs --batch (require 'X), then swept all modules standalone: every one loads or fails only with a clear missing-package message. Full make test, make validate-modules, and an init smoke all pass. Module headers and the inventory's hidden-dependency section are updated to mark the seven resolved.
</content>
</entry>
<entry>
<title>docs(load-graph): classify remaining domain and optional modules</title>
<updated>2026-05-24T22:01:40+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T22:01:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=f84bba186dca1543f9c5f02c03af355188b6e87c'/>
<id>urn:sha1:f84bba186dca1543f9c5f02c03af355188b6e87c</id>
<content type='text'>
Final classification batch: the last 19 modules — linear-config, local-repository, lorem-optimum, mail-config, markdown-config, music-config, pdf-config, quick-video-capture, reconcile-open-repos, restclient-config, slack-config, system-commands, telega-config, tramp-config, transcription-config, video-audio-recording, vterm-config, weather-config, wrap-up. I annotated each header, added a Batch 9 table to the inventory, and extended the validation allowlist. 101 of 102 modules are now classified; only elfeed-config remains, deferred on its test fix.

Two more hidden dependencies turned up. video-audio-recording uses the boundp shim for its C-; r binding, and mail-config registers C-; e directly without requiring keybindings, so it errors standalone rather than degrading. Both recorded for Phase 2.
</content>
</entry>
<entry>
<title>fix(recording): create the selected recording directory, not its parent</title>
<updated>2026-05-24T09:10:13+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T09:10:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=dc033c75a88102962414c3697654dd8c2fd85a27'/>
<id>urn:sha1:dc033c75a88102962414c3697654dd8c2fd85a27</id>
<content type='text'>
The recording toggles took a directory from the prefix-arg prompt (or the default), then ran (file-name-directory location) before make-directory. For a path without a trailing slash that returns the parent, so make-directory created the parent and left the selected directory uncreated — ffmpeg then failed to write into it.

Both toggles now route the destination through cj/recording--normalize-recording-dir, which expands and applies file-name-as-directory, then call make-directory on that normalized path. The selected directory itself is created (parents=t is a no-op when it already exists), including names with spaces. Tests cover trailing-slash normalization, idempotence, spaces, and relative-to-absolute expansion.
</content>
</entry>
<entry>
<title>fix(recording): scope wf-recorder stop signal to our own process</title>
<updated>2026-05-24T09:08:19+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T09:08:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=556f48a2a0518253015496a618eec9e7a7142dcc'/>
<id>urn:sha1:556f48a2a0518253015496a618eec9e7a7142dcc</id>
<content type='text'>
Stopping a Wayland recording ran pkill -INT wf-recorder, which signals every wf-recorder on the system — including an unrelated screen capture the user started outside Emacs. The stop path now scopes the producer-first interrupt to the wf-recorder child of our own recording shell via pkill -P &lt;shell-pid&gt;, in the new cj/recording--interrupt-child-wf-recorder helper.

The producer-first ordering is unchanged: wf-recorder still gets SIGINT before the process-group signal so ffmpeg sees a clean EOF on pipe:0 and finalizes the MKV. The orphan-cleanup at recording start stays a broad by-name kill on purpose — those leftover recorders come from crashed sessions whose shells are already dead, so there is no live PID to scope to. Tests cover the scoped call, the nil-PID no-op, and that the bare system-wide form is never used.
</content>
</entry>
<entry>
<title>fix(recording): shell-quote device names and output paths in ffmpeg commands</title>
<updated>2026-05-24T09:04:59+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T09:04:59+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=39795e850f2027a88021307a37de0381996df8a5'/>
<id>urn:sha1:39795e850f2027a88021307a37de0381996df8a5</id>
<content type='text'>
The X11 video path and the audio path interpolated the mic device, system device, and output filename straight into the shell command, so a device name or recording directory with a space (or other shell metacharacter) would break the command or mishandle the path. The Wayland video branch already quoted these; the other two did not.

I wrapped all three in shell-quote-argument on both paths. To make the audio command testable, I extracted it into cj/recording--build-audio-command mirroring the existing cj/recording--build-video-command, then quoted there. Tests cover device names and filenames with spaces on both the X11 and audio builders.
</content>
</entry>
<entry>
<title>refactor(recording): extract select-from-labeled helper, flatten quick-setup</title>
<updated>2026-04-05T11:37:38+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-05T11:37:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=4cd9a0e8822d1af79dde2324eb98c87306051b93'/>
<id>urn:sha1:4cd9a0e8822d1af79dde2324eb98c87306051b93</id>
<content type='text'>
Extracted completing-read+cancel pattern into cj/recording--select-from-labeled.
Reduces quick-setup nesting from 5 to 3 levels and eliminates duplicated
completion table lambda.
</content>
</entry>
<entry>
<title>refactor(recording): extract video command builder from ffmpeg-record-video</title>
<updated>2026-04-05T11:37:01+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-05T11:37:01+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=a6f8c4ba6adf9ae4f1caa656d1ec02a63a3d3c42'/>
<id>urn:sha1:a6f8c4ba6adf9ae4f1caa656d1ec02a63a3d3c42</id>
<content type='text'>
Moved Wayland/X11 command string construction into cj/recording--build-video-command.
Reduces ffmpeg-record-video from 70 to 25 lines, nesting from 4 to 2 levels.
</content>
</entry>
<entry>
<title>refactor(recording): extract shared test-device helper from test-mic/test-monitor</title>
<updated>2026-04-05T11:36:20+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-05T11:36:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=1f5410a2522269f2346fb7f676dfb262d7eaf254'/>
<id>urn:sha1:1f5410a2522269f2346fb7f676dfb262d7eaf254</id>
<content type='text'>
Both functions had identical record-5-seconds-and-playback logic. Extracted to
cj/recording--test-device with device, prefix, and prompt-action parameters.
</content>
</entry>
<entry>
<title>refactor(recording): unify parse-pactl-sources/sinks-verbose into single function</title>
<updated>2026-04-05T11:35:45+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-05T11:35:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=a9c51241b5d645abc31eddd4f0f711d924a9985e'/>
<id>urn:sha1:a9c51241b5d645abc31eddd4f0f711d924a9985e</id>
<content type='text'>
Identical 31-line parser logic differed only in "Source #" vs "Sink #" header.
Replaced with cj/recording--parse-pactl-verbose taking a record-type parameter.
</content>
</entry>
</feed>
