mirror of
https://github.com/derfenix/photocatalog.git
synced 2026-03-11 21:35:34 +03:00
Compare commits
4 Commits
bdd3eee69f
...
bcaeba5ea6
| Author | SHA1 | Date | |
|---|---|---|---|
| bcaeba5ea6 | |||
| 9248a9a84d | |||
| f0a8abb380 | |||
| fb1ab2f8b5 |
35
README.md
35
README.md
@@ -6,9 +6,10 @@ A simple tool to organize your photos, videos, or other files by copying or hard
|
|||||||
|
|
||||||
## TL;DR
|
## TL;DR
|
||||||
|
|
||||||
I use a smartphone and Syncthing to automatically sync my photos to my PC. However, if I clean up my phone's memory, the synced photos on my PC are deleted as well. To avoid this, I needed a solution to back up and organize my photos without manual effort.
|
I use a smartphone and Syncthing to automatically sync my photos to my PC. However, if I clean up my phone's memory, the synced photos on my PC are deleted as well.
|
||||||
|
Dumping everything into one folder wasn't an option — finding anything later would be a nightmare.
|
||||||
|
|
||||||
Dumping everything into one folder wasn't an option — finding anything later would be a nightmare. So, I built this tool in one evening to solve the problem. It has worked flawlessly for me and might help you too. If you encounter any issues, feel free to open a ticket — I'll do my best to assist.
|
To avoid this, I needed a solution to back up and organize my photos without manual effort. So, I built this tool in one evening to solve the problem. It has worked flawlessly for me and might help you too. If you encounter any issues, feel free to open a ticket — I'll do my best to assist.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ sudo cp ${GOPATH}/bin/photocatalog /usr/local/bin/photocatalog
|
|||||||
|
|
||||||
The tool supports the following organization modes:
|
The tool supports the following organization modes:
|
||||||
|
|
||||||
- **copy** — Copies files to the target directory. If the filesystem supports it, uses Copy-on-Write (COW) for efficiency.
|
- **copy** — Copies files to the target directory. If the filesystem supports it, uses Copy-on-Write (COW) for efficiency (via FICLONE ioctl call).
|
||||||
- **hardlink** — Creates hardlinks to the source files, saving disk space. Ideal if the source and target are on the same partition, though file permissions remain linked to the original.
|
- **hardlink** — Creates hardlinks to the source files, saving disk space. Ideal if the source and target are on the same partition, though file permissions remain linked to the original.
|
||||||
- **move** — Moves files from the source to the target directory.
|
- **move** — Moves files from the source to the target directory.
|
||||||
- **symlink** — Creates symbolic links at the target pointing to the source files.
|
- **symlink** — Creates symbolic links at the target pointing to the source files.
|
||||||
@@ -44,6 +45,34 @@ Currently, the timestamp format is not customizable. Let me know if support for
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
Arguments
|
||||||
|
```
|
||||||
|
-dir-mode string
|
||||||
|
Mode bits for directories can be created while syncing (default "0777")
|
||||||
|
-file-mode string
|
||||||
|
Mode bits for files created while syncing (not applicable for hardlink mode) (default "0644")
|
||||||
|
-mode string
|
||||||
|
Organazing mode (default "hardlink")
|
||||||
|
-overwrite
|
||||||
|
Overwrite existing files
|
||||||
|
-skip-full-sync
|
||||||
|
Skip full sync at startup
|
||||||
|
-source string
|
||||||
|
Source directory
|
||||||
|
-target string
|
||||||
|
Target directory
|
||||||
|
-watch
|
||||||
|
Watch for changes in the source directory (default true)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
`-skip-full-sync` and `-watch` are not compatible.
|
||||||
|
|
||||||
|
`-source` and `-target` are required.
|
||||||
|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
### One-Time Run
|
### One-Time Run
|
||||||
|
|
||||||
#### Copy Files
|
#### Copy Files
|
||||||
|
|||||||
@@ -180,7 +180,9 @@ func (o *Organizer) FullSync(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := o.processFile(path); err != nil {
|
if err := o.processFile(path); err != nil {
|
||||||
return err
|
log.Printf("Process file `%s` failed: %s", path, err.Error())
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -203,7 +205,7 @@ func (o *Organizer) getMetaForPath(fp string) (metadata.Metadata, error) {
|
|||||||
|
|
||||||
meta, err := o.getMetadata(fp, file)
|
meta, err := o.getMetadata(fp, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return metadata.Metadata{}, fmt.Errorf("get metadata: %w", err)
|
return metadata.Metadata{}, fmt.Errorf("get metadatas: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return meta, nil
|
return meta, nil
|
||||||
|
|||||||
16
main.go
16
main.go
@@ -41,13 +41,15 @@ func loadCfg() application.Config {
|
|||||||
flag.BoolVar(&cfg.Watch, "watch", true, "Watch for changes in the source directory")
|
flag.BoolVar(&cfg.Watch, "watch", true, "Watch for changes in the source directory")
|
||||||
flag.BoolVar(&cfg.SkipFullSync, "skip-full-sync", false, "Skip full sync at startup")
|
flag.BoolVar(&cfg.SkipFullSync, "skip-full-sync", false, "Skip full sync at startup")
|
||||||
|
|
||||||
var dirMode string
|
var (
|
||||||
var fileMode string
|
dirMode string
|
||||||
|
fileMode string
|
||||||
|
mode string
|
||||||
|
)
|
||||||
|
|
||||||
flag.StringVar(&dirMode, "dir-mode", "0777", "Mode bits for directories can be created while syncing")
|
flag.StringVar(&dirMode, "dir-mode", "0777", "Mode bits for directories can be created while syncing")
|
||||||
flag.StringVar(&fileMode, "file-mode", "0644", "Mode bits for files created while syncing (not applicable for hardlink mode)")
|
flag.StringVar(&fileMode, "file-mode", "0644", "Mode bits for files created while syncing (not applicable for hardlink mode)")
|
||||||
|
flag.StringVar(&mode, "mode", "hardlink", "Organizing mode")
|
||||||
var mode string
|
|
||||||
flag.StringVar(&mode, "mode", "hardlink", "Mode")
|
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@@ -57,11 +59,15 @@ func loadCfg() application.Config {
|
|||||||
|
|
||||||
cfg.DirMode, err = strconv.ParseUint(dirMode, 8, 32)
|
cfg.DirMode, err = strconv.ParseUint(dirMode, 8, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Println("Parse -dir-mode failed:", err)
|
||||||
|
|
||||||
cfg.DirMode = 0o777
|
cfg.DirMode = 0o777
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.FileMode, err = strconv.ParseUint(fileMode, 8, 32)
|
cfg.FileMode, err = strconv.ParseUint(fileMode, 8, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Println("Parse -file-mode failed:", err)
|
||||||
|
|
||||||
cfg.DirMode = 0o644
|
cfg.DirMode = 0o644
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user