1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GAS】 X投稿+Discord通知を自動化する方法

Posted at

この記事について

この記事では、Google Apps Script(GAS)初心者向けに、X(旧:Twitter, 以降Xと記載)への自動投稿と、実行結果をDiscordに自動通知する方法を記載します。
基本的な使い方から具体的なコード例、トリガー設定までカバーしています。

目次

  1. 概要
  2. 目的
  3. 必要なもの
  4. スクリプト構成
  5. トリガー設定手順
  6. まとめ

概要

Google Apps Script(GAS)を使ってXに投稿し、その結果をDiscordへ自動通知する方法を紹介します。実際のユースケースとして、スプレッドシートのデータをもとにポストし、その投稿結果(成功・失敗)をDiscordのチャンネルにWebhookで通知します。

目的

  • GASからXに投稿
  • 実行結果(成功・失敗)をDiscordに自動通知

必要なもの

  • Google スプレッドシート
    ※今回は以下の形式を使用します。
    ID タイトル 投稿文 投稿ステータス
    1 サンプル投稿① これは自動投稿テストです①。 未投稿
    2 サンプル投稿② これは自動投稿テストです②。 投稿済み
    3 サンプル投稿③ これは自動投稿テストです③。 未投稿
  • Google Apps Script エディタ
  • Discord Webhook URL
  • XのAPI認証情報

スクリプト構成

「スプレッドシートから投稿」→「投稿処理の中でX APIに通信」→「結果をDiscord通知」という構成になっています。

ステップ1. スプレッドシートの未投稿データをXに投稿する

関数:postX()

中で呼ばれる関数:postToX() → sendXRequest() → getOAuthHeader()

🧠 処理の流れ

  • スプレッドシートから「未投稿」のデータを探す
  • 見つけたテキストをpostToX()でX(旧Twitter)に投稿
    • → この中で認証情報を元にAPIリクエストを送る関数が順に呼ばれます
  • 投稿できたら「投稿済み」に更新
  • 成否メッセージを返す(後でDiscord通知に使う)

コード(GAS)

function postX() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
  var lastMonth = new Date();
  lastMonth.setMonth(lastMonth.getMonth() - 1);

  var data = sheet.getDataRange().getValues();
  var itemToPost = null;
  var rowIndex = -1;

  for (var i = 1; i < data.length; i++) {
    if (data[i][3] === "未投稿") {
      itemToPost = {
        title: data[i][1],
        text: data[i][2],
      };
      rowIndex = i + 1;
      break;
    }
  }

  if (!itemToPost) {
    return "投稿できる新しいコンテンツがありません";
  }

  var postResponse = postToX(itemToPost.text);

  if (!postResponse || !postResponse.data || !postResponse.data.id) {
    return "ポスト失敗: " + JSON.stringify(postResponse);
  }

  sheet.getRange(rowIndex, 4).setValue("投稿済み");
  return "ポスト成功: " + itemToPost.title + "\n" + itemToPost.text;
}

function postToX(content) {
  var url = "https://api.twitter.com/2/tweets";
  var payload = { "text": content };
  return sendXRequest(url, "POST", payload, "application/json");
}

/**
 * APIへリクエストを送る関数
 * @param {string} url - APIエンドポイントのURL
 * @param {string} method - HTTPメソッド (POST/GET)
 * @param {Object} payload - 送信するデータ (nullの場合は無し)
 * @param {string} contentType - Content-Type (JSON, multipart/form-data など)
 * @returns {Object} APIのレスポンス(JSON)
 */
function sendXRequest(url, method, payload, contentType) {
  var options = {
    "method": method,
    "headers": {
      "Authorization": getOAuthHeader(method, url),
      "Content-Type": contentType
    },
    "muteHttpExceptions": true
  };
  if (payload) {
    options.payload = (contentType === "application/json") ? JSON.stringify(payload) : payload;
  }
  var response = UrlFetchApp.fetch(url, options);
  return JSON.parse(response.getContentText());
}

/**
 * OAuth1.0aの署名を作成し、OAuth認証ヘッダーを生成する関数
 * @param {string} method - HTTPメソッド (POST/GET)
 * @param {string} url - APIのURL
 * @returns {string} OAuth認証ヘッダー
 */
function getOAuthHeader(method, url) {
  var credentials = X_CREDENTIALS;
  var timestamp = Math.floor(new Date().getTime() / 1000);
  var nonce = Math.random().toString(36).substring(2, 15);

  var parameterString = [
    "oauth_consumer_key=" + credentials.consumerKey,
    "oauth_nonce=" + nonce,
    "oauth_signature_method=HMAC-SHA1",
    "oauth_timestamp=" + timestamp,
    "oauth_token=" + credentials.accessToken,
    "oauth_version=1.0"
  ].sort().join("&");

  var signatureBaseString = method + "&" + encodeURIComponent(url) + "&" + encodeURIComponent(parameterString);
  var signingKey = encodeURIComponent(credentials.consumerSecret) + "&" + encodeURIComponent(credentials.accessTokenSecret);
  var signatureBytes = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_1, signatureBaseString, signingKey);
  var signature = Utilities.base64Encode(signatureBytes);

  return 'OAuth ' +
    'oauth_consumer_key="' + credentials.consumerKey + '", ' +
    'oauth_nonce="' + nonce + '", ' +
    'oauth_signature="' + encodeURIComponent(signature) + '", ' +
    'oauth_signature_method="HMAC-SHA1", ' +
    'oauth_timestamp="' + timestamp + '", ' +
    'oauth_token="' + credentials.accessToken + '", ' +
    'oauth_version="1.0"';
}

ステップ2. 投稿の結果をDiscordに通知する

関数:sendToDiscord(message)

🧠 処理の流れ

  • ステップ①で取得した「成功」または「失敗」の結果メッセージをDiscordのWebhook URLにPOSTして通知

コード(GAS)

function sendToDiscord(message) {
  const webhookUrl = "https://discord.com/api/webhooks/XXXXX/XXXXX"; // ここを自分のWebhookに置き換えてください
  const payload = { content: message };

  const options = {
    method: "post",
    contentType: "application/json",
    payload: JSON.stringify(payload)
  };

  UrlFetchApp.fetch(webhookUrl, options);
}

ステップ3. ステップ1,2を実行する

関数:executeAndNotify()

🧠 処理の流れ

  • postX()を呼び出してXに投稿
  • その結果をsendToDiscord()で通知

→ これひとつで全体が動きます!

コード(GAS)

function executeAndNotify() {
  var result = postX();
  sendToDiscord(result);
}

トリガー設定手順

初心者でも簡単に設定できます。以下の手順で、自動実行の仕組みを構築しましょう。

  1. GASエディタ上部メニューから「トリガー」アイコンをクリック
  2. 「+ トリガーを追加」を選択
  3. 実行関数として executeAndNotify を選択
  4. イベントの種類(時間ベースなど)を選択し、実行頻度を設定
  5. 保存して完了

参考

まとめ

この構成により、スプレッドシートに登録された「未投稿」データを元にXへ投稿を行い、その処理結果をDiscordへ自動通知する仕組みが実現できます。GAS初心者でもすぐに始められる実用的な自動化テクニックです。

もし「XのAPIの使い方」や「Webhookの作成方法」などでつまずいた場合は、それぞれのドキュメントをチェックしてみてください。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?