Skip to main content
Glama
Nesh771

socialpost

by Nesh771
README.md
# socialpost

一個指令發到 X、LinkedIn、YouTube、Facebook 粉專、Instagram、TikTok。
有兩種用法:終端機指令(CLI),或接上 Claude 當 MCP server,讓 Claude 幫你改寫各平台版本再發。

只發自己的帳號,所以各平台都停在開發模式(Development / Testing / Sandbox mode),不用送審。

---

## 0. 安裝(Mac)

```bash
# 沒有 uv 的話先裝(Python 套件與環境管理工具)
brew install uv            # 或:curl -LsSf https://astral.sh/uv/install.sh | sh

cd ~/Downloads/social-poster
uv sync                    # 建立 .venv 並安裝套件
uv run socialpost init     # 建立 ~/.socialpost/.env
uv run pytest -q           # 跑測試,應該全綠
```

所有金鑰和 token 都放在 `~/.socialpost/`(權限 600),不在專案資料夾裡,所以專案可以放上 GitHub。

---

## 1. 各平台開發者帳號設定

每個平台做完一次就好。建議順序:LinkedIn、X、YouTube、Meta、TikTok(由簡到難)。

所有 redirect URI(回呼網址)統一用 port 8765:
- LinkedIn:`http://localhost:8765/callback`
- X、TikTok:`http://127.0.0.1:8765/callback`

### LinkedIn(個人檔案發文)
1. 到 https://www.linkedin.com/developers/apps 建立 App。LinkedIn 規定 App 要綁一個公司粉專(LinkedIn Page),沒有的話先建一個簡單的。
2. **Products** 分頁加上 `Share on LinkedIn` 和 `Sign In with LinkedIn using OpenID Connect`,這兩個是自助開通(self-serve)。
3. **Auth** 分頁:把 Client ID / Secret 填進 `.env`,Authorized redirect URLs 加 `http://localhost:8765/callback`。
4. `uv run socialpost login linkedin`

注意:LinkedIn 一般開發者拿不到 refresh token,token 約 60 天到期,`status` 會顯示剩幾天,到期再 login 一次。

### X
1. https://developer.x.com 建立 Project 和 App。
2. **User authentication settings**:
   - App permissions:**Read and write**
   - Type of App:**Native App**(public client,不需 secret)或 Web App(會給 secret,填進 `X_CLIENT_SECRET`)
   - Callback URI:`http://127.0.0.1:8765/callback`;Website URL 隨便填你的網站或 LinkedIn
3. Keys and tokens 裡的 **OAuth 2.0 Client ID** 填進 `X_CLIENT_ID`。
4. Developer Console 儲值 credits。X 現在是按次計費(pay-per-use):一般貼文約 $0.015,帶連結約 $0.20。綁卡有一次性贈送額度。
5. `uv run socialpost login x`

### YouTube
1. https://console.cloud.google.com 建立專案,啟用 **YouTube Data API v3**。
2. **Google Auth Platform / OAuth consent screen**:User type 選 External,把你自己的 Gmail 加進 **Test users**。
3. **Clients** 建立 OAuth client,類型選 **Desktop app**,下載 JSON,存成 `~/.socialpost/google_client_secret.json`。
4. `uv run socialpost login youtube`

注意:App 在 Testing 狀態時 refresh token 7 天就失效。不想每週重新登入,可以把 consent screen 改成 **In production**(不送驗證也能用,登入時會出現「未驗證的應用程式」警告,點進階 > 繼續即可)。

配額:每天約 100 次上傳,個人用綽綽有餘。

### Meta:Facebook 粉專 + Instagram
前置條件:
- IG 要轉成 **專業帳號(Creator 或 Business)**:IG App > 設定 > 帳號類型和工具。
- 要有一個 **Facebook 粉絲專頁(Page)**,並在粉專設定 > 連結的帳號,把 IG 連過去。API 不能發到 FB 個人檔案,這是 Meta 的限制。

設定步驟:
1. https://developers.facebook.com 建立 App,用途(use case)選跟「管理粉絲專頁」和「Instagram API(透過 Facebook 登入)」有關的選項。Meta 介面常改名,認權限名稱就好。
2. App settings > Basic 的 App ID / App Secret 填進 `.env`(用來把短效 token 換成長效 token)。
3. App 留在 **Development mode**。你是 App 管理員,可以直接操作自己的粉專和 IG。
4. 打開 https://developers.facebook.com/tools/explorer ,右上選你的 App,User or Page 選 User Token,加這些權限:
   `pages_show_list, pages_read_engagement, pages_manage_posts, instagram_basic, instagram_content_publish, business_management`
   按 Generate Access Token,授權時勾選你的粉專和 IG。
