168 lines
3.9 KiB
Go
168 lines
3.9 KiB
Go
package moonblood
|
|
|
|
import (
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.kplus.net.ua/yevhen/resource-scraper/internal/releaseparser"
|
|
)
|
|
|
|
var yearRegexp = regexp.MustCompile(`^(19|20)\d{2}$`)
|
|
|
|
func Parse(raw string) releaseparser.ParsedRelease {
|
|
result := releaseparser.ParsedRelease{
|
|
Raw: strings.TrimSpace(raw),
|
|
Warnings: []string{},
|
|
UnknownTokens: []string{},
|
|
}
|
|
|
|
tokens := split(raw)
|
|
if len(tokens) < 5 {
|
|
result.Warnings = append(result.Warnings, "too few tokens")
|
|
result.Confidence = 0.2
|
|
return result
|
|
}
|
|
|
|
// Останній токен — група. Вона ж — ключ до профілю групи (довідників).
|
|
result.Group = tokens[len(tokens)-1]
|
|
|
|
// Передостанній — рік
|
|
last := len(tokens) - 2
|
|
if yearRegexp.MatchString(tokens[last]) {
|
|
result.Year, _ = strconv.Atoi(tokens[last])
|
|
last--
|
|
}
|
|
|
|
// Рухаємось вліво по хвосту: format, source, bit_depth, resolution, language, edition.
|
|
// Кожен слот бере токен лише зі свого словника (регістронезалежно).
|
|
// Невідомий токен: репортимо лише якщо ліворуч ще є відомий хвостовий маркер
|
|
// (токен між двома маркерами = сміття в хвості). Інакше це початок core.
|
|
tailLoop:
|
|
for last >= 0 {
|
|
token := strings.ToUpper(tokens[last])
|
|
|
|
switch {
|
|
case Profile.FormatTokens[token]:
|
|
if result.Format == "" {
|
|
result.Format = token
|
|
}
|
|
last--
|
|
|
|
case Profile.SourceTokens[token]:
|
|
if result.Source == "" {
|
|
result.Source = token
|
|
}
|
|
last--
|
|
|
|
case Profile.BitDepthTokens[token]:
|
|
if result.BitDepth == "" {
|
|
result.BitDepth = token
|
|
}
|
|
last--
|
|
|
|
case Profile.ResolutionTokens[token]:
|
|
if result.Resolution == "" {
|
|
result.Resolution = token
|
|
}
|
|
last--
|
|
|
|
case Profile.LanguageMarkers[token]:
|
|
if result.Language == "" {
|
|
result.Language = token
|
|
}
|
|
last--
|
|
|
|
case Profile.EditionTokens[token]:
|
|
if result.Edition == "" {
|
|
result.Edition = token
|
|
}
|
|
last--
|
|
|
|
default:
|
|
if hasKnownTailToken(tokens[:last]) {
|
|
result.UnknownTokens = append(result.UnknownTokens, tokens[last])
|
|
last--
|
|
continue
|
|
}
|
|
break tailLoop
|
|
}
|
|
}
|
|
|
|
// Core = artist-title (все, що залишилось ліворуч)
|
|
coreTokens := tokens[:last+1]
|
|
result.Core = strings.Join(coreTokens, "-")
|
|
|
|
if len(coreTokens) >= 2 {
|
|
result.Artist = coreTokens[0]
|
|
result.Title = strings.Join(coreTokens[1:], "-")
|
|
} else if len(coreTokens) == 1 {
|
|
result.Artist = coreTokens[0]
|
|
result.Title = ""
|
|
result.Warnings = append(result.Warnings, "title not found")
|
|
}
|
|
|
|
score(&result)
|
|
return result
|
|
}
|
|
|
|
func split(raw string) []string {
|
|
parts := strings.Split(strings.TrimSpace(raw), "-")
|
|
out := make([]string, 0, len(parts))
|
|
for _, part := range parts {
|
|
if part = strings.TrimSpace(part); part != "" {
|
|
out = append(out, part)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// hasKnownTailToken reports whether any token is a known tail marker
|
|
// (format, source, bit_depth, resolution, edition, language or a year).
|
|
func hasKnownTailToken(tokens []string) bool {
|
|
for _, tok := range tokens {
|
|
up := strings.ToUpper(tok)
|
|
if Profile.FormatTokens[up] || Profile.SourceTokens[up] ||
|
|
Profile.BitDepthTokens[up] || Profile.ResolutionTokens[up] ||
|
|
Profile.EditionTokens[up] || Profile.LanguageMarkers[up] {
|
|
return true
|
|
}
|
|
if yearRegexp.MatchString(up) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func score(result *releaseparser.ParsedRelease) {
|
|
score := 0.0
|
|
if result.Group != "" {
|
|
score += 0.25
|
|
}
|
|
if result.Year != 0 {
|
|
score += 0.20
|
|
}
|
|
if result.Format != "" {
|
|
score += 0.15
|
|
}
|
|
if result.Source != "" {
|
|
score += 0.15
|
|
}
|
|
if result.Artist != "" {
|
|
score += 0.15
|
|
}
|
|
if len(result.Warnings) == 0 {
|
|
score += 0.10
|
|
}
|
|
if len(result.UnknownTokens) > 0 {
|
|
score -= 0.10
|
|
}
|
|
if score > 1 {
|
|
score = 1
|
|
}
|
|
if score < 0 {
|
|
score = 0
|
|
}
|
|
result.Confidence = score
|
|
}
|