Comment blocks in cmd/minstrel and 30 smaller internal packages, rewritten
to rule 32's standard with each citation read in context: task, milestone
and rule ids go, and so do the stories they were attached to ("used to",
"Before #N", measurements from one install, quotes, pointers to Fabled
Librarian's records and to docs/superpowers files that are not in the
repo). Where a story wrapped a real constraint, the constraint stays as a
present-tense fact.
Comments that had gone stale are corrected:
- taste.Config: the tuned values are overlaid by internal/recsettings;
it is no longer "a later follow-up".
- StorageConfig: the data dir holds art, caches and the stream secret,
not only playlist covers.
- the Subsonic album list and getUser comments describe what they do
today rather than a milestone that would change it.
Checked: the non-comment token stream of every changed file matches
HEAD, and gofmt -l is empty.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
41 lines
1022 B
Go
41 lines
1022 B
Go
package release
|
|
|
|
import "slices"
|
|
|
|
// Comparing a file against a MusicBrainz track: shared by the importer's
|
|
// check of a download and the library listing's match of an album.
|
|
|
|
// LengthFits allows five seconds or 3%, whichever is more: remasters and
|
|
// rips differ by a second or two, a different recording by far more. A
|
|
// track MusicBrainz has no length for says nothing against the file.
|
|
func LengthFits(fileMs, trackMs int) bool {
|
|
if trackMs <= 0 {
|
|
return true
|
|
}
|
|
if fileMs <= 0 {
|
|
return false
|
|
}
|
|
tol := max(5000, trackMs*3/100)
|
|
d := fileMs - trackMs
|
|
return d <= tol && -d <= tol
|
|
}
|
|
|
|
// TitleAgrees: the same words, or one title holding all of the other's
|
|
// ("Get Lucky (Radio Edit)" holds "Get Lucky").
|
|
func TitleAgrees(a, b string) bool {
|
|
ta, tb := Tokens(a), Tokens(b)
|
|
if len(ta) == 0 || len(tb) == 0 {
|
|
return false
|
|
}
|
|
return subset(ta, tb) || subset(tb, ta)
|
|
}
|
|
|
|
func subset(small, big []string) bool {
|
|
for _, w := range small {
|
|
if !slices.Contains(big, w) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|