##はじめに
GoogleDriveAPIを触っていたので、LINEBotに送信した画像を代わりにアップロードし、共有URLを返して欲しくなったので実装してみました。
##どうなりたいか
LINEBotに送った画像をGooleDriveにアップロードし、共有URLを返してくれるDEMO #lineapi pic.twitter.com/eHoLXtrQvb
— ようかん / Yosuke Inoue @LAE (@inoue2002) January 23, 2021
単純に画像URLが欲しい時に使う感じです。(パソコンだとなんとでもなるけど、スマホ単体の時には結構助かる)
###①画像を受け取るLINEBotを実装する
LINEBotでユーザーから画像メッセージを受け取ると以下のようなJSONが送られてきます。
{
"type": "message",
"replyToken": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"source": { "userId": "123456789abcdefghijk", "type": "user" },
"timestamp": 1611364562326,
"mode": "active",
"message": {
"type": "image",
"id": "13429433729723",
"contentProvider": {
"type": "line"
}
}
}
LINE Messaging APIでは直接画像データが送られてくる訳ではないので注意が必要です。
JSONの中のmessage
プロパティの中にあるid
を使ってコンテンツ取得のAPIを叩くことでデータを取得することができます。
※画像の他にも動画や音声ファイルなども同じようにid
が送られてきます。
詳しくは公式のリファレンスのこちらをご覧ください。
###②メッセージIDから画像データを取得する
LINE Messaging APIにはユーザーが送ってきたデータをコンテンツ取得のAPIを利用して扱うことができます。詳しくは公式リファレンスはのこちらをご覧ください。
nodejsだと以下のように利用できます(公式リファレンス引用)
const line = require('@line/bot-sdk');
const client = new line.Client({
channelAccessToken: '<channel access token>'
});
client.getMessageContent('<messageId>')
.then((stream) => {
stream.on('data', (chunk) => {
...
});
stream.on('error', (err) => {
// error handling
});
});
###③サービスアカウントを作成する
まず、サービスアカウントというものを作成しなければいけません。
LambdaからgoogleDriveAPIを操作するこちらの記事の通りにサービスアカウントを作成し、連携することで、google APIを利用することができるようになります。
###④サービスアカウントにGoogle Driveのファイルを共有する
画像をアップロードする権限を付与しなければいけません。
サービスアカウントを作成したときにダウンロードするJSONの中にあった、client_email
のメールアドレスをコピーし、画像をアップロードしたいDriveのファイルをそのメールアドレスに共有します。
▼GoogleDriveでフォルダ共有の方法
###⑤フォルダIDを取得する
先ほどサービスアカウントに共有したフォルダを開き、そのフォルダのIDを取得します。
https://drive.google.com/drive/u/1/folders/xxxxxxxxxxxxxxxxxxxxxxxx
フォルダを開いた状態の時のurlを確認し、/folders以降のxxxxxxxxxxxxxxxxxxxxxxxx
をコピーします。
###⑥Google APIでGoogle Driveにアップロードする
画像をアップロードする部分は以下のように書くことができます。
const drive = google.drive({ version: "v3", auth: jwtClient });
//アップロードする画像のデータを取得
const imageStream = await client.getMessageContent(event.message.id);
var fileMetadata = {
//nameはDriveに保存する時のファイル名になります
name: `photo.jpg`,
parents: ["<先ほど取得したフォルダID>"],
};
var media = {
mimeType: "image/jpeg",
body: imageStream,
};
await drive.files.create(
{
resource: fileMetadata,
media: media,
fields: "id",
},
function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
//file.data.idをアップロードされたファイルID
resolve(file.data.id);
}
}
);
###⑦返ってきたファイルIDを元に画像URLを作る
https://drive.google.com/uc
にパラメータとして先ほど取得したファイルIDをつけることで画像URLが完成します。
ex)
https://drive.google.com/uc?id=1T4QABnxnU_gNt6ORxNvnKU9EiiFxn795
###⑧応答するメッセージを作成(リファレンス引用)
応答メッセージの記述も公式リファレンスを参考にしながら書くことができます。こちら
const line = require('@line/bot-sdk');
const client = new line.Client({
channelAccessToken: '<channel access token>'
});
const message = {
type: 'text',
text: '保存に成功したよ!https://drive.google.com/uc?id=1T4QABnxnU_gNt6ORxNvnKU9EiiFxn795'
};
client.replyMessage('<replyToken>', message)
.then(() => {
...
})
.catch((err) => {
// error handling
});
▼成功したらこんな感じ
#最後に
はじめてGoogle Drive APIを触ったついでに作ってみたのですが、やっぱり何かと画像URLを作成してくれるのは楽ですよね。PCがあればそれほど必要ないかもしれないですが、何かと役に立ちますよ。是非皆さんも挑戦してみてください。お疲れ様でした。
▼ちなみにGoogleDriveの反映スピード半端ないです。
LINEBot▶️googleDrive 画像のアップロードに成功した#lineapi pic.twitter.com/PC59b6CmfG
— ようかん / Yosuke Inoue @LAE (@inoue2002) January 20, 2021