gobbler/categorize/categorizer.go

88 lines
2.4 KiB
Go

package categorize
import (
"errors"
"fmt"
"io/fs"
"os"
"github.com/ollien/gobbler/categorize/match"
"github.com/ollien/gobbler/categorize/tv"
)
// Categorizer will attempt to categorize media based on the names of the paths
type Categorizer struct {
libraryFS fs.FS
}
// NewCategorizer makes a new categorizer for the given library path
func NewCategorizer(libraryPath string) (Categorizer, error) {
isLibraryPathDir, err := isDir(libraryPath)
if err != nil {
return Categorizer{}, err
} else if !isLibraryPathDir {
return Categorizer{}, errors.New("libraryPath is not directory")
}
fs := os.DirFS(libraryPath)
return newCategorizerForFS(fs), err
}
func newCategorizerForFS(libraryFs fs.FS) Categorizer {
return Categorizer{libraryFS: libraryFs}
}
// CategorizeFile will categorize the given filename to an existing TV show/season folder
// (though the season folder need not exist)
func (c Categorizer) CategorizeFile(filename string) (tv.Location, error) {
showFolder, err := c.findShowFolder(filename)
if errors.Is(err, tv.ErrNotTvShow) {
return tv.Location{}, match.ErrNoMatches
} else if err != nil {
return tv.Location{}, fmt.Errorf("could not find show folder for categorization: %w", err)
}
seasons, err := tv.GetSeasonsForFile(filename)
if err != nil {
return tv.Location{}, fmt.Errorf("could not find seasons for show: %w", err)
}
return tv.NewLocation(showFolder, seasons), nil
}
// findShowFolder will find the already existing show fgolder that best matches the given show
func (c Categorizer) findShowFolder(filename string) (string, error) {
showFolders, err := fs.ReadDir(c.libraryFS, ".")
if err != nil {
return "", fmt.Errorf("could not read show folder: %w", err)
}
showFolderNames := getDirEntryNames(showFolders)
showFolder, err := tv.FindShowFolder(filename, showFolderNames)
if err != nil {
return "", fmt.Errorf("could not find folder for show: %w", err)
}
return showFolder, nil
}
// isDir checks if the given path is a directory, or an error if the check did not succeed
func isDir(path string) (bool, error) {
fileInfo, err := os.Stat(path)
if err != nil {
return false, fmt.Errorf("could not stat dir for categorization: %w", err)
}
return fileInfo.IsDir(), nil
}
// getDirEntryNames maps a slice of DirEntrys to their names
func getDirEntryNames(entries []fs.DirEntry) []string {
res := make([]string, len(entries))
for i, entry := range entries {
res[i] = entry.Name()
}
return res
}