デッキ登録がLINEでできるBOT作ってみた

 チャットボット作る勉強がてらに作りました。

作成言語

Google App Script

コード

これ。こういうの作りなれてないのでめちゃくちゃ汚いです。このまま運用するのはあまり推奨しません。
日付の取得にmoment.jsを利用しているのでそちらをライブラリに追加してください。

//LINE Messaging APIのチャネルアクセストークン
var LINE_ACCESS_TOKEN = "";

//画像を保存するフォルダーID
var GOOGLE_DRIVE_FOLDER_ID = "";
//データを補完するスプレッドシート
var SPREADSHEET_ID ="";


//LINE Messaging APIからPOST送信を受けたときに起動する
// e はJSON文字列
function doPost(e){
  if (typeof e === "undefined"){
    //eがundefinedの場合動作を終了する
    return;
  } 

  //JSON文字列をパース(解析)し、変数jsonに格納する
  var json = JSON.parse(e.postData.contents);

  //受信したメッセージ情報を変数に格納する
  var reply_token = json.events[0].replyToken; //reply token
  var messageId = json.events[0].message.id; //メッセージID
  var messageType = json.events[0].message.type; //メッセージタイプ
  var userId=JSON.parse(e.postData.contents).events[0].source.userId;
  writeSpredsheet(userId,userId,1);
  var ssID=searchID(userId);
  //LINEで送信されたものが画像以外の場合、LINEで返信し動作を終了する
  if(messageType == "image"){
    var LINE_END_POINT = "https://api-data.line.me/v2/bot/message/" + messageId + "/content";
  
  //変数LINE_END_POINTとreply_tokenを関数getImageに渡し、getImageを起動する
    getImage(LINE_END_POINT, reply_token,userId);
  }
  
  if(messageType=="text"){
    var userMessage = JSON.parse(e.postData.contents).events[0].message;
    if(userMessage.text=="regist_check"){
      sendMessage(reply_token,regist_out(userId));
    }
    else if(userMessage.text=="delete"){
      deletecell(ssID,2)
      deletecell(ssID,3)
      sendMessage(reply_token,"登録情報を削除しました。")
    }
    else if(userMessage.text=="regist" && checkcell(ssID,2)==1){
      sendMessage(reply_token,"ユーザー名を入力してください")
    }
    else if(checkcell(ssID,2)==1){
      writeSpredsheet(userId,userMessage.text,2)
      sendMessage(reply_token,"デュエマIDを入力してください")
    }
    else if(checkcell(ssID,3)==1){
      writeSpredsheet(userId,userMessage.text,3)
      sendMessage(reply_token,"デッキリストを入力してください")
    }else if(checkcell(ssID,3)==0){
      sendMessage(reply_token,"デッキリストを入力してください")
    }
    else{
      sendMessage(reply_token,regist_out(userId));
    }
  }

  
}


//Blob形式で画像を取得する
function getImage(LINE_END_POINT, reply_token,userId){
  //ファイル名に使う現在日時をMomentライブラリーを使って取得
  var date = Moment.moment(); //現在日時を取得
  var formattedDate = date.format("YYYYMMDD_HHmmss");

  try {
    var url = LINE_END_POINT;

    var headers = {
      "Content-Type": "application/json; charset=UTF-8",
      "Authorization": "Bearer " + LINE_ACCESS_TOKEN
    };

    var options = {
      "method" : "get",
      "headers" : headers,
    };

  var res = UrlFetchApp.fetch(url, options);

  //Blob形式で画像を取得し、ファイル名を設定する
  //ファイル名: LINE画像_YYYYMMDD_HHmmss.png
  var imageName=userId+"_"+formattedDate + ".png"
  var imageBlob = res.getBlob().getAs("image/png").setName(imageName)

  //変数imageBlobとreply_tokenを関数saveImageに渡し、saveImageを起動する
  saveImage(imageBlob, reply_token,userId)
  
  } catch(e) {
  //例外エラーが起きた時にログを残す
  Logger.log(e.message);
  }
}
function regist_out(userId){//登録内容の出力
  var ss=SpreadsheetApp.openById(SPREADSHEET_ID)
  var sheet=ss.getSheetByName('シート1');
  var row=searchID(userId);
  if(checkcell(row,2)==1||checkcell(row,3)==1){
    return "登録ができていません。もう一度登録を行ってください。"
  }
  text=sheet.getRange(row,3).getValue()+" "+sheet.getRange(row,2).getValue();
  return text;
}
function checkcell(row,column){//セルの中に値があるのかのチェック
  var ss=SpreadsheetApp.openById(SPREADSHEET_ID)
  var sheet=ss.getSheetByName('シート1');
  
  if(sheet.getRange(row,column).isBlank()==true){
    var a=1;
  }
  else{
    a=0;
  }
  return a;
}
function deletecell(row,column){//セルの値を削除
  var ss=SpreadsheetApp.openById(SPREADSHEET_ID)
  var sheet=ss.getSheetByName('シート1');
  sheet.getRange(row,column).clearContent();
  
}

