digitalpardoe-rflickr 1.1.4 → 2.0.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +5 -0
  3. data/.document +5 -0
  4. data/.rspec +0 -0
  5. data/Gemfile +5 -5
  6. data/README.md +40 -0
  7. data/Rakefile +17 -21
  8. data/VERSION +1 -0
  9. data/digitalpardoe-rflickr.gemspec +39 -42
  10. data/lib/flickr.rb +44 -37
  11. data/lib/flickr/api.rb +26 -0
  12. data/lib/flickr/interaction/flickr_api_request.rb +75 -0
  13. data/lib/flickr/interaction/request.rb +37 -0
  14. data/spec/api/activity_spec.rb +16 -0
  15. data/spec/api/api_spec.rb +16 -0
  16. data/spec/api/auth_spec.rb +16 -0
  17. data/spec/api/blogs_spec.rb +12 -0
  18. data/spec/api/collections_spec.rb +17 -0
  19. data/spec/api/commons_spec.rb +12 -0
  20. data/spec/api/contacts_spec.rb +16 -0
  21. data/spec/api/favorites_spec.rb +11 -0
  22. data/spec/api/groups/members_spec.rb +20 -0
  23. data/spec/config/api.example.yml +3 -0
  24. data/spec/flickr_spec.rb +33 -0
  25. data/spec/spec_helper.rb +19 -0
  26. metadata +95 -116
  27. data/LICENSE +0 -278
  28. data/README.markdown +0 -22
  29. data/VERSION.yml +0 -5
  30. data/lib/flickr/auth.rb +0 -94
  31. data/lib/flickr/base.rb +0 -810
  32. data/lib/flickr/blogs.rb +0 -50
  33. data/lib/flickr/contacts.rb +0 -68
  34. data/lib/flickr/favorites.rb +0 -79
  35. data/lib/flickr/groups.rb +0 -102
  36. data/lib/flickr/interestingness.rb +0 -39
  37. data/lib/flickr/licenses.rb +0 -43
  38. data/lib/flickr/notes.rb +0 -44
  39. data/lib/flickr/people.rb +0 -99
  40. data/lib/flickr/photos.rb +0 -305
  41. data/lib/flickr/photosets.rb +0 -124
  42. data/lib/flickr/pools.rb +0 -90
  43. data/lib/flickr/reflection.rb +0 -109
  44. data/lib/flickr/tags.rb +0 -79
  45. data/lib/flickr/transform.rb +0 -29
  46. data/lib/flickr/upload.rb +0 -225
  47. data/lib/flickr/urls.rb +0 -69
  48. data/test/test_suite.rb +0 -3
