neves-ruby_picasa 0.2.3

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 ADDED
@@ -0,0 +1,22 @@
1
+ === 0.2.1 / 2009-03-05
2
+
3
+ * Now fully documented.
4
+ * Full spec suite with 100% coverage.
5
+ * Even easier to use the api.
6
+ * Move thumbnail and url to Base so it can be used for Photos and Albums.
7
+ * Enable url to optionally return width and height for image_tag.
8
+ * Use the numeric gphoto:id as id and rename tho standard atom feed id to feed_id
9
+ * Fixed handling of cropped thumbnails and automatically query for valid thumbnail sizes.
10
+ * Stopped using the wrong url to #load albums. Renamed method to #feed.
11
+
12
+ === 0.2.0 / 2009-02-25
13
+
14
+ * First public release.
15
+
16
+ === 0.1.0 / 2009-02-21
17
+
18
+ * First working version.
19
+
20
+ === 0.0.0 / 2009-02-21
21
+
22
+ * Needed to access Picasa.
data/README.txt ADDED
@@ -0,0 +1,79 @@
1
+ = ruby_picasa
2
+
3
+ * http://github.com/pangloss/ruby_picasa
4
+
5
+ == DESCRIPTION:
6
+
7
+ Provides a super easy to use object layer for authenticating and accessing
8
+ Picasa through their API.
9
+
10
+ == FEATURES:
11
+
12
+ * Simplifies the process of obtaining both a temporary and a permanent AuthSub
13
+ token.
14
+ * Very easy to use API.
15
+ * Allows access to both public and private User, Album and Photo data.
16
+ * Uses Objectify::Xml to define the XML object-relational layer with a very
17
+ easy to understand DSL. See www.github.com/pangloss/objectify_xml
18
+
19
+ == PROBLEMS:
20
+
21
+ * None known.
22
+
23
+ == SYNOPSIS:
24
+
25
+ # 1. Authorize application for access (in a rails controller)
26
+ #
27
+ redirect_to RubyPicasa.authorization_url(auth_result_url)
28
+
29
+ # 2. Extract the Picasa token from the request Picasa sends back to your app
30
+ # and create a permanent AuthSub token. Returns an initialized Picasa
31
+ # session. (Called from the Rails action for auth_result_url above)
32
+ picasa = RubyPicasa.authorize_request(self.request)
33
+
34
+ # 3. Access the data you are interested in
35
+ @album = picasa.user.albums.first
36
+ @photo = @album.photos.first
37
+
38
+ # 4. Display your photos
39
+ image_tag @photo.url
40
+ image_tag @photo.url('160c') # Picasa thumbnail names are predefined
41
+
42
+ == PUBLIC ALBUMS:
43
+ # 1. Create an public user by its id:
44
+ #
45
+ user = Picasa.public_user("user_id")
46
+
47
+ == REQUIREMENTS:
48
+
49
+ * objectify_xml
50
+
51
+ == INSTALL:
52
+
53
+ * gem install ruby-picasa
54
+ * gem install pangloss-ruby-picasa --source http://gems.github.com
55
+
56
+ == LICENSE:
57
+
58
+ (The MIT License)
59
+
60
+ Copyright (c) 2009 Darrick Wiebe
61
+
62
+ Permission is hereby granted, free of charge, to any person obtaining
63
+ a copy of this software and associated documentation files (the
64
+ 'Software'), to deal in the Software without restriction, including
65
+ without limitation the rights to use, copy, modify, merge, publish,
66
+ distribute, sublicense, and/or sell copies of the Software, and to
67
+ permit persons to whom the Software is furnished to do so, subject to
68
+ the following conditions:
69
+
70
+ The above copyright notice and this permission notice shall be
71
+ included in all copies or substantial portions of the Software.
72
+
73
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
74
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
75
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
76
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
77
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
78
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
79
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,315 @@
1
+ module RubyPicasa
2
+ # attributes :url, :height, :width
3
+ class PhotoUrl < Objectify::ElementParser
4
+ attributes :url, :height, :width
5
+ end
6
+
7
+
8
+ class ThumbnailUrl < PhotoUrl
9
+
10
+ # The name of the current thumbnail. For possible names, see Photo#url
11
+ def thumb_name
12
+ name = url.scan(%r{/s([^/]+)/[^/]+$}).flatten.compact.first
13
+ if name
14
+ name.sub(/-/, '')
15
+ end
16
+ end
17
+ end
18
+
19
+
20
+ # Note that in all defined classes I'm ignoring values I don't happen to need
21
+ # or know about. Please do add support for the ones I've missed. Be sure to
22
+ # declare which namespaces are supported with the namespaces method. Any
23
+ # elements defined in other namespaces are automatically ignored.
24
+ #
25
+ # Base class for User, Photo and Album types, not used independently.
26
+ #
27
+ # attribute :id, 'gphoto:id'
28
+ # attribute :feed_id, 'id'
29
+ # attributes :updated, :title
30
+ #
31
+ # has_many :links, Objectify::Atom::Link, 'link'
32
+ # has_one :content, PhotoUrl, 'media:content'
33
+ # has_many :thumbnails, ThumbnailUrl, 'media:thumbnail'
34
+ # has_one :author, Objectify::Atom::Author, 'author'
35
+ class Base < Objectify::DocumentParser
36
+ namespaces :openSearch, :gphoto, :media
37
+ flatten 'media:group'
38
+
39
+ attribute :id, 'gphoto:id'
40
+ attribute :feed_id, 'id'
41
+ attributes :updated, :title
42
+
43
+ has_many :links, Objectify::Atom::Link, 'link'
44
+ has_one :content, PhotoUrl, 'media:content'
45
+ has_many :thumbnails, ThumbnailUrl, 'media:thumbnail'
46
+ has_one :author, Objectify::Atom::Author, 'author'
47
+
48
+ # Return the link object with a matching rel attribute value. +rel+ can be
49
+ # either a fully matching string or a regular expression.
50
+ def link(rel)
51
+ links.find { |l| rel === l.rel }
52
+ end
53
+
54
+ def session=(session)
55
+ @session = session
56
+ end
57
+
58
+ # Should return the Picasa instance that retrieved this data.
59
+ def session
60
+ if @session
61
+ @session
62
+ else
63
+ @session = parent.session if parent
64
+ end
65
+ end
66
+
67
+ # Retrieves the data feed at the url of the current record.
68
+ def feed(options = {})
69
+ session.get_url(link('http://schemas.google.com/g/2005#feed').href, options)
70
+ end
71
+
72
+ # If the results are paginated, retrieve the next page.
73
+ def next
74
+ if link = link('next')
75
+ session.get_url(link.href)
76
+ end
77
+ end
78
+
79
+ # If the results are paginated, retrieve the previous page.
80
+ def previous
81
+ if link = link('previous')
82
+ session.get_url(link.href)
83
+ end
84
+ end
85
+
86
+ # Thumbnail names are by image width in pixels. Sizes up to 160 may be
87
+ # either cropped (square) or uncropped:
88
+ #
89
+ # cropped: 32c, 48c, 64c, 72c, 144c, 160c
90
+ # uncropped: 32u, 48u, 64u, 72u, 144u, 160u
91
+ #
92
+ # The rest of the image sizes should be specified by the desired width
93
+ # alone. Widths up to 800px may be embedded on a webpage:
94
+ #
95
+ # embeddable: 200, 288, 320, 400, 512, 576, 640, 720, 800
96
+ # not embeddable: 912, 1024, 1152, 1280, 1440, 1600
97
+ #
98
+ # if a options is set to true or a hash is given, the width and height of
99
+ # the image will be added to the hash and returned. Useful for passing to
100
+ # the rails image_tag helper as follows:
101
+ #
102
+ # image_tag(*image.url('72c', { :class => 'thumb' }))
103
+ #
104
+ # which results in:
105
+ #
106
+ # <img href="..." class="thumb" width="72" height="72">
107
+ #
108
+ def url(thumb_name = nil, options = nil)
109
+ url = nil
110
+ if thumb_name.is_a? Hash
111
+ options = thumb_name
112
+ thumb_name = nil
113
+ end
114
+ options = {} if options and not options.is_a? Hash
115
+ if thumb_name
116
+ if thumb = thumbnail(thumb_name)
117
+ url = thumb.url
118
+ options = { :width => thumb.width, :height => thumb.height }.merge(options) if options
119
+ end
120
+ else
121
+ url = content.url
122
+ options = { :width => content.width, :height => content.height }.merge(options) if options
123
+ end
124
+ if options
125
+ [url, options]
126
+ else
127
+ url
128
+ end
129
+ end
130
+
131
+ # See +url+ for possible image sizes
132
+ def thumbnail(thumb_name)
133
+ raise PicasaError, 'Invalid thumbnail size' unless Photo::VALID.include?(thumb_name.to_s)
134
+ thumb = thumbnails.find { |t| t.thumb_name == thumb_name }
135
+ if thumb
136
+ thumb
137
+ elsif session
138
+ f = feed(:thumbsize => thumb_name)
139
+ if f
140
+ f.thumbnails.first
141
+ end
142
+ end
143
+ end
144
+
145
+ # convert a thumbnail from a size to another, example:
146
+ # tb(160) converts this thumbnail url:
147
+ # http://lh5.ggpht.com/_8t0hxCMjpcM/SZ7OKoCAAsI/AAAAAAAABYA/_lUCR6-iV2g/s144-c/Calibration_Control_Image.jpg
148
+ # into this one with new size:
149
+ # http://lh5.ggpht.com/_8t0hxCMjpcM/SZ7OKoCAAsI/AAAAAAAABYA/_lUCR6-iV2g/s160/Calibration_Control_Image.jpg
150
+ # the thumb does not need to exist on the xml
151
+ def tb(new_size, crop = false)
152
+ crop = crop ? "-c" : ""
153
+ parts = thumbnails.first.url.split "/"
154
+ parts[-2] = "s" + new_size.to_s + crop
155
+ parts.join "/"
156
+ end
157
+ end
158
+
159
+
160
+ # Includes attributes and associations defined on Base, plus:
161
+ #
162
+ # attributes :total_results, # represents total number of albums
163
+ # :start_index,
164
+ # :items_per_page,
165
+ # :thumbnail
166
+ # has_many :entries, :Album, 'entry'
167
+ class User < Base
168
+ attributes :total_results, # represents total number of albums
169
+ :start_index,
170
+ :items_per_page,
171
+ :thumbnail
172
+ has_many :entries, :Album, 'entry'
173
+
174
+ # The current page of albums associated to the user.
175
+ def albums
176
+ entries
177
+ end
178
+ end
179
+
180
+
181
+ # Includes attributes and associations defined on Base and User, plus:
182
+ #
183
+ # has_many :entries, :Photo, 'entry'
184
+ class RecentPhotos < User
185
+ has_many :entries, :Photo, 'entry'
186
+
187
+ # The current page of recently updated photos associated to the user.
188
+ def photos
189
+ entries
190
+ end
191
+
192
+ undef albums
193
+ end
194
+
195
+
196
+ # Includes attributes and associations defined on Base, plus:
197
+ #
198
+ # attributes :published,
199
+ # :summary,
200
+ # :rights,
201
+ # :name,
202
+ # :access,
203
+ # :numphotos, # number of pictures in this album
204
+ # :total_results, # number of pictures matching this 'search'
205
+ # :start_index,
206
+ # :items_per_page,
207
+ # :allow_downloads
208
+ # has_many :entries, :Photo, 'entry'
209
+ class Album < Base
210
+ attributes :published,
211
+ :summary,
212
+ :rights,
213
+ :name,
214
+ :access,
215
+ :numphotos, # number of pictures in this album
216
+ :total_results, # number of pictures matching this 'search'
217
+ :start_index,
218
+ :items_per_page,
219
+ :allow_downloads
220
+ has_many :entries, :Photo, 'entry'
221
+
222
+ # True if this album's rights are set to public
223
+ def public?
224
+ rights == 'public'
225
+ end
226
+
227
+ # True if this album's rights are set to private
228
+ def private?
229
+ rights == 'private'
230
+ end
231
+
232
+ # The current page of photos in the album.
233
+ def photos(options = {})
234
+ if entries.blank? and !@photos_requested
235
+ @photos_requested = true
236
+ if session and data = feed
237
+ self.entries = data.entries
238
+ else
239
+ []
240
+ end
241
+ else
242
+ entries
243
+ end
244
+ end
245
+ end
246
+
247
+
248
+ class Search < Album
249
+ # The current page of photos matching the search.
250
+ def photos(options = {})
251
+ super
252
+ end
253
+ end
254
+
255
+
256
+ # Includes attributes and associations defined on Base, plus:
257
+ #
258
+ # attributes :published,
259
+ # :summary,
260
+ # :version, # can use to determine if need to update...
261
+ # :position,
262
+ # :albumid, # useful from the recently updated feed for instance.
263
+ # :width,
264
+ # :height,
265
+ # :description,
266
+ # :keywords,
267
+ # :credit
268
+ # attribute :unique_id, 'exif:imageUniqueID'
269
+ # attribute :exif_distance, 'exif:distance'
270
+ # attribute :exif_exposure, 'exif:exposure'
271
+ # attribute :exif_flash, 'exif:flash'
272
+ # attribute :exif_focallength, 'exif:focallength'
273
+ # attribute :exif_fstop, 'exif:fstop'
274
+ # attribute :exif_iso, 'exif:iso'
275
+ # attribute :exif_make, 'exif:make'
276
+ # attribute :exif_model, 'exif:model'
277
+ # attribute :exif_time, 'exif:time'
278
+ # has_one :author, Objectify::Atom::Author, 'author'
279
+ class Photo < Base
280
+ CROPPED = %w[ 32c 48c 64c 72c 144c 160c ]
281
+ UNCROPPED = %w[ 32u 48u 64u 72u 144u 160u 32 48 64 72 144 160 ]
282
+ MEDIUM = %w[ 200 288 320 400 512 576 640 720 800 ]
283
+ LARGE = %w[ 912 1024 1152 1280 1440 1600 ]
284
+ VALID = CROPPED + UNCROPPED + MEDIUM + LARGE
285
+
286
+ namespace :exif
287
+
288
+ attributes :published,
289
+ :summary,
290
+ :version, # can use to determine if need to update...
291
+ :position,
292
+ :albumid, # useful from the recently updated feed for instance.
293
+ :width,
294
+ :height,
295
+ :description,
296
+ :keywords,
297
+ :credit
298
+
299
+ flatten 'exif:tags'
300
+ attribute :unique_id, 'exif:imageUniqueID'
301
+ attribute :exif_distance, 'exif:distance'
302
+ attribute :exif_exposure, 'exif:exposure'
303
+ attribute :exif_flash, 'exif:flash'
304
+ attribute :exif_focallength, 'exif:focallength'
305
+ attribute :exif_fstop, 'exif:fstop'
306
+ attribute :exif_iso, 'exif:iso'
307
+ attribute :exif_make, 'exif:make'
308
+ attribute :exif_model, 'exif:model'
309
+ attribute :exif_time, 'exif:time'
310
+
311
+ has_one :author, Objectify::Atom::Author, 'author'
312
+
313
+ end
314
+ end
315
+