multistockphoto 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,10 +1,21 @@
1
- == 0.3.0 2008-05-10
2
- * 5 major enhancements:
1
+ == 0.5.0 2008-05-19???
2
+ * 2 major enhancements:
3
+ * Schalter in Konfigurationsdatei :total_per_day (pro Site)
4
+
5
+ == 0.4.0 2008-05-19
6
+ * 2 major enhancements:
7
+ * Schalter --stats fuer Sendestatistik
8
+ * Bilder automatisch drehen, wenn in Hochformat aufgenommmen
9
+ * Schalter --verbose fuer geschwaetzigen Output
10
+
11
+ == 0.3.0 2008-05-19
12
+ * 6 major enhancements:
3
13
  * Site in Lauf deaktivieren, wenn zu viele Fehler
4
14
  * Schalter '--total-per-site=N'
5
15
  * Schalter '--total-transfers=N' - Nur N Uploads insgsamte pro Session
6
16
  * Schalter '--check-orientation'
7
17
  * Schalter '--rotate'
18
+ * Schalter '--not-sent' Listet auf wieviele Photos je Site noch nicht gesendet wurden
8
19
  * 1 bug fix
9
20
  * kurze Optionsschalter nur noch 1 Zeichen lang und anders benannt
10
21
 
data/bin/multistockphoto CHANGED
@@ -7,6 +7,8 @@ require 'RMagick'
7
7
  include Magick
8
8
  require 'exifr'
9
9
 
10
+ SENDELISTE = 'sendeliste.dat'
11
+
10
12
  def all_sites_done(sites,n)
11
13
  p sites
12
14
  result = true
@@ -19,6 +21,11 @@ def all_sites_done(sites,n)
19
21
  end
20
22
 
21
23
  version = Multistockphoto::VERSION::STRING
24
+ SITES = ['fotolia',
25
+ 'zoonar',
26
+ 'photocase',
27
+ ]
28
+
22
29
  Choice.options do
23
30
  header ''
24
31
  header 'Specific options:'
@@ -41,7 +48,7 @@ Choice.options do
41
48
  exit
42
49
  end
43
50
  end
44
-
51
+
45
52
  option :send_all do
46
53
  short '-a'
47
54
  long '--send-all'
@@ -50,11 +57,29 @@ Choice.options do
50
57
  $send_all=true
51
58
  end
52
59
  end
53
-
60
+
61
+ option :verbose do
62
+ short '-y'
63
+ long '--verbose'
64
+ desc 'Verbose output'
65
+ action do
66
+ $verbose = true
67
+ end
68
+ end
69
+
70
+ option :not_sent do
71
+ short '-n'
72
+ long '--not-sent'
73
+ desc 'Count not sent files per site'
74
+ action do
75
+ $not_sent = true
76
+ end
77
+ end
78
+
54
79
  option :total_transfers do
55
80
  short '-t'
56
81
  long '--total-transfers'
57
- desc 'dont\'t send more than N photos in total'
82
+ desc 'Dont\'t send more than N photos in total'
58
83
  cast Integer
59
84
  default 999
60
85
  action do
@@ -68,7 +93,7 @@ Choice.options do
68
93
  option :total_per_site do
69
94
  short '-s'
70
95
  long '--total-per-site'
71
- desc 'send no more than N photos per site'
96
+ desc 'Send no more than N photos per site'
72
97
  cast Integer
73
98
  default 999
74
99
  action do
@@ -78,11 +103,11 @@ Choice.options do
78
103
  p $total_per_site
79
104
  end
80
105
  end
81
-
106
+
82
107
  option :check_orientation do
83
108
  short '-o'
84
109
  long '--check-orientation'
85
- desc 'displays the orientiation of photo files'
110
+ desc 'Displays the orientiation of photo files'
86
111
  action do
87
112
  $check_orientation_loop = true
88
113
  end
@@ -91,11 +116,39 @@ Choice.options do
91
116
  option :rotate do
92
117
  short '-r'
93
118
  long '--rotate'
94
- desc 'rotate a photo file 90 degrees to the left'
119
+ desc 'Rotate a photo file 90 degrees to the left'
95
120
  action do
96
121
  $rotate_photos = true
97
122
  end
98
123
  end
