Compare commits
5 commits
5e8f954a14
...
ac0baba3a8
| Author | SHA1 | Date | |
|---|---|---|---|
| ac0baba3a8 | |||
| 64b2242567 | |||
| 1abe398c7a | |||
| 56fd7bf0b4 | |||
| 1b072f42d3 |
8 changed files with 211 additions and 78 deletions
|
|
@ -7,7 +7,11 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SelfCancelingCotext(ctx context.Context) (context.Context, context.CancelFunc) {
|
func SelfCancelingContextFromBackground() (context.Context, context.CancelFunc) {
|
||||||
|
return SelfCancelingContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
func SelfCancelingContext(ctx context.Context) (context.Context, context.CancelFunc) {
|
||||||
c, done := context.WithCancel(ctx)
|
c, done := context.WithCancel(ctx)
|
||||||
ch := make(chan os.Signal, 1)
|
ch := make(chan os.Signal, 1)
|
||||||
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,24 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"codeberg.org/danjones000/utils/chill"
|
|
||||||
c "codeberg.org/danjones000/utils/cli/context"
|
c "codeberg.org/danjones000/utils/cli/context"
|
||||||
e "codeberg.org/danjones000/utils/cli/err"
|
e "codeberg.org/danjones000/utils/cli/err"
|
||||||
"codeberg.org/danjones000/utils/cli/spin"
|
ccli "codeberg.org/danjones000/utils/internal/cli/convids"
|
||||||
"codeberg.org/danjones000/utils/convids"
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const dataPath = "shows.yml"
|
const dataPath = "shows.yml"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
loop := pflag.BoolP("loop", "l", false, "Loop")
|
ctx, done := c.SelfCancelingContextFromBackground()
|
||||||
help := pflag.BoolP("help", "h", false, "Get Help")
|
|
||||||
dryRun := pflag.BoolP("dry-run", "d", false, "Do a dry run")
|
|
||||||
pflag.Parse()
|
|
||||||
|
|
||||||
if *help {
|
|
||||||
pflag.Usage()
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, done := c.SelfCancelingCotext(context.Background())
|
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
var walker convids.ShowWalker
|
app, err := ccli.NewApp(ctx, os.Args[0], os.Args[1:], dataPath, os.Stdout, os.Stdin, os.Stderr)
|
||||||
if *dryRun {
|
|
||||||
*loop = false
|
|
||||||
walker = convids.DryRun(os.Stdout)
|
|
||||||
} else {
|
|
||||||
gs := convids.GetShow(ctx)
|
|
||||||
|
|
||||||
walker = func(s *convids.Show, path string) error {
|
|
||||||
ct := chill.Chill(ctx)
|
|
||||||
msg := fmt.Sprintf("Waiting for CPU to cool, for %s", path)
|
|
||||||
sp := spin.Spin(ct, msg)
|
|
||||||
err := sp.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return gs(s, path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := convids.NewData(dataPath)
|
|
||||||
e.HandleErr(err)
|
e.HandleErr(err)
|
||||||
|
|
||||||
groupPrinter := convids.PrintGroupName(os.Stdout)
|
err = app.Run(ctx)
|
||||||
|
|
||||||
if *loop {
|
|
||||||
fmt.Println("looping")
|
|
||||||
for err == nil {
|
|
||||||
err = convids.WalkFiles(data, false, groupPrinter, walker)
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = convids.WalkFiles(data, false, groupPrinter, walker)
|
|
||||||
}
|
|
||||||
e.HandleErr(err)
|
e.HandleErr(err)
|
||||||
|
|
||||||
fmt.Println("Done!")
|
fmt.Println("Done!")
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, done := c.SelfCancelingCotext(context.Background())
|
ctx, done := c.SelfCancelingContext(context.Background())
|
||||||
defer done()
|
defer done()
|
||||||
ctx = chill.Chill(ctx)
|
ctx = chill.Chill(ctx)
|
||||||
s := spin.Spin(ctx, "Waiting for CPU to cool...")
|
s := spin.Spin(ctx, "Waiting for CPU to cool...")
|
||||||
|
|
|
||||||
101
convids/logic.go
101
convids/logic.go
|
|
@ -39,21 +39,32 @@ type GroupPrinter func(name string, group Shows)
|
||||||
var ErrNoFiles = errors.New("no files processed")
|
var ErrNoFiles = errors.New("no files processed")
|
||||||
var ErrSkipped = errors.New("skipped")
|
var ErrSkipped = errors.New("skipped")
|
||||||
|
|
||||||
func processFile(conf *Config, walk ShowWalker, show *Show, file os.DirEntry) (processed bool, processError, cbError error) {
|
type processInput struct {
|
||||||
|
file os.DirEntry
|
||||||
|
source string
|
||||||
|
show *Show
|
||||||
|
extRe *regexp.Regexp
|
||||||
|
skips []string
|
||||||
|
walk ShowWalker
|
||||||
|
}
|
||||||
|
|
||||||
|
func processFile(input processInput) (processed bool, processError, cbError error) {
|
||||||
|
file := input.file
|
||||||
if file.IsDir() {
|
if file.IsDir() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !conf.extRe.MatchString(file.Name()) {
|
if !input.extRe.MatchString(file.Name()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
show := input.show
|
||||||
var found bool
|
var found bool
|
||||||
found, processError = show.Match(file.Name())
|
found, processError = show.Match(file.Name())
|
||||||
if processError != nil || !found {
|
if processError != nil || !found {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
path := fp.Join(conf.Source, file.Name())
|
path := fp.Join(input.source, file.Name())
|
||||||
for _, ext := range conf.Skip {
|
for _, ext := range input.skips {
|
||||||
if !strings.HasPrefix(ext, ".") {
|
if !strings.HasPrefix(ext, ".") {
|
||||||
ext = "." + ext
|
ext = "." + ext
|
||||||
}
|
}
|
||||||
|
|
@ -64,13 +75,31 @@ func processFile(conf *Config, walk ShowWalker, show *Show, file os.DirEntry) (p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cbError = walk(show, path)
|
cbError = input.walk(show, path)
|
||||||
if cbError == nil {
|
if cbError == nil {
|
||||||
processed = true
|
processed = true
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fileMap map[string][]os.DirEntry
|
||||||
|
|
||||||
|
func (fm fileMap) GetFiles(path string) []os.DirEntry {
|
||||||
|
files, ok := fm[path]
|
||||||
|
if ok {
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
fm.ReadPath(path)
|
||||||
|
return fm[path]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fm fileMap) ReadPath(path string) {
|
||||||
|
if _, ok := fm[path]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fm[path], _ = os.ReadDir(path)
|
||||||
|
}
|
||||||
|
|
||||||
func WalkFiles(d *Data, stopOnError bool, gp GroupPrinter, cb ShowWalker) (err error) {
|
func WalkFiles(d *Data, stopOnError bool, gp GroupPrinter, cb ShowWalker) (err error) {
|
||||||
err = ensureExtRe(d.Config)
|
err = ensureExtRe(d.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -80,33 +109,42 @@ func WalkFiles(d *Data, stopOnError bool, gp GroupPrinter, cb ShowWalker) (err e
|
||||||
cb = DryRun(os.Stdout)
|
cb = DryRun(os.Stdout)
|
||||||
}
|
}
|
||||||
count := 0
|
count := 0
|
||||||
|
allFiles := fileMap{}
|
||||||
var files []os.DirEntry
|
var files []os.DirEntry
|
||||||
files, err = os.ReadDir(d.Config.Source)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for s := range d.AllShows(gp) {
|
for s := range d.AllShows(gp) {
|
||||||
for _, file := range files {
|
if len(s.Sources) == 0 {
|
||||||
processed, processErr, cbErr := processFile(d.Config, cb, s, file)
|
s.Sources = []string{d.Config.Source}
|
||||||
if !processed && processErr == nil && cbErr == nil {
|
}
|
||||||
continue
|
showstart:
|
||||||
|
for _, source := range s.Sources {
|
||||||
|
files = allFiles.GetFiles(source)
|
||||||
|
for _, file := range files {
|
||||||
|
pIn := processInput{file, source, s, d.Config.extRe, d.Config.Skip, cb}
|
||||||
|
processed, processErr, cbErr := processFile(pIn)
|
||||||
|
if !processed && processErr == nil && cbErr == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if errors.Is(processErr, ErrSkipped) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if processErr != nil {
|
||||||
|
return processErr
|
||||||
|
}
|
||||||
|
if cbErr != nil && stopOnError {
|
||||||
|
return cbErr
|
||||||
|
}
|
||||||
|
if cbErr == nil && processed {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
if cbErr != nil {
|
||||||
|
err = cbErr
|
||||||
|
}
|
||||||
|
break showstart
|
||||||
}
|
}
|
||||||
if errors.Is(processErr, ErrSkipped) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if processErr != nil {
|
|
||||||
return processErr
|
|
||||||
}
|
|
||||||
if cbErr != nil && stopOnError {
|
|
||||||
return cbErr
|
|
||||||
}
|
|
||||||
if cbErr == nil && processed {
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
if cbErr != nil {
|
|
||||||
err = cbErr
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err == nil && count < 1 {
|
if err == nil && count < 1 {
|
||||||
|
|
@ -124,13 +162,18 @@ func DryRun(out io.Writer) ShowWalker {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetShow(ctx context.Context) ShowWalker {
|
func GetShow(ctx context.Context) ShowWalker {
|
||||||
|
return GetShowWithIO(ctx, os.Stdin, os.Stdout, os.Stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetShowWithIO(ctx context.Context, stdin io.Reader, stdout io.Writer, stderr io.Writer) ShowWalker {
|
||||||
return func(s *Show, path string) error {
|
return func(s *Show, path string) error {
|
||||||
cmd := exec.CommandContext(ctx, "get-shows", s.Folder, path)
|
cmd := exec.CommandContext(ctx, "get-shows", s.Folder, path)
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = stdin
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = stderr
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrintGroupName(out io.Writer) GroupPrinter {
|
func PrintGroupName(out io.Writer) GroupPrinter {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ type Show struct {
|
||||||
Pattern string
|
Pattern string
|
||||||
Name string
|
Name string
|
||||||
Anime bool
|
Anime bool
|
||||||
|
Sources []string
|
||||||
|
|
||||||
re *regexp.Regexp
|
re *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
|
||||||
60
internal/cli/convids/app.go
Normal file
60
internal/cli/convids/app.go
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
package convids
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
conutils "codeberg.org/danjones000/utils/convids"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
type App struct {
|
||||||
|
Name string
|
||||||
|
Data *conutils.Data
|
||||||
|
flags *pflag.FlagSet
|
||||||
|
stdout io.Writer
|
||||||
|
stderr io.Writer
|
||||||
|
stdin io.Reader
|
||||||
|
walker conutils.ShowWalker
|
||||||
|
groupPrinter conutils.GroupPrinter
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApp(ctx context.Context, name string, args []string, dataPath string, stdout io.Writer, stdin io.Reader, stderr io.Writer) (*App, error) {
|
||||||
|
a := App{Name: name, stdout: stdout, stdin: stdin, stderr: stderr}
|
||||||
|
var err error
|
||||||
|
a.flags, err = ParseFlags(name, args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a.walker = GetWalker(ctx, *DryRun, stdin, stdout, stderr)
|
||||||
|
a.Data, err = conutils.NewData(dataPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
a.groupPrinter = conutils.PrintGroupName(stdout)
|
||||||
|
|
||||||
|
return &a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Run(ctx context.Context) error {
|
||||||
|
if *Loop {
|
||||||
|
return a.runInLoop(ctx)
|
||||||
|
}
|
||||||
|
return a.run(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) run(ctx context.Context) error {
|
||||||
|
return conutils.WalkFiles(a.Data, false, a.groupPrinter, a.walker)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) runInLoop(ctx context.Context) error {
|
||||||
|
fmt.Fprintln(a.stdout, "Looping")
|
||||||
|
var err error
|
||||||
|
for err == nil {
|
||||||
|
err = a.run(ctx)
|
||||||
|
fmt.Fprintln(a.stdout, err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
39
internal/cli/convids/flags.go
Normal file
39
internal/cli/convids/flags.go
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package convids
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Help *bool
|
||||||
|
var Loop *bool
|
||||||
|
var DryRun *bool
|
||||||
|
|
||||||
|
func GetFlags(name string) *pflag.FlagSet {
|
||||||
|
flags := pflag.NewFlagSet(name, pflag.ExitOnError)
|
||||||
|
|
||||||
|
Help = flags.BoolP("help", "h", false, "Get Help")
|
||||||
|
Loop = flags.BoolP("loop", "l", false, "Loop")
|
||||||
|
DryRun = flags.BoolP("dry-run", "d", false, "Do a dry run (won't loop)")
|
||||||
|
|
||||||
|
flags.Usage = func() {
|
||||||
|
fmt.Printf("Usage of %s:\n", name)
|
||||||
|
flags.PrintDefaults()
|
||||||
|
}
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseFlags(name string, args []string) (*pflag.FlagSet, error) {
|
||||||
|
flags := GetFlags(name)
|
||||||
|
err := flags.Parse(args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if *DryRun {
|
||||||
|
flags.Set("loop", "false")
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags, nil
|
||||||
|
}
|
||||||
29
internal/cli/convids/walker.go
Normal file
29
internal/cli/convids/walker.go
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package convids
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"codeberg.org/danjones000/utils/chill"
|
||||||
|
"codeberg.org/danjones000/utils/cli/spin"
|
||||||
|
conutils "codeberg.org/danjones000/utils/convids"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetWalker(ctx context.Context, dryRun bool, in io.Reader, out, errOut io.Writer) conutils.ShowWalker {
|
||||||
|
if dryRun {
|
||||||
|
return conutils.DryRun(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
gs := conutils.GetShowWithIO(ctx, in, out, errOut)
|
||||||
|
return func(s *conutils.Show, path string) error {
|
||||||
|
ct := chill.Chill(ctx)
|
||||||
|
msg := fmt.Sprintf("Waiting for CPU to cool, for %s", path)
|
||||||
|
sp := spin.Spin(ct, msg)
|
||||||
|
err := sp.Wait()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return gs(s, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue