Ruby API for Flickr
IMPORTANT: This is an older version of the Ruby API for Flickr. The stuff has moved here: http://rubyforge.org/projects/libyws
You can grab the latest copy from CVS: http://rubyforge.org/cgi-bin/viewvc.cgi/flickr/?root=libyws
#!/usr/local/bin/ruby
##
# Ruby API for Flickr (See http://www.flickr.com/services/api/)
# (C) 2005 Premshree Pillai
# http://www.livejournal.com/~premshree
#
# EXAMPLES:
#
# user = User.new('18645779@N00')
# user.getPhotosets
#
# photoset = Photoset.new('4784077', '', '4784077')
#
# photoset.create(Photo.new('4784077'), 'Test set')
#
# group = Photo.new('6714892')
# group.tags_getListPhoto
#
# user = Search.new('18645779@N00')
# user.photosSearch(['bombay', 'bangalore'])
#
# people = Search.new
# people.people_getPublicPhotos('44124329962@N01')
#
# people = Search.new
# people.favorites_getList('44124329962@N01')
#
# HISTORY:
#
# 0.2 [2005-03-27]: Added Upload class
# 0.1 [2005-03-21]: Initial release
#
# see code to understand stuff
##
__AUTHOR__ = "Premshree Pillai"
__VERSION__ = "0.1"
__DATE__ = "2005-03-27 04:13"
require 'cgi'
require 'md5'
require 'net/http'
require 'rexml/document'
include REXML
$HOST = 'http://flickr.com'
$API = '/services/rest'
$API_KEY = 'YOUR-API-KEY'
$email = 'YOUR-EMAIL'
$password = 'YOUR-PASSWORD'
##
# Represents a Flickr Photo
##
class Photo
def initialize(id, owner=nil, dateuploaded=nil, \
title=nil, description=nil, ispublic=nil, \
isfriend=nil, isfamily=nil, cancomment=nil, \
canaddmeta=nil, comments=nil, tags=nil)
@__id = id
@__owner = owner
@__dateuploaded = dateuploaded
@__title = title
@__description = description
@__ispublic = ispublic
@__isfriend = isfriend
@__isfamily = isfamily
@__cancomment = cancomment
@__canaddmeta = canaddmeta
@__comments = comments
@__tags = tags
end
def _get_attr_id
@__id
end
##
# Loads the properties from Flickr
##
def _load_properties
method = 'flickr.photos.getInfo'
data = _doget(method, false, {'photo_id' => @__id})
doc = Document.new(data)
p = []
doc.elements.each('rsp/photo') { |photo|
@__dateuploaded = photo.attributes['dateuploaded']
owner = photo.elements['owner']
@__owner = User.new(owner.attributes['nsid'],\
username=owner.attributes['username'],\
realname=owner.attributes['realname'],\
location=owner.attributes['location'])
@__title = photo.elements['title'].text
@__description = photo.elements['description'].text
@__ispublic = photo.elements['visibility'].attributes['ispublic']
@__isfriend = photo.elements['visibility'].attributes['isfriend']
@__isfamily = photo.elements['visibility'].attributes['isfamily']
@__ispublic = photo.elements['editability'].attributes['cancomment']
@__canaddmeta = photo.elements['editability'].attributes['canaddmeta']
@__comments = photo.elements['comments'].text
@__permcomment = photo.elements['permissions'].attributes['permcomment']
@__permaddmeta = photo.elements['permissions'].attributes['permaddmeta']
@__tags = []
photo.elements.each('tags/tag') { |tag|
@__tags << tag.text
}
}
end
##
# Set the tags for current photo to list tags
# (will delete any existing tags)
##
def setTags(tags)
method = 'flickr.photos.setTags'
tags = tags.uniq
_doget(method, auth=true, {'photo_id'=>@__id, 'tags'=>tags})
@__tags = tags
end
##
# Add more tags to photo
##
def addTags(tags)
method = 'flickr.photos.addTags'
tags = tags.uniq
_doget(method, auth=true, {'photo_id'=>@__id, 'tags'=>tags})
_load_properties
tags.each { |tag| @__tags << tag }
end
##
# Set metadata to photo
##
def setMeta(title=nil, description=nil)
method = 'flickr.photos.setMeta'
if title == nil
title = self.title
end
if description == nil
description = self.description
end
_doget(method, auth=true, {'title'=>title, \
'description'=>description, 'photo_id'=>@__id})
@__title = title
@__description = description
end
##
# Retrieves a url for the photo
# urlType - 'url' or 'source'
# 'url' - flickr page of photo
# 'source' - image file
##
def getURL(size='Medium', urlType='url')
method = 'flickr.photos.getSizes'
data = _doget(method, false, {'photo_id'=>@__id})
doc = Document.new(data)
p = []
doc.elements.each('rsp/sizes/size') { |x|
if x.attributes['label'] == size
return x.attributes['url']
end
}
end
##
# Returns a list of tags for a photo
##
def tags_getListPhoto
method = 'flickr.tags.getListPhoto'
data = _doget(method, false, {'photo_id'=>@__id})
doc = Document.new(data)
tags = []
doc.elements.each('rsp/photo/tags/tag') { |tag|
tags << tag.text
}
tags
end
end
##
# A Flickr photoset
##
class Photoset
def initialize(id, title, primary, photos=0, description='')
@__id = id
@__title = title
@__primary = primary
@__description = description
@__n = photos
end
##
# Returns a list of photos for a Photoset
##
def getPhotos
method = 'flickr.photosets.getPhotos'
data = _doget(method, false, {'photoset_id' => @__id})
doc = Document.new(data)
p = []
doc.elements.each('rsp/photoset/photo') { |x|
p << x.attributes['id']
}
end
##
# Edit the photos in a set
# photos - photos for set
# primary - primary photo (if None will used current)
##
def editPhotos(photos, primary=nil)
method = 'flickr.photosets.editPhotos'
if primary == nil
primary = @__primary
end
ids = photos.join(',')
if !ids.include? primary.id
ids << primary.id
end
_doget(method, auth=true, {'photoset_id'=>@__id,\
'primary_photo_id'=>'primary.id', 'photo_ids'=>ids})
@__n = ids.length
end
##
# Create a new photoset
# photo - primary photo
##
def create(photo, title, description='')
if photo.class != Photo
print "TypeError, Photo expected"
exit
end
method = 'flickr.photosets.create'
data = _doget(method, auth=true, {'title'=>title,\
'description'=>description,\
'primary_photo_id'=>photo._get_attr_id})
end
end
##
# A Flickr User
##
class User
def initialize(id, username=nil, isadmin=nil, ispro=nil, \
realname=nil, location=nil, firstdate=nil, count=nil)
@__id = id
@__username = username
@__isadmin = isadmin
@__ispro = ispro
@__realname = realname
@__location = location
@__photos_firstdate = firstdate
@__photos_count = count
end
def _load_properties
method = 'flickr.people.getInfo'
data = _doget(method, false, {'user_id' => @__id})
doc = Document.new(data)
person = doc.elements['rsp'].elements['person']
@__isadmin = person.attributes['isadmin']
@__ispro = person.attributes['ispro']
@__username = person.elements['username'].text
@__realname = person.elements['realname'].text
@__location = person.elements['location'].text
@__photos_firstdate = person.elements['photos'].elements['firstdate'].text
@__photos_count = person.elements['photos'].elements['count'].text
end
##
# Returns a list of Photosets
##
def getPhotosets
method = 'flickr.photosets.getList'
data = _doget(method, false, {'user_id' => @__id})
sets = []
doc = Document.new(data)
doc.elements.each('rsp/photosets/photoset') { |photoset|
id = photoset.attributes['id']
title = photoset.elements['title'].text
primary = photoset.attributes['primary']
description = photoset.elements['description'].text
photos = photoset.attributes['photos']
sets << Photoset.new(id, title, Photo.new(primary), description,\
photos)
}
sets
end
##
# Returns a list of tags for a userid
##
def tags_getListUser
method = 'flickr.tags.getListUser'
data = _doget(method, false, {'photo_id'=>@__id})
doc = Document.new(data)
tags = []
doc.elements.each('rsp/who/tags/tag') { |tag|
tags << tag.text
}
tags
end
end
##
# Upload
##
class Upload
def initialize
@flickr_host = 'www.flickr.com'
@upload_action = '/tools/uploader_go.gne'
@boundary = ''
end
def _to_multipart(name, value)
return "Content-Disposition: form-data; name=\"#{CGI::escape(name)}\"\r\n\r\n#{value}\r\n"
end
def _file_to_multipart(name, file, content)
return "Content-Disposition: form-data; name=\"#{CGI::escape(name)}\"; filename=\"#{file}\"\r\n" +
"Content-Transfer-Encoding: binary\r\n" +
"Content-Type: image/jpeg\r\n\r\n" + content + "\r\n"
end
def _prepare_query(params)
query = params.collect { |k, v|
if v.respond_to?(:read)
q = _file_to_multipart(k, v.path, v.read)
else
q = _to_multipart(k, v)
end
"--" + @boundary + "\r\n" + q
}.join("") + "--" + @boundary + "--"
header = {"Content-type" => "multipart/form-data, boundary=" + @boundary + " "}
return query, header
end
##
# Upload a photo to Flickr
# returns a Photo object
# returns o on error
##
def upload(photo, title='', description='', tags=[], is_public=1,\
is_friend=0, is_family=0)
@boundary = MD5.md5(photo).to_s
file = File.new(photo, 'rb')
params = {
"email" => $email,
"password" => $password,
"photo" => file,
"title" => title,
"description" => description,
"tags" => tags.join(","),
"is_public" => is_public,
"is_friend" => is_friend,
"is_family" => is_family
}
query, header = _prepare_query(params)
file.close
Net::HTTP.start(@flickr_host, 80) { |http|
response = http.post(@upload_action, query, header)
doc = Document.new(response.body)
status = doc.elements['uploader/status'].text
if status == "ok"
photoid = doc.elements['uploader/photoid'].text
Photo.new(photoid, nil, nil, title=title, description=description,\
ispublic=ispublic, isfriend=isfriend,\
isfamily=isfamily)
else
0
end
}
end
end
##
# Flickr Group
##
class Group
def initialize(id, name=nil, members=nil, online=nil, privacy=nil,\
chatid=nil, chatcount=nil)
@__id = id
@__name = name
@__members = members
@__online = online
@__privacy = privacy
@__chatid = chatid
@__chatcount = chatcount
end
def _load_properties()
# Loads the properties from Flickr
method = 'flickr.groups.getInfo'
data = _doget(method, false, {'group_id'=>@__id})
doc = Document.new(data)
group = doc.elements['rsp'].elements['group']
@__name = group.elements['name'].text
@__members = group.elements['members'].text
@__online = group.elements['online'].text
@__privacy = group.elements['privacy'].text
@__chatid = group.elements['chatid'].text
@__chatcount = group.elements['chatid'].text
p @__chatid
end
##
# Get a list of photo objects for this group
##
def getPhotos(tags=[], per_page='', page='')
tags = tags.join(',')
method = 'flickr.groups.pools.getPhotos'
data = _doget(method, false, {'group_id'=>@__id, 'tags'=>tags,\
'per_page'=>per_page, 'page'=>page})
p = []
doc = Document.new(data)
doc.elements.each('rsp/photos/photo') { |photo|
id = photo.attributes['id']
owner = photo.attributes['owner']
title = photo.attributes['title']
ispublic = photo.attributes['ispublic']
isfriend = photo.attributes['isfriend']
isfamily = photo.attributes['isfamily']
photo_obj = Photo.new(id, owner=owner, title=title,\
ispublic=ispublic, isfriend=isfriend,\
isfamily=isfamily)
p << photo_obj
}
p
end
end
##
# Methods to search
##
class Search
def initialize(id='')
@__id = id
end
def tags_getListUserPopular(id='', count='')
method = 'flickr.tags.getListUserPopular'
data = _doget(method, false, {'user_id'=>id, 'count'=>count})
data = _doget(method, false, {'photo_id'=>@__id})
doc = Document.new(data)
tags = []
doc.elements.each('rsp/who/tags/tag') { |tag|
tags << tag.text
}
tags
end
##
# Returns a list of Photo objects.
# If auth=true then will load private pics, etc.
##
def photosSearch(user_id='', auth=false, tags=[], tag_mode='',\
text='',min_upload_date='', max_upload_date='',\
per_page='', page='')
tags = tags.join(',')
method = 'flickr.photos.search'
data = _doget(method, auth=auth, {'user_id'=>user_id, 'tags'=>tags,\
'text'=>text, 'min_upload_date'=>min_upload_date,\
'max_upload_date'=>max_upload_date, 'per_page'=>per_page,\
'page'=>page})
p = []
doc = Document.new(data)
doc.elements.each('rsp/photos/photo') { |photo|
id = photo.attributes['id']
owner = photo.attributes['owner']
title = photo.attributes['title']
ispublic = photo.attributes['ispublic']
isfriend = photo.attributes['isfriend']
isfamily = photo.attributes['isfamily']
photo_obj = Photo.new(id, owner=owner, title=title,\
ispublic=ispublic, isfriend=isfriend,\
isfamily=isfamily)
p << photo_obj
}
p
end
##
# Returns a User object for given email
##
def people_findByEmail(email)
method = 'flickr.people.findByEmail'
data = _doget(method, false, {'find_email'=>email})
doc = Document.new(data)
user = doc.elements['rsp/user']
user = User.new(user.attributes['id'], username=user.elements['username'].text)
user
end
##
# Returns a User object for given username
##
def people_findByUsername(username)
method = 'flickr.people.findByUsername'
data = _doget(method, false, {'username'=>username})
doc = Document.new(data)
user = doc.elements['rsp/user']
user = User.new(user.attributes['id'], username=user.elements['username'].text)
user
end
##
# Returns a list of public photos for userid, as Photo objects
##
def people_getPublicPhotos(user_id, per_page='', page='')
method = 'flickr.people.getPublicPhotos'
data = _doget(method, false, {'user_id'=>user_id,\
'per_page'=>per_page, 'page'=>page})
p = []
doc = Document.new(data)
doc.elements.each('rsp/photos/photo') { |photo|
id = photo.attributes['id']
owner = photo.attributes['owner']
title = photo.attributes['title']
ispublic = photo.attributes['ispublic']
isfriend = photo.attributes['isfriend']
isfamily = photo.attributes['isfamily']
photo_obj = Photo.new(id, owner=owner, title=title,\
ispublic=ispublic, isfriend=isfriend,\
isfamily=isfamily)
p << photo_obj
}
p
end
##
# Returns a list of favorite photos for userid, as Photo objects
##
def favorites_getList(user_id='', per_page='', page='')
# Returns list of Photo objects
method = 'flickr.favorites.getList'
data = _doget(method, auth=true, {'user_id'=>user_id,\
'per_page'=>per_page, 'page'=>page})
p = []
doc = Document.new(data)
doc.elements.each('rsp/photos/photo') { |photo|
id = photo.attributes['id']
owner = photo.attributes['owner']
title = photo.attributes['title']
ispublic = photo.attributes['ispublic']
isfriend = photo.attributes['isfriend']
isfamily = photo.attributes['isfamily']
photo_obj = Photo.new(id, owner=owner, title=title,\
ispublic=ispublic, isfriend=isfriend,\
isfamily=isfamily)
p << photo_obj
}
p
end
end
##
# JLT
##
def login
method = 'flickr.test.login'
data = _doget(method, auth=true)
doc = Document.new(data)
user = doc.elements['rsp/user']
user = User.new(user.attributes['id'],\
username=user.elements['username'].text)
user
end
def test_echo
method = 'flickr.test.echo'
data = _doget(method, false)
doc = Document.new(data)
doc.elements['rsp'].attributes['stat']
end
##
# methods for use within the classes
##
def _doget(method, auth=false, *params)
params.each { |x, y|
if y.class == Array then params[x] = y.join(y) end
}
url = "#{$HOST}#{$API}/?api_key=#{$API_KEY}&method=#{method}#{_urlencode(params)}"
if auth then url = url + "&email=#{$email}&password=#{$password}" end
p url
resp = Net::HTTP.get_response(URI.parse(url))
doc = Document.new(resp.body.to_s)
if doc.elements['rsp'].attributes['stat'] != 'ok'
error_code = doc.elements['rsp'].elements['err'].attributes['code']
error_msg = doc.elements['rsp'].elements['err'].attributes['msg']
msg = "ERROR[#{error_code}]: #{error_msg}"
end
resp.body.to_s
end
def _urlencode(params)
ret = ''
params.each { |param|
param.each { |x, y|
ret += "{x}=#{y}"
}
}
ret
end