124
+
125
+ option :stats do
126
+ short '-x'
127
+ long '--stats'
128
+ desc 'Displays statistics'
129
+ action do
130
+ $stats = true
131
+ end
132
+ end
133
+
134
+ option :list_done do
135
+ short '-d'
136
+ long '--list-done'
137
+ desc 'List photos sent to all sites'
138
+ action do
139
+ $list_done = true
140
+ end
141
+ end
142
+
143
+ option :purge_done do
144
+ short '-p'
145
+ long '--purge-done'
146
+ desc 'Purge photos sent to all sites'
147
+ action do
148
+ $purge_done = true
149
+ end
150
+ end
151
+
99
152
  end
100
153
 
101
154
  def send_all
@@ -104,97 +157,67 @@ def send_all
104
157
  errors = {}
105
158
  sites = [:fotolia, :zoonar, :photocase]
106
159
  sites.each {|site|
107
- total[site] = 0
108
- errors[site] = 0
160
+ total[site] = 0
161
+ errors[site] = 0
109
162
  }
110
163
  p total
111
164
  puts 'sending all unsent photos'
112
- Dir.glob('upload/*').each {|filename|
165
+
166
+ done = {:fotolia => false,
167
+ :zoonar => false,
168
+ :photocase => false,
169
+ }
170
+ remaining = {:fotolia => 999_999_999,
171
+ :zoonar => 999_999_999,
172
+ :photocase => 999_999_999,
173
+ }
174
+ sites.each {|site|
175
+ # p "#{site.to_s.capitalize}"+".new(#{site.to_s.capitalize})"
176
+ s = eval("#{site.to_s.capitalize}"+".new(#{site.to_s.capitalize})")
177
+ if s.total_per_day
178
+ remaining[site] = s.total_per_day - s.heute_schon_gesendet(site)
179
+ end
180
+ }
181
+
182
+ Dir.glob('upload/*').each {|filename|
113
183
  next if File.basename(filename)[0,4] == 'rot_'
114
184
  #puts "rot_ uebersprungen"
115
185
  if filename.upcase =~ /.PNG|.JPG|.GIF|.JPEG/
116
- #puts filename
117
186
  total_per_site_flag = $total_per_site
118
- #p total_per_site_flag
119
- # Fotolia
120
- if errors[:fotolia] < 3
121
- if $send_all or (total_per_site_flag and total[:fotolia] < Choice.choices[:total_per_site])
122
- site = Fotolia.new("Fotolia")
123
- photo = Photo.new(filename)
187
+ photo = Photo.new(filename)
188
+ [:fotolia, :zoonar, :photocase].each {|site_name|
189
+ site = eval(site_name.to_s.capitalize+".new(#{site_name.to_s.capitalize})")
190
+ skip if done[:sitename]
191
+ # skip if !site.photos_fuer_heute_uebrig?
192
+ if $send_all or
193
+ # ($send_all and site.total_per_day and site.photos_fuer_heute_uebrig?) or
194
+ (total_per_site_flag and total[site_name] < Choice.choices[:total_per_site])
195
+ #photo = Photo.new(filename)
124
196
  begin
125
- result = site.transfer(photo)
126
- if result != :duplicate
127
- total_transfers += 1
128
- total[:fotolia] += 1
129
- end
130
- if result != :duplicate
131
- errors[:fotolia] = 0
197
+ if !site.already_sent?(photo)
198
+ result = site.transfer(photo)
199
+ if result != :duplicate
200
+ total_transfers += 1
201
+ total[site_name] += 1
202
+ remaining[site_name] -= 1
203
+ done[site_name] = true if remaining[site_name] <= 0
204
+ end
205
+ if result != :duplicate
206
+ errors[site_name] = 0
207
+ end
132
208
  end
133
209
  break if result != :duplicate && total_transfers >= Choice.choices[:total_transfers]
134
210
  break if all_sites_done(total,Choice.choices[:total_per_site])
135
211
  rescue Net::FTPTempError
136
- errors[:fotolia] += 1
137
- if errors[:fotolia] >= 3
138
- puts "too many errors. giving up."
139
- end
140
- puts "FTP-Fehler beim Senden an Fotolia aufgetreten. Ggf. Konfiguration ueberpruefen oder spaeter erneut vesuchen"
141
- end
142
- end
143
- end
144
-
145
- # Zoonar
146
- if errors[:zoonar] < 3
147
- if $send_all or (total_per_site_flag and total[:zoonar] < Choice.choices[:total_per_site])
148
- site = Zoonar.new("Zoonar")
149
- photo = Photo.new(filename)
150
- begin
151
- result = site.transfer(photo)
152
- if result != :duplicate
153
- total_transfers += 1
154
- total[:zoonar] += 1
155
- end
156
- if result != :duplicate
157
- errors[:zoonar] = 0
158
- end
159
- break if result != :duplicate && total_transfers >= Choice.choices[:total_transfers]
160
- break if all_sites_done(total,Choice.choices[:total_per_site])
161
- rescue
162
- errors[:zoonar] += 1
163
- if errors[:zoonar] >= 3
164
- puts "too many errors. giving up."
165
- end
166
- puts "Fehler beim Senden an Zoonar aufgetreten"
167
- end
168
- end
169
- end
170
-
171
- # Photocase
172
- if errors[:photocase] < 3
173
- if $send_all or (total_per_site_flag and total[:photocase] < Choice.choices[:total_per_site])
174
- site = Photocase.new("Photocase")
175
- photo = Photo.new(filename)
176
- begin
177
- result = site.transfer(photo)
178
-
179
- if result != :duplicate
180
- total_transfers += 1
181
- total[:photocase] += 1
182
- end
183
- if result != :duplicate
184
- errors[:photocase] = 0
185
- end
186
-
187
- break if result != :duplicate && total_transfers >= Choice.choices[:total_transfers]
188
- break if all_sites_done(total, Choice.choices[:total_per_site])
189
- rescue
190
- errors[:photocase] += 1
191
- if errors[:photocase] >= 3
212
+ errors[site_name] += 1
213
+ if errors[site_name] >= 3
214
+ done[site_name] = true # nichts mehr uploaden
192
215
  puts "too many errors. giving up."
193
216
  end
194
- puts "Fehler beim Senden an Photocase aufgetreten"
217
+ puts "FTP-Fehler beim Senden an #{site_name} aufgetreten. Ggf. Konfiguration ueberpruefen oder spaeter erneut vesuchen"
195
218
  end
196
219
  end
197
- end
220
+ }
198
221
  end
199
222
  }
200
223
  puts "#{total_transfers} photos sent."
@@ -206,7 +229,7 @@ def check_orientation_loop
206
229
  pic = ImageList.new(fn)
207
230
  puts "#{fn}:\t#{pic.orientation}"
208
231
  end
209
- }
232
+ }
210
233
  end
