pwup 0.0.1
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/bin/pwupcli +35 -0
- data/lib/picasa.rb +575 -0
- data/lib/picasa_example.rb +88 -0
- data/lib/pwup.rb +68 -0
- metadata +68 -0
data/bin/pwupcli
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
require 'pwup'
|
7
|
+
|
8
|
+
$options = OpenStruct.new
|
9
|
+
$options.files = []
|
10
|
+
$options.album = nil
|
11
|
+
$options.email = nil
|
12
|
+
$options.password = nil
|
13
|
+
|
14
|
+
OptionParser.new do |opts|
|
15
|
+
opts.banner = "Usage: pwup.rb [$options]"
|
16
|
+
|
17
|
+
opts.on("-f", "--file=MANDATORY", "File to process") do |f|
|
18
|
+
$options.files << f
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on("-a", "--album=MANDATORY", "Album name") do |a|
|
22
|
+
$options.album = a
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on("-e", "--email=MANDATORY", "email") do |a|
|
26
|
+
$options.email = a
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on("-p", "--album=MANDATORY", "password") do |a|
|
30
|
+
$options.password = a
|
31
|
+
end
|
32
|
+
end.parse!
|
33
|
+
|
34
|
+
pwup = PwUp::PwUp.new($options.email, $options.password)
|
35
|
+
pwup.process!($options.files, $options.album)
|
data/lib/picasa.rb
ADDED
@@ -0,0 +1,575 @@
|
|
1
|
+
# Copyright (c) 2008 Code71 Bangladesh
|
2
|
+
# www.code71.com
|
3
|
+
# http://code.google.com/p/picasaonrails/
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'cgi'
|
7
|
+
require 'net/https'
|
8
|
+
require 'net/http'
|
9
|
+
require 'xmlsimple'
|
10
|
+
|
11
|
+
module Picasa
|
12
|
+
|
13
|
+
class PicasaSession
|
14
|
+
attr_accessor :auth_key
|
15
|
+
attr_accessor :user_id
|
16
|
+
end
|
17
|
+
|
18
|
+
class Picasa
|
19
|
+
attr_accessor :picasa_session
|
20
|
+
|
21
|
+
def login(email, password)
|
22
|
+
url = "https://www.google.com/accounts/ClientLogin"
|
23
|
+
source = "MyCompany-TestProject-1.0.0" # source will be of CompanyName-ProjectName-ProjectVersion format
|
24
|
+
|
25
|
+
uri = URI.parse(url)
|
26
|
+
|
27
|
+
request = Net::HTTP.new(uri.host, uri.port)
|
28
|
+
request.use_ssl = true
|
29
|
+
request.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
30
|
+
response, data = request.post(uri.path, "accountType=GOOGLE&Email=#{email}&Passwd=#{password}&service=lh2&source=#{source}")
|
31
|
+
data = response.body
|
32
|
+
authMatch = Regexp.compile("(Auth=)([A-Za-z0-9_\-]+)\n").match(data.to_s)
|
33
|
+
if authMatch
|
34
|
+
authorizationKey = authMatch[2].to_s # substring that matched the pattern ([A-Za-z0-9_\-]+)
|
35
|
+
end
|
36
|
+
|
37
|
+
self.picasa_session = PicasaSession.new
|
38
|
+
self.picasa_session.auth_key = authorizationKey
|
39
|
+
self.picasa_session.user_id = email
|
40
|
+
|
41
|
+
return authorizationKey
|
42
|
+
end
|
43
|
+
|
44
|
+
def album(options = {})
|
45
|
+
|
46
|
+
if(options[:name] == nil)
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
|
50
|
+
albums = self.albums(options)
|
51
|
+
for album in albums
|
52
|
+
if(album.name == options[:name])
|
53
|
+
return album
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
return nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def albums(options = {})
|
61
|
+
|
62
|
+
userId = options[:user_id] == nil ? self.picasa_session.user_id : options[:user_id]
|
63
|
+
access = options[:access] == nil ? "public" : options[:access]
|
64
|
+
url = "http://picasaweb.google.com/data/feed/api/user/#{userId}?kind=album&access=#{access}"
|
65
|
+
|
66
|
+
uri = URI.parse(url)
|
67
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
68
|
+
|
69
|
+
headers = {"Authorization" => "GoogleLogin auth=#{self.picasa_session.auth_key}"}
|
70
|
+
|
71
|
+
response, xml_response = http.get(uri.path, headers)
|
72
|
+
|
73
|
+
#xml_response = Net::HTTP.get_response(URI.parse(url)).body.to_s
|
74
|
+
albums = create_albums_from_xml(xml_response)
|
75
|
+
|
76
|
+
return albums
|
77
|
+
end
|
78
|
+
|
79
|
+
def photos(options = {})
|
80
|
+
|
81
|
+
options[:user_id] = options[:user_id].nil? ? self.picasa_session.user_id : options[:user_id]
|
82
|
+
options[:album] = options[:album].nil? ? "" : options[:album]
|
83
|
+
|
84
|
+
album = Album.new
|
85
|
+
album.picasa_session = self.picasa_session
|
86
|
+
photos = album.photos(options)
|
87
|
+
|
88
|
+
return photos
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_album(options = {})
|
92
|
+
|
93
|
+
title = options[:title].nil? ? "" : options[:title]
|
94
|
+
summary = options[:summary].nil? ? "" : options[:summary]
|
95
|
+
location = options[:location].nil? ? "" : options[:location]
|
96
|
+
access = options[:access].nil? ? "public" : options[:access]
|
97
|
+
commentable = options[:commentable].nil? ? "true" : options[:commentable].to_s
|
98
|
+
keywords = options[:keywords].nil? ? "" : options[:keywords]
|
99
|
+
time_i = (Time.now).to_i
|
100
|
+
|
101
|
+
createAlbumRequestXml = "<entry xmlns='http://www.w3.org/2005/Atom'
|
102
|
+
xmlns:media='http://search.yahoo.com/mrss/'
|
103
|
+
xmlns:gphoto='http://schemas.google.com/photos/2007'>
|
104
|
+
<title type='text'>#{title}</title>
|
105
|
+
<summary type='text'>#{summary}</summary>
|
106
|
+
<gphoto:location>#{location}</gphoto:location>
|
107
|
+
<gphoto:access>#{access}</gphoto:access>
|
108
|
+
<gphoto:commentingEnabled>#{commentable}</gphoto:commentingEnabled>
|
109
|
+
<gphoto:timestamp>#{time_i}</gphoto:timestamp>
|
110
|
+
<media:group>
|
111
|
+
<media:keywords>#{keywords}</media:keywords>
|
112
|
+
</media:group>
|
113
|
+
<category scheme='http://schemas.google.com/g/2005#kind'
|
114
|
+
term='http://schemas.google.com/photos/2007#album'></category>
|
115
|
+
</entry>"
|
116
|
+
|
117
|
+
url = "http://picasaweb.google.com/data/feed/api/user/#{self.picasa_session.user_id}"
|
118
|
+
|
119
|
+
uri = URI.parse(url)
|
120
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
121
|
+
|
122
|
+
headers = {"Content-Type" => "application/atom+xml", "Authorization" => "GoogleLogin auth=#{self.picasa_session.auth_key}"}
|
123
|
+
response, data = http.post(uri.path, createAlbumRequestXml, headers)
|
124
|
+
data = response.body
|
125
|
+
album = create_album_from_xml(data)
|
126
|
+
return album
|
127
|
+
end
|
128
|
+
|
129
|
+
def load_album(album_url)
|
130
|
+
uri = URI.parse(album_url)
|
131
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
132
|
+
|
133
|
+
headers = {"Authorization" => "GoogleLogin auth=#{self.picasa_session.auth_key}"}
|
134
|
+
|
135
|
+
response, album_entry_xml_response = http.get(uri.path, headers)
|
136
|
+
|
137
|
+
if(response.code == "200")
|
138
|
+
#parse the entry xml element and get the photo object
|
139
|
+
album = self.create_album_from_xml(album_entry_xml_response)
|
140
|
+
return album
|
141
|
+
else
|
142
|
+
return nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def load_album_with_id(album_id)
|
147
|
+
album_url = "http://picasaweb.google.com/data/entry/api/user/#{self.picasa_session.user_id}/albumid/#{album_id}"
|
148
|
+
|
149
|
+
return load_album(album_url)
|
150
|
+
end
|
151
|
+
|
152
|
+
def load_photo(photo_url)
|
153
|
+
uri = URI.parse(photo_url)
|
154
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
155
|
+
|
156
|
+
headers = {"Authorization" => "GoogleLogin auth=#{self.picasa_session.auth_key}"}
|
157
|
+
|
158
|
+
response, photo_entry_xml_response = http.get(uri.path, headers)
|
159
|
+
|
160
|
+
if(response.code == "200")
|
161
|
+
#parse the entry xml element and get the photo object
|
162
|
+
photo = self.create_photo_from_xml(photo_entry_xml_response)
|
163
|
+
return photo
|
164
|
+
else
|
165
|
+
return nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def load_photo_with_id(photo_id, album_id)
|
170
|
+
photo_url = "http://picasaweb.google.com/data/entry/api/user/#{self.picasa_session.user_id}/albumid/#{album_id}/photoid/#{photo_id}"
|
171
|
+
|
172
|
+
return load_photo(photo_url)
|
173
|
+
end
|
174
|
+
|
175
|
+
def post_photo(image_data = nil, options = {})
|
176
|
+
summary = options[:summary] == nil ? "" : options[:summary]
|
177
|
+
album_name = options[:album] == nil ? "" : options[:album]
|
178
|
+
album_id = options[:album_id] == nil ? "" : options[:album_id]
|
179
|
+
local_file_name = options[:local_file_name] == nil ? "" : options[:local_file_name]
|
180
|
+
title = options[:title] == nil ? local_file_name : options[:title]
|
181
|
+
|
182
|
+
if(image_data == nil)
|
183
|
+
return nil
|
184
|
+
# Or throw an exception in next update
|
185
|
+
end
|
186
|
+
|
187
|
+
if(album_id != "")
|
188
|
+
url = "http://picasaweb.google.com/data/feed/api/user/#{self.picasa_session.user_id}/albumid/#{album_id}"
|
189
|
+
else
|
190
|
+
url = "http://picasaweb.google.com/data/feed/api/user/#{self.picasa_session.user_id}/album/#{album_name}"
|
191
|
+
end
|
192
|
+
|
193
|
+
uri = URI.parse(url)
|
194
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
195
|
+
|
196
|
+
headers = {"Content-Type" => "image/jpeg",
|
197
|
+
"Authorization" => "GoogleLogin auth=#{self.picasa_session.auth_key}",
|
198
|
+
"Slug" => title, "Content-Transfer-Encoding" => "binary"}
|
199
|
+
|
200
|
+
response, data = http.post(uri.path, image_data, headers)
|
201
|
+
data = response.body
|
202
|
+
photo = self.create_photo_from_xml(data)
|
203
|
+
|
204
|
+
return photo
|
205
|
+
end
|
206
|
+
|
207
|
+
def delete_photo(photo)
|
208
|
+
url = photo.edit_url
|
209
|
+
|
210
|
+
uri = URI.parse(url)
|
211
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
212
|
+
|
213
|
+
headers = {"Authorization" => "GoogleLogin auth=#{self.picasa_session.auth_key}"}
|
214
|
+
|
215
|
+
response, data = http.delete(uri.path, headers)
|
216
|
+
data = response.body
|
217
|
+
|
218
|
+
if(response.code == "200")
|
219
|
+
return true
|
220
|
+
else
|
221
|
+
return false
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
def delete_album(album)
|
227
|
+
url = album.edit_url
|
228
|
+
|
229
|
+
uri = URI.parse(url)
|
230
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
231
|
+
|
232
|
+
headers = {"Authorization" => "GoogleLogin auth=#{self.picasa_session.auth_key}"}
|
233
|
+
|
234
|
+
response, data = http.delete(uri.path, headers)
|
235
|
+
data = response.body
|
236
|
+
|
237
|
+
if(response.code == "200")
|
238
|
+
return true
|
239
|
+
else
|
240
|
+
return false
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
|
245
|
+
def create_albums_from_xml(xml_response)
|
246
|
+
albums = []
|
247
|
+
#response_hash = XmlSimple.xml_in(xml_response, { 'ForceArray' => false })
|
248
|
+
#puts response_hash.inspect
|
249
|
+
|
250
|
+
Picasa.entries(xml_response).each do |entry|
|
251
|
+
#parse the entry xml element and get the album object
|
252
|
+
album = Picasa.parse_album_entry(entry)
|
253
|
+
|
254
|
+
#enter session values in album object
|
255
|
+
album.picasa_session = PicasaSession.new
|
256
|
+
album.picasa_session.auth_key = self.picasa_session.auth_key
|
257
|
+
album.picasa_session.user_id = self.picasa_session.user_id
|
258
|
+
|
259
|
+
albums << album
|
260
|
+
end
|
261
|
+
|
262
|
+
return albums
|
263
|
+
end
|
264
|
+
|
265
|
+
def create_album_from_xml(xml_response)
|
266
|
+
album = nil
|
267
|
+
|
268
|
+
#parse the entry xml element and get the album object
|
269
|
+
album = Picasa.parse_album_entry(XmlSimple.xml_in(xml_response, { 'ForceArray' => false }))
|
270
|
+
|
271
|
+
#enter session values in album object
|
272
|
+
album.picasa_session = PicasaSession.new
|
273
|
+
album.picasa_session.auth_key = self.picasa_session.auth_key
|
274
|
+
album.picasa_session.user_id = self.picasa_session.user_id
|
275
|
+
|
276
|
+
return album
|
277
|
+
end
|
278
|
+
|
279
|
+
def create_photo_from_xml(xml_response)
|
280
|
+
photo = nil
|
281
|
+
|
282
|
+
#parse the entry xml element and get the photo object
|
283
|
+
photo = Picasa.parse_photo_entry(XmlSimple.xml_in(xml_response, { 'ForceArray' => false }))
|
284
|
+
|
285
|
+
#enter session values in photo object
|
286
|
+
photo.picasa_session = PicasaSession.new
|
287
|
+
photo.picasa_session.auth_key = self.picasa_session.auth_key
|
288
|
+
photo.picasa_session.user_id = self.picasa_session.user_id
|
289
|
+
|
290
|
+
return photo
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.entries(xml_response)
|
294
|
+
document = XmlSimple.xml_in(xml_response, { 'ForceArray' => false });
|
295
|
+
return [] if (!document['totalResults'].nil? && document['totalResults'].to_i == 0)
|
296
|
+
|
297
|
+
entries = (document['totalResults']).to_i > 1 ? document["entry"] : [document["entry"]]
|
298
|
+
return entries.compact
|
299
|
+
end
|
300
|
+
|
301
|
+
def self.parse_album_entry(album_entry_xml)
|
302
|
+
#album_hash = XmlSimple.xml_in(album_entry_xml.to_s, { 'ForceArray' => false })
|
303
|
+
album_hash = album_entry_xml
|
304
|
+
|
305
|
+
album = Album.new
|
306
|
+
album.xml = album_entry_xml.to_s
|
307
|
+
|
308
|
+
album.id = album_hash["id"][1]
|
309
|
+
album.name = album_hash["name"]
|
310
|
+
album.user = album_hash["user"]
|
311
|
+
album.number_of_photos = album_hash["numphotos"]
|
312
|
+
album.number_of_comments = album_hash["commentCount"]
|
313
|
+
album.is_commentable = album_hash["commentingEnabled"] == true ? true : false
|
314
|
+
album.access = album_hash["access"]
|
315
|
+
|
316
|
+
album.author_name = album_hash["author"]["name"]
|
317
|
+
album.author_uri = album_hash["author"]["uri"]
|
318
|
+
|
319
|
+
album.title = album_hash["group"]["title"]["content"]
|
320
|
+
album.title_type = album_hash["group"]["title"]["type"]
|
321
|
+
album.description = album_hash["group"]["description"]["content"]
|
322
|
+
album.description_type = album_hash["group"]["description"]["type"]
|
323
|
+
album.image_url = album_hash["group"]["content"]["url"]
|
324
|
+
album.image_type = album_hash["group"]["content"]["type"]
|
325
|
+
album.thumbnail = Thumbnail.new()
|
326
|
+
album.thumbnail.url = album_hash["group"]["thumbnail"]["url"]
|
327
|
+
album.thumbnail.width = album_hash["group"]["thumbnail"]["width"]
|
328
|
+
album.thumbnail.height = album_hash["group"]["thumbnail"]["height"]
|
329
|
+
|
330
|
+
# make self xml url
|
331
|
+
links_from_hash = album_hash["link"]
|
332
|
+
if(links_from_hash.respond_to?(:each))
|
333
|
+
links_from_hash.each do |link|
|
334
|
+
if(link["rel"] == "self")
|
335
|
+
album.self_xml_url = link["href"]
|
336
|
+
elsif(link["rel"] == "edit")
|
337
|
+
album.edit_url = link["href"]
|
338
|
+
end
|
339
|
+
end
|
340
|
+
else
|
341
|
+
album.self_xml_url = nil
|
342
|
+
album.edit_url = nil
|
343
|
+
end
|
344
|
+
|
345
|
+
return album
|
346
|
+
end
|
347
|
+
|
348
|
+
def self.parse_photo_entry(photo_entry_xml)
|
349
|
+
#photo_hash = XmlSimple.xml_in(photo_entry_xml.to_s, { 'ForceArray' => false })
|
350
|
+
photo_hash = photo_entry_xml
|
351
|
+
|
352
|
+
photo = Photo.new
|
353
|
+
photo.xml = photo_entry_xml.to_s
|
354
|
+
|
355
|
+
photo.id = photo_hash["id"][1]
|
356
|
+
photo.album_id = photo_hash["albumid"]
|
357
|
+
photo.version_number = photo_hash["version"]
|
358
|
+
photo.is_commentable = photo_hash["commentingEnabled"]
|
359
|
+
photo.size = photo_hash["size"]
|
360
|
+
photo.client = photo_hash["client"]
|
361
|
+
photo.title = photo_hash["group"]["title"]["content"]
|
362
|
+
photo.description = photo_hash["group"]["description"]["content"]
|
363
|
+
photo.url = photo_hash["group"]["content"]["url"]
|
364
|
+
photo.width = photo_hash["group"]["content"]["width"]
|
365
|
+
photo.height = photo_hash["group"]["content"]["height"]
|
366
|
+
photo.type = photo_hash["group"]["content"]["type"]
|
367
|
+
photo.medium = photo_hash["group"]["content"]["medium"]
|
368
|
+
|
369
|
+
# make thumbnails
|
370
|
+
photo.thumbnails = []
|
371
|
+
thumbnails_from_hash = photo_hash["group"]["thumbnail"]
|
372
|
+
if(thumbnails_from_hash.respond_to?(:each))
|
373
|
+
thumbnails_from_hash.each do |thumb|
|
374
|
+
thumbnail = Thumbnail.new
|
375
|
+
thumbnail.url = thumb["url"]
|
376
|
+
thumbnail.width = thumb["width"]
|
377
|
+
thumbnail.height = thumb["height"]
|
378
|
+
|
379
|
+
photo.thumbnails << thumbnail
|
380
|
+
end
|
381
|
+
else
|
382
|
+
|
383
|
+
end
|
384
|
+
|
385
|
+
# make self xml url
|
386
|
+
links_from_hash = photo_hash["link"]
|
387
|
+
if(links_from_hash.respond_to?(:each))
|
388
|
+
links_from_hash.each do |link|
|
389
|
+
if(link["rel"] == "self")
|
390
|
+
photo.self_xml_url = link["href"]
|
391
|
+
elsif(link["rel"] == "edit")
|
392
|
+
photo.edit_url = link["href"]
|
393
|
+
end
|
394
|
+
end
|
395
|
+
else
|
396
|
+
photo.self_xml_url = nil
|
397
|
+
photo.edit_url = nil
|
398
|
+
end
|
399
|
+
|
400
|
+
return photo
|
401
|
+
end
|
402
|
+
|
403
|
+
end
|
404
|
+
|
405
|
+
class Album
|
406
|
+
attr_accessor :picasa_session
|
407
|
+
|
408
|
+
attr_accessor :id, :name
|
409
|
+
attr_accessor :user
|
410
|
+
attr_accessor :title, :title_type
|
411
|
+
attr_accessor :description, :description_type
|
412
|
+
attr_accessor :access
|
413
|
+
attr_accessor :author_name, :author_uri
|
414
|
+
attr_accessor :number_of_photos, :number_of_comments
|
415
|
+
attr_accessor :is_commentable
|
416
|
+
attr_accessor :image_url, :image_type
|
417
|
+
attr_accessor :thumbnail
|
418
|
+
attr_accessor :xml
|
419
|
+
attr_accessor :self_xml_url, :edit_url
|
420
|
+
|
421
|
+
def initialize()
|
422
|
+
thumbnail = Thumbnail.new()
|
423
|
+
end
|
424
|
+
|
425
|
+
def photos(options = {})
|
426
|
+
|
427
|
+
userId = options[:user_id].nil? ? self.user : options[:user_id]
|
428
|
+
albumName = options[:album].nil? ? self.name : options[:album]
|
429
|
+
albumId = options[:album_id].nil? ? self.id : options[:album_id]
|
430
|
+
|
431
|
+
if(albumId != nil && albumId != "")
|
432
|
+
url = "https://picasaweb.google.com/data/feed/api/user/#{userId}/albumid/#{albumId}?kind=photo"
|
433
|
+
else
|
434
|
+
url = "https://picasaweb.google.com/data/feed/api/user/#{userId}/album/#{albumName}?kind=photo"
|
435
|
+
end
|
436
|
+
|
437
|
+
uri = URI.parse(url)
|
438
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
439
|
+
|
440
|
+
headers = {"Authorization" => "GoogleLogin auth=#{self.picasa_session.auth_key}"}
|
441
|
+
|
442
|
+
response, xml_response = http.get(uri.path, headers)
|
443
|
+
photos = self.create_photos_from_xml(xml_response)
|
444
|
+
|
445
|
+
return photos
|
446
|
+
end
|
447
|
+
|
448
|
+
def create_photos_from_xml(xml_response)
|
449
|
+
photos = []
|
450
|
+
#response_hash = XmlSimple.xml_in(xml_response, { 'ForceArray' => false })
|
451
|
+
#puts response_hash.inspect
|
452
|
+
|
453
|
+
Picasa.entries(xml_response).each do |entry|
|
454
|
+
#parse the entry xml element and get the photo object
|
455
|
+
photo = Picasa.parse_photo_entry(entry)
|
456
|
+
|
457
|
+
#enter session values in photo object
|
458
|
+
photo.picasa_session = PicasaSession.new
|
459
|
+
photo.picasa_session.auth_key = self.picasa_session.auth_key
|
460
|
+
photo.picasa_session.user_id = self.picasa_session.user_id
|
461
|
+
|
462
|
+
photos << photo
|
463
|
+
end
|
464
|
+
|
465
|
+
return photos
|
466
|
+
end
|
467
|
+
|
468
|
+
end
|
469
|
+
|
470
|
+
class Photo
|
471
|
+
attr_accessor :picasa_session
|
472
|
+
|
473
|
+
attr_accessor :id
|
474
|
+
attr_accessor :title, :description
|
475
|
+
attr_accessor :album_id
|
476
|
+
attr_accessor :size
|
477
|
+
attr_accessor :client
|
478
|
+
attr_accessor :is_commentable, :number_of_comments
|
479
|
+
attr_accessor :url, :width, :height, :type, :medium
|
480
|
+
attr_accessor :thumbnails
|
481
|
+
attr_accessor :xml
|
482
|
+
attr_accessor :version_number
|
483
|
+
attr_accessor :self_xml_url, :edit_url
|
484
|
+
|
485
|
+
def initialize()
|
486
|
+
thumbnails = []
|
487
|
+
end
|
488
|
+
|
489
|
+
def update()
|
490
|
+
|
491
|
+
updatePhotoXml = "<entry xmlns='http://www.w3.org/2005/Atom'
|
492
|
+
xmlns:media='http://search.yahoo.com/mrss/'
|
493
|
+
xmlns:gphoto='http://schemas.google.com/photos/2007'>
|
494
|
+
<title type='text'>#{self.title}</title>
|
495
|
+
<summary type='text'>#{self.description}</summary>
|
496
|
+
<gphoto:checksum></gphoto:checksum>
|
497
|
+
<gphoto:client></gphoto:client>
|
498
|
+
<gphoto:rotation>#{0}</gphoto:rotation>
|
499
|
+
<gphoto:timestamp>#{Time.new.to_i.to_s}</gphoto:timestamp>
|
500
|
+
<gphoto:commentingEnabled>#{self.is_commentable.to_s}</gphoto:commentingEnabled>
|
501
|
+
<category scheme='http://schemas.google.com/g/2005#kind'
|
502
|
+
term='http://schemas.google.com/photos/2007#photo'></category>
|
503
|
+
</entry>"
|
504
|
+
|
505
|
+
url = "http://picasaweb.google.com/data/entry/api/user/#{self.picasa_session.user_id}/albumid/#{self.album_id}/photoid/#{self.id}/#{self.version_number}"
|
506
|
+
|
507
|
+
uri = URI.parse(url)
|
508
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
509
|
+
|
510
|
+
headers = {"Content-Type" => "application/atom+xml", "Authorization" => "GoogleLogin auth=#{self.picasa_session.auth_key}"}
|
511
|
+
|
512
|
+
response, data = http.put(uri.path, updatePhotoXml, headers)
|
513
|
+
data = response.body
|
514
|
+
|
515
|
+
if(response.code == "200")
|
516
|
+
#parse the entry xml element and get the photo object
|
517
|
+
#new_photo = Picasa.parse_photo_entry(data)
|
518
|
+
new_photo = Picasa.parse_photo_entry(XmlSimple.xml_in(data.to_s, { 'ForceArray' => false }))
|
519
|
+
self.version_number = new_photo.version_number
|
520
|
+
|
521
|
+
return true
|
522
|
+
else
|
523
|
+
return false
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
def move_to_album(picasa_album_id)
|
528
|
+
|
529
|
+
updatePhotoXml = "<entry xmlns='http://www.w3.org/2005/Atom'
|
530
|
+
xmlns:media='http://search.yahoo.com/mrss/'
|
531
|
+
xmlns:gphoto='http://schemas.google.com/photos/2007'>
|
532
|
+
<title type='text'>#{self.title}</title>
|
533
|
+
<summary type='text'>#{self.description}</summary>
|
534
|
+
<gphoto:albumid>#{picasa_album_id}</gphoto:albumid>
|
535
|
+
<gphoto:checksum></gphoto:checksum>
|
536
|
+
<gphoto:client></gphoto:client>
|
537
|
+
<gphoto:rotation>#{0}</gphoto:rotation>
|
538
|
+
<gphoto:timestamp>#{Time.new.to_i.to_s}</gphoto:timestamp>
|
539
|
+
<gphoto:commentingEnabled>#{self.is_commentable.to_s}</gphoto:commentingEnabled>
|
540
|
+
<category scheme='http://schemas.google.com/g/2005#kind'
|
541
|
+
term='http://schemas.google.com/photos/2007#photo'></category>
|
542
|
+
</entry>"
|
543
|
+
|
544
|
+
url = "http://picasaweb.google.com/data/entry/api/user/#{self.picasa_session.user_id}/albumid/#{self.album_id}/photoid/#{self.id}/#{self.version_number}"
|
545
|
+
|
546
|
+
uri = URI.parse(url)
|
547
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
548
|
+
|
549
|
+
headers = {"Content-Type" => "application/atom+xml", "Authorization" => "GoogleLogin auth=#{self.picasa_session.auth_key}"}
|
550
|
+
|
551
|
+
response, data = http.put(uri.path, updatePhotoXml, headers)
|
552
|
+
data = response.body
|
553
|
+
|
554
|
+
if(response.code == "200")
|
555
|
+
#parse the entry xml element and get the photo object
|
556
|
+
new_photo = Picasa.parse_photo_entry(XmlSimple.xml_in(data.to_s, { 'ForceArray' => false }))
|
557
|
+
self.version_number = new_photo.version_number
|
558
|
+
self.album_id = new_photo.album_id
|
559
|
+
|
560
|
+
return true
|
561
|
+
else
|
562
|
+
return false
|
563
|
+
end
|
564
|
+
|
565
|
+
end
|
566
|
+
|
567
|
+
end
|
568
|
+
|
569
|
+
class Thumbnail
|
570
|
+
attr_accessor :url, :width, :height
|
571
|
+
end
|
572
|
+
|
573
|
+
end
|
574
|
+
|
575
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# http://code.google.com/p/picasaonrails/
|
2
|
+
require "picasa"
|
3
|
+
|
4
|
+
picasa = Picasa::Picasa.new
|
5
|
+
puts picasa.login("you@gmail.com", "yourpass")
|
6
|
+
puts picasa.picasa_session.auth_key
|
7
|
+
|
8
|
+
albums = []
|
9
|
+
# get albums of logged in account
|
10
|
+
albums = picasa.albums(:access => "private")
|
11
|
+
albums.each do |album|
|
12
|
+
puts "===== Album ======"
|
13
|
+
puts album.id
|
14
|
+
puts album.name
|
15
|
+
|
16
|
+
puts album.thumbnail.url
|
17
|
+
puts album.thumbnail.width
|
18
|
+
puts album.thumbnail.height
|
19
|
+
|
20
|
+
# get photos of an album
|
21
|
+
photos = album.photos
|
22
|
+
if(photos.size > 0)
|
23
|
+
photos.each do |photo|
|
24
|
+
puts "====== Photo ====="
|
25
|
+
puts photo.id
|
26
|
+
puts photo.title
|
27
|
+
puts photo.url
|
28
|
+
photo.thumbnails.each do |thumbnail|
|
29
|
+
puts thumbnail.url
|
30
|
+
puts thumbnail.width
|
31
|
+
puts thumbnail.height
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
puts "====== No photo for this album ====="
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
# get photos using album name
|
41
|
+
photos = picasa.photos(:album => "AlbumFromRuby")
|
42
|
+
puts "====== Photos of AlbumFromRuby ====="
|
43
|
+
if(photos.size > 0)
|
44
|
+
photos.each do |photo|
|
45
|
+
puts "====== Photos ====="
|
46
|
+
puts photo.id
|
47
|
+
puts photo.title
|
48
|
+
puts photo.url
|
49
|
+
photo.thumbnails.each do |thumbnail|
|
50
|
+
puts thumbnail.url
|
51
|
+
puts thumbnail.width
|
52
|
+
puts thumbnail.height
|
53
|
+
end
|
54
|
+
end
|
55
|
+
else
|
56
|
+
puts "====== No photo for this album ====="
|
57
|
+
end
|
58
|
+
|
59
|
+
# get photos using another user_id and album name
|
60
|
+
photos = []
|
61
|
+
photos = albums[0].photos(:user_id => "me")
|
62
|
+
|
63
|
+
photos.each do |photo|
|
64
|
+
puts photo.id
|
65
|
+
puts photo.title
|
66
|
+
puts photo.description
|
67
|
+
puts photo.url
|
68
|
+
photo.thumbnails.each do |thumbnail|
|
69
|
+
puts thumbnail.url
|
70
|
+
puts thumbnail.width
|
71
|
+
puts thumbnail.height
|
72
|
+
end
|
73
|
+
puts "====== Photo ====="
|
74
|
+
end
|
75
|
+
|
76
|
+
# Create an album
|
77
|
+
album = picasa.create_album(:title => "Album From Ruby",
|
78
|
+
:summary => "This album is created from ruby code",
|
79
|
+
:location => "Bangladesh", :keywords => "keyword1, keyword2")
|
80
|
+
puts album.inspect
|
81
|
+
|
82
|
+
# Post photo to an album
|
83
|
+
fileName = "C:/Documents and Settings/All Users/Documents/My Pictures/Sample Pictures/Blue hills.jpg"
|
84
|
+
image_data = open(fileName, "rb").read
|
85
|
+
photo = picasa.post_photo(image_data, :album => "AlbumFromRuby",
|
86
|
+
:summary => "Upload2 from ruby api", :title => "From Ruby 2",
|
87
|
+
:local_file_name => "Blue hills.jpg")
|
88
|
+
puts photo.inspect
|
data/lib/pwup.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'picasa'
|
4
|
+
|
5
|
+
module PwUp
|
6
|
+
|
7
|
+
class PwUp
|
8
|
+
# FILE_TYPES = %w[.rar .zip]
|
9
|
+
COMMANDS = {
|
10
|
+
".rar" => "unrar x -ep \"%<file>s\" %<target_dir>s",
|
11
|
+
".zip" => "unzip -j \"%<file>s\" -d %<target_dir>s",
|
12
|
+
}
|
13
|
+
IMAGE_TYPES = %w[.jpg .png .gif]
|
14
|
+
|
15
|
+
def initialize(email, password)
|
16
|
+
@email = email
|
17
|
+
@password = password
|
18
|
+
@picasa = Picasa::Picasa.new
|
19
|
+
p @picasa.login(email, password)
|
20
|
+
end
|
21
|
+
|
22
|
+
def process!(files, album_name)
|
23
|
+
# create a tmp folder
|
24
|
+
target_dir = Dir.mktmpdir('pwup', '/tmp')
|
25
|
+
# these are the compressed ones
|
26
|
+
files.each do |file|
|
27
|
+
if not process? file
|
28
|
+
puts "Skipping, can't process file #{file}"
|
29
|
+
next
|
30
|
+
end
|
31
|
+
# unpack file there
|
32
|
+
puts "Unpacking #{file}"
|
33
|
+
unpack file, target_dir
|
34
|
+
end
|
35
|
+
# filter only the images
|
36
|
+
images = Dir.foreach(target_dir).select {|f| IMAGE_TYPES.include? File.extname(f).downcase}
|
37
|
+
puts "Found #{images.length} images"
|
38
|
+
# exit if no images where found
|
39
|
+
return if images.length == 0
|
40
|
+
puts "Uploading to #{album_name}"
|
41
|
+
# create album
|
42
|
+
album = @picasa.create_album(:title => album_name,
|
43
|
+
:summary => album_name,
|
44
|
+
:location => "", :keywords => "", :timestamp => DateTime.now.to_time.to_i)
|
45
|
+
puts "album name = #{album.name}"
|
46
|
+
images.each do |image|
|
47
|
+
file_name = File.join(target_dir, image)
|
48
|
+
puts "Reading #{file_name}"
|
49
|
+
image_data = open(file_name, "rb").read
|
50
|
+
photo = @picasa.post_photo(image_data, :album => album.name,
|
51
|
+
:summary => file_name, :title => file_name)
|
52
|
+
puts "photo #{file_name} uploaded to #{album.name}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def process?(file)
|
58
|
+
ext = File.extname(file)
|
59
|
+
COMMANDS.include? ext.downcase and File.exists? file
|
60
|
+
end
|
61
|
+
|
62
|
+
def unpack(file, target_dir)
|
63
|
+
ext = File.extname(file)
|
64
|
+
command = COMMANDS[ext] % {:file=>file, :target_dir=>target_dir}
|
65
|
+
system(command)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pwup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Esteban Feldman
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: xml-simple
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: A simple picasa web uploador utility class that support compressed archives
|
31
|
+
(.rar, .zip)
|
32
|
+
email: esteban.feldman@gmail.com
|
33
|
+
executables:
|
34
|
+
- pwupcli
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- lib/picasa.rb
|
39
|
+
- lib/picasa_example.rb
|
40
|
+
- lib/pwup.rb
|
41
|
+
- bin/pwupcli
|
42
|
+
homepage: https://github.com/eka/pwup
|
43
|
+
licenses: []
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements:
|
61
|
+
- unrar cli
|
62
|
+
- unzip cli
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 1.8.23
|
65
|
+
signing_key:
|
66
|
+
specification_version: 3
|
67
|
+
summary: Picasa Web Uploader
|
68
|
+
test_files: []
|