package groups import ( "embed" "strings" "git.kplus.net.ua/yevhen/resource-scraper/internal/releaseparser" ) // The token dictionaries live under resources/dicts/*.txt — one token (in any // case) per line; blank lines and lines starting with "#" are ignored. They // can be edited without recompiling the parsing logic: go:embed pulls them // into the binary at build time. //go:embed resources/dicts/*.txt var dictFS embed.FS func loadDict(name string) map[string]bool { data, err := dictFS.ReadFile("resources/dicts/" + name + ".txt") if err != nil { panic("release parser: cannot load dictionary " + name + ": " + err.Error()) } out := make(map[string]bool) for line := range strings.SplitSeq(string(data), "\n") { line = strings.ToUpper(strings.TrimSpace(line)) if line == "" || strings.HasPrefix(line, "#") { continue } out[line] = true } return out } // loadOverrides parses the override table: " => artist | title". func loadOverrides(name string) map[string]releaseparser.Override { data, err := dictFS.ReadFile("resources/dicts/" + name + ".txt") if err != nil { panic("release parser: cannot load dictionary " + name + ": " + err.Error()) } out := make(map[string]releaseparser.Override) for line := range strings.SplitSeq(string(data), "\n") { line = strings.TrimSpace(line) if line == "" || strings.HasPrefix(line, "#") { continue } head, rest, ok := strings.Cut(line, "=>") if !ok { continue } artist, title, ok := strings.Cut(strings.TrimSpace(rest), "|") if !ok { continue } out[strings.TrimSpace(head)] = releaseparser.Override{ Artist: strings.TrimSpace(artist), Title: strings.TrimSpace(title), } } return out } // loadTypeVariants parses types.txt: " = variant, variant, ..." and // returns variant (uppercased) -> base as written in the file. func loadTypeVariants(name string) map[string]string { data, err := dictFS.ReadFile("resources/dicts/" + name + ".txt") if err != nil { panic("release parser: cannot load dictionary " + name + ": " + err.Error()) } out := make(map[string]string) for line := range strings.SplitSeq(string(data), "\n") { line = strings.TrimSpace(line) if line == "" || strings.HasPrefix(line, "#") { continue } base, rest, ok := strings.Cut(line, "=") if !ok { continue } base = strings.TrimSpace(base) for v := range strings.SplitSeq(rest, ",") { v = strings.ToUpper(strings.TrimSpace(v)) if v != "" { out[v] = base } } } return out } // Profile holds the shared dictionaries for the release parser. The parser is // group-agnostic: the group name is read from each release line, never from // this profile, so there is a single set of dictionaries covering all groups. var Profile = releaseparser.GroupProfile{ FormatTokens: loadDict("format"), ArtistTokens: loadDict("artists"), TypeVariants: loadTypeVariants("types"), SourceTokens: loadDict("source"), BitDepthTokens: loadDict("bitdepth"), ResolutionTokens: loadDict("resolution"), LanguageMarkers: loadDict("language"), EditionTokens: loadDict("edition"), Overrides: loadOverrides("overrides"), CommentTokens: loadDict("comment"), }