54
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

LINEBotに送った画像をGoogleDriveに保存して共有URLを返すまで

Last updated at Posted at 2021-01-23

##はじめに
GoogleDriveAPIを触っていたので、LINEBotに送信した画像を代わりにアップロードし、共有URLを返して欲しくなったので実装してみました。

##どうなりたいか

単純に画像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だと以下のように利用できます(公式リファレンス引用)

index.js
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にアップロードする

画像をアップロードする部分は以下のように書くことができます。

index.js
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

###⑧応答するメッセージを作成(リファレンス引用)
応答メッセージの記述も公式リファレンスを参考にしながら書くことができます。こちら

index.js
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の反映スピード半端ないです。

54
57
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?