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>
59 lines
2.5 KiB
Go
59 lines
2.5 KiB
Go
// Package mood maps folksonomy tags (from the track_tags cache) to a small
|
|
// set of canonical mood buckets. Both the
|
|
// taste-profile builder and the recommendation scorer classify a track's tags
|
|
// through Of() so a track's mood is derived the same way on both sides.
|
|
//
|
|
// The vocabulary is intentionally narrow: only words that clearly denote mood
|
|
// (not genre). A track with no mood-word tags contributes nothing — the mood
|
|
// facet is a supplement whose coverage grows with folksonomy enrichment
|
|
// (thin on MusicBrainz-only, richer once Last.fm is keyed).
|
|
package mood
|
|
|
|
import "strings"
|
|
|
|
// vocab maps a lowercased folksonomy tag to its canonical mood bucket. Several
|
|
// synonyms collapse to one bucket so "sad" / "melancholy" / "melancholic" all
|
|
// score the same dimension.
|
|
var vocab = map[string]string{
|
|
// melancholic
|
|
"melancholic": "melancholic", "melancholy": "melancholic", "sad": "melancholic",
|
|
"sombre": "melancholic", "somber": "melancholic", "wistful": "melancholic",
|
|
"bittersweet": "melancholic", "mournful": "melancholic",
|
|
// energetic
|
|
"energetic": "energetic", "energy": "energetic", "upbeat": "energetic",
|
|
"uplifting": "energetic", "party": "energetic", "anthemic": "energetic",
|
|
// chill
|
|
"chill": "chill", "chillout": "chill", "chilled": "chill", "mellow": "chill",
|
|
"relaxing": "chill", "relaxed": "chill", "calm": "chill", "laid-back": "chill",
|
|
"laidback": "chill", "soothing": "chill",
|
|
// aggressive
|
|
"aggressive": "aggressive", "angry": "aggressive", "intense": "aggressive",
|
|
"heavy": "aggressive", "brutal": "aggressive",
|
|
// dark
|
|
"dark": "dark", "moody": "dark", "brooding": "dark", "haunting": "dark", "eerie": "dark",
|
|
// dreamy
|
|
"dreamy": "dreamy", "ethereal": "dreamy", "atmospheric": "dreamy",
|
|
"ambient": "dreamy", "hypnotic": "dreamy",
|
|
// happy
|
|
"happy": "happy", "cheerful": "happy", "feel good": "happy", "feel-good": "happy",
|
|
"feelgood": "happy", "joyful": "happy", "fun": "happy",
|
|
// romantic
|
|
"romantic": "romantic", "sensual": "romantic", "sexy": "romantic", "sentimental": "romantic",
|
|
}
|
|
|
|
// Of returns the distinct canonical mood buckets present in tags, lowercasing +
|
|
// trimming each tag before lookup. Returns nil when no tag maps to a mood, so
|
|
// callers get no mood signal for a track with only genre/descriptive tags.
|
|
func Of(tags []string) []string {
|
|
var out []string
|
|
seen := make(map[string]bool)
|
|
for _, t := range tags {
|
|
key := strings.ToLower(strings.TrimSpace(t))
|
|
if m, ok := vocab[key]; ok && !seen[m] {
|
|
seen[m] = true
|
|
out = append(out, m)
|
|
}
|
|
}
|
|
return out
|
|
}
|