initial commit
This commit is contained in:
commit
646732fa5f
11 changed files with 293 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
__debug_bin
|
||||
worklog
|
18
.vscode/launch.json
vendored
Normal file
18
.vscode/launch.json
vendored
Normal file
|
@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"go.delveConfig": {
|
||||
"debugAdapter": "dlv-dap",
|
||||
}
|
||||
}
|
20
LICENSE.md
Normal file
20
LICENSE.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
# MIT License
|
||||
**Copyright (c) 2023 Daniel Sommer \<daniel.sommer@velvettear.de\>**
|
||||
|
||||
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.**
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# dedupe
|
||||
|
||||
simple command line tool to find and move/delete duplicate audio files
|
55
files/finder.go
Normal file
55
files/finder.go
Normal file
|
@ -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
|
||||
}
|
3
go.mod
Normal file
3
go.mod
Normal file
|
@ -0,0 +1,3 @@
|
|||
module velvettear/dedupe
|
||||
|
||||
go 1.20
|
99
log/log.go
Normal file
99
log/log.go
Normal file
|
@ -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
|
||||
}
|
11
main.go
Normal file
11
main.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"velvettear/dedupe/files"
|
||||
"velvettear/dedupe/settings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
settings.Initialize()
|
||||
files.Scan()
|
||||
}
|
43
settings/arguments.go
Normal file
43
settings/arguments.go
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
34
settings/variables.go
Normal file
34
settings/variables.go
Normal file
|
@ -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)
|
||||
}
|
Loading…
Reference in a new issue