From be17f91990628120ef6a7271df6c047a392c4a78 Mon Sep 17 00:00:00 2001
From: Muihd <1083092844@qq.com>
Date: Thu, 1 Jan 2026 12:35:20 +0800
Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20Watchdog=20=E7=A1=AE?=
=?UTF-8?q?=E4=BF=9D=E8=BF=9B=E7=A8=8B=E9=80=80=E5=87=BA=E6=97=B6=E5=85=B3?=
=?UTF-8?q?=E9=97=AD=E7=B3=BB=E7=BB=9F=E4=BB=A3=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
BarrageGrab/Program.cs | 98 +++++++++++++++++++++++++++++++++++
BarrageGrab/Utility/WinApi.cs | 14 ++++-
2 files changed, 110 insertions(+), 2 deletions(-)
diff --git a/BarrageGrab/Program.cs b/BarrageGrab/Program.cs
index 38f8646..a9196cc 100644
--- a/BarrageGrab/Program.cs
+++ b/BarrageGrab/Program.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
+using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
@@ -20,8 +21,17 @@ namespace BarrageGrab
static WinApi.ControlCtrlDelegate controlCtr = ControlCtrlHandle;
static Mutex mutex = new Mutex(false, "DyBarrageGrab");
+ private const string WatchdogArg = "--watchdog";
+ private const string WatchdogPidArg = "--pid";
+
static void Main(string[] args)
{
+ if (IsWatchdogMode(args))
+ {
+ RunWatchdog(args);
+ return;
+ }
+
if (!mutex.WaitOne(TimeSpan.Zero, true))
{
Console.WriteLine("另一个实例已在运行。");
@@ -31,6 +41,8 @@ namespace BarrageGrab
SetTitle("抖音弹幕监听推送");
+ StartWatchdog();
+
try
{
Init();
@@ -56,6 +68,92 @@ namespace BarrageGrab
WinApi.SetConsoleCtrlHandler(controlCtr, false);//反注册捕获控制台关闭
}
+ private static void StartWatchdog()
+ {
+ try
+ {
+ var exePath = Application.ExecutablePath;
+ if (string.IsNullOrWhiteSpace(exePath) || !File.Exists(exePath)) return;
+
+ var pid = Process.GetCurrentProcess().Id;
+ var args = string.Format("{0} {1} {2}", WatchdogArg, WatchdogPidArg, pid);
+ var psi = new ProcessStartInfo(exePath, args)
+ {
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ WindowStyle = ProcessWindowStyle.Hidden
+ };
+ Process.Start(psi);
+ }
+ catch
+ {
+ // best-effort only
+ }
+ }
+
+ private static bool IsWatchdogMode(string[] args)
+ {
+ return args != null && args.Any(a => string.Equals(a, WatchdogArg, StringComparison.OrdinalIgnoreCase));
+ }
+
+ private static int? TryGetWatchdogPid(string[] args)
+ {
+ if (args == null) return null;
+ for (int i = 0; i < args.Length; i++)
+ {
+ if (!string.Equals(args[i], WatchdogPidArg, StringComparison.OrdinalIgnoreCase)) continue;
+ if (i + 1 >= args.Length) return null;
+ int pid;
+ if (int.TryParse(args[i + 1], out pid)) return pid;
+ return null;
+ }
+ return null;
+ }
+
+ private static void RunWatchdog(string[] args)
+ {
+ try
+ {
+ var pid = TryGetWatchdogPid(args);
+ if (pid == null || pid <= 0) return;
+
+ Process target;
+ try
+ {
+ target = Process.GetProcessById(pid.Value);
+ }
+ catch
+ {
+ SafeCloseSystemProxy();
+ return;
+ }
+
+ for (; ; )
+ {
+ if (target.HasExited) break;
+ Thread.Sleep(1000);
+ }
+
+ SafeCloseSystemProxy();
+ }
+ catch
+ {
+ try { SafeCloseSystemProxy(); } catch { }
+ }
+ }
+
+ private static void SafeCloseSystemProxy()
+ {
+ try
+ {
+ if (!AppSetting.Current.UsedProxy) return;
+ WinApi.CloseSystemProxy();
+ }
+ catch
+ {
+ }
+ }
+
private static void Init()
{
AppRuntime.Init();
diff --git a/BarrageGrab/Utility/WinApi.cs b/BarrageGrab/Utility/WinApi.cs
index 0cb42f0..ccc4b1d 100644
--- a/BarrageGrab/Utility/WinApi.cs
+++ b/BarrageGrab/Utility/WinApi.cs
@@ -1,4 +1,6 @@
-using System;
+using BarrageGrab.Proxy.ProxyEventArgs;
+using Microsoft.Win32;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
@@ -64,7 +66,15 @@ namespace BarrageGrab
SetConsoleMode(hStdin, mode);
}
-
+ ///
+ /// 关闭系统代理
+ ///
+ public static void CloseSystemProxy()
+ {
+ RegistryKey registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
+ registry.SetValue("ProxyEnable", 0);
+ registry.SetValue("ProxyServer", $"");
+ }
public enum CmdShow : int
{
From ce23bde71e51344b4533d5564a85e49ae939cd32 Mon Sep 17 00:00:00 2001
From: Muihd <1083092844@qq.com>
Date: Thu, 9 Apr 2026 22:47:04 +0800
Subject: [PATCH 2/2] =?UTF-8?q?=E7=9B=B4=E6=92=AD=E4=BC=B4=E4=BE=A3?=
=?UTF-8?q?=E5=BC=80=E6=92=AD/=E4=B8=8B=E6=92=AD=E4=BA=8B=E4=BB=B6?=
=?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=8E=E9=85=8D=E7=BD=AE=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
新增对直播伴侣开播/下播事件的检测与弹幕推送,增加相关数据结构和事件机制。移除脚本缓存配置,简化直播页自动暂停逻辑。同步优化消息类型、颜色映射及项目结构,版本升级至2.8.0。
---
BarrageGrab/AppConfig.json | 4 +-
BarrageGrab/AppSetting.cs | 24 +-
BarrageGrab/Modles/AnchorFinishInfo.cs | 41 +++
.../Modles/JsonEntity/BarrageMessages.cs | 28 +-
BarrageGrab/Properties/AssemblyInfo.cs | 4 +-
BarrageGrab/Proxy/ISystemProxy.cs | 5 +
.../ProxyEventArgs/LiveCompanEventArgs.cs | 31 ++
BarrageGrab/Proxy/SystemProxy.cs | 18 +-
BarrageGrab/Proxy/TitaniumProxy.cs | 284 +++++++++---------
BarrageGrab/Scripts/inject/livePage.js | 14 -
BarrageGrab/Server/WsBarrageServer.cs | 64 +++-
BarrageGrab/WssBarrageService.csproj | 6 +-
12 files changed, 337 insertions(+), 186 deletions(-)
create mode 100644 BarrageGrab/Modles/AnchorFinishInfo.cs
create mode 100644 BarrageGrab/Proxy/ProxyEventArgs/LiveCompanEventArgs.cs
diff --git a/BarrageGrab/AppConfig.json b/BarrageGrab/AppConfig.json
index 477c69f..7497daa 100644
--- a/BarrageGrab/AppConfig.json
+++ b/BarrageGrab/AppConfig.json
@@ -49,9 +49,7 @@
// 强制启用轮询模式获取弹幕 (对于容易断开连接或者更加追求稳定的直播间,可以启用这个开关,虽然响应速度不如WebSocket,但是绝对稳定!)
"enabled": false,
// 弹幕轮询间隔,当 forcePolling 为 true 时生效 (毫秒,1000毫秒=1秒,不建议小于1000毫秒,太小可能会被封IP,值越小,弹幕流越丝滑,对于观众多的直播间可以改小)
- "interval": 3000,
- // 禁用直播页浏览器脚本缓存 (如果需要确保脚本每次能够正常匹配替换,则启用它,可能会损失一定的页面加载速度)
- "disableScriptCache": false
+ "interval": 3000
}
},
"liveCompanion": {
diff --git a/BarrageGrab/AppSetting.cs b/BarrageGrab/AppSetting.cs
index fb2437a..f7bbc1e 100644
--- a/BarrageGrab/AppSetting.cs
+++ b/BarrageGrab/AppSetting.cs
@@ -39,8 +39,7 @@ namespace BarrageGrab
ShowWindow = bool.Parse(AppSettings["showWindow"].Trim());
AutoPause = bool.Parse(AppSettings["autoPause"].Trim());
ForcePolling = bool.Parse(AppSettings["forcePolling"].Trim());
- PollingInterval = int.Parse(AppSettings["pollingInterval"].Trim());
- DisableLivePageScriptCache = bool.Parse(AppSettings["disableLivePageScriptCache"].Trim());
+ PollingInterval = int.Parse(AppSettings["pollingInterval"].Trim());
WebRoomIds = AppSettings["webRoomIds"].Trim().Split(',').Where(w => !string.IsNullOrWhiteSpace(w)).ToArray();
LiveCompanPath = AppSettings["liveCompanPath"].Trim();
LiveCompanHookSwitch = bool.Parse(AppSettings["liveCompanHookSwitch"].Trim());
@@ -115,8 +114,7 @@ namespace BarrageGrab
BarrageLog = barrage["barrageFileLog"]?.Value() ?? false;
var polling = app["barrage"]["polling"];
ForcePolling = polling["enabled"]?.Value() ?? false;
- PollingInterval = polling["interval"]?.Value() ?? 3000;
- DisableLivePageScriptCache = polling["disableScriptCache"]?.Value() ?? false;
+ PollingInterval = polling["interval"]?.Value() ?? 3000;
// 设置默认过滤器
PrintFilter = Enum.GetValues(typeof(PackMsgType)).Cast().Where(w => w > 0).ToArray();
@@ -353,14 +351,7 @@ namespace BarrageGrab
PollingInterval = interval;
Logger.PrintColor($"轮询间隔设置为: {interval}ms");
}
- break;
-
- case "disable-cache":
- case "disablecache":
- if (switchDef) break;
- DisableLivePageScriptCache = ParseBool(paramValue);
- Logger.PrintColor($"禁用脚本缓存设置为: {DisableLivePageScriptCache}");
- break;
+ break;
// 直播伴侣相关
case "auto-pause":
@@ -529,7 +520,9 @@ namespace BarrageGrab
{ PackMsgType.直播间统计, Tuple.Create(ConsoleColor.Magenta, Color.Magenta) },
{ PackMsgType.粉丝团消息, Tuple.Create(ConsoleColor.Blue, Color.Blue) },
{ PackMsgType.直播间分享, Tuple.Create(ConsoleColor.DarkBlue, Color.DarkBlue) },
- { PackMsgType.下播, Tuple.Create(ConsoleColor.DarkCyan, Color.DarkCyan) }
+ { PackMsgType.下播, Tuple.Create(ConsoleColor.DarkCyan, Color.DarkCyan) },
+ { PackMsgType.直播伴侣开播, Tuple.Create(ConsoleColor.Yellow, Color.Yellow) },
+ { PackMsgType.直播伴侣下播, Tuple.Create(ConsoleColor.Yellow, Color.Yellow) },
};
///
@@ -627,11 +620,6 @@ namespace BarrageGrab
///
public int PollingInterval { get; private set; } = 1000;
- ///
- /// 禁用直播页面脚本缓存
- ///
- public bool DisableLivePageScriptCache { get; private set; } = true;
-
///
/// 配置的串口
///
diff --git a/BarrageGrab/Modles/AnchorFinishInfo.cs b/BarrageGrab/Modles/AnchorFinishInfo.cs
new file mode 100644
index 0000000..5ed37ca
--- /dev/null
+++ b/BarrageGrab/Modles/AnchorFinishInfo.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BarrageGrab.Modles
+{
+ public class AnchorFinishInfo
+ {
+ ///
+ /// 用户ID
+ ///
+ public long UserId { get; set; }
+
+ ///
+ /// 抖音号
+ ///
+ public string DisplayId { get; set; }
+
+ ///
+ /// SecUid
+ ///
+ public string SecUid { get; set; }
+
+ ///
+ /// 昵称
+ ///
+ public string Nickname { get; set; }
+
+ ///
+ /// 头像地址
+ ///
+ public string HeadUrl { get; set; }
+
+ ///
+ /// 直播间号
+ ///
+ public string RoomId { get; set; }
+ }
+}
diff --git a/BarrageGrab/Modles/JsonEntity/BarrageMessages.cs b/BarrageGrab/Modles/JsonEntity/BarrageMessages.cs
index c449dc7..7c8b844 100644
--- a/BarrageGrab/Modles/JsonEntity/BarrageMessages.cs
+++ b/BarrageGrab/Modles/JsonEntity/BarrageMessages.cs
@@ -30,7 +30,12 @@ namespace BarrageGrab.Modles.JsonEntity
[Description("分享")]
直播间分享 = 8,
[Description("下播")]
- 下播 = 9
+ 下播 = 9,
+
+ [Description("伴侣开播")]
+ 直播伴侣开播 = 101,
+ [Description("伴侣下播")]
+ 直播伴侣下播 = 102
}
///
@@ -67,6 +72,15 @@ namespace BarrageGrab.Modles.JsonEntity
//...其他暂时未知
}
+ ///
+ /// 直播伴侣操作事件
+ ///
+ public enum LiveCompanAction
+ {
+ 开播 = 0,
+ 下播 = 1
+ }
+
///
/// 数据包装器
///
@@ -148,7 +162,7 @@ namespace BarrageGrab.Modles.JsonEntity
/// 解析所有未知类型的消息
///
public void IfAnyMsg(Action action)
- {
+ {
// 将 Data 转换为 JObject
JObject jObject = null;
try
@@ -535,4 +549,14 @@ namespace BarrageGrab.Modles.JsonEntity
///
public ShareType ShareType { get; set; }
}
+
+ ///
+ /// 直播伴侣操作消息
+ ///
+ public class LiveCompanActionMsg : Msg
+ {
+ public LiveCompanAction Action { get; set; }
+
+ public object Data { get; set; } = null;
+ }
}
\ No newline at end of file
diff --git a/BarrageGrab/Properties/AssemblyInfo.cs b/BarrageGrab/Properties/AssemblyInfo.cs
index 87fe95c..b1107af 100644
--- a/BarrageGrab/Properties/AssemblyInfo.cs
+++ b/BarrageGrab/Properties/AssemblyInfo.cs
@@ -33,6 +33,6 @@ using System.Runtime.InteropServices;
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.7.9")]
-[assembly: AssemblyFileVersion("2.7.9")]
+[assembly: AssemblyVersion("2.8.0")]
+[assembly: AssemblyFileVersion("2.8.0")]
[assembly: NeutralResourcesLanguage("zh-CN")]
diff --git a/BarrageGrab/Proxy/ISystemProxy.cs b/BarrageGrab/Proxy/ISystemProxy.cs
index a3edcb1..aa8ab64 100644
--- a/BarrageGrab/Proxy/ISystemProxy.cs
+++ b/BarrageGrab/Proxy/ISystemProxy.cs
@@ -13,6 +13,11 @@ namespace BarrageGrab.Proxy
event EventHandler OnProxyStatus;
+ ///
+ /// 直播伴侣操作事件
+ ///
+ event EventHandler OnLiveCompanAction;
+
///
/// Http上游代理地址
///
diff --git a/BarrageGrab/Proxy/ProxyEventArgs/LiveCompanEventArgs.cs b/BarrageGrab/Proxy/ProxyEventArgs/LiveCompanEventArgs.cs
new file mode 100644
index 0000000..534cb0d
--- /dev/null
+++ b/BarrageGrab/Proxy/ProxyEventArgs/LiveCompanEventArgs.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BarrageGrab.Proxy.ProxyEventArgs
+{
+ public class LiveCompanEventArgs:EventArgs
+ {
+ ///
+ /// 0登录/进入直播伴侣 ,1开播 ,2关播 ,3登出/退出直播伴侣
+ ///
+ public int Action { get; set; }
+
+ ///
+ /// 相关数据
+ ///
+ public object Data { get; set; }
+
+ ///
+ /// 进程ID
+ ///
+ public int ProcessId { get; set; }
+
+ ///
+ /// 进程名称
+ ///
+ public string ProcessName { get; set; }
+ }
+}
diff --git a/BarrageGrab/Proxy/SystemProxy.cs b/BarrageGrab/Proxy/SystemProxy.cs
index 1bd20d6..ce3bd77 100644
--- a/BarrageGrab/Proxy/SystemProxy.cs
+++ b/BarrageGrab/Proxy/SystemProxy.cs
@@ -25,9 +25,14 @@ namespace BarrageGrab.Proxy
public event EventHandler OnFetchResponse;
///
- /// 代理切换时触�?
+ /// 代理切换时触发
///
- public event EventHandler OnProxyStatus;
+ public event EventHandler OnProxyStatus;
+
+ ///
+ /// 直播伴侣操作事件
+ ///
+ public event EventHandler OnLiveCompanAction;
///
/// 代理端口
@@ -82,6 +87,15 @@ namespace BarrageGrab.Proxy
OnFetchResponse?.Invoke(this, args);
}
+ ///
+ /// 触发直播伴侣操作事件
+ ///
+ ///
+ protected void FireLiveCompanEvent(LiveCompanEventArgs args)
+ {
+ OnLiveCompanAction?.Invoke(this, args);
+ }
+
///
/// 获取进程名称
///
diff --git a/BarrageGrab/Proxy/TitaniumProxy.cs b/BarrageGrab/Proxy/TitaniumProxy.cs
index cc2bb43..5a7133d 100644
--- a/BarrageGrab/Proxy/TitaniumProxy.cs
+++ b/BarrageGrab/Proxy/TitaniumProxy.cs
@@ -208,7 +208,10 @@ namespace BarrageGrab.Proxy
var contentType = e.HttpClient.Response.ContentType ?? "";
//处理直播伴侣开播更新
- await HookSelfLive(e);
+ await HookLiveCompanStartLive(e);
+
+ //处理直播伴侣下播
+ await HookLiveCompanEndLive(e);
//处理弹幕
await HookBarrage(e);
@@ -221,15 +224,15 @@ namespace BarrageGrab.Proxy
}
// Hook 直播伴侣开播信息并更新
- private async Task HookSelfLive(SessionEventArgs e)
+ private async Task HookLiveCompanStartLive(SessionEventArgs e)
{
- //Hook 直播伴侣直播间创建 https://webcast.amemv.com/webcast/room/create/?ac=wifi&app_name=webcast_mate&version_code=7.3.3&device_platform=windows&webcast_sdk_version=1520&resolution=1707%2A1067&os_version=10.0.22621&language=zh&aid=2079&live_id=1&channel=online&device_id=2164319493312045&iid=42200736232026&extra_first_tag_id=22&extra_second_tag_id=22093&extra_third_tag_id=22093195&extra_encoder_core=qsv&extra_codec_name=h264_qsv_ex&extra_codec_is_ex=1&extra_use_265=0&msToken=8tJ0NCHWun7wHpdPd_fd0_nlUmgRwM8sQYThkqkq4-qR00mKiJ3Wd3h05r4mm5HO_R_qA2qeTIn8qR2yjcXXoh5mmXkewUuTS4G1Yoi_D-m8EZiacZVWoDqgnqw=&X-Bogus=DFSzswVLJzC4fUiKt5a4a3JCqOA1&_signature=_02B4Z6wo00001fHp2wAAAIDCdmADbSJfNUnx6d-AABpim6xRe8bmnvrrC1Z7GWTwK8sPujtot.bkv7h8bk-nde0WvO-78H3cwglXRzZk8uHTs3ZKWlZqOqaBVjgdHIRritV.peh4bkRETofZ7f
+ //Hook 直播伴侣直播间创建 https://webcast.amemv.com/webcast/room/create
string uri = e.HttpClient.Request.RequestUri.ToString();
var urix = new Uri(uri);
var processid = e.HttpClient.ProcessId.Value;
var processName = base.GetProcessName(processid);
- var response = e.HttpClient.Response;
- if (!uri.Contains("/webcast/room/create")) return;
+ var response = e.HttpClient.Response;
+ if (!urix.AbsolutePath.TrimEnd('/').EndsWith("/webcast/room/create")) return;
if (processName != "直播伴侣") return;
if (response.StatusCode != 200) return;
var reponse = await e.GetResponseBodyAsString();
@@ -263,6 +266,56 @@ namespace BarrageGrab.Proxy
{
AppRuntime.RoomCaches.AddRoomInfoCache(roomInfo);
}
+
+ FireLiveCompanEvent(new LiveCompanEventArgs()
+ {
+ Action = 1,
+ Data = roomInfo,
+ ProcessId = processid,
+ ProcessName = processName
+ });
+ }
+
+ // Hook 直播伴侣关播
+ private async Task HookLiveCompanEndLive(SessionEventArgs e)
+ {
+ //Hook 直播伴侣关闭直播 https://webcast5-mate-lf.amemv.com/webcast/room/anchor_finish_info
+ string uri = e.HttpClient.Request.RequestUri.ToString();
+ var urix = new Uri(uri);
+ var processid = e.HttpClient.ProcessId.Value;
+ var processName = base.GetProcessName(processid);
+ var response = e.HttpClient.Response;
+ if (!urix.AbsolutePath.TrimEnd('/').EndsWith("/webcast/room/anchor_finish_info")) return;
+ if (processName != "直播伴侣") return;
+ if (response.StatusCode != 200) return;
+ var reponse = await e.GetResponseBodyAsString();
+
+ dynamic jobj = JsonConvert.DeserializeObject(reponse);
+ JObject owner = jobj?.data?.owner?.ToObject();
+
+ if (owner == null) return;
+
+ var info = new AnchorFinishInfo()
+ {
+ Nickname = owner["nickname"].Value(),
+ HeadUrl = owner["avatar_thumb"]?["url_list"]?.Values().FirstOrDefault() ?? "",
+ SecUid = owner["sec_uid"]?.Value() ?? "",
+ UserId = owner["id"]?.Value() ?? 0,
+ DisplayId = owner["display_id"]?.Value() ?? "",
+ RoomId = owner["own_room"]?["room_ids_str"]?.Values().FirstOrDefault() ?? ""
+ };
+
+ if (info.UserId == 0) return;
+
+ Logger.LogInfo($"直播伴侣关播,关播账号:{info.DisplayId} {info.Nickname} RoomId={info.RoomId}");
+
+ FireLiveCompanEvent(new LiveCompanEventArgs()
+ {
+ Action = 2,
+ Data = info,
+ ProcessId = processid,
+ ProcessName = processName
+ });
}
// Hook 弹幕
@@ -282,6 +335,7 @@ namespace BarrageGrab.Proxy
)
{
e.DataReceived += WebSocket_DataReceived;
+ e.DataSent += WebSocket_DataSent;
var urix = new Uri(uri);
var roomid = urix.GetQueryParam("room_id");
Logger.LogInfo($"订阅到新的弹幕流地址,roomid:{roomid}");
@@ -333,6 +387,8 @@ namespace BarrageGrab.Proxy
}
}
+
+
// Hook 直播页面
private async Task HookPageAsync(SessionEventArgs e)
{
@@ -360,152 +416,50 @@ namespace BarrageGrab.Proxy
if (liveRoomMactch.Success)
{
string webrid = liveRoomMactch.Groups[1].Value;
- //获取直播页注入js
- string liveRoomInjectScript = EmbResource.GetFileContent("livePage.js");
- //注入上下文变量;
- var scriptContext = BuildContext(new Dictionary()
- {
- {"PROCESS_NAME","'{processName}'"},
- {"AUTOPAUSE",AppSetting.Current.AutoPause.ToString().ToLower()}
- });
- liveRoomInjectScript = scriptContext + liveRoomInjectScript;
var html = await e.GetResponseBodyAsString();
- var doc = new HtmlDocument();
- doc.LoadHtml(html);
- if (!liveRoomInjectScript.IsNullOrWhiteSpace())
+ //利用 HtmlAgilityPack 在尾部注入script 标签
+ RoomInfo roominfo;
+ var tup = RoomInfo.TryParseRoomPageHtml(html, out roominfo);
+ int code = tup.Item1;
+ string msg = tup.Item2;
+
+ if (code == 0)
{
- //利用 HtmlAgilityPack 在尾部注入script 标签
- RoomInfo roominfo;
- var tup = RoomInfo.TryParseRoomPageHtml(html, out roominfo);
- int code = tup.Item1;
- string msg = tup.Item2;
-
- if (code == 0)
- {
- Logger.LogInfo($"直播页{webrid} [{roominfo.Owner.Nickname}]的直播间,房间信息已采集到缓存");
- roominfo.WebRoomId = webrid;
- roominfo.LiveUrl = url;
- AppRuntime.RoomCaches.AddRoomInfoCache(roominfo);
- }
- else
- {
- roominfo = new RoomInfo();
- roominfo.WebRoomId = webrid;
- roominfo.LiveUrl = url;
- //正则匹配主播标题
- //和平精英小夜y
- var match = Regex.Match(html, @"(?<=live-room-nickname""\>).+(?=<\/div>)");
- if (match.Success)
- {
- roominfo.Owner = new RoomInfo.RoomAnchor()
- {
- Nickname = match.Value,
- UserId = "-1"
- };
- }
- AppRuntime.RoomCaches.AddRoomInfoCache(roominfo);
- }
-
- try
- {
-
- //找到body标签,在尾部注入script标签
- var body = doc.DocumentNode.SelectSingleNode("//body");
- if (body != null)
- {
- var script = doc.CreateElement("script");
- script.InnerHtml = liveRoomInjectScript;
- body.AppendChild(script);
- html = doc.DocumentNode.OuterHtml;
- Logger.LogTrace($"直播页{urlNoQuery},用户脚本已成功注入!\n");
- }
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, $"直播页{url},用户脚本注入异常");
- }
+ Logger.LogInfo($"直播页{webrid} [{roominfo.Owner.Nickname}]的直播间,房间信息已采集到缓存");
+ roominfo.WebRoomId = webrid;
+ roominfo.LiveUrl = url;
}
-
- //给script标签 src加上时间戳避免缓存
- if (AppSetting.Current.DisableLivePageScriptCache)
+ else
{
- ScriptAddTocks(doc);
+ roominfo = new RoomInfo();
+ roominfo.WebRoomId = webrid;
+ roominfo.LiveUrl = url;
+ //正则匹配主播标题
+ //和平精英小夜y
+ var match = Regex.Match(html, @"(?<=live-room-nickname""\>).+(?=<\/div>)");
+ if (match.Success)
+ {
+ roominfo.Owner = new RoomInfo.RoomAnchor()
+ {
+ Nickname = match.Value,
+ UserId = "-1"
+ };
+ }
}
+ AppRuntime.RoomCaches.AddRoomInfoCache(roominfo);
- html = doc.DocumentNode.OuterHtml;
+ //控制自动暂停
+ if (AppSetting.Current.AutoPause)
+ {
+ html = html.Replace("autoplay":true", "autoplay":false");
+ Logger.LogInfo("已禁用直播自动播放");
+ }
e.SetResponseBodyString(html);
- }
-
- //直播主页
- if (liveHomeMatch.Success)
- {
- //获取直播页注入js
- string liveHoomInjectScript = EmbResource.GetFileContent("livePage.js");
-
- //注入上下文变量;
- var scriptContext = BuildContext(new Dictionary()
- {
- {"PROCESS_NAME","'{processName}'"},
- {"AUTOPAUSE",AppSetting.Current.AutoPause.ToString().ToLower()}
- });
- liveHoomInjectScript = scriptContext + liveHoomInjectScript;
-
-
- if (!liveHoomInjectScript.IsNullOrWhiteSpace())
- {
- //利用 HtmlAgilityPack 在尾部注入script 标签
- var html = await e.GetResponseBodyAsString();
- var doc = new HtmlAgilityPack.HtmlDocument();
- doc.LoadHtml(html);
- //找到body标签,在尾部注入script标签
- var body = doc.DocumentNode.SelectSingleNode("//body");
- if (body != null)
- {
- var script = doc.CreateElement("script");
- script.InnerHtml = liveHoomInjectScript;
- body.AppendChild(script);
- var newHtml = doc.DocumentNode.OuterHtml;
- e.SetResponseBodyString(newHtml);
- Logger.PrintColor($"直播首页{urlNoQuery},用户脚本已成功注入!\n", ConsoleColor.Green);
- }
- }
- }
+ }
}
-
- //给部分脚本加上时间戳避免缓存
- private void ScriptAddTocks(HtmlDocument doc)
- {
- var scripts = doc.DocumentNode.SelectNodes("//script[@src]");
- if (scripts != null)
- {
- var ticks = DateTime.Now.Ticks;
- foreach (var script in scripts)
- {
- var src = script.Attributes["src"].Value;
-
- var srcUri = new Uri(src);
- if (!CheckHost(srcUri.Host)) continue;
-
- var fileName = Path.GetFileName(src.Split('?')[0]);
- //目前只需要用到相关这些js
- if (!fileName.StartsWith("island") && !src.Contains(LIVE_SCRIPT_PATH)) continue;
-
- if (src.Contains("?"))
- {
- src += "&_t=" + ticks;
- }
- else
- {
- src += "?_t=" + ticks;
- }
- script.Attributes["src"].Value = src;
- }
-
- }
- }
-
+
//生成注入上下文
private string BuildContext(IDictionary constVals)
{
@@ -533,9 +487,10 @@ namespace BarrageGrab.Proxy
if (e.HttpClient.Response.StatusCode != 200) return;
//https://lf-webcast-platform.bytetos.com/obj/webcast-platform-cdn/webcast/douyin_live/chunks/island_a74ce.b55095a0.js
+ //https://lf-webcast-platform.bytetos.com/obj/webcast-platform-cdn/webcast/douyin_live/chunks/PausePop.ec38fcf8.js 2026/04/09
//判断响应内容是否为js application/javascript
if (processName != "直播伴侣" && processName != "douyin"
- && fileName.StartsWith("island")
+ && fileName.ToLower().StartsWith("pausepop")
)
{
var js = await e.GetResponseBodyAsString();
@@ -628,6 +583,51 @@ namespace BarrageGrab.Proxy
return base.CheckHost(hostname);
}
+ private void WebSocket_DataSent(object sender, DataEventArgs e)
+ {
+ var args = (SessionEventArgs)sender;
+
+ string hostname = args.HttpClient.Request.RequestUri.Host;
+
+ var processid = args.HttpClient.ProcessId.Value;
+
+ List messageData = new List();
+
+ foreach (var frame in args.WebSocketDecoderReceive.Decode(e.Buffer, e.Offset, e.Count))
+ {
+ if (frame.OpCode == WebsocketOpCode.Continuation)
+ {
+ messageData.AddRange(frame.Data.ToArray());
+ continue;
+ }
+ else
+ {
+ //读取完毕
+ byte[] payload;
+ if (messageData.Count > 0)
+ {
+ messageData.AddRange(frame.Data.ToArray());
+ payload = messageData.ToArray();
+ messageData.Clear();
+ }
+ else
+ {
+ payload = frame.Data.ToArray();
+ }
+
+ var str = Encoding.UTF8.GetString(payload);
+
+ //base.FireWsEvent(new WsMessageEventArgs()
+ //{
+ // ProcessID = processid,
+ // HostName = hostname,
+ // Payload = payload,
+ // ProcessName = base.GetProcessName(processid)
+ //});
+ }
+ }
+ }
+
//WebSocket 流读取
private async void WebSocket_DataReceived(object sender, DataEventArgs e)
{
diff --git a/BarrageGrab/Scripts/inject/livePage.js b/BarrageGrab/Scripts/inject/livePage.js
index 1192a18..5aeda24 100644
--- a/BarrageGrab/Scripts/inject/livePage.js
+++ b/BarrageGrab/Scripts/inject/livePage.js
@@ -18,17 +18,3 @@ function getQueryString(name) {
return null;
}
-if (getQueryString("pause") === "true" || AUTOPAUSE === true) {
- //自动暂停一次播放
- var pauseIdx = setInterval(() => {
- let playbtn = document.querySelector(".xgplayer-play");
- if (!playbtn) return;
- let status = playbtn.getAttribute("data-state");
- if (status !== "play") return;
- playbtn.click();
- clearInterval(pauseIdx);
- console.log("已自动暂停播放");
- }, 500);
-}
-
-
diff --git a/BarrageGrab/Server/WsBarrageServer.cs b/BarrageGrab/Server/WsBarrageServer.cs
index 31276fa..12b99d2 100644
--- a/BarrageGrab/Server/WsBarrageServer.cs
+++ b/BarrageGrab/Server/WsBarrageServer.cs
@@ -15,6 +15,7 @@ using System.Timers;
using BarrageGrab.Modles;
using BarrageGrab.Modles.JsonEntity;
using BarrageGrab.Modles.ProtoEntity;
+using BarrageGrab.Proxy.ProxyEventArgs;
using Fleck;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -89,12 +90,15 @@ namespace BarrageGrab
this.grab.OnRoomUserSeqMessage += Grab_OnRoomUserSeqMessage;
this.grab.OnFansclubMessage += Grab_OnFansclubMessage; ;
this.grab.OnControlMessage += Grab_OnControlMessage;
+ this.grab.Proxy.OnLiveCompanAction += Proxy_OnLiveCompanAction;
this.socketServer = socket;
//dieout.Start();
giftCountTimer.Start();
}
+
+
//礼物缓存清理计时器回调
private void GiftCountTimer_Elapsed(object sender, ElapsedEventArgs e)
{
@@ -562,7 +566,7 @@ namespace BarrageGrab
AttachRoomInfo(enty);
FirePack(enty, msgType);
PrintMsg(enty, msgType);
- pack = new BarrageMsgPack(enty.ToJson(), PackMsgType.下播, e.Process);
+ pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process);
}
if (pack != null)
@@ -571,6 +575,64 @@ namespace BarrageGrab
}
}
+ //直播伴侣上下播
+ private void Proxy_OnLiveCompanAction(object sender, LiveCompanEventArgs e)
+ {
+ var msgid = DateTime.Now.Ticks;
+ BarrageMsgPack pack = null;
+
+ if (e.Action == 1)
+ {
+ RoomInfo roomInfo = e.Data as RoomInfo;
+ if(roomInfo == null) return;
+
+ var enty = new LiveCompanActionMsg()
+ {
+ MsgId = msgid,
+ Content = $" [{roomInfo.Owner.Nickname}] 开播了",
+ RoomId = roomInfo.RoomId,
+ WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(roomInfo.RoomId),
+ User = null,
+ Appid = "0",
+ Data = roomInfo,
+ };
+
+ var msgType = PackMsgType.直播伴侣开播;
+ AttachRoomInfo(enty);
+ FirePack(enty, msgType);
+ PrintMsg(enty, msgType);
+ pack = new BarrageMsgPack(enty.ToJson(), msgType, e.ProcessName);
+ }
+
+ if (e.Action == 2)
+ {
+ var info = e.Data as AnchorFinishInfo;
+ if (info.RoomId.IsNullOrWhiteSpace()) return;
+
+ var enty = new LiveCompanActionMsg()
+ {
+ MsgId = msgid,
+ Content = $" [{info.Nickname}]下播,房间号:{info.RoomId}",
+ RoomId = info.RoomId,
+ WebRoomId = AppRuntime.RoomCaches.GetCachedWebRoomid(info.RoomId),
+ Appid = "0",
+ Data = info
+ };
+
+ var msgType = PackMsgType.直播伴侣下播;
+ AttachRoomInfo(enty);
+ FirePack(enty, msgType);
+ PrintMsg(enty, msgType);
+ pack = new BarrageMsgPack(enty.ToJson(), msgType, e.ProcessName);
+ }
+
+
+ if (pack != null)
+ {
+ Broadcast(pack);
+ }
+ }
+
//监听用户连接
private void Listen(IWebSocketConnection socket)
{
diff --git a/BarrageGrab/WssBarrageService.csproj b/BarrageGrab/WssBarrageService.csproj
index 42c0452..cbdd9ff 100644
--- a/BarrageGrab/WssBarrageService.csproj
+++ b/BarrageGrab/WssBarrageService.csproj
@@ -16,6 +16,8 @@
true
false
+
+
publish\
true
Disk
@@ -30,8 +32,6 @@
1.0.0.%2a
false
true
-
-
true
@@ -221,6 +221,8 @@
+
+