hitode909の日記

以前はプログラミング日記でしたが、今は子育て日記です

指定したディレクトリのファイルを見ながら仕分けするスクリプト

めんどうな作業があったのでスクリプトで効率化を試みた。

解決したい課題

  • 大量の写真やら動画やら(1000枚くらい)が1つのディレクトリにあって、それを公開用と非公開用に仕分けする
  • マウスを使わず、かつ内容を確認してから仕分けたい
  • Macで作業する
  • iPhotoは重いので使わない

作戦

  1. 仕分けたいファイル一覧と、仕分け先のディレクトリを得る
  2. QuickLookで1枚プレビュー
  3. プレビューしつつキー入力を得て、キーと対応するディレクトリにファイルを移動、プレビューをkillする
  4. 2,3を繰り返し

プレビュー中に「1」を押すとpublic、「2」を押すとprivateにファイルが移動される、みたいな感じ。
エンターキー押すのはめんどうなので、バッファリングをオフにするため、Cursesを使ってみる。

参考

QuickLookで開いて、2秒後にkillするソースがあるので、参考というか勝手に使った。

ソース

#! /usr/bin/ruby -Ku
require "curses"
require "fileutils"

# 特定のディレクトリにあるファイルを複数のディレクトリに分別する

# 画像が置いてあるディレクトリを読んで、ファイル一覧を作る
if ARGV.size == 0
  basedir = Dir.pwd
else
  basedir = ARGV.first
end

files = Dir.entries(basedir).select{ |f| f.include?('.') }.reject{ |f| f[0..0] == '.'}.map{ |f| File.expand_path(f, basedir) }

p files

# ファイルの移動先の候補
dirs = []
puts "ファイルを移動する先の候補をスペース区切りで入力してください"
puts "(空白の場合,public, privateになります)"
print "> "
s = $stdin.gets
dirs = s.chomp.size > 0 ? s.split(' ') : %w{public private}
dirs.map!{ |d| File.expand_path(d, basedir) }
dirs.each do |d|
  if File.directory?(d)
    puts "#{d}は既に存在します"
  else
    puts "#{d}を作りました"
    Dir.mkdir(d)
  end
end

files -= dirs

sleep 1

# ファイルを1ずつつプレビューして移動先を聞いていく

Curses::init_screen

current_num = 0

message_dirs = ""
i = 0
dirs.each { |d| message_dirs << "#{i+=1}:#{File.basename(d)} " }
message_dirs << "other: don't move"

files.each do |file|
  current_num += 1
  Curses::setpos(0, 0)
  Curses::addstr( "#{current_num} / #{files.size} #{File.basename(file)}" )
  Curses::setpos(1, 0)
  Curses::addstr( message_dirs )
  Curses::setpos(2, 0)
  Curses::addstr( "> " )

  # qlmanageで開く
  # http://ujihisa.nowa.jp/entry/0572683d30
  pid = fork {
    STDERR.reopen(File.open('/dev/null', 'w'))
    exec ['qlmanage']*2, '-p', file
  }

  # 1文字入力を得て(条件によって)移動
  str = Curses::getch.chr
  if str.to_i > 0 and str.to_i <= dirs.size
    FileUtils.mv(file, dirs[str.to_i-1])
  end
  
  Process.kill(:TERM, pid)
  Curses::refresh
end

# Cursesおわり
Curses::close_screen

不愉快な点

  • QuickLookが開くのが遅い(0.5秒くらいかかる)
  • Cursesを使ったのでputsではなくaddstrを使わないといけなくて不便

Curses以外のバッファリングなしでキー入力を得る方法があれば、それを使いたい。