flickr_fu 0.1.6 → 0.3.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.
Files changed (58) hide show
  1. data/.gitignore +13 -0
  2. data/README +38 -1
  3. data/Rakefile +64 -13
  4. data/VERSION.yml +4 -0
  5. data/flickr_fu.gemspec +114 -32
  6. data/lib/flickr/auth.rb +8 -1
  7. data/lib/flickr/base.rb +75 -26
  8. data/lib/flickr/contact.rb +16 -0
  9. data/lib/flickr/contacts.rb +55 -0
  10. data/lib/flickr/errors.rb +20 -0
  11. data/lib/flickr/geo.rb +42 -0
  12. data/lib/flickr/license.rb +10 -0
  13. data/lib/flickr/location.rb +15 -0
  14. data/lib/flickr/photo.rb +130 -107
  15. data/lib/flickr/photos.rb +29 -11
  16. data/lib/flickr/photoset.rb +37 -0
  17. data/lib/flickr/photosets.rb +39 -0
  18. data/lib/flickr/token.rb +1 -1
  19. data/lib/flickr/urls.rb +44 -0
  20. data/lib/flickr_fu.rb +25 -2
  21. data/spec/fixtures/flickr/contacts/get_list-fail-99.xml +4 -0
  22. data/spec/fixtures/flickr/contacts/get_public_list-0.xml +7 -0
  23. data/spec/fixtures/flickr/photos/geo/get_location-0.xml +11 -0
  24. data/spec/fixtures/flickr/photos/geo/get_location-fail-2.xml +4 -0
  25. data/spec/fixtures/flickr/photos/get_info-0.xml +41 -0
  26. data/spec/fixtures/flickr/photos/get_info-1.xml +19 -0
  27. data/spec/fixtures/flickr/photos/get_sizes-0.xml +10 -0
  28. data/spec/fixtures/flickr/photos/get_sizes-1.xml +8 -0
  29. data/spec/fixtures/flickr/photos/licenses/get_info.xml +12 -0
  30. data/spec/fixtures/flickr/photosets/get_list-0.xml +13 -0
  31. data/spec/fixtures/flickr/photosets/get_photos-0.xml +7 -0
  32. data/spec/fixtures/flickr/test/echo-0.xml +5 -0
  33. data/spec/fixtures/flickr/test/null-fail-99.xml +4 -0
  34. data/spec/fixtures/flickr/urls/get_group-0.xml +4 -0
  35. data/spec/fixtures/flickr/urls/get_group-fail-1.xml +4 -0
  36. data/spec/fixtures/flickr/urls/get_user_photos-0.xml +4 -0
  37. data/spec/fixtures/flickr/urls/get_user_photos-fail-1.xml +4 -0
  38. data/spec/fixtures/flickr/urls/get_user_photos-fail-2.xml +4 -0
  39. data/spec/fixtures/flickr/urls/get_user_profile-0.xml +4 -0
  40. data/spec/fixtures/flickr/urls/get_user_profile-fail-1.xml +4 -0
  41. data/spec/fixtures/flickr/urls/get_user_profile-fail-2.xml +4 -0
  42. data/spec/fixtures/flickr/urls/lookup_group-0.xml +6 -0
  43. data/spec/fixtures/flickr/urls/lookup_group-fail-1.xml +4 -0
  44. data/spec/fixtures/flickr/urls/lookup_user-0.xml +6 -0
  45. data/spec/fixtures/flickr/videos/get_info-0.xml +31 -0
  46. data/spec/fixtures/flickr/videos/get_sizes-0.xml +13 -0
  47. data/spec/flickr/base_spec.rb +97 -0
  48. data/spec/flickr/contacts_spec.rb +47 -0
  49. data/spec/flickr/errors_spec.rb +21 -0
  50. data/spec/flickr/geo_spec.rb +20 -0
  51. data/spec/flickr/photo_spec.rb +140 -0
  52. data/spec/flickr/photos_spec.rb +50 -0
  53. data/spec/flickr/photosets_spec.rb +49 -0
  54. data/spec/flickr/test_spec.rb +34 -0
  55. data/spec/flickr/urls_spec.rb +99 -0
  56. data/spec/spec.opts +4 -0
  57. data/spec/spec_helper.rb +20 -0
  58. metadata +66 -7
