Google Calendarから予定を取得してLINEで自動でリマインドする
公開日:
やりたいこと
毎週月曜日の朝に、今週の予定をGoogle Calendarから取得して、下の画像のようにLINEにメッセージを送信したい。
利用するサービス
- Google API: Googleカレンダーから予定を取得する
- LINE API: LINEにメッセージを送信する
- Render.com: 毎週月曜日の朝に定期処理を実行する
それぞれ個別のサービスの使い方については記事を書いているのでよかったら、読んでみてください。今回はそれらのサービスを組み合わせた必殺技です。
https://www.yukendev.com/blogs/tips-googleapi-calendar
https://www.yukendev.com/blogs/tips-line-api
https://www.yukendev.com/blogs/tips-render-com-cron-job
完成したコード
https://github.com/yukendev/shin.jing.rui-bot
ポイント
以下は、毎週月曜日の午前9時半に実行されるコード
import { getEventListFromGoogleCalendar } from "../api/google.js";
import { sendLineMessage } from "../api/line.js";
import dotenv from "dotenv";
import { parseCalendarEvent, parseToLineMessage } from "../utils/calendar.js";
import dayjs from "dayjs";
/*
日本時間で毎週月曜日の午前9時半に実行されるジョブ
*/
dotenv.config();
const myId = process.env.YUKEN_LINE_ID; // 自分のLINEのID
const shinjingruiGroupId = process.env.SHINJINGRUI_LINE_GROUP_ID; // グループのLINEのID
const sendGoogleCalendarEvents = async () => {
const minDate = dayjs().set("hour", 0).set("minute", 0); // 今日の00時00分
const maxDate = minDate.add(7, "d").set("hour", 23).set("minute", 59); // 1週間後の23時59分
try {
// 今日の00時00分から1週間後の23時59分までの予定を取得
const result = await getEventListFromGoogleCalendar(
minDate.format(),
maxDate.format()
);
if (!result) return;
const parsedData = parseCalendarEvent(result);
const lineMessage = parseToLineMessage(parsedData);
if (shinjingruiGroupId !== undefined) {
sendLineMessage(
shinjingruiGroupId,
"今週の予定です!今週もゆっくり頑張りましょう🐈⬛"
);
sendLineMessage(shinjingruiGroupId, lineMessage);
}
} catch (err) {
if (myId !== undefined) {
sendLineMessage(myId, "カレンダーイベント取得中にエラーが発生しました🚨");
}
}
};
sendGoogleCalendarEvents();
以下はカレンダーの予定取得部分です。詳しくは別の記事で解説していますが、googleのapiを利用して、指定された範囲の予定一覧を取得しています。
import dotenv from "dotenv";
import { google } from "googleapis";
dotenv.config();
const clientId = process.env.GOOGLE_OAUTH_CLIENT_ID;
const clientSecret = process.env.GOOGLE_OAUTH_CLIENT_SECRET;
const refreshToken = process.env.GOOGLE_OAUTH_REFRESH_TOKEN;
const calendarId = process.env.CALENDAR_ID;
const getGoogleOAuth = async () => {
const googleOAuth = new google.auth.OAuth2(
clientId,
clientSecret,
"http://localhost"
);
// 毎回のリクエスト時に新しいアクセストークンを取得
googleOAuth.setCredentials({
refresh_token: refreshToken,
});
try {
const accessTokenResponse = await googleOAuth.getAccessToken();
const accessToken = accessTokenResponse.token;
if (!accessToken)
throw new Error("有効なアクセストークンを取得できませんでした");
googleOAuth.setCredentials({
access_token: accessToken,
});
return googleOAuth;
} catch (err) {
console.log("エラーの中身", err);
throw new Error("アクセストークン取得時にエラーが発生しました");
}
};
/**
* @param timeMin new Date().toISOString() etc...
* @param timeMax new Date().toISOString() etc...
*/
export const getEventListFromGoogleCalendar = async (
timeMin: string,
timeMax: string
) => {
try {
const googleOAuth = await getGoogleOAuth();
const calendar = google.calendar({ version: "v3", auth: googleOAuth });
const res = await calendar.events.list({
calendarId,
timeMin,
timeMax,
timeZone: "Asia/Tokyo",
});
if (!res.data.items)
throw new Error("正常にイベントを取得できませんでした");
const events = res.data.items.reverse();
return events;
} catch (err) {
console.log("カレンダーからイベント取得時にエラーが発生しました", err);
}
};
以下はRender.comでデプロイする用のrender.yml
ファイルです。
render.yml
services:
# 日本時間の毎週土曜日の午前9時30分に実行
- type: cron
name: saturday job
runtime: node
schedule: "30 0 * * 6"
buildCommand: pnpm install && pnpm run build
startCommand: pnpm run job:saturday
region: singapore
# 日本時間の毎週月曜日の午前9時30分に実行
- type: cron
name: monday job
runtime: node
schedule: "30 0 * * 1"
buildCommand: pnpm install && pnpm run build
startCommand: pnpm run job:monday
region: singapore
# 日本時間の毎月1日の午後12時に実行
- type: cron
name: monthly job
runtime: node
schedule: "0 3 1 * *"
buildCommand: pnpm install && pnpm run build
startCommand: pnpm run job:monthly
region: singapore
今回の予定を取得してLINEで通知する以外の定期処理の設定も入っていますが、これでRender.com
に簡単にデプロイすることができます。
完成!
これでこんな感じのLINEが毎週月曜に自動的に送信されます!ハッピー!
最後に
自分で作ったシステムが実際に身近なところで動いて、役に立っていると嬉しいですね。
では
Bye