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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -19,24 +18,58 @@ const (
|
||||||
musicPath = absBasePath + "/music"
|
musicPath = absBasePath + "/music"
|
||||||
programsPath = absBasePath + "/programs"
|
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 (
|
const (
|
||||||
series = iota
|
series kindOf = iota
|
||||||
film
|
film
|
||||||
music
|
music
|
||||||
program
|
program
|
||||||
)
|
)
|
||||||
|
|
||||||
var maybeSeries, maybeFilm, maybeMusic, maybeProgram *regexp.Regexp
|
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 {
|
func (c classification) add(element string, kind kindOf) {
|
||||||
if _, ok := c[element]; ok {
|
if pre, ok := c[element]; ok {
|
||||||
return errYetPresent
|
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
|
c[element] = kind
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c classification) get(element string) (string, bool) {
|
func (c classification) get(element string) (string, bool) {
|
||||||
|
@ -44,21 +77,11 @@ func (c classification) get(element string) (string, bool) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
switch kind {
|
return fmt.Sprint(kind), true
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cls classification
|
var cls classification
|
||||||
|
var l *log.Logger
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
maybeSeries = regexp.MustCompile(`(?i)^.*(((s|S)(\d+)((e|E)(\d+))?)|((season)(\ )?(\d+)?)).*\.(mkv|mp4|avi)$`)
|
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)$`)
|
maybeMusic = regexp.MustCompile(`(?i)^.*\.(mp3|ogg|flac)$`)
|
||||||
maybeProgram = regexp.MustCompile(`(?i)^.*\.(zip|tar|tar\.gz|exe|msi|rar)$`)
|
maybeProgram = regexp.MustCompile(`(?i)^.*\.(zip|tar|tar\.gz|exe|msi|rar)$`)
|
||||||
cls = make(classification)
|
cls = make(classification)
|
||||||
|
l = log.Default()
|
||||||
}
|
}
|
||||||
|
|
||||||
func isInSpecialDir(dir string) bool {
|
func isInSpecialDir(dir string) bool {
|
||||||
|
@ -85,7 +109,39 @@ func isInSpecialDir(dir string) bool {
|
||||||
return false
|
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
|
// skip directories
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
|
@ -94,9 +150,62 @@ func find(name string, info fs.FileInfo, err error) error {
|
||||||
if isInSpecialDir(name) {
|
if isInSpecialDir(name) {
|
||||||
return nil
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func link(basePath, target string, kind kindOf) error {
|
||||||
fmt.Println("vim-go")
|
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