FanSi · 內部安裝手冊

IG 輪播自動生成 + 多平台一鍵排程

丟一個主題,系統自動生出 IG 輪播圖、寫好文案,一鍵排程發到 IG、Threads、Facebook,發完自動記帳、通知手機。原本一篇手動做一兩小時,整條串起來幾分鐘跑完,還能排定時自動發。

照順序裝,每步附指令跟驗證方法。裝到哪、驗到哪,一張圖能手動發成功再往下,不要跳步。

版本 2026-07-06 · 帳號 ID/金鑰皆為 <佔位符>,填你自己的

你會用到的平台

平台用途要開什麼申請 App 要勾的權限
Instagram主發佈(輪播)IG 商業帳號+綁 FB 粉專+Meta 開發者 Appinstagram_basicinstagram_content_publishmanage_commentsmanage_messages
Threads純文字擴散Threads 帳號+Threads API Appthreads_basicthreads_content_publish
Facebook 粉專圖文,唯一支援原生排程FB 粉專+企業商家型 Apppages_manage_posts
Cloudflare R2 或 Pages圖床(發文前置,必要)Cloudflare 帳號Public 存取
Notion內容日曆/名單台賬Notion workspace+IntegrationIntegration 要在該頁 Connections 分享
Telegram發佈前審查+通知BotFather 建一支 Bot
LINE通知LINE 官方帳號+Messaging API
生圖服務(如 Higgsfield)AI 生圖生圖帳號+API/CLI

要裝的工具

工具用途安裝
Python 3全產線系統內建/brew
Playwright + ChromiumHTML 截 PNGpip install playwright && playwright install chromium
requests打 Graph APIpip install requests
PyYAML讀寫主題包pip install pyyaml
rclone上傳圖床brew install rclone
boto3(選)程式上傳 R2pip install boto3
launchd(mac)/cron(Linux)排程系統內建
sips(mac)驗裁切、壓圖內建

金鑰清單

每支 .envchmod 600,加進 .gitignore,不上版控。

服務檔名變數去哪拿
Instagraminstagram.envIG_USER_IDIG_LONG_TOKENMeta 開發者後台,短 token 換 60 天長效
Threadsthreads.envTHREADS_USER_IDTHREADS_TOKENTHREADS_APP_IDTHREADS_APP_SECRETThreads API 後台,測試人員手機接受邀請後產 token
Facebookfb.envFB_APP_IDFB_APP_SECRETFB_PAGE_IDFB_PAGE_TOKEN企業商家型 App,換永久 Page Token
Cloudflare R2r2.envR2_ACCOUNT_IDR2_ACCESS_KEY_IDR2_SECRET_ACCESS_KEYR2_BUCKETR2_PUBLIC_BASER2 → Manage API Tokens 建 S3 金鑰
Notion.envNOTION_TOKEN+各 DB idNotion → My integrations
Telegramtelegram.envTELEGRAM_BOT_TOKENTELEGRAM_CHAT_IDBotFather
LINEline.envLINE_CHANNEL_ACCESS_TOKENLINE_USER_IDLINE Developers Messaging API

IG/Threads 長效 token 約 60 天,排程每週刷。FB Page Token 可設永久(expires_at=0)。


步驟 1 · 開帳號、拿權限、手動發一則

  1. IG 轉商業帳號,綁一個 FB 粉專。
  2. Meta 開發者後台建 App,勾上表那些權限,拿到 IG_USER_ID 跟短 token。
  3. 短 token 換 60 天長效 token,存進 instagram.env
  4. 先用 curl 手動發一張圖驗證帳號通了(用一張你已有公開網址的圖):
# 建容器
curl -X POST "https://graph.instagram.com/<IG_USER_ID>/media" \
  -d "image_url=<公開圖URL>" -d "caption=測試" -d "access_token=<IG_LONG_TOKEN>"
# 拿回 {"id":"<creation_id>"},等 5 秒發佈
curl -X POST "https://graph.instagram.com/<IG_USER_ID>/media_publish" \
  -d "creation_id=<creation_id>" -d "access_token=<IG_LONG_TOKEN>"
驗證:回傳有 media_id,IG App 上看到那則貼文。這步不過,後面全部免談。

步驟 2 · 建圖床

IG Graph API 只吃公開 https 圖,本機檔一律拒收。發文前所有圖先上圖床拿公開網址。

用 Cloudflare R2:

rclone config create r2 s3 provider=Cloudflare \
  access_key_id=<R2_ACCESS_KEY_ID> secret_access_key=<R2_SECRET_ACCESS_KEY> \
  endpoint=https://<R2_ACCOUNT_ID>.r2.cloudflarestorage.com
