separate import.rb
@@ -0,0 +1,204 @@ | ||
1 | +#!/usr/bin/ruby | |
2 | +# | |
3 | +# RbPhoto library for Importing | |
4 | +# Copyright (C) 2008 Taku YASUI <tach@debian.or.jp> | |
5 | +# | |
6 | +# This program is free software; you can redistribute it and/or modify | |
7 | +# it under the terms of the GNU General Public License as published by | |
8 | +# the Free Software Foundation; either version 2 of the License, or | |
9 | +# (at your option) any later version. | |
10 | +# | |
11 | +# This program is distributed in the hope that it will be useful, | |
12 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | +# GNU General Public License for more details. | |
15 | +# | |
16 | +# You should have received a copy of the GNU General Public License | |
17 | +# along with this program; if not, write to the Free Software | |
18 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | +# | |
20 | +# $Id$ | |
21 | + | |
22 | +require 'getoptlong' | |
23 | +require 'fileutils' | |
24 | +require 'exif' | |
25 | +require 'gettext' | |
26 | +require 'gtk2' | |
27 | +require 'rbphoto' | |
28 | + | |
29 | +class Exif | |
30 | + def datetime | |
31 | + self.each_entry do |name, value| | |
32 | + return value if name.match(/^Date and Time/) | |
33 | + end | |
34 | + end | |
35 | +end | |
36 | + | |
37 | +class RbPhoto | |
38 | + class Args < Hash | |
39 | + def initialize | |
40 | + parser = GetoptLong.new( | |
41 | + ['--datedir', '-D', GetoptLong::NO_ARGUMENT], | |
42 | + ['--force', '-f', GetoptLong::NO_ARGUMENT], | |
43 | + ['--no-gui', '-G', GetoptLong::NO_ARGUMENT], | |
44 | + ['--help', '-h', GetoptLong::NO_ARGUMENT], | |
45 | + ['--with-movie', '-M', GetoptLong::NO_ARGUMENT], | |
46 | + ['--move', '-m', GetoptLong::NO_ARGUMENT], | |
47 | + ['--without-rename', '-N', GetoptLong::NO_ARGUMENT], | |
48 | + ['--no-act', '-n', GetoptLong::NO_ARGUMENT], | |
49 | + ['--photographer', '-p', GetoptLong::REQUIRED_ARGUMENT], | |
50 | + ['--version', '-V', GetoptLong::NO_ARGUMENT], | |
51 | + ['--verbose', '-v', GetoptLong::NO_ARGUMENT]) | |
52 | + begin | |
53 | + parser.each do |name, arg| | |
54 | + arg = true if (arg == "") | |
55 | + self[name.sub(/^--/, '').gsub(/-/, '_').downcase] = arg | |
56 | + end | |
57 | + rescue | |
58 | + self['help'] = true | |
59 | + end | |
60 | + end | |
61 | + end | |
62 | + | |
63 | + class Import | |
64 | + include GetText | |
65 | + bindtextdomain("rbphoto") | |
66 | + | |
67 | + def initialize(args) | |
68 | + @args = args | |
69 | + @fileopts = {:verbose => @args['verbose'], :noop => @args['no_act']} | |
70 | + @postfix = '-' + ENV['USER'] | |
71 | + | |
72 | + if ( @args['version'] ) | |
73 | + print self.version | |
74 | + exit | |
75 | + elsif ( @args['help'] ) | |
76 | + print self.help | |
77 | + exit | |
78 | + end | |
79 | + @dstdir = ARGV.pop | |
80 | + @target = self.prepare_target(ARGV) | |
81 | + @postfix = "-#{@args['photographer']}" if ( @args['photographer'] ) | |
82 | + self.copy | |
83 | + end | |
84 | + | |
85 | + def show_error(str) | |
86 | + STDERR.puts(str) | |
87 | + end | |
88 | + | |
89 | + def show_log(str) | |
90 | + puts(str) | |
91 | + end | |
92 | + | |
93 | + def prepare_target(args = ARGV) | |
94 | + ret = [] | |
95 | + args.each do |arg| | |
96 | + if (File.directory?(arg)) | |
97 | + ret.concat(Dir.glob("#{arg}/*.{jpg,jpeg,JPG,JPEG}")) | |
98 | + ret.concat(Dir.glob("#{arg}/*.{avi,AVI,mpg,MPG}")) if ( @args['with_movie'] ) | |
99 | + else | |
100 | + ret.push(arg) | |
101 | + end | |
102 | + end | |
103 | + return ret | |
104 | + end | |
105 | + | |
106 | + def copy | |
107 | + @target.each do |file| | |
108 | + target_file = @args['without_rename'] ? file : self.rename(file) | |
109 | + target_dir = File.dirname(target_file) | |
110 | + | |
111 | + if ( ! File.directory?(target_dir) ) | |
112 | + begin | |
113 | + FileUtils.makedirs(target_dir, @fileopts) | |
114 | + rescue => e | |
115 | + show_error("ERROR: mkdir failed: #{e.to_s}") | |
116 | + end | |
117 | + end | |
118 | + | |
119 | + if ( @args['move'] ) | |
120 | + begin | |
121 | + FileUtils.mv(file, target_file, @fileopts) | |
122 | + rescue => e | |
123 | + if ( e.is_a?(Errno::EACCES) && @args['force'] && !File.writable?(target_file)) | |
124 | + FileUtils.chmod(0644, target_file, @fileopts) | |
125 | + retry | |
126 | + end | |
127 | + show_error("ERROR: mv failed: #{e.to_s}") | |
128 | + end | |
129 | + else | |
130 | + begin | |
131 | + FileUtils.cp(file, target_file, @fileopts) | |
132 | + rescue => e | |
133 | + show_error("ERROR: cp failed: #{e.to_s}") | |
134 | + end | |
135 | + end | |
136 | + begin | |
137 | + FileUtils.chmod(0444, target_file, @fileopts) | |
138 | + rescue => e | |
139 | + show_error("ERROR: chmod failed: #{e.to_s}") | |
140 | + end | |
141 | + end | |
142 | + end | |
143 | + | |
144 | + def rename(filename) | |
145 | + datedir = '' | |
146 | + suffix = '' | |
147 | + time = Time.at(0) | |
148 | + case File.extname(filename) | |
149 | + when /^\.avi$/i | |
150 | + suffix = 'avi' | |
151 | + time = File.mtime(filename) | |
152 | + when /^\.mpe?g$/i | |
153 | + suffix = 'mpg' | |
154 | + time = File.mtime(filename) | |
155 | + when /^\.jpe?g$/i | |
156 | + suffix = 'jpg' | |
157 | + begin | |
158 | + exif = Exif.new(filename) | |
159 | + time = Time.local(*exif.datetime.split(/[:\s]/)) | |
160 | + rescue | |
161 | + show_error("Cannot read exif data correctly: #{filename}") | |
162 | + return @dstdir + "/#{File.basename(filename, '.*')}#{@postfix}.#{suffix}" | |
163 | + end | |
164 | + else | |
165 | + show_error("Unsupported filetype: #{filename}") | |
166 | + return @dstdir + "/#{filename}" | |
167 | + end | |
168 | + datedir = '/' + time.strftime('%Y-%m-%d') if ( @args['datedir'] ) | |
169 | + return @dstdir + datedir + "/#{time.strftime('%Y%m%d-%H%M%S')}#{@postfix}.#{suffix}" | |
170 | + end | |
171 | + | |
172 | + def help | |
173 | + return <<_EOT | |
174 | +Usage: #{$0} [options] src_(dir|file)[s]... target_dir | |
175 | +Copy photo image from src to target. it renames photo file name | |
176 | +not to duplicate by its exif data. | |
177 | + | |
178 | +Options: | |
179 | + -D, --datedir copy/move photos with datedir | |
180 | + -f, --force force to overwrite when move | |
181 | + -m, --move move photos instead of copy | |
182 | + -M, --with-movie process not only images but also movies | |
183 | + -N, --without-rename do not rename photo files | |
184 | + -p, --photographer=id set photographer id (default: $USER) | |
185 | + -n, --no-act do not copy/move only test | |
186 | + -h, --help show this help | |
187 | + -v, --verbose make verbose output | |
188 | + -V, --version show software version | |
189 | +_EOT | |
190 | + end | |
191 | + | |
192 | + def version | |
193 | + return <<_EOT | |
194 | +Robust Photo management tool (import) #{RbPhoto::VERSION} | |
195 | + | |
196 | +Copyright (C) Taku YASUI <tach@debian.or.jp> | |
197 | +This is free software; see the source for copying conditions. There is NO | |
198 | +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
199 | +_EOT | |
200 | + end | |
201 | + end | |
202 | +end | |
203 | + | |
204 | +# vim: set ts=2 sw=2 expandtab: |