2021-08-30 03:20:38 +00:00
|
|
|
package categorize
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io/fs"
|
|
|
|
"os"
|
2021-09-04 01:33:31 +00:00
|
|
|
|
2021-09-04 04:20:48 +00:00
|
|
|
"github.com/ollien/gobbler/categorize/match"
|
2021-09-04 01:33:31 +00:00
|
|
|
"github.com/ollien/gobbler/categorize/tv"
|
2021-08-30 03:20:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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)
|
2021-09-04 01:33:31 +00:00
|
|
|
func (c Categorizer) CategorizeFile(filename string) (tv.Location, error) {
|
2021-08-30 03:20:38 +00:00
|
|
|
showFolder, err := c.findShowFolder(filename)
|
2021-09-04 04:20:48 +00:00
|
|
|
if errors.Is(err, tv.ErrNotTvShow) {
|
|
|
|
return tv.Location{}, match.ErrNoMatches
|
|
|
|
} else if err != nil {
|
2021-09-04 01:33:31 +00:00
|
|
|
return tv.Location{}, fmt.Errorf("could not find show folder for categorization: %w", err)
|
2021-08-30 03:20:38 +00:00
|
|
|
}
|
|
|
|
|
2021-09-04 01:33:31 +00:00
|
|
|
seasons, err := tv.GetSeasonsForFile(filename)
|
2021-08-30 03:20:38 +00:00
|
|
|
if err != nil {
|
2021-09-04 01:33:31 +00:00
|
|
|
return tv.Location{}, fmt.Errorf("could not find seasons for show: %w", err)
|
2021-08-30 03:20:38 +00:00
|
|
|
}
|
|
|
|
|
2021-09-04 01:33:31 +00:00
|
|
|
return tv.NewLocation(showFolder, seasons), nil
|
2021-08-30 03:20:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
2021-09-04 01:33:31 +00:00
|
|
|
showFolder, err := tv.FindShowFolder(filename, showFolderNames)
|
2021-08-30 03:20:38 +00:00
|
|
|
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
|
|
|
|
}
|