@@ -0,0 +1,16 @@
1
+ # wrapping class to hold a flickr contact
2
+ #
3
+ class Flickr::Contacts::Contact
4
+ attr_accessor :nsid, :friend, :family, :iconfarm, :iconserver, :location, :username, :ignored, :realname, :path_alias
5
+
6
+ # create a new instance of a flickr note.
7
+ #
8
+ # Params
9
+ # * attributes (Required)
10
+ # a hash of attributes used to set the initial values of the contact object
11
+ def initialize(attributes)
12
+ attributes.each do |k,v|
13
+ send("#{k}=", v)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,55 @@
1
+ class Flickr::Contacts < Flickr::Base
2
+ def initialize(flickr)
3
+ @flickr = flickr
4
+ end
5
+
6
+ # Get a user's public contact list.
7
+ #
8
+ # Params
9
+ # * id (Required)
10
+ # the nsid of the user to get information for
11
+ #
12
+ def get_public_list(id, options={})
13
+ options.merge!({:user_id => id})
14
+ rsp = @flickr.send_request('flickr.contacts.getPublicList', options)
15
+ collect_contacts(rsp)
16
+ end
17
+
18
+
19
+ # Get the authorized user's contact list.
20
+ #
21
+ def get_list(options={})
22
+ rsp = @flickr.send_request('flickr.contacts.getList', options)
23
+ collect_contacts(rsp)
24
+ end
25
+
26
+
27
+ protected
28
+ def collect_contacts(rsp)
29
+ contacts = []
30
+ return contacts unless rsp
31
+ if rsp.contacts.contact
32
+ rsp.contacts.contact.each do |contact|
33
+ attributes = create_attributes(contact)
34
+ contacts << Contact.new(attributes)
35
+ end
36
+ end
37
+ return contacts
38
+ end
39
+
40
+ def create_attributes(contact)
41
+ {
42
+ :nsid => contact[:nsid],
43
+ :path_alias => contact[:path_alias],
44
+ :username => contact[:username],
45
+ :iconfarm => contact[:iconfarm],
46
+ :iconserver => contact[:iconserver],
47
+ :ignored => contact[:ignored],
48
+ :friend => contact[:friend],
49
+ :family => contact[:family],
50
+ :realname => contact[:realname],
51
+ :location => contact[:location]
52
+ }
53
+ end
54
+
55
+ end
@@ -0,0 +1,20 @@
1
+ module Flickr
2
+ class Error < RuntimeError
3
+ attr_accessor :code
4
+ end
5
+
6
+
7
+ class Errors
8
+
9
+ # Method used for raising the appropriate error class for a given error code.
10
+ # Currently raises only Flickr::Error
11
+ def self.error_for(code, message)
12
+ raise RuntimeError.new("Internal error. Flickr API error not identified or unknown error.") if (code.nil? || message.nil? || message.empty?)
13
+ raise RuntimeError.new("Internal error. Unknown error.") if code.to_i == 0 # We assume that error code 0 is never returned
14
+ e = Flickr::Error.new("#{code}: #{message}")
15
+ e.code = code
16
+ raise e
17
+ end
18
+ end
19
+
20
+ end
data/lib/flickr/geo.rb ADDED
@@ -0,0 +1,42 @@
1
+ class Flickr::Photos::Geo < Flickr::Base
2
+
3
+ def initialize(flickr)
4
+ @flickr = flickr
5
+ end
6
+
7
+ # Get the geo data (latitude and longitude and the accuracy level) of a photo.
8
+ #
9
+ # Params
10
+ # * photo_id (Required)
11
+ #
12
+ # Returns Flickr::Photos::Location object containing photo location
13
+ # or nil if photo is not geotagged.
14
+ def get_location(photo_id)
15
+ # begin
16
+ rsp = @flickr.send_request('flickr.photos.geo.getLocation', {:photo_id => photo_id})
17
+ Flickr::Photos::Location.new(:latitude => rsp.photo.location[:latitude].to_f,
18
+ :longitude => rsp.photo.location[:longitude].to_f, :accuracy => rsp.photo.location[:accuracy].to_i)
19
+ end
20
+
21
+ # Sets the geo data(latitude and longitude and the accuracy level) of a photo.
22
+ #
23
+ # Params
24
+ # * photo_id (Required)
25
+ # * latittude (Requried)
26
+ # * longitude (Required)
27
+ # * accuracy (Optional)
28
+ #
29
+ # Returns true if successful, raises an error otherwise.
30
+ def set_location(photo_id, lat, lon, accuracy = nil)
31
+ request_options = {:photo_id => photo_id, :lat => lat, :lon => lon}
32
+ request_options[:accuracy] = accuracy if !accuracy.nil?
33
+ @flickr.send_request('flickr.photos.geo.setLocation', request_options, :post)
34
+ true
35
+ end
36
+
37
+ def remove_location(photo_id)
38
+ request_options = {:photo_id => photo_id}
39
+ @flickr.send_request('flickr.photos.geo.removeLocation', request_options, :post)
40
+ true
41
+ end
42
+ end
@@ -11,4 +11,14 @@ class Flickr::Photos::License
11
11
  send("#{k}=", v)
