summaryrefslogtreecommitdiff
path: root/server/cmd
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-10-07 09:14:11 +0000
committerClaude <noreply@anthropic.com>2026-10-07 09:14:11 +0000
commit9ba30c95c6bc9a6405ab21f616e933b09fa0358f (patch)
tree76c40975e4dd962fbcea631883ef627b23df8d8a /server/cmd
parent7847e13c3fab23edfda096396e4dbe01df3471c3 (diff)
Examine each batch once instead of every poll
The first full pass over all 42 feeds finished, then the server kept re-deriving the same answers: Radiolab reported "53:29 of 59:39" four times in one day. pollOne called detect unconditionally and the mirror skips files it already has, so nothing had changed between passes. At ~6.5 minutes a show that is 4.5 hours a cycle against a two-hour poll interval -- the machine never finished a cycle and never idled, burning 13h42m of CPU in 11h of wall clock, roughly 60% of it on the intro search whose results are deliberately not published. Show.DetectedBatch records the episode ids a completed pass examined. The batch is the unit rather than the episode because every offset and every break comes from comparing an episode against the others fetched alongside it, so one arrival or one pruning legitimately changes all of them. Order-independent, since feeds are not reliably sorted. Recorded only on completion, so a cancelled or failed pass is retried. Episode.DetectedAtUnix could not serve as the gate: it is only set for episodes appearing in result.Offsets, so an episode nothing was found in never got a timestamp and the gate would never close. Also records what the first full corpus showed, including a disproven hypothesis worth not retrying -- filtering breaks by partner count or run length looks obviously right and makes agreement with the declared length gap substantially worse -- and a correction: Sleepy History's 117 minutes of "advertising" was a show-level sum sitting almost entirely inside the two episodes its own guard already refused. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
Diffstat (limited to 'server/cmd')
-rw-r--r--server/cmd/listend/main.go18
1 files changed, 14 insertions, 4 deletions
diff --git a/server/cmd/listend/main.go b/server/cmd/listend/main.go
index 04c933f..3e5c65a 100644
--- a/server/cmd/listend/main.go
+++ b/server/cmd/listend/main.go
@@ -278,6 +278,7 @@ func (w *worker) pollOne(ctx context.Context, feedURL string) {
// over weeks and lost it whenever retention reclaimed the file it was holding.
func (w *worker) detect(ctx context.Context, show *store.Show, candidates []*store.Episode) {
var episodes []skips.Episode
+ var ids []string
byID := map[string]*store.Episode{}
for _, e := range candidates {
if !e.Mirrored() {
@@ -288,11 +289,15 @@ func (w *worker) detect(ctx context.Context, show *store.Show, candidates []*sto
Path: filepath.Join(w.mirror.AudioDir, e.Path),
DeclaredDurationMs: e.DeclaredDurationMs,
})
+ ids = append(ids, e.ID)
byID[e.ID] = e
}
if len(episodes) < skips.DefaultConfirmThreshold || ctx.Err() != nil {
return
}
+ if !show.NeedsDetection(ids) {
+ return
+ }
started := time.Now()
result, err := skips.Detect(ctx, w.decoder, episodes, skips.DefaultConfig())
@@ -323,7 +328,9 @@ func (w *worker) detect(ctx context.Context, show *store.Show, candidates []*sto
result.OutroConfirmedOn, len(episodes), checkNote(result.OutroCheck),
time.Since(started).Round(time.Second))
- w.detectAds(ctx, show, episodes, byID)
+ if w.detectAds(ctx, show, episodes, byID) {
+ show.RecordDetected(ids)
+ }
}
// detectAds finds the advertising a batch of episodes shares, which is what simultaneous
@@ -334,20 +341,22 @@ func (w *worker) detect(ctx context.Context, show *store.Show, candidates []*sto
// is how it came to confirm an advertisement as an intro. This uses that dependence rather than
// being defeated by it -- and reports what it found against the declared-versus-served length
// gap, a figure it did not produce and which can therefore contradict it.
+// Reports whether the scan completed, so an interrupted or failed pass is examined again rather
+// than written off as done.
func (w *worker) detectAds(
ctx context.Context,
show *store.Show,
episodes []skips.Episode,
byID map[string]*store.Episode,
-) {
+) bool {
if ctx.Err() != nil {
- return
+ return false
}
started := time.Now()
ads, err := skips.DetectAds(ctx, w.decoder, episodes, skips.DefaultAdConfig())
if err != nil {
log.Printf("%s: ad scan failed: %v", show.Title, err)
- return
+ return false
}
var withBreaks, refused int
@@ -381,6 +390,7 @@ func (w *worker) detectAds(
log.Printf("%s: ads on %d/%d episode(s)%s, accounted %s of %s inserted, took %s",
show.Title, withBreaks, len(episodes), refusedNote(refused),
clock(foundTotal), clock(insertedTotal), time.Since(started).Round(time.Second))
+ return true
}
func refusedNote(refused int) string {