tomk32-flickr_fu 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/.gitignore +13 -0
  2. data/LICENSE +22 -0
  3. data/README +182 -0
  4. data/Rakefile +73 -0
  5. data/VERSION.yml +4 -0
  6. data/lib/flickr/auth.rb +76 -0
  7. data/lib/flickr/base.rb +151 -0
  8. data/lib/flickr/comment.rb +16 -0
  9. data/lib/flickr/contact.rb +16 -0
  10. data/lib/flickr/contacts.rb +55 -0
  11. data/lib/flickr/errors.rb +20 -0
  12. data/lib/flickr/geo.rb +42 -0
  13. data/lib/flickr/license.rb +24 -0
  14. data/lib/flickr/location.rb +15 -0
  15. data/lib/flickr/note.rb +16 -0
  16. data/lib/flickr/people.rb +54 -0
  17. data/lib/flickr/person.rb +82 -0
  18. data/lib/flickr/photo.rb +333 -0
  19. data/lib/flickr/photo_response.rb +37 -0
  20. data/lib/flickr/photos.rb +277 -0
  21. data/lib/flickr/photoset.rb +37 -0
  22. data/lib/flickr/photosets.rb +39 -0
  23. data/lib/flickr/size.rb +16 -0
  24. data/lib/flickr/status.rb +19 -0
  25. data/lib/flickr/test.rb +31 -0
  26. data/lib/flickr/token.rb +22 -0
  27. data/lib/flickr/uploader.rb +162 -0
  28. data/lib/flickr/urls.rb +44 -0
  29. data/lib/flickr_fu.rb +51 -0
  30. data/spec/fixtures/flickr/contacts/get_list-fail-99.xml +4 -0
  31. data/spec/fixtures/flickr/contacts/get_public_list-0.xml +7 -0
  32. data/spec/fixtures/flickr/photos/geo/get_location-0.xml +11 -0
  33. data/spec/fixtures/flickr/photos/geo/get_location-fail-2.xml +4 -0
  34. data/spec/fixtures/flickr/photos/get_info-0.xml +41 -0
  35. data/spec/fixtures/flickr/photos/get_info-1.xml +19 -0
  36. data/spec/fixtures/flickr/photos/get_sizes-0.xml +10 -0
  37. data/spec/fixtures/flickr/photos/get_sizes-1.xml +8 -0
  38. data/spec/fixtures/flickr/photos/licenses/get_info.xml +12 -0
  39. data/spec/fixtures/flickr/photosets/get_list-0.xml +13 -0
  40. data/spec/fixtures/flickr/photosets/get_photos-0.xml +7 -0
  41. data/spec/fixtures/flickr/test/echo-0.xml +5 -0
  42. data/spec/fixtures/flickr/test/null-fail-99.xml +4 -0
  43. data/spec/fixtures/flickr/urls/get_group-0.xml +4 -0
  44. data/spec/fixtures/flickr/urls/get_group-fail-1.xml +4 -0
  45. data/spec/fixtures/flickr/urls/get_user_photos-0.xml +4 -0
  46. data/spec/fixtures/flickr/urls/get_user_photos-fail-1.xml +4 -0
  47. data/spec/fixtures/flickr/urls/get_user_photos-fail-2.xml +4 -0
  48. data/spec/fixtures/flickr/urls/get_user_profile-0.xml +4 -0
  49. data/spec/fixtures/flickr/urls/get_user_profile-fail-1.xml +4 -0
  50. data/spec/fixtures/flickr/urls/get_user_profile-fail-2.xml +4 -0
  51. data/spec/fixtures/flickr/urls/lookup_group-0.xml +6 -0
  52. data/spec/fixtures/flickr/urls/lookup_group-fail-1.xml +4 -0
  53. data/spec/fixtures/flickr/urls/lookup_user-0.xml +6 -0
  54. data/spec/fixtures/flickr/videos/get_info-0.xml +31 -0
  55. data/spec/fixtures/flickr/videos/get_sizes-0.xml +13 -0
  56. data/spec/flickr/base_spec.rb +97 -0
  57. data/spec/flickr/contacts_spec.rb +47 -0
  58. data/spec/flickr/errors_spec.rb +21 -0
  59. data/spec/flickr/geo_spec.rb +20 -0
  60. data/spec/flickr/photo_spec.rb +140 -0
  61. data/spec/flickr/photos_spec.rb +50 -0
  62. data/spec/flickr/photosets_spec.rb +49 -0
  63. data/spec/flickr/test_spec.rb +34 -0
  64. data/spec/flickr/urls_spec.rb +99 -0
  65. data/spec/spec.opts +4 -0
  66. data/spec/spec_helper.rb +20 -0
  67. data/tomk32-flickr_fu.gemspec +121 -0
  68. metadata +151 -0
