【なんでも自動化してみたい🤖④】GAS x Disney API x LINE x Wikipedia毎日ディズニーキャラを教えてBot!!!!!
前回までは
【なんでも自動化してみたい🤖1.1】 Twitter ✖️ note ✖️ GAS (Google App Script)
【なんでも自動化してみたい🤖②】 LINE BOT + GAS + Heroku + OpenWeatherMAP API ⛈⛈⛈
1. Disney APIについて🐭
2. GASでDisney APIを取得❗️❗️❗️
function newDisney() {
return new Disney();
}
class Disney {
constructor() {
this.baseUrl = 'https://api.disneyapi.dev/characters';
}
/**
* @typedef {object} Args
* @property {number} id
* @property {number} page
*
* @param args {Args} args
*/
_callAPI(args) {
args = args || {};
return Http.getJson(`${this.baseUrl}/${args.id || ''}?page=${args.page ? args.page : 1}`);
}
getCharacters(page) {
return (this._callAPI({ page }) || {}).data;
}
getCharacter(id) {
if (!id) throw new Error('id is required');
return this._callAPI({ id });
}
getTotalPages() {
// TODO: キャッシュするべき
return this._callAPI().totalPages;
}
getRamdomCharacter() {
const total = this.getTotalPages();
const idx = Math.floor(Math.random() * total);
const characters = this.getCharacters(idx);
const character = characters[Math.floor(Math.random() * characters.length)];
return character;
}
}
3. GASでWikipediaからの情報を取得🌐
function newWiki() {
return new WikipediaDataSource();
}
class WikipediaDataSource {
/**
* @typedef {object} WikiArgs
* @property {number} query
*
* @param args {WikiArgs} args
*/
_callAPI(args) {
if (!args || !args.query) {
throw new Error('Query text is required');
}
const url = `https://ja.wikipedia.org/w/api.php?action=query&format=json&list=search&srsearch=${args.query}&srlimit
=500`;
return Http.getJson(encodeURI(url));
}
/**
* @typedef {object} Page
* @property {string} title
* @property {string} link
* @property {string} summary
*
* @param {string} text
* @return {Array<Page>}
*/
getPages(text) {
const response = this._callAPI({ query : text });
if (!response.query || !response.query.search || !response.query.search.length) {
return [];
}
return response.query.search.map(info => (
{
title : info.title,
summary : info.snippet.replace(/(<([^>]+)>)/gi, ''),
link : `https://ja.wikipedia.org/wiki/${info.title}`,
}
));
}
}
参考
4. LINE Botについて
**
* @param {string} token
* @param {string} targetGroupId
* @return {LineStreamer}
*/
function newLine(token, targetGroupId) {
return new LineStreamer(token, targetGroupId);
}
const APIEndpointBase = "https://api.line.me";
const APIEndpointPushMessage = "/v2/bot/message/push"
class LineStreamer {
constructor(token, targetGroupId) {
this.token = token;
this.groupId = targetGroupId;
}
/**
* @param {string} text
* @param {string} to
*/
publishTextMessage(text, to) {
const headers = {
Authorization : `Bearer ${this.token}`,
"Content-Type" : "application/json; charset=UTF-8",
};
const body = JSON.stringify({
to : to || this.groupId,
messages : [{ type : 'text', text }],
});
return Http.post(`${APIEndpointBase}${APIEndpointPushMessage}`, { body, headers });
}
publishImageURL(url, to) {
const headers = {
Authorization : `Bearer ${this.token}`,
"Content-Type" : "application/json; charset=UTF-8",
};
const body = JSON.stringify({
to : to || this.groupId,
messages : [
{
type : "image",
originalContentUrl : url,
previewImageUrl : url,
},
],
});
return Http.post(`${APIEndpointBase}${APIEndpointPushMessage}`, { body, headers });
}
}
5. DBの代わりにスプレッドシート田
6. 適当なユースケースをまとめる
function pushDisney(line, disney, db, wiki) {
const character = disney.getRamdomCharacter();
const films = character.films.map(film => film).join('\n') +
character.shortFilms.map(film => film).join('\n') +
character.videoGames.map(film => film).join('\n') +
character.tvShows.map(film => film).join('\n');
const query = db.select(UseCase.disney_character_db.DB_NAME);
// Wikipediaを検索
const info = wiki.getPages(character.name) || [];
const filmInfo = (character.films.length ? wiki.getPages(character.films.join(" ")) : []) || [];
const tvInfo = (character.tvShows.length ? wiki.getPages(character.tvShows.join(" ")) : []) || [];
const videoGamesInfo = (character.videoGames.length ? wiki.getPages(character.videoGames.join(" ")) : []) || [];
// 既にお知らせ済みなら無効・それ以外はdbに挿入
if (query.read(`characterID=${character._id}`)) return console.log('already ', character);
query.insertValues(
[
UseCase.disney_character_db.toRecord(
character._id,
character.name,
character.imageUrl,
character.films.join(', '),
character.tvShows.join(', '),
character.videoGames.join(', '),
character.parkAttractions.join(', '),
character.allies.join(', '),
character.enemies.join(', '),
character.url,
),
],
);
// Wikipediaから関連記事を探す
const foundInfo = (() => {
const foundInfo = info ? info.find(value => value.summary.match(/ディズニー|Disney/)) : undefined;
const foundFilmInfo = filmInfo ? filmInfo.find(value => value.summary.match(/ディズニー|Disney/)) : undefined;
const foundTVInfo = tvInfo ? tvInfo.find(value => value.summary.match(/ディズニー|Disney/)) : undefined;
const foundvideoGamesInfo = videoGamesInfo ? videoGamesInfo.find(value => value.summary.match(/ディズニー|Disney/)) : undefined;
if (foundInfo) return foundInfo;
if (foundFilmInfo) return foundFilmInfo;
if (foundTVInfo) return foundTVInfo;
if (foundvideoGamesInfo) return foundvideoGamesInfo;
return {};
})();
// Lineに画像・文字列を送信!
line.publishImageURL(character.imageUrl);
line.publishTextMessage('名前: ' +character.name + '\n\n作品:\n' + films + '\n' +
[foundInfo.title, foundInfo.summary, foundInfo.link].join("\n\n"));
}
まとめ🙇♂️
今回はソースコード貼るだけですみません🙇♂️
許してください🙇♂️
これで、朝起きたら自動でディズにキャラクターについてお知らせがきます!
今まで、知らなかったキャラクターが分かることができて毎日ハッピーです?????
次回はGmailからGASを使って楽天カードの使用内容を調べてみる感じの記事を書こうかなと思います。