2024年7月10日水曜日

Slack が使いづらくなった

今までSlackの無料プランでRSSリーダーとして、ボットでHTMLパーサーして某掲示板のビューワーとして個人的に使っていたのだけど、制限が厳しくなってきてしまい使えなくなってしまった。

無料だから文句は言えないのだが、この際Slackには見切りをつけてDiscordに引っ越すことにした。まずDiscordでRSSリーダーチックな物を作るのに下記のページを参考にさせていただきました。

GASでRSSフィードを取得してDiscordに投稿する

サーバーレスでDiscord bot作っちゃおうってやつでGoogle App Scriptで定期的にRSSフィードをクロールし、更新があればDiscordに投稿してくれるというものです。ただ、上記のページのコードではRSS 2.0にしか対応してないのでPC WatchのRSS 1.0やロドストのAtomを指定するとエラーになってしまいます。

なので色々といじった。JavaScriptとか使ったことないんで色々とツッコミ所が多いかもしれないですがスルーしてください。

/**
 * RSSフィードから記事を取得する
 */
function getArticles() {
  // フィード定義を取得
  const feeds = getFeeds();

  for (const feed of feeds) {
    // RSSの読み込み
    console.log(feed.name + ': ' + feed.link);
    let xml = UrlFetchApp.fetch(feed.link).getContentText();
    let document = XmlService.parse(xml);
    let root = document.getRootElement();

    let rss = XmlService.getNamespace('http://purl.org/rss/1.0/');
    let dc = XmlService.getNamespace('dc', 'http://purl.org/dc/elements/1.1/');
    let rdf = XmlService.getNamespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
    let atom = XmlService.getNamespace('http://www.w3.org/2005/Atom');

    let rootTagName = root.getName().toLowerCase();
    let items;
    switch (rootTagName) {
      case 'rdf': // 1.0
        items = root.getChildren('item', rss);
        break;
      case 'rss': // 2.0
        items = root.getChild('channel').getChildren('item');
        break;
      case 'feed' :  // atom
        items = root.getChildren('entry', atom);
        break;
    }

    // スプレッドシートからデータを取得
    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;
      let link;
      let pubDate;

      switch (rootTagName) {
        case 'rdf': // 1.0
          title = item.getChild('title', rss).getText();
          link = item.getChild('link', rss).getValue();
          pubDate = Utilities.formatDate(new Date(item.getChild('date', dc).getValue()), "JST", "yyyy-MM-dd'T'HH:mm:ssXXX");
          break;
        case 'rss': // 2.0
          title = item.getChild('title').getText();
          link = item.getChild('link').getValue();
          pubDate = Utilities.formatDate(new Date(item.getChild('pubDate').getValue()), "JST", "yyyy-MM-dd'T'HH:mm:ssXXX");
          break;
        case 'feed': // atom
          title = item.getChild('title', atom).getText();
          link = item.getChild('link', atom).getAttribute('href').getValue();
          pubDate = Utilities.formatDate(new Date(item.getChild('published', atom).getValue()), "JST", "yyyy-MM-dd'T'HH:mm:ssXXX");
          break;
      }

      // URLが一致しないときは新しいデータ
      if (urls.some(url => url[0] === link)) {
        continue;
      }

      // スプレッドシートへの保存
      articlesSheet.appendRow([feed.name, title, link, pubDate]);

      // 連続投稿で怒られるので
      Utilities.sleep(1000);

      // チャンネルに投稿
      postToChannel(feed.name, title, link);

      console.log(feed.name + ': ' + title);
    }
  }
}

しばらく運用して問題なさそうならSlackのワークスペースは削除して、Discordに完全に移行する予定です。

参考情報:
TypetalkとGoogle App Scriptを組み合わせて、RSSのBOTを作ってみる。