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