multistockphoto 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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