Fetching RSS feeds and posting to Discord using GAS
Discord has a bot called MonitoRSS, but since it only allows subscribing to a maximum of 5 feeds for free, I tried creating my own using Google Apps Script.
*Slack also has an app called RSS, which has no such limits.
Webhook
From the settings of the channel you want to post to, select Integrations > Create Webhook to generate and copy the Webhook URL.
*Change the bot name and icon image as appropriate.
Prepare a spreadsheet
First, prepare a spreadsheet to manage the feeds you want to subscribe to and the articles you have fetched, rename the sheets as follows, and list the feeds you want to subscribe to.
feeds sheet
A sheet to define the RSS feeds to subscribe to. List an arbitrary feed name (highlighted when posting) and the RSS link.
Column A: RSS feed name
Column B: RSS link
articles sheet
In this sheet, articles are fetched from each feed during periodic execution, and rows for new articles are automatically inserted.
Column A: RSS feed name
Column B: Article title
Column C: Article link
Column D: Article publication date (yyyy-MM-dd'T'HH:mm:ssXXX)
Script
Edit Apps Script from the spreadsheet extensions.
Get feed definitions
/**
* フィード定義を取得
*/
function getFeeds() {
// feedsシートのA1:B最終行を取得する
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('feeds');
const lastRow = sheet.getDataRange().getLastRow();
const values = sheet.getRange(1,1,lastRow,2).getValues();
const feeds = [];
values.forEach((value) => {
const feed = {};
feed["name"] = value[0];
feed["link"] = value[1];
feeds.push(feed);
});
return feeds
}
Fetch articles from RSS feeds
/**
* RSSフィードから記事を取得する
*/
function getArticles() {
// フィード定義を取得
const feeds = getFeeds();
for (const feed of feeds) {
// RSSの読み込み
let xml = UrlFetchApp.fetch(feed.link).getContentText();
let document = XmlService.parse(xml);
let items = document.getRootElement().getChild('channel').getChildren('item');
// スプレッドシートからデータを取得
let articlesSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('articles');
let lastRow = articlesSheet.getDataRange().getLastRow();
let urls = articlesSheet.getRange(1, 3, lastRow).getValues();
// 新しい記事かどうかを古いアイテム(記事)から比較するため
items.reverse();
// RSSから取得したデータと比較と保存
for (var item of items) {
let title = item.getChild('title').getText();
let link = item.getChild('link').getValue();
let pubDate = Utilities.formatDate(new Date(item.getChild('pubDate').getValue()), "JST", "yyyy-MM-dd'T'HH:mm:ssXXX");
// URLが一致しないときは新しいデータ
if (urls.some(url => url[0] === link)) {
continue;
}
// スプレッドシートへの保存
articlesSheet.appendRow([feed.name, title, link, pubDate]);
// チャンネルに投稿
postToChannel(feed.name, title, link);
console.log(feed.name + ': ' + title);
}
}
}
Addendum: If the RSS format is RDF or similar, the document structure will differ, so you should branch by rootTagName as shown in this article to fetch items, titles, etc.
Post to channel
/**
* チャンネルに通知を投稿する
* @param {string} name フィード名
* @param {string} title 記事タイトル
* @param {string} link 記事リンク
*/
function postToChannel(name, title, link) {
const webhookURL = "https://discord.com/api/webhooks/XXXX";
const message = {
"content": '`' + name + '`\n' + '**' + title + '**' + '\n' + link
}
const param = {
"method": "POST",
"headers": { 'Content-type': "application/json" },
"payload": JSON.stringify(message)
}
UrlFetchApp.fetch(webhookURL, param);
}
*If posting to Slack, you just need to change message.content to message.text (refer to here).
Periodic execution
Finally, by setting an arbitrary trigger and setting the function to be executed to getArticles, articles will be automatically fetched from the RSS feed periodically, and if there are any new articles, they will be posted to the channel.
