more initial changes

This commit is contained in:
Javis Sullivan
2025-12-08 07:56:46 -05:00
parent 0e0fe0e37c
commit 4bed19ab73
14 changed files with 701 additions and 32 deletions

View File

@@ -1,27 +1,112 @@
package classifier
import (
"fmt"
"path/filepath"
"regexp"
"strconv"
"strings"
"mediawatcher/internal/config"
)
var movieYear = regexp.MustCompile(`(?i)(19|20)\d{2}`)
type Type string
func classifyMovie(filename string) (bool, string, int) {
base := strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename))
const (
TypeTV Type = "tv"
TypeMovie Type = "movie"
TypeMisc Type = "misc"
TypeUnknown Type = "unknown"
)
// Find year
yearMatch := movieYear.FindString(base)
if yearMatch == "" {
return false, "", 0
type Result struct {
Type Type
Title string
Season int
Episode int
Year int
DestDir string
DestName string
SourcePath string
}
// regexes
var (
tvPattern = regexp.MustCompile(`(?i)(S?(\d{1,2}))[ ._-]*[Ex](\d{1,3})`)
yearPattern = regexp.MustCompile(`\b(19\d{2}|20[0-3]\d)\b`)
)
func Classify(path string, cfg *config.Config) Result {
base := filepath.Base(path)
nameNoExt := strings.TrimSuffix(base, filepath.Ext(base))
// TV first
if m := tvPattern.FindStringSubmatch(nameNoExt); len(m) == 4 {
season := atoiSafe(m[2])
episode := atoiSafe(m[3])
cleaned := tvPattern.ReplaceAllString(nameNoExt, "")
title := cleanupTitle(cleaned)
destDir := filepath.Join(cfg.Structure.TVDir, title, fmt.Sprintf("Season %02d", season))
return Result{
Type: TypeTV,
Title: title,
Season: season,
Episode: episode,
DestDir: destDir,
DestName: base,
SourcePath: path,
}
}
year := parseInt(yearMatch)
// Movie
if ym := yearPattern.FindString(nameNoExt); ym != "" {
year := atoiSafe(ym)
cleaned := strings.Replace(nameNoExt, ym, "", 1)
title := cleanupTitle(cleaned)
destDir := filepath.Join(cfg.Structure.MoviesDir, fmt.Sprintf("%s (%d)", title, year))
// Extract title (everything before year)
title := strings.TrimSpace(strings.Replace(base, yearMatch, "", 1))
title = cleanupTitle(title)
return Result{
Type: TypeMovie,
Title: title,
Year: year,
DestDir: destDir,
DestName: base,
SourcePath: path,
}
}
return true, title, year
// Misc based on extension
ext := strings.ToLower(filepath.Ext(base))
if ext == ".mp3" || ext == ".flac" || ext == ".m4a" || ext == ".aac" {
return Result{
Type: TypeMisc,
DestDir: cfg.Structure.MiscDir,
DestName: base,
SourcePath: path,
}
}
// Unknown
return Result{
Type: TypeUnknown,
DestDir: cfg.Structure.UnknownDir,
DestName: base,
SourcePath: path,
}
}
func cleanupTitle(s string) string {
s = strings.ReplaceAll(s, ".", " ")
s = strings.ReplaceAll(s, "_", " ")
s = strings.ReplaceAll(s, "-", " ")
s = strings.Join(strings.Fields(s), " ")
return strings.TrimSpace(s)
}
func atoiSafe(s string) int {
n, _ := strconv.Atoi(s)
return n
}