ruby-flickr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ module Flickr
2
+ def self.new(*params)
3
+ Flickr::Base.new(*params)
4
+ end
5
+
6
+ class Base
7
+ ENDPOINT = 'http://api.flickr.com/services/rest/'
8
+
9
+ def initialize(api_key, api_secret = nil)
10
+ @api_key = api_key
11
+ @api_secret = api_secret
12
+ end
13
+
14
+ def send_request(method, options = {})
15
+ options.merge!(:api_key => @api_key, :method => method)
16
+
17
+ api_call = ENDPOINT + "?" + options.collect{|k,v| "#{k}=#{v}"}.join('&')
18
+ rsp = open(api_call).read
19
+ xm = XmlMagic.new(rsp)
20
+
21
+ if xm[:stat] == 'ok'
22
+ xm
23
+ else
24
+ raise "#{xm.err[:code]}: #{xm.err[:msg]}"
25
+ end
26
+ end
27
+
28
+ def photos() @photos ||= Photos.new(self) end
29
+ end
30
+ end
@@ -0,0 +1,365 @@
1
+ class Flickr::Photos < Flickr::Base
2
+ def initialize(flickr)
3
+ @flickr = flickr
4
+ end
5
+
6
+ # Return a list of photos matching some criteria. Only photos visible to the calling user will be returned. To return private or semi-private photos,
7
+ # the caller must be authenticated with 'read' permissions, and have permission to view the photos. Unauthenticated calls will only return public photos.
8
+ #
9
+ # == Authentication
10
+ # This method does not require authentication.
11
+ #
12
+ # == Options
13
+ # * user_id (Optional)
14
+ # The NSID of the user who's photo to search. If this parameter isn't passed then everybody's public photos will be searched. A value of "me" will
15
+ # search against the calling user's photos for authenticated calls.
16
+ # * tags (Optional)
17
+ # A comma-delimited list of tags. Photos with one or more of the tags listed will be returned.
18
+ # * tag_mode (Optional)
19
+ # Either 'any' for an OR combination of tags, or 'all' for an AND combination. Defaults to 'any' if not specified.
20
+ # * text (Optional)
21
+ # A free text search. Photos who's title, description or tags contain the text will be returned.
22
+ # * min_upload_date (Optional)
23
+ # Minimum upload date. Photos with an upload date greater than or equal to this value will be returned. The date should be in the form of a unix timestamp.
24
+ # * max_upload_date (Optional)
25
+ # Maximum upload date. Photos with an upload date less than or equal to this value will be returned. The date should be in the form of a unix timestamp.
26
+ # * min_taken_date (Optional)
27
+ # Minimum taken date. Photos with an taken date greater than or equal to this value will be returned. The date should be in the form of a mysql datetime.
28
+ # * max_taken_date (Optional)
29
+ # Maximum taken date. Photos with an taken date less than or equal to this value will be returned. The date should be in the form of a mysql datetime.
30
+ # * license (Optional)
31
+ # The license id for photos (for possible values see the flickr.photos.licenses.getInfo method). Multiple licenses may be comma-separated.
32
+ # * sort (Optional)
33
+ # The order in which to sort returned photos. Deafults to date-posted-desc. The possible values are: date-posted-asc, date-posted-desc, date-taken-asc,
34
+ # date-taken-desc, interestingness-desc, interestingness-asc, and relevance.
35
+ # * privacy_filter (Optional)
36
+ # Return photos only matching a certain privacy level. This only applies when making an authenticated call to view photos you own. Valid values are:
37
+ # 1 public photos
38
+ # 2 private photos visible to friends
39
+ # 3 private photos visible to family
40
+ # 4 private photos visible to friends & family
41
+ # 5 completely private photos
42
+ # * bbox (Optional)
43
+ # A comma-delimited list of 4 values defining the Bounding Box of the area that will be searched.
44
+ #
45
+ # The 4 values represent the bottom-left corner of the box and the top-right corner, minimum_longitude, minimum_latitude, maximum_longitude, maximum_latitude.
46
+ #
47
+ # Longitude has a range of -180 to 180 , latitude of -90 to 90. Defaults to -180, -90, 180, 90 if not specified.
48
+ #
49
+ # Unlike standard photo queries, geo (or bounding box) queries will only return 250 results per page.
50
+ #
51
+ # Geo queries require some sort of limiting agent in order to prevent the database from crying. This is basically like the check against "parameterless searches"
52
+ # for queries without a geo component.
53
+ #
54
+ # A tag, for instance, is considered a limiting agent as are user defined min_date_taken and min_date_upload parameters — If no limiting factor is passed we
55
+ # return only photos added in the last 12 hours (though we may extend the limit in the future).
56
+ # * accuracy (Optional)
57
+ # Recorded accuracy level of the location information. Current range is 1-16 :
58
+ # World level is 1
59
+ # Country is ~3
60
+ # Region is ~6
61
+ # City is ~11
62
+ # Street is ~16
63
+ # Defaults to maximum value if not specified.
64
+ # * safe_search (Optional)
65
+ # Safe search setting:
66
+ # 1 for safe.
67
+ # 2 for moderate.
68
+ # 3 for restricted.
69
+ # (Please note: Un-authed calls can only see Safe content.)
70
+ # * content_type (Optional)
71
+ # Content Type setting:
72
+ # 1 for photos only.
73
+ # 2 for screenshots only.
74
+ # 3 for 'other' only.
75
+ # 4 for photos and screenshots.
76
+ # 5 for screenshots and 'other'.
77
+ # 6 for photos and 'other'.
78
+ # 7 for photos, screenshots, and 'other' (all).
79
+ # * machine_tags (Optional)
80
+ # Aside from passing in a fully formed machine tag, there is a special syntax for searching on specific properties :
81
+ # Find photos using the 'dc' namespace : "machine_tags" => "dc:"
82
+ # Find photos with a title in the 'dc' namespace : "machine_tags" => "dc:title="
83
+ # Find photos titled "mr. camera" in the 'dc' namespace : "machine_tags" => "dc:title=\"mr. camera\"
84
+ # Find photos whose value is "mr. camera" : "machine_tags" => "*:*=\"mr. camera\""
85
+ # Find photos that have a title, in any namespace : "machine_tags" => "*:title="
86
+ # Find photos that have a title, in any namespace, whose value is "mr. camera" : "machine_tags" => "*:title=\"mr. camera\""
87
+ # Find photos, in the 'dc' namespace whose value is "mr. camera" : "machine_tags" => "dc:*=\"mr. camera\""
88
+ # Multiple machine tags may be queried by passing a comma-separated list. The number of machine tags you can pass in a single query depends on
89
+ # the tag mode (AND or OR) that you are querying with. "AND" queries are limited to (16) machine tags. "OR" queries are limited to (8).
90
+ # * machine_tag_mode (Required)
91
+ # Either 'any' for an OR combination of tags, or 'all' for an AND combination. Defaults to 'any' if not specified.
92
+ # * group_id (Optional)
93
+ # The id of a group who's pool to search. If specified, only matching photos posted to the group's pool will be returned.
94
+ # * woe_id (Optional)
95
+ # A 32-bit identifier that uniquely represents spatial entities. (not used if bbox argument is present). Experimental.
96
+ #
97
+ # Geo queries require some sort of limiting agent in order to prevent the database from crying. This is basically like the check against "parameterless searches"
98
+ # for queries without a geo component.
99
+ #
100
+ # A tag, for instance, is considered a limiting agent as are user defined min_date_taken and min_date_upload parameters &emdash; If no limiting factor is passed
101
+ # we return only photos added in the last 12 hours (though we may extend the limit in the future).
102
+ # * place_id (Optional)
103
+ # A Flickr place id. (not used if bbox argument is present). Experimental.
104
+ #
105
+ # Geo queries require some sort of limiting agent in order to prevent the database from crying. This is basically like the check against "parameterless searches"
106
+ # for queries without a geo component.
107
+ #
108
+ # A tag, for instance, is considered a limiting agent as are user defined min_date_taken and min_date_upload parameters &emdash; If no limiting factor is passed
109
+ # we return only photos added in the last 12 hours (though we may extend the limit in the future).
110
+ # * extras (Included Automatically)
111
+ # A comma-delimited list of extra information to fetch for each returned record.
112
+ #
113
+ # Currently supported fields are:
114
+ # license
115
+ # date_upload
116
+ # date_taken
117
+ # owner_name
118
+ # icon_server
119
+ # original_format
120
+ # last_update
121
+ # geo
122
+ # tags
123
+ # machine_tags
124
+ # o_dims
125
+ # views
126
+ # * per_page (Optional)
127
+ # Number of photos to return per page. If this argument is omitted, it defaults to 100. The maximum allowed value is 500.
128
+ # * page (Optional)
129
+ # The page of results to return. If this argument is omitted, it defaults to 1.
130
+ #
131
+ def search(options)
132
+ options = {:extras => "license,date_upload,date_taken,owner_name,icon_server,original_format,last_update,geo,tags,machine_tags,o_dims,views"}.merge(options)
133
+
134
+ rsp = @flickr.send_request('flickr.photos.search', options)
135
+
136
+ returning PhotoResponse.new(:page => rsp.photos[:page], :pages => rsp.photos[:pages], :per_page => rsp.photos[:perpage], :total => rsp.photos[:total], :photos => [], :api => self, :method => 'flickr.photos.search', :options => options) do |photos|
137
+ rsp.photos.photo.each do |photo|
138
+ all_attributes = {:id => photo[:id],
139
+ :owner => photo[:owner],
140
+ :secret => photo[:secret],
141
+ :server => photo[:server],
142
+ :farm => photo[:farm],
143
+ :title => photo[:title],
144
+ :is_public => photo[:ispublic],
145
+ :is_friend => photo[:isfriend],
146
+ :is_family => photo[:isfamily],
147
+ :license => photo[:license],
148
+ :date_upload => (Time.at(photo[:dateupload].to_i) rescue nil),
149
+ :date_taken => (Time.parse(photo[:datetaken]) rescue nil),
150
+ :owner_name => photo[:ownername],
151
+ :icon_server => photo[:icon_server],
152
+ :original_format => photo[:originalformat],
153
+ :last_update => (Time.at(photo[:lastupdate].to_i) rescue nil),
154
+ :geo => photo[:geo],
155
+ :tags => photo[:tags],
156
+ :machine_tags => photo[:machine_tags],
157
+ :o_dims => photo[:o_dims],
158
+ :views => photo[:views]}
159
+
160
+ used_attributes = {}
161
+
162
+ all_attributes.each do |k,v|
163
+ used_attributes[k] = v if v
164
+ end
165
+
166
+ photos << Photo.new(@flickr, used_attributes)
167
+ end if rsp.photos.photo
168
+ end
169
+ end
170
+
171
+ # wrapping class to hold a photos response from the flickr api
172
+ class PhotoResponse
173
+ attr_accessor :page, :pages, :per_page, :total, :photos, :api, :method, :options
174
+
175
+ def initialize(attributes)
176
+ attributes.each do |k,v|
177
+ send("#{k}=", v)
178
+ end
179
+ end
180
+
181
+ # Add a Flickr::Photos::Photo object to the photos array. It does nothing if you pass a non photo object
182
+ def <<(photo)
183
+ self.photos ||= []
184
+ self.photos << photo if photo.is_a?(Flickr::Photos::Photo)
185
+ end
186
+
187
+ # gets the next page from flickr if there are anymore pages in the current photos object
188
+ def next_page
189
+ api.send(self.method.split('.').last, options.merge(:page => self.page.to_i + 1)) if self.page.to_i < self.pages.to_i
190
+ end
191
+
192
+ # gets the previous page from flickr if there is a previous page in the current photos object
193
+ def previous_page
194
+ api.send(self.method.split('.').last, options.merge(:page => self.page.to_i - 1)) if self.page.to_i > 1
195
+ end
196
+
197
+ def method_missing(method, *args, &block)
198
+ self.photos.respond_to?(method) ? self.photos.send(method, *args, &block) : super
199
+ end
200
+ end
201
+
202
+ # wrapping class to hold an flickr photo
203
+ class Photo
204
+ attr_accessor :id, :owner, :secret, :server, :farm, :title, :is_public, :is_friend, :is_family # standard attributes
205
+ attr_accessor :license, :date_upload, :date_taken, :owner_name, :icon_server, :original_format, :last_update, :geo, :tags, :machine_tags, :o_dims, :views # extra attributes
206
+ attr_accessor :info_added, :description, :original_secret, :owner_username, :owner_realname, :url_photopage # info attributes
207
+ attr_accessor :sizes_added, :url_square, :url_thumbnail, :url_small, :url_medium, :url_large, :url_original # size attributes
208
+
209
+ def initialize(flickr, attributes)
210
+ @flickr = flickr
211
+ attributes.each do |k,v|
212
+ send("#{k}=", v)
213
+ end
214
+ end
215
+
216
+ # retreive the url to the image stored on flickr
217
+ #
218
+ # == Params
219
+ # * size (Optional)
220
+ # the size of the image to return. Optional sizes are:
221
+ # :square - square 75x75
222
+ # :thumbnail - 100 on longest side
223
+ # :small - 240 on longest side
224
+ # :medium - 500 on longest side
225
+ # :large - 1024 on longest side (only exists for very large original images)
226
+ # :original - original image, either a jpg, gif or png, depending on source format
227
+ #
228
+ def url(size = :medium)
229
+ attach_sizes
230
+ send("url_#{size}")
231
+ end
232
+
233
+ # save the current photo to the local computer
234
+ #
235
+ # == Params
236
+ # * filename (Required)
237
+ # name of the new file omiting the extention (ex. photo_1)
238
+ # * size (Optional)
239
+ # the size of the image to return. Optional sizes are:
240
+ # :small - square 75x75
241
+ # :thumbnail - 100 on longest side
242
+ # :small - 240 on longest side
243
+ # :medium - 500 on longest side
244
+ # :large - 1024 on longest side (only exists for very large original images)
245
+ # :original - original image, either a jpg, gif or png, depending on source format
246
+ #
247
+ def save_as(filename, size = :medium)
248
+ format = size.to_sym == :original ? self.original_format : 'jpg'
249
+ filename = "#{filename}.#{format}"
250
+
251
+ if File.exists?(filename) or not self.url(size)
252
+ false
253
+ else
254
+ f = File.new(filename, 'w+')
255
+ f.puts open(self.url(size)).read
256
+ f.close
257
+ true
258
+ end
259
+ end
260
+
261
+ def description
262
+ attach_info
263
+ @description
264
+ end
265
+
266
+ def original_secret
267
+ attach_info
268
+ @original_secret
269
+ end
270
+
271
+ def owner_username
272
+ attach_info
273
+ @owner_username
274
+ end
275
+
276
+ def owner_realname
277
+ attach_info
278
+ @owner_realname
279
+ end
280
+
281
+ def url_photopage
282
+ attach_info
283
+ @url_photopage
284
+ end
285
+
286
+ protected
287
+ def url_square
288
+ attach_sizes
289
+ @url_square
290
+ end
291
+
292
+ def url_thumbnail
293
+ attach_sizes
294
+ @url_thumbnail
295
+ end
296
+
297
+ def url_small
298
+ attach_sizes
299
+ @url_small
300
+ end
301
+
302
+ def url_medium
303
+ attach_sizes
304
+ @url_medium
305
+ end
306
+
307
+ def url_large
308
+ attach_sizes
309
+ @url_large
310
+ end
311
+
312
+ def url_original
313
+ attach_sizes
314
+ @url_original
315
+ end
316
+
317
+ private
318
+ # convert the size to the key used in the flickr url
319
+ def size_key(size)
320
+ case size.to_sym
321
+ when :square : 's'
322
+ when :thumb, :thumbnail : 't'
323
+ when :small : 'm'
324
+ when :medium : '-'
325
+ when :large : 'b'
326
+ when :original : 'o'
327
+ else ''
328
+ end
329
+ end
330
+
331
+ # loads photo info when a field is requested that requires additional info
332
+ def attach_info
333
+ unless self.info_added
334
+ rsp = @flickr.send_request('flickr.photos.getInfo', :photo_id => self.id, :secret => self.secret)
335
+
336
+ self.info_added = true
337
+ self.description = rsp.photo.description.to_s
338
+ self.original_secret = rsp.photo[:originalsecret]
339
+ self.owner_username = rsp.photo.owner[:username]
340
+ self.owner_realname = rsp.photo.owner[:realname]
341
+ self.url_photopage = rsp.photo.urls.url.to_s
342
+ end
343
+ end
344
+
345
+ # loads picture sizes only after one has been requested
346
+ def attach_sizes
347
+ unless self.sizes_added
348
+ rsp = @flickr.send_request('flickr.photos.getSizes', :photo_id => self.id)
349
+
350
+ self.sizes_added = true
351
+
352
+ rsp.sizes.size.each do |size|
353
+ case size[:label]
354
+ when 'Square' : self.url_square = size[:source]
355
+ when 'Thumbnail' : self.url_thumbnail = size[:source]
356
+ when 'Small' : self.url_small = size[:source]
357
+ when 'Medium' : self.url_medium = size[:source]
358
+ when 'Large' : self.url_large = size[:source]
359
+ when 'Original' : self.url_original = size[:source]
360
+ end
361
+ end
362
+ end
363
+ end
364
+ end
365
+ end
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'xml_magic'
3
+ require 'open-uri'
4
+ include CommonThread::XML
5
+
6
+ Dir[File.join(File.dirname(__FILE__), 'flickr/**/*.rb')].sort.each { |lib| require lib }
7
+
8
+ class Object
9
+ # returning allows you to pass an object to a block that you can manipulate returning the manipulated object
10
+ def returning(value)
11
+ yield(value)
12
+ value
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-flickr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Wyrosdick
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-03-29 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: ben@commonthread.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/flickr
26
+ - lib/flickr/base.rb
27
+ - lib/flickr/photos.rb
28
+ - lib/ruby_flickr.rb
29
+ has_rdoc: false
30
+ homepage: http://www.commonthread.com/projects/ruby-flickr/rdoc/
31
+ post_install_message:
32
+ rdoc_options: []
33
+
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: "0"
41
+ version:
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ requirements: []
49
+
50
+ rubyforge_project: ruby-flickr
51
+ rubygems_version: 1.0.1
52
+ signing_key:
53
+ specification_version: 2
54
+ summary: Provides a ruby interface to flickr via the REST api
55
+ test_files: []
56
+