net-flickr 0.0.1

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,65 @@
1
+ #--
2
+ # Copyright (c) 2007-2008 Ryan Grove <ryan@wonko.com>
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of this project nor the names of its contributors may be
14
+ # used to endorse or promote products derived from this software without
15
+ # specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #++
28
+
29
+ module Net; class Flickr
30
+
31
+ class People
32
+
33
+ def initialize(flickr)
34
+ @flickr = flickr
35
+ end
36
+
37
+ #--
38
+ # Public Instance Methods
39
+ #++
40
+
41
+ # Looks up a Flickr user based on their email address.
42
+ #
43
+ # See http://flickr.com/services/api/flickr.people.findByEmail.html for
44
+ # details.
45
+ def find_by_email(email, args = {})
46
+ args['find_email'] = email
47
+ response = @flickr.request('flickr.people.findByEmail', args)
48
+
49
+ return Person.new(@flickr, response.at('user'))
50
+ end
51
+
52
+ # Looks up a Flickr user based on their username.
53
+ #
54
+ # See http://flickr.com/services/api/flickr.people.findByUsername.html for
55
+ # details.
56
+ def find_by_username(username, args = {})
57
+ args['username'] = username
58
+ response = @flickr.request('flickr.people.findByUsername', args)
59
+
60
+ return Person.new(@flickr, response.at('user'))
61
+ end
62
+
63
+ end
64
+
65
+ end; end
@@ -0,0 +1,251 @@
1
+ #--
2
+ # Copyright (c) 2007-2008 Ryan Grove <ryan@wonko.com>
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of this project nor the names of its contributors may be
14
+ # used to endorse or promote products derived from this software without
15
+ # specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #++
28
+
29
+ module Net; class Flickr
30
+
31
+ class Person
32
+
33
+ attr_reader :id, :username
34
+
35
+ def initialize(flickr, person_xml)
36
+ @flickr = flickr
37
+
38
+ @id = person_xml['nsid']
39
+ @username = person_xml.at('username').inner_text
40
+ @infoxml = nil
41
+ end
42
+
43
+ #--
44
+ # Public Instance Methods
45
+ #++
46
+
47
+ # +true+ if this person is a Flickr admin, +false+ otherwise.
48
+ def admin?
49
+ infoxml = get_info
50
+ return infoxml['isadmin'] == '1'
51
+ end
52
+
53
+ # +true+ if this person is a contact of the calling user, +false+ otherwise.
54
+ # This method requires authentication with +read+ permission. In all other
55
+ # cases, it returns +false+.
56
+ def contact?
57
+ infoxml = get_info
58
+
59
+ if contact = infoxml['contact']
60
+ return contact == '1'
61
+ end
62
+
63
+ return false
64
+ end
65
+
66
+ # +true+ if this person is a family member of the calling user, +false+
67
+ # otherwise. This method requires authentication with +read+ permission. In
68
+ # all other cases, it returns +false+.
69
+ def family?
70
+ infoxml = get_info
71
+
72
+ if family = infoxml['family']
73
+ return family == '1'
74
+ end
75
+
76
+ return false
77
+ end
78
+
79
+ # +true+ if this person is a friend of the calling user, +false+ otherwise.
80
+ # This method requires authentication with +read+ permission. In all other
81
+ # cases, it returns +false+.
82
+ def friend?
83
+ infoxml = get_info
84
+
85
+ if friend = infoxml['friend']
86
+ return friend == '1'
87
+ end
88
+
89
+ return false
90
+ end
91
+
92
+ # Gets this person's gender (e.g., 'M'). This method requires authentication
93
+ # with +read+ permission and only returns information for contacts of the
94
+ # calling user. In all other cases, it returns +nil+.
95
+ def gender
96
+ infoxml = get_info
97
+ return infoxml['gender']
98
+ end
99
+
100
+ # TODO: Implement Flickr.person.groups
101
+ def groups
102
+ end
103
+
104
+ # Gets the URL of this person's buddy icon.
105
+ def icon_url
106
+ infoxml = get_info
107
+
108
+ icon_server = infoxml['iconserver']
109
+ icon_farm = infoxml['iconfarm']
110
+
111
+ if icon_server.to_i <= 0
112
+ return 'http://www.flickr.com/images/buddyicon.jpg'
113
+ else
114
+ return "http://farm#{icon_farm}.static.flickr.com/#{icon_server}/buddyicons/#{@id}.jpg"
115
+ end
116
+ end
117
+
118
+ # +true+ if this person is an ignored contact of the calling user, +false+
119
+ # otherwise. This method requires authentication with +read+ permission and
120
+ # only returns information for contacts of the calling user. In all other
121
+ # cases, it returns +false+.
122
+ def ignored?
123
+ infoxml = get_info
124
+
125
+ if ignored = infoxml['ignored']
126
+ return ignored == '1'
127
+ end
128
+
129
+ return false
130
+ end
131
+
132
+ # Gets this person's location.
133
+ def location
134
+ infoxml = get_info
135
+ return infoxml.at('location').inner_text
136
+ end
137
+
138
+ # Gets the mobile URL of this person's photos.
139
+ def mobile_url
140
+ infoxml = get_info
141
+ return infoxml.at('mobileurl').inner_text
142
+ end
143
+
144
+ # Gets the total number of photos uploaded by this user.
145
+ def photo_count
146
+ infoxml = get_info
147
+ return infoxml.at('photos/count').inner_text.to_i
148
+ end
149
+
150
+ # Gets the URL of this person's photo stream.
151
+ def photo_url
152
+ infoxml = get_info
153
+ return infoxml.at('photosurl').inner_text
154
+ end
155
+
156
+ # Gets the number of times this person's photo stream has been viewed. This
157
+ # method requires authentication with +read+ permission and only returns
158
+ # information for the calling user. In all other cases, it returns +nil+.
159
+ def photo_views
160
+ infoxml = get_info
161
+
162
+ if views = infoxml.at('photos/views')
163
+ return views.inner_text.to_i
164
+ end
165
+
166
+ return nil
167
+ end
168
+
169
+ # Gets a list of public photos for this person.
170
+ #
171
+ # See http://flickr.com/services/api/flickr.people.getPublicPhotos.html for
172
+ # details.
173
+ def photos(args = {})
174
+ return @flickr.photos.user(@id, args)
175
+ end
176
+
177
+ # +true+ if this person is a Flickr Pro user, +false+ otherwise.
178
+ def pro?
179
+ infoxml = get_info
180
+ return infoxml['ispro'] == '1'
181
+ end
182
+
183
+ # Gets the URL of this person's profile.
184
+ def profile_url
185
+ infoxml = get_info
186
+ return infoxml.at('profileurl').inner_text
187
+ end
188
+
189
+ # Gets this person's real name (e.g., 'John Doe').
190
+ def realname
191
+ infoxml = get_info
192
+ return infoxml.at('realname').inner_text
193
+ end
194
+
195
+ # +true+ if the calling user is a contact of this person, +false+ otherwise.
196
+ # This method requires authentication with +read+ permission. In all other
197
+ # cases, it returns +false+.
198
+ def rev_contact?
199
+ infoxml = get_info
200
+
201
+ if rev_contact = infoxml['revcontact']
202
+ return rev_contact == '1'
203
+ end
204
+
205
+ return false
206
+ end
207
+
208
+ # +true+ if this person considers the calling user family, +false+
209
+ # otherwise. This method requires authentication with +read+ permission. In
210
+ # all other cases, it returns +false+.
211
+ def rev_family?
212
+ infoxml = get_info
213
+
214
+ if rev_family = infoxml['revfamily']
215
+ return rev_family == '1'
216
+ end
217
+
218
+ return false
219
+ end
220
+
221
+ # +true+ if this person considers the calling user a friend, +false+
222
+ # otherwise. This method requires authentication with +read+ permission. In
223
+ # all other cases, it returns +false+.
224
+ def rev_friend?
225
+ infoxml = get_info
226
+
227
+ if rev_friend = infoxml['revfriend']
228
+ return rev_friend == '1'
229
+ end
230
+
231
+ return false
232
+ end
233
+
234
+ #--
235
+ # Private Instance Methods
236
+ #++
237
+
238
+ private
239
+
240
+ # Gets detailed information for this person.
241
+ def get_info
242
+ return @infoxml unless @infoxml.nil?
243
+
244
+ response = @flickr.request('flickr.people.getInfo', 'user_id' => @id)
245
+
246
+ return @infoxml = response.at('person')
247
+ end
248
+
249
+ end
250
+
251
+ end; end
@@ -0,0 +1,335 @@
1
+ #--
2
+ # Copyright (c) 2007-2008 Ryan Grove <ryan@wonko.com>
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of this project nor the names of its contributors may be
14
+ # used to endorse or promote products derived from this software without
15
+ # specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #++
28
+
29
+ module Net; class Flickr
30
+
31
+ # A Flickr photo.
32
+ #
33
+ # Don't instantiate this class yourself. Use the methods in Flickr::Photos to
34
+ # retrieve photos from Flickr.
35
+ class Photo
36
+ SIZE_SUFFIX = {
37
+ :square => 's',
38
+ :thumb => 't',
39
+ :small => 'm',
40
+ :medium => nil,
41
+ :large => 'b',
42
+ :original => 'o'
43
+ }
44
+
45
+ #--
46
+ # Public Instance Methods
47
+ #++
48
+
49
+ attr_reader :id, :secret, :server, :farm
50
+
51
+ def initialize(flickr, photo_xml)
52
+ @flickr = flickr
53
+
54
+ parse_xml(photo_xml)
55
+
56
+ # Detailed photo info.
57
+ @context_xml = nil
58
+ @info_xml = nil
59
+ end
60
+
61
+ # Deletes this photo from Flickr. This method requires authentication with
62
+ # +delete+ permission.
63
+ def delete
64
+ @flickr.photos.delete(@id)
65
+ end
66
+
67
+ # Gets this photo's description.
68
+ def description
69
+ info_xml = get_info
70
+ return info_xml.at('description').inner_text
71
+ end
72
+
73
+ # Sets this photo's description. This method requires authentication with
74
+ # +write+ permission.
75
+ def description=(value)
76
+ set_meta(@title, value)
77
+ end
78
+
79
+ # flickr.photos.getExif
80
+ def exif
81
+ raise NotImplementedError
82
+ end
83
+
84
+ # Whether or not this photo is visible to family.
85
+ def family?
86
+ get_info if @is_family.nil?
87
+ return @is_family || @is_public
88
+ end
89
+
90
+ # flickr.photos.getFavorites
91
+ def favorites
92
+ raise NotImplementedError
93
+ end
94
+
95
+ # Whether or not this photo is visible to friends.
96
+ def friend?
97
+ get_info if @is_friend.nil?
98
+ return @is_friend || @is_public
99
+ end
100
+
101
+ # flickr.photos.getExif
102
+ def gps
103
+ raise NotImplementedError
104
+ end
105
+
106
+ # Gets the time this photo was last modified.
107
+ def modified
108
+ info_xml = get_info
109
+ return Time.at(info_xml.at('dates')[:lastupdate].to_i)
110
+ end
111
+
112
+ # Gets the next photo in the owner's photo stream, or +nil+ if this is the
113
+ # last photo in the stream.
114
+ def next
115
+ context_xml = get_context
116
+ next_xml = context_xml.at('nextphoto')
117
+
118
+ return Photo.new(@flickr, next_xml) if next_xml[:id] != '0'
119
+ return nil
120
+ end
121
+
122
+ # Gets the user id of this photo's owner.
123
+ def owner
124
+ @owner
125
+ end
126
+
127
+ # Gets the URL of this photo's Flickr photo page.
128
+ def page_url
129
+ return "http://www.flickr.com/photos/#{@owner}/#{@id}"
130
+ end
131
+
132
+ # flickr.photos.getAllContexts
133
+ def pools
134
+ raise NotImplementedError
135
+ end
136
+
137
+ # Gets the time this photo was posted to Flickr.
138
+ def posted
139
+ info_xml = get_info
140
+ return Time.at(info_xml.at('dates')[:posted].to_i)
141
+ end
142
+
143
+ # flickr.photos.setDates
144
+ def posted=(time)
145
+ end
146
+
147
+ # Gets the previous photo in the owner's photo stream, or +nil+ if this is
148
+ # the first photo in the stream.
149
+ def previous
150
+ context_xml = get_context
151
+ prev_xml = context_xml.at('prevphoto')
152
+
153
+ return Photo.new(@flickr, prev_xml) if prev_xml[:id] != '0'
154
+ return nil
155
+ end
156
+
157
+ alias prev previous
158
+
159
+ # Whether or not this photo is visible to the general public.
160
+ def public?
161
+ get_info if @is_public.nil?
162
+ return @is_public
163
+ end
164
+
165
+ # flickr.photos.getAllContexts
166
+ def sets
167
+ raise NotImplementedError
168
+ end
169
+
170
+ # flickr.photos.getSizes
171
+ def sizes
172
+ raise NotImplementedError
173
+ end
174
+
175
+ # Gets the source URL for this photo at one of the following specified
176
+ # sizes. Returns +nil+ if the specified _size_ is not available.
177
+ #
178
+ # [:square] 75x75px
179
+ # [:thumb] 100px on longest side
180
+ # [:small] 240px on longest side
181
+ # [:medium] 500px on longest side
182
+ # [:large] 1024px on longest side (not available for all images)
183
+ # [:original] original image in original file format
184
+ def source_url(size = :medium)
185
+ suffix = SIZE_SUFFIX[size]
186
+
187
+ case size
188
+ when :medium
189
+ return "http://farm#{@farm}.static.flickr.com/#{@server}/#{@id}_" +
190
+ "#{@secret}.jpg"
191
+
192
+ when :original
193
+ info_xml = get_info
194
+
195
+ original_secret = info_xml[:originalsecret]
196
+ original_format = info_xml[:originalformat]
197
+
198
+ return nil if original_secret.nil? || original_format.nil?
199
+ return "http://farm#{@farm}.static.flickr.com/#{@server}/#{@id}_" +
200
+ "#{original_secret}_o.#{original_format}"
201
+
202
+ else
203
+ return "http://farm#{@farm}.static.flickr.com/#{@server}/#{@id}_" +
204
+ "#{@secret}_#{suffix}.jpg"
205
+ end
206
+ end
207
+
208
+ # flickr.photos.getInfo
209
+ def tags
210
+ raise NotImplementedError
211
+ end
212
+
213
+ # Gets the time this photo was taken.
214
+ def taken
215
+ info_xml = get_info
216
+ return Time.parse(info_xml.at('dates')[:taken])
217
+ end
218
+
219
+ # flickr.photos.setDates
220
+ def taken=(time)
221
+ raise NotImplementedError
222
+ end
223
+
224
+ # flickr.photos.getExif
225
+ def tiff
226
+ raise NotImplementedError
227
+ end
228
+
229
+ # Gets this photo's title.
230
+ def title
231
+ @title
232
+ end
233
+
234
+ # Sets this photo's title. This method requires authentication with +write+
235
+ # permission.
236
+ def title=(value)
237
+ set_meta(value, description)
238
+ end
239
+
240
+ #--
241
+ # Private Instance Methods
242
+ #++
243
+
244
+ private
245
+
246
+ # Gets context information for this photo.
247
+ def get_context
248
+ @context_xml ||= @flickr.request('flickr.photos.getContext',
249
+ :photo_id => @id)
250
+ end
251
+
252
+ # Gets detailed information for this photo.
253
+ def get_info
254
+ return @info_xml unless @info_xml.nil?
255
+
256
+ response = @flickr.request('flickr.photos.getInfo', :photo_id => @id,
257
+ :secret => @secret)
258
+
259
+ @info_xml = response.at('photo')
260
+
261
+ if @is_family.nil? || @is_friend.nil? || @is_public.nil?
262
+ @is_family = @info_xml.at('visibility')[:isfamily] == '1'
263
+ @is_friend = @info_xml.at('visibility')[:isfriend] == '1'
264
+ @is_public = @info_xml.at('visibility')[:ispublic] == '1'
265
+ end
266
+
267
+ return @info_xml
268
+ end
269
+
270
+ # Parse a photo xml chunk.
271
+ def parse_xml(photo_xml)
272
+ # Convert photo_xml to an Hpricot::Elem if it isn't one already.
273
+ unless photo_xml.is_a?(Hpricot::Elem)
274
+ photo_xml = Hpricot::XML(photo_xml)
275
+ end
276
+
277
+ # Figure out what format we're dealing with, since someone at Flickr
278
+ # thought it would be fun to be inconsistent (thanks, whoever you are).
279
+ if photo_xml[:owner] && photo_xml[:ispublic]
280
+ # This is a basic XML chunk.
281
+ @id = photo_xml[:id]
282
+ @owner = photo_xml[:owner]
283
+ @secret = photo_xml[:secret]
284
+ @server = photo_xml[:server]
285
+ @farm = photo_xml[:farm]
286
+ @title = photo_xml[:title]
287
+ @is_public = photo_xml[:ispublic] == '1'
288
+ @is_friend = photo_xml[:isfriend] == '1'
289
+ @is_family = photo_xml[:isfamily] == '1'
290
+
291
+ elsif photo_xml[:url] && photo_xml[:thumb]
292
+ # This is a context XML chunk. It doesn't include visibility info.
293
+ @id = photo_xml[:id]
294
+ @secret = photo_xml[:secret]
295
+ @server = photo_xml[:server]
296
+ @farm = photo_xml[:farm]
297
+ @title = photo_xml[:title]
298
+ @is_public = nil
299
+ @is_friend = nil
300
+ @is_family = nil
301
+
302
+ elsif photo_xml[:originalsecret] && photo_xml.at('owner[@nsid]')
303
+ # This is a detailed XML chunk (probably from flickr.photos.getInfo).
304
+ @id = photo_xml[:id]
305
+ @owner = photo_xml.at('owner[@nsid]')
306
+ @secret = photo_xml[:secret]
307
+ @server = photo_xml[:server]
308
+ @farm = photo_xml[:farm]
309
+ @title = photo_xml.at(:title).inner_text
310
+ @is_public = photo_xml.at('visibility')[:ispublic] == '1'
311
+ @is_friend = photo_xml.at('visibility')[:isfriend] == '1'
312
+ @is_family = photo_xml.at('visibility')[:isfamily] == '1'
313
+ @info_xml = photo_xml
314
+ end
315
+ end
316
+
317
+ # Sets date information for this photo.
318
+ def set_dates(posted, taken, granularity = 0, args = {})
319
+ raise NotImplementedError
320
+ end
321
+
322
+ # Sets meta information for this photo.
323
+ def set_meta(title, description, args = {})
324
+ args[:photo_id] = @id
325
+ args[:title] = title
326
+ args[:description] = description
327
+
328
+ @flickr.request('flickr.photos.setMeta', args)
329
+
330
+ @info_xml = nil
331
+ end
332
+
333
+ end
334
+
335
+ end; end