見出し画像

RSSフィードからDiscord通知を行うGoogle Apps Script入門

こんにちは!今回は、Google Apps Scriptを使って、RSSフィードの更新をDiscordに通知する方法を解説します。このスクリプトを使えば、お気に入りのブログやニュースサイトの更新を自動でチェックし、Discordで通知を受け取ることができます。


1. スクリプトの全体構造

このスクリプトは、以下の主要な部分で構成されています:

  1. 定数の定義

  2. メイン関数(`main`)

  3. RSSフィード処理関数(`processFeed`)

  4. 記事処理関数(`processItem`)

  5. Discord送信関数(`sendToDiscord`)

  6. トリガー設定関数(`createTimeTrigger`)

  7. スクリプトプロパティ設定関数(`setScriptProperties`)

それでは、各部分を詳しく見ていきましょう。

2. 定数の定義とスクリプトプロパティ

const SPREADSHEET_ID = PropertiesService.getScriptProperties().getProperty('SPREADSHEET_ID');
const DISCORD_WEBHOOK_URL = PropertiesService.getScriptProperties().getProperty('DISCORD_WEBHOOK_URL');

ここでは、スクリプトプロパティから重要な情報を取得しています。スクリプトプロパティとは、Google Apps Scriptで使用する変数を安全に保存する機能です。

スクリプトプロパティの設定方法

  1. スクリプトエディタを開く

  2. 左側のメニューから「プロジェクトの設定」を選択

  3. 「スクリプトプロパティ」タブをクリック

  4. 「行を追加」をクリックし、以下の項目を設定:

    • `SPREADSHEET_ID`: RSSフィードのURLが記載されているスプレッドシートのID

    • `DISCORD_WEBHOOK_URL`: Discord通知用のWebhook URL

また、以下の関数を使って、コードからスクリプトプロパティを設定することもできます:

function setScriptProperties() {
  const scriptProperties = PropertiesService.getScriptProperties();
  scriptProperties.setProperties({
    'SPREADSHEET_ID': 'あなたのスプレッドシートIDをここに入力',
    'DISCORD_WEBHOOK_URL': 'あなたのDiscord WebhookのURLをここに入力'
  });
  console.log('スクリプトプロパティが設定されました。');
}

この方法を使う場合は、セキュリティ上の理由から、設定後にこの関数を削除することをお勧めします。

スクリプトプロパティの設定

3. メイン関数(`main`)

function main() {
  console.log('main関数が開始されました。');
  
  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getActiveSheet();
  const data = sheet.getDataRange().getValues();
  
  console.log(`スプレッドシートから ${data.length} 行のデータを取得しました。`);
  
  // ヘッダーを除いてデータを処理
  const rssFeeds = data.slice(1).map(row => ({
    title: row[0],
    url: row[1]
  }));

  rssFeeds.forEach(processFeed);
}

この関数は、スクリプトの起点となります。主な処理は以下の通りです:

  1. スプレッドシートを開く

  2. データを取得

  3. ヘッダー行を除いてRSSフィードの情報を抽出

  4. 各フィードに対して`processFeed`関数を実行

4. RSSフィード処理関数(`processFeed`)

function processFeed(feed) {
  console.log(`フィード処理開始: ${feed.title}`);
  try {
    const xmlContent = UrlFetchApp.fetch(feed.url).getContentText();
    const document = XmlService.parse(xmlContent);
    const root = document.getRootElement();
    const channel = root.getChild('channel');
    const items = channel.getChildren('item');
    console.log(`${items.length} 件の記事を取得しました。`);

    const now = new Date();
    const twentyFourHoursAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);

    items.forEach(item => {
      const pubDate = new Date(item.getChildText('pubDate'));
      if (pubDate >= twentyFourHoursAgo) {
        processItem(item, feed.title);
        Utilities.sleep(1000); // Discordのレート制限を避けるために1秒待機
      }
    });
  } catch (error) {
    console.error(`フィード処理中にエラーが発生しました: ${feed.title}`, error);
    sendToDiscord(`エラー: "${feed.title}" のフィード処理中に問題が発生しました。`);
  }
}

この関数は各RSSフィードを処理します:

  1. フィードのURLからXMLコンテンツを取得

  2. XMLを解析し、記事(item)を抽出

  3. 過去24時間以内の記事のみを処理

  4. 各記事に対して`processItem`関数を実行

5. 記事処理関数(`processItem`)

function processItem(item, feedTitle) {
  const title = item.getChildText('title');
  const link = item.getChildText('link');
  const message = `**${feedTitle}**\n[${title}](${link})`;
  if (message.trim().length > 0) {
    sendToDiscord(message);
  } else {
    console.log('空のメッセージは送信しません。');
  }
}

この関数は個々の記事を処理し、Discord用のメッセージを作成して送信します。

6. Discord送信関数(`sendToDiscord`)

function sendToDiscord(message) {
  if (!message || message.trim().length === 0) {
    console.log('空のメッセージは送信しません。');
    return;
  }

  console.log('Discordにメッセージを送信中...');
  const maxRetries = 5;
  let retries = 0;

  while (retries < maxRetries) {
    try {
      const response = UrlFetchApp.fetch(DISCORD_WEBHOOK_URL, {
        method: 'post',
        headers: {
          'Content-Type': 'application/json'
        },
        payload: JSON.stringify({ content: message }),
        muteHttpExceptions: true
      });

      const responseCode = response.getResponseCode();
      if (responseCode === 204 || responseCode === 200) {
        console.log('Discordへのメッセージ送信が完了しました。');
        return;
      } else if (responseCode === 429) {
        const retryAfter = JSON.parse(response.getContentText()).retry_after;
        console.log(`レート制限に達しました。${retryAfter}秒後にリトライします。`);
        Utilities.sleep(retryAfter * 1000);
      } else {
        throw new Error(`Discord API returned status ${responseCode}: ${response.getContentText()}`);
      }
    } catch (error) {
      console.error('Discordへのメッセージ送信中にエラーが発生しました:', error);
      retries++;
      if (retries >= maxRetries) {
        console.error('最大再試行回数に達しました。メッセージの送信を諦めます。');
        break;
      }
      Utilities.sleep(1000 * retries); // 指数バックオフ
    }
  }
}

この関数はDiscordにメッセージを送信します。主な特徴は:

  1. 空のメッセージをチェックして送信しない

  2. エラー発生時に最大5回まで再試行

  3. レート制限に対応(429エラー時に待機)

7. トリガー設定関数(`createTimeTrigger`)

function createTimeTrigger() {
  console.log('日次トリガーを作成中...');
  ScriptApp.newTrigger('main')
    .timeBased()
    .everyDays(1)
    .atHour(8)
    .create();
  console.log('日次トリガーの作成が完了しました。');
}

この関数は、スクリプトを毎日自動実行するためのトリガーを設定します。

トリガーの設定方法

  1. スクリプトエディタで`createTimeTrigger`関数を実行

  2. または、スクリプトエディタの左側メニューから「トリガー」を選択し、手動で設定

まとめ

このスクリプトを使えば、お気に入りのRSSフィードの更新を自動的にDiscordで受け取ることができます。初期設定さえ済ませてしまえば、あとは自動で動作するので非常に便利です。

ぜひ、自分好みにカスタマイズして使ってみてください!

追記 Discord側の設定


サーバー設定
連携サービス
ウェブフックのコピー

この記事が気に入ったらサポートをしてみませんか?