package library import ( "path" "regexp" "strings" ) // sourceMarker is one sign that a file was ripped from a video rather than // taken from a release: words a video title carries and an album track does // not (#5410). // // Each pattern is used twice, so it is written in the subset that Postgres's // regex flavour and Go's RE2 read the same way: no \b (Postgres spells word // boundaries \y), no lookaround, and brackets written as (\(|\[) rather than // as a bracket expression. The SQL side matches it case-insensitively with ~*, // the Go side with (?i); [^a-zA-Z] is spelled out so neither has to fold case // inside a negated class. type sourceMarker struct { label string pattern string } // suspectSourceMarkers was calibrated against the operator's library on // 2026-10-08. Two candidates were left out on purpose: // - "live in"/"live at": 229 files, nearly all from real live albums. // - a bare "reaction": it caught Beck's "Chain Reaction". The marker below // wants the phrases a reaction video actually uses. var suspectSourceMarkers = []sourceMarker{ {"music video", `official[^a-zA-Z]*(music[^a-zA-Z]*)?video|music[^a-zA-Z]*video`}, {"official audio", `official[^a-zA-Z]*audio`}, {"lyric video", `lyrics?[^a-zA-Z]*video`}, {"visualiser", `visuali[sz]er`}, {"reaction", `reaction[^a-zA-Z]*(video|mashup)|reacts?[^a-zA-Z]+to[^a-zA-Z]|first[^a-zA-Z]*time[^a-zA-Z]*(hearing|listening)`}, {"MV", `(^|[^a-zA-Z])(mv|m/v)([^a-zA-Z]|$)`}, {"[Audio]", `(\(|\[)audio(\)|\])`}, {"[HD]", `(\(|\[)(hd|hq|4k)(\)|\])`}, } // SuspectSourcePattern is every marker as one alternation, for the SQL filter // behind the admin suspect-sources report. var SuspectSourcePattern = func() string { parts := make([]string, len(suspectSourceMarkers)) for i, m := range suspectSourceMarkers { parts[i] = "(" + m.pattern + ")" } return strings.Join(parts, "|") }() var suspectSourceRegexps = func() []*regexp.Regexp { out := make([]*regexp.Regexp, len(suspectSourceMarkers)) for i, m := range suspectSourceMarkers { out[i] = regexp.MustCompile("(?i)" + m.pattern) } return out }() // SourceMarkersFor returns the labels of every marker the file's basename // carries, in list order. Empty for a file the SQL filter would not return. func SourceMarkersFor(filePath string) []string { base := path.Base(filePath) labels := make([]string, 0, 2) for i, re := range suspectSourceRegexps { if re.MatchString(base) { labels = append(labels, suspectSourceMarkers[i].label) } } return labels }