こんにちは、エンジニアのさもです。
タイトルにもありますが、Line(グループ)に投稿した画像をクラウド(S3)で保存し、webページで一覧を見れるようにするBot(とwebサービス)を作りました。
普段Lineで画像のやり取りをしているという方は試してみてはどうでしょうか?
スポンサーリンク
目次
背景
普段、息子の写真を僕の親や妻などと共有するのにLineで送りあったりしています。
ですが、Lineだと保存期間があったり、ちょっと前の画像みるのに上のほうへさかのぼっていたので、もう少し見やすくならないかなと、今回のBot&サービスを作ってみました。
やりたかったこと
実現したかった構成はこんな感じです。
インターフェース(これまでのやり方)を変えたくなかったので、いつもどおりLineにアップロードしたら自動的にS3へ保存してくれるようにしました。
画像の登録に成功すると、メッセージを返してくれます
画像の閲覧は専用のwebサイトで登録した月別でみれるようにしています(未実装)
Line側の準備
STEP1. Line developersへユーザー登録します。
STEP2. 登録後、ログインしたら、プロバイダーを作成します。
プロバイダー名は何でもいいです。
STEP3. Botを作成します
作成したプロバイダを選択し、「Messaging API」から作成画面に進みます
分類などは適当でいいです。
STEP4. キーの取得と設定
作成後、APIを使うために、「Channel Secret」と「アクセストークン」を記録しておきます。
もしまだ表示されていない場合は、再発行してください。
Webhook送信 は有効にしておきます。
Botのグループトーク参加は利用するにしておきます。
Webhook URL はRails側の実装が終わってからで良いと思います。
自動応答や友達登録時メッセージは無効にしておくのが良いと思います。
S3の準備
やることは、IAM設定とバケットの作成のみですが、
ここは分かりやすいページがあったので丸投げしてしまいます。
Railsの準備
Railsでは、Lineからのpostの受け取りと、S3へのアップロードを行います。(実際には画像の一覧があるのですが、割愛します)
gem
以下のgemをgemfileに書いてbundleしてください
- line-bot-api・・・LineBotを使うときに必要
- carrierwave・・・画像アップロード
- fog・・・・・・S3を使うときに必要
model
今回はPhotoモデルを作って行きます(あとから気づいたのですが、動画にも対応するので、モデル名は適切でないですが、このまま行きます)
カラムは、アップローダをマウントするimageカラムと画像か動画かを覚えておくcontent_typeカラムぐらいがあればいいと思います。
あと、誰が投稿したか分かるように、uploader_id, いつの写真か分かるようにphoto_dateを付け加えました。
今回は、年月毎にディレクトリを分けたいので、Photoモデルにディレクトリを返すメソッドを登録しておきます
class Photo < ActiveRecord::Base mount_uploader :image, ImageUploader belongs_to :uploader def upload_dir self.photo_date.strftime("%Y%m") end end
投稿したユーザを表すUploaderモデルも作っておきます。
カラムは、line_id, token(webサイトへログイン用), nameです。tokenはwebサイトを見るために使っているので、無くてもいいです
uploader
rails g uploader Image
でアップローダーを作成します
上を実行すると、新たにuploadersディレクトリが作られ、image_uploader.rbというファイルが作られます。
S3の設定のため、以下のように修正してください
class ImageUploader < CarrierWave::Uploader::Base if Rails.env.development? || Rails.env.test? storage :file else storage :fog end def store_dir "uploads/#{model.upload_dir}" end # ファイル名をランダム文字列にする def filename "#{secure_token}.#{file.extension}" if original_filename.present? end protected def secure_token var = :"@#{mounted_as}_secure_token" model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid) end end
ルーティング
コントローラ名は何でもいいですが、URLは/callback
となるようにしておいてください
post '/callback' => 'webhook#callback'
controller
基本的には、ラインクライアントをインスタンス化し、
画像か動画であればPhotoモデルに登録、
登録が成功すれば、メッセージを返す。
という流れです。
途中で投稿者の登録が挟まっています。
require 'line/bot' class WebhookController < ApplicationController before_action :set_line_client CHANNEL_SECRET = 'aaaaa' # 記録しておいたChannel Secret 本当はENVでやるのが望ましい CHANNEL_ACCESS_TOKEN = 'aaaaa' # 記録しておいたアクセストークン 本当はENVでやるのが望ましい def callback body = request.body.read unless @client.validate_signature(body, request.env['HTTP_X_LINE_SIGNATURE']) error 400 do 'Bad Request' end end event = @client.parse_events_from(body)[0] message = { text: nil } case event.type # 画像か動画なら登録する when "image", "video" temp = Tempfile.new("example").binmode.tap do |file| file.write @client.get_message_content(event.message['id']).body end if Photo.create(image: temp, uploader_id: find_or_create_uploader.id, photo_date: Time.zone.today, content_type: event.type) type_str = event.type == "image" ? "画像" : "動画" message = { type: 'text', text: "#{type_str}を登録しました。" } end end # Botを介してLineへメッセージ送信 if message[:text].present? @client.reply_message(event['replyToken'], message) end # webからは何も返さない render :nothing => true, status: :ok end private # メッセージを取扱いやすくしてくれるclientをセット def set_line_client @client ||= Line::Bot::Client.new { |config| config.channel_secret = CHANNEL_SECRET config.channel_token = CHANNEL_ACCESS_TOKEN } end # Uploaderを見つけるor登録する def find_or_create_uploader line_id = params[:events][0][:source][:userId] uploader = Uploader.find_by(line_id: line_id) unless uploader uploader = Uploader.create(line_id: line_id, token: SecureRandom.uuid, name: line_name(line_id)) end uploader end # プロフィールからLineの名前を取ってくる def line_name(line_id) response = @client.get_profile(line_id) case response when Net::HTTPSuccess then return JSON.parse(response.body)['displayName'] end end end
Railsはこんな感じです。
Herokuへデプロイ
ちょっと端折りますが、HerokuでRailsのプロジェクトを作り、メニューの「deploy」を参考にしながらデプロイします。
僕は開発環境にcloud9を使っているのですが、clod9からHerokuへデプロイする方法もそのうち記事に書きたいと思います。
引っかかるところはあまり無いと思いますが、Rubyのbuild packを追加するのを忘れないでください。
Line側の準備2
Herokuへデプロイしたら、メニューの「setting」からURLを確認し、
Botの設定のWebhook URL へpostするパスを入力します。上の例では、
https://なんとかかんとか.herokuapp.com/callback
です。
あとは利用したいグループへ招待するだけです!
まとめ
トークの中に埋もれていた画像が一覧でみやすくなりました!
Lineでも写真を一覧表示することは出来るのですが、保存期間が過ぎても保存しておきたい、月別で表示・ダウンロードしたいと思っていたのと、自分で作ったものだと自由にカスタマイズ出来るので今回のBot+サービスを作ってみました。
以上、エンジニアの皆様もお試しください!
読者登録はこちらからお願いします。