flickr.rb
上传用户:netsea168
上传日期:2022-07-22
资源大小:4652k
文件大小:15k
源码类别:

Ajax

开发平台:

Others

  1. # = Flickr
  2. #   An insanely easy interface to the Flickr photo-sharing service. By Scott Raymond.
  3. #   
  4. # Author::    Scott Raymond <sco@redgreenblu.com>
  5. # Copyright:: Copyright (c) 2005 Scott Raymond <sco@redgreenblu.com>
  6. # License::   MIT <http://www.opensource.org/licenses/mit-license.php>
  7. #
  8. # USAGE:
  9. #  require 'flickr'
  10. #  flickr = Flickr.new                           # create a flickr client
  11. #  user = flickr.users('sco@scottraymond.net')   # lookup a user
  12. #  user.getInfo.name                             # get the user's name
  13. #  user.location                                 # and location
  14. #  user.photos                                   # grab their collection of Photo objects...
  15. #  user.groups                                   # ...the groups they're in...
  16. #  user.contacts                                 # ...their contacts...
  17. #  user.favorites                                # ...favorite photos...
  18. #  user.photosets                                # ...their photo sets...
  19. #  user.tags                                     # ...and their tags
  20. #  recentphotos = flickr.photos                  # get the 100 most recent public photos
  21. #  photo = recent.first                          # or very most recent one
  22. #  photo.getInfo.url                             # see its URL,
  23. #  photo.title                                   # title,
  24. #  photo.description                             # and description,
  25. #  photo.owner                                   # and its owner.
  26. #  File.open(photo.filename, 'w') do |file|
  27. #    file.puts p.file                            # save the photo to a local file
  28. #  end
  29. #  flickr.photos.each do |p|                     # get the last 100 public photos...
  30. #    File.open(p.filename, 'w') do |f|
  31. #      f.puts p.file('Square')                   # ...and save a local copy of their square thumbnail
  32. #    end
  33. #  end
  34. # TODO:
  35. #  - convert dates to ruby Dates
  36. #  - investigate xmlsimple caching
  37. #  - make to_s methods automatic?
  38. #  - complete tests
  39. #  - in tests, implement a MockFlickr object that has stored responses. automate the getting of the responses?
  40. #  - test on a few platforms
  41. #  - seek feedback from somebody
  42. #  - make a kickass demo, including autocompleting-ajax photo lookup ala http://mir.aculo.us/images/autocomplete1.mov
  43. require 'cgi'
  44. require 'open-uri'
  45. # Flickr client class. Requires an API key, and optionally takes an email and password for authentication
  46. class Flickr
  47.   attr_accessor :user
  48.   # Replace this API key with your own (see http://www.flickr.com/services/api/misc.api_keys.html)
  49.   def initialize(api_key=FLICKR_KEY, email=nil, password=nil)
  50.     @api_key = api_key
  51.     @host = 'http://flickr.com'
  52.     @api = '/services/rest'
  53.     login(email, password) if email and password
  54.   end
  55.   # Takes a Flickr API method name and set of parameters; returns an XmlSimple object with the response
  56.   def request(method, *params)
  57.     response = XmlSimple.xml_in(http_get(request_url(method, params)), { 'ForceArray' => false })
  58.     raise response['err']['msg'] if response['stat'] != 'ok'
  59.     response
  60.   end
  61.   
  62.   # Takes a Flickr API method name and set of parameters; returns the correct URL for the REST API.
  63.   # If @email and @password are present, authentication information is included
  64.   def request_url(method, *params)
  65.     url = "#{@host}#{@api}/?api_key=#{@api_key}&method=flickr.#{method}"
  66.     params[0][0].each_key do |key| url += "&#{key}=" + CGI::escape(params[0][0][key].to_s) end if params[0][0]
  67.     url += "&email=#{@email}&password=#{@password}" if @email and @password
  68.     url
  69.   end
  70.   
  71.   # Does an HTTP GET on a given URL and returns the response body
  72.   def http_get(url)
  73.     open(URI.parse(url)) {|h| h.read }
  74.   end
  75.   # Stores authentication credentials to use on all subsequent calls.
  76.   # If authentication succeeds, returns a User object
  77.   def login(email='', password='')
  78.     @email = email
  79.     @password = password
  80.     user = request('test.login')['user'] rescue fail
  81.     @user = User.new(user['id'])
  82.   end
  83.   
  84.   # Implements flickr.urls.lookupGroup and flickr.urls.lookupUser
  85.   def find_by_url(url)
  86.     response = urls_lookupUser('url'=>url) rescue urls_lookupGroup('url'=>url) rescue nil
  87.     (response['user']) ? User.new(response['user']['id']) : Group.new(response['group']['id']) unless response.nil?
  88.   end
  89.   # Implements flickr.photos.getRecent and flickr.photos.search
  90.   def photos(*criteria)
  91.     photos = (criteria[0]) ? photos_search(criteria[0]) : photos_getRecent
  92.     photos['photos']['photo'].collect { |photo| Photo.new(photo['id']) }
  93.   end
  94.   # Gets public photos with a given tag
  95.   def tag(tag)
  96.     photos('tags'=>tag)
  97.   end
  98.   
  99.   # Implements flickr.people.getOnlineList, flickr.people.findByEmail, and flickr.people.findByUsername
  100.   def users(lookup=nil)
  101.     if(lookup)
  102.       user = people_findByEmail('find_email'=>lookup)['user'] rescue people_findByUsername('username'=>lookup)['user']
  103.       return User.new(user['nsid'])
  104.     else
  105.       return people_getOnlineList['online']['user'].collect { |person| User.new(person['nsid']) }
  106.     end
  107.   end
  108.   # Implements flickr.groups.getActiveList
  109.   def groups
  110.     groups_getActiveList['activegroups']['group'].collect { |group| Group.new(group['nsid']) }
  111.   end
  112.   
  113.   # Implements flickr.tags.getRelated
  114.   def related_tags(tag)
  115.     tags_getRelated('tag_id'=>tag)['tags']['tag']
  116.   end
  117.   
  118.   # Implements flickr.photos.licenses.getInfo
  119.   def licenses
  120.     photos_licenses_getInfo['licenses']['license']
  121.   end
  122.   
  123.   # Implements everything else.
  124.   # Any method not defined explicitly will be passed on to the Flickr API,
  125.   # and return an XmlSimple document. For example, Flickr#test_echo is not defined,
  126.   # so it will pass the call to the flickr.test.echo method.
  127.   # e.g., Flickr#test_echo['stat'] should == 'ok'
  128.   def method_missing(method_id, *params)
  129.     request(method_id.id2name.gsub(/_/, '.'), params[0])
  130.   end
  131.   # Todo:
  132.   # logged_in?
  133.   # if logged in:
  134.   # flickr.blogs.getList
  135.   # flickr.favorites.add
  136.   # flickr.favorites.remove
  137.   # flickr.groups.browse
  138.   # flickr.photos.getCounts
  139.   # flickr.photos.getNotInSet
  140.   # flickr.photos.getUntagged
  141.   # flickr.photosets.create
  142.   # flickr.photosets.orderSets
  143.   # flickr.tags.getListUserPopular
  144.   # flickr.test.login
  145.   # uploading
  146.   class User
  147.     
  148.     attr_reader :client, :id, :name, :location, :photos_url, :url, :count, :firstdate, :firstdatetaken
  149.     def initialize(id=nil, username=nil, email=nil, password=nil)
  150.       @id = id
  151.       @username = username
  152.       @email = email
  153.       @password = password
  154.       @client = Flickr.new
  155.       @client.login(email, password) if email and password
  156.     end
  157.     def username
  158.       @username.nil? ? getInfo.username : @username
  159.     end
  160.     def name
  161.       @name.nil? ? getInfo.name : @name
  162.     end
  163.     def location
  164.       @location.nil? ? getInfo.location : @location
  165.     end
  166.     def count
  167.       @count.nil? ? getInfo.count : @count
  168.     end
  169.     def firstdate
  170.       @firstdate.nil? ? getInfo.firstdate : @firstdate
  171.     end
  172.     def firstdatetaken
  173.       @firstdatetaken.nil? ? getInfo.firstdatetaken : @firstdatetaken
  174.     end
  175.     def photos_url
  176.       @photos_url.nil? ? getInfo.photos_url : @photos_url
  177.     end
  178.     def url
  179.       @url.nil? ? getInfo.url : @url
  180.     end
  181.         
  182.     # Implements flickr.people.getPublicGroups
  183.     def groups
  184.       @client.people_getPublicGroups('user_id'=>@id)['groups']['group'].collect { |group| Group.new(group['nsid']) }
  185.     end
  186.     
  187.     # Implements flickr.people.getPublicPhotos
  188.     def photos
  189.       @client.people_getPublicPhotos('user_id'=>@id)['photos']['photo'].collect { |photo| Photo.new(photo['id']) }
  190.       # what about non-public photos?
  191.     end
  192.     # Gets photos with a given tag
  193.     def tag(tag)
  194.       @client.photos('user_id'=>@id, 'tags'=>tag)
  195.     end
  196.     # Implements flickr.contacts.getPublicList and flickr.contacts.getList
  197.     def contacts
  198.       @client.contacts_getPublicList('user_id'=>@id)['contacts']['contact'].collect { |contact| User.new(contact['nsid']) }
  199.       #or
  200.     end
  201.     
  202.     # Implements flickr.favorites.getPublicList and flickr.favorites.getList
  203.     def favorites
  204.       @client.favorites_getPublicList('user_id'=>@id)['photos']['photo'].collect { |photo| Photo.new(photo['id']) }
  205.       #or
  206.     end
  207.     
  208.     # Implements flickr.photosets.getList
  209.     def photosets
  210.       @client.photosets_getList('user_id'=>@id)['photosets']['photoset'].collect { |photoset| Photoset.new(photoset['id']) }
  211.     end
  212.     # Implements flickr.tags.getListUser
  213.     def tags
  214.       @client.tags_getListUser('user_id'=>@id)['who']['tags']['tag'].collect { |tag| tag }
  215.     end
  216.     # Implements flickr.photos.getContactsPublicPhotos and flickr.photos.getContactsPhotos
  217.     def contactsPhotos
  218.       @client.photos_getContactsPublicPhotos('user_id'=>@id)['photos']['photo'].collect { |photo| Photo.new(photo['id']) }
  219.       # or
  220.       #@client.photos_getContactsPhotos['photos']['photo'].collect { |photo| Photo.new(photo['id']) }
  221.     end
  222.     
  223.     def to_s
  224.       @name
  225.     end
  226.     private
  227.       # Implements flickr.people.getInfo, flickr.urls.getUserPhotos, and flickr.urls.getUserProfile
  228.       def getInfo
  229.         info = @client.people_getInfo('user_id'=>@id)['person']
  230.         @username = info['username']
  231.         @name = info['realname']
  232.         @location = info['location']
  233.         @count = info['photos']['count']
  234.         @firstdate = info['photos']['firstdate']
  235.         @firstdatetaken = info['photos']['firstdatetaken']
  236.         @photos_url = @client.urls_getUserPhotos('user_id'=>@id)['user']['url']
  237.         @url = @client.urls_getUserProfile('user_id'=>@id)['user']['url']
  238.         self
  239.       end
  240.   end
  241.   class Photo
  242.     attr_reader :id, :client
  243.     def initialize(id=nil)
  244.       @id = id
  245.       @client = Flickr.new
  246.     end
  247.     
  248.     def title
  249.       @title.nil? ? getInfo.title : @title
  250.     end
  251.     def owner
  252.       @owner.nil? ? getInfo.owner : @owner
  253.     end
  254.     def server
  255.       @server.nil? ? getInfo.server : @server
  256.     end
  257.     def isfavorite
  258.       @isfavorite.nil? ? getInfo.isfavorite : @isfavorite
  259.     end
  260.     def license
  261.       @license.nil? ? getInfo.license : @license
  262.     end
  263.     def rotation
  264.       @rotation.nil? ? getInfo.rotation : @rotation
  265.     end
  266.     def description
  267.       @description.nil? ? getInfo.description : @description
  268.     end
  269.     def notes
  270.       @notes.nil? ? getInfo.notes : @notes
  271.     end
  272.     # Returns the URL for the photo page (default or any specified size)
  273.     def url(size='Medium')
  274.       if size=='Medium'
  275.         owner.photos_url+id
  276.       else
  277.         sizes(size)['url']
  278.       end
  279.     end
  280.     # Returns the URL for the image (default or any specified size)
  281.     def source(size='Medium')
  282.       sizes(size)['source']
  283.     end
  284.     # Returns the photo file data itself, in any specified size. Example: File.open(photo.title, 'w') { |f| f.puts photo.file }
  285.     def file(size='Medium')
  286.       open(URI.parse(source(size))) {|h| h.read }
  287.     end
  288.     # Unique filename for the image, based on the Flickr NSID
  289.     def filename
  290.       "#{@id}.jpg"
  291.     end
  292.     # Implements flickr.photos.getContext
  293.     def context
  294.       context = @client.photos_getContext('photo_id'=>@id)
  295.       @previousPhoto = Photo.new(context['prevphoto']['id'])
  296.       @nextPhoto = Photo.new(context['nextphoto']['id'])
  297.       return [@previousPhoto, @nextPhoto]
  298.     end
  299.     # Implements flickr.photos.getExif
  300.     def exif
  301.       @client.photos_getExif('photo_id'=>@id)['photo']
  302.     end
  303.     # Implements flickr.photos.getPerms
  304.     def permissions
  305.       @client.photos_getPerms('photo_id'=>@id)['perms']
  306.     end
  307.     # Implements flickr.photos.getSizes
  308.     def sizes(size=nil)
  309.       sizes = @client.photos_getSizes('photo_id'=>@id)['sizes']['size']
  310.       sizes = sizes.find{|asize| asize['label']==size} if size
  311.       return sizes
  312.     end
  313.     # flickr.tags.getListPhoto
  314.     def tags
  315.       @client.tags_getListPhoto('photo_id'=>@id)['photo']['tags']
  316.     end
  317.     # Implements flickr.photos.notes.add
  318.     def add_note(note)
  319.     end
  320.     
  321.     # Implements flickr.photos.setDates
  322.     def dates=(dates)
  323.     end
  324.     # Implements flickr.photos.setPerms
  325.     def perms=(perms)
  326.     end
  327.     
  328.     # Implements flickr.photos.setTags
  329.     def tags=(tags)
  330.     end
  331.     
  332.     # Implements flickr.photos.setMeta
  333.     def title=(title)
  334.     end
  335.     def description=(title)
  336.     end
  337.     # Implements flickr.photos.addTags
  338.     def add_tag(tag)
  339.     end
  340.     
  341.     # Implements flickr.photos.removeTag
  342.     def remove_tag(tag)
  343.     end
  344.     # Implements flickr.photos.transform.rotate
  345.     def rotate
  346.     end
  347.     # Implements flickr.blogs.postPhoto
  348.     def postToBlog(blog_id, title='', description='')
  349.       @client.blogs_postPhoto('photo_id'=>@id, 'title'=>title, 'description'=>description)
  350.     end
  351.     # Implements flickr.photos.notes.delete
  352.     def deleteNote(note_id)
  353.     end
  354.     # Implements flickr.photos.notes.edit
  355.     def editNote(note_id)
  356.     end
  357.         
  358.     # Converts the Photo to a string by returning its title
  359.     def to_s
  360.       getInfo.title
  361.     end
  362.     
  363.     private
  364.       # Implements flickr.photos.getInfo
  365.       def getInfo
  366.         info = @client.photos_getInfo('photo_id'=>@id)['photo']
  367.         @title = info['title']
  368.         @owner = User.new(info['owner']['nsid'])
  369.         @server = info['server']
  370.         @isfavorite = info['isfavorite']
  371.         @license = info['license']
  372.         @rotation = info['rotation']
  373.         @description = info['description']
  374.         @notes = info['notes']['note']#.collect { |note| Note.new(note.id) }
  375.         self
  376.       end
  377.   end
  378.   # Todo:
  379.   # flickr.groups.pools.add
  380.   # flickr.groups.pools.getContext
  381.   # flickr.groups.pools.getGroups
  382.   # flickr.groups.pools.getPhotos
  383.   # flickr.groups.pools.remove
  384.   class Group
  385.     attr_reader :id, :client, :name, :members, :online, :privacy, :chatid, :chatcount, :url
  386.     
  387.     def initialize(id=nil)
  388.       @id = id
  389.       @client = Flickr.new
  390.     end
  391.     # Implements flickr.groups.getInfo and flickr.urls.getGroup
  392.     # private, once we can call it as needed
  393.     def getInfo
  394.       info = @client.groups_getInfo('group_id'=>@id)['group']
  395.       @name = info['name']
  396.       @members = info['members']
  397.       @online = info['online']
  398.       @privacy = info['privacy']
  399.       @chatid = info['chatid']
  400.       @chatcount = info['chatcount']
  401.       @url = @client.urls_getGroup('group_id'=>@id)['group']['url']
  402.       self
  403.     end
  404.   end
  405.   # Todo:
  406.   # flickr.photosets.delete
  407.   # flickr.photosets.editMeta
  408.   # flickr.photosets.editPhotos
  409.   # flickr.photosets.getContext
  410.   # flickr.photosets.getInfo
  411.   # flickr.photosets.getPhotos
  412.   class Photoset
  413.     attr_reader :id, :client, :owner, :primary, :photos, :title, :description, :url
  414.     def initialize(id=nil)
  415.       @id = id
  416.       @client = Flickr.new
  417.     end
  418.     # Implements flickr.photosets.getInfo
  419.     # private, once we can call it as needed
  420.     def getInfo
  421.       info = @client.photosets_getInfo('photosets_id'=>@id)['photoset']
  422.       @owner = User.new(info['owner'])
  423.       @primary = info['primary']
  424.       @photos = info['photos']
  425.       @title = info['title']
  426.       @description = info['description']
  427.       @url = "http://www.flickr.com/photos/#{@owner.getInfo.username}/sets/#{@id}/"
  428.       self
  429.     end
  430.   end
  431.     
  432. end