みなさん大掃除は済みましたか?
自分は今パソコンの中を大掃除中です。
今年たくさん写真とったおかげでMACのディスクをかなり圧迫していてちょうどそれの整理をしています。
自分のカメラは1枚の写真に対してORFとJPGファイルを2つ生成するような設定となっています。
ただ、ORFファイルがあればJPGは要らないな〜と思ったので今回まとめて整理出来るスクリプトを書きました。
ディレクトリを引数にとってそのディレクトリ以下を探索して、
JPGとORFファイルを重複して持っているものは削除するというものです。
package main
import (
"fmt"
"os"
"path/filepath"
"regexp"
"flag"
"log"
"os/exec"
)
const (
DEBUG = false
EXTENSION = ".JPG"
WALK_PATH = "/Users/hogehoge/Dropbox/Pictures/写真 Library.photoslibrary/"
TRASH_BOX = "~/.Trash"
)
const raw = `
on run argv
tell application "Finder"
repeat with f in argv
move (f as POSIX file) to trash
end repeat
end tell
end run
`
var trash = filepath.Join(os.Getenv("HOME"), ".Trash")
func go2Trash(f string) error {
bin, err := exec.LookPath("osascript")
if err != nil {
err = fmt.Errorf("not yet supported")
return err
}
if _, err = os.Stat(trash); err != nil {
err = fmt.Errorf("not yet supported")
return err
}
path, err := filepath.Abs(f)
if err != nil {
return err
}
params := []string{"-e", raw, path}
cmd := exec.Command(bin, params...)
if err = cmd.Run(); err != nil {
return err
}
return nil
}
func WalkFunc(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Println(err)
return nil
}
if info.IsDir() {
return nil
}
if ext := filepath.Ext(path); ext == EXTENSION {
pat, err := regexp.Compile(EXTENSION + "$")
if err != nil {
fmt.Println(err)
return nil
}
orfpath := pat.ReplaceAllString(path, ".ORF")
if _, berr := os.Stat(orfpath); berr == nil {
fmt.Println("ORF File Exist: ", path)
if dryrun {
log.Println("next file will be deleted: ", path)
return nil
}
if rename {
derr := go2Trash(path)
if derr != nil {
log.Println(err)
return err
}
} else {
derr := os.Remove(path)
if derr != nil {
log.Println(err)
return err
}
}
}
}
return nil
}
var path string
var rename, dryrun bool
func init() {
flag.StringVar(&path, "path", WALK_PATH, "Pictures filepath.")
flag.BoolVar(&dryrun, "n", false, "dry run flag")
flag.BoolVar(&rename, "trash", true, "go to trashbox")
flag.Parse()
debugp(fmt.Sprintf("dryrun: %s", dryrun))
debugp(fmt.Sprintf("trash: %s", rename))
if path != WALK_PATH {
tmp_p, err := filepath.Abs(path)
if err != nil {
log.Fatalln(err)
}
path = tmp_p
}
debugp(path)
}
func debugp(debugObj interface{}) {
if DEBUG {
fmt.Println(debugObj)
}
}
func main() {
f := WalkFunc
err := filepath.Walk(path, f)
if err != nil {
fmt.Println(err)
}
}
機能は以下のとおり。
あとはこのスクリプトをビルドしてドライランで削除されるファイルを確認。
問題がなければドライランオプションを外して削除という流れです。
$ go build -o walker
$ ./walker -path=~/Dropbox/Pictures/写真\ Library.photoslibrary -n
<中略>
$ ./walker -path=~/Dropbox/Pictures/写真\ Library.photoslibrary
〜〜〜〜〜〜
ORF File Exist: /path/to/2015/09/20/20150920-181504/P9200882.JPG
ORF File Exist: /path/to/2015/09/20/20150920-181504/P9200883.JPG
ORF File Exist: /path/to/2015/09/20/20150920-181504/P9200886.JPG
ORF File Exist: /path/to/2015/09/20/20150920-181504/P9200889.JPG
〜〜〜〜〜〜
こんなスクリプトでもうまく動きましたが実行してみてると1つ課題が見つかりました。
コマンド実行でゴミ箱に送ってる部分が遅いのです。
ファイル1000個ぐらいで15分程度なので耐えられない遅さではないとは思いますが、
go で並列化出来るといいんだろうなと感じました。
余談ですが、ゴミ箱に入れる方法が分からなかったのでその部分は gomi
を参考にさせてもらいました。
(AppleScript使って実現してるんですね。)
Link