Working thing
This commit is contained in:
parent
bcb6c0f388
commit
d4a632f48d
3
go.mod
Normal file
3
go.mod
Normal file
|
@ -0,0 +1,3 @@
|
|||
module git.abbiamoundominio.org/blallo/classifier
|
||||
|
||||
go 1.16
|
155
main.go
155
main.go
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
|
@ -19,24 +18,58 @@ const (
|
|||
musicPath = absBasePath + "/music"
|
||||
programsPath = absBasePath + "/programs"
|
||||
)
|
||||
|
||||
type kindOf int
|
||||
|
||||
func (k kindOf) String() string {
|
||||
switch k {
|
||||
case series:
|
||||
return "series"
|
||||
case film:
|
||||
return "film"
|
||||
case music:
|
||||
return "music"
|
||||
case program:
|
||||
return "program"
|
||||
default:
|
||||
panic("Unkwnown kind")
|
||||
}
|
||||
}
|
||||
|
||||
func (k kindOf) replace(other kindOf) bool {
|
||||
switch {
|
||||
case k == program && other == film:
|
||||
return true
|
||||
case k == program && other == series:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
series = iota
|
||||
series kindOf = iota
|
||||
film
|
||||
music
|
||||
program
|
||||
)
|
||||
|
||||
var maybeSeries, maybeFilm, maybeMusic, maybeProgram *regexp.Regexp
|
||||
var errYetPresent = errors.New("element yet present")
|
||||
|
||||
type classification map[string]int
|
||||
type classification map[string]kindOf
|
||||
|
||||
func (c classification) add(element string, kind int) error {
|
||||
if _, ok := c[element]; ok {
|
||||
return errYetPresent
|
||||
func (c classification) add(element string, kind kindOf) {
|
||||
if pre, ok := c[element]; ok {
|
||||
if kind == pre {
|
||||
return
|
||||
}
|
||||
l.Printf("%s yet present with different type (%s != %s)\n", element, pre, kind)
|
||||
if !pre.replace(kind) {
|
||||
l.Printf("(%s > %s), replacing kind for %s\n", kind, pre, element)
|
||||
return
|
||||
}
|
||||
}
|
||||
c[element] = kind
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c classification) get(element string) (string, bool) {
|
||||
|
@ -44,21 +77,11 @@ func (c classification) get(element string) (string, bool) {
|
|||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
switch kind {
|
||||
case series:
|
||||
return "series", true
|
||||
case film:
|
||||
return "film", true
|
||||
case music:
|
||||
return "music", true
|
||||
case program:
|
||||
return "program", true
|
||||
default:
|
||||
panic(fmt.Sprintf("kind value now allowed: %d\n", kind))
|
||||
}
|
||||
return fmt.Sprint(kind), true
|
||||
}
|
||||
|
||||
var cls classification
|
||||
var l *log.Logger
|
||||
|
||||
func init() {
|
||||
maybeSeries = regexp.MustCompile(`(?i)^.*(((s|S)(\d+)((e|E)(\d+))?)|((season)(\ )?(\d+)?)).*\.(mkv|mp4|avi)$`)
|
||||
|
@ -66,6 +89,7 @@ func init() {
|
|||
maybeMusic = regexp.MustCompile(`(?i)^.*\.(mp3|ogg|flac)$`)
|
||||
maybeProgram = regexp.MustCompile(`(?i)^.*\.(zip|tar|tar\.gz|exe|msi|rar)$`)
|
||||
cls = make(classification)
|
||||
l = log.Default()
|
||||
}
|
||||
|
||||
func isInSpecialDir(dir string) bool {
|
||||
|
@ -85,7 +109,39 @@ func isInSpecialDir(dir string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func find(name string, info fs.FileInfo, err error) error {
|
||||
func baseDirOrFile(name string) string {
|
||||
dir := filepath.Dir(name)
|
||||
if dir == absBasePath {
|
||||
return name
|
||||
}
|
||||
rel := strings.Trim(strings.Replace(dir, absBasePath, "", 1), "/")
|
||||
comps := strings.Split(rel, "/")
|
||||
return filepath.Join(absBasePath, comps[0])
|
||||
}
|
||||
|
||||
func findSeriesByDir(path string, d fs.DirEntry, err error) error {
|
||||
if !d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
videoFiles := []string{}
|
||||
for _, f := range files {
|
||||
if maybeFilm.Match([]byte(f.Name())) {
|
||||
videoFiles = append(videoFiles, f.Name())
|
||||
}
|
||||
}
|
||||
|
||||
if len(videoFiles) > 2 {
|
||||
cls.add(baseDirOrFile(path), series)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func findByFile(name string, info fs.FileInfo, err error) error {
|
||||
// skip directories
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
|
@ -94,9 +150,62 @@ func find(name string, info fs.FileInfo, err error) error {
|
|||
if isInSpecialDir(name) {
|
||||
return nil
|
||||
}
|
||||
baseFile := baseDirOrFile(name)
|
||||
base := filepath.Base(name)
|
||||
v := []byte(base)
|
||||
switch {
|
||||
case maybeSeries.Match(v):
|
||||
cls.add(baseFile, series)
|
||||
case maybeFilm.Match(v):
|
||||
cls.add(baseFile, film)
|
||||
case maybeMusic.Match(v):
|
||||
cls.add(baseFile, music)
|
||||
case maybeProgram.Match(v):
|
||||
cls.add(baseFile, program)
|
||||
default:
|
||||
l.Printf("No match: %s\n", base)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("vim-go")
|
||||
func link(basePath, target string, kind kindOf) error {
|
||||
targetName := filepath.Base(target)
|
||||
switch kind {
|
||||
case series:
|
||||
src := filepath.Join(basePath, "series", targetName)
|
||||
return doLink(target, src)
|
||||
case film:
|
||||
src := filepath.Join(basePath, "film", targetName)
|
||||
return doLink(target, src)
|
||||
case music:
|
||||
src := filepath.Join(basePath, "music", targetName)
|
||||
return doLink(target, src)
|
||||
case program:
|
||||
src := filepath.Join(basePath, "programs", targetName)
|
||||
return doLink(target, src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func doLink(target, src string) error {
|
||||
err := os.Symlink(target, src)
|
||||
if err == os.ErrExist {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := filepath.WalkDir(absBasePath, findSeriesByDir); err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
if err := filepath.Walk(absBasePath, findByFile); err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
l.Printf("Result: %s\n", cls)
|
||||
for file, kind := range cls {
|
||||
if err := link(absBasePath, file, kind); err != nil {
|
||||
l.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
174
main_test.go
Normal file
174
main_test.go
Normal file
|
@ -0,0 +1,174 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsInSpecialDir(t *testing.T) {
|
||||
special := []string{
|
||||
filepath.Join(absBasePath, "series", "media1", "file"),
|
||||
filepath.Join(absBasePath, "film", "file"),
|
||||
filepath.Join(absBasePath, "music", "album", "file"),
|
||||
filepath.Join(absBasePath, "programs", "file"),
|
||||
}
|
||||
|
||||
for _, s := range special {
|
||||
if !isInSpecialDir(s) {
|
||||
t.Errorf("Should be special: %s\n", s)
|
||||
}
|
||||
}
|
||||
|
||||
other := []string{
|
||||
filepath.Join(absBasePath, "media1", "film", "file"),
|
||||
filepath.Join(absBasePath, "aFilm", "film", "file"),
|
||||
filepath.Join(absBasePath, "album", "music", "file"),
|
||||
filepath.Join(absBasePath, "myProgram", "program", "theProgram.exe"),
|
||||
}
|
||||
|
||||
for _, o := range other {
|
||||
if isInSpecialDir(o) {
|
||||
t.Errorf("Should be special: %s\n", o)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaseDirOrFile(t *testing.T) {
|
||||
data := []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: filepath.Join(absBasePath, "file"),
|
||||
expected: filepath.Join(absBasePath, "file"),
|
||||
},
|
||||
{
|
||||
name: filepath.Join(absBasePath, "baseDir", "file"),
|
||||
expected: filepath.Join(absBasePath, "baseDir"),
|
||||
},
|
||||
{
|
||||
name: filepath.Join(absBasePath, "baseDir", "otherDir", "file"),
|
||||
expected: filepath.Join(absBasePath, "baseDir"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, datum := range data {
|
||||
if res := baseDirOrFile(datum.name); res != datum.expected {
|
||||
t.Errorf("%s != %s\n", res, datum.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLink(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("/tmp", "classifier-test-*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, d := range []string{"series", "film", "music", "programs"} {
|
||||
if err := os.Mkdir(filepath.Join(dir, d), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
testDirs := []struct {
|
||||
path string
|
||||
kind kindOf
|
||||
}{
|
||||
{path: filepath.Join(dir, "testFilm1"), kind: film},
|
||||
{path: filepath.Join(dir, "testSeries"), kind: series},
|
||||
{path: filepath.Join(dir, "testAlbum"), kind: music},
|
||||
{path: filepath.Join(dir, "testProgram1"), kind: program},
|
||||
}
|
||||
for _, d := range testDirs {
|
||||
err := os.Mkdir(d.path, 0700)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = link(dir, d.path, d.kind)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
testFiles := []struct {
|
||||
path string
|
||||
kind kindOf
|
||||
}{
|
||||
{path: filepath.Join(dir, "testFilm2.avi"), kind: film},
|
||||
{path: filepath.Join(dir, "testProgram2.exe"), kind: program},
|
||||
}
|
||||
for _, f := range testFiles {
|
||||
fh, err := os.Create(f.path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fh.Close()
|
||||
err = link(dir, f.path, f.kind)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fFilm, err := ioutil.ReadDir(filepath.Join(dir, "film"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sFilm := []string{}
|
||||
for _, f := range fFilm {
|
||||
sFilm = append(sFilm, f.Name())
|
||||
}
|
||||
if reflect.DeepEqual(sFilm, []string{
|
||||
filepath.Join(dir, "film", "testFilm1"),
|
||||
filepath.Join(dir, "film", "testFilm2.avi"),
|
||||
}) {
|
||||
t.Errorf("Unexpected film links: %s\n", sFilm)
|
||||
}
|
||||
|
||||
fSeries, err := ioutil.ReadDir(filepath.Join(dir, "series"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sSeries := []string{}
|
||||
for _, f := range fSeries {
|
||||
sSeries = append(sSeries, f.Name())
|
||||
}
|
||||
if reflect.DeepEqual(sFilm, []string{
|
||||
filepath.Join(dir, "film", "testSeries"),
|
||||
}) {
|
||||
t.Errorf("Unexpected series links: %s\n", sFilm)
|
||||
}
|
||||
|
||||
fMusic, err := ioutil.ReadDir(filepath.Join(dir, "music"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sMusic := []string{}
|
||||
for _, f := range fMusic {
|
||||
sMusic = append(sMusic, f.Name())
|
||||
}
|
||||
if reflect.DeepEqual(sMusic, []string{
|
||||
filepath.Join(dir, "film", "testAlbum"),
|
||||
}) {
|
||||
t.Errorf("Unexpected music links: %s\n", sMusic)
|
||||
}
|
||||
|
||||
fProg, err := ioutil.ReadDir(filepath.Join(dir, "film"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sProg := []string{}
|
||||
for _, f := range fProg {
|
||||
sProg = append(sProg, f.Name())
|
||||
}
|
||||
if reflect.DeepEqual(sProg, []string{
|
||||
filepath.Join(dir, "film", "testProgram1"),
|
||||
filepath.Join(dir, "film", "testProgram2.exe"),
|
||||
}) {
|
||||
t.Errorf("Unexpected programs links: %s\n", sProg)
|
||||
}
|
||||
os.RemoveAll(dir)
|
||||
}
|
Loading…
Reference in New Issue
Block a user