-
Notifications
You must be signed in to change notification settings - Fork 0
/
sort.go
164 lines (143 loc) · 4.42 KB
/
sort.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
Karl Ramberg
Loupe v0.1.0
sort.go
*/
package main
import (
"bufio"
"errors"
"fmt"
"os"
"path/filepath"
)
func sort(dir string) error {
fmt.Println("Loupe", loupeVersion, "-", "Sort")
// Check that the -a flag was used
if dir == "" {
return errors.New("provide an archive directory using the -a flag")
}
// Check that the given directory exists
stats, err := os.Stat(dir)
if os.IsNotExist(err) || !stats.IsDir() {
return errors.New("directory \"" + dir + "\" not found")
}
// Get a list of image files in the directory and its subdirectories
files, err := getImageFiles(dir)
if err != nil {
return errors.Join(errors.New("trouble getting image files from \""+dir+"\""), err)
}
// Check that the directory actually has image files to sort
if len(files) == 0 {
return errors.New("no image files found in \"" + dir + "\"")
}
// Sort the files into valid and invalid slices. Instantiate a Photograph struct for the valids
var validPhotos []Photograph
var validFiles []string
var invalidFiles []string
for _, file := range files {
var photograph Photograph
err := photograph.init(filepath.Base(file))
if err != nil {
fmt.Printf("Found invalid file: \"%s\", %s", file, err)
invalidFiles = append(invalidFiles, file)
} else {
validPhotos = append(validPhotos, photograph)
validFiles = append(validFiles, file)
}
}
// Ask for a confimation if the folder has less than 2/3rds validly named photos
if float64(len(validPhotos)) < (0.66 * float64(len(files))) {
scanner := bufio.NewScanner(os.Stdin)
okay, err := promptConfimation(scanner,
"Less than 2/3rds of images in this directory are named correctly, do you wish to proceed?")
if err != nil {
return err
}
if !okay {
fmt.Println("Aborting!")
return nil
}
}
var duplicateCount int
// Move valids to their directories, creating them if they don't exist
for index, photo := range validPhotos {
// Check that the new directory exists, creating it if it doesn't
newdir := filepath.Join(dir, photo.directory())
_, err := os.Stat(newdir)
if os.IsNotExist(err) {
err := os.MkdirAll(newdir, 0755)
if err != nil {
return errors.Join(errors.New("trouble while creating directory \""+newdir+"\""), err)
}
fmt.Println("Created folder", newdir)
}
// Move the file with the Rename function
oldpath := validFiles[index]
newpath := filepath.Join(newdir, photo.filename())
_, err = os.Stat(newpath)
if os.IsNotExist(err) && oldpath != newpath {
err = os.Rename(oldpath, newpath)
if err != nil {
return errors.Join(errors.New("trouble while moving \""+oldpath+"\""), err)
} else {
fmt.Println("Moved", filepath.Base(oldpath), "to", filepath.Dir(newpath))
}
} else if oldpath != newpath {
invalidFiles = append(invalidFiles, validFiles[index])
duplicateCount++
fmt.Println("Left", filepath.Base(oldpath), "alone, file already exists at the destination")
}
}
// Move invalids to the base folder
for _, oldpath := range invalidFiles {
newpath := filepath.Join(dir, filepath.Base(oldpath))
if oldpath != newpath {
err = os.Rename(oldpath, newpath)
if err != nil {
return errors.Join(errors.New("trouble while moving \""+oldpath+"\""), err)
} else {
fmt.Println("Moved invalid photo", filepath.Base(oldpath), "to", dir)
}
}
}
// Clean empty directories
_, err = cleanEmptyDirs(dir)
if err != nil {
return err
}
fmt.Println(len(validPhotos)-duplicateCount, "sorted photograph(s)")
fmt.Println(len(invalidFiles), "photograph(s) to be fixed")
return nil
}
// Traverses a directory, recursively removing any empty subdirectories
func cleanEmptyDirs(dir string) (bool, error) {
// Get a list of contents in the directory
entries, err := os.ReadDir(dir)
if err != nil {
return false, errors.Join(errors.New("trouble while reading \""+dir+"\""), err)
}
// Go through the entries, recursing on any other directory
removedEntries := 0
for _, entry := range entries {
if entry.IsDir() {
removed, err := cleanEmptyDirs(filepath.Join(dir, entry.Name()))
if err != nil {
return false, err
}
if removed {
removedEntries++
}
}
}
// If the directory is originally empty or all entries have been deleted
if len(entries)-removedEntries <= 0 {
err := os.Remove(dir)
if err != nil {
return false, errors.Join(errors.New("trouble while deleting \""+dir+"\""), err)
}
fmt.Println("Removed empty directory", dir)
return true, nil
}
return false, nil
}