summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-10-29 20:13:13 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-10-29 20:13:13 +0000
commit247c6a6456173e4ec67b6f95191765a2cf62b744 (patch)
tree6ca8ef0d6a790a1d2517ecc6f763a8c8b0fbd214
parent8c6343c9185bd3978e1e2f81374eef0571e1965d (diff)
A music cue at the edge of a break is not part of the break
whisper writes "[music]", "(upbeat music)", "(audience laughing)" -- 312 of the 56,306 recognised lines in the library. They are not speech, so no publisher's written transcript contains them, so they can never anchor, so they sit at the front of a break and widen it. Earlier I said these could not be told from an advertisement and left them alone. That conflated two different things. A title card -- "Today's episode, Tamara." -- genuinely cannot be told apart, and is still left alone. A non-speech note says what it is by its shape. Measured across the eighteen episodes holding a master: before 99% - 110%, mean 103% after 99% - 106%, mean 101% #69 Tamara 110% -> 103% #70 Cayden 109% -> 106% Regrets 108% -> 104% Gobi 104% -> 100% Fourteen of the eighteen now sit within one point of the length gap. Nothing regressed. They are trimmed from break edges but still stored and still shown: a reader following along is better off seeing the laughter than a hole where it was. This is a judgement about where an advertisement starts, not about what was said. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
-rw-r--r--server/internal/transcript/trim.go23
-rw-r--r--server/internal/transcript/trim_test.go31
2 files changed, 45 insertions, 9 deletions
diff --git a/server/internal/transcript/trim.go b/server/internal/transcript/trim.go
index 995bc85..f2ded4c 100644
--- a/server/internal/transcript/trim.go
+++ b/server/internal/transcript/trim.go
@@ -1,6 +1,9 @@
package transcript
-import "strings"
+import (
+ "regexp"
+ "strings"
+)
/*
Pulling a candidate's edges back off the programme.
@@ -59,10 +62,10 @@ func trimmed(found []Candidate, master, served []Cue) []Candidate {
for _, candidate := range found {
inside := cuesWithin(served, candidate)
first, last := 0, len(inside)-1
- for first <= last && inMaster(inside[first], runs) {
+ for first <= last && trimmable(inside[first], runs) {
first++
}
- for last > first && inMaster(inside[last], runs) {
+ for last > first && trimmable(inside[last], runs) {
last--
}
if first > last {
@@ -82,7 +85,21 @@ func trimmed(found []Candidate, master, served []Cue) []Candidate {
return out
}
+// annotation matches a line that is entirely one of whisper's non-speech notes -- "[music]",
+// "(upbeat music)", "(audience laughing)". 312 of 56,306 recognised lines are one of these.
+//
+// They are not speech, so a publisher's written transcript never contains them and they can
+// never anchor -- which leaves them sitting at the front of a break, widening it. Unlike a
+// title card, which this deliberately leaves alone, an annotation says what it is by its shape,
+// so it can be told from an advertisement without guessing.
+var annotation = regexp.MustCompile(`^\s*[\[(][^\])]{0,40}[\])]\s*$`)
+
// inMaster reports whether a line's words appear in the master.
+// trimmable reports whether a line at the edge of a break belongs to the break.
+func trimmable(cue Cue, runs map[string]bool) bool {
+ return annotation.MatchString(cue.Text) || inMaster(cue, runs)
+}
+
func inMaster(cue Cue, runs map[string]bool) bool {
words := strings.FieldsFunc(strings.ToLower(cue.Text), notWord)
if len(words) < trimMinWords {
diff --git a/server/internal/transcript/trim_test.go b/server/internal/transcript/trim_test.go
index 51f3965..b9cdaec 100644
--- a/server/internal/transcript/trim_test.go
+++ b/server/internal/transcript/trim_test.go
@@ -109,13 +109,15 @@ func TestTheAdvertisementItselfIsLeftWhole(t *testing.T) {
}
/*
-Non-speech markers and title cards are left alone.
+A non-speech note at the edge of a break is not part of it.
-"[MUSIC PLAYING]" and "Today's episode, Tamara." are genuinely absent from a publisher's written
-transcript, so nothing here can tell them from an advertisement. They sit against the break
-anyway, and a rule invented to catch them would be a guess.
+"[MUSIC PLAYING]", "(upbeat music)", "(audience laughing)" -- 312 of 56,306 recognised lines.
+They are not speech, so no publisher's transcript contains them and they can never anchor,
+which leaves them sitting at the front of a break and widening it. They say what they are by
+their shape, which is what separates them from a title card like "Today's episode, Tamara."
+-- that one is left alone, because nothing here can tell it from an advertisement.
*/
-func TestNonSpeechMarkersAreNotTrimmed(t *testing.T) {
+func TestANonSpeechNoteAtTheEdgeIsTrimmed(t *testing.T) {
master := words(0, programme[0], programme[1], programme[2])
served := words(0, lines(
[]string{programme[0], "[MUSIC PLAYING]"}, advert, []string{programme[1], programme[2]},
@@ -125,8 +127,25 @@ func TestNonSpeechMarkersAreNotTrimmed(t *testing.T) {
if len(got) != 1 {
t.Fatalf("got %+v, want one candidate", got)
}
+ if got[0].StartMs != 2*cueMs {
+ t.Errorf("start = %d, want the advertisement's own first line", got[0].StartMs)
+ }
+}
+
+// A title card is not identifiable, so it stays.
+func TestATitleCardIsLeftAlone(t *testing.T) {
+ master := words(0, programme[0], programme[1], programme[2])
+ served := words(0, lines(
+ []string{programme[0], "Today's episode, Tamara."}, advert,
+ []string{programme[1], programme[2]},
+ )...)
+
+ got := Inserted(master, served)
+ if len(got) != 1 {
+ t.Fatalf("got %+v, want one candidate", got)
+ }
if got[0].StartMs != cueMs {
- t.Errorf("start = %d, want the music marker kept with the break", got[0].StartMs)
+ t.Errorf("start = %d, want the title card kept with the break", got[0].StartMs)
}
}