SYSTEM NOTICE

Auto translation by AI. Be sure, accuracy, nuances and authorial intent may not be fully reflected.
見出し画像

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.

Reference


いいなと思ったら応援しよう!