]>
code.octet-stream.net Git - photosorter/blob - photosorter.go
16 "github.com/fsnotify/fsnotify"
22 func getSeenPath() string {
23 cacheDir
, err
:= os
.UserCacheDir()
25 log
.Fatal(err
, "No cache directory available")
27 return path
.Join(cacheDir
, "photosorter", "seen")
30 func prepareStateDir() {
31 parent
:= path
.Dir(getSeenPath())
32 log
.Println("Storing seen cache in:", parent
)
33 os
.MkdirAll(parent
, 0700)
36 func getSeen() map[string]bool {
37 seenFiles
:= make(map[string]bool)
38 file
, err
:= os
.Open(getSeenPath())
43 scanner
:= bufio
.NewScanner(file
)
45 seenFiles
[scanner
.Text()] = true
50 func setSeen(seenFiles
map[string]bool) {
51 file
, err
:= os
.Create(getSeenPath())
56 w
:= bufio
.NewWriter(file
)
57 for key
:= range seenFiles
{
64 func processFile(name
string, modified time
.Time
) {
65 sourceFile
:= path
.Join(sourcePath
, name
)
66 targetDir
:= path
.Join(targetPath
, strconv
.Itoa(modified
.Year()))
67 targetFile
:= path
.Join(targetDir
, name
)
68 if _
, err
:= os
.Stat(targetFile
); errors
.Is(err
, os
.ErrNotExist
) {
69 log
.Println("Copying src:", sourceFile
, "target:", targetFile
)
70 r
, err
:= os
.Open(sourceFile
)
75 os
.MkdirAll(targetDir
, 0700)
76 w
, err
:= os
.Create(targetFile
)
81 _
, err
= w
.ReadFrom(r
)
83 // Try to clean up for next time
87 log
.Println("Skipping because it exists, src:", sourceFile
, "target:", targetFile
)
92 log
.Println("Starting sort...")
94 seenFiles
:= getSeen()
95 newSeenFiles
:= make(map[string]bool)
96 files
, err
:= os
.ReadDir(sourcePath
)
100 for _
, file
:= range files
{
101 if strings
.HasPrefix(file
.Name(), ".") {
104 if !file
.Type().IsRegular() {
107 info
, err
:= file
.Info()
111 newSeenFiles
[file
.Name()] = true
112 if seenFiles
[file
.Name()] {
115 processFile(file
.Name(), info
.ModTime())
118 setSeen(newSeenFiles
)
120 log
.Println("Sort complete")
122 log
.Println("Sort complete (no changes)")
126 func sortWorker(changeTimes
chan time
.Time
) {
127 // Handle signals cleanly so we avoid stopping mid-execution
128 stopping
:= make(chan os
.Signal
)
129 signal
.Notify(stopping
, syscall
.SIGTERM
, syscall
.SIGHUP
)
131 // Initial sort to catch any changes before startup
132 lastRun
:= time
.Now()
137 log
.Println("Stopping due to signal")
139 case t
:= <-changeTimes
:
140 if t
.After(lastRun
) {
141 log
.Println("Source directory did change")
149 func watcher(changeTimes
chan time
.Time
) {
150 w
, err
:= fsnotify
.NewWatcher()
157 changeTimes
<- time
.Now()
162 const req
= "REQUIRED"
163 flag
.StringVar(&sourcePath
, "s", req
, "source directory where photos are uploaded")
164 flag
.StringVar(&targetPath
, "t", req
, "target directory in which year directories are created")
166 if sourcePath
== req || targetPath
== req
{
167 log
.Println("Source and Target paths must both be provided")
171 changeTimes
:= make(chan time
.Time
, 1024)
172 go sortWorker(changeTimes
)