diff --git a/arrange.go b/arrange.go index aba4f60..4d4059f 100644 --- a/arrange.go +++ b/arrange.go @@ -13,6 +13,23 @@ import ( "time" ) +var exts map[string]bool + +func init() { + exts = map[string]bool{ + // images + ".jpg": true, + ".jpeg": true, + ".png": true, + ".gif": true, + + // videos + ".mov": true, + ".mp4": true, + ".m4v": true, + } +} + type File interface { Move(root string) error } @@ -30,7 +47,7 @@ func PrepOutput(root string) error { return nil } -func Source(root string, exts map[string]bool) <-chan string { +func Source(root string) <-chan string { out := make(chan string) go func() { err := filepath.Walk( @@ -42,8 +59,6 @@ func Source(root string, exts map[string]bool) <-chan string { ext := strings.ToLower(filepath.Ext(path)) if _, ok := exts[ext]; ok { out <- path - } else { - log.Printf("ignoring: %q", path) } return nil }, @@ -118,7 +133,6 @@ func _parse(path string) (File, error) { success = true } if !success { - log.Printf("no exif for %q: %+v", path, err) t, err = mtime(path) } if err != nil { @@ -134,11 +148,9 @@ func _parse(path string) (File, error) { return nil, fmt.Errorf("problem calculating checksum on %q: %v", path, err) } r = Image{ - Path: path, - Hash: fmt.Sprintf("%x", hash.Sum(nil)), - Year: fmt.Sprintf("%04d", t.Year()), - Month: fmt.Sprintf("%02d", t.Month()), - Time: fmt.Sprintf("%d", t.UnixNano()), + Path: path, + Hash: fmt.Sprintf("%x", hash.Sum(nil)), + Time: t, } case ".png": return nil, fmt.Errorf("NYI: %q", path) diff --git a/cmd/am/main.go b/cmd/am/main.go index 4a3805b..fe2c5fc 100644 --- a/cmd/am/main.go +++ b/cmd/am/main.go @@ -1,9 +1,11 @@ package main import ( + "flag" "fmt" "log" "os" + "runtime" "mcquay.me/arrange" ) @@ -16,36 +18,31 @@ type stats struct { moved int } +var cores = flag.Int("cores", 0, "how many threads to use") + func main() { + flag.Parse() log.SetFlags(log.Lshortfile) - if len(os.Args) != 3 { + if len(flag.Args()) != 2 { fmt.Fprintf(os.Stderr, "%s\n", usage) os.Exit(1) } - in, out := os.Args[1], os.Args[2] + in, out := flag.Args()[0], flag.Args()[1] if err := arrange.PrepOutput(out); err != nil { fmt.Fprintf(os.Stderr, "problem creating directory structure: %v", err) os.Exit(1) } - exts := map[string]bool{ - // images - ".jpg": true, - ".jpeg": true, - ".png": true, - ".gif": true, - - // videos - ".mov": true, - ".mp4": true, - ".m4v": true, - } - - work := arrange.Source(in, exts) + work := arrange.Source(in) streams := []<-chan arrange.File{} - for w := 0; w < 16; w++ { + workers := runtime.NumCPU() + if *cores != 0 { + workers = *cores + } + + for w := 0; w < workers; w++ { streams = append(streams, arrange.Parse(work)) } diff --git a/image.go b/image.go index 968dc39..77f98e6 100644 --- a/image.go +++ b/image.go @@ -20,11 +20,9 @@ func (m Media) Move(root string) error { } type Image struct { - Path string - Hash string - Year string - Month string - Time string + Path string + Hash string + Time time.Time } func (im Image) Move(root string) error { @@ -49,11 +47,16 @@ func (im Image) Move(root string) error { if _, err := io.Copy(out, f); err != nil { return fmt.Errorf("trouble copying file: %v", err) } - if err := os.MkdirAll(filepath.Join(root, "date", im.Year, im.Month), 0755); err != nil { + + year := fmt.Sprintf("%04d", im.Time.Year()) + month := fmt.Sprintf("%02d", im.Time.Month()) + ts := fmt.Sprintf("%d", im.Time.UnixNano()) + + if err := os.MkdirAll(filepath.Join(root, "date", year, month), 0755); err != nil { return fmt.Errorf("problem creating date directory: %v", err) } - date := filepath.Join(root, "date", im.Year, im.Month, im.Time) + date := filepath.Join(root, "date", year, month, ts) name := date + ".jpg" for i := 0; i < 10000; i++ { if _, err := os.Stat(name); os.IsNotExist(err) {