rclone copyto 本地.png r2:<R2_BUCKET>/ig/2026-07-06/檔名.png
# 公開網址 = <R2_PUBLIC_BASE>/ig/2026-07-06/檔名.png

或用 Cloudflare Pages 靜態站當免費圖床,把 PNG 推上去拿 xxx.pages.dev/...

驗證每張上傳的圖:

curl -w "HTTP %{http_code} %{content_type} %{size_download}\n" -o /dev/null -s <URL>

HTTP 200、content-type 對、bytes 跟原檔一樣,三項全過才算。403/404 是 bucket 沒設公開存取。

生圖服務本來就回公開 URL(如 Higgsfield)的圖,直接用,不必再上傳。

步驟 3 · 做 HTML 底版

封面、內頁、結果頁三個 4:5 樣板,套下面規則,先手填文字截出一張合格圖。

尺寸(HTML 上的 frame-XxY class 決定):

class尺寸用途
frame-4x51080×1350輪播三頁都用這個
frame-9x161080×1920Reel 片頭/Stories
frame-1x11080×1080方形貼文

安全區規則(不照做會被 IG 介面切掉頭跟字):

#檢查門檻
1底部操作條=底 22%重要文字:4:5 落在 y≤1053;9:16 落在 y≤1498
2格狀縮圖裁切(1:1 置中,上下各裁 135px)頭/文字/handle 全在 y135~1215
3標題字級≥ 32px
4內文字級≥ 16px
5對比 WCAG AA一般字 ≥4.5:1、大字 ≥3:1
6Emoji每張 ≤3,封面 0~1

全身模特照 full-bleed 進 4:5 防破框,照片下壓 155px:

