r2flickr 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ require 'flickr/base'
2
+
3
+ class Flickr::PhotoSets < Flickr::APIBase
4
+ # photoset can be a PhotoSet or a a photoset id
5
+ # photo can be a Photo or a photo id
6
+ def addPhoto(photoset,photo)
7
+ photo = photo.id if photo.class == Flickr::Photo
8
+ photoset = photoset.id if photoset.class == Flickr::PhotoSet
9
+
10
+ @flickr.call_method('flickr.photosets.addPhoto',
11
+ 'photoset_id' => photoset, 'photo_id' => photo)
12
+ end
13
+
14
+ def create(title,primary_photo, description = nil)
15
+ primary_photo = primary_photo.id if
16
+ primary_photo.class == Flickr::Photo
17
+ args = { 'title' => title, 'primary_photo_id' => primary_photo }
18
+ args['description'] = description if description
19
+ res = @flickr.call_method('flickr.photosets.create',args)
20
+ id = res.elements['/photoset'].attributes['id']
21
+ url = res.elements['/photoset'].attributes['url']
22
+ set = Flickr::PhotoSet.new(id,@flickr)
23
+ set.title = title
24
+ set.url = url
25
+ @flickr.photoset_cache_store(set)
26
+ return set
27
+ end
28
+
29
+ def delete(photoset)
30
+ photoset = photoset.id if photoset.class == Flickr::PhotoSet
31
+ @flickr.call_method('flickr.photosets.delete',
32
+ 'photoset_id' => photoset)
33
+ end
34
+
35
+ def editMeta(photoset,title,description=nil)
36
+ photoset = photoset.id if photoset.class == Flickr::PhotoSet
37
+ args = {'photoset_id' => photoset, 'title' => title}
38
+ args['description' ] = description if description
39
+ @flickr.call_method('flickr.photosets.editMeta',args)
40
+ end
41
+
42
+ def editPhotos(photoset,primary_photo,photos)
43
+ photoset = photoset.id if photoset.class == Flickr::PhotoSet
44
+ primary_photo = primary_photo.id if
45
+ primary_photo.class == Flickr::Photo
46
+ photos=photos.map{|p| p.id if p.class==Flickr::Photo}.join(',')
47
+ args = {'photoset_id' => photoset,
48
+ 'primary_photo_id' => primary_photo,
49
+ 'photo_ids' => photos }
50
+ @flickr.call_method('flickr.photosets.editPhotos',args)
51
+ end
52
+
53
+ def getContext(photo,photoset)
54
+ photoset = photoset.id if photoset.class == Flickr::PhotoSet
55
+ photo = photo.id if photo.class == Flickr::Photo
56
+ res = @flickr.call_method('flickr.photosets.getContext',
57
+ 'photo_id' => photo, 'photoset_id' => photoset)
58
+ return Flickr::Context.from_xml(res,@flickr)
59
+ end
60
+
61
+ def getList(user=nil)
62
+ user = user.nsid if user.respond_to?(:nsid)
63
+ args = {}
64
+ args['user_id'] = user if user
65
+ res = @flickr.call_method('flickr.photosets.getList',args)
66
+ list = []
67
+ res.elements['/photosets'].each_element do |el|
68
+ list << Flickr::PhotoSet.from_xml(el,@flickr)
69
+ end
70
+ return list
71
+ end
72
+
73
+ def removePhoto(photoset,photo)
74
+ photoset = photoset.id if photoset.class == Flickr::PhotoSet
75
+ photo = photo.id if photo.class == Flickr::Photo
76
+ @flickr.call_method('flickr.photosets.removePhoto',
77
+ 'photo_id' => photo, 'photoset_id' => photoset)
78
+ end
79
+
80
+ def getPhotos(photoset,extras=nil)
81
+ photoset = photoset.id if photoset.class == Flickr::PhotoSet
82
+ extras = extras.join(',') if extras.class == Array
83
+ args = { 'photoset_id' => photoset }
84
+ args['extras'] = extras if extras
85
+ res = @flickr.call_method('flickr.photosets.getPhotos',args)
86
+ return Flickr::PhotoSet.from_xml(res.root,@flickr)
87
+ end
88
+
89
+ def getInfo(photoset)
90
+ photoset = photoset.id if photoset.class == Flickr::PhotoSet
91
+ res = @flickr.call_method('flickr.photosets.getInfo',
92
+ 'photoset_id' => photoset)
93
+ return Flickr::PhotoSet.from_xml(res.root,@flickr)
94
+ end
95
+
96
+ def orderSets(photosets)
97
+ photosets=photosets.map { |ps|
98
+ (ps.class==Flickr::PhotoSet) ? ps.id : ps}.join(',')
99
+ @flickr.call_method('flickr.photosets.orderSets',
100
+ 'photoset_ids' => photosets)
101
+ end
102
+ end
@@ -0,0 +1,73 @@
1
+ require 'flickr/groups'
2
+
3
+ class Flickr::Pools < Flickr::APIBase
4
+
5
+ def initialize(flickr,groups)
6
+ super(flickr)
7
+ @groups = groups
8
+ end
9
+
10
+ # photo can be a Photo or photo_id
11
+ # group can be a Group or group_id
12
+ def add(photo,group)
13
+ group = group.nsid if group.class == Flickr::Group
14
+ photo = photo.id if photo.class == Flickr::Photo
15
+ @flickr.call_method('flickr.groups.pools.add',
16
+ 'group_id' => group, 'photo_id' => photo)
17
+ end
18
+
19
+ # photo can be a Photo or photo_id
20
+ # group can be a Group or group_id
21
+ def remove(photo,group)
22
+ group = group.nsid if group.class == Flickr::Group
23
+ photo = photo.id if photo.class == Flickr::Photo
24
+ @flickr.call_method('flickr.groups.pools.add',
25
+ 'group_id' => group, 'photo_id' => photo)
26
+ end
27
+
28
+ # photo can be a Photo or photo_id
29
+ # group can be a Group or group_id
30
+ def getContext(photo,group)
31
+ group = group.nsid if group.class == Flickr::Group
32
+ photo = photo.id if photo.class == Flickr::Photo
33
+ res = @flickr.call_method('flickr.groups.pools.getContex',
34
+ 'group_id' => group, 'photo_id' => photo)
35
+ return Flickr::Context.from_xml(res)
36
+ end
37
+
38
+ def getGroups
39
+ res = @flickr.call_method('flickr.groups.pools.getGroups')
40
+ list = []
41
+
42
+ res.elements['/groups'].each_element do |el|
43
+ att = el.attributes
44
+ nsid = att['nsid']
45
+ g = @flickr.group_cache_lookup(nsid) ||
46
+ Flickr::Group.new(@flickr,nsid,att['name'])
47
+ g.name = att['name']
48
+ g.admin = att['admin'].to_i == 1
49
+ g.privacy = Flickr::Group::PRIVACY[att['privacy'].to_i]
50
+ g.photo_count = att['photos'].to_i
51
+ g.iconserver = att['iconserver'].to_i
52
+
53
+ @flickr.group_cache_store(g)
54
+ list << g
55
+ end
56
+
57
+ return list
58
+ end
59
+
60
+ def getPhotos(group,tags=nil,extras=nil,per_page=nil,page=nil)
61
+ group = group.nsid if group.class == Flickr::Group
62
+ group = group.id.to_s if group.class == Flickr::PhotoPool
63
+ args = { 'group_id' => group }
64
+ args['tags'] = tags.map{|t| t.clean if t.class ==
65
+ Flick::Tag}.join(',') if tags
66
+ args['extras'] = extras.join(',') if extras.class == Array
67
+ args['per_page'] = per_page if per_page
68
+ args['page'] = page if page
69
+
70
+ res = @flickr.call_method('flickr.groups.pools.getPhotos', args)
71
+ return Flickr::PhotoList.from_xml(res,@flickr)
72
+ end
73
+ end
@@ -0,0 +1,89 @@
1
+ require 'flickr/base'
2
+
3
+ class Flickr::Method
4
+ attr_reader :name, :authenticated, :description, :response, :explanation,
5
+ :arguments, :errors
6
+
7
+ def initialize(name,authenticated,description,response,explanation)
8
+ @name = name
9
+ @authenticated = authenticated
10
+ @description = description
11
+ @response = response
12
+ @explanation = explanation
13
+ @arguments = []
14
+ @errors = []
15
+ end
16
+ end
17
+
18
+ class Flickr::MethodArgument
19
+ attr_reader :name, :optional, :description
20
+
21
+ def initialize(name,optional,description)
22
+ @name = name
23
+ @optional = optional
24
+ @description = description
25
+ end
26
+ end
27
+
28
+ class Flickr::Reflection < Flickr::APIBase
29
+ # We don't bother with caching because it's not worth it for the
30
+ # reflection API.
31
+ def getMethodInfo(method_name)
32
+ res = @flickr.call_method('flickr.reflection.getMethodInfo',
33
+ 'method_name' => method_name)
34
+ els = res.elements
35
+ att = res.root.attributes
36
+ desc = els['/method/description'] ?
37
+ els['/method/description'].text : nil
38
+ resp = els['/method/response'] ?
39
+ els['/method/response'].text : nil
40
+ expl = els['/method/explanation'] ?
41
+ els['/method/explanation'].text : nil
42
+ meth = Flickr::Method.new(att['name'],att['needslogin'].to_i==1,
43
+ desc,resp,expl)
44
+ els['/method/arguments'].each_element do |el|
45
+ att = el.attributes
46
+ arg = Flickr::MethodArgument.new(att['name'],
47
+ att['optional'].to_i == 1,el.text)
48
+ meth.arguments << arg
49
+ end
50
+ els['/method/errors'].each_element do |el|
51
+ att = el.attributes
52
+ err = XMLRPC::FaultException.new(att['code'].to_i,
53
+ el.text)
54
+ meth.errors << err
55
+ end
56
+ return meth
57
+ end
58
+
59
+ def getMethods
60
+ res = @flickr.call_method('flickr.reflection.getMethods')
61
+ list = []
62
+ res.elements['/methods'].each_element do |el|
63
+ list << el.text
64
+ end
65
+ return list
66
+ end
67
+
68
+ def missing_methods
69
+ list = []
70
+ methods = self.getMethods
71
+ methods.each do |mname|
72
+ parts = mname.split('.')
73
+ parts.shift
74
+ call = parts.pop
75
+ obj = @flickr
76
+ parts.each do |part|
77
+ if obj.respond_to?(part)
78
+ obj = obj.method(part).call
79
+ else
80
+ obj = nil
81
+ list << mname
82
+ break
83
+ end
84
+ end
85
+ list << mname if (obj && !obj.respond_to?(call))
86
+ end
87
+ return list
88
+ end
89
+ end
@@ -0,0 +1,59 @@
1
+ require 'flickr/base'
2
+
3
+ class Flickr::Tags < Flickr::APIBase
4
+ def getListPhoto(photo)
5
+ photo = photo.id if photo.class == Flickr::Photo
6
+ res = @flickr.call_method('flickr.tags.getListPhoto',
7
+ 'photo_id'=>photo)
8
+ xml = res.root
9
+ phid = xml.attributes['id']
10
+ photo = (photo.class == Flickr::Photo) ? photo :
11
+ (@flickr.photo_cache_lookup(phid) ||
12
+ Flickr::Photo.new(@flickr,phid))
13
+ if xml.elements['tags']
14
+ tags = []
15
+ xml.elements['tags'].each_element do |el|
16
+ tags << Flickr::Tag.from_xml(el,photo)
17
+ end
18
+ end
19
+ photo.tags = tags
20
+ return tags
21
+ end
22
+
23
+ def getListUserPopular(user,count = nil)
24
+ user = user.nsid if user.class == Flickr::Person
25
+ args = { 'user_id' => user }
26
+ args['count'] = count if count
27
+
28
+ res = @flickr.call_method('flickr.tags.getListUserPopular',args)
29
+ tags = {}
30
+ res.elements['/who/tags'].each_element do |tag|
31
+ att = tag.attributes
32
+ tags[tag.text]=att['count'].to_i
33
+ end
34
+ return tags
35
+ end
36
+
37
+ def getListUser(user)
38
+ user = user.nsid if user.class == Flickr::Person
39
+ args = { 'user_id' => user }
40
+
41
+ res = @flickr.call_method('flickr.tags.getListUser',args)
42
+ tags = []
43
+ res.elements['/who/tags'].each_element do |tag|
44
+ tags << tag.text
45
+ end
46
+ return tags
47
+ end
48
+
49
+ def getRelated(tag)
50
+ args = { 'tag' => tag }
51
+
52
+ res = @flickr.call_method('flickr.tags.getRelated',args)
53
+ tags = []
54
+ res.elements['/tags'].each_element do |tag|
55
+ tags << tag.text
56
+ end
57
+ return tags
58
+ end
59
+ end
@@ -0,0 +1,20 @@
1
+ require 'flickr/base'
2
+
3
+ class Flickr::Test < Flickr::APIBase
4
+
5
+ # This has to be a Hash
6
+ def echo(args)
7
+ return @flickr.call_method('flickr.test.echo',args)
8
+ end
9
+
10
+ def login
11
+ res = @flickr.call_method('flickr.test.login')
12
+ nsid = res.elements['/user'].attributes['id']
13
+ name = res.elements['/user/username'].text
14
+ p = @flickr.person_cache_lookup(nsid) ||
15
+ Flickr::Person.new(@flickr,nsid,name)
16
+ p.name = name
17
+ @flickr.person_cache_store(p)
18
+ return p
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ require 'flickr/base'
2
+
3
+ class Flickr::BaseTokenCache < Flickr::APIBase
4
+
5
+ def load_token
6
+ nil
7
+ end
8
+
9
+ def cache_token(token)
10
+ nil
11
+ end
12
+
13
+ end
14
+
15
+ class Flickr::FileTokenCache < Flickr::BaseTokenCache
16
+
17
+ def initialize(filename)
18
+ @cache_file = filename
19
+ end
20
+
21
+ def load_token
22
+ token = nil
23
+ File.open(@cache_file,'r'){ |f| token = f.read }
24
+ @token = Flickr::Token.from_xml(REXML::Document.new(token))
25
+ rescue Errno::ENOENT
26
+ nil
27
+ end
28
+
29
+ def cache_token(token)
30
+ File.open(@cache_file,'w'){ |f| f.write token.to_xml } if token
31
+ end
32
+
33
+ end
@@ -0,0 +1,11 @@
1
+ require 'flickr/base'
2
+
3
+ class Flickr::Transform < Flickr::APIBase
4
+
5
+ def rotate(photo,degrees)
6
+ photo = photo.id if photo.class == Flickr::Photo
7
+ @flickr.call_method('flickr.photos.transform.rotate',
8
+ 'photo_id' => photo, 'degrees' => degrees)
9
+ end
10
+
11
+ end
@@ -0,0 +1,205 @@
1
+ require 'flickr/base'
2
+ require 'mime/types'
3
+ require 'net/http'
4
+
5
+ class Flickr::Ticket
6
+
7
+ attr_reader :id
8
+ attr_accessor :complete, :invalid, :photoid
9
+
10
+ COMPLETE=[:incomplete,:completed,:failed]
11
+
12
+ def initialize(id,upload)
13
+ @id = id
14
+ @upload = upload
15
+ end
16
+
17
+ def check
18
+ t = @upload.checkTickets(self)[0]
19
+ self.complete = t.complete
20
+ self.invalid = t.invalid
21
+ self.photoid = t.photoid
22
+ return t
23
+ end
24
+ end
25
+
26
+ class Flickr::FormPart
27
+ attr_reader :data, :mime_type, :attributes
28
+
29
+ def initialize(name,data,mime_type=nil)
30
+ @attributes = {}
31
+ @attributes['name'] = name
32
+ @data = data
33
+ @mime_type = mime_type
34
+ end
35
+
36
+ def to_s
37
+ ([ "Content-Disposition: form-data" ] +
38
+ attributes.map{|k,v| "#{k}=\"#{v}\""}).
39
+ join('; ') + "\r\n"+
40
+ (@mime_type ? "Content-Type: #{@mime_type}\r\n" : '')+
41
+ "\r\n#{data}"
42
+ end
43
+ end
44
+
45
+ class Flickr::MultiPartForm
46
+ attr_accessor :boundary, :parts
47
+
48
+ def initialize(boundary=nil)
49
+ @boundary = boundary ||
50
+ "----------------------------Ruby#{rand(1000000000000)}"
51
+ @parts = []
52
+ end
53
+
54
+ def to_s
55
+ "--#@boundary\r\n" + parts.map{|p| p.to_s}.join("\r\n--#@boundary\r\n") +
56
+ "\r\n--#@boundary--\r\n"
57
+ end
58
+
59
+ end
60
+
61
+ class Flickr::Upload < Flickr::APIBase
62
+
63
+ # TODO: It would probably be better if we wrapped the fault
64
+ # in something more meaningful. At the very least, a broad
65
+ # division of errors, such as retryable and fatal.
66
+ def error(el)
67
+ att = el.attributes
68
+ fe = XMLRPC::FaultException.new(att['code'].to_i,
69
+ att['msg'])
70
+ $stderr.puts "ERR: #{fe.faultString} (#{fe.faultCode})"
71
+ raise fe
72
+ end
73
+
74
+ def prepare_parts(data,mimetype,filename,title=nil,description=nil,
75
+ tags=nil, is_public=nil,is_friend=nil,is_family=nil,
76
+ sig=nil, async=nil)
77
+ parts = []
78
+ parts << Flickr::FormPart.new('title',title) if title
79
+ parts << Flickr::FormPart.new('description',description) if
80
+ description
81
+ parts << Flickr::FormPart.new('tags',tags.join(',')) if tags
82
+ parts << Flickr::FormPart.new('is_public',
83
+ is_public ? '1' : '0') if is_public != nil
84
+ parts << Flickr::FormPart.new('is_friend',
85
+ is_friend ? '1' : '0') if is_friend != nil
86
+ parts << Flickr::FormPart.new('is_family',
87
+ is_family ? '1' : '0') if is_family != nil
88
+ parts << Flickr::FormPart.new('async',
89
+ async ? '1' : '0') if async != nil
90
+
91
+ parts << Flickr::FormPart.new('api_key',@flickr.api_key)
92
+ parts << Flickr::FormPart.new('auth_token',
93
+ @flickr.auth.token.token)
94
+ parts << Flickr::FormPart.new('api_sig',sig)
95
+
96
+ parts << Flickr::FormPart.new('photo',data,mimetype)
97
+ parts.last.attributes['filename'] = filename
98
+ return parts
99
+ end
100
+
101
+ def make_signature(title=nil,description=nil, tags=nil,
102
+ is_public=nil,is_friend=nil,is_family=nil,async=nil)
103
+ args = {'api_key' => @flickr.api_key,
104
+ 'auth_token' => @flickr.auth.token.token}
105
+ args['title'] = title if title
106
+ args['description'] = description if description
107
+ args['tags'] = tags.join(',') if tags
108
+ args['is_public'] = (is_public ? '1' : '0') if is_public != nil
109
+ args['is_friend'] = (is_friend ? '1' : '0') if is_friend != nil
110
+ args['is_family'] = (is_family ? '1' : '0') if is_family != nil
111
+ args['async'] = (async ? '1' : '0') if async != nil
112
+ args['api_sig'] = @flickr.sign(args)
113
+ end
114
+
115
+ def send_form(form)
116
+ headers = {"Content-Type" => "multipart/form-data; boundary=" + form.boundary}
117
+
118
+ http = Net::HTTP.new('www.flickr.com', 80)
119
+ # http.read_timeout = 900 # 15 minutes max upload time
120
+ tries = 3
121
+ begin
122
+ res=http.post('/services/upload/',form.to_s,headers)
123
+ rescue Timeout::Error => err
124
+ tries -= 1
125
+ $stderr.puts "Timed out, will retry #{tries} more."
126
+ retry if tries > 0
127
+ raise err
128
+ end
129
+ return res
130
+ end
131
+
132
+ def upload_file_async(filename,title=nil,description=nil,tags=nil,
133
+ is_public=nil,is_friend=nil,is_family=nil)
134
+ mt = MIME::Types.of(filename)
135
+ f = File.open(filename,'rb')
136
+ data = f.read
137
+ f.close
138
+ return upload_image_async(data,mt,filename,title,description,
139
+ tags, is_public,is_friend,is_family)
140
+ end
141
+
142
+
143
+ def upload_file(filename,title=nil,description=nil,tags=nil,
144
+ is_public=nil,is_friend=nil,is_family=nil)
145
+ mt = MIME::Types.of(filename)
146
+ f = File.open(filename,'rb')
147
+ data = f.read
148
+ f.close
149
+ return upload_image(data,mt,filename,title,description,tags,
150
+ is_public,is_friend,is_family)
151
+ end
152
+
153
+ def upload_image_async(data,mimetype,filename,title=nil,description=nil,
154
+ tags=nil, is_public=nil,is_friend=nil,is_family=nil)
155
+ form = Flickr::MultiPartForm.new
156
+
157
+ sig = make_signature(title,description, tags, is_public,
158
+ is_friend, is_family, true)
159
+ form.parts += prepare_parts(data,mimetype,filename,title,
160
+ description, tags, is_public, is_friend,
161
+ is_family, sig, true)
162
+ res = REXML::Document.new(send_form(form).body)
163
+ error(res.elements['/rsp/err']) if res.elements['/rsp/err']
164
+ t = Flickr::Ticket.new(res.elements['/rsp/ticketid'].text, self)
165
+ @flickr.ticket_cache_store(t)
166
+ return t
167
+ end
168
+
169
+ def upload_image(data,mimetype,filename,title=nil,description=nil,
170
+ tags=nil, is_public=nil,is_friend=nil,is_family=nil)
171
+ form = Flickr::MultiPartForm.new
172
+
173
+ sig = make_signature(title,description, tags, is_public,
174
+ is_friend, is_family)
175
+ form.parts += prepare_parts(data,mimetype,filename,title,
176
+ description, tags, is_public, is_friend,
177
+ is_family, sig)
178
+ res = REXML::Document.new(send_form(form).body)
179
+ error(res.elements['/rsp/err']) if res.elements['/rsp/err']
180
+ val = res.elements['/rsp/photoid'].text
181
+ return val
182
+ end
183
+
184
+ def checkTickets(tickets)
185
+ tickets = [tickets] if tickets.class != Array
186
+ targ = tickets.map{|t|
187
+ t.id.to_s if t.class == Flickr::Ticket }.join(',')
188
+ res = @flickr.call_method('flickr.photos.upload.checkTickets',
189
+ 'tickets' => targ)
190
+ tickets = []
191
+ res.elements['/uploader'].each_element('ticket') do |tick|
192
+ att = tick.attributes
193
+ tid = att['id']
194
+ t = @flickr.ticket_cache_lookup(tid) ||
195
+ Flickr::Ticket.new(tid,self)
196
+ t.complete = Flickr::Ticket::COMPLETE[att['complete'].to_i]
197
+ t.photoid = att['photoid']
198
+ t.invalid = true if (att['invalid'] &&
199
+ (att['invalid'].to_i == 1))
200
+ @flickr.ticket_cache_store(t)
201
+ tickets << t
202
+ end
203
+ return tickets
204
+ end
205
+ end