Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9050

LINE BOTでYouTubeの検索をしてみたよ

$
0
0

初めに

先日、LINE BOT の開発を教わったので、実際に作成してみました。
教わったのは簡単なテキストを返すものでしたが、LINE Messaging API でテンプレートメッセージのカルーセルを使ってみました。
LINE BOT の初期設定(事前準備)は以下を参考にしています。
1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest

目的

私はよくYouTubeで動画を見るので、簡単なYouTube検索ボットを作ってみました。
単純メッセージのレスポンスだとつまらないと思ったので、カルーセル形式に挑戦してみました。

環境

Visual Studio Code v1.49.0
node.js v14.9.0
ngrok v2.3.35

概要

自PCを(Node.js)サーバに見立て、LINEサーバからWebhookを受け取る為のトンネリングサービスはngrokを利用しています。
データの流れについては、公式ページ上記の参考サイトをみると何となく分かります。

今回、YouTubeのデータ検索にはYouTube API DATA v3 を利用し、LINE BOT に送ったメッセージでキーワード検索をしています。APIのレスポンスはaxiosで受け取り、関連する上位3件の動画情報から、サムネイル表示、タイトル表示、動画URLへ飛ぶようにしてみようと思いました。

コード

.js
'use strict';// おまじない// ########################################//               初期設定など// ########################################// パッケージを使用しますconstexpress=require('express');constline=require('@line/bot-sdk');constaxios=require('axios');constPORT=process.env.PORT||3000;// ローカル(自分のPC)でサーバーを公開するときのポート番号constYoutubeURL='https://www.youtube.com/watch?v=';// YouTubeURLconstYoutubeAPIKey='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';//YouTubeAPIKey// Messaging APIで利用するクレデンシャル(秘匿情報)です。constconfig={channelSecret:'99999999999999999999999999999999',//作成したBotのチャネルシークレットchannelAccessToken:'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'//作成したBotのチャネルアクセストークン};// ########## ▼▼▼ サンプル関数 ▼▼▼ ##########constMainFunction=async(event)=>{constuserText=event.message.text;// ユーザーメッセージaxios.defaults.baseURL='https://www.googleapis.com/youtube/v3';// YouTube Data API// 「リプライ」を使って先に返事しておきますawaitclient.replyMessage(event.replyToken,{type:'text',text:'調べています……'});letTitle=[];letIdUrl=[];letImageUrl=[];try{// axiosでAPIを叩きます(少し時間がかかる・ブロッキングする)constres=awaitaxios.get('/search?part=snippet&q='+encodeURIComponent(userText)+'&key='+YoutubeAPIKey);// 関連の高い動画を3件返すfor(leti=0;i<3;i++){Title.push(res.data.items[i].snippet.title);// タイトル// 文字数が50より大きかったら末尾に...を付けたす ※MessagingApiの制限60文字を超えるとエラーになるので。if(Title[i].length>50){Title[i]=Title[i].substr(0,50)+'...';}IdUrl.push(YoutubeURL+res.data.items[i].id.videoId);// 動画URLImageUrl.push(res.data.items[i].snippet.thumbnails.medium.url);// サムネ画像}}catch(error){// APIからエラーが返ってきたらターミナルに表示するreturnclient.pushMessage(event.source.userId,{type:'text',text:'検索中にエラーが発生しました。ごめんね。',});console.error(error);}// 「プッシュ」で後からユーザーに通知(カルーセル形式ガリ書き。)returnclient.pushMessage(event.source.userId,{"type":"template","altText":"this is a carousel template","template":{"type":"carousel","columns":[{"thumbnailImageUrl":ImageUrl[0],"text":Title[0],"defaultAction":{"type":"uri","label":"動画を見に行く","uri":IdUrl[0]},"actions":[{"type":"uri","label":"動画を見に行く","uri":IdUrl[0]}]},{"thumbnailImageUrl":ImageUrl[1],"text":Title[1],"defaultAction":{"type":"uri","label":"動画を見に行く","uri":IdUrl[1]},"actions":[{"type":"uri","label":"動画を見に行く","uri":IdUrl[1]}]},{"thumbnailImageUrl":ImageUrl[2],"text":Title[2],"defaultAction":{"type":"uri","label":"動画を見に行く","uri":IdUrl[2]},"actions":[{"type":"uri","label":"動画を見に行く","uri":IdUrl[2]}]}],"imageAspectRatio":"rectangle","imageSize":"cover"}});};// ########## ▲▲▲ サンプル関数 ▲▲▲ ##########// ########################################//  LINEサーバーからのWebhookデータを処理する部分// ########################################// LINE SDKを初期化しますconstclient=newline.Client(config);// LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されますasyncfunctionhandleEvent(event){// 受信したWebhookが「テキストメッセージ以外」であれば固定メッセージを返すif(event.type!=='message'||event.message.type!=='text'){//return Promise.resolve(null);returnclient.replyMessage(event.replyToken,{type:'text',text:'YouTubeで検索しようか?\n検索キーワードは?'});}// サンプル関数を実行しますreturnMainFunction(event);}// ########################################//          Expressによるサーバー部分// ########################################// expressを初期化しますconstapp=express();// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をしますapp.post('/webhook',line.middleware(config),(req,res)=>{// Webhookの中身を確認用にターミナルに表示しますconsole.log(req.body.events);// 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行if(req.body.events[0].replyToken==='00000000000000000000000000000000'&&req.body.events[1].replyToken==='ffffffffffffffffffffffffffffffff'){res.send('Hello LINE BOT! (HTTP POST)');// LINEサーバーに返答しますconsole.log('検証イベントを受信しました!');// ターミナルに表示しますreturn;// これより下は実行されません}// あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、// 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返しますPromise.all(req.body.events.map(handleEvent)).then((result)=>res.json(result));});// 最初に決めたポート番号でサーバーをPC内だけに公開します// (環境によってはローカルネットワーク内にも公開されます)app.listen(PORT);console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);

苦戦した箇所

・YouTube APIの仕様理解
以下サイトを参考に、APIの有効化と仕様を確認しましたが、上手くデータを取れず少し苦戦しました。
原因は余計なパラメータを渡していた為でした。(APIの仕様書を読み解くのが、なかなか慣れない、、、)
 Youtube Data API Key の取得手順
 YouTube Data API | Google Developers
 動画の検索 | YouTube Data API v2

・LINE Messaging APIのカルーセル表示
テンプレートメッセージのカルーセル表示もかなり苦戦しました。YouTube APIからのデータは取れているのにエラーで上手くいかず、原因箇所特定に苦戦しました。
原因は、タイトルの文字数制限があり、超えていた為でした。なので、文字数判定を入れて無理やり切るように工夫してます。
Title.push(res.data.items[i].snippet.title);// タイトル// 文字数が50より大きかったら末尾に...を付けたす ※MessagingApiの制限60文字を超えるとエラーになるので。if(Title[i].length>50){Title[i]=Title[i].substr(0,50)+'...';}

結果

実行結果は以下の通り、上手くデータを取ることができました。
テキストメッセージ以外は、固定メッセージを返すようにしています。
tgtns-zwkp0.gif

振り返り

課題はAPIの利用方法がまだ慣れない点だと強く感じました。
JavaScript、JSONがまだ良く分かっていない、自分の課題が見えました。
これからも書き続けてコツを掴めたら、もっとできることが増えていって楽しいだろうなぁと感じました。
(おすすめ提案とかもさせてみたかったけど、時間的に厳しかった。)


Viewing all articles
Browse latest Browse all 9050

Latest Images

Trending Articles