//画像をGoogle Driveのフォルダーに保存する
function saveImage(imageBlob, reply_token,userId){
  try{
    var folder = DriveApp.getFolderById(GOOGLE_DRIVE_FOLDER_ID);
    var file = folder.createFile(imageBlob);
    var message = "デッキ登録が完了しました";
    writeSpredsheet(userId,file.getUrl(),4)
    //変数reply_tokenとmessageを関数sendMessageに渡し、sendMessageを起動する
    sendMessage(reply_token, message)

  } catch(e){
    //例外エラーが起きた時にログを残す
    Logger.log(e)
  }
}
function searchID(id){//idを検索して存在した行を返す、存在しなければ末尾を返す
  var ss=SpreadsheetApp.openById(SPREADSHEET_ID)
  var sheet=ss.getSheetByName('シート1');
  var lastRow = sheet.getLastRow();
    
    for(var i = 2; i <= lastRow; i++) 
    {
          if(  sheet.getRange(i, 1).getValue() === id)
          {   
            Logger.log(sheet.getRange(i, 1).getValue());
            return i;
          }
    }
    lastRow=parseInt(lastRow);
    return lastRow+1;
}
function writeSpredsheet(id,text,column){//id:ユーザーid,text:書き込む内容,column:書き込む列 値をセルに書き込む
  var ss=SpreadsheetApp.openById(SPREADSHEET_ID)
  var sheet=ss.getSheetByName('シート1');
  var row=searchID(id);
  row=parseInt(row)
  sheet.getRange(row,column).setValue(text);

}

//ユーザーにメッセージを送信する
function sendMessage(reply_token, text){
  //返信先URL
  var replyUrl = "https://api.line.me/v2/bot/message/reply";

  var headers = {
    "Content-Type": "application/json; charset=UTF-8",
    "Authorization": "Bearer " + LINE_ACCESS_TOKEN
  };
  
  var postData = {
    "replyToken": reply_token,
    "messages": [{
                  "type": "text",
                  "text": text
                  }]
  };

  var options = {
    "method" : "post",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };

  //LINE Messaging APIにデータを送信する
  UrlFetchApp.fetch(replyUrl, options);
}

このBOTでできること

ラインで画像でのデッキ登録を行うことができます。デュエマIDとユーザー名と共にデッキリストの画像がスプレッドシートに保存されます。

右からlineのユーザーID、ユーザーネーム、デュエマID、保存されてるドライブのアドレス


導入方法

line bot チャンネルを作る

この辺の記事参考にしたらできると思います。

スプレッドシートと画像を保存するフォルダをドライブに用意する。

これはドライブ上のどこでもいいです。任意の場所に作成してIDを控えておいてください。

IDをコード内に記入する

LINE Messaging APIのチャネルアクセストークンとスプレッドシートのID,フォルダーのIDをコード内の指定の場所に記入してください。

//LINE Messaging APIのチャネルアクセストークン
var LINE_ACCESS_TOKEN = "";

//画像を保存するフォルダーID
var GOOGLE_DRIVE_FOLDER_ID = "";
//データを補完するスプレッドシート
var SPREADSHEET_ID ="";

デプロイを行う

上部の青いボタンからデプロイを行ってください。

リッチメニューを作成する

LINEオフィシャルアカウントマネージャーからリッチメニューを作成してください。
テキストでregist,regist_check,deleteのボタンを3つ作ってください。

こんな感じでボタンを3つ用意してください

これでbotが稼働します。

実際の動作

ラインアカウント側の動作です。

デッキ登録のボタンを押します。

押すとこのようにユーザー名、デュエマID、デッキリストの送信を促されるので、それに従って情報を入力してください。

デッキリストは画像形式で受け付けています。下のように画像を送信してください。デッキ登録が完了するとその旨が送られてきます。

登録確認を押すと現在登録されているデュエマIDと名前が送信されてきます。
登録削除を押すと登録情報を削除します。

このように登録削除を行うと登録確認を行っても登録情報が存在しないため、登録ができていない旨が送信されてきます。
再びデッキ登録を行うと、再度情報がスプレッドシートに記録されます。

このようにデッキを登録すると以下のように登録してあるスプレッドシートに保存されます。

個人情報だけ誤魔化してあります。実際には正しく記録されます。


追加したい機能

運営への連絡

運営へ質問がある場合にチャットで連絡できるといいなと思ってます。bot起動しながらチャットできなかった気もしますが、問い合わせ事項をスプシに出力とかすれば問題なかったりするんですかね。

マッチング連携

スイスドローのマッチングがラインに送られてくると便利なのでやりたいです。

プレイヤーの呼び出し

運営側から任意のプレイヤーにメッセージを送れるようにしたいです。

結果報告

同じく対戦結果の報告をライン上でできるようにしたいです。勝った側入力だけだと不正ができちゃうので相手側に確認連絡なんかができないといけないですね。この辺厳密にやると大変そうですけど、実際のCSでは結構適当にやっても何とかなってるので大規模想定しないなら適当でいいのかもしれません。




反省と問題点と感想

めちゃくちゃ端折っていますが、これでbotに送られてきた情報がスプレッドシートで管理されます。
デッキ登録終了段階でbotを停止すればそれ以降の時間の提出を防げますが、多分時間で区切れるように内部で処理した方がいいです。それかその時間になったら別の場所にスプレッドシートを保存したりするといいのかもしれません。
実際の運用はしてないのでその辺の運用に関する問題点は無限にあると思いますのでフィードバックくれたりすると対応するかはともかく助かります。
また、画像メッセージについて調べるのが面倒だったため、登録したデッキ内容の確認ができません。フォルダ内を公開にしとくと他人のデッキを見れてしまう可能性が出てしまうため、それの対策が分からないので辞めました。
大量のアクセスがあった場合なんかも想定してないのでトラブルが起きそうです。その確認のためにもデッキ登録ができているかくらいの確認とできていない場合に個別にメッセージ送れるみたいな機能があるといいのかもしれません。
このような点や他にも実際に運用するにはいくつか課題がありますが、小規模の大会なら便利に使える程度にはなった気がします。
始めてラインボットを作りましたが意外と簡単にそれっぽいものができるので楽しかったです。
ラインでデッキ提出ができるとめちゃくちゃ便利なので、もっと上手な人がこういうの作って公開してくれたらいいなーと思ってます。是非パクったり、改良したりしてください。


この記事が気に入ったらサポートをしてみませんか?