以 Cloudflare Workers + grammY 構建的多平台影片下載 Telegram 機器人,
支援 YouTube、TikTok、Instagram、Twitter/X、Reddit、小紅書等平台,
無伺服器、邊緣運算、零流量費用的 R2 儲存架構。
A multi-platform video download Telegram bot built on Cloudflare Workers + grammY.
Supports YouTube, TikTok, Instagram, Twitter/X, Reddit, Xiaohongshu and more.
Serverless edge-compute architecture with zero-egress R2 storage.
Haku 以 Cloudflare Workers 為核心運行環境。使用者向 Telegram 發送影片網址,Telegram 透過 Webhook 將訊息推送至 Workers 上的 Hono 路由器,再依指令類型分發至對應的 Command Handler。影片下載優先走 Cobalt API(自架 Docker 於家庭主機),若失敗則透過 youtube-capture 非同步任務 API 備援(Windows 小主機)。最終影片以 Multipart Upload 串流至 R2,再由 Telegram 媒體端點回傳使用者。
Haku's runtime is Cloudflare Workers. A user sends a video URL to Telegram, which forwards it via Webhook to a Hono router on Workers. The router dispatches to the appropriate Command Handler. Downloads first attempt the Cobalt API (self-hosted Docker on a home machine), with youtube-capture (Windows mini PC) as an async fallback. The resulting video is multipart-streamed to R2 and served back to the user via the Telegram media endpoint.
graph TD USER["👤 使用者 / User"] TG["Telegram API"] IDX["index.ts
Hono Webhook Router"] AUTH["auth.ts
使用者配對 + 防爆破"] CMD["commands/*
download · social · callback · transcript"] PLT["platforms/*
cobalt · detect · extract · capture"] TLG["telegram.ts
Bot API Wrapper"] R2[("R2 Storage
零流量費用")] KV[("KV Store
使用者狀態")] DO["Durable Objects
StatsCounter + HistoryStore"] COB["Cobalt API
家庭主機 Docker"] CAP["youtube-capture
Windows 小主機"] WHI["OpenAI Whisper
語音轉文字"] SUB["subscribe.ts
訂閱 Cron"] USER ==>|傳送網址| TG TG ==>|Webhook POST| IDX IDX --> AUTH AUTH --> CMD CMD --> PLT CMD --> TLG PLT -->|快速路徑| COB PLT -.->|備援 fallback| CAP CMD --> DO CMD -->|儲存影片| R2 CMD -->|使用者狀態| KV CMD -.->|語音轉錄| WHI TLG ==>|回傳結果| TG TG ==> USER R2 -->|"/media/:key"| TLG SUB -.->|Cron 觸發| PLT classDef user fill:#9c7b3022,stroke:#9c7b30,stroke-width:2px classDef tg fill:#a8552e22,stroke:#a8552e,stroke-width:2px classDef infra fill:#3a5a4022,stroke:#3a5a40,stroke-width:1.5px classDef cmd fill:#7a352b22,stroke:#7a352b,stroke-width:1.5px classDef plt fill:#9c7b3022,stroke:#9c7b30,stroke-width:1.5px classDef store fill:#3a5a4033,stroke:#3a5a40,stroke-width:2px,stroke-dasharray:0 classDef ext fill:#a8552e22,stroke:#a8552e,stroke-width:1.5px,stroke-dasharray:5 5 class USER user class TG tg class IDX,TLG,AUTH,SUB infra class CMD cmd class PLT plt class R2,KV,DO store class COB,CAP,WHI ext
每一個影片請求都經過平台偵測、Cobalt 嘗試、失敗判斷、YouTube 備援四個階段。detect.ts 根據 URL 正規表達式判斷平台,extract.ts 作為協調器統籌下載策略,最後透過 Multipart Upload 串流至 R2 並以 Telegram API 回傳。
Each video request passes through four stages: platform detection, Cobalt attempt, failure adjudication, and YouTube fallback. detect.ts identifies the platform via URL regex. extract.ts acts as the coordinator that orchestrates the download strategy, streaming the result to R2 via multipart upload and returning it through the Telegram API.
flowchart TD
URL["使用者傳送 URL\nUser sends URL"]
DET["detect.ts\n偵測平台 / Detect platform"]
EXT["extract.ts\n下載協調器 / Coordinator"]
COB["Cobalt API\n家庭主機 / Home Docker"]
CHK{"下載成功?\nSuccess?"}
YT{"是 YouTube?\nYouTube?"}
CAP["youtube-capture\n非同步任務 / Async Job"]
POLL["輪詢任務狀態\nPoll job status"]
R2S["串流至 R2\nMultipart stream to R2"]
SEND["Telegram sendVideo\n或 sendDocument"]
URL --> DET --> EXT --> COB --> CHK
CHK -->|"是 / Yes"| R2S
CHK -->|"否 / No"| YT
YT -->|"是 / Yes"| CAP --> POLL --> R2S
YT -->|"否 / No"| SEND
R2S --> SEND
classDef start fill:#9c7b3022,stroke:#9c7b30,stroke-width:2px
classDef process fill:#3a5a4022,stroke:#3a5a40,stroke-width:1.5px
classDef decision fill:#a8552e22,stroke:#a8552e,stroke-width:1.5px
classDef fallback fill:#7a352b22,stroke:#7a352b,stroke-width:1.5px,stroke-dasharray:5 5
classDef output fill:#9c7b3033,stroke:#9c7b30,stroke-width:2px
class URL start
class DET,EXT,COB,R2S,POLL process
class CHK,YT decision
class CAP fallback
class SEND output
index.ts 透過 Hono 接收 Telegram Webhook POST。auth.ts 驗證 HMAC 簽名並執行使用者配對(pairing)。若配對未完成或觸發防爆破鎖定,請求立即終止。index.ts receives the Telegram Webhook POST via Hono. auth.ts verifies the HMAC signature and runs user pairing. If pairing is incomplete or a brute-force lockout triggers, the request terminates immediately.detect.ts 使用正規表達式依序比對 URL,識別出 YouTube、TikTok、Instagram、Twitter/X、Reddit、小紅書等平台,並回傳帶有 PlatformType 的偵測結果物件。detect.ts matches the URL against a series of regexes to identify the platform (YouTube, TikTok, Instagram, Twitter/X, Reddit, Xiaohongshu, etc.) and returns a detection result object with a PlatformType discriminant.cobalt.ts 向家庭主機上的 Cobalt 容器發送請求,指定 downloadMode(mute / audio / auto)和 videoQuality(144p–max)。Cobalt 透過 Cloudflare Tunnel 暴露,零公網 IP。若成功回傳可串流的媒體 URL,立即進入 R2 串流步驟。cobalt.ts sends a request to the Cobalt container on the home host, specifying downloadMode (mute / audio / auto) and videoQuality (144p–max). Cobalt is exposed via a Cloudflare Tunnel with no public IP. If it returns a streamable media URL, processing advances directly to the R2 stream step.youtube-capture.ts 向 Windows 小主機的非同步任務 API 提交任務(enqueue),並輪詢任務狀態(poll)直到完成。完成後取得媒體串流 URL 進行 R2 上傳。youtube-capture.ts submits a job (enqueue) to the async job API on the Windows mini PC, then polls job status until completion. On success, it obtains a media stream URL for R2 upload.utils.ts 的串流工具函式以分塊方式將媒體串流上傳至 Cloudflare R2,避免 Workers 記憶體限制。上傳完成後生成一個帶有 HMAC 簽名的媒體金鑰(/media/:key),可供 Telegram 存取。utils.ts upload the media stream to Cloudflare R2 in chunks, avoiding Workers memory limits. After upload, an HMAC-signed media key (/media/:key) is generated for Telegram to access the file.telegram.ts 呼叫 sendVideo 或 sendDocument,URL 指向 Workers 上的 R2 媒體端點。同步更新 StatsCounter DO(原子計數)和 HistoryStore DO(每用戶下載歷史與最愛)。telegram.ts calls sendVideo or sendDocument with a URL pointing to the R2 media endpoint on Workers. StatsCounter DO (atomic counters) and HistoryStore DO (per-user download history and favorites) are updated concurrently.Hono 路由接受 Webhook 和媒體請求,process-download.ts 封裝完整的下載管線,stats.ts 是 StatsCounter + HistoryStore DO 的薄封裝層。
Hono routes handle Webhook and media requests. process-download.ts encapsulates the complete download pipeline. stats.ts is a thin wrapper over StatsCounter and HistoryStore DOs.
helpers.ts 共用常數、型別、訊息輔助函式Shared constants, types, message helperscallback.ts Inline 按鈕回呼(語言、畫質、最愛)Inline button callbacks (lang, quality, favorites)download.ts R2 優先影片流程 + /audio 指令R2-first video flow + /audio commandtranscript.ts /sub + /transcript 字幕與轉錄處理/sub + /transcript subtitle and transcriptionsocial.ts /batch、/subscribe、/unsub、/mysubs/batch, /subscribe, /unsub, /mysubscobalt.ts Cobalt API 客戶端(downloadMode, videoQuality)Cobalt API client (downloadMode, videoQuality)detect.ts URL → 平台識別(regex 匹配)URL → Platform detection via regexextract.ts 下載協調器 + youtube-capture 備援Download coordinator + capture fallbackyoutube-capture.ts 非同步任務 API(enqueue, poll, stream)Async job API (enqueue, poll, stream)xiaohongshu.ts HTML 抓取備援(脆弱,受限頁面結構)HTML scraping fallback (fragile, layout-dependent)telegram.ts Bot API 封裝(send*, edit*, delete*)Bot API wrapper (send*, edit*, delete*)auth.ts 使用者配對 + HMAC 驗證 + 防爆破鎖定User pairing + HMAC + brute-force lockoutsubscribe.ts 訂閱 CRUD + Cron 定時檢查(6AM/6PM)Subscription CRUD + cron check (6AM/6PM)utils.ts KV 解析、HMAC、串流、媒體偵測KV parsing, HMAC, streaming, media detectioni18n.ts 7 語言:EN, zh-TW, zh-CN, FR, HI, VI, TH7 languages: EN, zh-TW, zh-CN, FR, HI, VI, THtranscript.ts OpenAI Whisper(25MB 限制)OpenAI Whisper (25MB limit)stats-counter.ts StatsCounter DO — 每用戶原子計數器StatsCounter DO — atomic per-user countershistory-store.ts HistoryStore DO — 歷史記錄、最愛、KV 遷移HistoryStore DO — history, favorites, KV migrationcontainer.ts CobaltContainer DO — 僅用於遷移(INERT)CobaltContainer DO — migration only (INERT)Telegram API Webhook 接收 + sendVideo / sendDocumentWebhook receive + sendVideo / sendDocumentCobalt 家庭主機 Docker,透過 CF Tunnel 存取Home Docker host via Cloudflare Tunnelyoutube-capture Windows 小主機,非同步任務 HTTP APIWindows mini PC, async job HTTP APIOpenAI Whisper 音訊轉文字,25MB 檔案限制Audio-to-text, 25MB file size limitCloudflare KV 使用者偏好、配對令牌、訂閱狀態User preferences, pairing tokens, subscription stateCloudflare R2 影片儲存,零流量費用(egress-free)Video storage, zero-egress-cost以下列出 Haku 目前支援的平台、下載方式、格式選項與限制。Cobalt 為主要路徑,部分平台有特殊備援或抓取方式。
The table below lists the platforms Haku currently supports, download methods, format options, and limits. Cobalt is the primary path; certain platforms have special fallback or scraping mechanisms.
| 平台 | Platform | 下載方式 | Download Method | 格式選項 | Format Options | 備援 | Fallback | 備注 | Notes |
|---|---|---|---|---|---|---|---|---|---|
| YouTube | Cobalt | 144p、360p、480p、720p、1080p、max | 144p, 360p, 480p, 720p, 1080p, max | youtube-capture | Shorts、Live 截片均支援;長影片使用非同步任務 | Shorts and live clips supported; long videos use async job | |||
| TikTok | Cobalt | 影片(含/不含浮水印)、純音訊 | Video (with/without watermark), audio only | 無None | 部分地區有速率限制 | Rate limits in some regions | |||
| Cobalt | Reels、貼文影片、Stories | Reels, post videos, Stories | 無None | 需要有效的 Cobalt Cookie 配置 | Requires valid Cobalt cookie config | ||||
| Twitter / X | Cobalt | 影片推文、GIF | Video tweets, GIFs | 無None | API 變動頻繁,穩定性依 Cobalt 版本而定 | Frequent API changes; stability depends on Cobalt version | |||
| Cobalt | 影片(含音訊合併) | Video (with audio merge) | 無None | Reddit v.redd.it 影片音訊分離需 Cobalt 合併 | Reddit v.redd.it video/audio are separate; Cobalt merges them | ||||
| 小紅書Xiaohongshu | HTML Scrape | 影片、圖片 | Video, images | 無None | HTML 抓取,脆弱;頁面結構改動即失效 | HTML scraping, fragile; breaks on page structure changes |
videoQuality)videoQuality)| 選項 | Option | 說明 | Description |
|---|---|---|---|
144 | 最低畫質,檔案最小 | Lowest quality, smallest file | |
360 | 低畫質(省流量) | Low quality (data-saving) | |
480 | 標準畫質 SD | Standard definition | |
720 | 高清 HD(預設) | High definition (default) | |
1080 | 全高清 Full HD | Full HD 1080p | |
max | 最高可用畫質 | Best available quality |
downloadMode)downloadMode)| 模式 | Mode | 說明 | Description |
|---|---|---|---|
auto | 自動判斷(影片含音訊) | Auto-detect (video with audio) | |
audio | 僅下載音訊(MP3/M4A) | Audio only (MP3/M4A) | |
mute | 影片靜音(無音訊軌道) | Muted video (no audio track) |
Bot 上傳:50MB。透過伺服器 API:2GB。Haku 以 R2 媒體端點繞過 Bot 的 50MB 限制,讓 Telegram 伺服器從 R2 拉取。
Bot upload: 50MB. Via server API: 2GB. Haku bypasses the 50MB Bot limit by using the R2 media endpoint so Telegram's servers pull directly from R2.
以下為 wrangler.toml 和 Workers Secrets 中使用的關鍵環境變數。
Key environment variables used in wrangler.toml and Workers Secrets.
| 變數名稱 | Variable | 類型 | Type | 說明 | Description |
|---|---|---|---|---|---|
TELEGRAM_BOT_TOKEN |
機密Secret | Telegram Bot Token,用於 API 認證和 Webhook 簽名驗證 | Telegram Bot Token for API auth and webhook signature verification | ||
COBALT_API_URL |
Var | Cobalt 服務端點 URL(例:透過 CF Tunnel 的家庭主機 URL) | Cobalt service endpoint URL (e.g., home host via Cloudflare Tunnel) | ||
COBALT_API_KEY |
機密Secret | Cobalt API 存取金鑰(若 Cobalt 設定了 API 驗證) | Cobalt API access key (if Cobalt has API auth configured) | ||
YOUTUBE_CAPTURE_URL |
Var | youtube-capture 任務 API 端點(Windows 小主機) | youtube-capture job API endpoint (Windows mini PC) | ||
YOUTUBE_CAPTURE_KEY |
機密Secret | youtube-capture API 認證金鑰 | youtube-capture API authentication key | ||
OPENAI_API_KEY |
機密Secret | OpenAI API 金鑰,用於 Whisper 語音轉錄功能 | OpenAI API key for Whisper audio transcription | ||
HMAC_SECRET |
機密Secret | HMAC 簽名金鑰,用於媒體 URL 防篡改和使用者配對 | HMAC signing key for media URL integrity and user pairing | ||
R2_BUCKET |
Binding | Cloudflare R2 Bucket Binding(在 wrangler.toml 設定) | Cloudflare R2 Bucket Binding (configured in wrangler.toml) | ||
KV_NAMESPACE |
Binding | Cloudflare KV Namespace Binding(使用者狀態、訂閱) | Cloudflare KV Namespace Binding (user state, subscriptions) | ||
STATS_DO |
Binding | StatsCounter Durable Object Binding | StatsCounter Durable Object Binding | ||
HISTORY_DO |
Binding | HistoryStore Durable Object Binding | HistoryStore Durable Object Binding |
Cobalt 返回非 2xx、網路逾時、或媒體 URL 無效時,extract.ts 捕獲錯誤並判斷是否為 YouTube。若是,自動降級至 youtube-capture 非同步備援。非 YouTube 平台則直接向使用者回報失敗原因。
When Cobalt returns non-2xx, times out, or returns an invalid media URL, extract.ts catches the error and checks if the platform is YouTube. If so, it automatically degrades to the youtube-capture async fallback. For non-YouTube platforms it reports the failure reason to the user directly.
Cobalt 的自架特性讓 IP 封鎖風險大幅降低(家庭 IP 而非 VPS IP)。遇到平台 429 或 403 回應時,錯誤訊息透過 i18n 系統以使用者設定語言回報,並建議稍後重試。
Self-hosting Cobalt on a home IP dramatically reduces blocking risk compared to VPS IPs. When a platform returns 429 or 403, the error is reported in the user's configured language via the i18n system, with a suggestion to retry later.
Whisper 有 25MB 音訊檔案限制。影片下載若超過 Telegram Bot API 的 50MB 限制,Haku 使用 R2 媒體端點繞過此限制(讓 Telegram 伺服器拉取而非 Bot 上傳)。youtube-capture 的非同步設計可處理更長的影片。
Whisper has a 25MB audio file limit. For video downloads exceeding Telegram's 50MB Bot API limit, Haku routes through the R2 media endpoint (Telegram servers pull directly from R2 instead of Bot uploading). The youtube-capture async design accommodates longer videos.
Cloudflare Workers 有 CPU 時間限制(免費方案 10ms,付費方案 30s)。長任務(youtube-capture 等待)透過 Durable Objects 的持久狀態和輪詢模式實作,不阻塞 Worker 執行緒。Cron 任務使用 scheduled() 處理器。
Cloudflare Workers has CPU time limits (10ms free, 30s paid). Long-running tasks (youtube-capture waiting) are implemented via Durable Object persistent state and polling patterns, not blocking the Worker thread. Cron tasks use the scheduled() handler.
auth.ts 追蹤失敗嘗試次數並在 KV 中設置臨時鎖定。配對令牌有時效性,過期後需重新配對。所有驗證錯誤均以靜默失敗模式處理,不洩漏系統內部資訊。
auth.ts tracks failed attempts and sets temporary lockouts in KV. Pairing tokens are time-limited and require re-pairing after expiry. All auth errors use silent failure mode, revealing no internal system information.
StatsCounter 和 HistoryStore 的 DO 呼叫採用 fire-and-forget 模式,失敗不影響主下載流程。DO 的強一致性保證計數不重複、不遺失,即使 Workers 實例重啟也能持久化。
StatsCounter and HistoryStore DO calls use a fire-and-forget pattern; failures do not block the main download flow. DO strong consistency guarantees counts are neither duplicated nor lost, surviving Worker instance restarts.
以下為靜態圖分析識別的高耦合邊(依引用次數排序)。commands/* 到 utils/helpers 的 151 條邊說明輔助函式是系統最核心的共用依賴。
The following high-coupling edges were identified by static graph analysis (sorted by reference count). The 151 edges from commands/* to utils/helpers confirm that utility functions are the most central shared dependency in the system.
| 來源 | Source | 目標 | Target | 引用數 | Edges | 視覺化 | Visual |
|---|---|---|---|---|---|---|---|
commands/* |
utils / helpers |
151 | |||||
commands/* |
telegram.ts |
51 | |||||
commands/* |
message helpers |
51 | |||||
platforms/* |
detect.ts |
43 | |||||
platforms/* |
capture.ts |
37 | |||||
extract.ts |
capture.ts |
14 |
高耦合集中在 commands/* → utils/helpers,說明輔助層承擔了過多職責。未來重構建議將 Telegram 訊息輔助、KV 操作、HMAC 工具分別提取為獨立模組,降低 helpers.ts 的耦合廣度。
High coupling is concentrated at commands/* → utils/helpers, indicating the helper layer carries too many responsibilities. A future refactor could extract Telegram message helpers, KV operations, and HMAC utilities into separate modules to reduce the coupling breadth of helpers.ts.
graph LR
subgraph CF["Cloudflare Edge (全球 / Global)"]
W["Workers Runtime
Hono + grammY"]
R2B["R2 Bucket
影片儲存 / Video Store"]
KVS["KV Namespace
使用者狀態 / User State"]
DO2["Durable Objects
Stats + History"]
end
subgraph HOME["家庭網路 / Home Network"]
DOCKER["Cobalt Docker
Linux 主機"]
WHOST["youtube-capture
Windows 小主機"]
CFT["Cloudflare Tunnel
Client (cloudflared)"]
end
subgraph EXT["外部 SaaS / External SaaS"]
TGAPI["Telegram API
api.telegram.org"]
OAI["OpenAI API
Whisper"]
end
TGAPI -->|Webhook POST| W
W --> R2B
W --> KVS
W --> DO2
W -->|via CF Tunnel| CFT
CFT --> DOCKER
CFT --> WHOST
W -.->|Transcription| OAI
W ==>|sendVideo / sendDocument| TGAPI
classDef cf fill:#3a5a4022,stroke:#3a5a40,stroke-width:2px
classDef home fill:#9c7b3022,stroke:#9c7b30,stroke-width:2px
classDef ext fill:#a8552e22,stroke:#a8552e,stroke-width:1.5px,stroke-dasharray:5 5
class W,R2B,KVS,DO2 cf
class DOCKER,WHOST,CFT home
class TGAPI,OAI ext
Workers 部署於 Cloudflare 全球 300+ 節點,請求從最近節點服務。Webhook 處理、R2 上傳、DO 呼叫均在同一 Worker 內完成,延遲極低。使用 wrangler deploy 部署,CI/CD 透過 GitHub Actions。
Workers are deployed across Cloudflare's 300+ global PoPs; requests are served from the nearest node. Webhook handling, R2 uploads, and DO calls all complete within the same Worker, minimizing latency. Deployed via wrangler deploy; CI/CD through GitHub Actions.
Cobalt Docker 和 youtube-capture 服務均透過 cloudflared 客戶端建立 Cloudflare Tunnel,無需開放防火牆埠或暴露家庭 IP。Workers 透過私有 Tunnel URL 存取這兩個服務。
Both Cobalt Docker and youtube-capture services connect outbound via cloudflared clients establishing Cloudflare Tunnels — no firewall ports opened, no home IP exposed. Workers access both services through their private Tunnel URLs.
R2 是 S3 相容物件儲存,但出站流量免費(對 Workers 而言)。影片串流上傳後,Telegram 伺服器透過帶有 HMAC 簽名的 /media/:key 端點拉取媒體,Workers 充當反向代理串流 R2 物件。
R2 is S3-compatible object storage with zero egress fees (for Workers). After streaming upload, Telegram servers pull media via the HMAC-signed /media/:key endpoint, with Workers acting as a reverse proxy streaming the R2 object.
零冷啟動(相對 Lambda)、全球邊緣、免費方案足夠個人使用、原生 R2/KV/DO 整合無需跨服務呼叫。與家庭主機透過 Tunnel 整合使架構完全無公網 IP。
Near-zero cold starts (compared to Lambda), global edge presence, free tier sufficient for personal use, and native R2/KV/DO integration with no cross-service calls. Tunnel integration with home hosts makes the architecture completely public-IP-free.
grammY 原生支援 Cloudflare Workers 執行環境(非 Node.js 特定),提供完整的 Telegram Bot API 型別定義、Middleware 鏈、Inline Keyboard 處理。與 Hono 組合實現 Webhook + HTTP 路由共存。
grammY natively supports the Cloudflare Workers runtime (not Node.js-specific), provides full Telegram Bot API type definitions, a middleware chain, and inline keyboard handling. Combined with Hono it enables Webhook and HTTP routing to coexist.
Hono 是為 Cloudflare Workers 最佳化的超輕量路由框架,支援 Web Standard Request/Response,比 Express 更快且零依賴。在同一個 Worker 中同時處理 Telegram Webhook 和 /media/:key 媒體端點。
Hono is an ultra-lightweight router framework optimized for Cloudflare Workers, using Web Standard Request/Response — faster than Express and zero-dependency. Handles both Telegram Webhook and the /media/:key media endpoint within the same Worker.
自架 Cobalt 避免速率限制和 API 費用,使用家庭 IP 降低平台封鎖風險。Cobalt 支援多平台(YouTube、TikTok、Instagram、Twitter/X 等),統一了下載介面,無需為每個平台維護獨立的解析邏輯。
Self-hosting Cobalt avoids rate limits and API fees, using a home IP to reduce platform blocking risk. Cobalt supports multiple platforms (YouTube, TikTok, Instagram, Twitter/X, etc.), unifying the download interface so platform-specific parsing logic doesn't need to be maintained per-platform.
DO 提供強一致性的持久狀態,適合計數器(不重複計數)和有序歷史記錄。相較 KV(最終一致性),DO 保證在並發請求下計數正確。每個使用者有獨立的 DO 實例,避免熱點競爭。
DOs provide strongly-consistent persistent state, ideal for counters (no double-counting) and ordered history. Compared to KV (eventually consistent), DOs guarantee correct counts under concurrent requests. Each user has a dedicated DO instance, avoiding hot-spot contention.
Worker 本身完全無狀態,所有持久狀態都在 KV(使用者偏好、配對)、R2(媒體檔案)和 DO(統計、歷史)中。這讓 Worker 可以在任何 Cloudflare 節點運行、橫向擴展無需協調,且部署回滾安全。
The Worker itself is completely stateless; all persistent state lives in KV (user preferences, pairing), R2 (media files), and DOs (stats, history). This allows the Worker to run on any Cloudflare node, scale horizontally without coordination, and makes deployment rollbacks safe.
YouTube 長影片下載可能需要數分鐘,超過 Workers 的 CPU 時間限制。將此工作卸載至 Windows 小主機的非同步任務 API,Worker 只負責提交任務和輪詢結果,不持有長連線。
Downloading long YouTube videos may take minutes, exceeding Workers' CPU time limits. Offloading to the Windows mini PC's async job API lets the Worker only submit a job and poll for results — no long-held connections.
透過 Workers 的 /media/:key 端點提供 R2 內容(而非 R2 公開存取),讓 Haku 可以:驗證 HMAC 簽名防盜鏈、在回應 headers 設定 Content-Type、控制快取策略、隨時撤銷媒體存取。
Serving R2 content through Workers' /media/:key endpoint (rather than R2 public access) lets Haku: verify HMAC signatures to prevent hotlinking, set Content-Type in response headers, control caching strategy, and revoke media access at any time.
Haku 的 UI 訊息透過 i18n.ts 模組提供 7 種語言支援。使用者可透過 Inline Keyboard 切換語言,偏好儲存於 KV,每次回應均以使用者偏好語言呈現。
Haku's UI messages are available in 7 languages via the i18n.ts module. Users switch language via an inline keyboard; preferences are stored in KV and all responses use the user's preferred language.
預設語言,所有訊息鍵的基準
Default language; all message keys baseline
台灣、香港繁體中文使用者
Traditional Chinese for Taiwan and Hong Kong users
中國大陸簡體中文使用者
Simplified Chinese for mainland China users
法語使用者
French language users
印地語使用者
Hindi language users
越南語使用者
Vietnamese language users
泰語使用者
Thai language users
i18n.ts 定義所有語言的訊息鍵對應表。helpers.ts 提供 t(key, lang) 輔助函式。所有面向使用者的訊息都透過此函式而非硬編碼字串。語言偏好從 KV 讀取,回落至使用者的 Telegram 語言設定,最後回落至英文。
i18n.ts defines message key mappings for all languages. helpers.ts provides a t(key, lang) helper. All user-facing messages go through this function, never hardcoded strings. Language preference is read from KV, falls back to the user's Telegram language setting, then to English.
// Example usage
const msg = t('download.success', userLang);
// → "下載完成!" (zh-TW) / "Download complete!" (en)
| 指令 | Command | 說明 | Description | Handler | Handler |
|---|---|---|---|---|---|
/start |
開始使用,觸發配對流程 | Get started, triggers pairing flow | index.ts |
||
/help |
顯示使用說明 | Show usage help | helpers.ts |
||
[URL] |
直接傳送影片 URL 觸發下載 | Send video URL directly to trigger download | download.ts |
||
/audio [URL] |
下載純音訊(MP3/M4A) | Download audio only (MP3/M4A) | download.ts |
||
/sub [URL] |
下載字幕(YouTube 自動字幕) | Download subtitles (YouTube auto captions) | transcript.ts |
||
/transcript [URL] |
使用 Whisper 轉錄音訊 | Transcribe audio using Whisper | transcript.ts |
||
/batch [URLs] |
批次下載多個 URL | Batch download multiple URLs | social.ts |
||
/subscribe [URL] |
訂閱頻道新影片(Cron 每 12 小時檢查) | Subscribe to channel for new videos (Cron checks every 12h) | social.ts |
||
/unsub [URL] |
取消訂閱 | Unsubscribe from channel | social.ts |
||
/mysubs |
查看目前訂閱列表 | View current subscription list | social.ts |
||
/history |
查看下載歷史記錄 | View download history | stats.ts + DO |
||
/stats |
查看個人使用統計 | View personal usage statistics | stats.ts + DO |
||
/lang |
切換界面語言(Inline Keyboard) | Switch UI language (Inline Keyboard) | callback.ts |
||
/quality |
設定預設下載畫質 | Set default download quality | callback.ts |
目前 helpers.ts 擁有 151 條耦合邊,職責過多。建議拆分為 telegram-helpers.ts(Telegram 訊息)、kv-helpers.ts(KV 操作)、crypto-helpers.ts(HMAC),降低各模組耦合度。
Currently helpers.ts has 151 coupling edges and carries too many responsibilities. Suggested decomposition: telegram-helpers.ts (Telegram messages), kv-helpers.ts (KV operations), crypto-helpers.ts (HMAC), reducing per-module coupling.
xiaohongshu.ts 的 HTML 抓取方法脆弱,易受頁面結構變動影響。理想方案是將小紅書整合進 Cobalt(若官方支援),或使用 Mobile API 端點(需逆向工程)。
xiaohongshu.ts's HTML scraping approach is fragile and breaks on page structure changes. The ideal solution is integrating Xiaohongshu into Cobalt (if officially supported) or using mobile API endpoints (requiring reverse engineering).
目前每次只處理單一 URL。YouTube 播放清單、TikTok 合輯需要多任務協調。可利用現有 youtube-capture 非同步架構擴展為批次任務,結合 DO 追蹤各任務狀態。
Currently processes one URL at a time. YouTube playlists and TikTok collections require multi-task coordination. The existing youtube-capture async architecture can be extended to batch jobs, with DOs tracking per-task status.
目前依賴 Cloudflare Workers 的內建日誌。可加入結構化日誌(JSON 格式)推送至 Cloudflare Logpush,並設置 Cobalt 失敗率告警(超過閾值自動通知管理員 Telegram)。
Currently relies on Cloudflare Workers built-in logging. Adding structured logs (JSON format) pushed to Cloudflare Logpush, plus Cobalt failure-rate alerts (auto-notify admin Telegram when threshold exceeded) would improve visibility.
同一 URL 被多個使用者下載時,每次都重新下載並上傳至 R2。可用 URL hash 作為 KV 快取鍵,若已存在則直接回傳已有的 R2 物件,節省 Cobalt 請求和 R2 儲存。
When the same URL is downloaded by multiple users, each request re-downloads and re-uploads to R2. Using URL hash as a KV cache key — returning an existing R2 object if present — would save Cobalt requests and R2 storage.
目前支援 7 種語言。根據使用者分佈,可考慮加入西班牙語(ES)、葡萄牙語(PT)、阿拉伯語(AR)、韓語(KO)和日語(JA)。i18n 架構已支援擴展,只需在 i18n.ts 加入新語言鍵值對。
Currently 7 languages supported. Based on user distribution, Spanish (ES), Portuguese (PT), Arabic (AR), Korean (KO), and Japanese (JA) could be added. The i18n architecture already supports extension — just add new key-value pairs to i18n.ts.