.s.photo .photo, .s.photo .ph_img { top: 155px; }   /* 頭最高只到 y155 */
.s.photo { background: #13160F; }                    /* 頂部深色帶 */

色票(範例,換你自家):

用途色碼
底色(禁純白)#FAF6EE
主文字#1F2823
輔色#9CB5A6
CTA#E85D3C
安全區深頂帶#13160F

配色 60% 底+主色 : 30% 功能色 : 10% CTA。字型:標題襯線、內文思源黑 300、標籤 Tenor Sans。

驗證裁切:sips -c 1080 1080 封面.png --out 檢查.jpg,目視頭跟字有沒有被切。

步驟 4 · 寫出圖腳本

Playwright 開無頭 chromium,把文字跟照片注入底版 selector,截 PNG。

python3 出圖.py --html 底版.html --out 輸出.png \
  --photo 照片.png \                # 注入 .photo img
  --text '.hook=封面鉤子文字' \      # 注入 selector innerHTML,可多次
  --hide-safe-zone                  # 截圖前移除輔助虛線

截圖用 device_scale_factor=1,只擷取 frame 區塊。

驗證:截出來的 PNG 是 1080×1350,文字照片都到位,過安全區。

步驟 5 · 串 IG 發佈

輪播三步,host 是 graph.instagram.com

1  每張子圖  POST /<IG_USER_ID>/media
             image_url=<公開URL>  is_carousel_item=true       → 各拿 child creation_id
2  建父容器  POST /<IG_USER_ID>/media
             media_type=CAROUSEL  children=<id,id,...>  caption=<文案>  → parent id
3  等 5 秒   POST /<IG_USER_ID>/media_publish
             creation_id=<parent>                            → 回 media_id
驗證        GET /<media_id>?fields=permalink,media_type,timestamp  → 撈 permalink

發完一定要撈到 permalink 才算成功,送出不等於發成功。

Reel 帶 media_type=REELSvideo_url,限動帶 media_type=STORIES,影片要輪詢容器 status_code=FINISHED 才能發。

驗證:用步驟 4 出的圖跑完三步,IG 上看到輪播,拿到 permalink。

步驟 6 · 組主題包 YAML,串成編排器

一支主腳本把「主題 → 生圖 → PNG → 安全區 → 上 CDN → 發佈」串起來,任一步失敗停下來回報,不硬往下衝。

主題包 YAML(鍵名層級一字不差,carousel 底下只能是 封面內頁結果頁,多內頁用 內頁1內頁4):

期數: "003"
日期: "2026-06-28"
主題: "<一句話主題>"
hashtag: "#A #B #你的品牌tag"

carousel:
  封面:
    photo_prompt: >
      <英文場景,no people no faces no text no logos>
    文字:
      ".hook": "<封面鉤子>"
  內頁:
    photo_prompt: >
      <英文場景>
    文字:
      ".hero-num": "<主數據>"
      ".body-zh": "<內文 ≤60字>"
  結果頁:
    photo_prompt: >
      <英文場景>
    文字:
      ".hl-block": "<結果重點>"
      ".cta-italic": "<CTA:留言『X』我私訊你>"

caption: |
  <IG 發文全文:鉤子→內容→單一CTA→hashtag 8~15個>

字數上限(4:5 安全區小,寧少勿多):封面鉤子 ≤20 字、內頁大字 ≤10 字+內文 ≤60 字、結果頁結論 ≤16 字+CTA ≤24 字。photo_prompt 一律英文,結尾 no people no faces no text no logos

組完跑 PyYAML 語法驗:頂層鍵齊、carousel 鍵集合等於 {封面,內頁,結果頁}、每頁有 photo_prompt

驗證:一支 YAML 丟進編排器,自動跑到 IG 出現貼文。

步驟 7 · 加調度

排程用 launchd(mac,plist 放 ~/Library/LaunchAgents/),指向非保護目錄,別指 ~/Desktop(新版 macOS 擋 launchd 讀桌面)。Linux 用 cron。

Job頻率動作
留言回覆+私訊 CTA每 2 分鐘輪詢掃留言→公開回覆+私訊 CTA,handled.json 去重
Token 刷新每週日刷 IG/Threads 長效 token
排程佇列定時掃 Threads 本地佇列到點發

發佈前 TG 審查(多平台扇出時必備),把預覽推到 Telegram,附三顆 inline 按鈕:核准全發/退改/跳過。人點核准才發:

send <批次ID> <平台清單>   → 推審查訊息+三顆按鈕
poll <批次ID> <秒數>        → 讀回 {"action":"approve|revise|skip","platforms":[...]}

規則:讀不到 approve 一律不發,逾時全停待發不自動發。圖/影片本機檔先上 CDN 拿可預覽 URL 再推。送出的 bot 要跟輪詢的 bot 同一支,否則互搶訊息。

回填 Notion:發完把 發文ID完成素材URL狀態(已發布)寫回內容日曆,寫完重新讀一次逐欄比對才算生效。失敗把「狀態=失敗」+「失敗原因」一起寫。

推播:一支 notify.py 同時推 Telegram+LINE,單邊掛不擋另一邊。

步驟 8 · 擴 Threads、FB、扇出

IG 通了再複製到其他平台。

Threads 兩步,host graph.threads.net/v1.0

1  POST /<THREADS_USER_ID>/threads
   media_type=TEXT  text=<≤500字>          (帶圖:media_type=IMAGE image_url=<URL>)  → creation_id
2  等 5 秒(帶圖 30 秒)
   POST /<THREADS_USER_ID>/threads_publish  creation_id=<id>  → media_id
驗證  GET /<media_id>?fields=permalink,timestamp

Threads 無原生排程,走本地佇列+launchd 到點才發。API 不能刪文,只能 App 手動刪。

FB 發文,host graph.facebook.com/v21.0

純文字   POST /<FB_PAGE_ID>/feed     message=<文案>
單圖     POST /<FB_PAGE_ID>/photos   url=<公開圖URL>  caption=<文案>
多圖     每張 POST /photos  url=<URL>  published=false  → 各拿 media_fbid
         再  POST /feed     message=<文案>  attached_media[0]={"media_fbid":"<id>"}
原生排程 發佈加  published=false  scheduled_publish_time=<unix秒>  (須 ≥現在+10分、≤+6個月)
驗證     GET /<post_id>?fields=permalink_url,is_published,scheduled_publish_time

FB 是三平台唯一支援 API 原生排程的,多平台定時發就靠它。

扇出(選配):一份主題,為四平台各挑錯開角度(IG 教學拆解、FB 長文+主圖、Threads 短觀點、數字人口播),並行生成→TG 審查→核准後排程發。四平台角度不能重複。


實戰提點(這幾個地方會卡,先避開)

會卡在哪怎麼過
CTA 連結還是佔位符上線前把 config 的 cta_link 改成真報名連結
IG 不吃本機圖發文前必上 CDN,對照表存 manifest.json
macOS 擋 launchd 讀桌面運作檔複製到 ~/.隱藏目錄/,launchd 指那裡
FB 加不進發文權限App 選企業商家型,不是廣告型
IG 不能刪文只能瀏覽器手動刪
TG 審查 bot 互搶訊息送出跟輪詢用同一支 bot
Token 過期排程每週刷 IG/Threads,FB 設永久

觸發詞

喊這句啟動
一鍵發IG/IG一條龍/一鍵生整篇生圖+發佈全鏈
fansi 試跑(換你的詞)只做到 PNG+caption,不真發
把這份輿情扇出/內容工廠多平台扇出
回留言/設定 IG 自動回覆留言客服+名單