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

4 months ago
3 months ago
4 months ago
4 months ago
4 months ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
3 months ago
4 months ago
4 months ago
4 months ago
3 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
  1. package main
  2. import (
  3. "errors"
  4. "flag"
  5. "fmt"
  6. "io"
  7. "log"
  8. "os"
  9. "path"
  10. "time"
  11. "github.com/evanoberholster/imagemeta"
  12. )
  13. const version = "v0.0.3_2024-02-13"
  14. const layout = "2006-01-02T15:04:05.000Z"
  15. func main() {
  16. fmt.Printf("version: %s\n (get latest version at https://github.com/arnaucube/exif-dates/releases )\n\n", version)
  17. var versionFlag bool
  18. var inputDirFlag, outputDirFlag string
  19. flag.BoolVar(&versionFlag, "version", false, "print current version")
  20. flag.BoolVar(&versionFlag, "v", false, "print current version")
  21. flag.StringVar(&inputDirFlag, "input", "./", "input directory")
  22. flag.StringVar(&inputDirFlag, "i", "./", "input directory")
  23. flag.StringVar(&outputDirFlag, "output", "output", "output directory")
  24. flag.StringVar(&outputDirFlag, "o", "output", "output directory")
  25. flag.Parse()
  26. if versionFlag {
  27. os.Exit(0)
  28. }
  29. if err := os.Mkdir(outputDirFlag, os.ModePerm); err != nil {
  30. log.Fatal("output directory already exists")
  31. }
  32. entries, err := os.ReadDir(inputDirFlag)
  33. if err != nil {
  34. log.Fatal(err)
  35. }
  36. nImgsDetected := 0
  37. nImgsConverted := 0
  38. var unconvertedFileNames []string
  39. for _, e := range entries {
  40. // skip subdirectories
  41. if e.IsDir() {
  42. continue
  43. }
  44. nImgsDetected++
  45. fileName := inputDirFlag + "/" + e.Name()
  46. fileExtension := path.Ext(fileName)
  47. // get file
  48. fmt.Printf("--> FileName: %s,", fileName)
  49. f, err := os.Open(fileName)
  50. if err != nil {
  51. fmt.Println("\ne", err)
  52. }
  53. defer f.Close()
  54. // get camera date
  55. date, err := getExifDate(f)
  56. if err != nil {
  57. fmt.Printf(" Error: %s\n\n", err)
  58. unconvertedFileNames = append(unconvertedFileNames, fileName)
  59. continue
  60. }
  61. fmt.Println("\n DATE", date)
  62. dateString := date.String()
  63. if date.IsZero() {
  64. // if date is not set (=0), do not use the zero date as
  65. // name, and reuse the original name of the file
  66. fn := e.Name()
  67. dateString = fn[0 : len(fn)-len(fileExtension)]
  68. }
  69. newFileName := getValidFileName(outputDirFlag+"/"+dateString, fileExtension)
  70. newFileName = newFileName + fileExtension
  71. fmt.Printf(" storing the new img as %s\n\n", newFileName)
  72. // duplicate the original file into newFileName
  73. f, err = os.Open(fileName)
  74. if err != nil {
  75. fmt.Printf("\nerror (os.Open): %s\n\n", err)
  76. }
  77. defer f.Close()
  78. fo, err := os.Create(newFileName)
  79. if err != nil {
  80. panic(err)
  81. }
  82. defer fo.Close()
  83. buf := make([]byte, 1024)
  84. for {
  85. n, err := f.Read(buf)
  86. if err != nil && err != io.EOF {
  87. panic(err)
  88. }
  89. if n == 0 {
  90. break
  91. }
  92. if _, err := fo.Write(buf[:n]); err != nil {
  93. panic(err)
  94. }
  95. }
  96. // set the img date into the file date (file's access and modification times)
  97. // Notice that when exif.time=0, this will be the date being
  98. // set here. In a future version might change it to just reuse
  99. // the original file date.
  100. os.Chtimes(newFileName, *date, *date)
  101. nImgsConverted++
  102. }
  103. fmt.Printf("converted %d images out of %d\n", nImgsConverted, nImgsDetected)
  104. fmt.Println("Unconverted images:")
  105. for i := 0; i < len(unconvertedFileNames); i++ {
  106. fmt.Println(" ", unconvertedFileNames[i])
  107. }
  108. }
  109. func getExifDate(f *os.File) (*time.Time, error) {
  110. x, err := imagemeta.Decode(f)
  111. if err != nil {
  112. return nil, err
  113. }
  114. t := x.DateTimeOriginal()
  115. return &t, nil
  116. }
  117. func getValidFileName(fileName, fileExtension string) string {
  118. _, err := os.Open(fileName + fileExtension)
  119. if !errors.Is(err, os.ErrNotExist) {
  120. return getValidFileName(fileName+"_1", fileExtension)
  121. }
  122. return fileName
  123. }