more initial changes
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user