You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

140 lines
3.4 KiB

package main
import (
"errors"
"flag"
"fmt"
"io"
"log"
"os"
"path"
"time"
"github.com/evanoberholster/imagemeta"
)
const version = "v0.0.3_2024-02-13"
const layout = "2006-01-02T15:04:05.000Z"
func main() {
fmt.Printf("version: %s\n (get latest version at https://github.com/arnaucube/exif-dates/releases )\n\n", version)
var versionFlag bool
var inputDirFlag, outputDirFlag string
flag.BoolVar(&versionFlag, "version", false, "print current version")
flag.BoolVar(&versionFlag, "v", false, "print current version")
flag.StringVar(&inputDirFlag, "input", "./", "input directory")
flag.StringVar(&inputDirFlag, "i", "./", "input directory")
flag.StringVar(&outputDirFlag, "output", "output", "output directory")
flag.StringVar(&outputDirFlag, "o", "output", "output directory")
flag.Parse()
if versionFlag {
os.Exit(0)
}
if err := os.Mkdir(outputDirFlag, os.ModePerm); err != nil {
log.Fatal("output directory already exists")
}
entries, err := os.ReadDir(inputDirFlag)
if err != nil {
log.Fatal(err)
}
nImgsDetected := 0
nImgsConverted := 0
var unconvertedFileNames []string
for _, e := range entries {
// skip subdirectories
if e.IsDir() {
continue
}
nImgsDetected++
fileName := inputDirFlag + "/" + e.Name()
fileExtension := path.Ext(fileName)
// get file
fmt.Printf("--> FileName: %s,", fileName)
f, err := os.Open(fileName)
if err != nil {
fmt.Println("\ne", err)
}
defer f.Close()
// get camera date
date, err := getExifDate(f)
if err != nil {
fmt.Printf(" Error: %s\n\n", err)
unconvertedFileNames = append(unconvertedFileNames, fileName)
continue
}
fmt.Println("\n DATE", date)
dateString := date.String()
if date.IsZero() {
// if date is not set (=0), do not use the zero date as
// name, and reuse the original name of the file
fn := e.Name()
dateString = fn[0 : len(fn)-len(fileExtension)]
}
newFileName := getValidFileName(outputDirFlag+"/"+dateString, fileExtension)
newFileName = newFileName + fileExtension
fmt.Printf(" storing the new img as %s\n\n", newFileName)
// duplicate the original file into newFileName
f, err = os.Open(fileName)
if err != nil {
fmt.Printf("\nerror (os.Open): %s\n\n", err)
}
defer f.Close()
fo, err := os.Create(newFileName)
if err != nil {
panic(err)
}
defer fo.Close()
buf := make([]byte, 1024)
for {
n, err := f.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
if n == 0 {
break
}
if _, err := fo.Write(buf[:n]); err != nil {
panic(err)
}
}
// set the img date into the file date (file's access and modification times)
// Notice that when exif.time=0, this will be the date being
// set here. In a future version might change it to just reuse
// the original file date.
os.Chtimes(newFileName, *date, *date)
nImgsConverted++
}
fmt.Printf("converted %d images out of %d\n", nImgsConverted, nImgsDetected)
fmt.Println("Unconverted images:")
for i := 0; i < len(unconvertedFileNames); i++ {
fmt.Println(" ", unconvertedFileNames[i])
}
}
func getExifDate(f *os.File) (*time.Time, error) {
x, err := imagemeta.Decode(f)
if err != nil {
return nil, err
}
t := x.DateTimeOriginal()
return &t, nil
}
func getValidFileName(fileName, fileExtension string) string {
_, err := os.Open(fileName + fileExtension)
if !errors.Is(err, os.ErrNotExist) {
return getValidFileName(fileName+"_1", fileExtension)
}
return fileName
}