12
12
  end
13
13
  end
14
+
15
+ def == o
16
+ return false unless o.respond_to?(:id) && o.respond_to?(:name) && o.respond_to?(:url)
17
+ return true if id == o.id && name == o.name && url == o.url
18
+ false
19
+ end
20
+
21
+ def eql? o
22
+ return self == o
23
+ end
14
24
  end
@@ -0,0 +1,15 @@
1
+ class Flickr::Photos::Location
2
+
3
+ attr_accessor :latitude, :longitude, :accuracy
4
+
5
+ # Create an instance of Flickr::Photos::Location
6
+ #
7
+ # Params
8
+ # * attributes (Required)
9
+ # a hash of attributes used to set the initial values of the Location object
10
+ def initialize(attributes)
11
+ attributes.each do |k,v|
12
+ send("#{k}=", v)
13
+ end
14
+ end
15
+ end
data/lib/flickr/photo.rb CHANGED
@@ -1,11 +1,9 @@
1
1
  # wrapping class to hold an flickr photo
2
- #
3
2
  class Flickr::Photos::Photo
4
3
  attr_accessor :id, :owner, :secret, :server, :farm, :title, :is_public, :is_friend, :is_family # standard attributes
5
4
  attr_accessor :license_id, :uploaded_at, :taken_at, :owner_name, :icon_server, :original_format, :updated_at, :geo, :tags, :machine_tags, :o_dims, :views, :media # extra attributes
6
5
  attr_accessor :info_added, :description, :original_secret, :owner_username, :owner_realname, :url_photopage, :notes # info attributes
7
- attr_accessor :sizes_added, :sizes, :url_square, :url_thumbnail, :url_small, :url_medium, :url_large, :url_original # size attributes
8
- attr_accessor :comments_added, :comments # comment attributes
6
+ attr_accessor :comments # comment attributes
9
7
 
10
8
  # create a new instance of a flickr photo.
11
9
  #
@@ -21,8 +19,31 @@ class Flickr::Photos::Photo
21
19
  end
22
20
  end
23
21
 
22
+ # Alias to image_url method
23
+ def url(size = :medium)
24
+ image_url(size)
25
+ end
26
+
27
+ # returns an instance of Flickr::Photos::Size for the required size
28
+ #
29
+ # Params
30
+ # * size (Optional)
31
+ # the size of the size instance to return. Optional sizes are:
32
+ # :square - square 75x75
33
+ # :thumbnail - 100 on longest side
34
+ # :small - 240 on longest side
35
+ # :medium - 500 on longest side
36
+ # :large - 1024 on longest side (only exists for very large original images)
37
+ # :original - original image, either a jpg, gif or png, depending on source format
38
+ # Examples
39
+ # Photo.photo_size(:square).source
40
+ # Photo.photo_size(:large).width
41
+ def photo_size(size = :medium)
42
+ size_hash.fetch(size.to_s, size_hash['medium'])
43
+ end
44
+
24
45
  # retreive the url to the image stored on flickr