@@ -0,0 +1,277 @@
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
+ # * media (Optional)
115
+ # The type of media to search for. 'photo', 'video', or 'both' are allowed arguments, with 'both' being the default.
116
+ #
117
+ def search(options)
118
+ options.merge!({:extras => "license,date_upload,date_taken,owner_name,icon_server,original_format,last_update,geo,tags,machine_tags,o_dims,views,media"})
119
+
120
+ rsp = @flickr.send_request('flickr.photos.search', options)
121
+
122
+ returning PhotoResponse.new(:page => rsp.photos[:page].to_i,
123
+ :pages => rsp.photos[:pages].to_i,
124
+ :per_page => rsp.photos[:perpage].to_i,
125
+ :total => rsp.photos[:total].to_i,
126
+ :photos => [],
127
+ :api => self,
128
+ :method => 'search',
129
+ :options => options) do |photos|
130
+ rsp.photos.photo.each do |photo|
131
+ attributes = create_attributes(photo)
132
+
133
+ photos << Photo.new(@flickr, attributes)
134
+ end if rsp.photos.photo
135
+ end
136
+ end
137
+
138
+ # Returns a list of the latest public photos uploaded to flickr.
139
+ #
140
+ # == Authentication
141
+ # This method does not require authentication.
142
+ #
143
+ # == Options
144
+ # * per_page (Optional)
145
+ # Number of photos to return per page. If this argument is omitted, it defaults to 100. The maximum allowed value is 500.
146
+ # * page (Optional)
147
+ # The page of results to return. If this argument is omitted, it defaults to 1.
148
+ # * media (Optional)
149
+ # The type of media to search for. 'photo', 'video', or 'both' are allowed arguments, with 'both' being the default.
150
+ #
151
+ def get_recent(options = {})
152
+ options.merge!({:extras => "license,date_upload,date_taken,owner_name,icon_server,original_format,last_update,geo,tags,machine_tags,o_dims,views,media"})
153
+
154
+ rsp = @flickr.send_request('flickr.photos.getRecent', options)
155
+
156
+ returning PhotoResponse.new(:page => rsp.photos[:page].to_i,
157
+ :pages => rsp.photos[:pages].to_i,
158
+ :per_page => rsp.photos[:perpage].to_i,
159
+ :total => rsp.photos[:total].to_i,
160
+ :photos => [], :api => self,
161
+ :method => 'flickr.photos.getRecent',
162
+ :options => options) do |photos|
163
+ rsp.photos.photo.each do |photo|
164
+ attributes = create_attributes(photo)
165
+
166
+ photos << Photo.new(@flickr, attributes)
167
+ end if rsp.photos.photo
168
+ end
169
+ end
170
+
171
+ def interesting(options)
172
+ options.merge!({:extras => "license,date_upload,date_taken,owner_name,icon_server,original_format,last_update,geo,tags,machine_tags,o_dims,views,media"})
173
+
174
+ rsp = @flickr.send_request('flickr.interestingness.getList', options)
175
+
176
+ returning PhotoResponse.new(:page => rsp.photos[:page].to_i,
177
+ :pages => rsp.photos[:pages].to_i,
178
+ :per_page => rsp.photos[:perpage].to_i,
179
+ :total => rsp.photos[:total].to_i,
180
+ :photos => [],
181
+ :api => self,
182
+ :method => 'flickr.interestingness.getList',
183
+ :options => options) do |photos|
184
+ rsp.photos.photo.each do |photo|
185
+ attributes = create_attributes(photo)
186
+
187
+
188
+ photos << Photo.new(@flickr, attributes)
189
+ end if rsp.photos.photo
190
+ end
191
+ end
192
+
193
+ def licenses
194
+ @licenses ||= begin
195
+ rsp = @flickr.send_request('flickr.photos.licenses.getInfo')
196
+
197
+ returning Hash.new do |licenses|
198
+ rsp.licenses.license.each do |license|
199
+ licenses[license[:id].to_i] = Flickr::Photos::License.new(:id => license[:id].to_i, :name => license[:name], :url => license[:url])
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ # creates and/or returns the Flickr::Photos::Geo object
206
+ def geo
207
+ @geo ||= Flickr::Photos::Geo.new(@flickr)
208
+ end
209
+
210
+ # Returns a Flickr::Photos::Photo object of the given id.
211
+ # Raises an error if photo not found
212
+ def find_by_id(photo_id)
213
+ rsp = @flickr.send_request('flickr.photos.getInfo', :photo_id => photo_id)
214
+
215
+ tags = []
216
+ machine_tags = []
217
+
218
+ if rsp.photo.tags.tag
219
+ rsp.photo.tags.tag.each do |tag|
220
+ if tag[:machine_tag] == '1'
221
+ machine_tags << tag[:raw]
222
+ else
223
+ tags << tag[:raw]
224
+ end
225
+ end
226
+ end
227
+
228
+ Photo.new(@flickr,
229
+ :id => rsp.photo[:id].to_i,
230
+ :owner => rsp.photo.owner,
231
+ :secret => rsp.photo[:secret],
232
+ :server => rsp.photo[:server].to_i,
233
+ :farm => rsp.photo[:farm],
234
+ :title => rsp.photo.title.to_s,
235
+ :is_public => rsp.photo.visibility[:ispublic],
236
+ :is_friend => rsp.photo.visibility[:isfriend],
237
+ :is_family => rsp.photo.visibility[:isfamily],
238
+ :license_id => rsp.photo[:license].to_i,
239
+ :uploaded_at => (Time.at(rsp.photo[:dateuploaded].to_i) rescue nil),
240
+ :taken_at => (Time.parse(rsp.photo.dates[:taken]) rescue nil),
241
+ :owner_name => rsp.photo.owner[:username],
242
+ :icon_server => rsp.photo[:icon_server],
243
+ :original_format => rsp.photo[:originalformat],
244
+ :updated_at => (Time.at(rsp.photo.dates[:lastupdate].to_i) rescue nil),
245
+ :tags => tags,
246
+ :machine_tags => machine_tags,
247
+ :views => rsp.photo[:views].to_i,
248
+ :media => rsp.photo[:media])
249
+ end
250
+
251
+ protected
252
+ def create_attributes(photo)
253
+ {:id => photo[:id],
254
+ :owner => photo[:owner],
255
+ :secret => photo[:secret],
256
+ :server => photo[:server],
257
+ :farm => photo[:farm],
258
+ :title => photo[:title],
259
+ :is_public => photo[:ispublic],
260
+ :is_friend => photo[:isfriend],
261
+ :is_family => photo[:isfamily],
262
+ :license_id => photo[:license].to_i,
263
+ :uploaded_at => (Time.at(photo[:dateupload].to_i) rescue nil),
264
+ :taken_at => (Time.parse(photo[:datetaken]) rescue nil),
265
+ :owner_name => photo[:ownername],
266
+ :icon_server => photo[:icon_server],
267
+ :original_format => photo[:originalformat],
268
+ :updated_at => (Time.at(photo[:lastupdate].to_i) rescue nil),
269
+ :geo => photo[:geo],
270
+ :tags => photo[:tags],
271
+ :machine_tags => photo[:machine_tags],
272
+ :o_dims => photo[:o_dims],
273
+ :views => photo[:views].to_i,
274
+ :media => photo[:media]}
275
+ end
276
+
277
+ end
@@ -0,0 +1,37 @@
1
+ class Flickr::Photosets::Photoset
2
+ attr_accessor :id,:num_photos,:title,:description
3
+
4
+ def initialize(flickr, attributes)
5
+ @flickr = flickr
6
+ attributes.each do |k,v|
7
+ send("#{k}=", v)
8
+ end
9
+ end
10
+
11
+ def get_photos(options={})
12
+ options = options.merge(:photoset_id=>id)
13
+ rsp = @flickr.send_request('flickr.photosets.getPhotos', options)
14
+ collect_photos(rsp)
15
+ end
16
+
17
+ protected
18
+ def collect_photos(rsp)
19
+ photos = []
20
+ return photos unless rsp
21
+ if rsp.photoset.photo
22
+ rsp.photoset.photo.each do |photo|
23
+ attributes = create_attributes(photo)
24
+ photos << Flickr::Photos::Photo.new(@flickr,attributes)
25
+ end
26
+ end
27
+ return photos
28
+ end
29
+
30
+ def create_attributes(photo)
31
+ {:id => photo[:id],
32
+ :secret => photo[:secret],
33
+ :server => photo[:server],
34
+ :farm => photo[:farm],
35
+ :title => photo[:title]}
36
+ end
37
+ end
@@ -0,0 +1,39 @@
1
+ class Flickr::Photosets < Flickr::Base
2
+ def initialize(flickr)
3
+ @flickr = flickr
4
+ end
5
+
6
+ # Get the authorized user's contact list.
7
+ #
8
+ def get_list(options={})
9
+ rsp = @flickr.send_request('flickr.photosets.getList', options)
10
+ collect_photosets(rsp)
11
+ end
12
+
13
+ protected
14
+ def collect_photosets(rsp)
15
+ photosets = []
16
+ return photosets unless rsp
17
+ if rsp.photosets.photoset
18
+ rsp.photosets.photoset.each do |photoset|
19
+ attributes = create_attributes(photoset)
20
+ photosets << Photoset.new(@flickr, attributes)
21
+ end
22
+ end
23
+ return photosets
24
+ end
25
+
26
+ def create_attributes(photoset)
27
+ # comment by : smeevil
28
+ #
29
+ # for some reason it was needed to call to_s on photoset.title and photoset.description
30
+ # without this it will not set the value correctly
31
+ {
32
+ :id => photoset[:id],
33
+ :num_photos => photoset[:photos],
34
+ :title => photoset.title.to_s,
35
+ :description => photoset.description.to_s
36
+ }
37
+ end
38
+
39
+ 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,19 @@
1
+ # wrapper class to hold a flickr upload status object.
2
+ #
3
+ class Flickr::Uploader::Status
4
+ attr_accessor :nsid, :is_pro, :username, :max_bandwidth, :used_bandwidth, :remaining_bandwidth, :max_filesize, :max_videosize, :sets_created, :sets_remaining
5
+
6
+ # create a new instance of a flickr upload status object.
7
+ #
8
+ # Params
9
+ # * flickr (Required)
10
+ # the flickr object
11
+ # * attributes (Required)
12
+ # a hash of attributes used to set the initial values of the status object
13
+ def initialize(flickr, attributes)
14
+ @flickr = flickr
15
+ attributes.each do |k,v|
16
+ send("#{k}=", v)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ class Flickr::Test
2
+ def initialize(flickr)
3
+ @flickr = flickr
4
+ end
5
+
6
+ # A testing method which checks if the caller is logged in then returns their username.
7
+ #
8
+ def login
9
+ rsp = @flickr.send_request('flickr.test.login')
10
+ rsp.user.username.to_s
11
+ end
12
+
13
+ # A testing method which echo's all parameters back in the response.
14
+ #
15
+ # pass any number of options as a hash and it will be returned
16
+ #
17
+ def echo(options = {})
18
+ rsp = @flickr.send_request('flickr.test.echo', options)
19
+
20
+ options
21
+ end
22
+
23
+ # Null test
24
+ #
25
+ # Returns true unless there is an error
26
+ #
27
+ def null
28
+ rsp = @flickr.send_request('flickr.test.null')
29
+ true
30
+ end
31
+ 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) if respond_to?("#{k}=")
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,162 @@
1
+ class Flickr::Uploader < Flickr::Base
2
+ def initialize(flickr)
3
+ @flickr = flickr
4
+ end
5
+
6
+ # upload a photo to flickr
7
+ #
8
+ # Params
9
+ # * filename (Required)
10
+ # path to the file to upload
11
+ # * options (Optional)
12
+ # options to attach to the photo (See Below)
13
+ #
14
+ # Options
15
+ # * title (Optional)
16
+ # The title of the photo.
17
+ # * description (Optional)
18
+ # A description of the photo. May contain some limited HTML.
19
+ # * tags (Optional)
20
+ # A space-seperated list of tags to apply to the photo.
21
+ # * privacy (Optional)
22
+ # Specifies who can view the photo. valid valus are:
23
+ # :public
24
+ # :private
25
+ # :friends
26
+ # :family
27
+ # :friends_and_family
28
+ # * safety_level (Optional)
29
+ # sets the safety level of the photo. valid values are:
30
+ # :safe
31
+ # :moderate
32
+ # :restricted
33
+ # * content_type (Optional)
34
+ # tells what type of image you are uploading. valid values are:
35
+ # :photo
36
+ # :screenshot
37
+ # :other
38
+ # * hidden (Optional)
39
+ # boolean that determines if the photo shows up in global searches
40
+ #
41
+ def upload(filename, options = {})
42
+ upload_data(File.new(filename, 'rb').read, MIME::Types.of(filename), options.merge(:filename => filename))
43
+ end
44
+
45
+ # upload a photo to flickr
46
+ #
47
+ # Params
48
+ # * photo (Required)
49
+ # image stored in a variable
50
+ # * mimetype (Required)
51
+ # mime type of the image
52
+ # * options (Optional)
53
+ # see upload method
54
+ #
55
+ def upload_data(photo, mimetype, options = {})
56
+ filename = options.delete(:filename) || Time.now.to_s
57
+ options = upload_options(options)
58
+ @flickr.sign_request(options)
59
+
60
+ form = Flickr::Uploader::MultiPartForm.new
61
+
62
+ options.each do |k,v|
63
+ form.parts << Flickr::Uploader::FormPart.new(k.to_s, v.to_s)
64
+ end
65
+
66
+ form.parts << Flickr::Uploader::FormPart.new('photo', photo, mimetype, filename)
67
+
68
+ headers = {"Content-Type" => "multipart/form-data; boundary=" + form.boundary}
69
+
70
+ rsp = Net::HTTP.start('api.flickr.com').post("/services/upload/", form.to_s, headers).body
71
+
72
+ xm = XmlMagic.new(rsp)
73
+
74
+ if xm[:stat] == 'ok'
75
+ xm
76
+ else
77
+ raise "#{xm.err[:code]}: #{xm.err[:msg]}"
78
+ end
79
+ end
80
+
81
+ # Returns information for the calling user related to photo uploads.
82
+ #
83
+ # * Bandwidth and filesize numbers are provided in bytes.
84
+ # * Bandwidth is specified in bytes per month.
85
+ # * Pro accounts display 99 for the number of remaining sets, since they have unlimited sets. Free accounts will display either 3, 2, 1, or 0.
86
+ #
87
+ def status
88
+ rsp = @flickr.send_request('flickr.people.getUploadStatus')
89
+
90
+ Flickr::Uploader::Status.new(@flickr, :nsid => rsp.user[:id],
91
+ :is_pro => (rsp.user[:ispro] == "1" ? true : false),
92
+ :username => rsp.user.username.to_s,
93
+ :max_bandwidth => rsp.user.bandwidth[:maxbytes],
94
+ :used_bandwidth => rsp.user.bandwidth[:usedbytes],
95
+ :remaining_bandwidth => rsp.user.bandwidth[:remainingbytes],
96
+ :max_filesize => rsp.user.filesize[:maxbytes],
97
+ :max_videosize => rsp.user.videosize[:maxbytes],
98
+ :sets_created => rsp.user.sets[:created].to_i,
99
+ :sets_remaining => (rsp.user[:ispro] == "1" ? 99 : rsp.user.sets[:remaining].to_i))
100
+ end
101
+
102
+ protected
103
+
104
+ def upload_options(options)
105
+ upload_options = { :api_key => @flickr.api_key }
106
+ upload_options.merge!({:title => options[:title], :description => options[:description], :tags => options[:tags]})
107
+ [ :is_public, :is_friend, :is_family, :async ].each { |key| upload_options[key] = options[key] ? '1' : '0' }
108
+
109
+ upload_options[:safety_level] = case options[:safety_level]
110
+ when :safe then '1'
111
+ when :moderate then '2'
112
+ when :restricted then '3'
113
+ end if options.has_key?(:safety_level)
114
+
115
+ upload_options[:content_type] = case options[:content_type]
116
+ when :photo then '1'
117
+ when :screenshot then '2'
118
+ when :other then '3'
119
+ end if options.has_key?(:content_type)
120
+
121
+ upload_options[:hidden] = options.has_key?(:hidden) ? '2' : '1'
122
+ upload_options
123
+ end
124
+ end
125
+
126
+
127
+ class Flickr::Uploader::FormPart
128
+ attr_reader :data, :mime_type, :attributes, :filename
129
+
130
+ def initialize(name, data, mime_type = nil, filename = nil)
131
+ @attributes = {}
132
+ @attributes['name'] = name
133
+ @attributes['filename'] = filename if filename
134
+ @data = data
135
+ @mime_type = mime_type
136
+ @filename = filename
137
+ end
138
+
139
+ def to_s
140
+ ([ "Content-Disposition: form-data" ] +
141
+ attributes.map{|k,v| "#{k}=\"#{v}\""}).
142
+ join('; ') + "\r\n"+
143
+ (@mime_type ? "Content-Type: #{@mime_type}\r\n" : '')+
144
+ "\r\n#{data}"
145
+ end
146
+ end
147
+
148
+
149
+ class Flickr::Uploader::MultiPartForm
150
+ attr_accessor :boundary, :parts
151
+
152
+ def initialize(boundary=nil)
153
+ @boundary = boundary || "----------------------------Ruby#{rand(1000000000000)}"
154
+ @parts = []
155
+ end
156
+
157
+ def to_s
158
+ "--#@boundary\r\n" +
159
+ parts.map{|p| p.to_s}.join("\r\n--#@boundary\r\n")+
160
+ "\r\n--#@boundary--\r\n"
161
+ end
162
+ end
@@ -0,0 +1,44 @@
1
+ # Wrapping class that holds methods in the flickr.urls namespace
2
+ class Flickr::Urls < Flickr::Base
3
+ def initialize(flickr)
4
+ @flickr = flickr
5
+ end
6
+
7
+ def get_group group_id
8
+ rsp = @flickr.send_request('flickr.urls.getGroup', {:group_id => group_id})
9
+ rsp.group[:url]
10
+ end
11
+
12
+ def get_user_photos user_id
13
+ rsp = @flickr.send_request('flickr.urls.getUserPhotos', {:user_id => user_id})
14
+ rsp.user[:url]
15
+ end
16
+
17
+ def get_user_profile user_id
18
+ rsp = @flickr.send_request('flickr.urls.getUserProfile', {:user_id => user_id})
19
+ rsp.user[:url]
20
+ end
21
+
22
+ def lookup_group url #, options = {}
23
+ #options.symbolize_keys!
24
+ #options.reverse_merge!({:include_groupname => false})
25
+ rsp = @flickr.send_request('flickr.urls.lookupGroup', {:url => url})
26
+ #if options[:include_groupname]
27
+ #[rsp.group[:id], {:groupname => rsp.group.groupname}]
28
+ #else
29
+ rsp.group[:id]
30
+ #end
31
+ end
32
+
33
+ def lookup_user url
34
+ rsp = @flickr.send_request('flickr.urls.lookupUser', {:url => url})
35
+ user_id = UserLookupResult.new(rsp.user[:id])
36
+ user_id.username = rsp.user.username
37
+ user_id
38
+ end
39
+
40
+ class UserLookupResult < String
41
+ attr_accessor :username
42
+ end
43
+
44
+ end