diff options
Diffstat (limited to 'server')
| -rw-r--r-- | server/internal/transcript/trim.go | 23 | ||||
| -rw-r--r-- | server/internal/transcript/trim_test.go | 31 |
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) } } |
