Speaking of the UI, any plans to maybe have some type of startup wizard inside the webui instead of trying to do it on the environments? I think doing that can curb any confusion or any madness that any noob will have using this
With adbtuner, I can already do this. Just set my tuners and my device ips inside the webui and away I go with importing the configs
I use it all the time when my router &or minipc decide to be lazy and pick whichever network they decide it most convenient . the mini pc sometimes doesn't reboot with ethernet and falls back to wifi, causing a hornets nest of network collisions, and adb authorization prompts
ip's more reliable.
Since ADBTuner already exists, I feel like this project doesn't really need to duplicate it -- but rather innovate, like @mackid1993. If someone is confused by env vars, even the simplest Bash scripting is going to be beyond them.
I had Claude go off and do some research on what the defaults should be, like the best options for most people, and this is what I came up with. I was looking at the BBC and Ofcom and all sorts of things, so I don't know why it was defaulting to the UK, which is weird, but I guess it's a good authoritative source.
It's actually readable in real time with Nemotron right now. The BBC was right, evidently. The words are coming up in real time, but they're recycling at a very steady pace.
I was watching a broadcast TV show earlier, and it had two line captions in a common box -- with word wrap. No roll-up, and I had plenty of time to read them.
I had Claude Code do a "plan" for it. Let me know if this appeals, and if you think it might be a workable option to add to the roll-up options:
"Box, 2 lines" caption style
Context
Roll-up is the only presentation style ah4c currently sends (CEA-708 was tried and ripped back out — commit 7b6359d — so line 21 / CEA-608 is the one path with the pacing, dwell and backlog handling actually built out). Roll-up inherently keeps the previous line on screen for one more line-cycle while the new one scrolls in underneath it. What the user is watching on a broadcast recording right now is a different, more common style for prerecorded captioning: a joined two-line box that wraps line 1 → line 2 when needed, and is replaced as a whole unit between captions — no line ever lingers into the next caption.
This plan (previously discussed as "Option A") adds that as a new style, box2, alongside the existing rollup2/rollup3/rollup4, by reusing essentially all of the existing cea608 encoder — the character writer, the 32-column wrap, the credit-based reveal pacing, the "time on screen" dwell — and changing only how a finished caption hands off to the next one.
How it works
Roll-up's line hand-off is one primitive: ctrl(ccCR) (a scroll). Box style needs two different hand-offs depending on why a new line is starting:
Wrapping within one caption (line 1 is full, line 2 is needed): this should behave exactly like a roll-up's line-2 already does today — write starts at the bottom row, a wrap rolls it up to the top row and frees the bottom row for line 2. Reusing the existing wrap-triggered c.newRow() call in pushText (captions.go:2854-2868) gives this for free.
Starting a new caption (the pendingBreak CR taken at the top of pushText, captions.go:2849-2852): for box style this must erase (ccEDM, already defined at captions.go:2519 but currently unused anywhere except the stale-caption clear at captions.go:3086) instead of scrolling, so the old caption's line(s) never persist alongside the new one. For roll-up styles this stays exactly what it is today.
So: a new newBlock() method takes over the pendingBreak call site. For non-box styles it's c.newRow(), byte-identical to current behavior. For box style it's ctrl(ccEDM) + mode() (restate RU2 + the row-15 PAC, same as every other mode restatement) + col = 0.
begin() (captions.go:2765-2771) gets the same box-aware ccEDM prefix, which matters for one existing case: the backlog-cull in pushText (captions.go:2830-2835) sets started = false and clears the queue without un-displaying whatever the decoder is currently showing — begin() runs next, and for box style it needs to erase that leftover text rather than scroll past it. (Harmless to do unconditionally at true stream start too, since erasing a blank display is a no-op.)
The dwell ("time on screen") has to follow the new primitive
The existing dwell in next() (captions.go:3098-3111) only recognizes ccCR at the queue head. If newBlock() emits ccEDM instead, that dwell silently stops applying to box style's caption-to-caption timing — exactly the kind of gate-only-covers-half-the-behavior gap this file has been bitten by before. The fix is to extend that head-of-queue check to ccEDM as well, gated on c.box, using a separate timestamp (lastBlock, new field) rather than reusing lastCR:
ccEDM (new caption) → held against minRollGap using lastBlock, same shape as today's CR case.
ccCR in box mode (the intra-caption wrap) → not held. It's paced only by the existing character-reveal meter, same as it is today — the "time on screen" setting is a promise about a finished caption, not about how soon its own second line may catch up to its first. Reusing lastCR for this would also be wrong on its own terms: a wrap mid-caption would push the next ccEDM's dwell further out than the configured seconds actually asked for.
ccCR in roll-up styles → unchanged, byte-for-byte.
minRollGap for box style also needs to be computed differently in newCEA608 (captions.go:2740-2757): roll-up's rollGapFor(onScreen, rows) divides the setting by the row count because a line survives rows roll events. Box style replaces the whole block in one ccEDM, so the full onScreen duration applies undivided — call rollGapFor(onScreen, 1) for the gap, then re-floor against ccMinOnScreen(2) (the guidance minimum for a two-line caption, captions.go:2990-3008) rather than the one-line floor rollGapFor would otherwise apply.
Known limitation worth flagging, not fixing here
The existing backlog bypass (!c.waiting() in the dwell check, tied to the fixed ccMaxBacklogSec = 5.0 constant) already can undercut roll-up's dwell during sustained dialogue at longer "time on screen" settings — this came up earlier in this session and was reverted at your request. Box style's minRollGap is the undivided onScreen value (up to 8s vs. roll-up's onScreen/rows, e.g. 2.67s for rollup3), so it will hit that same bypass more readily, not less. This plan does not touch waiting()/ccMaxBacklogSec — flagging it here so the trade-off is visible, and it can be scoped separately if it turns out to matter in practice for box style.
Files to change
captions.go
cea608 struct (~2640-2680): add box bool, lastBlock time.Time.
newCEA608 (2740-2757): recognize "box2" → rows = ccRU2, box = true, and the minRollGap computation described above.
begin() (2765-2771): box-aware ccEDM prefix.
New newBlock() method near newRow() (2780-2794): the styled hand-off described above.
pushText (2849-2852): call newBlock() instead of newRow() at the pendingBreak site. The inline wrap call inside the same function (2856-2857) stays c.newRow(), unchanged.
next() (3098-3111): extend the queue-head check to ccEDM, add the lastBlock-gated case and the un-held box-CR case, per above.
No change to captionConfig, defaultCaptionConfig, or the save handler in main.go — Style is already an unvalidated free string (confirmed: only newCEA608's switch interprets it, and it already falls back to rollup3 for anything unrecognized), so "box2" is a purely additive value.
html/captions.html
Add <option value="box2">Box, 2 lines</option> to the #style select (captions.html:192-199), matching the existing Roll-up, N lines naming.
The muted explanatory paragraph under "Time on screen" (captions.html:221-227) currently asserts roll-up-only behavior ("each row is added and the oldest scrolls away"). Add a sentence covering the box case (whole caption replaced at once, full duration applies) rather than rewriting it as style-conditional — a single dropdown option doesn't need dynamic per-style copy.
Verification
No test files exist in the repo yet, and this is exactly the kind of subtle timing logic (two control codes competing for one dwell) that has already caused bugs in this file. Add captions_test.go exercising cea608 directly (no injector/pipeline needed):
Box style: an ccEDM at the queue head is withheld until minRollGap has elapsed since the last block, then released (mirrors the existing CR dwell behavior, just against lastBlock).
Box style: a ccCR at the queue head (simulating an intra-caption wrap) is released immediately regardless of minRollGap.
Regression: rollup2/rollup3/rollup4 — next()'s CR handling and minRollGap computation are unchanged from current behavior.
Beyond the unit test, this can't be fully confirmed without watching real decoded output (the DVR/player renders the actual CEA-608 stream), which isn't available in this environment — worth a manual check against Channels or another 608-aware player before considering it done.
@bnhf i got the box mode working. I added it as an option rather than stripping out the roll-up. I still think for most people to roll up is a better option because it's lower latency. But the box option is great if the roll-up is moving too fast. I kind of personally prefer to roll up to the box so leaving both and just letting people choose.
The last thing i'm validating is that the moonshine model works, it's having some weird issues right now so i'm trying to sort that out
Moonshine is just terrible, I'm swapping it out for something else.
Ok: Swapped in Parakeet TDT-CTC 110M. The nice thing about it is it shares memory amongst tunes like Cohere does. It's also very quick and pretty accurate. I think this is good for the low power machine folks. If you want to take a look at the code I pushed, feel free. I think this might be ready for another release at leaat for people to test and give feedback on. I also changed the tuner numbering to start at 1.
I'm swapping the recommended model to NVIDIA Canary 180M Flash. I found it to be nearly as accurate as Cohere, faster and much less intensive. Hopefully others like it! This is actually a real Goldilocks model. It uses like 350 megs of RAM, and is really accurate, i have to say. I was running seven tunes off it and didn't break a sweat.
Edit: off to bed, but I think this is in a pretty good place for tomorrow. It's on my fork if anyone wants to try it out before bnhf takes a look.
No problem! Thanks @bnhf!. This model I added is really really good. Also good call on the box style captions. I think they are working well.
@mnwxman132 when you have time give the Canary model a shot and let me know what you think. For me it's fast to transcribe (almost as accurate as cohere) but with the box style transcripts it really is much slower to read.