Docker環境でLINE botとYoutubeAPI使って動画検索サービスを作ってみた。
対象者
完成イメージ
前からYouTube API使ってみたいなーって思ってたので、
— らんぼー@Railsエンジニア (@rambolog) 2019年12月15日
Docker環境でLine上でYouTube検索できるやつ作った笑
いい感じに検索の利便性も上げたいなー🤔 pic.twitter.com/J4eUKKSzpI
Docker
まずはRailsの環境構築をDockerで行います。
docker docsに記載されている、Railsの環境構築マニュアルを元に作成いたします。
何箇所か自分で変更した部分もあり、コメントを残しています。
Dockerfile
FROM ruby:2.5 RUN apt-get update -qq && apt-get install -y nodejs postgresql-client RUN mkdir /myapp WORKDIR /myapp # 文字化けしないように ENV LANG=C.UTF-8 COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install COPY . /myapp
Dockerfileのコマンドを簡単に説明すると、
- FROMはDockerfileで使用するイメージを指定します。
- RUNは実行してほしい命令になります。
- WORKDIRはディレクトリの指定
- ENVは環境変数の設定
- COPYは左辺にあるを右辺にコピー。(
COPY Gemfile /myapp/Gemfile
だったら、ローカルのGemfileをコンテナ上のmyapp/Gemfileにコピー)
他にもコマンドが気になる方は、下記記事が参考になります。
Gemfile
source 'https://rubygems.org' gem 'rails', '~>5'
GemfileをDockerfileと同じディレクトリに作成してください。
また、touch Gemfile.lock
で一緒にGemfile.lockを作ってください(中身は空で大丈夫です)
次にdocker-compose.yaml
を作ってください。ファイルの中身は以下のようになります。
docker-compose.yaml
version: '3' # buildし直すのがめんどいので、bundleをvolumeで繋ぐ volumes: bundle: services: db: image: postgres # postgresのイメージを使ってDBを作成 volumes: - ./tmp/db:/var/lib/postgresql/data app: build: . # 同じディレクトリに存在するDockerfileのイメージを使う command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp ports: - "3000:3000" depends_on: - db
次に、以下のコマンドでRailsの新規プロジェクトを作成してください!
docker-compose run app rails new . --force --no-deps --database=postgresql
rails newをしたことでGemfileが変わったので、imageを作り直します!
先程、作成したGemfileとは中身が変わっているはずです。
docker-compose build
Railsはlocalhostで動いていますが、DBのコンテナを使用しているのでconfig/database.yml
を以下のように修正します。
default: &default adapter: postgresql encoding: unicode host: db username: postgres password: pool: 5 development: <<: *default database: myapp_development test: <<: *default database: myapp_test
変更したら、下記コマンドを実行してください。
docker-compose up
docker-compose run app rake db:create
これで、localhost:3000にアクセスしてみてください!
ちなみにopen http://localhost:3000
とターミナル上で打てば、localhost:3000にアクセスしてくれます。
LINE BOTとYoutube API
まず、Gemfileにdotenv-rails
とline-bot-api
を追加します。
Gemfile
# frozen_string_literal: true source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.5.7' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 5.2.4' # Use postgresql as the database for Active Record gem 'pg', '>= 0.18', '< 2.0' # Use Puma as the app server gem 'puma', '~> 3.11' # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets gem 'uglifier', '>= 1.3.0' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'mini_racer', platforms: :ruby gem 'rubocop', '~> 0.77.0', require: false # Use CoffeeScript for .coffee assets and views gem 'coffee-rails', '~> 4.2' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.5' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use ActiveStorage variant # gem 'mini_magick', '~> 4.8' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.1.0', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: %i[mri mingw x64_mingw] gem 'pry-byebug' gem 'pry-doc' gem 'pry-rails' end group :development do # Access an interactive console on exception pages or by calling 'console' anywhere in the code. gem 'listen', '>= 3.0.5', '< 3.2' gem 'web-console', '>= 3.3.0' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' end group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara', '>= 2.15' gem 'selenium-webdriver' # Easy installation and use of chromedriver to run system tests with Chrome gem 'chromedriver-helper' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] #----------------------追加--------------------------------- gem 'dotenv-rails', require: 'dotenv/rails-now' gem 'google-api-client', '~> 0.34' gem 'line-bot-api' #----------------------追加---------------------------------
この時、必ずdotenv-rails
がline-bot-api
より上になるようにGemfileに書いてください。
dotenv-rails
は環境変数をセットするGemより前に置かないと(line-bot-api
とgoogle-api-client
)、環境変数を上手くセットできないからです。
routes.rbを作ってください
Rails.application.routes.draw do post '/callback' => 'linebot#callback' end
次にlinebot用のcontrollerを作ってください。
ザックリした流れとしては、line-botでテキストを受け取って、そのテキストでYoutubeAPIを叩き(そのテキストでYoutube内を検索し)、該当するYoutubeの動画をレスポンスで返すと言うのが流れです。
linebot_controller.rb
# frozen_string_literal: true class LinebotsController < ApplicationController # linebotを使うためにrequire require 'line/bot' # youtube apiを使うためにrequire require 'google/apis/youtube_v3' require 'active_support/all' # callbackアクションのCSRFトークン認証を無効 protect_from_forgery except: [:callback] def callback body = request.body.read signature = request.env['HTTP_X_LINE_SIGNATURE'] unless client.validate_signature(body, signature) halt 400, { 'Content-Type' => 'text/plain' }, 'Bad Request' end events = client.parse_events_from(body) events.each do |event| # 定数は下記参照 # https://github.com/line/line-bot-sdk-ruby/blob/8963a4c277259b225a766269e9e53040e414b90f/lib/line/bot/event/message.rb#L18 case event when Line::Bot::Event::Message case event.type # テキストが送られてきたケース when Line::Bot::Event::MessageType::Text # event.message['text']にユーザーが入力したテキストが入っている item_ids = find_videos(event.message['text']) start_word = { type: 'text', text: message_first_text(item_ids, event) } message = item_ids.map do |id| { type: 'text', # 動画のidを元にYoutubeの動画のリンクを作る text: "https://www.youtube.com/embed/#{id.video_id}" } end # 破壊的変更 message.unshift(start_word) # 画像が送られてきたケース when Line::Bot::Event::MessageType::Image message = { type: 'text', text: '画像は送れません' } # スタンプが送られてきたケース when Line::Bot::Event::MessageType::Sticker message = { type: 'text', text: 'スタンプは対応していません' } # その他のケース else message = { type: 'text', text: 'テキストを入力してください' } end client.reply_message(event['replyToken'], message) end end 'OK' end private # 送られてきたテキストがkeyword def find_videos(keyword) service = Google::Apis::YoutubeV3::YouTubeService.new service.key = ENV['API_KEY'] # 環境変数をセット opt = { q: keyword, type: 'video', max_results: 4 # 表示する動画の最大数 } # そのkeywordでYoutubeの動画を検索 results = service.list_searches(:snippet, opt) # 検索にヒットした動画のidを配列で返却 results.items.map(&:id) end # ヒットしたものがあるかないかでメッセージを変更する def message_first_text(item_ids, event) if item_ids.blank? # 動画が見つからなかったケース "「#{event.message['text']}」という検索ワードにヒットした動画は見つかりませんでした" else # 動画が見つかったケース "「#{event.message['text']}」という検索ワードにヒットした動画が#{item_ids.count}件ありました!" end end # 呼ばれる度にインスタンスを生成しないようにメモ化 def client @client ||= Line::Bot::Client.new do |config| config.channel_secret = ENV['LINE_CHANNEL_SECRET'] # 環境変数をセット config.channel_token = ENV['LINE_CHANNEL_TOKEN'] # 環境変数をセット end end end
linebotのアクセスkeyの発行方法
【Rails】1時間ぐらいで簡単にLINEのBot開発をしよう-アンケート集計Bot基礎-【画像付き】 - Qiita
記事が凄く参考になったので、この記事に従ってLINE Developerにアクセスしてアカウントを作ってください。
記事どうり、Webhook送信: 利用する
に変更です。
YoutubeAPIのアクセスkeyの発行方法
アクセスkeyは下記の記事どうりにやれば問題ないかなと思います!
harokuにデプロイ
heroku config:set LINE_CHANNEL_SECRET=ここに先程メモしたChannel Secretを貼り付ける heroku config:set LINE_CHANNEL_TOKEN=ここに先程メモしたアクセストークンを貼り付ける heroku config:set API_KEY=ここに先程はメモしたAPI_KEY(YoutubeAPI)を貼り付ける
そしてデプロイです。
デバッグ用
LINEBOTは一回一回本番へデプロイしないと動作確認ができないです。
でも、それだと大変めんどくさいですよね?
ですので、Ngrok
と言うオープンソースを使うといいです!
Ngrokの公式に行っていただいて、無料の会員登録をしてインストールして下さい。
./ngrok http -host-header="0.0.0.0:3000" 3000
でlocalhost3000にアクセスできるようにngrokを起動して、
あとは、上記のQiita記事のようにWebhookのURLを変更してあげれば大丈夫です!