25
- #
46
+ #
26
47
  # == Params
27
48
  # * size (Optional)
28
49
  # the size of the image to return. Optional sizes are:
@@ -32,10 +53,30 @@ class Flickr::Photos::Photo
32
53
  # :medium - 500 on longest side
33
54
  # :large - 1024 on longest side (only exists for very large original images)
34
55
  # :original - original image, either a jpg, gif or png, depending on source format
35
- #
36
- def url(size = :medium)
37
- attach_sizes
38
- send("url_#{size}")
56
+ #
57
+ def image_url(size = :medium)
58
+ # It turns out that flickr always stores all the sizes of the picture even when getSizes call returns otherwise.
59
+ # Not calling getSizes is also very important for performance reasons.
60
+ # Retrieving 30 search results means calling the API 31 times if you call getSizes every time.
61
+ # Mind that you still need to call getSizes if you go out for the original image.
62
+ if size == :original
63
+ size_hash[size.to_s].source if size_hash.has_key? size.to_s
64
+ else
65
+ key = "_#{size_key(size.to_sym)}"
66
+ key = "" if key == "_"
67
+ "http://farm#{farm}.static.flickr.com/#{server}/#{id}_#{secret}#{key}.jpg"
68
+ end
69
+ end
70
+
71
+ def photopage_url
72
+ # Keeping the same convention as image_url (foo_url)
73
+ url_photopage
74
+ end
75
+
76
+ def video_url
77
+ if size_hash['video player']
78
+ size_hash['video player'].source
79
+ end
39
80
  end
40
81
 
41
82
  # save the current photo to the local computer
@@ -53,7 +94,7 @@ class Flickr::Photos::Photo
53
94
  # :original - original image, either a jpg, gif or png, depending on source format
54
95
  #
55
96
  def save_as(filename, size = :medium)
56
- format = size.to_sym == :original ? self.original_format : 'jpg'
97
+ format = size.to_sym == :original ? (self.original_format || 'jpg') : 'jpg'
57
98
  filename = "#{filename}.#{format}"
58
99
 
59
100
  if File.exists?(filename) or not self.url(size)
@@ -73,7 +114,7 @@ class Flickr::Photos::Photo
73
114
  # comma seperated list of tags
74
115
  #
75
116
  def add_tags(tags)
76
- rsp = @flickr.send_request('flickr.photos.addTags', {:photo_id => self.id, :tags => tags}, :post)
117
+ @flickr.send_request('flickr.photos.addTags', {:photo_id => self.id, :tags => tags}, :post)
77
118
  true
78
119
  end
79
120
 
@@ -84,7 +125,7 @@ class Flickr::Photos::Photo
84
125
  # text of the comment
85
126
  #
86
127
  def add_comment(message)
87
- rsp = @flickr.send_request('flickr.photos.comments.addComment', {:photo_id => self.id, :comment_text => message}, :post)
128
+ @flickr.send_request('flickr.photos.comments.addComment', {:photo_id => self.id, :comment_text => message}, :post)
88
129
  true
89
130
  end
90
131
 
@@ -103,7 +144,7 @@ class Flickr::Photos::Photo
103
144
  # The height of the note
104
145
  #
105
146
  def add_note(message, x, y, w, h)
106
- rsp = @flickr.send_request('flickr.photos.notes.add', {:photo_id => self.id, :note_x => x, :note_y => y, :note_w => w, :note_h => h, :note_text => message}, :post)
147
+ @flickr.send_request('flickr.photos.notes.add', {:photo_id => self.id, :note_x => x, :note_y => y, :note_w => w, :note_h => h, :note_text => message}, :post)
107
148
  true
108
149
  end
109
150
 
@@ -114,7 +155,7 @@ class Flickr::Photos::Photo
114
155
  # The amount of degrees by which to rotate the photo (clockwise) from it's current orientation. Valid values are 90, 180 and 270.
