commit 646732fa5fecf3beb777847a781bec71ace6e765 Author: velvettear Date: Fri Aug 11 13:34:54 2023 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9a19b49 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__debug_bin +worklog diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..4fe4729 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "dedupe", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/main.go", + "args": [ + "/tmp/nfs/music/lossless", + "/tmp/nfs/music/mp3", + "-v", + "--delete" + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0b83fca --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "go.delveConfig": { + "debugAdapter": "dlv-dap", + } +} \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..43b85c9 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,20 @@ +# MIT License +**Copyright (c) 2023 Daniel Sommer \** + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.** \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2d8e194 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# dedupe + +simple command line tool to find and move/delete duplicate audio files \ No newline at end of file diff --git a/files/finder.go b/files/finder.go new file mode 100644 index 0000000..52719e6 --- /dev/null +++ b/files/finder.go @@ -0,0 +1,55 @@ +package files + +import ( + "io/fs" + "path/filepath" + "strconv" + "time" + "velvettear/dedupe/log" + "velvettear/dedupe/settings" +) + +var sourceFiles []string +var comparisonFiles []string + +// exported function(s) +func Scan() { + timestamp := time.Now() + log.Info("scanning source directory...", settings.SourceDirectory) + filepath.WalkDir(settings.SourceDirectory, fillSourceFiles) + log.InfoTimed("found "+strconv.Itoa(len(sourceFiles))+" source files", timestamp.UnixMilli()) + + timestamp = time.Now() + log.Info("scanning comparison directory...", settings.SourceDirectory) + filepath.WalkDir(settings.ComparisonDirectory, fillComparisonFiles) + log.InfoTimed("found "+strconv.Itoa(len(comparisonFiles))+" comparison files", timestamp.UnixMilli()) + + for _, sourceFile := range sourceFiles { + log.Debug("checking file", sourceFile) + sourceFileName := filepath.Base(sourceFile) + log.Debug("derp", sourceFileName) + } +} + +// unexported function(s) +func fillSourceFiles(path string, dir fs.DirEntry, err error) error { + if err != nil { + return err + } + if dir.IsDir() { + return nil + } + sourceFiles = append(sourceFiles, path) + return nil +} + +func fillComparisonFiles(path string, dir fs.DirEntry, err error) error { + if err != nil { + return err + } + if dir.IsDir() { + return nil + } + comparisonFiles = append(comparisonFiles, path) + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1564760 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module velvettear/dedupe + +go 1.20 diff --git a/log/log.go b/log/log.go new file mode 100644 index 0000000..e4ff346 --- /dev/null +++ b/log/log.go @@ -0,0 +1,99 @@ +package log + +import ( + "fmt" + "os" + "strconv" + "strings" + "time" +) + +const LEVEL_DEBUG = 0 +const LEVEL_INFO = 1 +const LEVEL_WARNING = 2 +const LEVEL_ERROR = 3 +const LEVEL_FATAL = 4 + +var logLevel = 1 + +// exported functions +func SetLogLevel(level int) { + logLevel = level +} + +func Debug(message string, extras ...string) { + DebugTimed(message, -1, extras...) +} + +func DebugTimed(message string, timestamp int64, extras ...string) { + trace(LEVEL_DEBUG, timestamp, message, extras...) +} + +func Info(message string, extras ...string) { + InfoTimed(message, -1, extras...) +} + +func InfoTimed(message string, timestamp int64, extras ...string) { + trace(LEVEL_INFO, timestamp, message, extras...) +} + +func Warning(message string, extras ...string) { + WarningTimed(message, -1, extras...) +} + +func WarningTimed(message string, timestamp int64, extras ...string) { + trace(LEVEL_WARNING, timestamp, message, extras...) +} + +func Error(message string, extras ...string) { + ErrorTimed(message, -1, extras...) +} + +func ErrorTimed(message string, timestamp int64, extras ...string) { + trace(LEVEL_ERROR, -1, message, extras...) +} + +func Fatal(message string, extras ...string) { + FatalTimed(message, -1, extras...) +} + +func FatalTimed(message string, timestamp int64, extras ...string) { + trace(LEVEL_FATAL, timestamp, message, extras...) + trace(LEVEL_FATAL, -1, "exiting...") + os.Exit(1) +} + +// unexported functions +func trace(level int, timestamp int64, message string, extras ...string) { + if len(message) == 0 || level < logLevel { + return + } + suffix := strings.Join(extras, " | ") + if len(suffix) > 0 { + message += " (" + suffix + ")" + } + if timestamp >= 0 { + + message += " [" + strconv.Itoa(int(time.Now().UnixMilli()-timestamp)) + "ms" + "]" + } + fmt.Println(buildLogMessage(getPrefixForLogLevel(level), message)) +} + +func getPrefixForLogLevel(level int) string { + switch level { + case LEVEL_FATAL: + return "fatal" + case LEVEL_ERROR: + return "error" + case LEVEL_WARNING: + return "warning" + case LEVEL_INFO: + return "info" + default: + return "debug" + } +} + +func buildLogMessage(prefix string, message string) string { + return "[" + prefix + "] > " + message +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..9d753f6 --- /dev/null +++ b/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "velvettear/dedupe/files" + "velvettear/dedupe/settings" +) + +func main() { + settings.Initialize() + files.Scan() +} diff --git a/settings/arguments.go b/settings/arguments.go new file mode 100644 index 0000000..0257e57 --- /dev/null +++ b/settings/arguments.go @@ -0,0 +1,43 @@ +package settings + +import ( + "os" + "strings" + "velvettear/dedupe/log" +) + +// exported function(s) +func Initialize() { + if len(os.Args) < 3 { + log.Fatal("error: missing arguments") + } + for _, arg := range os.Args { + arg = strings.ToLower(arg) + switch arg { + case "-d": + fallthrough + case "--delete": + setDelete(true) + case "-v": + fallthrough + case "--verbose": + setVerbose(true) + } + } + setSourceDirectory(os.Args[1]) + setComparisonDirectory(os.Args[2]) + stats, error := os.Stat(SourceDirectory) + if os.IsNotExist(error) { + log.Fatal("given source directory does not exist", SourceDirectory) + } + if !stats.IsDir() { + log.Fatal("given source directory is not a directory", SourceDirectory) + } + stats, error = os.Stat(ComparisonDirectory) + if os.IsNotExist(error) { + log.Fatal("given comparison directory does not exist", ComparisonDirectory) + } + if !stats.IsDir() { + log.Fatal("given comparison directory is not a directory", ComparisonDirectory) + } +} diff --git a/settings/variables.go b/settings/variables.go new file mode 100644 index 0000000..52f1757 --- /dev/null +++ b/settings/variables.go @@ -0,0 +1,34 @@ +package settings + +import ( + "strconv" + "velvettear/dedupe/log" +) + +// exported variable(s) +var Verbose bool +var Delete bool +var SourceDirectory string +var ComparisonDirectory string + +// unexported function(s) +func setVerbose(verbose bool) { + Verbose = verbose + log.SetLogLevel(0) + log.Debug("set verbose flag", strconv.FormatBool(Verbose)) +} + +func setDelete(delete bool) { + Delete = delete + log.Debug("set delete flag", strconv.FormatBool(Delete)) +} + +func setSourceDirectory(directory string) { + SourceDirectory = directory + log.Debug("set source directory", SourceDirectory) +} + +func setComparisonDirectory(directory string) { + ComparisonDirectory = directory + log.Debug("set source directory", ComparisonDirectory) +}