アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

Ruby で Picasa

こんにちは!! tahara です。 RubyPicasaAPI をたたいてみました。

OAuth でアクセスできる素敵なライブラリをうまく見つけることができなかったので、 Google Data Ruby Utility Library を使って地味に作りました。

Developer's Guide: Protocol - Picasa Web Albums Data API - Google Code を参照しながらの試行錯誤だったので、いまいち自信ありません。

# -*- coding: utf-8 -*-
require 'oauth/client/net_http'

module Actindi
  class Picasa

    SITE = "http://photos.googleapis.com"
    CONSUMER_KEY = "xxxxxxxxx"
    CONSUMER_SECRET = "xxxxxxxxxxx"

    PUBLIC_ALBUM  = "公開アルバム"
    PRIVATE_ALBUM = "プライベートアルバム"
    ALBUM_ACCESS_PUBLIC = "public"
    ALBUM_ACCESS_PROTECTED = "protected"

    def initialize(token, secret)
      consumer = OAuth::Consumer.new CONSUMER_KEY, CONSUMER_SECRET, {
        :site             => SITE,
        :signature_method => 'HMAC-SHA1',
        :token            => OAuth::Token.new(token, secret)
      }
      @picasa = GData::Client::Photos.new(:http_service => GData::HTTP::OAuthService.new(consumer))
    end

    def ensure_albums
      return if @public_album && @private_album

      feed = @picasa.get("#{SITE}/data/feed/api/user/default").to_xml
      feed.elements.each("entry") do |entry|
        title = entry.elements["title"].text
        puts title
        if title == PUBLIC_ALBUM
          @public_album = entry
        elsif title == PRIVATE_ALBUM
          @private_album = entry
        end
      end
      return if @public_album && @private_album
      unless @public_album
        @public_album = create_album(PUBLIC_ALBUM, "public")
      end
      unless @private_album
        @private_album = create_album(PRIVATE_ALBUM, "protected")
      end
      ensure_albums
    end

    def user_data
      feed = @picasa.get("#{SITE}/data/entry/api/user/default").to_xml
      puts feed
      feed
    end

    def create_album(title, access)
      entry = <<ENTRY
<entry xmlns='http://www.w3.org/2005/Atom'
       xmlns:media='http://search.yahoo.com/mrss/'
       xmlns:gphoto='http://schemas.google.com/photos/2007'>
  <title type='text'>#{title}</title>
  <summary type='text'>あるばむぅ</summary>
  <gphoto:access>#{access}</gphoto:access>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/photos/2007#album'>
</entry>
ENTRY
      @picasa.headers = {}
      feed = @picasa.post("#{SITE}/data/feed/api/user/default", entry).to_xml
      feed
    end

    def post_photo(title, summary, photo_file_path, mime_type, access)
      album_id = album_id_from_access(access)
      entry = <<ENTRY
<entry xmlns='http://www.w3.org/2005/Atom'>
  <title>#{title}</title>
  <summary>#{summary}</summary>
  <category scheme="http://schemas.google.com/g/2005#kind"
    term="http://schemas.google.com/photos/2007#photo"/>
</entry>
ENTRY
      url = "#{SITE}/data/feed/api/user/default/albumid/#{album_id}"
      puts url
      puts entry
      @picasa.headers = {}
      feed = @picasa.post_file(url,
                               photo_file_path,
                               mime_type,
                               entry).to_xml
      puts feed
      feed.elements["link[@rel='edit']"].attributes['href']
    end

    def delete_photo(feed)
      @picasa.headers = {}
      @picasa.delete(feed)
    end

    def change_album(feed_url, access)
      album_id = album_id_from_access(access)
      @picasa.headers = {}
      entry = @picasa.get(feed_url).to_xml
      entry.elements["gphoto:albumid"].text = album_id
      edit_url = entry.elements["link[@rel='edit']"].attributes['href']
      @picasa.headers = {}
      feed = @picasa.put(edit_url, entry.to_s).to_xml
      feed.elements["link[@rel='edit']"].attributes['href']
    end

    def album_id_from_access(access)
      ensure_albums
      url = if access == ALBUM_ACCESS_PUBLIC
              @public_album.elements["id"].text
            else
              @private_album.elements["id"].text
            end
      url =~ /([^\/]+$)/
      $1
    end

    class << self
      def example
        token = "access token"
        secret = "access token secret"
        picasa = Actindi::Picasa.new(token, secret)
        feed = picasa.post_photo("題名", "サマリー", "/tmp/aaa.jpg", "image/jpeg", Actindi::Picasa::ALBUM_ACCESS_PUBLIC)
      end
    end
  end

end

module GData
  module HTTP
    class OAuthService

      def initialize(consumer)
        @consumer = consumer
      end

      def new
        self
      end

      # Take a GData::HTTP::Request, execute the request, and return a
      # GData::HTTP::Response object.
      def make_request(request)
        url = URI.parse(request.url)
        http = Net::HTTP.new(url.host, url.port)
        http.use_ssl = (url.scheme == 'https')
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE

        case request.method
        when :get
          req = Net::HTTP::Get.new(url.request_uri)
        when :put
          req = Net::HTTP::Put.new(url.request_uri)
        when :post
          req = Net::HTTP::Post.new(url.request_uri)
        when :delete
          req = Net::HTTP::Delete.new(url.request_uri)
        else
          raise ArgumentError, "Unsupported HTTP method specified."
        end

        case request.body
        when String
          req.body = request.body
        when Hash
          req.set_form_data(request.body)
        when File
          req.body_stream = request.body
          request.chunked = true
        when GData::HTTP::MimeBody
           req.body_stream = request.body
          request.chunked = true
        else
          req.body = request.body.to_s
        end

        request.headers.each do |key, value|
          req[key] = value
        end

        request.calculate_length!

        @consumer.sign!(req)
        res = http.request(req)

        response = Response.new
        response.body = res.body
        response.headers = Hash.new
        res.each do |key, value|
          response.headers[key] = value
        end
        response.status_code = res.code.to_i
        return response
      end
    end
  end
end