Add basic CLI tool to print results
parent
7a34955318
commit
8c42ea05be
|
@ -6,6 +6,7 @@ import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/ollien/gobbler/categorize/match"
|
||||||
"github.com/ollien/gobbler/categorize/tv"
|
"github.com/ollien/gobbler/categorize/tv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +36,9 @@ func newCategorizerForFS(libraryFs fs.FS) Categorizer {
|
||||||
// (though the season folder need not exist)
|
// (though the season folder need not exist)
|
||||||
func (c Categorizer) CategorizeFile(filename string) (tv.Location, error) {
|
func (c Categorizer) CategorizeFile(filename string) (tv.Location, error) {
|
||||||
showFolder, err := c.findShowFolder(filename)
|
showFolder, err := c.findShowFolder(filename)
|
||||||
if err != nil {
|
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)
|
return tv.Location{}, fmt.Errorf("could not find show folder for categorization: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,14 @@ import (
|
||||||
"github.com/ollien/gobbler/categorize/match"
|
"github.com/ollien/gobbler/categorize/match"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errNotTvShow = errors.New("no tv-like information found in show name")
|
var ErrNotTvShow = errors.New("no tv-like information found in show name")
|
||||||
|
|
||||||
// FindShowFolder finds the show that the given filename likey belongs to, among the given show folders.
|
// FindShowFolder finds the show that the given filename likey belongs to, among the given show folders.
|
||||||
// Returns errNotTvShow if no match can be found
|
// Returns ErrNotTvShow if no match can be found
|
||||||
func FindShowFolder(filename string, showFolders []string) (string, error) {
|
func FindShowFolder(filename string, showFolders []string) (string, error) {
|
||||||
possibleShowName, err := extractShowName(filename)
|
possibleShowName, err := extractShowName(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errNotTvShow
|
return "", ErrNotTvShow
|
||||||
}
|
}
|
||||||
|
|
||||||
return matchToFolder(possibleShowName, showFolders)
|
return matchToFolder(possibleShowName, showFolders)
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ollien/gobbler/categorize"
|
||||||
|
"github.com/ollien/gobbler/categorize/match"
|
||||||
|
"github.com/ollien/gobbler/categorize/tv"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fileLocationMap = map[string]tv.Location
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) != 3 {
|
||||||
|
fmt.Fprintln(os.Stderr, "Usage: ./gobbler sourceFolder libraryFolder")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceFolder, libraryFolder := os.Args[1], os.Args[2]
|
||||||
|
|
||||||
|
sourceFolderContents, err := getDirEntries(sourceFolder)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
categorizer, err := categorize.NewCategorizer(libraryFolder)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
locations := performCategorization(categorizer, sourceFolderContents)
|
||||||
|
prettyPrintLocations(locations)
|
||||||
|
|
||||||
|
numSkipped := len(sourceFolderContents) - len(locations)
|
||||||
|
fmt.Fprintf(os.Stderr, "%d items not categorized\n", numSkipped)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDirEntries(path string) ([]string, error) {
|
||||||
|
fd, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer fd.Close()
|
||||||
|
|
||||||
|
return fd.Readdirnames(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// performCategorization categorizes the given files through the given categorizer, converting them to a map of
|
||||||
|
// filename to Locations
|
||||||
|
func performCategorization(categorizer categorize.Categorizer, sourceFolderContents []string) fileLocationMap {
|
||||||
|
locations := map[string]tv.Location{}
|
||||||
|
for _, entry := range sourceFolderContents {
|
||||||
|
location, err := categorizer.CategorizeFile(entry)
|
||||||
|
if errors.Is(err, match.ErrNoMatches) {
|
||||||
|
continue
|
||||||
|
} else if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to categorize '%s':\n\t%s\n", entry, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
locations[entry] = location
|
||||||
|
}
|
||||||
|
|
||||||
|
return locations
|
||||||
|
}
|
||||||
|
|
||||||
|
func prettyPrintLocations(locations fileLocationMap) {
|
||||||
|
for filename, location := range locations {
|
||||||
|
color.New(color.FgGreen, color.Bold).Println(filename)
|
||||||
|
seasonString := "Season"
|
||||||
|
if len(location.Seasons()) > 1 {
|
||||||
|
seasonString = "Seasons"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(" ├── %s\n", location.MediaTitle())
|
||||||
|
fmt.Printf(" └── %s %s\n", seasonString, joinIntsGramatically(location.Seasons()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// joinIntsGramatically joins a seqwuence of ints as a comma separated list of strings, compelte with "and" and
|
||||||
|
// oxford comma (e.g. "1, 2, 3, 4, and 5")
|
||||||
|
func joinIntsGramatically(nums []int) string {
|
||||||
|
if len(nums) == 0 {
|
||||||
|
return ""
|
||||||
|
} else if len(nums) == 1 {
|
||||||
|
return strconv.Itoa(nums[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
numStrings := make([]string, len(nums))
|
||||||
|
for i, num := range nums {
|
||||||
|
numStrings[i] = strconv.Itoa(num)
|
||||||
|
}
|
||||||
|
|
||||||
|
joined := strings.Join(numStrings[:len(numStrings)-1], ", ")
|
||||||
|
|
||||||
|
return joined + ", and " + numStrings[len(numStrings)-1]
|
||||||
|
}
|
5
go.mod
5
go.mod
|
@ -3,6 +3,7 @@ module github.com/ollien/gobbler
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/agnivade/levenshtein v1.1.1 // indirect
|
github.com/agnivade/levenshtein v1.1.1
|
||||||
github.com/stretchr/testify v1.7.0 // indirect
|
github.com/fatih/color v1.12.0
|
||||||
|
github.com/stretchr/testify v1.7.0
|
||||||
)
|
)
|
||||||
|
|
11
go.sum
11
go.sum
|
@ -1,13 +1,21 @@
|
||||||
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
|
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
|
||||||
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
|
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
|
||||||
|
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||||
github.com/bevacqua/fuzzysearch v1.0.2 h1:23dOu/69YB8gzAIc2vk4eWtY2lg8YgCcTMQwg2QVyvA=
|
github.com/bevacqua/fuzzysearch v1.0.2 h1:23dOu/69YB8gzAIc2vk4eWtY2lg8YgCcTMQwg2QVyvA=
|
||||||
github.com/bevacqua/fuzzysearch v1.0.2/go.mod h1:Pjn0r0ohRYG/5PnkllhikX34r67ITFOdCM32/uJnxl4=
|
github.com/bevacqua/fuzzysearch v1.0.2/go.mod h1:Pjn0r0ohRYG/5PnkllhikX34r67ITFOdCM32/uJnxl4=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
|
||||||
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||||
|
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
|
||||||
|
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
github.com/lithammer/fuzzysearch v1.1.2 h1:ePUtm14xKxbpCxozcFbIDRtvANxnVnE+RKpJUqkr2gA=
|
github.com/lithammer/fuzzysearch v1.1.2 h1:ePUtm14xKxbpCxozcFbIDRtvANxnVnE+RKpJUqkr2gA=
|
||||||
github.com/lithammer/fuzzysearch v1.1.2/go.mod h1:v6tYW/9kpfV6LNcweXdSjQsfCku/1M/oObmSox1fzP8=
|
github.com/lithammer/fuzzysearch v1.1.2/go.mod h1:v6tYW/9kpfV6LNcweXdSjQsfCku/1M/oObmSox1fzP8=
|
||||||
|
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||||
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
||||||
|
@ -16,6 +24,9 @@ github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
|
||||||
|
|
Loading…
Reference in New Issue