flickr-fu 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,69 @@
1
+ class Flickr::Auth < Flickr::Base
2
+ def initialize(flickr)
3
+ @flickr = flickr
4
+ end
5
+
6
+ # get or return a frob to use for authentication
7
+ def frob
8
+ @frob ||= get_frob
9
+ end
10
+
11
+ # generates the authorization url to allow access to a flickr account.
12
+ #
13
+ # Params
14
+ # * perms (Optional)
15
+ # sets the permision level to grant on the flickr account.
16
+ # :read - permission to read private information (DEFAULT)
17
+ # :write - permission to add, edit and delete photo metadata (includes 'read')
18
+ # :delete - permission to delete photos (includes 'write' and 'read')
19
+ #
20
+ def url(perms = :read)
21
+ options = {:api_key => @flickr.api_key, :perms => perms, :frob => self.frob}
22
+ @flickr.sign_request(options)
23
+ Flickr::Base::AUTH_ENDPOINT + "?" + options.collect{|k,v| "#{k}=#{v}"}.join('&')
24
+ end
25
+
26
+ # gets the token object for the current frob
27
+ #
28
+ # Params
29
+ # * pass_through (Optional)
30
+ # Boolean value that determines if a call will be made to flickr to find a taken for the current frob if empty
31
+ #
32
+ def token(pass_through = true)
33
+ @token ||= get_token(pass_through) rescue nil
34
+ end
35
+
36
+ # saves the current token to the cache file if token exists
37
+ #
38
+ # Param
39
+ # * filename (Optional)
40
+ # filename of the cache file. defaults to the file passed into Flickr.new
41
+ #
42
+ def cache_token(filename = @flickr.token_cache)
43
+ if filename and self.token
44
+ cache_file = File.open(filename, 'w+')
45
+ cache_file.puts self.token.to_yaml
46
+ cache_file.close
47
+ true
48
+ else
49
+ false
50
+ end
51
+ end
52
+
53
+ private
54
+ def get_frob
55
+ rsp = @flickr.send_request('flickr.auth.getFrob')
56
+
57
+ rsp.frob.to_s
58
+ end
59
+
60
+ def get_token(pass_through)
61
+ if @flickr.token_cache and File.exists?(@flickr.token_cache)
62
+ YAML.load_file(@flickr.token_cache)
63
+ elsif pass_through
64
+ rsp = @flickr.send_request('flickr.auth.getToken', {:frob => self.frob})
65
+
66
+ Token.new(:token => rsp.auth.token.to_s, :permisions => rsp.auth.perms.to_s, :user_id => rsp.auth.user[:nsid], :username => rsp.auth.user[:username], :user_real_name => rsp.auth.user[:fullname])
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,94 @@
1
+ module Flickr
2
+ def self.new(*params)
3
+ Flickr::Base.new(*params)
4
+ end
5
+
6
+ class Base
7
+ attr_reader :api_key, :api_secret, :token_cache
8
+
9
+ REST_ENDPOINT = 'http://api.flickr.com/services/rest/'
10
+ AUTH_ENDPOINT = 'http://flickr.com/services/auth/'
11
+ UPLOAD_ENDPOINT = 'http://api.flickr.com/services/upload/'
12
+
13
+ # create a new flickr object
14
+ #
15
+ # Params
16
+ # * config_file (Required)
17
+ # yaml file to load configuration from
18
+ # * token_cache (Optional)
19
+ # location of the token cache file. This will override the setting in the config file
20
+ #
21
+ # Config Example (yaml file)
22
+ #
23
+ # ---
24
+ # key: YOUR_API_KEY
25
+ # secret: YOUR_API_SECRET
26
+ # token_cache: token.yml
27
+ #
28
+ def initialize(config_file, token_cache = nil)
29
+ config = YAML.load_file(config_file)
30
+
31
+ @api_key = config['key']
32
+ @api_secret = config['secret']
33
+ @token_cache = token_cache || config['token_cache']
34
+
35
+ raise 'flickr config file must contain an api key and secret' unless @api_key and @api_secret
36
+ end
37
+
38
+ # sends a request to the flcikr REST api
39
+ #
40
+ # Params
41
+ # * method (Required)
42
+ # name of the flickr method (ex. flickr.photos.search)
43
+ # * options (Optional)
44
+ # hash of query parameters, you do not need to include api_key, api_sig or auth_token because these are added automatically
45
+ # * http_method (Optional)
46
+ # choose between a GET and POST http request. Valid options are:
47
+ # :get (DEFAULT)
48
+ # :post
49
+ # * endpoint (Optional)
50
+ # url of the api endpoint
51
+ #
52
+ def send_request(method, options = {}, http_method = :get, endpoint = REST_ENDPOINT)
53
+ options.merge!(:api_key => @api_key, :method => method)
54
+ sign_request(options)
55
+
56
+ if http_method == :get
57
+ api_call = endpoint + "?" + options.collect{|k,v| "#{k}=#{v}"}.join('&')
58
+ rsp = Net::HTTP.get(URI.parse(api_call))
59
+ else
60
+ rsp = Net::HTTP.post_form(URI.parse(REST_ENDPOINT), options).body
61
+ end
62
+
63
+ xm = XmlMagic.new(rsp)
64
+
65
+ if xm[:stat] == 'ok'
66
+ xm
67
+ else
68
+ raise "#{xm.err[:code]}: #{xm.err[:msg]}"
69
+ end
70
+ end
71
+
72
+ # alters your api parameters to include a signiture and authorization token
73
+ #
74
+ # Params
75
+ # * options (Required)
76
+ # the hash of parameters to be passed to the send_request
77
+ # * authorize (Optional)
78
+ # boolean value to determine if the call with include an auth_token (Defaults to true)
79
+ #
80
+ def sign_request(options, authorize = true)
81
+ options.merge!(:auth_token => self.auth.token(false).to_s) if authorize and self.auth.token(false)
82
+ options.merge!(:api_sig => Digest::MD5.hexdigest(@api_secret + options.keys.sort_by{|k| k.to_s}.collect{|k| k.to_s + options[k].to_s}.join)) if @api_secret
83
+ end
84
+
85
+ # creates and/or returns the Flickr::Photos object
86
+ def photos() @photos ||= Photos.new(self) end
87
+
88
+ # creates and/or returns the Flickr::Auth object
89
+ def auth() @auth ||= Auth.new(self) end
90
+
91
+ # creates and/or returns the Flickr::Uploader object
92
+ def uploader() @uploader ||= Uploader.new(self) end
93
+ end
94
+ end
@@ -0,0 +1,16 @@
1
+ # wrapping class to hold a flickr comment
2
+ #
3
+ class Flickr::Photos::Comment
4
+ attr_accessor :id, :comment, :author, :author_name, :created_at, :permalink
5
+
6
+ # create a new instance of a flickr comment.
7
+ #
8
+ # Params
9
+ # * attributes (Required)
10
+ # a hash of attributes used to set the initial values of the comment object
11
+ def initialize(attributes)
12
+ attributes.each do |k,v|
13
+ send("#{k}=", v)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # wrapping class to hold a flickr note
2
+ #
3
+ class Flickr::Photos::Note
4
+ attr_accessor :id, :note, :author, :author_name, :x, :y, :width, :height
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 note object
11
+ def initialize(attributes)
12
+ attributes.each do |k,v|
13
+ send("#{k}=", v)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,266 @@
1
+ # wrapping class to hold an flickr photo
2
+ #
3
+ class Flickr::Photos::Photo
4
+ attr_accessor :id, :owner, :secret, :server, :farm, :title, :is_public, :is_friend, :is_family # standard attributes
5
+ attr_accessor :license, :uploaded_at, :taken_at, :owner_name, :icon_server, :original_format, :updated_at, :geo, :tags, :machine_tags, :o_dims, :views # extra attributes
6
+ 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
9
+
10
+ # create a new instance of a flickr photo.
11
+ #
12
+ # Params
13
+ # * flickr (Required)
14
+ # the flickr object
15
+ # * attributes (Required)
16
+ # a hash of attributes used to set the initial values of the photo object
17
+ def initialize(flickr, attributes)
18
+ @flickr = flickr
19
+ attributes.each do |k,v|
20
+ send("#{k}=", v)
21
+ end
22
+ end
23
+
24
+ # retreive the url to the image stored on flickr
25
+ #
26
+ # == Params
27
+ # * size (Optional)
28
+ # the size of the image to return. Optional sizes are:
29
+ # :square - square 75x75
30
+ # :thumbnail - 100 on longest side
31
+ # :small - 240 on longest side
32
+ # :medium - 500 on longest side
33
+ # :large - 1024 on longest side (only exists for very large original images)
34
+ # :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}")
39
+ end
40
+
41
+ # save the current photo to the local computer
42
+ #
43
+ # == Params
44
+ # * filename (Required)
45
+ # name of the new file omiting the extention (ex. photo_1)
46
+ # * size (Optional)
47
+ # the size of the image to return. Optional sizes are:
48
+ # :small - square 75x75
49
+ # :thumbnail - 100 on longest side
50
+ # :small - 240 on longest side
51
+ # :medium - 500 on longest side
52
+ # :large - 1024 on longest side (only exists for very large original images)
53
+ # :original - original image, either a jpg, gif or png, depending on source format
54
+ #
55
+ def save_as(filename, size = :medium)
56
+ format = size.to_sym == :original ? self.original_format : 'jpg'
57
+ filename = "#{filename}.#{format}"
58
+
59
+ if File.exists?(filename) or not self.url(size)
60
+ false
61
+ else
62
+ f = File.new(filename, 'w+')
63
+ f.puts open(self.url(size)).read
64
+ f.close
65
+ true
66
+ end
67
+ end
68
+
69
+ # Add tags to a photo.
70
+ #
71
+ # Params
72
+ # * tags (Required)
73
+ # comma seperated list of tags
74
+ #
75
+ def add_tags(tags)
76
+ rsp = @flickr.send_request('flickr.photos.addTags', {:photo_id => self.id, :tags => tags}, :post)
77
+ true
78
+ end
79
+
80
+ # Add comment to a photo as the currently authenticated user.
81
+ #
82
+ # Params
83
+ # * message (Required)
84
+ # text of the comment
85
+ #
86
+ def add_comment(message)
87
+ rsp = @flickr.send_request('flickr.photos.comments.addComment', {:photo_id => self.id, :comment_text => message}, :post)
88
+ true
89
+ end
90
+
91
+ # Add a note to a photo. Coordinates and sizes are in pixels, based on the 500px image size shown on individual photo pages.
92
+ #
93
+ # Params
94
+ # * message (Required)
95
+ # The text of the note
96
+ # * x (Required)
97
+ # The left coordinate of the note
98
+ # * y (Required)
99
+ # The top coordinate of the note
100
+ # * w (Required)
101
+ # The width of the note
102
+ # * h (Required)
103
+ # The height of the note
104
+ #
105
+ 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)
107
+ true
108
+ end
109
+
110
+ def description # :nodoc:
111
+ attach_info
112
+ @description
113
+ end
114
+
115
+ def original_secret # :nodoc:
116
+ attach_info
117
+ @original_secret
118
+ end
119
+
120
+ def owner_username # :nodoc:
121
+ attach_info
122
+ @owner_username
123
+ end
124
+
125
+ def owner_realname # :nodoc:
126
+ attach_info
127
+ @owner_realname
128
+ end
129
+
130
+ def url_photopage # :nodoc:
131
+ attach_info
132
+ @url_photopage
133
+ end
134
+
135
+ def comments # :nodoc:
136
+ attach_comments
137
+ @comments
138
+ end
139
+
140
+ def sizes # :nodoc:
141
+ attach_sizes
142
+ @sizes
143
+ end
144
+
145
+ def notes # :nodoc:
146
+ attach_info
147
+ @notes
148
+ end
149
+
150
+ protected
151
+ def url_square # :nodoc:
152
+ attach_sizes
153
+ @url_square
154
+ end
155
+
156
+ def url_thumbnail # :nodoc:
157
+ attach_sizes
158
+ @url_thumbnail
159
+ end
160
+
161
+ def url_small # :nodoc:
162
+ attach_sizes
163
+ @url_small
164
+ end
165
+
166
+ def url_medium # :nodoc:
167
+ attach_sizes
168
+ @url_medium
169
+ end
170
+
171
+ def url_large # :nodoc:
172
+ attach_sizes
173
+ @url_large
174
+ end
175
+
176
+ def url_original # :nodoc:
177
+ attach_sizes
178
+ @url_original
179
+ end
180
+
181
+ private
182
+ attr_accessor :comment_count
183
+
184
+ # convert the size to the key used in the flickr url
185
+ def size_key(size)
186
+ case size.to_sym
187
+ when :square : 's'
188
+ when :thumb, :thumbnail : 't'
189
+ when :small : 'm'
190
+ when :medium : '-'
191
+ when :large : 'b'
192
+ when :original : 'o'
193
+ else ''
194
+ end
195
+ end
196
+
197
+ # loads photo info when a field is requested that requires additional info
198
+ def attach_info
199
+ unless self.info_added
200
+ rsp = @flickr.send_request('flickr.photos.getInfo', :photo_id => self.id, :secret => self.secret)
201
+
202
+ self.info_added = true
203
+ self.description = rsp.photo.description.to_s
204
+ self.original_secret = rsp.photo[:originalsecret]
205
+ self.owner_username = rsp.photo.owner[:username]
206
+ self.owner_realname = rsp.photo.owner[:realname]
207
+ self.url_photopage = rsp.photo.urls.url.to_s
208
+ self.comment_count = rsp.photo.comments.to_s.to_i
209
+
210
+ self.notes = []
211
+
212
+ rsp.photo.notes.note.each do |note|
213
+ self.notes << Flickr::Photos::Note.new(:id => note[:id],
214
+ :note => note.to_s,
215
+ :author => note[:author],
216
+ :author_name => note[:authorname],
217
+ :x => note[:x],
218
+ :y => note[:y],
219
+ :width => note[:w],
220
+ :height => note[:h])
221
+ end if rsp.photo.notes.note
222
+ end
223
+ end
224
+
225
+ # loads picture sizes only after one has been requested
226
+ def attach_sizes
227
+ unless self.sizes_added
228
+ rsp = @flickr.send_request('flickr.photos.getSizes', :photo_id => self.id)
229
+
230
+ self.sizes_added = true
231
+ self.sizes = []
232
+
233
+ rsp.sizes.size.each do |size|
234
+ send("url_#{size[:label].downcase}=", size[:source])
235
+
236
+ self.sizes << Flickr::Photos::Size.new(:label => size[:label],
237
+ :width => size[:width],
238
+ :height => size[:height],
239
+ :source => size[:source],
240
+ :url => size[:url])
241
+ end
242
+ end
243
+ end
244
+
245
+ # loads comments once they have been requested
246
+ def attach_comments
247
+ if @comment_count == 0
248
+ self.comments = []
249
+ self.comments_added = true
250
+ elsif not self.comments_added
251
+ rsp = @flickr.send_request('flickr.photos.comments.getList', :photo_id => self.id)
252
+
253
+ self.comments = []
254
+ self.comments_added = true
255
+
256
+ rsp.comments.comment.each do |comment|
257
+ self.comments << Flickr::Photos::Comment.new(:id => comment[:id],
258
+ :comment => comment.to_s,
259
+ :author => comment[:author],
260
+ :author_name => comment[:authorname],
261
+ :permalink => comment[:permalink],
262
+ :created_at => (Time.at(comment[:datecreate].to_i) rescue nil))
263
+ end
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,37 @@
1
+ # wrapping class to hold a photos response from the flickr api
2
+ #
3
+ class Flickr::Photos::PhotoResponse
4
+ attr_accessor :page, :pages, :per_page, :total, :photos, :api, :method, :options
5
+
6
+ # creates an object to hold the search response.
7
+ #
8
+ # Params
9
+ # * attributes (Required)
10
+ # a hash of attributes used to set the initial values of the response object
11
+ def initialize(attributes)
12
+ attributes.each do |k,v|
13
+ send("#{k}=", v)
14
+ end
15
+ end
16
+
17
+ # Add a Flickr::Photos::Photo object to the photos array. It does nothing if you pass a non photo object
18
+ def <<(photo)
19
+ self.photos ||= []
20
+ self.photos << photo if photo.is_a?(Flickr::Photos::Photo)
21
+ end
22
+
23
+ # gets the next page from flickr if there are anymore pages in the current photos object
24
+ def next_page
25
+ api.send(self.method.split('.').last, options.merge(:page => self.page.to_i + 1)) if self.page.to_i < self.pages.to_i
26
+ end
27
+
28
+ # gets the previous page from flickr if there is a previous page in the current photos object
29
+ def previous_page
30
+ api.send(self.method.split('.').last, options.merge(:page => self.page.to_i - 1)) if self.page.to_i > 1
31
+ end
32
+
33
+ # passes all unknown request to the photos array if it responds to the method
34
+ def method_missing(method, *args, &block)
35
+ self.photos.respond_to?(method) ? self.photos.send(method, *args, &block) : super
36
+ end
37
+ end
@@ -0,0 +1,205 @@
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
+ # * per_page (Optional)
111
+ # Number of photos to return per page. If this argument is omitted, it defaults to 100. The maximum allowed value is 500.
112
+ # * page (Optional)
113
+ # The page of results to return. If this argument is omitted, it defaults to 1.
114
+ #
115
+ def search(options)
116
+ options.merge!({:extras => "license,date_upload,date_taken,owner_name,icon_server,original_format,last_update,geo,tags,machine_tags,o_dims,views"})
117
+
118
+ rsp = @flickr.send_request('flickr.photos.search', options)
119
+
120
+ returning PhotoResponse.new(:page => rsp.photos[:page].to_i,
121
+ :pages => rsp.photos[:pages].to_i,
122
+ :per_page => rsp.photos[:perpage].to_i,
123
+ :total => rsp.photos[:total].to_i,
124
+ :photos => [], :api => self,
125
+ :method => 'flickr.photos.search',
126
+ :options => options) do |photos|
127
+ rsp.photos.photo.each do |photo|
128
+ attributes = {:id => photo[:id],
129
+ :owner => photo[:owner],
130
+ :secret => photo[:secret],
131
+ :server => photo[:server],
132
+ :farm => photo[:farm],
133
+ :title => photo[:title],
134
+ :is_public => photo[:ispublic],
135
+ :is_friend => photo[:isfriend],
136
+ :is_family => photo[:isfamily],
137
+ :license => photo[:license],
138
+ :uploaded_at => (Time.at(photo[:dateupload].to_i) rescue nil),
139
+ :taken_at => (Time.parse(photo[:datetaken]) rescue nil),
140
+ :owner_name => photo[:ownername],
141
+ :icon_server => photo[:icon_server],
142
+ :original_format => photo[:originalformat],
143
+ :updated_at => (Time.at(photo[:lastupdate].to_i) rescue nil),
144
+ :geo => photo[:geo],
145
+ :tags => photo[:tags],
146
+ :machine_tags => photo[:machine_tags],
147
+ :o_dims => photo[:o_dims],
148
+ :views => photo[:views].to_i}
149
+
150
+ photos << Photo.new(@flickr, attributes)
151
+ end if rsp.photos.photo
152
+ end
153
+ end
154
+
155
+ # Returns a list of the latest public photos uploaded to flickr.
156
+ #
157
+ # == Authentication
158
+ # This method does not require authentication.
159
+ #
160
+ # == Options
161
+ # * per_page (Optional)
162
+ # Number of photos to return per page. If this argument is omitted, it defaults to 100. The maximum allowed value is 500.
163
+ # * page (Optional)
164
+ # The page of results to return. If this argument is omitted, it defaults to 1.
165
+ #
166
+ def get_recent(options)
167
+ options.merge!({:extras => "license,date_upload,date_taken,owner_name,icon_server,original_format,last_update,geo,tags,machine_tags,o_dims,views"})
168
+
169
+ rsp = @flickr.send_request('flickr.photos.getRecent', options)
170
+
171
+ returning PhotoResponse.new(:page => rsp.photos[:page].to_i,
172
+ :pages => rsp.photos[:pages].to_i,
173
+ :per_page => rsp.photos[:perpage].to_i,
174
+ :total => rsp.photos[:total].to_i,
175
+ :photos => [], :api => self,
176
+ :method => 'flickr.photos.getRecent',
177
+ :options => options) do |photos|
178
+ rsp.photos.photo.each do |photo|
179
+ attributes = {:id => photo[:id],
180
+ :owner => photo[:owner],
181
+ :secret => photo[:secret],
182
+ :server => photo[:server],
183
+ :farm => photo[:farm],
184
+ :title => photo[:title],
185
+ :is_public => photo[:ispublic],
186
+ :is_friend => photo[:isfriend],
187
+ :is_family => photo[:isfamily],
188
+ :license => photo[:license],
189
+ :uploaded_at => (Time.at(photo[:dateupload].to_i) rescue nil),
190
+ :taken_at => (Time.parse(photo[:datetaken]) rescue nil),
191
+ :owner_name => photo[:ownername],
192
+ :icon_server => photo[:icon_server],
193
+ :original_format => photo[:originalformat],
194
+ :updated_at => (Time.at(photo[:lastupdate].to_i) rescue nil),
195
+ :geo => photo[:geo],
196
+ :tags => photo[:tags],
197
+ :machine_tags => photo[:machine_tags],
198
+ :o_dims => photo[:o_dims],
199
+ :views => photo[:views].to_i}
200
+
201
+ photos << Photo.new(@flickr, attributes)
202
+ end if rsp.photos.photo
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,16 @@
1
+ # wrapping class to hold a flickr size
2
+ #
3
+ class Flickr::Photos::Size
4
+ attr_accessor :label, :width, :height, :source, :url
5
+
6
+ # create a new instance of a flickr size.
7
+ #
8
+ # Params
9
+ # * attributes (Required)
10
+ # a hash of attributes used to set the initial values of the size object
11
+ def initialize(attributes)
12
+ attributes.each do |k,v|
13
+ send("#{k}=", v)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ # wrapping class to hold a flickr size
2
+ #
3
+ class Flickr::Auth::Token
4
+ attr_accessor :token, :permisions, :user_id, :username, :user_real_name
5
+
6
+ # create a new instance of a flickr auth token.
7
+ #
8
+ # Params
9
+ # * attributes (Required)
10
+ # a hash of attributes used to set the initial values of the token object
11
+ def initialize(attributes)
12
+ attributes.each do |k,v|
13
+ send("#{k}=", v)
14
+ end
15
+ end
16
+
17
+ # overide the default to_s to output the text of the token
18
+ #
19
+ def to_s
20
+ self.token.to_s
21
+ end
22
+ end
@@ -0,0 +1,106 @@
1
+ class Flickr::Uploader < Flickr::Base
2
+ def initialize(flickr)
3
+ @flickr = flickr
4
+ end
5
+
6
+ # upload a photo to flickr
7
+ #
8
+ # NOT WORKING ... FILE UPLOADS IN NET::HTTP SUX
9
+ #
10
+ # Params
11
+ # * filename (Required)
12
+ # path to the file to upload
13
+ # * options (Optional)
14
+ # options to attach to the photo (See Below)
15
+ #
16
+ # Options
17
+ # * title (Optional)
18
+ # The title of the photo.
19
+ # * description (Optional)
20
+ # A description of the photo. May contain some limited HTML.
21
+ # * tags (Optional)
22
+ # A space-seperated list of tags to apply to the photo.
23
+ # * privacy (Optional)
24
+ # Specifies who can view the photo. valid valus are:
25
+ # :public
26
+ # :private
27
+ # :friends
28
+ # :family
29
+ # :friends_and_family
30
+ # * safety_level (Optional)
31
+ # sets the safety level of the photo. valid values are:
32
+ # :safe
33
+ # :moderate
34
+ # :restricted
35
+ # * content_type (Optional)
36
+ # tells what type of image you are uploading. valid values are:
37
+ # :photo
38
+ # :screenshot
39
+ # :other
40
+ # * hidden (Optional)
41
+ # boolean that determines if the photo shows up in global searches
42
+ #
43
+ def upload(filename, options = {})
44
+ photo = File.new(filename, 'r').read
45
+ mimetype = MIME::Types.of(filename)
46
+
47
+ upload_options = {}
48
+ @flickr.sign_request(upload_options)
49
+
50
+ form = Flickr::Uploader::MultiPartForm.new
51
+
52
+ upload_options.each do |k,v|
53
+ form.parts << Flickr::Uploader::FormPart.new(k.to_s, v.to_s)
54
+ end
55
+
56
+ form.parts << Flickr::Uploader::FormPart.new('photo', photo, mimetype, filename)
57
+
58
+ headers = {"Content-Type" => "multipart/form-data; boundary=" + form.boundary}
59
+
60
+ rsp = Net::HTTP.start('api.flickr.com').post("/services/upload/", form.to_s, headers).body
61
+
62
+ xm = XmlMagic.new(rsp)
63
+
64
+ if xm[:stat] == 'ok'
65
+ xm
66
+ else
67
+ raise "#{xm.err[:code]}: #{xm.err[:msg]}"
68
+ end
69
+ end
70
+ end
71
+
72
+ class Flickr::Uploader::FormPart
73
+ attr_reader :data, :mime_type, :attributes, :filename
74
+
75
+ def initialize(name, data, mime_type = nil, filename = nil)
76
+ @attributes = {}
77
+ @attributes['name'] = name
78
+ @data = data
79
+ @mime_type = mime_type
80
+ @filename = filename
81
+ end
82
+
83
+ def to_s
84
+ ([ "Content-Disposition: form-data" ] +
85
+ attributes.map{|k,v| "#{k}=\"#{v}\""}).
86
+ join('; ') + "\r\n"+
87
+ (@mime_type ? "Content-Type: #{@mime_type}\r\n" : '')+
88
+ "\r\n#{data}"
89
+ end
90
+ end
91
+
92
+ class Flickr::Uploader::MultiPartForm
93
+ attr_accessor :boundary, :parts
94
+
95
+ def initialize(boundary=nil)
96
+ @boundary = boundary ||
97
+ "----------------------------Ruby#{rand(1000000000000)}"
98
+ @parts = []
99
+ end
100
+
101
+ def to_s
102
+ "--#@boundary\r\n"+
103
+ parts.map{|p| p.to_s}.join("\r\n--#@boundary\r\n")+
104
+ "\r\n--#@boundary--\r\n"
105
+ end
106
+ end
data/lib/flickr_fu.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'xml_magic'
3
+ require 'net/http'
4
+ require 'cgi'
5
+ require 'uri'
6
+ require 'mime/types'
7
+ require 'digest/md5'
8
+ require 'yaml'
9
+
10
+ # base must load first
11
+ %w(base auth token photos photo photo_response comment note size uploader).each do |file|
12
+ require File.join(File.dirname(__FILE__), 'flickr', file)
13
+ end
14
+
15
+ include CommonThread::XML
16
+
17
+ class Object
18
+ # returning allows you to pass an object to a block that you can manipulate returning the manipulated object
19
+ def returning(value)
20
+ yield(value)
21
+ value
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flickr-fu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Ben Wyrosdick
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-04-09 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: xml-magic
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ description:
25
+ email: ben@commonthread.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - lib/flickr
34
+ - lib/flickr/auth.rb
35
+ - lib/flickr/base.rb
36
+ - lib/flickr/comment.rb
37
+ - lib/flickr/note.rb
38
+ - lib/flickr/photo.rb
39
+ - lib/flickr/photo_response.rb
40
+ - lib/flickr/photos.rb
41
+ - lib/flickr/size.rb
42
+ - lib/flickr/token.rb
43
+ - lib/flickr/uploader.rb
44
+ - lib/flickr_fu.rb
45
+ has_rdoc: true
46
+ homepage: http://www.commonthread.com/projects/flickr-fu/rdoc
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project: flickr-fu
67
+ rubygems_version: 1.0.1
68
+ signing_key:
69
+ specification_version: 2
70
+ summary: Provides a ruby interface to flickr via the REST api
71
+ test_files: []
72
+