115
156
  #
116
157
  def rotate(degrees)
117
- rsp = @flickr.send_request('flickr.photos.transform.rotate', {:photo_id => self.id, :degrees => degrees}, :post)
158
+ @flickr.send_request('flickr.photos.transform.rotate', {:photo_id => self.id, :degrees => degrees}, :post)
118
159
  true
119
160
  end
120
161
 
@@ -123,6 +164,29 @@ class Flickr::Photos::Photo
123
164
  def license
124
165
  @flickr.photos.licenses[self.license_id]
125
166
  end
167
+
168
+ # Returns the location of the photo (if available)
169
+ # or nil if photo is not geo-tagged.
170
+ def location
171
+ begin
172
+ @location ||= @flickr.photos.geo.get_location(self.id)
173
+ rescue Flickr::Error => e
174
+ if e.code == 2 # 2: Photo has no location information.
175
+ return nil
176
+ else
177
+ raise e
178
+ end
179
+ end
180
+ end
181
+
182
+ def location= location
183
+ if !location.nil?
184
+ @flickr.photos.geo.set_location(self.id, location.latitude, location.longitude, location.accuracy)
185
+ else
186
+ @flickr.photos.geo.remove_location(self.id)
187
+ end
188
+ @location = location
189
+ end
126
190
 
127
191
  # Sets the license for a photo.
128
192
  #
@@ -130,7 +194,7 @@ class Flickr::Photos::Photo
130
194
  # * license_id (Required)
131
195
  # The license to apply, or 0 (zero) to remove the current license.
132
196
  def set_license(license_id)
133
- rsp = @flickr.send_request('flickr.photos.licenses.setLicense', {:photo_id => self.id, :license_id => license_id}, :post)
197
+ @flickr.send_request('flickr.photos.licenses.setLicense', {:photo_id => self.id, :license_id => license_id}, :post)
134
198
  true
135
199
  end
136
200
 
@@ -160,13 +224,39 @@ class Flickr::Photos::Photo
160
224
  end
161
225
 
162
226
  def comments # :nodoc:
163
- attach_comments
164
- @comments
227
+ @comments ||= begin
228
+ if @comment_count == 0
229
+ self.comments = []
230
+ else
231
+ rsp = @flickr.send_request('flickr.photos.comments.getList', :photo_id => self.id)
232
+
233
+ self.comments = []
234
+
235
+ rsp.comments.comment.each do |comment|
236
+ self.comments << Flickr::Photos::Comment.new(:id => comment[:id],
237
+ :comment => comment.to_s,
238
+ :author => comment[:author],
239
+ :author_name => comment[:authorname],
240
+ :permalink => comment[:permalink],
241
+ :created_at => (Time.at(comment[:datecreate].to_i) rescue nil))
242
+ end
243
+ end
244
+
245
+ self.comments
246
+ end
165
247
  end
166
248
 
167
249
  def sizes # :nodoc:
168
- attach_sizes
169
- @sizes
250
+ @sizes ||= begin
251
+ rsp = @flickr.send_request('flickr.photos.getSizes', :photo_id => self.id)
252
+
253
+ _sizes = []
254
+ rsp.sizes.size.each do |size|
255
+ _sizes << Flickr::Photos::Size.new(:label => size[:label], :width => size[:width],
256
+ :height => size[:height], :source => size[:source], :url => size[:url])
257
+ end
258
+ _sizes
259
+ end
170
260
  end
171
261
 
172
262
  def notes # :nodoc:
@@ -175,34 +265,14 @@ class Flickr::Photos::Photo
175
265
  end
176
266
 
177
267
  protected
178
- def url_square # :nodoc:
179
- attach_sizes
180
- @url_square
181
- end
182
-
183
- def url_thumbnail # :nodoc:
184
- attach_sizes
185
- @url_thumbnail
186
- end
187
-
188
- def url_small # :nodoc:
189
- attach_sizes
190
- @url_small
191
- end
192
-
193
- def url_medium # :nodoc:
194
- attach_sizes
195
- @url_medium
196
- end
197
-
198
- def url_large # :nodoc:
199
- attach_sizes
200
- @url_large
201
- end
202
-
203
- def url_original # :nodoc:
204
- attach_sizes
205
- @url_original
268
+ def size_hash
269
+ @size_hash ||= begin
270
+ hash = {}
271
+ sizes.each do |size|
272
+ hash[size.label.downcase] = size
273
+ end
274
+ hash
275
+ end
206
276
  end