data/LICENSE DELETED
@@ -1,278 +0,0 @@
1
- GNU GENERAL PUBLIC LICENSE
2
- Version 2, June 1991
3
-
4
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
- Everyone is permitted to copy and distribute verbatim copies
7
- of this license document, but changing it is not allowed.
8
-
9
- Preamble
10
-
11
- The licenses for most software are designed to take away your
12
- freedom to share and change it. By contrast, the GNU General Public
13
- License is intended to guarantee your freedom to share and change free
14
- software--to make sure the software is free for all its users. This
15
- General Public License applies to most of the Free Software
16
- Foundation's software and to any other program whose authors commit to
17
- using it. (Some other Free Software Foundation software is covered by
18
- the GNU Lesser General Public License instead.) You can apply it to
19
- your programs, too.
20
-
21
- When we speak of free software, we are referring to freedom, not
22
- price. Our General Public Licenses are designed to make sure that you
23
- have the freedom to distribute copies of free software (and charge for
24
- this service if you wish), that you receive source code or can get it
25
- if you want it, that you can change the software or use pieces of it
26
- in new free programs; and that you know you can do these things.
27
-
28
- To protect your rights, we need to make restrictions that forbid
29
- anyone to deny you these rights or to ask you to surrender the rights.
30
- These restrictions translate to certain responsibilities for you if you
31
- distribute copies of the software, or if you modify it.
32
-
33
- For example, if you distribute copies of such a program, whether
34
- gratis or for a fee, you must give the recipients all the rights that
35
- you have. You must make sure that they, too, receive or can get the
36
- source code. And you must show them these terms so they know their
37
- rights.
38
-
39
- We protect your rights with two steps: (1) copyright the software, and
40
- (2) offer you this license which gives you legal permission to copy,
41
- distribute and/or modify the software.
42
-
43
- Also, for each author's protection and ours, we want to make certain
44
- that everyone understands that there is no warranty for this free
45
- software. If the software is modified by someone else and passed on, we
46
- want its recipients to know that what they have is not the original, so
47
- that any problems introduced by others will not reflect on the original
48
- authors' reputations.
49
-
50
- Finally, any free program is threatened constantly by software
51
- patents. We wish to avoid the danger that redistributors of a free
52
- program will individually obtain patent licenses, in effect making the
53
- program proprietary. To prevent this, we have made it clear that any
54
- patent must be licensed for everyone's free use or not licensed at all.
55
-
56
- The precise terms and conditions for copying, distribution and
57
- modification follow.
58
-
59
- GNU GENERAL PUBLIC LICENSE
60
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
-
62
- 0. This License applies to any program or other work which contains
63
- a notice placed by the copyright holder saying it may be distributed
64
- under the terms of this General Public License. The "Program", below,
65
- refers to any such program or work, and a "work based on the Program"
66
- means either the Program or any derivative work under copyright law:
67
- that is to say, a work containing the Program or a portion of it,
68
- either verbatim or with modifications and/or translated into another
69
- language. (Hereinafter, translation is included without limitation in
70
- the term "modification".) Each licensee is addressed as "you".
71
-
72
- Activities other than copying, distribution and modification are not
73
- covered by this License; they are outside its scope. The act of
74
- running the Program is not restricted, and the output from the Program
75
- is covered only if its contents constitute a work based on the
76
- Program (independent of having been made by running the Program).
77
- Whether that is true depends on what the Program does.
78
-
79
- 1. You may copy and distribute verbatim copies of the Program's
80
- source code as you receive it, in any medium, provided that you
81
- conspicuously and appropriately publish on each copy an appropriate
82
- copyright notice and disclaimer of warranty; keep intact all the
83
- notices that refer to this License and to the absence of any warranty;
84
- and give any other recipients of the Program a copy of this License
85
- along with the Program.
86
-
87
- You may charge a fee for the physical act of transferring a copy, and
88
- you may at your option offer warranty protection in exchange for a fee.
89
-
90
- 2. You may modify your copy or copies of the Program or any portion
91
- of it, thus forming a work based on the Program, and copy and
92
- distribute such modifications or work under the terms of Section 1
93
- above, provided that you also meet all of these conditions:
94
-
95
- a) You must cause the modified files to carry prominent notices
96
- stating that you changed the files and the date of any change.
97
-
98
- b) You must cause any work that you distribute or publish, that in
99
- whole or in part contains or is derived from the Program or any
100
- part thereof, to be licensed as a whole at no charge to all third
101
- parties under the terms of this License.
102
-
103
- c) If the modified program normally reads commands interactively
104
- when run, you must cause it, when started running for such
105
- interactive use in the most ordinary way, to print or display an
106
- announcement including an appropriate copyright notice and a
107
- notice that there is no warranty (or else, saying that you provide
108
- a warranty) and that users may redistribute the program under
109
- these conditions, and telling the user how to view a copy of this
110
- License. (Exception: if the Program itself is interactive but
111
- does not normally print such an announcement, your work based on
112
- the Program is not required to print an announcement.)
113
-
114
- These requirements apply to the modified work as a whole. If
115
- identifiable sections of that work are not derived from the Program,
116
- and can be reasonably considered independent and separate works in
117
- themselves, then this License, and its terms, do not apply to those
118
- sections when you distribute them as separate works. But when you
119
- distribute the same sections as part of a whole which is a work based
120
- on the Program, the distribution of the whole must be on the terms of
121
- this License, whose permissions for other licensees extend to the
122
- entire whole, and thus to each and every part regardless of who wrote it.
123
-
124
- Thus, it is not the intent of this section to claim rights or contest
125
- your rights to work written entirely by you; rather, the intent is to
126
- exercise the right to control the distribution of derivative or
127
- collective works based on the Program.
128
-
129
- In addition, mere aggregation of another work not based on the Program
130
- with the Program (or with a work based on the Program) on a volume of
131
- a storage or distribution medium does not bring the other work under
132
- the scope of this License.
133
-
134
- 3. You may copy and distribute the Program (or a work based on it,
135
- under Section 2) in object code or executable form under the terms of
136
- Sections 1 and 2 above provided that you also do one of the following:
137
-
138
- a) Accompany it with the complete corresponding machine-readable
139
- source code, which must be distributed under the terms of Sections
140
- 1 and 2 above on a medium customarily used for software interchange; or,
141
-
142
- b) Accompany it with a written offer, valid for at least three
143
- years, to give any third party, for a charge no more than your
144
- cost of physically performing source distribution, a complete
145
- machine-readable copy of the corresponding source code, to be
146
- distributed under the terms of Sections 1 and 2 above on a medium
147
- customarily used for software interchange; or,
148
-
149
- c) Accompany it with the information you received as to the offer
150
- to distribute corresponding source code. (This alternative is
151
- allowed only for noncommercial distribution and only if you
152
- received the program in object code or executable form with such
153
- an offer, in accord with Subsection b above.)
154
-
155
- The source code for a work means the preferred form of the work for
156
- making modifications to it. For an executable work, complete source
157
- code means all the source code for all modules it contains, plus any
158
- associated interface definition files, plus the scripts used to
159
- control compilation and installation of the executable. However, as a
160
- special exception, the source code distributed need not include
161
- anything that is normally distributed (in either source or binary
162
- form) with the major components (compiler, kernel, and so on) of the
163
- operating system on which the executable runs, unless that component
164
- itself accompanies the executable.
165
-
166
- If distribution of executable or object code is made by offering
167
- access to copy from a designated place, then offering equivalent
168
- access to copy the source code from the same place counts as
169
- distribution of the source code, even though third parties are not
170
- compelled to copy the source along with the object code.
171
-
172
- 4. You may not copy, modify, sublicense, or distribute the Program
173
- except as expressly provided under this License. Any attempt
174
- otherwise to copy, modify, sublicense or distribute the Program is
175
- void, and will automatically terminate your rights under this License.
176
- However, parties who have received copies, or rights, from you under
177
- this License will not have their licenses terminated so long as such
178
- parties remain in full compliance.
179
-
180
- 5. You are not required to accept this License, since you have not
181
- signed it. However, nothing else grants you permission to modify or
182
- distribute the Program or its derivative works. These actions are
183
- prohibited by law if you do not accept this License. Therefore, by
184
- modifying or distributing the Program (or any work based on the
185
- Program), you indicate your acceptance of this License to do so, and
186
- all its terms and conditions for copying, distributing or modifying
187
- the Program or works based on it.
188
-
189
- 6. Each time you redistribute the Program (or any work based on the
190
- Program), the recipient automatically receives a license from the
191
- original licensor to copy, distribute or modify the Program subject to
192
- these terms and conditions. You may not impose any further
193
- restrictions on the recipients' exercise of the rights granted herein.
194
- You are not responsible for enforcing compliance by third parties to
195
- this License.
196
-
197
- 7. If, as a consequence of a court judgment or allegation of patent
198
- infringement or for any other reason (not limited to patent issues),
199
- conditions are imposed on you (whether by court order, agreement or
200
- otherwise) that contradict the conditions of this License, they do not
201
- excuse you from the conditions of this License. If you cannot
202
- distribute so as to satisfy simultaneously your obligations under this
203
- License and any other pertinent obligations, then as a consequence you
204
- may not distribute the Program at all. For example, if a patent
205
- license would not permit royalty-free redistribution of the Program by
206
- all those who receive copies directly or indirectly through you, then
207
- the only way you could satisfy both it and this License would be to
208
- refrain entirely from distribution of the Program.
209
-
210
- If any portion of this section is held invalid or unenforceable under
211
- any particular circumstance, the balance of the section is intended to
212
- apply and the section as a whole is intended to apply in other
213
- circumstances.
214
-
215
- It is not the purpose of this section to induce you to infringe any
216
- patents or other property right claims or to contest validity of any
217
- such claims; this section has the sole purpose of protecting the
218
- integrity of the free software distribution system, which is
219
- implemented by public license practices. Many people have made
220
- generous contributions to the wide range of software distributed
221
- through that system in reliance on consistent application of that
222
- system; it is up to the author/donor to decide if he or she is willing
223
- to distribute software through any other system and a licensee cannot
224
- impose that choice.
225
-
226
- This section is intended to make thoroughly clear what is believed to
227
- be a consequence of the rest of this License.
228
-
229
- 8. If the distribution and/or use of the Program is restricted in
230
- certain countries either by patents or by copyrighted interfaces, the
231
- original copyright holder who places the Program under this License
232
- may add an explicit geographical distribution limitation excluding
233
- those countries, so that distribution is permitted only in or among
234
- countries not thus excluded. In such case, this License incorporates
235
- the limitation as if written in the body of this License.
236
-
237
- 9. The Free Software Foundation may publish revised and/or new versions
238
- of the General Public License from time to time. Such new versions will
239
- be similar in spirit to the present version, but may differ in detail to
240
- address new problems or concerns.
241
-
242
- Each version is given a distinguishing version number. If the Program
243
- specifies a version number of this License which applies to it and "any
244
- later version", you have the option of following the terms and conditions
245
- either of that version or of any later version published by the Free
246
- Software Foundation. If the Program does not specify a version number of
247
- this License, you may choose any version ever published by the Free Software
248
- Foundation.
249
-
250
- 10. If you wish to incorporate parts of the Program into other free
251
- programs whose distribution conditions are different, write to the author
252
- to ask for permission. For software which is copyrighted by the Free
253
- Software Foundation, write to the Free Software Foundation; we sometimes
254
- make exceptions for this. Our decision will be guided by the two goals
255
- of preserving the free status of all derivatives of our free software and
256
- of promoting the sharing and reuse of software generally.
257
-
258
- NO WARRANTY
259
-
260
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
- FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
- OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
- PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
- OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
- TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
- PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
- REPAIR OR CORRECTION.
269
-
270
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
- REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
- INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
- OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
- TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
- YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
- PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
- POSSIBILITY OF SUCH DAMAGES.
data/README.markdown DELETED
@@ -1,22 +0,0 @@
1
- # rFlickr
2
-
3
- **Warning**: This gem only works with Ruby 1.8, a new version compatible with Ruby 2.0 is coming soon.
4
-
5
- To use this version of rFlickr, first you will need to install
6
- the RubyGem using the following command:
7
-
8
- $ sudo gem install digitalpardoe-rflickr
9
-
10
- Then you'll need to get a Flickr API key as detailed here:
11
-
12
- [http://www.flickr.com/services/api/misc.api_keys.html](http://www.flickr.com/services/api/misc.api_keys.html)
13
-
14
- You'll need to authorize your application's API key from each
15
- Flickr user account which wants to use it.
16
-
17
- A short guide to get you started can be found here:
18
-
19
- [http://digitalpardoe.co.uk/blog/show/87](http://digitalpardoe.co.uk/blog/show/87)
20
-
21
- The guide is a little out of date in it's gem installation technique,
22
- use the instructions above instead.
data/VERSION.yml DELETED
@@ -1,5 +0,0 @@
1
- ---
2
- :minor: 1
3
- :patch: 4
4
- :build:
5
- :major: 1
data/lib/flickr/auth.rb DELETED
@@ -1,94 +0,0 @@
1
- # rFlickr: A Ruby based Flickr API implementation.
2
- # Copyright (C) 2009, Alex Pardoe (digital:pardoe)
3
- #
4
- # Derrived from work by Trevor Schroeder, see here:
5
- # http://rubyforge.org/projects/rflickr/.
6
- #
7
- # This program is free software; you can redistribute it and/or
8
- # modify it under the terms of the GNU General Public License
9
- # as published by the Free Software Foundation; either version 2
10
- # of the License, or (at your option) any later version.
11
- #
12
- # This program is distributed in the hope that it will be useful,
13
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- # GNU General Public License for more details.
16
- #
17
- # You should have received a copy of the GNU General Public License
18
- # along with this program; if not, write to the Free Software
19
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
-
21
- require 'flickr/base'
22
-
23
- class Flickr::Auth < Flickr::APIBase
24
- attr_accessor :cache_file, :token
25
-
26
- def clear_cache
27
- @token = nil
28
- @frob = nil
29
- end
30
-
31
- def initialize(flickr,cache_file=nil)
32
- super(flickr)
33
- @frob = nil
34
- @token = nil
35
- @cache_file = cache_file
36
- if @cache_file && File.exists?(@cache_file)
37
- load_token
38
- end
39
- end
40
-
41
- def login_link(perms='delete')
42
- args={ 'api_key' => @flickr.api_key, 'perms' => perms}
43
- args['frob'] = self.frob
44
- args['api_sig'] = @flickr.sign(args)
45
- return "http://flickr.com/services/auth/?"+
46
- args.to_a.map{|arr| arr.join('=')}.join('&')
47
- end
48
-
49
- def frob=(frob) @frob = frob end
50
- def frob() return @frob || getFrob end
51
-
52
- def cache_token
53
- File.open(@cache_file,'w'){ |f| f.write @token.to_xml } if token
54
- end
55
-
56
- def load_token
57
- token = nil
58
- File.open(@cache_file,'r'){ |f| token = f.read }
59
- # Dirt stupid check to see if it's probably XML or
60
- # not. If it is, then we don't call checkToken.
61
- #
62
- # Backwwards compatible with old token storage.
63
- @token = token.include?('<') ?
64
- Flickr::Token.from_xml(REXML::Document.new(token)) :
65
- @token = checkToken(token)
66
- end
67
-
68
- def getToken(frob=nil)
69
- frob ||= @frob
70
- res=@flickr.call_unauth_method('flickr.auth.getToken',
71
- 'frob'=>frob)
72
- @token = Flickr::Token.from_xml(res)
73
- end
74
-
75
- def getFullToken(mini_token)
76
- res = flickr.call_unauth_method('flickr.auth.getFullToken',
77
- 'mini_token' => mini_token)
78
- @token = Flickr::Token.from_xml(res)
79
- end
80
-
81
- def getFrob
82
- doc = @flickr.call_unauth_method('flickr.auth.getFrob')
83
- @frob = doc.elements['/frob'].text
84
- return @frob
85
- end
86
-
87
- def checkToken(token=nil)
88
- token ||= @token
89
- token = token.token if token.class == Flickr::Token
90
- res = @flickr.call_unauth_method('flickr.auth.checkToken',
91
- 'auth_token' => token)
92
- @token = Flickr::Token.from_xml(res)
93
- end
94
- end
data/lib/flickr/base.rb DELETED
@@ -1,810 +0,0 @@
1
- # rFlickr: A Ruby based Flickr API implementation.
2
- # Copyright (C) 2009, Alex Pardoe (digital:pardoe)
3
- #
4
- # Derrived from work by Trevor Schroeder, see here:
5
- # http://rubyforge.org/projects/rflickr/.
6
- #
7
- # This program is free software; you can redistribute it and/or
8
- # modify it under the terms of the GNU General Public License
9
- # as published by the Free Software Foundation; either version 2
10
- # of the License, or (at your option) any later version.
11
- #
12
- # This program is distributed in the hope that it will be useful,
13
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- # GNU General Public License for more details.
16
- #
17
- # You should have received a copy of the GNU General Public License
18
- # along with this program; if not, write to the Free Software
19
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
-
21
- ## Structure this class hierarchy the way the Flickr API is structured.
22
- ## Flickr::Auth and so on. At least think about whether it makes sense or
23
- ## not.
24
-
25
- require 'xmlrpc/client'
26
- require 'md5'
27
- require 'rexml/document'
28
- require 'parsedate'
29
-
30
- class Flickr
31
- API_KEY=''
32
- SHARED_SECRET=''
33
-
34
- attr_reader :api_key
35
- attr_accessor :async, :debug, :caching, :auth_mode
36
-
37
- ############################### CACHE ACCESSORS ###########################
38
- def ticket_cache_lookup(id) @ticket_by_id[id] if @caching end
39
-
40
- def ticket_cache_store(ticket)
41
- @ticket_by_id[ticket.id] = ticket if @caching
42
- end
43
-
44
- def person_cache_lookup(nsid) @person_by_nsid[nsid] if @caching end
45
-
46
- def person_cache_store(person)
47
- @person_by_nsid[person.nsid] = person if @caching
48
- end
49
-
50
- def photo_cache_lookup(id) @photo_by_id[id] if @caching end
51
-
52
- def photo_cache_store(photo)
53
- @photo_by_id[photo.id] = photo if @caching
54
- end
55
-
56
- def license_cache_lookup() @license_cache if @caching end
57
-
58
- def license_cache_store(licenses)
59
- @license_cache = licenses if @caching
60
- end
61
-
62
- def blog_cache_lookup() @blog_cache if @caching end
63
-
64
- def blog_cache_store(blogs) @blog_cache = blogs if @caching end
65
-
66
- def photoset_cache_lookup(id) @photoset_by_id[id] if @caching end
67
-
68
- def photoset_cache_store(set)
69
- @photoset_by_id[set.id] = set if @caching
70
- end
71
-
72
- def photopool_cache_lookup(id) @photopool_by_id[id] if @caching end
73
-
74
- def photopool_cache_store(pool)
75
- @photopool_by_id[pool.id] = pool if @caching
76
- end
77
-
78
- def group_cache_lookup(id) @group_by_id[id] if @caching end
79
-
80
- def group_cache_store(group)
81
- @group_by_id[group.id] = group if @caching
82
- end
83
- ############################################################################
84
-
85
- def debug(*args) $stderr.puts(sprintf(*args)) if @debug end
86
-
87
- def Flickr.todo
88
- [
89
- 'Refactor, especially more Class.from_xml methods',
90
- 'More logical OO design, wrap the API methods to make transparent',
91
- 'Class & method documentation',
92
- 'Unit tests',
93
- 'Implement missing methods (see flickr.reflection.missing_methods)'
94
- ]
95
- end
96
-
97
- def todo()
98
- Flickr.todo+reflection.missing_methods.map{|m| 'Implement '+m}
99
- end
100
-
101
- def initialize(token_cache=nil,api_key=API_KEY,
102
- shared_secret=SHARED_SECRET,
103
- endpoint='http://www.flickr.com/services/xmlrpc/')
104
- @async = false
105
- @caching = true
106
- @auth_mode = true
107
- @api_key=api_key
108
- @shared_secret=shared_secret
109
- @token_cache = token_cache
110
- @endpoint=endpoint
111
- proto,host,port,path,user,pass=parse_url(@endpoint)
112
- raise ProtoUnknownError.new("Unhandled protocol '#{proto}'") if
113
- proto.downcase != 'http'
114
- @client=XMLRPC::Client.new(host,path,port)
115
- clear_cache
116
- end
117
-
118
- def clear_cache()
119
- @auth = nil
120
- @blogs = nil
121
- @contacts = nil
122
- @favorites = nil
123
- @groups = nil
124
- @interestingness = nil
125
- @reflection = nil
126
- @people = nil
127
- @photos = nil
128
- @photosets = nil
129
- @urls = nil
130
-
131
- @ticket_by_id = {}
132
- @person_by_nsid = {}
133
- @photo_by_id = {}
134
- @photoset_by_id = {}
135
- @photopool_by_id = {}
136
- @group_by_id = {}
137
- @license_cache = nil
138
- @blog_cache = nil
139
- end
140
-
141
- def auth() @auth ||= Auth.new(self,@token_cache) end
142
- def blogs() @blogs ||= Blogs.new(self) end
143
- def contacts() @contacts ||= Contacts.new(self) end
144
- def favorites() @favorites ||= Favorites.new(self) end
145
- def groups() @groups ||= Groups.new(self) end
146
- def people() @people ||= People.new(self) end
147
- def photos() @photos ||= Photos.new(self) end
148
- def photosets() @photosets ||= PhotoSets.new(self) end
149
- def reflection() @reflection ||= Reflection.new(self) end
150
- def urls() @urls ||= Urls.new(self) end
151
- def tags() @tags ||= Tags.new(self) end
152
- def interestingness() @interestingness ||= Interestingness.new(self) end
153
-
154
- def call_method(method,args={})
155
- @auth_mode ? call_auth_method(method,args) :
156
- call_unauth_method(method,args)
157
- end
158
-
159
- def call_unauth_method(method,args={})
160
- debug('%s(%s)', method, args.inspect)
161
- tries = 3
162
- args = args.dup
163
- args['api_key'] = @api_key
164
- api_sig=sign(args)
165
- args['api_sig']=api_sig
166
- begin
167
- tries -= 1;
168
- str = @async ? @client.call_async(method,args) :
169
- @client.call(method,args)
170
- debug('RETURN: %s',str)
171
- return REXML::Document.new(str)
172
- rescue Timeout::Error => te
173
- $stderr.puts "Timed out, will try #{tries} more times."
174
- if tries > 0
175
- retry
176
- else
177
- raise te
178
- end
179
- rescue REXML::ParseException => pe
180
- return REXML::Document.new('<rsp>'+str+'</rsp>').
181
- elements['/rsp']
182
- rescue XMLRPC::FaultException => fe
183
- $stderr.puts "ERR: #{fe.faultString} (#{fe.faultCode})"
184
- raise fe
185
- end
186
- end
187
-
188
- def call_auth_method(method,args={})
189
- at = args['auth_token']
190
- args['auth_token'] ||= auth.token.token
191
- res = call_unauth_method(method,args)
192
- args.delete('auth_token') unless at
193
- return res
194
- end
195
-
196
- def sign(args)
197
- return MD5.md5(@shared_secret+args.sort.flatten.join).to_s
198
- end
199
-
200
- def parse_url(url)
201
- url =~ /([^:]+):\/\/([^\/]*)(.*)/
202
- proto = $1.to_s
203
- hostplus = $2.to_s
204
- path = $3.to_s
205
-
206
- hostplus =~ /(?:(.*)@)?(.*)/
207
- userpass = $1
208
- hostport = $2
209
- user,pass = userpass.to_s.split(':',2)
210
- host,port = hostport.to_s.split(':',2)
211
- port = port ? port.to_i : 80
212
-
213
- return proto,host,port,path,user,pass
214
- end
215
-
216
- def mysql_datetime(time) time.strftime('%Y-%m-%d %H:%M:%S') end
217
- def mysql_date(time) time.strftime('%Y-%m-%d') end
218
- end
219
-
220
- class Flickr::APIBase
221
- attr_reader :flickr
222
-
223
- def initialize(flickr) @flickr = flickr end
224
- end
225
-
226
- class Flickr::Token
227
- attr_reader :token, :perms, :user
228
-
229
- def initialize(token, perms, user)
230
- @token = token
231
- @perms = perms
232
- @user = user
233
- end
234
-
235
- def self.from_xml(xml, flickr=nil)
236
- token = xml.elements['/auth/token'].text
237
- perms = xml.elements['/auth/perms'].text.intern
238
- user = xml.elements['/auth/user']
239
- nsid = user.attributes['nsid']
240
- username = user.attributes['username']
241
- fullname = user.attributes['fullname']
242
-
243
- p = flickr.person_cache_lookup(nsid) if flickr
244
- p ||= Flickr::Person.new(flickr,nsid,username)
245
- p.realname=fullname
246
- flickr.person_cache_store(p) if flickr
247
-
248
- return Flickr::Token.new(token,perms,p)
249
- end
250
-
251
- def to_xml
252
- return "<auth><token>#{self.token}</token>"+
253
- "<perms>#{self.perms}</perms>"+
254
- "<user nsid=\"#{self.user.nsid}\" "+
255
- "username=\"#{self.user.username}\" "+
256
- "fullname=\"#{self.user.realname}\" /></auth>"
257
- end
258
- end
259
-
260
- class Flickr::Blog
261
- attr_reader :id, :name, :needspassword, :url
262
-
263
- def initialize(id,name,needspassword,url)
264
- @id = id
265
- @name = name
266
- @needspassword = needspassword
267
- @url = url
268
- end
269
- end
270
-
271
- class Flickr::Person
272
- attr_accessor :nsid, :username, :realname, :mbox_sha1sum, :location,
273
- :photosurl, :profileurl, :photos_firstdate, :photos_firstdatetaken,
274
- :photos_count, :info_fetched, :isadmin, :ispro, :iconserver,
275
- :bandwidth_max, :bandwidth_used, :filesize_max, :upload_fetched,
276
- :friend, :family, :ignored
277
-
278
- def initialize(flickr, nsid, username)
279
- @flickr = flickr
280
- @nsid = nsid
281
- @username = username
282
- @info_fetched = false
283
- @upload_fetched = false
284
- end
285
-
286
- def full_info()
287
- self.info_fetched ? self : @flickr.people.getInfo(self)
288
- end
289
- def upload_status() self.upload_fetched ? self :
290
- @flickr.people.getUploadStatus(self) end
291
-
292
-
293
- # I think this will define a class method. You can't use
294
- # Flickr::Person.from_xml and if you just say Person.from_xml, it
295
- # can't resolve Flickr::Person::Person
296
- def self.from_xml(xml,flickr=nil)
297
- els = xml.elements
298
- att = xml.root.attributes
299
-
300
- nsid = cond_attr(att,'nsid')
301
- username = cond_text(els,'/person/username')
302
-
303
- p = flickr.person_cache_lookup(nsid) if flickr
304
- p ||= Flickr::Person.new(flickr,nsid,username)
305
-
306
- p.username = username
307
- p.isadmin = cond_attr(att,'isadmin') &&
308
- cond_attr(att,'isadmin') == '1'
309
- p.ispro = cond_attr(att,'ispro') &&
310
- cond_attr(att,'ispro') == '1'
311
- p.iconserver = cond_attr(att,'iconserver') &&
312
- cond_attr(att,'iconserver').to_i
313
- p.realname = cond_text(els,'/person/realname')
314
- p.mbox_sha1sum = cond_text(els,'/person/mbox_sha1sum')
315
- p.location = cond_text(els,'/person/location')
316
- p.photosurl = cond_text(els,'/person/photosurl')
317
- p.profileurl = cond_text(els,'/person/profileurl')
318
- tstr = cond_text(els,'/person/photos/firstdate')
319
- p.photos_firstdate = Time.at(tstr.to_i) if tstr
320
- tstr = cond_text(els, '/person/photos/firstdatetaken')
321
- p.photos_firstdatetaken = Time.gm(*ParseDate.parsedate(tstr)) if
322
- tstr
323
- p.photos_count = cond_text(els,'/person/photos/count')
324
- p.photos_count = p.photos_count if p.photos_count
325
-
326
- p.info_fetched = true if p.photos_count
327
-
328
- if els['/user/bandwidth']
329
- att = els['/user/bandwidth'].attributes
330
- p.bandwidth_max = cond_attr(att,'max') &&
331
- cond_attr(att,'max').to_i
332
- p.bandwidth_used = cond_attr(att,'used') &&
333
- cond_attr(att,'used').to_i
334
- end
335
- if els['/user/filesize']
336
- att = els['/user/filesize'].attributes
337
- p.filesize_max = cond_attr(att,'max') &&
338
- cond_attr(att,'max').to_i
339
- end
340
-
341
- p.upload_fetched = true if p.bandwidth_max
342
-
343
- flickr.person_cache_store(p) if flickr
344
- return p
345
- end
346
-
347
- private
348
- def self.cond_text(elements,index)
349
- elements[index] ? elements[index].text : nil
350
- end
351
-
352
- def self.cond_attr(attributes,name) attributes[name] end
353
- end
354
-
355
- class Flickr::Size
356
- attr_reader :label,:width,:height,:source,:url
357
-
358
- def initialize(label,width,height,source,url)
359
- @label = label
360
- @width = width
361
- @height = height
362
- @source = source
363
- @url = url
364
- end
365
-
366
- def self.from_xml(xml)
367
- att = xml.attributes
368
- return Flickr::Size.new(att['label'],att['width'].to_i,
369
- att['height'].to_i,att['source'],att['url'])
370
- end
371
- end
372
-
373
- class Flickr::Photo
374
- attr_accessor :id, :owner_id, :secret, :server, :title, :ispublic,
375
- :isfriend, :isfamily, :ownername, :dateadded,
376
- :license_id, :description, :dates, :taken,
377
- :lastupdate, :takengranularity, :cancomment, :canaddmeta,
378
- :comments, :rotation, :notes, :urls, :permaddmeta,
379
- :permcomment, :originalformat, :farm
380
-
381
- attr_reader :flickr
382
-
383
- def owner() @owner ||= @flickr.people.getInfo(owner_id) end
384
- def sizes() @sizes || @flickr.photos.getSizes(self).sizes end
385
- def sizes=(sizes) @sizes = sizes end
386
-
387
- def max_size
388
- sizes[:Original] || sizes[:Large] || sizes[:Medium] ||
389
- sizes[:Small]
390
- end
391
-
392
- def initialize(flickr,id)
393
- @flickr = flickr
394
- @id = id
395
- end
396
-
397
- def exif() @exif ||= @flickr.photos.getExif(self) end
398
- def exif=(set) @exif = set end
399
-
400
- def tags() @tags ||= @flickr.tags.getListPhoto(self) end
401
- def tags=(set) @tags = set end
402
-
403
- def license() @flickr.photos.licenses.getInfo[@license_id] end
404
-
405
- def contexts() @contexts ||= @flickr.photos.getAllContexts(self) end
406
-
407
- def url(size=nil)
408
- base = "http://farm#{@farm}.static.flickr.com"
409
- ext = (size == 'o') ? self.originalformat : 'jpg'
410
- return size ?
411
- "#{base}/#@server/#{@id}_#{@secret}_#{size}.#{ext}" :
412
- "#{base}/#@server/#{@id}_#{@secret}.jpg"
413
- end
414
-
415
- def delete() @flickr.photos.delete(self) end
416
-
417
- def self.from_xml(xml,flickr=nil)
418
- att = xml.attributes
419
- phid = att['id']
420
-
421
- photo = flickr.photo_cache_lookup(phid) if flickr
422
- photo ||= Flickr::Photo.new(flickr,phid)
423
-
424
- photo.owner_id ||= att['owner'] || (xml.elements['owner'] &&
425
- xml.elements['owner'].attributes['nsid'])
426
- photo.secret = att['secret'] if att['secret']
427
- photo.originalformat = att['originalformat'] if
428
- att['originalformat']
429
- photo.server = att['server'].to_i if att['server']
430
- photo.title = att['title'] || cond_text(xml.elements,'title')
431
- photo.license_id = att['license']
432
- photo.rotation = att['rotation'].to_i if att['rotation']
433
- photo.farm = att['farm'].to_i if att['farm']
434
-
435
- photo.ispublic = (att['ispublic'].to_i == 1) if att['ispublic']
436
- photo.isfriend = (att['isfriend'].to_i == 1) if att['isfriend']
437
- photo.isfamily = (att['isfamily'].to_i == 1) if att['isfamily']
438
- photo.ownername = att['ownername'] || (xml.elements['owner'] &&
439
- xml.elements['owner'].attributes['username'])
440
- photo.description = cond_text(xml.elements,'description')
441
- photo.dateadded = Time.at(att['dateadded'].to_i) if
442
- att['dateadded']
443
- if xml.elements['exif']
444
- list = []
445
- xml.elements.each('exif') do |el|
446
- exif = Flickr::Exif.from_xml(el)
447
- list << exif
448
- end
449
- photo.exif = list
450
- end
451
- if xml.elements['visibility']
452
- att = xml.elements['visibility'].attributes
453
- photo.ispublic = (att['ispublic'].to_i == 1)
454
- photo.isfriend = (att['isfriend'].to_i == 1)
455
- photo.isfamily = (att['isfamily'].to_i == 1)
456
- end
457
- if xml.elements['dates']
458
- att = xml.elements['dates'].attributes
459
- dates = {}
460
- dates[:posted] = Time.at(att['posted'].to_i)
461
- dates[:taken] = Time.gm(*ParseDate.parsedate(att['taken']))
462
- dates[:lastupdate] = Time.at(att['lastupdate'].to_i)
463
- dates[:takengranularity] = att['takengranularity'].to_i
464
- photo.dates = dates
465
- end
466
- if xml.elements['editability']
467
- att = xml.elements['editability'].attributes
468
- photo.cancomment = (att['cancomment'].to_i == 1)
469
- photo.canaddmeta = (att['canaddmeta'].to_i == 1)
470
- end
471
- photo.comments = cond_text(xml.elements,'comments')
472
- photo.comments &&= photo.comments.to_i
473
- if xml.elements['notes']
474
- notes = []
475
- xml.elements['notes'].each_element do |el|
476
- notes << Flickr::Note.from_xml(el,photo)
477
- end
478
- photo.notes = notes
479
- end
480
- if xml.elements['tags']
481
- tags = []
482
- xml.elements['tags'].each_element do |el|
483
- tags << Flickr::Tag.from_xml(el,photo)
484
- end
485
- photo.tags = tags
486
- end
487
- if xml.elements['urls']
488
- urls = {}
489
- xml.elements['urls'].each_element do |el|
490
- att = el.attributes
491
- urls[att['type'].intern] = el.text
492
- end
493
- photo.urls = urls
494
- end
495
-
496
- flickr.photo_cache_store(photo) if flickr
497
- return photo
498
- end
499
-
500
- private
501
- def self.cond_text(elements,index)
502
- elements[index] ? elements[index].text : nil
503
- end
504
- end
505
-
506
- class Flickr::Exif
507
- attr_reader :tagspace,:tagspaceid,:tag,:label
508
- attr_accessor :raw,:clean
509
- def initialize(tagspace,tagspaceid,tag,label)
510
- @tagspace = tagspace
511
- @tagspaceid = tagspaceid
512
- @tag = tag
513
- @label = label
514
- end
515
-
516
- def self.from_xml(element)
517
- att = element.attributes
518
- exif = Flickr::Exif.new(att['tagspace'],att['tagspaceid'].to_i,
519
- att['tag'],att['label'])
520
- exif.raw=element.elements['raw'].text if element.elements['raw']
521
- exif.clean=element.elements['clean'].text if
522
- element.elements['clean']
523
- return exif
524
- end
525
- end
526
-
527
- class Flickr::PhotoList < Array
528
- attr_reader :page,:pages,:perpage,:total
529
-
530
- def initialize(page,pages,perpage,total)
531
- @page = page
532
- @pages = pages
533
- @perpage = perpage
534
- @total = total
535
- end
536
-
537
- def self.from_xml(xml,flickr=self)
538
- att = xml.root.attributes
539
- list = Flickr::PhotoList.new(att['page'].to_i,att['pages'].to_i,
540
- att['perpage'].to_i,att['total'].to_i)
541
- xml.elements['/photos'].each_element do |e|
542
- list << Flickr::Photo.from_xml(e,flickr)
543
- end
544
- return list
545
- end
546
- end
547
-
548
- class Flickr::Category
549
- attr_reader :name, :path, :pathids, :groups, :subcats, :id
550
-
551
- def initialize(name,path,pathids)
552
- @name = name
553
- @path = path
554
- @pathids = pathids
555
- @groups = []
556
- @subcats = []
557
- @id = pathids.split('/').last
558
- end
559
- end
560
-
561
- class Flickr::SubCategory
562
- attr_reader :name, :id, :count
563
-
564
- def initialize(name,id,count)
565
- @name = name
566
- @id = id
567
- @count = count
568
- end
569
- end
570
-
571
- class Flickr::Group
572
- # The privacy attribute is 1 for private groups, 2 for invite-only public
573
- # groups and 3 for open public groups.
574
- PRIVACY = [nil,:private,:invite,:public]
575
-
576
- attr_accessor :nsid, :name, :members, :online, :chatnsid, :inchat,
577
- :description, :privacy, :eighteenplus, :fully_fetched, :admin,
578
- :photo_count, :iconserver
579
-
580
- def initialize(flickr,nsid, name=nil, members=nil, online=nil,
581
- chatnsid=nil, inchat=nil)
582
- @flickr = flickr
583
- @nsid = nsid
584
- @name = name
585
- @members = members
586
- @online = online
587
- @chatnsid = chatnsid
588
- @inchat = inchat
589
- @fully_fetched = false
590
- end
591
-
592
- def full_info
593
- self.fully_fetched ? self : @flickr.groups.getInfo(self)
594
- end
595
- end
596
-
597
- class Flickr::GroupList < Array
598
- attr_reader :page,:pages,:perpage,:total
599
-
600
- def initialize(page,pages,perpage,total)
601
- @page = page
602
- @pages = pages
603
- @perpage = perpage
604
- @total = total
605
- end
606
- end
607
-
608
- class Flickr::Context
609
- attr_reader :prev_id,:prev_secret,:prev_title,:prev_url,
610
- :next_id,:next_secret,:next_title,:next_url
611
-
612
- def initialize(prev_id,prev_secret,prev_title,prev_url,
613
- next_id,next_secret,next_title,next_url)
614
- @prev_id = prev_id
615
- @prev_secret = prev_secret
616
- @prev_title = prev_title
617
- @prev_url = prev_url
618
- @next_id = next_id
619
- @next_secret = next_secret
620
- @next_title = next_title
621
- @next_url = next_url
622
- end
623
-
624
- def self.from_xml(xml)
625
- a0 = xml.elements['prevphoto'].attributes
626
- a1 = xml.elements['nextphoto'].attributes
627
- return Flickr::Context.new(
628
- a0['id'],a0['secret'],a0['title'],a0['url'],
629
- a1['id'],a1['secret'],a1['title'],a1['url'])
630
- end
631
- end
632
-
633
- class Flickr::License
634
- attr_reader :id, :name, :url
635
- def initialize(id,name,url)
636
- @id = id
637
- @name = name
638
- @url = url
639
- end
640
-
641
- def self.from_xml(xml)
642
- att = xml.attributes
643
- return Flickr::License.new(att['id'],att['name'],
644
- att['url'])
645
- end
646
- end
647
-
648
- class Flickr::Note
649
- attr_accessor :photo, :x, :y, :w, :h, :text, :id, :author_id
650
- def initialize(x, y, w, h, text, flickr = nil)
651
- @x = x
652
- @y = y
653
- @w = w
654
- @h = h
655
- @text = text
656
- @flickr = flickr
657
- end
658
-
659
- def author() @author_id && @flickr.people.getInfo(@author_id) end
660
-
661
- def self.from_xml(xml,photo=nil)
662
- att = xml.attributes
663
- note = Flickr::Note.new(att['x'].to_i,att['y'].to_i,
664
- att['w'].to_i,att['h'].to_i,xml.text,
665
- photo && photo.flickr)
666
- note.photo = photo
667
- note.id = att['id']
668
- note.author_id = att['author'] if att['author']
669
- end
670
- end
671
-
672
- class Flickr::Count
673
- attr_reader :fromdate, :todate, :count
674
- def initialize(count,fromdate,todate)
675
- @count = count
676
- @fromdate = fromdate
677
- @todate = todate
678
- end
679
-
680
- def self.from_xml(xml)
681
- att = xml.attributes
682
- return Flickr::Count.new(att['count'].to_i,
683
- Time.at(att['fromdate'].to_i),
684
- Time.at(att['todate'].to_i))
685
- end
686
- end
687
-
688
- class Flickr::Tag
689
- attr_reader :id, :author_id, :raw, :clean
690
-
691
- def initialize(flickr, id,author_id,raw,clean)
692
- @flickr = flickr
693
- @id = id
694
- @author_id = author_id
695
- @raw = raw
696
- @clean = clean
697
- end
698
-
699
- def author() @flickr.people.getInfo(@author_id) end
700
-
701
- def self.from_xml(xml,flickr=nil)
702
- att = xml.attributes
703
- clean = xml.text
704
- return Flickr::Tag.new(flickr,att['id'],att['author'],
705
- att['raw'], clean)
706
- end
707
- end
708
-
709
- class Flickr::PhotoSet < Array
710
- attr_accessor :id, :title, :url, :server, :primary_id,
711
- :photo_count, :description, :secret, :owner
712
-
713
- def initialize(id,flickr)
714
- @id = id
715
- @flickr = flickr
716
- end
717
-
718
- def <<(photo,raw=false)
719
- raw ? super(photo) : @flickr.photosets.addPhoto(self,photo)
720
- return self
721
- end
722
-
723
- def fetch(extras=nil)
724
- return self if @fetched
725
- set = @flickr.photosets.getPhotos(self,extras)
726
- @fetched = true
727
- return set
728
- end
729
-
730
- alias photos fetch
731
-
732
- def self.from_xml(xml,flickr=nil)
733
- att = xml.attributes
734
- psid = att['id']
735
-
736
- set = flickr.photoset_cache_lookup(psid) if flickr
737
- set ||= Flickr::PhotoSet.new(psid,flickr)
738
-
739
- set.secret = att['secret']
740
- set.owner = att['owner']
741
- set.url = att['url']
742
- set.server = att['server'].to_i
743
- set.primary_id = att['primary'].to_i
744
- set.photo_count = att['photos'].to_i
745
- set.title = xml.elements['title'].text if xml.elements['title']
746
- set.description = xml.elements['description'].text if
747
- xml.elements['description']
748
- if xml.elements['photo']
749
- set.clear
750
- xml.elements.each('photo') do |el|
751
- set.<<(Flickr::Photo.from_xml(el,flickr),true)
752
- end
753
- end
754
-
755
- flickr.photoset_cache_store(set) if flickr
756
- return set
757
- end
758
-
759
- def url
760
- owner = @owner || @flickr.photosets.getInfo(self).owner
761
- return "http://www.flickr.com/photos/#{owner}/sets/#{@id}"
762
- end
763
-
764
- def primary() @primary ||= @flickr.photos.getInfo(@primary_id) end
765
- end
766
-
767
- class Flickr::PhotoPool < Array
768
- attr_accessor :page, :pages, :perpage, :total, :title, :id
769
-
770
- def initialize(id,flickr)
771
- @id = id
772
- @flickr = flickr
773
- end
774
-
775
- def <<(photo,raw=false)
776
- raw ? super(photo) : @flickr.photosets.addPhoto(self,photo)
777
- return self
778
- end
779
-
780
- def fetch(extras=nil)
781
- return self if @fetched
782
- pool = @flickr.groups.pools.getPhotos(self,nil,extras,500)
783
- @fetched = true
784
- return pool
785
- end
786
-
787
- def self.from_xml(xml,flickr=nil)
788
- att = xml.attributes
789
- ppid = att['id']
790
-
791
- pool = flickr.photopool_cache_lookup(ppid)
792
- pool ||= Flickr::PhotoPool.new(ppid,flickr)
793
-
794
- pool.page = att['page'].to_i if att['page']
795
- pool.pages = att['pages'].to_i if att['pages']
796
- pool.perpage = att['perpage'].to_i if att['perpage']
797
- pool.total = att['total'].to_i if att['total']
798
- if xml.elements['photo']
799
- # I'd like to clear the pool, but I can't because I don't know if I'm
800
- # parsing the full set or just a single "page".
801
- # pool.clear
802
- xml.elements.each('photo') do |el|
803
- pool.<<(Flickr::Photo.from_xml(el,flickr),true)
804
- end
805
- end
806
-
807
- flickr.photopool_cache_store(pool) if flickr
808
- return pool
809
- end
810
- end