This repository has been archived by the owner on Nov 23, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from razenxc/cli-implementation
Cli implementation
- Loading branch information
Showing
10 changed files
with
235 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
.vscode/ | ||
build/ | ||
build/ | ||
old/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Technical Documentation of "Sort Files with EXIF data" cli program | ||
|
||
Problem: Once, I got the corrupted sd card in my camera, I was able to recover all the data, but all the photos were randomly "scattered" in one directory and with random names. | ||
|
||
Solution: I decided to write a program that would sort these photos into directories separated by date. | ||
|
||
Example: | ||
``` | ||
1ABCD.png 23_01_2020 | ||
2BCDE.png -> 02_06_2023 | ||
3CDEF.png 13_08_2024 | ||
``` | ||
|
||
## Program should: | ||
- be cli ✅ | ||
|
||
`sortex -h` | ||
|
||
`sortex --help` | ||
|
||
- sort files in current dir ✅ | ||
|
||
`sortex -c` | ||
|
||
`sortex --current` | ||
|
||
- sort files in determined dir ✅ | ||
|
||
`sortex -d` | ||
|
||
`sortex --determined` | ||
|
||
- sort files from dirs in current dirrectory ❌ | ||
|
||
`sortex -c` | ||
|
||
`sortex --internal-dirs` | ||
- select the path where files will be sorted ✅ | ||
|
||
`sortex -s "/home/sort/here"` | ||
|
||
`sortex --save "/home/sort/here"` | ||
|
||
## Also | ||
- set dir date format ❌ | ||
|
||
`-sdf "mm:dd:yyyy"` | ||
|
||
`--set-dir-format` | ||
|
||
- should files without exif data be transferred? (`true` by default) ✅ | ||
|
||
`-m` | ||
|
||
`--move-no-data false` | ||
|
||
- restore a backup ✅ | ||
|
||
`-b "/fullpath/to/a/backup/file"` | ||
|
||
`--restore-backup "/fullpath/to/a/backup/file"` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package cmd | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
var rootCmd = &cobra.Command{ | ||
Use: "sortex", | ||
Long: "Sort your files with EXIF data by date on directories. *The numbers down below in the description of the arguments, mean that are compatible with each other - ones with ones, twos with twos, nought only with itself.", | ||
Run: sort, | ||
} | ||
|
||
func Execute() { | ||
if err := rootCmd.Execute(); err != nil { | ||
log.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"sortex/sortex" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
var currentDir bool | ||
var determinedPath string | ||
var internalDirs bool | ||
var resultPath string | ||
var moveWithoutEx bool | ||
var restoreBackup string | ||
|
||
func init() { | ||
rootCmd.PersistentFlags().BoolVarP(¤tDir, "current", "c", false, "(1)sort files in current dir") | ||
rootCmd.PersistentFlags().StringVarP(&determinedPath, "determined", "d", "", "(2)sort files in specific dir") | ||
//rootCmd.PersistentFlags().BoolVarP(&internalDirs, "internal-dirs", "i", false, "(1)(2)sort files in all internal dirs") | ||
rootCmd.PersistentFlags().StringVarP(&resultPath, "save", "s", "", "(1)(2)select the path where the files will be sorted") | ||
rootCmd.PersistentFlags().BoolVarP(&moveWithoutEx, "move-no-data", "m", true, "(1)(2)should files without data be transferred? (true by default)") | ||
rootCmd.PersistentFlags().StringVarP(&restoreBackup, "restore-backup", "b", "", "(0)undo changes if something went wrong") | ||
} | ||
|
||
func sort(cmd *cobra.Command, args []string) { | ||
var path string | ||
var fileTypes []string = []string{"all"} | ||
|
||
if currentDir && determinedPath == "" { | ||
fmt.Println("[OK] sortex -c") | ||
p, err := os.Getwd() | ||
if err != nil { | ||
log.Fatal("Error while getting current dirrectory. Use -d") | ||
} | ||
path = p | ||
} else if !currentDir && determinedPath != "" { | ||
fmt.Println("[OK] sortex -d \"" + determinedPath + "\"") | ||
path = determinedPath | ||
} else if currentDir && determinedPath != "" { | ||
fmt.Println("[CANNOT USE] sortex -c -d \"" + determinedPath + "\"") | ||
} else if restoreBackup != "" { | ||
err := sortex.RevertChanges(restoreBackup) | ||
if err != nil { | ||
log.Fatal("[ERROR] -", err) | ||
} | ||
} else { | ||
log.Fatal("[CANNOT USE] sortex -h --help") | ||
} | ||
|
||
dir, err := os.ReadDir(path) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
var backupData []sortex.BackupJSON | ||
var movePath = path | ||
|
||
for _, value := range dir { | ||
fullPath := fmt.Sprintf("%v/%v", path, value.Name()) | ||
fmt.Println("full path", fullPath) | ||
|
||
if sortex.CheckTypes(fullPath, fileTypes) || fileTypes[0] == "all" { | ||
fmt.Println("--------------------------------") | ||
if internalDirs && sortex.IsItDir(fullPath) && fileTypes[0] == "all" { | ||
fmt.Println("path", fullPath, "is skipped because its directory ") | ||
continue | ||
} | ||
|
||
data, err := sortex.GetData(fullPath) | ||
if err != nil { | ||
log.Println(err) | ||
if !moveWithoutEx { | ||
continue | ||
} | ||
} | ||
fmt.Println("exif data:", data) | ||
|
||
if resultPath != "" { | ||
movePath = resultPath | ||
} | ||
newDir, err := sortex.CreateFolder(&data, movePath) | ||
if err != nil { | ||
log.Println(err) | ||
} | ||
fmt.Println("newDir:", newDir) | ||
|
||
err = sortex.MoveToDir(fullPath, newDir+"/"+value.Name()) | ||
if err != nil { | ||
log.Println(err) | ||
} | ||
|
||
backupData = append(backupData, sortex.BackupJSON{ | ||
OldPath: fullPath, | ||
NewPath: newDir + "/" + value.Name(), | ||
}) | ||
} else { | ||
fmt.Println("path", fullPath, "is skipped because its type is not in the list") | ||
} | ||
} | ||
sortex.CreateBackup(movePath, backupData) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,13 @@ | ||
module SortFilesWithEXIFdata | ||
module sortex | ||
|
||
go 1.22.2 | ||
|
||
require github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd | ||
require ( | ||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd | ||
github.com/spf13/cobra v1.8.1 | ||
) | ||
|
||
require ( | ||
github.com/inconshreveable/mousetrap v1.1.0 // indirect | ||
github.com/spf13/pflag v1.0.5 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,12 @@ | ||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= | ||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= | ||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= | ||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= | ||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= | ||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= | ||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= | ||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= | ||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,108 +1,9 @@ | ||
package main | ||
|
||
import ( | ||
"SortFilesWithEXIFdata/sortfiles" | ||
"bufio" | ||
"fmt" | ||
"log" | ||
"os" | ||
"strings" | ||
"sortex/cmd" | ||
) | ||
|
||
func main() { | ||
// Path to dir with files to sort | ||
input, err := readString("Enter full path to dir. with files: ") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
path := input | ||
|
||
dir, err := os.ReadDir(path) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
input, err = readString("Do you want revert changes? [y/n]: ") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
if input == "y" { | ||
err := sortfiles.RevertChanges(path + "/backup.json") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
os.Exit(0) | ||
} | ||
|
||
// File types to sort | ||
input, err = readString("Enter files types to sort separated by spaces \".jpeg .png .jpg\" or \"all\": ") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
fileTypes := strings.Split(input, " ") | ||
|
||
// Ignore directories or not | ||
var ignoreDirs bool | ||
if fileTypes[0] == "all" { | ||
|
||
input, err = readString("Do you want ignore directories? [y/n]: ") | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
switch input { | ||
case "y": | ||
ignoreDirs = true | ||
case "n": | ||
ignoreDirs = false | ||
default: | ||
fmt.Println("Invalid input. 'y' or 'n'.") | ||
} | ||
} | ||
|
||
var backupData []sortfiles.BackupJSON | ||
|
||
for _, value := range dir { | ||
fullPath := fmt.Sprintf("%v/%v", path, value.Name()) | ||
fmt.Println("full path", fullPath) | ||
|
||
if sortfiles.CheckTypes(fullPath, fileTypes) || fileTypes[0] == "all" { | ||
fmt.Println("--------------------------------") | ||
if ignoreDirs && sortfiles.IsItDir(fullPath) && fileTypes[0] == "all" { | ||
fmt.Println("path", fullPath, "is skipped because its directory ") | ||
continue | ||
} | ||
|
||
data, err := sortfiles.GetData(fullPath) | ||
if err != nil { | ||
log.Println(err) | ||
} | ||
fmt.Println("exif data:", data) | ||
|
||
newDir, err := sortfiles.CreateFolder(&data, path) | ||
if err != nil { | ||
log.Println(err) | ||
} | ||
fmt.Println("newDir:", newDir) | ||
|
||
err = sortfiles.MoveToDir(fullPath, newDir+"/"+value.Name()) | ||
if err != nil { | ||
log.Println(err) | ||
} | ||
backupData = append(backupData, sortfiles.BackupJSON{ | ||
OldPath: fullPath, | ||
NewPath: newDir + "/" + value.Name(), | ||
}) | ||
} else { | ||
fmt.Println("path", fullPath, "is skipped because its type is not in the list") | ||
} | ||
} | ||
sortfiles.CreateBackup(path, backupData) | ||
} | ||
|
||
func readString(prompt string) (string, error) { | ||
reader := bufio.NewReader(os.Stdin) | ||
fmt.Print(prompt) | ||
input, err := reader.ReadString('\n') | ||
return strings.TrimSpace(input), err | ||
cmd.Execute() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.