207
277
 
208
278
  private
@@ -211,12 +281,12 @@ class Flickr::Photos::Photo
211
281
  # convert the size to the key used in the flickr url
212
282
  def size_key(size)
213
283
  case size.to_sym
214
- when :square : 's'
215
- when :thumb, :thumbnail : 't'
216
- when :small : 'm'
217
- when :medium : '-'
218
- when :large : 'b'
219
- when :original : 'o'
284
+ when :square then 's'
285
+ when :thumb, :thumbnail then 't'
286
+ when :small then 'm'
287
+ when :medium then ''
288
+ when :large then 'b'
289
+ when :original then 'o'
220
290
  else ''
221
291
  end
222
292
  end
@@ -227,7 +297,7 @@ class Flickr::Photos::Photo
227
297
  rsp = @flickr.send_request('flickr.photos.getInfo', :photo_id => self.id, :secret => self.secret)
228
298
 
229
299
  self.info_added = true
230
- self.description = rsp.photo.description.to_s
300
+ self.description = rsp.photo.description.to_s.strip
231
301
  self.original_secret = rsp.photo[:originalsecret]
232
302
  self.owner_username = rsp.photo.owner[:username]
233
303
  self.owner_realname = rsp.photo.owner[:realname]
@@ -238,61 +308,14 @@ class Flickr::Photos::Photo
238
308
 
239
309
  rsp.photo.notes.note.each do |note|
240
310
  self.notes << Flickr::Photos::Note.new(:id => note[:id],
241
- :note => note.to_s,
242
- :author => note[:author],
243
- :author_name => note[:authorname],
244
- :x => note[:x],
245
- :y => note[:y],
246
- :width => note[:w],
247
- :height => note[:h])
311
+ :note => note.to_s,
312
+ :author => note[:author],
313
+ :author_name => note[:authorname],
314
+ :x => note[:x],
315
+ :y => note[:y],
316
+ :width => note[:w],
317
+ :height => note[:h])
248
318
  end if rsp.photo.notes.note
249
319
  end
250
320
  end
251
-
252
- # loads picture sizes only after one has been requested
253
- def attach_sizes
254
- unless self.sizes_added
255
- rsp = @flickr.send_request('flickr.photos.getSizes', :photo_id => self.id)
256
-
257
- self.sizes_added = true
258
- self.sizes = []
259
-
260
- # TODO: investigate the new video features and integrate better
261
- rsp.sizes.size.each do |size|
262
- method = "url_#{size[:label].downcase}="
263
- next unless respond_to? method
264
- send(method, size[:source])
265
-
266
- # send("url_#{size[:label].downcase}=", size[:source])
267
-
268
- self.sizes << Flickr::Photos::Size.new(:label => size[:label],
269
- :width => size[:width],
270
- :height => size[:height],
271
- :source => size[:source],
272
- :url => size[:url])
273
- end
274
- end
275
- end
276
-
277
- # loads comments once they have been requested
278
- def attach_comments
279
- if @comment_count == 0
280
- self.comments = []
281
- self.comments_added = true
282
- elsif not self.comments_added
283
- rsp = @flickr.send_request('flickr.photos.comments.getList', :photo_id => self.id)
284
-
285
- self.comments = []
286
- self.comments_added = true
287
-
288
- rsp.comments.comment.each do |comment|
289
- self.comments << Flickr::Photos::Comment.new(:id => comment[:id],
290
- :comment => comment.to_s,
291
- :author => comment[:author],
292
- :author_name => comment[:authorname],
293
- :permalink => comment[:permalink],
294
- :created_at => (Time.at(comment[:datecreate].to_i) rescue nil))
295
- end
296
- end
297
- end
298
321
  end