LINE Messaging APIを使ってランダムな写真を送信する

## やりたいこと

写真はよくスマホで取るので溜まっていくけど、数が増えてくると過去の写真って埋もれていくよね. botが適当な写真を選んで送ってくれたりすると楽しいのでは. 

ということで、Googleフォトの特定のアルバムからランダムに写真を選んで、LINEのトークに送信する、という機能をbotに実装した. ルーム内の発言に反応して送ったり、定期的にルームに投稿したりする.

![LINE_photo_mosaic.png](https://qiita-image-store.s3.amazonaws.com/0/30516/e45f1327-42aa-4d80-eb4b-85f2ef5009a5.png)

## 準備

* LINE Messaging APIを使える状態にする
   * 公式としてはこちら https://developers.line.me/messaging-api/getting-started
   * こちらのブログ [LINEのMessaging APIを使うメモ：事前知識と登録編](http://uzulla.hateblo.jp/entry/2016/10/06/230309) に日本語で親切に書いてある
   * LINEのトークとは関係なく、一方的に写真を送るならwebhookは不要
* GoogleのAPIを使える状態にする
    * https://console.developers.google.com から、プロジェクト登録、認証情報取得をする
    * http://www.yoheim.net/blog.php?q=20160411 あたりを参考に
    * GoogleフォトのAPIは、特に有効にしなくても使える (APIの一覧に出てこない)
    * Oauth2 access tokenの取得は http://qiita.com/giiko_/items/b0b2ff41dfb0a62d628b を参考にした

## 実装

rubyでやる. LINE, Googleともに色々な言語でライブラリが出ているので、好きなものを使えば良いと思う.

### Googleフォトからランダムに写真を取得

[Picasa Web Album Data API](https://developers.google.com/picasa-web/) を使う. rubyから使うので、https://github.com/morgoth/picasa を使用した.

こんな感じ. `get_random_photo_url` を呼ぶと、アルバム中写真から、どれか一枚のURLが返る.

```rb
require 'signet/oauth_2/client'
require 'picasa'
require 'dotenv'

Dotenv.load

class PicasaClient

  def initialize
    @client = nil
  end

  def client
    @client ||= Picasa::Client.new(user_id: ENV['GOOGLE_USER_ID'], access_token: access_token)
  end
  
  def access_token
    signet = Signet::OAuth2::Client.new(
      client_id: ENV['GOOGLE_CLIENT_ID'],
      client_secret: ENV['GOOGLE_CLIENT_SECRET'],
      token_credential_uri: "https://www.googleapis.com/oauth2/v3/token",
      refresh_token: ENV['GOOGLE_REFRESH_TOKEN']
    )
    signet.refresh! 
    
    # Use access token with picasa gem
    puts "access_token:" + signet.access_token
    signet.access_token
  end

  def get_random_photo_url
    album = client.album.list.entries.find{  |a| a.title == ENV['GOOGLE_PHOTO_ALBUM_NAME'] } 
    photo = client.album.show(album.id).entries.sample
    photo.content.src
  end
end

```

### LINE Botから画像を送る

一方的に写真を送るようなコマンドを作ってみる. こんな感じ. `ENV['LINE_SEND_TARGET']`の部分は、送信先のユーザまたはグループのID. 前者は"U...", 後者は"C..."みたいな形をしている. (これはどこから取るのが楽なんだろう. 自分は、webhook用に立てたサーバで、受信したイベントを出力して取得した)

```rb
require 'line/bot'
require 'dotenv'

Dotenv.load

def line_send_image(target, image_url)
  line_client = Line::Bot::Client.new { |config|
    config.channel_secret = ENV['LINE_CHANNEL_SECRET']
    config.channel_token = ENV['LINE_CHANNEL_TOKEN']
  }
  message = {
    type: "image",
    originalContentUrl: image_url,
    previewImageUrl: image_url
  }
  line_client.push_message(target, message)
end

log = Logger.new(STDOUT) # !> assigned but unused variable - log
picasa = PicasaClient.new
line = LineClient.new
photo_url = picasa.get_random_photo_url
res = line.send_image(ENV['LINE_SEND_TARGET'], photo_url)
```

### 会話に反応して画像を送る

Botのwebhook URLで指定したURLにWebサーバを立てることになる. ここでは、トーク内で'p' (photoのこと) と発言されたら、上と同じ要領でランダムな画像をピックアップして返すようにする. 

```rb
require "sinatra/base"
require 'line/bot'
require 'dotenv'

module MyBotserver
  class Server < Sinatra::Base
    Dotenv.load

    helpers do
      def client
        @client ||= Line::Bot::Client.new { |config|
          config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
          config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
        }
      end
    end

    post '/line' do
      request.body.rewind
      body = request.body.read
      events = client.parse_events_from(body)
      events.each do |event|
        case event
        when Line::Bot::Event::Message
          when Line::Bot::Event::MessageType::Text
            message = {}
            case event.message['text']
            when /^p$/
              logger.info "Sending photo"
              picasa = PicasaClient.new
              photo_url = picasa.get_random_photo_url
              message = {
                type: 'image',
                originalContentUrl: photo_url,
                previewImageUrl: photo_url
              }
              res = client.reply_message(event['replyToken'], message)
              logger.warn "Message send error: " + res.body unless res.is_a?(Net::HTTPOK)
            end
            unless message.empty?
              logger.info "Sending message #{message}"
              client.reply_message(event['replyToken'], message)
            end
          end
       end
     end
  end
end


```

## まとめ

LINE Messaging APIを使って、Googleフォトからランダムな写真をLINEトークに送信する機能を実装してみた. 自分は、cronで毎朝一枚送信、あとはリクエストしたら適宜送ってくれるような感じにして使っている. なかなか楽しい. 

子供の昔の写真を送るとか、空腹な時間を狙って飯画像を送るとか、遊ぶと良いと思う.