5. `uv run socialpost login meta`,貼上 token。程式會自動換成長效 token 並取得粉專 token(Page token 不會過期)。

IG 圖片怎麼處理:IG API 只吃公開網址的圖片。程式會先把圖片轉成 JPEG,以「未發布」狀態上傳到你的粉專拿到公開網址,IG 發完就刪掉,粉專上不會留下東西。影片走 resumable upload,直接傳本機檔案。

### TikTok
1. https://developers.tiktok.com > Manage apps > 建立 App。
2. 加入產品 **Login Kit** 和 **Content Posting API**(想用直接發布要另外打開 Direct Post)。
3. Platform 選 **Desktop**,redirect URI 填 `http://127.0.0.1:8765/callback`。
4. Scopes:`user.info.basic`、`video.upload`、`video.publish`。
5. 先用 **Sandbox**:把自己的 TikTok 帳號加成 target user,Client key / secret 填進 `.env`。
6. `uv run socialpost login tiktok`

兩種模式:
- `tiktok.mode=draft`(預設):影片送進你 TikTok App 的收件匣草稿,再到手機上加文字、音樂後發布。未審核的 App 這樣用最實際。
- `tiktok.mode=direct`:直接發布,但 App 沒通過 TikTok 審核(audit)前只能發成私人可見(`SELF_ONLY`)。

---

## 2. 用 CLI 發文

```bash
uv run socialpost status                       # 看哪些平台登入了、各平台規則

# 文字 + 圖片,發到 X 和 LinkedIn
uv run socialpost post "Autumn walk #vlog" -p x,linkedin -m ~/Pictures/photo.jpg

# 同一支影片發到所有平台,X 用短版文字,YouTube 設成不公開
uv run socialpost post "Week 8 vlog..." -p all -m ~/Movies/week8.mp4 \
  -t "Week 8 Vlog" \
  -O x="Week 8 vlog is up" \
  -o youtube.privacy=unlisted -o youtube.tags="vlog,travel"

# 用 JSON 檔(範例見 examples/post.json),先 dry-run 檢查
uv run socialpost post -f examples/post.json --dry-run
uv run socialpost post -f examples/post.json
```

| 參數 | 說明 |
|---|---|
| `-p` | 平台,逗號分隔或 `all`。別名:`ig` `fb` `yt` `li` `tt` `twitter` |
| `-m` | 媒體檔(可重複),IG 可用 2-10 個做輪播(carousel) |
| `-t` | 影片標題(YouTube、LinkedIn),沒給就用文字第一行 |
| `-O platform=文字` | 某平台用不同文字,`\n` 代表換行 |
| `-o platform.key=value` | 平台選項,見下表 |
| `--dry-run` | 只檢查不發 |
| `-y` | 不詢問直接發 |

平台選項:

| 選項 | 值 |
|---|---|
| `youtube.privacy` | `public`(預設)/ `unlisted` / `private` |
| `youtube.publish_at` | 預約發布,ISO 時間如 `2026-10-20T09:00:00-07:00` |
| `youtube.tags` | 逗號分隔 |
| `youtube.category` | 預設 22(People & Blogs) |
| `tiktok.mode` | `draft`(預設)/ `direct` |
| `tiktok.privacy` | direct 模式用,預設 `SELF_ONLY` |
| `linkedin.visibility` | `PUBLIC`(預設)/ `CONNECTIONS` |
| `x.max_chars` | 有 X Premium 可以調高,預設 280 |

每次發文結果會記在 `~/.socialpost/history.jsonl`。

發文前會先檢查每個平台的規則,例如 X 的中文字算 2、網址算 23,LinkedIn 的 `( )` `#` 等保留字元會自動跳脫(escape),避免文章被截斷。

---

## 3. 接上 Claude(MCP server)

Claude Desktop > Settings > Developer > Edit Config,在 `claude_desktop_config.json` 加:

```json
{
  "mcpServers": {
    "socialpost": {
      "command": "/opt/homebrew/bin/uv",
      "args": ["--directory", "/absolute/path/to/social-poster", "run", "socialpost-mcp"]
    }
  }
}
```

