mirror of
https://git.pumpin.online/funkpower/catena.git
synced 2026-10-22 18:57:14 +00:00
134 lines
4.1 KiB
Markdown
134 lines
4.1 KiB
Markdown
# cuenorm
|
||
|
||
Any subtitle format in, one normalised cue stream out.
|
||
|
||
Part of [catena](../../README.md).
|
||
|
||
## What it does
|
||
|
||
Reads a subtitle file — SubRip, WebVTT or SubStation Alpha — and writes one
|
||
[`cue` record](../../docs/records.md#cue--one-line-of-a-transcript) per line: a start, an
|
||
end, and what was said.
|
||
|
||
The format is worked out from the content, not from the name, because a
|
||
subtitle file is named for the format somebody expected it to be in.
|
||
|
||
## When you would use it
|
||
|
||
- **At the front of anything that reads recordings.** Everything downstream
|
||
works on cues and never has to know which of the three formats a recording
|
||
arrived with.
|
||
- **Cleaning up automatic captioning.** It repeats each line across
|
||
overlapping windows, so the same sentence arrives three or four times over;
|
||
indexed as they come, every one is a separate hit for the same words at
|
||
almost the same timestamp, which buries everything else in a result list.
|
||
- **Getting markup and sound cues out of the way.** `<v Speaker>` tags,
|
||
styling, `[Music]`, `[Applause]` — none of it is speech, and a search that
|
||
matches `[Music]` matches every recording with a theme tune.
|
||
|
||
## Install
|
||
|
||
```sh
|
||
cargo install --git https://git.pumpin.online/funkpower/catena cuenorm
|
||
```
|
||
|
||
## Example
|
||
|
||
A WebVTT file with a speaker tag, a sound cue, and a repeated line:
|
||
|
||
```
|
||
$ cat episode.vtt
|
||
WEBVTT
|
||
|
||
00:00:01.000 --> 00:00:04.500
|
||
<v Host>The mill stood at the northern end of the valley,
|
||
|
||
00:00:04.500 --> 00:00:08.000
|
||
where the fall of the river was steepest and the ice came latest.
|
||
|
||
00:00:08.000 --> 00:00:11.000
|
||
[Music]
|
||
|
||
00:00:11.000 --> 00:00:15.500
|
||
Its wheel was undershot, which was wasteful,
|
||
|
||
00:00:15.000 --> 00:00:19.000
|
||
Its wheel was undershot, which was wasteful,
|
||
|
||
00:00:19.000 --> 00:00:24.000
|
||
and nobody replaced it for two hundred years.
|
||
```
|
||
|
||
```
|
||
$ cuenorm episode.vtt
|
||
{"v":1,"start":1.0,"end":4.5,"text":"The mill stood at the northern end of the valley,"}
|
||
{"v":1,"start":4.5,"end":8.0,"text":"where the fall of the river was steepest and the ice came latest."}
|
||
{"v":1,"start":11.0,"end":19.0,"text":"Its wheel was undershot, which was wasteful,"}
|
||
{"v":1,"start":19.0,"end":24.0,"text":"and nobody replaced it for two hundred years."}
|
||
```
|
||
|
||
The speaker tag is gone, `[Music]` left no cue at all, and the repeated line
|
||
became one cue spanning both — `11.0` to `19.0`, the earliest start and the
|
||
latest end.
|
||
|
||
In a pipeline:
|
||
|
||
```sh
|
||
cuenorm episode.vtt | cuepack --seconds 75 > passages.ndjson
|
||
cuenorm episode.srt | cueseg --duration 7245 > chapters.ndjson
|
||
```
|
||
|
||
## Options
|
||
|
||
| Option | Effect |
|
||
|---|---|
|
||
| `--keep-repeats` | Keep consecutive repeats instead of merging them |
|
||
| `--man` | Write this page as a manual page, in roff |
|
||
|
||
## Exit codes
|
||
|
||
| Code | Meaning |
|
||
|---|---|
|
||
| `0` | Done |
|
||
| `64` | The command line was wrong |
|
||
| `74` | The file could not be read |
|
||
|
||
Bytes that are not UTF-8 are replaced rather than refused. A subtitle file
|
||
downloaded from anywhere is as likely to be Latin-1, and a cue with one wrong
|
||
character still has its timing and most of its words.
|
||
|
||
## The formats
|
||
|
||
| Format | Recognised by |
|
||
|---|---|
|
||
| WebVTT | The `WEBVTT` line at the front |
|
||
| SubStation Alpha | A `[Script Info]` or `[Events]` section |
|
||
| SubRip | Neither of the above |
|
||
|
||
SubStation Alpha events are rows under a `Format:` line that names the
|
||
columns, so the column order is read rather than assumed. Override blocks
|
||
(`{\an8}`), line breaks (`\N`) and drawing commands are handled: a drawing
|
||
command is a shape, not speech, and reads as a string of coordinates if it is
|
||
kept.
|
||
|
||
A WebVTT cue line carries positioning settings after the end time, which are
|
||
ignored — that is also what lets an old SubRip file with screen coordinates
|
||
after its timestamps read at all.
|
||
|
||
## As a library
|
||
|
||
```rust
|
||
let cues = cuekit::merge_repeats(&cuekit::parse(&content));
|
||
for cue in &cues {
|
||
println!("{:.1}–{:.1} {}", cue.start, cue.end, cue.text);
|
||
}
|
||
```
|
||
|
||
See [`cuekit`](../cuekit/README.md) for the parsers one at a time.
|
||
|
||
## See also
|
||
|
||
- [`cuepack`](../cuepack/README.md) — cues into passages worth embedding.
|
||
- [`cueseg`](../cueseg/README.md) — cues into topic chapters.
|
||
- [`cuekit`](../cuekit/README.md) — the library this is a command over.
|