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 }