tomk32-flickr_fu 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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