ruby-flickr 0.1.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.
@@ -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
+