直播途中突然斷網?開播後才發現忘了開彈幕機?此功能可在未開啟彈幕機時持續監控直播間事件,並定期同步至本機,真正做到不漏接任何禮物。雲端事件同步僅適用於控制台模式
- 雲端事件可取得最近 72 小時(可設定)內的所有付費禮物事件
- 在控制台中會每 20 分鐘自動與雲端同步,用於補回主播可能因網路問題而漏收的禮物
- 開啟 Bridge Mode 後,可與 LEB SDK 進行聯動,打造屬於您自己的彈幕應用程式
設定此功能需要一定的電腦基礎,如果您是主播,請將本文件轉交給社團/公會內相應的技術人員
前置條件
- 熟悉容器或 Kubernetes 的基本操作
- 高中及以上學歷(如果您是國中生,且完全能看懂下方的部署文件,可透過 Discord 與我聯繫)
請確認符合上述條件,否則不建議繼續閱讀
伺服器最低需求
- linux/amd64
- CPU:至少 0.25 核
- 記憶體:至少 256 MB,建議 512 MB 以上。記憶體需求會隨監控的直播間數量線性成長
- 伺服器能長時間穩定連上嗶哩嗶哩彈幕伺服器,建議選用日本、新加坡或中國(網域需備案)節點的伺服器
- PostgreSQL
- Redis(選用),用於快取近期的彈幕訊息
Serverless 需求
目前已測試通過 Koyeb/Vercel + Supabase/Neon/Render 的各種排列組合
容器可用標籤
latest:最新穩定版<major>.<minor>.<patch>:指定版本edge:最新開發版sha-<hash>:指定 commit hash 的版本
更多標籤與版本請查看容器介紹頁面
安裝方式
- 透過 Docker、Docker Compose 或 Kubernetes 進行部署
- 設定公開網路存取:需支援 HTTPS 存取,可透過 Traefik、Nginx、Caddy 或 serverless 雲端服務進行設定
- 填入 API:設定完成後,在 LAPLACE Chat 的設定器 - 進階 - 自訂雲端事件 API 中填入您的 API 網址
Docker Compose 設定範例
以下為在 Docker Compose 中部署 LAPLACE Event Fetcher 的設定範例
services:
lef:
image: ghcr.io/laplace-live/event-fetcher:latest
environment:
DATABASE_URL: postgresql://lef:lef@lef-pg:5432/lef
ROOMS: 25034104,456117
TZ: Asia/Shanghai # Recommended, this ensures all cron tasks are executed in CST
depends_on:
- lef-pg
- lef-redis # See below
# If you want to run the server on a different port, you can uncomment the following lines. Default is 8080.
# ports:
# - 9696:8080
restart: always
lef-pg:
image: postgres:18-alpine # Works with version 16 and above
environment:
POSTGRES_DB: lef
POSTGRES_USER: lef
POSTGRES_PASSWORD: lef
volumes:
# For PostgreSQL 17 and below, you should mount to `/var/lib/postgresql/data`
- lef-db:/var/lib/postgresql
restart: always
healthcheck:
test: pg_isready -U lef -h 127.0.0.1
interval: 5s
# Redis is optional for serving recent chat messages
lef-redis:
image: redis:latest
volumes:
- lef-redis:/data
restart: always
volumes:
lef-db:
lef-redis:Kubernetes 設定範例
以下為在 Kubernetes 中部署 LAPLACE Event Fetcher 的設定範例
apiVersion: v1
kind: ConfigMap
metadata:
name: lef-config
data:
ROOMS: "25034104,456117"
TZ: "Asia/Shanghai"apiVersion: v1
kind: Secret
metadata:
name: lef-secret
type: Opaque
stringData:
DATABASE_URL: "postgresql://lef:lef@lef-pg:5432/lef"
POSTGRES_DB: "lef"
POSTGRES_USER: "lef"
POSTGRES_PASSWORD: "lef"apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: lef-pg-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10GiapiVersion: apps/v1
kind: Deployment
metadata:
name: lef-pg
spec:
replicas: 1
selector:
matchLabels:
app: lef-pg
template:
metadata:
labels:
app: lef-pg
spec:
containers:
- name: postgres
image: postgres:18-alpine # Works with version 16 and above
envFrom:
- secretRef:
name: lef-secret
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-storage
# For PostgreSQL 17 and below, you should mount to `/var/lib/postgresql/data`
mountPath: /var/lib/postgresql
livenessProbe:
exec:
command:
- pg_isready
- -U
- lef
- -h
- 127.0.0.1
initialDelaySeconds: 30
periodSeconds: 10
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: lef-pg-pvc
---
apiVersion: v1
kind: Service
metadata:
name: lef-pg
spec:
selector:
app: lef-pg
ports:
- port: 5432apiVersion: apps/v1
kind: Deployment
metadata:
name: lef
spec:
replicas: 1
selector:
matchLabels:
app: lef
template:
metadata:
labels:
app: lef
spec:
containers:
- name: lef
image: ghcr.io/laplace-live/event-fetcher:latest
envFrom:
- configMapRef:
name: lef-config
- secretRef:
name: lef-secret
ports:
- containerPort: 8080
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
---
apiVersion: v1
kind: Service
metadata:
name: lef
spec:
selector:
app: lef
ports:
- port: 80
targetPort: 8080Ingress、HTTPS 請依自身的實際需求進行設定
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: lef-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: lef.example.tld
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: lef
port:
number: 80部署:Koyeb + Neon
首先,您需要在 Supabase 建立一個 PostgreSQL 資料庫:
- 在 Supabase 控制台中建立新的資料庫
- 將區域改為
AWS US East (N. Virginia) - 記住資料庫密碼,並從 Connection Details - Connection string 中記下您的連線字串
接著,我們要在 Koyeb 上部署 event fetcher:
- 建立新的 app,並選擇 Docker 作為部署方式
- 使用
ghcr.io/laplace-live/event-fetcher作為映像檔。留空或填入edge可取得最新的測試版映像檔 - 將區域改為
WAS(靠近您剛建立的資料庫) - 選擇
eMicro執行個體(更大的執行個體可承載更多直播間) - 點擊
Advanced按鈕,並加入以下環境變數:ROOMS與DATABASE_URL。DATABASE_URL的值就是上一步取得的連線字串,格式類似postgresql://postgres:<DB_PASSWORD>@xxxxxxxxxxxxxxxxxxxx.us-east-2.aws.neon.tech/neondb?sslmode=require - 點擊 Deploy
已測試的 Serverless 平台
以下組合皆已測試可正常運作:
- Koyeb + Supabase
- Koyeb + Neon
- Render
- Render + Neon
WebSocket API (Bridge Mode)
Event Fetcher 在根路徑 / 提供 WebSocket 模式,用於即時事件串流,可作為 Event Bridge Server 的替代方案。設定 BRIDGE_MODE=1 或 BRIDGE_MODE=true 即可啟用此功能。啟用後,伺服器會接受來自 LAPLACE Event Bridge SDK 的 WebSocket 連線
身分驗證
若已設定 BRIDGE_TOKEN,用戶端需使用 Sec-WebSocket-Protocol 標頭進行驗證。例如:
const ws = new WebSocket("ws://localhost:8080/", ["client", "auth-token"]);或者,您也可以透過 token 查詢參數傳入權杖:
const ws = new WebSocket("ws://localhost:8080/?token=auth-token");直播間篩選
您可以透過 rooms 查詢參數,依特定直播間篩選事件,傳入以逗號分隔的直播間 ID 清單:
// Only receive events from rooms 456117 and 25034104
const ws = new WebSocket("ws://localhost:8080/?rooms=456117,25034104");
// With query-style authentication
const ws = new WebSocket(
"ws://localhost:8080/?token=auth-token&rooms=456117,25034104",
);若未提供 rooms 參數,您將收到所有已設定直播間的事件
使用者 UID 篩選
您可以透過 uids 查詢參數,依特定使用者 UID 篩選事件,傳入以逗號分隔的 UID 清單:
// Only receive events triggered by users 11153765 or 1234567
const ws = new WebSocket("ws://localhost:8080/?uids=11153765,1234567");rooms 與 uids 可以並用;兩者同時設定時,事件必須符合兩項篩選條件才會送出。啟用 UID 篩選期間,沒有 uid(或 uid 為 0)的事件會被排除
接著,伺服器每處理一則事件,您就會即時收到對應的 LaplaceEvent
測試
專案內附了測試用戶端 websocket-test.html,可在瀏覽器中開啟,用來測試 WebSocket 連線並查看即時事件。測試頁面也內建 Mock Event Sender 面板,可透過 /mock 端點送出測試事件
您也可以使用 wscat 測試 WebSocket 連線:
# Via Sec-WebSocket-Protocol header
wscat -c ws://localhost:8080 -s client -s <auth-token>
# Via token query parameter
wscat -c 'ws://localhost:8080/?token=<auth-token>'
# With room filtering
wscat -c 'ws://localhost:8080/?rooms=456117,25034104'
# With uid filtering
wscat -c 'ws://localhost:8080/?uids=11153765,1234567'
# With both query-style authentication and room/uid filtering
wscat -c 'ws://localhost:8080/?token=<auth-token>&rooms=456117,25034104&uids=11153765'透過 curl 送出模擬事件:
curl -X POST http://localhost:8080/mock \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-admin-key-at-least-12-chars" \
-d '{"type": "message", "message": "Test message", "username": "TestUser"}'心跳機制
WebSocket 連線內建心跳機制,用於偵測失效連線並從中恢復:
- 伺服器 → 用戶端:伺服器每 10 秒送出一則
ping訊息 - 用戶端 → 伺服器:用戶端必須回覆
pong訊息 - 逾時:若 60 秒內未收到
pong,連線將被關閉 - 自動重連:相容的用戶端(LAPLACE Event Bridge SDK 1.0.0 以上)會自動重新連線
這能確保長時間連線在遇到網路問題、代理逾時或其他中斷時,仍保持穩定
注意:心跳功能僅在 LAPLACE Event Fetcher 中提供,LAPLACE Event Bridge (LEB) 伺服器並不支援,因為 LEB 的設計是在本機執行,不需考量連線穩定性
OpenTelemetry
本服務內建選用的 OpenTelemetry 支援,可用於分散式追蹤與可觀測性。設定完成後,會自動為 PostgreSQL 操作加上追蹤
Axiom 日誌(選用)
若您使用 Axiom,且除了追蹤之外還想要結構化日誌,當服務在 OTLP 標頭中偵測到 Axiom 憑證時,會自動設定 Pino logger 將日誌送往 Axiom:
- 當
OTEL_EXPORTER_OTLP_HEADERS中同時存在X-Axiom-Dataset與Authorization時,日誌會自動送出 - 日誌等級預設為
debug
已納入追蹤的元件
啟用 OpenTelemetry 後,以下元件會自動納入追蹤:
- PostgreSQL:所有資料庫查詢與操作
- HTTP 請求:所有傳入的 HTTP 請求與回應
API
您可以在自己執行個體的 /openapi 路徑查閱 API 文件
GET /events/<room_id>:依直播間 ID 從資料庫取得事件- 查詢參數:
?full=1:取得所有事件?uids=<uid1>,<uid2>:依一個或多個使用者 UID 篩選事件(以逗號分隔)。沒有相符uid的事件會被排除
- 查詢參數:
POST /upload:上傳事件並存入資料庫- 標頭:
Authorization:Bearer <ADMIN_TOKEN>(必填,權杖長度至少 12 個字元)
- 內容:
- 原始 JSON
LaplaceEvent[]或 LAPLACE Chat Archive (.lca)
- 原始 JSON
- 標頭:
POST /mock:模擬一則LaplaceEvent,並廣播給所有已連線的 WebSocket 用戶端(測試時很實用)。範例請見 @laplace.live/event-types- 標頭:
Authorization:Bearer <ADMIN_TOKEN>(必填,權杖長度至少 12 個字元)
- 內容:
- 至少包含
type欄位的 JSON 物件(例如{"type": "message", "message": "Test message"}) - 事件中的所有欄位都會被廣播,並額外附上
mock: true旗標與目前的時間戳記
- 至少包含
- 標頭:
GET /ping:檢查伺服器是否正常運作。此端點會連線至資料庫,並以 JSON 格式回傳pong與 200 狀態碼,失敗時則回傳 500 狀態碼GET /info:取得目前執行個體的資訊,包含已連線的直播間與主播資料- 標頭:
Authorization:<AUTH_TOKEN>或Bearer <AUTH_TOKEN>(設定AUTH_TOKEN時為必填)
- 標頭:
環境變數
PORT(選用):伺服器監聽的連接埠。預設:8080ROOMS:要抓取的直播間,多個直播間可用逗號分隔。預設:456117。建議每個節點加入的直播間少於 10 個,否則嗶哩嗶哩會阻擋您取得事件DATABASE_URL:要連線的資料庫,例如postgresql://username:password@pg:5432/lefREDIS_URL(選用):要連線的 Redis,例如redis://username:password@redis:6379EVENTS_KEEP(選用):超過此保留時長的事件將被捨棄。預設:72(小時)REDIS_EVENT_LIMIT(選用):每個直播間在 Redis 中最多保存的事件數。預設:100RESTART_WAIT(選用):重新建立連線前的等待時間。預設:2000(毫秒)RESTART_INTERVAL(選用):以 cron 格式表示的連線重啟間隔。預設:0 6,18 * * *(每天早上 6:00 與下午 6:00)LOGIN_SYNC_TOKEN(選用):來自 LAPLACE Login Sync 擴充功能的權杖。預設:undefined。多組金鑰可用逗號分隔AUTH_TOKEN(選用):一組長隨機字串,作為存取 REST API 的憑證。適合只想將 API 開放給已授權使用者的情況。預設:undefined。多組權杖可用逗號分隔(原名AUTH_KEY,仍可使用,但會顯示淘汰警告)ADMIN_TOKEN(選用):一組長隨機字串,作為上傳事件至雲端與送出模擬事件的憑證,長度至少 12 個字元。預設:undefined。若要上傳事件或使用 mock 端點,就必須設定此變數。可使用openssl rand -hex 32產生隨機字串(原名ADMIN_KEY,仍可使用,但會顯示淘汰警告)BRIDGE_MODE(選用):啟用 WebSocket bridge 模式,以進行即時事件串流。設為false或0可停用。預設:undefined(停用)(原名WEBSOCKET_BRIDGE,仍可使用,但會顯示淘汰警告)BRIDGE_TOKEN(選用):WebSocket 驗證用的密碼。設定後,用戶端必須提供此密碼才能連線至 WebSocket 端點。預設:undefined(原名WEBSOCKET_BRIDGE_AUTH,仍可使用,但會顯示淘汰警告)OTEL_EXPORTER_OTLP_ENDPOINT(選用):OpenTelemetry 端點網址,例如https://api.example.com。未設定時,OpenTelemetry 將停用OTEL_EXPORTER_OTLP_HEADERS(選用):隨 OpenTelemetry 請求送出的標頭,格式為以逗號分隔的key=value,例如Authorization=Bearer <token>,X-Dataset=my-datasetOTEL_TRACE_SAMPLE_RATE(選用):OpenTelemetry 追蹤的取樣率。預設:0.1(10%)
開發
bun run dev # session 1
bunx drizzle-kit studio # session 2
# init db and create migrations
bunx drizzle-kit migrate
# Update schemas
bunx drizzle-kit generateFAQ
為什麼沒有 Docker Hub?
Docker Hub 很爛
為什麼不開源?
- 我不認為其他使用者會為這個專案做出貢獻
- 我不需要靠開源專案來幫我找工作
- 我不希望其他使用者濫用這個專案
最後更新於 2026年9月19日