211
234
 
212
235
  def rotate_photos
@@ -218,7 +241,88 @@ def rotate_photos
218
241
  puts "writing to #{fn}"
219
242
  pic.write(fn)
220
243
  end
221
- }
244
+ }
245
+ end
246
+
247
+ def not_sent
248
+ not_sent = {}
249
+ SITES.each {|site|
250
+ not_sent[site] = 0
251
+ }
252
+ puts "not sent photos:"
253
+ Dir.glob('upload/*').each {|filename|
254
+ next if File.basename(filename)[0,4] == 'rot_'
255
+ #puts "rot_ uebersprungen"
256
+ if filename.upcase =~ /.PNG|.JPG|.GIF|.JPEG/
257
+ SITES.each {|site|
258
+ print filename+"\t"+site+"\t" if $verbose
259
+ g = grep("sendeliste.dat", /#{site}\t#{filename}/)
260
+ if g.size == 0
261
+ puts "not sent" if $verbose
262
+ not_sent[site] += 1
263
+ else
264
+ puts 'already sent' if $verbose
265
+ end
266
+ }
267
+ end
268
+ }
269
+ p not_sent
270
+ end
271
+
272
+ def stats
273
+ count = {}
274
+ File.open("sendeliste.dat") {|f|
275
+ f.each_line {|line|
276
+ site,photo_file,time = line.chomp.split("\t")
277
+ date = Date.parse(time)
278
+ key = [site, date]
279
+ if count[key]==nil
280
+ count[key] = 1
281
+ else
282
+ count[key] = count[key] + 1
283
+ end
284
+ }
285
+ }
286
+ print " "*11+"| "
287
+ SITES.each {|site|
288
+ print "#{site}"
289
+ print " | "
290
+ }
291
+ puts "total"
292
+ d = DateTime.now
293
+ today = Date.new(d.year, d.month, d.day)
294
+ 10.times do |i|
295
+ chosen_date = today - i
296
+ total = 0
297
+ print chosen_date.to_s+" | "
298
+ SITES.each {|site|
299
+ key = [site, chosen_date]
300
+ fmt = "%#{site.length}d | "
301
+ printf(fmt, (count[key] || 0))
302
+ total += (count[key] || 0)
303
+ }
304
+ printf("%5d\n", total)
305
+ end
306
+ puts
307
+ totals = {}
308
+ all = 0
309
+ SITES.each {|site|
310
+ totals[site] = 0
311
+ }
312
+ count.each_pair {|k,v|
313
+ site = k[0]
314
+ #date = k[1]
315
+ totals[site] += v
316
+ all += v
317
+ }
318
+ print "total | "
319
+ SITES.each {|site|
320
+ fmt = "%#{site.length}d | "
321
+ printf(fmt, (totals[site] || 0))
322
+ }
323
+ fmt = "%#{"total".length}d"
324
+ printf(fmt, all)
325
+ puts
222
326
  end
223
327
 
224
328
  if $send_all or $total_per_site
@@ -232,3 +336,79 @@ end
232
336
  if $rotate_photos
233
337
  rotate_photos
234
338
  end
339
+
340
+ if $not_sent
341
+ not_sent
342
+ end
343
+
344
+ if $stats
345
+ puts "Statistics"
346
+ stats
347
+ end
348
+
349
+ if $list_done
350
+ #puts 'list_done'
351
+ #not_sent = {}
352
+ #SITES.each {|site|
353
+ # not_sent[site] = 0
354
+ #}
355
+
356
+ Dir.glob('upload/*').each {|filename|
357
+ photo_sent = {}
358
+ SITES.each {|site|
359
+ photo_sent[site] = false
360
+ }
361
+ next if File.basename(filename)[0,4] == 'rot_'
362
+ #puts "rot_ uebersprungen"
363
+ if filename.upcase =~ /.PNG|.JPG|.GIF|.JPEG/
364
+ SITES.each {|site|
365
+ print filename+"\t"+site+"\t" if $verbose
366
+ g = grep(SENDELISTE, /#{site}\t#{filename}/)
367
+ if g.size == 0
368
+ #puts "not sent" if $verbose
369
+ #not_sent[site] += 1
370
+ else
371
+ #puts 'already sent' if $verbose
372
+ photo_sent[site] = true
373
+ end
374
+ }
375
+ end
376
+ # p photo_sent
377
+ if photo_sent.has_value?(false)
378
+ #puts "#{filename} nicht an alle gesendet"
379
+ else
380
+ puts "#{filename} an alle Sites gesendet"
381
+ end
382
+ }
383
+ # p not_sent
384
+ end
385
+
386
+ if $purge_done
387
+ puts 'purge_done'
388
+ Dir.glob('upload/*').each {|filename|
389
+ photo_sent = {}
390
+ SITES.each {|site|
391
+ photo_sent[site] = false
392
+ }
393
+ next if File.basename(filename)[0,4] == 'rot_'
394
+ if filename.upcase =~ /.PNG|.JPG|.GIF|.JPEG/
395
+ SITES.each {|site|
396
+ print filename+"\t"+site+"\t" if $verbose
397
+ g = grep(SENDELISTE, /#{site}\t#{filename}/)
398
+ if g.size > 0
399
+ photo_sent[site] = true
400
+ end
401
+ }
402
+ end
403
+ if photo_sent.has_value?(false)
404
+ #puts "#{filename} nicht an alle gesendet"
405
+ else
406
+ puts "#{filename} an alle Sites gesendet"
407
+ if !File.exist? 'done'
408
+ FileUtils.mkdir 'done'
409
+ end
410
+ puts "mv #{filename} done/#{File.basename filename}"
411
+ FileUtils.mv filename, "done/"
412
+ end
413
+ }
414
+ end
data/config.yaml CHANGED
@@ -2,11 +2,15 @@
2
2
  :zoonar:
3
3
  :user: 'hugo'
4
4
  :password: 'lalala'
5
+ :total_per_day: 10
6
+
5
7
  :fotolia:
6
8
  :user: 'hugo'
7
9
  :password: 'lalala'
8
10
  :ftp_user: '200507099'
9
11
  :ftp_password: 'hugolalala'
12
+ :total_per_day: 11
10
13
  :photocase:
11
14
  :user: 'hugo'
12
15
  :password: 'lalala'
16
+ :total_per_day: 12
@@ -1,9 +1,45 @@
1
1
  class GenericSite
2
-
3
2
  attr_reader :name
4
- attr_accessor :user, :password
3
+ attr_accessor :user, :password, :max_errors
4
+
5
+ MAX_ERRORS = 3
6
+ SENDELISTE = 'sendeliste.dat'
5
7
 
6
8
  def initialize(name)
7
9
  @name = name
10
+ @max_errors = MAX_ERRORS
11
+ end
12
+
13
+ def photos_fuer_heute_uebrig?
14
+ puts "noch #{total_per_day - sent_today} zu senden"
15
+ return total_per_day - sent_today > 0
8
16
  end
17
+
18
+ def heute_schon_gesendet(site)
19
+ sent_today_site(site)
20
+ end
21
+
22
+ protected
23
+
24
+ def sent_today_site(site)
25
+ count = {}
26
+ File.open("sendeliste.dat") {|f|
27
+ f.each_line {|line|
28
+ site, photo_file, time = line.chomp.split("\t")
29
+ date = Date.parse(time)
30
+ key = [site, date]
31
+ if count[key]==nil
32
+ count[key] = 1
33
+ else
34
+ count[key] = count[key] + 1
35
+ end
36
+ }
37
+ }
38
+ d = DateTime.now
39
+ today = Date.new(d.year, d.month, d.day)
40
+ chosen_date = today
41
+ key = [site, chosen_date]
42
+ return (count[key] || 0)
43
+ end
44
+
9
45
  end
@@ -1,47 +1,27 @@
1
- require 'RMagick'
2
- include Magick
3
- require 'exifr'
1
+ require 'rubygems'
2
+ require 'mini_exiftool'
3
+ #require 'RMagick'
4
+ #include Magick
5
+ #require 'exifr'
4
6
 
5
7
  class Photo
6
8
  attr_reader :filename
9
+ attr_accessor :tags
7
10
 
8
11
  def initialize(filename)
9
12
  @filename = filename
13
+ @tags = nil
10
14
  end
11
15
 
12
16
  # ist Bild im Hochformat
13
- # TODO: ziemlich dummer Test, verbessern!
14
- def hochformat
17
+ # TODO: paßt dieser Test für alle gedrehten Bilder?
18
+ def portrait
15
19
  pic = ImageList.new(@filename)
16
20
  if pic.orientation == LeftBottomOrientation
17
21
  return true
18
22
  else
19
23
  return false
20
24
  end
21
-
22
- if false
23
- require 'rubygems'
24
-
25
- require 'RMagick'
26
- include Magick
27
-
28
- pic = ImageList.new("/home/tp/multistockphoto/upload/IMG_3453.JPG")
29
- pic2 = ImageList.new("/home/tp/multistockphoto/upload/IMG_3464.JPG")
30
- puts pic.orientation
31
- puts pic2.orientation
32
- #pic2 = pic.auto_orient
33
- #pic.display
34
- #pic2.display
35
- if pic.orientation == LeftBottomOrientation
36
- pic.auto_orient!
37
- pic.write("/tmp/rLALA1234.JPG")
38
- end
39
-
40
- end
41
- # width = EXIFR::JPEG.new(@filename).width
42
- # height = EXIFR::JPEG.new(@filename).height
43
- # #return (width < height)
44
- # false
45
25
  end
46
26
 
47
27
  def drehen
@@ -55,6 +35,61 @@ class Photo
55
35
  pic.write(tmpname)
56
36
  end
57
37
  end
38
+ end
39
+
40
+ # setzt IPTC-Keywords, enthalten in Datei <imagefilename>.tags
41
+ def set_keywords
42
+ ext = File.extname(@filename)
43
+ fn = @filename.sub(ext,".tags")
44
+ lines=[]
45
+ begin
46
+ File.open(fn) {|f|
47
+ lines = f.read
48
+ }
49
+ puts "tags file #{fn} found"
50
+ tags = Photo.to_tags(lines)
51
+ self.tags = tags
52
+ puts "writing tags to file"
53
+ write_keywords
54
+ rescue Errno::ENOENT
55
+ warn "WARNING: no tags file #{fn}"
56
+ end
57
+ end
58
+
59
+ # Keywords aus Object-Attributen
60
+ def keywords
61
+ tags
62
+ end
63
+
64
+ # erstellt Key-Array aus String (getrennt durch newline,',' oder ' ')
65
+ def self.to_tags(s)
66
+ keys = []
67
+ s.split(/[, |\t\n]+/).each {|w|
68
+ keys << w
69
+ }
70
+ keys
71
+ end
72
+
73
+ # ermittelt Keywords aus Datei
74
+ def file_keywords
75
+ photo = MiniExiftool.new @filename
76
+ self.tags = photo.tags
77
+ photo.keywords
78
+ end
79
+
80
+ # schreibt Keywords in Datei-Header
81
+ def write_keywords
82
+ photo = MiniExiftool.new @filename
83
+ s = ''
84
+ tags.each {|tag|
85
+ if s == ''
86
+ s = s + tag
87
+ else
88
+ s = s + ' ' + tag
89
+ end
90
+ }
91
+ photo['keywords'] = s
92
+ photo.save
93
+ end
58
94
 
59
- end
60
95
  end