第 5 章
發出第一條帖
用兩步式發佈把帖文送上 Threads,並把連結自動發成主帖下面的一則回覆。
Threads 的發佈是兩步式的,不能一次過:
1. 建立容器 —— 把文字交給 Threads,取得一個 creation_id
2. 發佈容器 —— 用那個 id 正式出街
中間需要稍等,讓 Threads 處理好容器。這是官方建議的做法。
1. 加入發佈程式碼
在 Code.gs 底部加入:
/* ========================= 發佈 ========================= */
var TAB = "Calendar";
var COL = { STATUS: 0, WHEN: 1, TEXT: 2, LINK: 3, POSTED: 4, URL: 5 };
function sheet_() {
return SpreadsheetApp.getActiveSpreadsheet().getSheetByName(TAB);
}
function toast_(msg) {
SpreadsheetApp.getActiveSpreadsheet().toast(msg, "Threads", 8);
}
function token_() {
var t = props_().getProperty("ACCESS_TOKEN");
if (!t) throw new Error("尚未連接 Threads。");
return t;
}
function userId_() {
var u = props_().getProperty("USER_ID");
if (!u) throw new Error("找不到 user id,請重新連接。");
return u;
}
function query_(obj) {
return Object.keys(obj)
.map(function (k) {
return encodeURIComponent(k) + "=" + encodeURIComponent(obj[k]);
})
.join("&");
}
/**
* 兩步式發佈。傳入 replyToId 就會發成該帖的回覆。
* 回傳新帖的 media id。
*/
function publishText_(text, replyToId) {
var token = token_();
var uid = userId_();
var params = { media_type: "TEXT", text: text, access_token: token };
if (replyToId) params.reply_to_id = replyToId;
var createRes = UrlFetchApp.fetch(
API + "/" + uid + "/threads?" + query_(params),
{ method: "post", muteHttpExceptions: true }
);
var created = JSON.parse(createRes.getContentText() || "{}");
if (!created.id) {
throw new Error("建立容器失敗:" + createRes.getContentText().slice(0, 200));
}
Utilities.sleep(5000); // 讓 Threads 處理容器
var pubRes = UrlFetchApp.fetch(
API + "/" + uid + "/threads_publish?" +
query_({ creation_id: created.id, access_token: token }),
{ method: "post", muteHttpExceptions: true }
);
var published = JSON.parse(pubRes.getContentText() || "{}");
if (!published.id) {
throw new Error("發佈失敗:" + pubRes.getContentText().slice(0, 200));
}
return published.id;
}
/** 取得帖文的永久連結。 */
function permalink_(mediaId) {
var res = UrlFetchApp.fetch(
API + "/" + mediaId + "?fields=permalink&access_token=" +
encodeURIComponent(token_()),
{ muteHttpExceptions: true }
);
return JSON.parse(res.getContentText() || "{}").permalink || "";
}
/**
* 發主帖,再把連結發成自己的回覆。
* 回覆失敗不會影響已發出的主帖 —— 主帖比連結重要。
*/
function publishRow_(text, link) {
var mainId = publishText_(text, null);
if (link) {
Utilities.sleep(2000);
try {
publishText_(link, mainId);
} catch (err) {
Logger.log("回覆連結失敗(主帖已發出):" + err.message);
}
}
return { id: mainId, url: permalink_(mainId) };
}
/** 立即發佈游標所在的那一行。 */
function postSelectedRow() {
var sh = sheet_();
var row = sh.getActiveCell().getRow();
if (row < 2) {
toast_("請先選擇一行資料。");
return;
}
var values = sh.getRange(row, 1, 1, 6).getValues()[0];
var text = String(values[COL.TEXT] || "").trim();
if (!text) {
toast_("這一行沒有內容。");
return;
}
try {
var res = publishRow_(text, String(values[COL.LINK] || "").trim());
sh.getRange(row, COL.STATUS + 1).setValue("Posted");
sh.getRange(row, COL.POSTED + 1).setValue(new Date());
sh.getRange(row, COL.URL + 1).setValue(res.url);
toast_("✓ 已發佈:" + res.url);
} catch (err) {
sh.getRange(row, COL.STATUS + 1).setValue("Error");
sh.getRange(row, COL.URL + 1).setValue(String(err.message).slice(0, 300));
toast_("✗ " + err.message);
}
}
2. 把新功能加進選單
修改 onOpen:
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("Threads")
.addItem("連接 Threads", "connectThreads")
.addItem("測試連線", "testConnection")
.addSeparator()
.addItem("立即發佈選取的一行", "postSelectedRow")
.addToUi();
}
3. 試發一條
- 在
Calendar第 2 行填入內容:
| Status | Publish At | Text | Link |
|---|---|---|---|
| Draft | 測試一下自動發帖。 |
- 儲存程式碼,回試算表重新整理
- 把游標放在第 2 行任何一格
- 選 Threads → 立即發佈選取的一行
選單沒有更新? 改了
onOpen之後,單純按重新整理經常不夠——試算表會沿用快取住的舊選單,你會看見改動前那幾項。可靠的做法是把分頁完全關掉,再從試算表首頁重新開檔,強迫它冷啟動。先回 Apps Script 確認程式碼真的存好了,再這樣做。
成功的話,Status 會變成 Posted,Post URL 會出現連結。開連結確認帖文真的在你的帳戶上。
這一步不需要重新部署。重新部署只在改動
doGet(回呼行為)時才必要;選單函式是直接執行的。

4. 試一條帶連結的
再填一行,這次 Link 欄填一條網址。發佈後你會看到:主帖是純文字,連結是下面的一則回覆。
常見卡關
| 現象 | 原因 |
|---|---|
建立容器失敗 + 權限訊息 | 缺 threads_content_publish,或授權時未包含該權限 |
發佈失敗 | 容器還沒處理好。把 Utilities.sleep(5000) 加大到 8000 |
| 主帖出了、回覆沒有 | 正常的保護行為 —— 到左側「執行項目」看記錄 |
| 選單不見了,或仍是舊的項目 | onOpen 只在開檔時執行,而重新整理常常沿用快取。關掉分頁再重新開檔 |
這一章完成了什麼
- ✅ 可以由試算表一鍵發帖
- ✅ 連結自動發成回覆,主帖保持乾淨
- ✅ 發佈結果與錯誤都寫回試算表
下一章讓它自己按時發佈,不需要你在場。
步驟最後驗證於 2026年7月20日