`command` 填 `which uv` 印出來的路徑,`--directory` 填這個專案在你電腦上的絕對路徑。重開 Claude Desktop 後會多三個工具:

- `list_platforms`:登入狀態和各平台規則
- `preview_post`:檢查不發
- `publish_post`:要帶 `confirm=true` 才會真的發

用法範例:「把 ~/Movies/week8.mp4 發到所有平台,LinkedIn 寫成反思型長文,X 一句話,YouTube 標題幫我想三個讓我選。」

登入(login)只能在 CLI 做,因為要開瀏覽器。

---

## 4. 已知限制

- **Facebook 個人檔案**:API 不支援,只能發粉專。
- **TikTok 照片貼文**:需要驗證網域,沒做。
- **排程**:只有 YouTube 原生支援(`youtube.publish_at`)。其他平台要排程,可以用 macOS 的 `launchd` 或 cron 定時跑 `socialpost post -f ... -y`。
- **Facebook 影片**:用一般上傳,大約 1GB 以內沒問題。
- **API 版本**:Meta Graph API 預設 `v25.0`,LinkedIn 預設 `202609`。過期時改 `.env` 裡的 `META_GRAPH_VERSION` / `LINKEDIN_VERSION`。
- 各平台 API 規則常變,某個平台突然失敗時,先看錯誤訊息裡平台回傳的原因。

---

## 5. 隱私與更新流程

公開的只有程式碼,所有個人資料都留在你的電腦上:

| 內容 | 放哪裡 | 會進 git 嗎 |
|---|---|---|
| 程式碼、README、測試、`.env.example` | 這個 repo | 會 |
| App 金鑰(Client ID / Secret) | `~/.socialpost/.env` | 不會(在 repo 外) |
| 各平台登入 token | `~/.socialpost/tokens.json` | 不會 |
| 發文紀錄 | `~/.socialpost/history.jsonl` | 不會 |
| Google client JSON | `~/.socialpost/google_client_secret.json` | 不會 |
| MCP 設定(含你的電腦路徑) | Claude Desktop 的 `claude_desktop_config.json` | 不會 |
| 自己的貼文草稿 | 專案內的 `local/` 或 `*.local.json` | 不會(已在 `.gitignore`) |

更新時的習慣:
1. 改完先跑 `uv run pytest -q`。
2. commit 前看一眼 `git diff --staged`,確認沒有路徑、帳號、token。
3. 重要更新寫進 `CHANGELOG.md` 的 `[Unreleased]`,累積到一個段落再改成版本號(例如 0.2.0),同步改 `pyproject.toml` 的 version,然後打 tag:`git tag v0.2.0 && git push --tags`,再到 GitHub 建 Release。
4. 例子和測試資料一律用假的(demo、example.com),不要放真實帳號或檔案路徑。

## 專案結構

```
src/socialpost/
  cli.py            CLI 指令
  mcp_server.py     MCP server
  service.py        檢查與發文流程(CLI 和 MCP 共用)
  content.py        Post 資料結構、字數計算、LinkedIn 跳脫
  oauth.py          本機 OAuth 回呼伺服器、PKCE
  config.py         設定與 token 儲存
  platforms/        各平台 adapter:x, linkedin, youtube, meta(facebook+instagram), tiktok
tests/              用 mock HTTP 測各平台流程
```

加新平台(例如 Threads、Bluesky):在 `platforms/` 新增一個繼承 `Platform` 的類別,實作 `login / account / check / publish`,再登記到 `platforms/__init__.py` 的 `REGISTRY`。

TDQS

A4/5.0

Scored across 3 tools

Disambiguation5/5

Each tool maps to a distinct phase: discovery (list_platforms), validation/dry-run (preview_post), and execution (publish_post). No overlapping responsibilities, and descriptions reinforce the intended sequence.

Naming Consistency5/5

All tools follow a consistent verb_noun snake_case pattern: list_platforms, preview_post, publish_post. The verbs are clear and the naming style is uniform.

Tool Count5/5

Three tools are minimal but well-scoped for a streamlined publish-with-validation workflow. Each tool has a clear, non-redundant role, fitting the typical 3-15 range.

Completeness4/5

The core workflow from platform rules to preview to publish is covered. However, there are no tools for account login/management, scheduling, or deleting/editing posts, which may limit lifecycle tasks.

Maintenance

ActivityMaintained
ResponsivenessNo issues