00 · MECHANISM
核心机制(与 catclaw 1:1)
监控的本质是「调度器 + 连接器 + 录制器」三元组。代码源自 live-scan-scheduler.ts + live-monitor.ts (678 行) 。
1️⃣ Scheduler 调度器 每 30s 触发
setInterval(() => runOnce(), 30000)
查询所有 auto_monitor=1 的 room_meta
过滤已连接的(connected.has(username))
检查 90s backoff :距上次尝试 ≥ 90s 才允许重连(防窗口风暴)
更新 status='连接中' + last_connect_attempt_at
调用 liveMonitor.connectRoom(username)
成功 → status='监听中' / 离线 → '待开播' / 错误 → '连接失败'
降级策略: 不走 HTTP fetchRoomInfo(不可靠),直接尝试 WS 连接 = LIVE。
2️⃣ RoomConnection 连接器 tiktok-live-connector
每个直播间一个 worker thread,避免阻塞主进程。
建立 WebSocket 连接到 TikTok WebCast 协议
订阅 24 种事件类型 (见下表)
事件到达 → extractUserFields() → 标准化 → 派发
断开 → 5 次指数退避重连 (3s, 6s, 12s, 24s, 48s)
5 次失败 → close session
⚠ 签名问题:TikTok WS 需要 X-Bogus 等签名。catclaw 用 Electron hidden BrowserWindow 抓签名注入到 connector。
3️⃣ Session 复用机制 10 分钟窗口
连接成功后查询 live_sessions 表,10 分钟内同 room_id + username 的已结束 session 直接复用。
SELECT id FROM live_sessions
WHERE room_id = ? AND streamer_username = ?
AND disconnected_at IS NOT NULL
AND disconnected_at > (now - 600000)
ORDER BY disconnected_at DESC LIMIT 1
意义: 主播短暂掉线(< 10 分钟)重连,数据继续累计到同一场,不会拆成两场虚假记录。
4️⃣ 事件流持久化 live_events 表
每个事件 → incrementSessionStats() 实时更新聚合 + insert 到 live_events。
UPDATE live_sessions SET
total_events = total_events + 1,
total_chat = ...,
total_gift_value = total_gift_value + (?*?),
peak_viewers = MAX(peak_viewers, ?)
WHERE id = ?
session 结束时再次 updateLiveSessionStats() 全量重算(含 avg_viewers / duration / diamond_per_hour)。
24 种 WebCast 事件类型映射 EVENT_MAP · live-monitor.ts:79-121
WebcastChatMessage chat
WebcastGiftMessage gift
WebcastMemberMessage member
WebcastLikeMessage like
WebcastSocialMessage follow
WebcastSubNotifyMsg sub
WebcastQuestionNew qNew
WebcastRoomMessage roomInfo
RoomUserSeqMsg roomUsr
GoalUpdateMsg goal
CaptionMsg caption
ImDeleteMsg imDel
EnvelopeMsg envelope
RankUpdateMsg rank
RankTextMsg rankT
LiveIntroMsg intro
PollMsg poll
DetectMsg detect
LinkMicBattle battle
LinkMicArmies armies
ControlMsg(end) live_end
(internal) connected conn
(internal) disconnected disc
SubscriptionMsg sub2
01 · GRID
主监控网格 · 5 种状态色
所有 auto_monitor=1 的房间都会出现在网格里。每个 tile 显示当前状态(监听中/连接中/待开播/连接失败/已暂停)+ 实时观众/礼物数字。点击 tile 进入单房详情。
Pawcast · Live Monitor · 主页 v0.1.0
LIVE · 5
监控房间 · 9
LIVE 5
待开播 2
连接中 1
失败 1
⏱ 下次巡检 +14s · ✓ 上次扫描 16s 前 · 🔄 连接尝试 4 / 跳过 2(90s backoff)
调度器健康
巡检间隔 30s
连接 backoff 90s
本次扫描时长 1.84s
上次成功率 5/6 = 83%
总连接尝试 142
总成功 128
运行时长 14h 22m
实时事件流 最近 50 条
21:30:14 battle Mochi 进入 PK
21:29:58 gift Yoochan ← Galaxy ¥150
21:29:52 chat Link8 ← @taro_pop
21:29:45 follow Mira +3 关注
21:29:12 live_end Bubbloom 下播
21:28:40 member Link8 观众破 8K
21:28:22 like Yoochan +280 赞
21:28:02 battle Mochi PK 胜场
21:27:24 ⚠ alert Link8 速率破 540/min
① 5 种 tile 状态 监听中(红心跳)/ 连接中(黄色 spinner)/ 待开播(紫虚线)/ 连接失败(红边框)/ 已暂停。颜色对应 catclaw monitor_status 字段。
② HOT 标识 礼物速率突破阈值(默认 500/min 持续 3 分钟)→ 卡片背景变橙红 + HOT 标识。AlertEngine 自动判定。
③ session 编号 + 时长 每个 LIVE tile 底部显示 session #851 · 2h 14m,对应 live_sessions.id + duration_sec。
④ 调度器健康 右侧栏实时显示巡检状态。让运营知道系统在工作。"上次成功率 5/6" 一目了然知道哪个房间有连接问题。
⑤ 实时事件流 所有 24 种事件类型按 emoji + 颜色 pill 区分。Bloomberg 终端式滚动。点击单条可跳到对应房间详情。
实现说明 每 LIVE 房间一个 worker thread + WebSocket,事件 → IPC → zustand store → React re-render。30 秒巡检在主进程跑(轻量 SQL 查询不影响 worker)。
状态切换实例 「待开播 → 连接中」:Scheduler 检测到 90s backoff 已过,调用 connectRoom。「连接中 → 监听中」:WebSocket onopen + 收到第一个 RoomMessage。
02 · DETAIL
单房间详情 · session 列表 + 事件 + 礼物排行
点击 tile 进入。左侧是房间元信息 + 当前 session 实时数据。右侧是历史 sessions(每场一行)+ Top Gifters + 24 事件类型筛选。
Pawcast · Live Monitor / @link8_kr v0.1.0
LIVE · 5
L
Link8
@link8_kr · session #851 (active)
监听中
当前 session 聚合统计 实时
diamond_per_hour(核心 KPI)
12,673
历史 sessions · 最近 10 场
# 开播 时长 峰值 礼物币 钻/小时
#851 21:14 2h 14m 8,432 28,450 12,673
#847 04-29 21:00 2h 28m 7,840 22,180 8,932
#842 04-28 20:48 3h 02m 9,120 35,420 11,652
#838 04-27 21:12 1h 56m 5,420 14,820 7,659
事件流
Top Gifters
礼物排行
送礼者档案
全部 24 类
gift 340
chat 1247
like 47
member 84
follow 12
battle 3
21:30:14
battle
LinkMicBattleMessage start · vs @teamx_lia
21:30:08
gift
@taro_pop ← Galaxy ×1 (¥150) · 粉丝等级 12
21:29:58
chat
@silent_fan_42: 太精彩了!
21:29:50
follow
@kawaii_jin 关注了主播
21:29:45
member
@uchan_ 进入直播间
21:29:42
gift
@kawaii_jin ← Cake ×8 (¥2,480) · 粉丝等级 18
21:29:36
like
+82 赞 · 累计 8,432
21:29:30
sub
@vip_user 订阅了 Tier 1
21:29:24
rank
@taro_pop 升上 Top 1(贡献 12,450)
① 聚合统计字段 来自 live_sessions 表实时累计 + 重算。diamond_per_hour = total_gift_value × 3600 / duration_sec,是核心 KPI。
② 历史 sessions 表 每场一行,按 connected_at desc 排。点击 row 进入历史回放(Phase 7 后期实装)。
③ 24 事件筛选 顶部 chip 按事件类型过滤。可多选叠加。
④ 事件详情 含完整 user 字段(粉丝等级 / 关注状态 / 角色等),来自 extractUserFields()。
性能 事件流虚拟滚动,10 万条记录依然 60fps。SQL 用 (session_id) 索引秒级查询。
03 · ADD + CONFIG
添加房间 + 调度器配置
关键弹窗:① 添加房间到 room_meta 表 ② 调度器全局配置(巡检间隔 / backoff / 并发上限)。
添加监控房间 ×
TikTok 用户名
H
Hana
@hana.live · 3.1k 粉丝 · 韩国
正在直播
分组(room_meta.group_name)
核心团员
候补
观察中
✓ 添加 → 立即写入 room_meta 表
✓ 下次 30s 巡检时尝试 connectRoom()
✓ 90s backoff 已重置,可立即尝试一次
✓ 不需对方授权(所有公开直播间均可监控)
添加流程 ① 写入 room_meta 表 ② 调度器下次 tick 自动尝试 ③ 用户也可手动点"立即尝试"绕过 90s backoff。
auto_monitor 开关 临时禁用某房间不删除(保留 group / notes 等元数据)。
验证 添加前调用 fetch('https://www.tiktok.com/@username') 确认 username 真实存在,避免脏数据。
调度器全局配置 ×
⚠ 这些参数都是 catclaw 实战调出来的最优值。修改前建议先在测试环境验证。
5 个调度器参数 都来自 catclaw live-scan-scheduler.ts + live-monitor.ts 的真实常量。改这些 = 改运行时行为。
默认值 30s / 90s / 16 / 600s / 5 次都是生产验证过最优值,普通用户不需修改。
立即生效 保存后通过 IPC 推到 LiveScheduler / LiveMonitorManager 实例,下次 tick 应用新参数。无需重启。
04 · PK BATTLE
PK 战役详情(事件来自 LinkMicBattle / LinkMicArmies)
PK 战役在事件流中通过 WebcastLinkMicBattle + WebcastLinkMicArmies 触发。注:catclaw 的 EVENT_MAP 已映射,但主动写入 pk_battles 表的逻辑未实装 ,本 phase 在 Pawcast 补完。
PK 战役 · Mochi vs @teamx_lia ×
M
Mochi (我方)
@mochi.cat
8,420
落后 2,820
T
@teamx_lia
对方
11,240
领先
pk_battles 表数据
battle_id: 7384921846392
my_session_id: 851
my_streamer: @mochi.cat
other_room: @teamx_lia (room_id: 7384921846124)
start_at: 2026-05-02 21:30:14
end_at: NULL (进行中)
my_score: 8,420
other_score: 11,240
winner: NULL (未判定)
punish_type: NULL
我方 Top 3 贡献
1 @taro_pop 3,200
2 @kawaii_jin 2,480
3 @silent_fan_42 1,820
对方 Top 3
1 @lia_main_fan 5,400
2 @team_diehard 3,120
3 @x_supporter 1,680
⚠ catclaw 缺口: EVENT_MAP 映射了 LinkMicBattle / LinkMicArmies 事件,但未主动写入 pk_battles 表 。本 phase Task 8 补完此逻辑:监听事件 → 解析对手 uid + 头像 → upsert pk_battles → 实时更新 my_score/other_score。
事件源 WebcastLinkMicBattle 携带 battle_id / 对手 user_id / 起始时间。WebcastLinkMicArmies 携带每方观众阵营 + 实时积分。
胜负判定 战役结束时携带 winner_user_id(与 my_streamer.user_id 比对决定胜负)。catclaw 事件已收但未写入 pk_battles。
本 phase 补缺口 新建 PKCollector 类,订阅这两个事件 → 解析 → 写 pk_battles 表 → IPC 推 PKDetailModal。
05 · HISTORY
历史数据回看 · 切换实时 / 历史
监控主页顶部「实时 / 历史」切换 chip。切到历史后,房间网格变成日期列表 + 每场 session 卡片,可按主播 / 日期 / 时长 / 礼物币 / PK 状态筛选。点单场进入回放页(事件 timeline + 重算 KPI)。
Pawcast · Live Monitor / 历史 sessions v0.1.0
LIVE · 5
实时
历史
属性筛选
时长
不限 ≥ 30 分钟 ≥ 1 小时 ≥ 2 小时
礼物币
不限 ≥ 1万 ≥ 5万 ≥ 10万
导出 .xlsx
142 场 sessions
排序:钻/小时 ↓
礼物币 ↓
开播时间 ↓
时长 ↓
峰值观众 ↓
表格
卡片
#
主播
开播时间
时长
峰值观众
礼物币
钻/小时
PK
#851
L Link8 🔥
05-02 21:14
2h 14m
8,432
28,450
12,673
—
回放 →
#849
M Mochi
05-02 20:32
1h 02m
2,840
8,120
7,860
3 胜 1 负
回放 →
#847
Y Yoochan
05-01 21:00
2h 28m
7,840
22,180
8,932
—
回放 →
#842
L Link8
04-30 20:48
3h 02m
9,120
35,420
11,652
1 负
回放 →
#838
U Uni
04-30 19:12
1h 56m
5,420
14,820
7,659
2 胜
回放 →
#834
M Mochi
04-29 21:08
1h 38m
2,180
6,440
3,932
—
回放 →
① 实时 / 历史切换 顶部 chip。实时 = 当前 LIVE 房间网格;历史 = 所有 live_sessions 表的记录列表。
② 多维度筛选 日期范围 + 主播多选 + 时长 / 礼物币 / 含 PK / 含告警。所有过滤都走 SQLite 索引快查。
③ 5 卡总览统计 选定区间内:总场次 / 总时长 / 总礼物币 / 峰值观众 / PK 战役数。一目了然。
④ 30 天礼物币趋势 按日聚合柱图,看哪天哪个时段最爆。
⑤ 排序 + 表格视图 默认按钻/小时降序(核心 KPI)。可切卡片视图(每场显示缩略 hero)。
⑥ 每场点回放 进入历史回放页(下一屏):事件 timeline + 重算 KPI + 礼物排行。
实现说明 list 用 react-window 虚拟滚动。SQL 用 connected_at 索引按日期范围分页。趋势图用 SELECT date(connected_at), SUM(total_gift_value) GROUP BY date(...) 聚合。
Pawcast · Live Monitor / 回放 #851 · Link8 v0.1.0
LIVE · 5
← 返回历史列表
L
Link8 · session #851
2026-05-02 21:14 → 23:28 · 时长 2h 14m
已结束
导出本场 .xlsx
礼物排行
🌌 Galaxy ×24 12,000
🎂 Cake ×84 8,440
🌹 Rose ×156 3,120
💖 Heart Me ×980 2,940
🍦 Ice Cream ×186 1,950
Top 5 送礼者
1 T @taro_pop 12,450
2 K @kawaii_jin 5,840
3 S @silent_fan_42 3,820
4 U @uchan_ 2,480
5 M @mochi_88 1,860
21:14:00 开播
22:18:24(当前位置)
23:28:00 下播
⏮
▶ 播放 (1x)
⏭
1x 倍速 2x 5x 10x 30x
事件 timeline 共 18,420 条 · 当前 22:18 附近
22:18:24
gift
@taro_pop ← Galaxy ×3 (¥450) · 粉丝等级 12
22:18:18
chat
@silent_fan_42: 太精彩了!
22:18:12
follow
@kawaii_jin 关注
22:17:48
⚠ alert
速率突破 540/min · 持续 3 分钟
22:17:32
gift
@kawaii_jin ← Cake ×8 (¥2,480)
22:16:40
member
观众破 8K(峰值时刻)
22:15:18
chat
@hopecore_fan: cool!
22:15:02
rank
@taro_pop 升上 Top 1
22:14:36
like
+820 赞 · 累计 8,432
① 顶部 session 头 主播 + 时间范围 + 时长 + 已结束标识 + 导出本场 .xlsx 按钮。
② 左侧 KPI 卡 5 个核心字段:peak/avg viewers / total_gifts / total_chat / 钻每小时(突出色块强调)。
③ 礼物排行 + Top 5 送礼者 SQL GROUP BY 一次查回。Top 5 卡片让运营快速识别"金主"。
④ 时间轴 scrubber 顶部紫橙渐变进度条 + 高峰 marker(橙=大礼物 / 红=告警 / 绿=观众里程碑)。可拖动定位到任意时刻。
⑤ 播放控制 从开始播放或当前位置播放,1x/2x/5x/10x/30x 倍速。让运营快速看完一场 2 小时的录制。
⑥ 事件 timeline 显示当前时间附近的事件流。关键事件(gift / alert / 里程碑)有左侧色条强调。
实现说明 事件回放从 live_events 表按 ts 排序读出。倍速通过 setInterval 跳读 N 倍数据。"播放"模式下,UI 数字、礼物排行、Top Gifters 都按当前时间点的累计值实时重算(所以可以"回看"任一时刻的 leaderboard)。