multistockphoto 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env ruby
2
+ # wxRuby2 Sample Code. Copyright (c) 2004-2008 wxRuby development team
3
+ # Freely reusable code: see SAMPLES-LICENSE.TXT for details
4
+ begin
5
+ require 'rubygems'
6
+ rescue LoadError
7
+ end
8
+ require 'wx'
9
+
10
+ # This sample shows a fairly minimal Wx::App using a Frame, with a
11
+ # MenuBar and StatusBar but no controls. For the absolute minimum app,
12
+ # see nothing.rb
13
+
14
+ # A Wx::Frame is a self-contained, top-level Window that can contain
15
+ # controls, menubars, and statusbars
16
+ class MinimalFrame < Wx::Frame
17
+ Id_send_all = 2001
18
+ Id_list_done = 2002
19
+ Id_purge_done = 2003
20
+ Id_no_tags = 2004
21
+ Id_not_sent = 2005
22
+
23
+ def initialize(title)
24
+ # The main application frame has no parent (nil)
25
+ super(nil, :title => title, :size => [ 400, 300 ])
26
+
27
+ # PNG can be used on all platforms, but icon type must be specified
28
+ # to work on Windows. Note that OS X doesn't have "Frame" icons.
29
+ icon_file = File.join( File.dirname(__FILE__), "mondrian.png")
30
+ self.icon = Wx::Icon.new(icon_file, Wx::BITMAP_TYPE_PNG)
31
+
32
+ menu_bar = Wx::MenuBar.new
33
+ # The "file" menu
34
+ menu_file = Wx::Menu.new
35
+ # Using Wx::ID_EXIT standard id means the menu item will be given
36
+ # the right label for the platform and language, and placed in the
37
+ # correct platform-specific menu - eg on OS X, in the Application's menu
38
+ menu_file.append(Wx::ID_EXIT, "E&xit\tAlt-X", "Quit this program")
39
+ menu_bar.append(menu_file, "&File")
40
+
41
+ #multistockphoto - actions
42
+ menu_actions = Wx::Menu.new
43
+ menu_actions.append(Id_send_all,"Send all photos")
44
+ menu_actions.append(Id_list_done,"List all done photos")
45
+ menu_actions.append(Id_purge_done,"Purge all done photos")
46
+ menu_bar.append(menu_actions, "Actions")
47
+
48
+ #multistockphoto - admin
49
+ menu_admin = Wx::Menu.new
50
+ menu_admin.append(Id_no_tags,"Photos without tags")
51
+ menu_admin.append(Id_not_sent,"Photos not sent")
52
+ menu_bar.append(menu_admin, "Administration")
53
+
54
+ # The "help" menu
55
+ menu_help = Wx::Menu.new
56
+ menu_help.append(Wx::ID_ABOUT, "&About...\tF1", "Show about dialog")
57
+ menu_bar.append(menu_help, "&Help")
58
+
59
+ # Assign the menubar to this frame
60
+ self.menu_bar = menu_bar
61
+
62
+ # Create a status bar at the bottom of the frame
63
+ create_status_bar(2)
64
+ self.status_text = "Welcome to multistockphoto!"
65
+
66
+ # Set it up to handle menu events using the relevant methods.
67
+ evt_menu Wx::ID_EXIT, :on_quit
68
+ evt_menu Wx::ID_ABOUT, :on_about
69
+ evt_menu Id_send_all, :on_send_all
70
+ evt_menu Id_list_done, :on_list_done
71
+ evt_menu Id_no_tags, :on_no_tags
72
+ evt_menu Id_not_sent, :on_not_sent
73
+ end
74
+
75
+ # End the application; it should finish automatically when the last
76
+ # window is closed.
77
+ def on_quit
78
+ close()
79
+ end
80
+
81
+ # show an 'About' dialog - WxRuby's about_box function will show a
82
+ # platform-native 'About' dialog, but you could also use an ordinary
83
+ # Wx::MessageDialog here.
84
+ def on_about
85
+ Wx::about_box(:name => self.title,
86
+ :version => `multistockphoto --version`, # Wx::WXRUBY_VERSION,
87
+ :description => "multistockphoto-gui application",
88
+ :developers => ['Thomas Preymesser (thopre@gmail.com)'] )
89
+ end
90
+
91
+ def on_send_all
92
+ puts 'send-all'
93
+ self.status_text = "uploading all photos"
94
+
95
+ # puts `multistockphoto --send-all --verbose`
96
+ self.status_text = "done uploading all photos"
97
+ end
98
+
99
+ def on_list_done
100
+ self.status_text = "list-done"
101
+ result = `multistockphoto --list-done`
102
+ puts result
103
+ self.status_text = "done list-done"
104
+ end
105
+
106
+ def on_no_tags
107
+ self.status_text = "no-tags"
108
+ result = `multistockphoto --no-tags`
109
+ puts result
110
+ self.status_text = "done no-tags"
111
+ end
112
+
113
+
114
+ def on_not_sent
115
+
116
+ self.status_text = "not-sent"
117
+ #--
118
+ not_sent = {}
119
+ SITES.each {|site|
120
+ not_sent[site] = 0
121
+ }
122
+ Dir.glob(UPLOAD_DIR+'/*').each {|filename|
123
+ next if File.basename(filename)[0,4] == 'rot_'
124
+ #puts "rot_ uebersprungen"
125
+ if filename.upcase =~ PICTURE_FILES
126
+ SITES.each {|site|
127
+ print filename+"\t"+site+"\t" if $verbose
128
+ g = grep(SENDELISTE, /#{site}\t#{filename}/)
129
+ if g.size == 0
130
+ puts "not sent" if $verbose
131
+ not_sent[site] += 1
132
+ else
133
+ puts 'already sent' if $verbose
134
+ end
135
+ }
136
+ end
137
+ }
138
+ p not_sent
139
+ #--
140
+ self.status_text = "done not-sent"
141
+ end
142
+ end
143
+
144
+ # Wx::App is the container class for any wxruby app. To start an
145
+ # application, either define a subclass of Wx::App, create an instance,
146
+ # and call its main_loop method, OR, simply call the Wx::App.run class
147
+ # method, as shown here.
148
+ Wx::App.run do
149
+ self.app_name = 'Minimal'
150
+ frame = MinimalFrame.new("multistockphoto")
151
+ frame.show
152
+ end
data/config.yaml CHANGED
@@ -1,9 +1,12 @@
1
1
  ---
2
+ :active_sites:
3
+ - :fotolia
4
+ - :zoonar
5
+ - :photocase
2
6
  :zoonar:
3
7
  :user: 'hugo'
4
8
  :password: 'lalala'
5
9
  :total_per_day: 10
6
-
7
10
  :fotolia:
8
11
  :user: 'hugo'
9
12
  :password: 'lalala'
@@ -1,17 +1,18 @@
1
1
  class GenericSite
2
2
  attr_reader :name
3
- attr_accessor :user, :password, :max_errors
3
+ attr_accessor :user, :password, :max_errors, :rotate_photos
4
4
 
5
5
  MAX_ERRORS = 3
6
- SENDELISTE = 'sendeliste.dat'
6
+ SENDLIST = 'sendeliste.dat'
7
7
 
8
8
  def initialize(name)
9
9
  @name = name
10
10
  @max_errors = MAX_ERRORS
11
+ @rotate_photos = true
11
12
  end
12
13
 
13
14
  def photos_fuer_heute_uebrig?
14
- puts "noch #{total_per_day - sent_today} zu senden"
15
+ # puts "noch #{total_per_day - sent_today} zu senden"
15
16
  return total_per_day - sent_today > 0
16
17
  end
17
18
 
@@ -19,11 +20,23 @@ class GenericSite
19
20
  sent_today_site(site)
20
21
  end
21
22
 
23
+ def already_sent_site?(photo,site)
24
+ unless photo.class == Photo
25
+ raise 'not a Photo object'
26
+ end
27
+ unless File.exist?(photo.filename)
28
+ raise "file #{photo.filename} does not exist"
29
+ end
30
+ g = grep(SENDLIST, /#{site}\t#{photo.filename}/)
31
+ return g.size > 0
32
+ end
33
+
22
34
  protected
23
35
 
24
- def sent_today_site(site)
36
+ def sent_today_site(p_site)
37
+ p_site = p_site.to_s
25
38
  count = {}
26
- File.open("sendeliste.dat") {|f|
39
+ File.open(SENDLIST) {|f|
27
40
  f.each_line {|line|
28
41
  site, photo_file, time = line.chomp.split("\t")
29
42
  date = Date.parse(time)
@@ -38,7 +51,8 @@ class GenericSite
38
51
  d = DateTime.now
39
52
  today = Date.new(d.year, d.month, d.day)
40
53
  chosen_date = today
41
- key = [site, chosen_date]
54
+ key = [p_site, chosen_date]
55
+ #puts "#{count[key] || 0} photo sent to #{p_site} today"
42
56
  return (count[key] || 0)
43
57
  end
44
58
 
@@ -1,8 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'mini_exiftool'
3
- #require 'RMagick'
4
- #include Magick
5
- #require 'exifr'
3
+ require 'RMagick'
4
+ include Magick
6
5
 
7
6
  class Photo
8
7
  attr_reader :filename
@@ -15,12 +14,29 @@ class Photo
15
14
 
16
15
  # ist Bild im Hochformat
17
16
  # TODO: paßt dieser Test für alle gedrehten Bilder?
18
- def portrait
19
- pic = ImageList.new(@filename)
20
- if pic.orientation == LeftBottomOrientation
21
- return true
22
- else
23
- return false
17
+ def portrait?
18
+ if false
19
+ pic = ImageList.new(@filename)
20
+ if pic.orientation == LeftBottomOrientation
21
+ return true
22
+ else
23
+ return false
24
+ end
25
+ end
26
+ if true
27
+ img = Magick::Image::read(@filename).first
28
+ # p img
29
+ begin
30
+ if img.orientation == LeftBottomOrientation
31
+ return true
32
+ else
33
+ return false
34
+ end
35
+ rescue
36
+ puts "error in picture #{@filename}"
37
+ return false # TODO: etwas gefaehrlich, bei nicht richtiger JPG-Datei
38
+ # wuerde das auch zuenden
39
+ end
24
40
  end
25
41
  end
26
42
 
@@ -49,7 +65,7 @@ class Photo
49
65
  puts "tags file #{fn} found"
50
66
  tags = Photo.to_tags(lines)
51
67
  self.tags = tags
52
- puts "writing tags to file"
68
+ #puts "writing tags to file"
53
69
  write_keywords
54
70
  rescue Errno::ENOENT
55
71
  warn "WARNING: no tags file #{fn}"
@@ -0,0 +1,30 @@
1
+ =begin
2
+ Die Klasse Sender dient als Ausgangspunkt fuer die Applikation. Hier sind
3
+ zentrale Festlegungen gespeichert bzw. werden Methoden zur Verfuegung gestellt,
4
+ die nicht einzelne Sites sondern das Senden als ganzes betreffen.
5
+ =end
6
+
7
+ class Sender
8
+ def initialize(name)
9
+ @name = name
10
+ end
11
+
12
+ # gibt ein Array in Form [:fotolia,:zoonar,:photocase] zurueck
13
+ def active_sites
14
+ if ENV['MSP_CONFIG']
15
+ @config = YAML.load_file(ENV['MSP_CONFIG'])
16
+ else
17
+ @config = YAML.load_file("config.yaml")
18
+ end
19
+ @config[:active_sites]
20
+ end
21
+
22
+ def upload_dir
23
+ 'upload'
24
+ end
25
+
26
+ def done_dir
27
+ 'done'
28
+ end
29
+
30
+ end # Sender
@@ -1,5 +1,6 @@
1
1
  require 'net/ftp'
2
2
  require 'grep'
3
+ #require 'upload_exception'
3
4
  include Grep
4
5
 
5
6
  class Fotolia < GenericSite
@@ -24,8 +25,8 @@ class Fotolia < GenericSite
24
25
  @ftp_password = @config[:fotolia][:ftp_password]
25
26
  @total_per_day = @config[:fotolia][:total_per_day]
26
27
  end
27
- # TODO: Bild gedreht senden, falls Hochformat
28
- def transfer(photo)
28
+
29
+ def transfer(photo, dont_send=nil, dont_log=nil)
29
30
  # falls nicht in config Datei eingetragen dann nicht senden
30
31
  if @user == nil or @password == nil
31
32
  return
@@ -42,34 +43,37 @@ class Fotolia < GenericSite
42
43
  print "fotolia:#{photo.filename} ... "
43
44
  $stdout.flush
44
45
  #g = `grep "fotolia\t#{photo.filename}" sendeliste.dat` #TODO: will not work for windows
45
- g = grep(SENDELISTE, /fotolia\t#{photo.filename}/)
46
+ g = grep(SENDLIST, /fotolia\t#{photo.filename}/)
46
47
  if g.size > 0
47
48
  puts "already sent"
48
49
  return :duplicate
49
50
  end
50
- if photo.portrait
51
- photo.drehen
51
+ if rotate_photos
52
+ if photo.portrait?
53
+ photo.drehen
54
+ end
55
+ end
56
+ if ! dont_send
57
+ begin
58
+ ftp = Net::FTP.new(FTP_HOST)
59
+ ftp.login(@ftp_user,@ftp_password)
60
+ files=ftp.list('*')
61
+ res = ftp.putbinaryfile(photo.filename)
62
+ files =ftp.list('*')
63
+ #p files
64
+ ftp.close
65
+ rescue Errno::EPIPE
66
+ raise UploadException
67
+ end
52
68
  end
53
- ftp = Net::FTP.new(FTP_HOST)
54
- ftp.login(@ftp_user,@ftp_password)
55
- files=ftp.list('*')
56
- res = ftp.putbinaryfile(photo.filename)
57
- files=ftp.list('*')
58
- #p files
59
- ftp.close
60
- #Test auf Fehler?
61
- # if rand(100) == 42
62
- # @@errors += 1
63
- # if @@errors > max_errors
64
- # raise "too many errors"
65
- # end
66
- # end
67
69
  @@errors = 0
68
70
  puts 'OK'
69
71
  # `echo "fotolia\t#{photo.filename}\t#{Time.now}" >>sendeliste.dat` #TODO:
70
- File.open(SENDELISTE,'a') {|f|
71
- f.puts "fotolia\t#{photo.filename}\t#{Time.now}"
72
- }
72
+ if ! dont_log
73
+ File.open(SENDLIST,'a') {|f|
74
+ f.puts "fotolia\t#{photo.filename}\t#{Time.now}"
75
+ }
76
+ end
73
77
  true
74
78
  end
75
79
 
@@ -83,17 +87,14 @@ class Fotolia < GenericSite
83
87
  end
84
88
 
85
89
  def already_sent?(photo)
86
- unless photo.class == Photo
87
- raise 'not a Photo object'
88
- end
89
- unless File.exist?(photo.filename)
90
- raise "file #{photo.filename} does not exist"
91
- end
92
- g = grep(SENDELISTE, /fotolia\t#{photo.filename}/)
93
- if g.size > 0
94
- return true
95
- else
96
- return false
97
- end
90
+ already_sent_site?(photo,'fotolia')
91
+ # unless photo.class == Photo
92
+ # raise 'not a Photo object'
93
+ # end
94
+ # unless File.exist?(photo.filename)
95
+ # raise "file #{photo.filename} does not exist"
96
+ # end
97
+ # g = grep(SENDLIST, /fotolia\t#{photo.filename}/)
98
+ # return g.size > 0
98
99
  end
99
100
  end
@@ -19,7 +19,7 @@ class Photocase < GenericSite
19
19
  @total_per_day = @config[:photocase][:total_per_day]
20
20
  end
21
21
 
22
- def transfer(photo)
22
+ def transfer(photo,dont_send=false,dont_log=false)
23
23
  sav_photo_filename = photo.filename.dup
24
24
  # falls nicht in config Datei eingetragen dann nicht senden
25
25
  if @user == nil or @password == nil
@@ -34,69 +34,77 @@ class Photocase < GenericSite
34
34
  end
35
35
  print "photocase:#{photo.filename} ... "
36
36
  $stdout.flush
37
- g = grep(SENDELISTE, /photocase\t#{photo.filename}/)
37
+ g = grep(SENDLIST, /photocase\t#{photo.filename}/)
38
38
  if g.size > 0
39
39
  puts 'already sent'
40
40
  return :duplicate
41
41
  end
42
- if photo.portrait
43
- photo.drehen
44
- end
45
- agent = WWW::Mechanize.new
46
- agent.user_agent_alias = 'Linux Mozilla'
47
- page = agent.get 'http://www.photocase.de/en/login.asp'
48
- if !page.body.include?('Log in')
49
- raise 'not at the login page'
42
+ if rotate_photos
43
+ if photo.portrait?
44
+ photo.drehen
45
+ end
50
46
  end
51
- form = page.forms.first #TODO: besser nach Name
52
- # form['loginForm[Username]'] = @config[:zoonar][:user]
53
- # form['loginForm[Password]'] = @config[:zoonar][:password]
54
- form['UserName'] = @config[:photocase][:user]
55
- form['UserPassword'] = @config[:photocase][:password]
56
- #UserName
57
- #UserPassword
58
- page = agent.submit form
59
- raise "login error" if ! page.body.include?("Login successful")
60
- page = agent.click page.links.text('Upload')
61
- raise "no Upload a photo" if ! page.body.include?('Upload a photo')
62
- form = page.form('Form')
63
- if photo.portrait
47
+ if ! dont_send
48
+ agent = WWW::Mechanize.new
49
+ agent.user_agent_alias = 'Linux Mozilla'
50
+ page = agent.get 'http://www.photocase.de/en/login.asp'
51
+ if !page.body.include?('Log in')
52
+ raise 'not at the login page'
53
+ end
54
+ form = page.forms.first #TODO: besser nach Name
55
+ # form['loginForm[Username]'] = @config[:zoonar][:user]
56
+ # form['loginForm[Password]'] = @config[:zoonar][:password]
57
+ form['UserName'] = @config[:photocase][:user]
58
+ form['UserPassword'] = @config[:photocase][:password]
59
+ #UserName
60
+ #UserPassword
61
+ page = agent.submit form
62
+ raise "login error" if ! page.body.include?("Login successful")
63
+ page = agent.click page.links.text('Upload')
64
+ raise "no Upload a photo" if ! page.body.include?('Upload a photo')
65
+ form = page.form('Form')
66
+ if photo.portrait?
64
67
 
65
- b = File.basename(photo.filename)
66
- newfilename = photo.filename.sub(b,'')+'rot_'+b
67
- # form.file_uploads.first.file_name = 'r' + photo.filename
68
- form.file_uploads.first.file_name = newfilename
68
+ b = File.basename(photo.filename)
69
+ newfilename = photo.filename.sub(b,'')+'rot_'+b
70
+ # form.file_uploads.first.file_name = 'r' + photo.filename
71
+ form.file_uploads.first.file_name = newfilename
72
+ else
73
+ form.file_uploads.first.file_name = photo.filename
74
+ end
75
+ #TODO:
76
+ # 2 Checkboxen
77
+ #UploadDisclaimerAccepted
78
+ #HasCopyright
79
+ form.checkboxes.name('UploadDisclaimerAccepted').check
80
+ form.checkboxes.name('HasCopyright').check
81
+ page = agent.submit form
82
+ if !page.body.include?('Your photo was uploaded successfully.')
83
+ raise "not successfully uploaded"
84
+ end
85
+ if page.body.include?('Your photo was uploaded successfully.')
86
+ @@errors = 0
87
+ puts "OK"
88
+ else
89
+ #Fehler aufgetreten
90
+ @@errors += 1
91
+ if @@errors > 3
92
+ raise "too many errors"
93
+ end
94
+ end
69
95
  else
70
- form.file_uploads.first.file_name = photo.filename
71
- end
72
- #TODO:
73
- # 2 Checkboxen
74
- #UploadDisclaimerAccepted
75
- #HasCopyright
76
- form.checkboxes.name('UploadDisclaimerAccepted').check
77
- form.checkboxes.name('HasCopyright').check
78
- page = agent.submit form
79
- if !page.body.include?('Your photo was uploaded successfully.')
80
- raise "not successfully uploaded"
81
- end
82
- if page.body.include?('Your photo was uploaded successfully.')
83
- @@errors = 0
84
96
  puts "OK"
85
- else
86
- #Fehler aufgetreten
87
- @@errors += 1
88
- if @@errors > 3
89
- raise "too many errors"
90
- end
91
97
  end
92
98
  #'Your photo was uploaded successfully.'
93
99
  if sav_photo_filename != photo.filename
94
100
  raise "photo.filenames has been changed!"
95
101
  end
96
102
 
97
- File.open(SENDELISTE,'a') {|f|
98
- f.puts "photocase\t#{photo.filename}\t#{Time.now}"
99
- }
103
+ unless dont_log
104
+ File.open(SENDLIST,'a') {|f|
105
+ f.puts "photocase\t#{photo.filename}\t#{Time.now}"
106
+ }
107
+ end
100
108
  true
101
109
  end
102
110
 
@@ -110,17 +118,15 @@ class Photocase < GenericSite
110
118
  end
111
119
 
112
120
  def already_sent?(photo)
113
- unless photo.class == Photo
114
- raise 'not a Photo object'
115
- end
116
- unless File.exist?(photo.filename)
117
- raise "file #{photo.filename} does not exist"
118
- end
119
- g = grep(SENDELISTE, /photocase\t#{photo.filename}/)
120
- if g.size > 0
121
- return true
122
- else
123
- return false
124
- end
121
+ already_sent_site?(photo,'photocase')
122
+ #
123
+ # unless photo.class == Photo
124
+ # raise 'not a Photo object'
125
+ # end
126
+ # unless File.exist?(photo.filename)
127
+ # raise "file #{photo.filename} does not exist"
128
+ # end
129
+ # g = grep(SENDLIST, /photocase\t#{photo.filename}/)
130
+ # return g.size > 0
125
131
  end
126
132
  end