Merge pull request #19 from HaoDong108/master

Master
This commit is contained in:
小白不圆
2024-09-28 17:10:59 +08:00
committed by GitHub
13 changed files with 1046 additions and 196 deletions
+33 -3
View File
@@ -10,6 +10,8 @@
<add key="listenAny" value="true" /> <add key="listenAny" value="true" />
<!--系统代理端口--> <!--系统代理端口-->
<add key="proxyPort" value="8827" /> <add key="proxyPort" value="8827" />
<!--是否启用系统代理,若设置为false 则需要在程序手动指定代理地址 -->
<add key="usedProxy" value="true" />
<!--上游代理地址,例如开启了系统代理,但是需要将其他无关请求转发到VPN工具中,例如:127.0.0.1:11223,不要带http://--> <!--上游代理地址,例如开启了系统代理,但是需要将其他无关请求转发到VPN工具中,例如:127.0.0.1:11223,不要带http://-->
<add key="upstreamProxy" value="" /> <add key="upstreamProxy" value="" />
<!--在控制台输出弹幕--> <!--在控制台输出弹幕-->
@@ -22,8 +24,6 @@
<add key="logFilter" value="1,2,4,5,6,7,8" /> <add key="logFilter" value="1,2,4,5,6,7,8" />
<!--要进行过滤的Web房间ID,多个使用','分隔,根据缓存来过滤的,直播伴侣不支持 --> <!--要进行过滤的Web房间ID,多个使用','分隔,根据缓存来过滤的,直播伴侣不支持 -->
<add key="webRoomIds" value="" /> <add key="webRoomIds" value="" />
<!--是否启用系统代理,若设置为false 则需要在程序手动指定代理地址 -->
<add key="usedProxy" value="true" />
<!--开启内置的域名过滤,设置为false会解包所有https请求,cpu占用很高,建议在无法获取弹幕数据时调整 --> <!--开启内置的域名过滤,设置为false会解包所有https请求,cpu占用很高,建议在无法获取弹幕数据时调整 -->
<add key="filterHostName" value="true" /> <add key="filterHostName" value="true" />
<!--已知的弹幕域名列表 ','分隔 用作过滤规则中,凡是webcast开头的域名程序都会自动列入白名单--> <!--已知的弹幕域名列表 ','分隔 用作过滤规则中,凡是webcast开头的域名程序都会自动列入白名单-->
@@ -41,11 +41,13 @@
<!--弹幕轮询间隔,当 forcePolling 为 true 时生效 (毫秒,1000毫秒=1秒,不建议小于1000毫秒,太小可能会被封IP,值越小,弹幕流越丝滑,对于观众多的直播间可以改小)--> <!--弹幕轮询间隔,当 forcePolling 为 true 时生效 (毫秒,1000毫秒=1秒,不建议小于1000毫秒,太小可能会被封IP,值越小,弹幕流越丝滑,对于观众多的直播间可以改小)-->
<add key="pollingInterval" value="3000" /> <add key="pollingInterval" value="3000" />
<!--禁用直播页浏览器脚本缓存 (如果需要确保脚本每次能够正常匹配替换,则启用它,可能会损失一定的页面加载速度)--> <!--禁用直播页浏览器脚本缓存 (如果需要确保脚本每次能够正常匹配替换,则启用它,可能会损失一定的页面加载速度)-->
<add key="disableLivePageScriptCache" value="true" /> <add key="disableLivePageScriptCache" value="false" />
<!--指定要发送的COM串口 格式:'COM1:9600' 代表用COM1发送,波特率9600,若不需要使用串口抄送服务请留空 --> <!--指定要发送的COM串口 格式:'COM1:9600' 代表用COM1发送,波特率9600,若不需要使用串口抄送服务请留空 -->
<add key="comPort" value="" /> <add key="comPort" value="" />
<!--启用自定义消息过滤,启用后可去程序根目录 Scripts/engine/comPortFilter.js 调整过滤规则 --> <!--启用自定义消息过滤,启用后可去程序根目录 Scripts/engine/comPortFilter.js 调整过滤规则 -->
<add key="useComPortFilter" value="true" /> <add key="useComPortFilter" value="true" />
<!--直播伴侣exe文件位置(除非程序找不到,否则请留空)-->
<add key="liveCompanPath" value="" />
</appSettings> </appSettings>
<runtime> <runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
@@ -53,6 +55,34 @@
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> <assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" /> <bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.Tracing" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>
<startup> <startup>
+6
View File
@@ -40,6 +40,7 @@ namespace BarrageGrab
PollingInterval = int.Parse(AppSettings["pollingInterval"].Trim()); PollingInterval = int.Parse(AppSettings["pollingInterval"].Trim());
DisableLivePageScriptCache = bool.Parse(AppSettings["disableLivePageScriptCache"].Trim()); DisableLivePageScriptCache = bool.Parse(AppSettings["disableLivePageScriptCache"].Trim());
WebRoomIds = AppSettings["webRoomIds"].Trim().Split(',').Where(w => !string.IsNullOrWhiteSpace(w)).ToArray(); WebRoomIds = AppSettings["webRoomIds"].Trim().Split(',').Where(w => !string.IsNullOrWhiteSpace(w)).ToArray();
LiveCompanPath = AppSettings["liveCompanPath"].Trim();
ConfigComPort(); ConfigComPort();
ConfigFilter(); ConfigFilter();
@@ -243,5 +244,10 @@ namespace BarrageGrab
/// 是否启用串口过滤器脚本 /// 是否启用串口过滤器脚本
/// </summary> /// </summary>
public bool UseComPortFilter { get; set; } public bool UseComPortFilter { get; set; }
/// <summary>
/// 直播伴侣文件位置
/// </summary>
public string LiveCompanPath { get; set; } = string.Empty;
} }
} }
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura />
</Weavers>
+173
View File
@@ -0,0 +1,173 @@
using HtmlAgilityPack;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using IWshRuntimeLibrary;
using File = System.IO.File;
namespace BarrageGrab
{
public static class LiveCompanHelper
{
/// <summary>
/// 获取抖音直播伴侣的exe路径
/// </summary>
/// <returns></returns>
public static string GetExePath()
{
string exePath = "";
//获取exe所在目录
//1.先在开始菜单找
var shortcutPath = @"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\直播伴侣.lnk";
if (File.Exists(shortcutPath))
{
//获取快捷方式的目标路径
exePath = GetInkTargetPath(shortcutPath);
if (!File.Exists(exePath))
{
exePath = "";
Logger.LogWarn($"直播伴侣.lnk 所指向的exe文件位置 {exePath} 无效");
}
}
else
{
Logger.LogInfo("未找到直播伴侣的桌面快捷方式");
}
//再从配置文件读取
if (exePath.IsNullOrWhiteSpace())
{
exePath = AppSetting.Current.LiveCompanPath;
if(!exePath.IsNullOrWhiteSpace() && !File.Exists(exePath))
{
Logger.LogWarn($"所配置的 {exePath} 不存在");
exePath = "";
}
}
return exePath;
}
/// <summary>
/// 初始化直播伴侣环境
/// </summary>
public static void SwitchSetup()
{
var exePath = GetExePath();
if (string.IsNullOrEmpty(exePath))
{
Logger.LogWarn("未找到直播伴侣.exe文件,跳过环境设置");
return;
}
//设置index.js
var indexJsPath = Path.Combine(Path.GetDirectoryName(exePath), "resources", "app", "index.js");
Logger.LogInfo($"正在配置 " + indexJsPath);
if (!File.Exists(indexJsPath))
{
throw new Exception("未找到直播伴侣的index.js文件");
}
var indexJs = File.ReadAllText(indexJsPath, Encoding.UTF8);
CheckBackFile(indexJsPath);
var newjs = SetIndexJsContent(indexJs);
if (newjs != indexJs && !newjs.IsNullOrWhiteSpace())
{
File.WriteAllText(indexJsPath, newjs);
}
Logger.LogInfo("直播伴侣环境初始化完成");
}
//获取Ink快捷方式的目标路径
private static string GetInkTargetPath(string shortcutPath)
{
// 创建 Windows Script Host 对象
WshShell shell = new WshShell();
// 使用 IWshShortcut 接口加载 .ink 文件
IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutPath);
// 获取目标路径
string targetPath = shortcut.TargetPath;
return targetPath;
}
//检测备份文件
private static void CheckBackFile(string filePath)
{
if (!File.Exists(filePath)) return;
var bakPath = filePath + ".bak";
if (!File.Exists(bakPath))
{
//拷贝一份备份
File.Copy(filePath, bakPath);
Logger.LogInfo($"已备份 {filePath} -> {bakPath}");
}
}
//设置index.js内容
private static string SetIndexJsContent(string content)
{
//检测注入代理
var mineProxyHost = $"127.0.0.1:{AppSetting.Current.ProxyPort},direct://";
SetSwitch("proxy-server", mineProxyHost, ref content);
//移除文件损坏检测校验
var checkReg = new Regex(@"if\(\(0,\w.integrityCheckReport\)\(\w\),!\w\.ok\)");
if (checkReg.IsMatch(content))
{
content = checkReg.Replace(content, "if(false)");
Logger.LogInfo($"直播伴侣文件改动检测已拦截");
}
return content;
}
//添加 electron 启动参数
private static void SetSwitch(string name, string value, ref string content)
{
if (name.IsNullOrWhiteSpace()) return;
//检测注入
var proxyReg = new Regex($@"(?<varname>\w+)\.commandLine\.appendSwitch\(""{name}"",""(?<value>[^""]*)""\)");
var proxyMatch = proxyReg.Match(content);
//检测到已经存在配置,则更新参数值
if (proxyMatch.Success)
{
var matchValue = proxyMatch.Groups["value"].Value;
if (value != matchValue)
{
content = proxyReg.Replace(content, $@"${{varname}}.commandLine.appendSwitch(""{name}"",""{value}"")");
Logger.LogInfo($"直播伴侣成功覆盖启动参数 [{name}] = [{value}]");
}
}
//否则添加新的配置
else
{
var nosandboxReg = new Regex(@"(?<varname>\w+)\.commandLine\.appendSwitch\(""no-sandbox""\)");
var match = nosandboxReg.Match(content);
if (match.Success)
{
var newvalue = $@"{match.Groups["varname"].ToString()}.commandLine.appendSwitch(""{name}"",""{value}""),";
content = content.Insert(match.Index, newvalue);
Logger.LogInfo($"直播伴侣成功添加启动参数 [{name}] = [{value}]");
}
}
}
private static void SetInnerText(HtmlNode node, string text)
{
node.InnerHtml = "";
var textNode = node.OwnerDocument.CreateTextNode(text);
node.AppendChild(textNode);
}
}
}
+150 -2
View File
@@ -91,7 +91,28 @@ namespace BarrageGrab
foreach (var item in list) func(item, i++); foreach (var item in list) func(item, i++);
} }
/// <summary>
/// 是否包含
/// </summary>
/// <param name="obj"></param>
/// <param name="args"></param>
/// <returns></returns>
public static bool In<T>(this T obj, params T[] args)
{
return args.Contains(obj);
}
/// <summary>
/// 是否包含
/// </summary>
/// <param name="obj"></param>
/// <param name="args"></param>
/// <returns></returns>
public static bool LikeIn(this string str, params string[] args)
{
return args.Any(a => str.Contains(a));
}
public static CookieCollection ToCookies(this string cookieStr, string domain) public static CookieCollection ToCookies(this string cookieStr, string domain)
{ {
var cookies = new CookieCollection(); var cookies = new CookieCollection();
@@ -170,6 +191,133 @@ namespace BarrageGrab
if (cookies == null) return; if (cookies == null) return;
var cookieCollection = dic.ToCookies(domain); var cookieCollection = dic.ToCookies(domain);
cookies.Add(cookieCollection); cookies.Add(cookieCollection);
} }
/// <summary>
/// 将字典转为查询参数
/// </summary>
/// <param name="dic"></param>
/// <returns></returns>
public static string ToQueryParam(this IDictionary<string, string> dic, bool encode = true)
{
if (dic == null || dic.Count == 0)
return string.Empty;
var queryParams = dic.Select(kvp => kvp.Key + "=" + (encode ? WebUtility.UrlEncode(kvp.Value) : kvp.Value));
return string.Join("&", queryParams);
}
/// <summary>
/// 赋值字典,没有则添加,有则覆盖
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="dic"></param>
/// <param name="key"></param>
/// <param name="value"></param>
public static void Set<TKey, TValue>(this IDictionary<TKey, TValue> dic, TKey key, TValue value)
{
if (dic.ContainsKey(key))
{
dic[key] = value;
}
else
{
dic.Add(key, value);
}
}
/// <summary>
/// 赋值字典,没有则添加,有则覆盖
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="dic"></param>
/// <param name="kv"></param>
public static void Set<TKey, TValue>(this IDictionary<TKey, TValue> dic, KeyValuePair<TKey, TValue> kv)
{
dic.Set(kv.Key, kv.Value);
}
/// <summary>
/// 获取Uri查询参数
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static IDictionary<string, string> GetQueryParams(this UriBuilder uri)
{
if (uri == null)
{
throw new ArgumentNullException(nameof(uri));
}
var queryParams = uri.Query.TrimStart('?');
if (string.IsNullOrEmpty(queryParams))
{
return new Dictionary<string, string>();
}
return queryParams
.Split('&')
.Select(param => param.Split('='))
.ToDictionary(
keyValuePair => Uri.UnescapeDataString(keyValuePair[0]),
keyValuePair => Uri.UnescapeDataString(keyValuePair.Length > 1 ? keyValuePair[1] : ""));
}
/// <summary>
///
/// </summary>
/// <param name="uri"></param>
/// <param name="vals"></param>
public static void AddQueryParam(this UriBuilder uri, IEnumerable<KeyValuePair<string, string>> vals)
{
if (uri == null) return;
var dic = uri.GetQueryParams();
foreach (var item in vals)
{
dic.Set(item);
}
uri.Query = dic.ToQueryParam();
}
/// <summary>
/// 删除一个query项
/// </summary>
/// <param name="uri"></param>
/// <param name="key"></param>
public static void RemoveQueryParam(this UriBuilder uri, string key)
{
if (uri == null) return;
var dic = uri.GetQueryParams();
dic.Remove(key);
if (dic.Count > 0)
{
uri.Query = "?" + dic.ToQueryParam();
}
else
{
uri.Query = "";
}
}
/// <summary>
/// 添加参数
/// </summary>
/// <param name="uri"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public static void AddQueryParam(this UriBuilder uri, string key, string value)
{
if (uri == null) return;
uri.AddQueryParam(new[] {
new KeyValuePair<string, string>(key,value)
});
}
} }
} }
+10 -59
View File
@@ -18,19 +18,16 @@ namespace BarrageGrab
static bool exited = false; static bool exited = false;
static bool formExited = false; static bool formExited = false;
static WinApi.ControlCtrlDelegate controlCtr = ControlCtrlHandle; static WinApi.ControlCtrlDelegate controlCtr = ControlCtrlHandle;
static Mutex mutex = new Mutex(false, "DyBarrageGrab");
static void Main(string[] args) static void Main(string[] args)
{ {
//JintTest(); if (!mutex.WaitOne(TimeSpan.Zero, true))
//Console.WriteLine("结束");
//Console.ReadKey();
//return;
if (CheckAlreadyRunning())
{ {
Logger.PrintColor("已经有一个监听程序在运行,按任意键退出..."); Console.WriteLine("另一个实例已在运行。");
Console.ReadKey(); Console.ReadKey();
return; return;
} }
SetTitle("抖音弹幕监听推送"); SetTitle("抖音弹幕监听推送");
try try
@@ -39,7 +36,7 @@ namespace BarrageGrab
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.LogError(ex, "程序初始化错误"); Logger.LogError(ex, $"程序初始化错误,{ex.Message}");
MessageBox.Show(ex.Message, "程序初始化错误", MessageBoxButtons.OK, MessageBoxIcon.Error); MessageBox.Show(ex.Message, "程序初始化错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
exited = true; exited = true;
} }
@@ -56,12 +53,12 @@ namespace BarrageGrab
Logger.PrintColor("服务器已关闭..."); Logger.PrintColor("服务器已关闭...");
WinApi.SetConsoleCtrlHandler(controlCtr, false);//反注册捕获控制台关闭 WinApi.SetConsoleCtrlHandler(controlCtr, false);//反注册捕获控制台关闭
} }
private static void Init() private static void Init()
{ {
AppRuntime.Init(); AppRuntime.Init();
LiveCompanHelper.SwitchSetup();
WinApi.SetConsoleCtrlHandler(controlCtr, true);//捕获控制台关闭 WinApi.SetConsoleCtrlHandler(controlCtr, true);//捕获控制台关闭
WinApi.DisableQuickEditMode();//禁用控制台快速编辑模式 WinApi.DisableQuickEditMode();//禁用控制台快速编辑模式
AppRuntime.DisplayConsole(!AppSetting.Current.HideConsole);//控制控制台可见 AppRuntime.DisplayConsole(!AppSetting.Current.HideConsole);//控制控制台可见
@@ -94,8 +91,10 @@ namespace BarrageGrab
} }
AppRuntime.WsServer.StartListen();//启动WS以及代理服务 AppRuntime.WsServer.StartListen();//启动WS以及代理服务
Logger.PrintColor($"{AppRuntime.WsServer.ServerLocation} 弹幕服务已启动...",ConsoleColor.Green); Logger.PrintColor($"{AppRuntime.WsServer.ServerLocation} 弹幕服务已启动,其他端可通过此地址获取到弹幕流信息", ConsoleColor.Green);
SetTitle($"抖音弹幕监听推送 [{AppRuntime.WsServer.ServerLocation}]");
Version version = System.Reflection.Assembly.GetAssembly(typeof(Program)).GetName().Version;
SetTitle($"抖音弹幕监听推送 v{version} [{AppRuntime.WsServer.ServerLocation}]");
} }
//检测设置控制台标题 //检测设置控制台标题
@@ -123,53 +122,5 @@ namespace BarrageGrab
} }
return false; return false;
} }
//检测程序是否多开
private static bool CheckAlreadyRunning()
{
const string mutexName = "DyBarrageGrab";
// Try to create a new named mutex.
bool createdNew;
using (Mutex mutex = new Mutex(true, mutexName, out createdNew))
{
return !createdNew;
}
}
#if DEBUG
private static void JintTest()
{
var jsEng = JsEngine.CreateNewEngine();
var jsFile = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "Scripts", "engine", "comPortFilter.js"), Encoding.UTF8);
//var jsFile = @"D:\develop\Project\dy-barrage-grab\BarrageGrab\Scripts\engine\comPortFilter.js";
jsEng.Execute(jsFile);
var result = jsEng.Invoke("onPackData", 1, new
{
Aporp = 142,
Bprop = "48777",
Cprop = new string[] { "123" },
Dprop = new Dictionary<string, string>()
{
{ "key1","value1" }
}
},null);
Console.WriteLine($"返回类型:{ result.Type.ToString()},值:{result.ToString()}");
if (result.Type == Types.String)
{
Console.WriteLine("返回String: " + result.ToString());
}
if (result.Type == Types.Object)
{
var obj = result.ToObject();
if (obj is byte[])
{
Console.WriteLine("返回byte[]");
}
}
if (result.Type == Types.Symbol)
{
Console.WriteLine("返回Symbol: " + result.ToString());
}
}
#endif
} }
} }
+2 -2
View File
@@ -33,6 +33,6 @@ using System.Runtime.InteropServices;
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示: //通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.7.4.0")] [assembly: AssemblyVersion("2.7.6.0")]
[assembly: AssemblyFileVersion("2.7.4.0")] [assembly: AssemblyFileVersion("2.7.6.0")]
[assembly: NeutralResourcesLanguage("zh-CN")] [assembly: NeutralResourcesLanguage("zh-CN")]
+132 -48
View File
@@ -16,6 +16,13 @@ using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.StreamExtended.Network; using Titanium.Web.Proxy.StreamExtended.Network;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;
using System.Net.Http;
using System.Text;
using BrotliSharpLib;
using System.IO.Compression;
namespace BarrageGrab.Proxy namespace BarrageGrab.Proxy
{ {
@@ -65,7 +72,7 @@ namespace BarrageGrab.Proxy
Logger.LogWarn("代理环境设置失败:" + ex.Message); Logger.LogWarn("代理环境设置失败:" + ex.Message);
} }
} }
public TitaniumProxy() public TitaniumProxy()
{ {
//注册系统代理 //注册系统代理
@@ -75,9 +82,10 @@ namespace BarrageGrab.Proxy
proxyServer.ReuseSocket = false; proxyServer.ReuseSocket = false;
proxyServer.EnableConnectionPool = true; proxyServer.EnableConnectionPool = true;
proxyServer.ForwardToUpstreamGateway = true; proxyServer.ForwardToUpstreamGateway = true;
proxyServer.CertificateManager.SaveFakeCertificates = true;
proxyServer.CertificateManager.RootCertificate = proxyServer.CertificateManager.LoadRootCertificate(); proxyServer.CertificateManager.CertificateValidDays = 365 * 10;
proxyServer.CertificateManager.SaveFakeCertificates = true;
proxyServer.CertificateManager.RootCertificate = GetCert();
if (proxyServer.CertificateManager.RootCertificate == null) if (proxyServer.CertificateManager.RootCertificate == null)
{ {
Logger.PrintColor("正在进行证书安装,需要信任该证书才可进行https解密,若有提示请确定"); Logger.PrintColor("正在进行证书安装,需要信任该证书才可进行https解密,若有提示请确定");
@@ -97,6 +105,64 @@ namespace BarrageGrab.Proxy
proxyServer.AddEndPoint(explicitEndPoint); proxyServer.AddEndPoint(explicitEndPoint);
} }
private X509Certificate2 GetCert()
{
X509Certificate2 result = proxyServer.CertificateManager.LoadRootCertificate();
if (result != null) return result;
return null;
// 打开“受信任的根证书颁发机构”存储区
using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
store.Open(OpenFlags.ReadOnly);
// 遍历证书集合
foreach (X509Certificate2 cert in store.Certificates)
{
try
{
// 尝试使用证书创建 X509Certificate2 实例
X509Certificate2 certificate = new X509Certificate2(cert);
//判断过期
if (DateTime.Now > certificate.NotAfter) continue;
//判断黑名单
var black = new string[] { "localhost" };
if (certificate.FriendlyName.ToLower().LikeIn(black) ||
certificate.Subject.ToLower().LikeIn(black)
) continue;
if (certificate.FriendlyName.ToLower().LikeIn("titanium"))
{
result = certificate;
break;
}
// 打印证书信息
//Console.WriteLine("证书: " + certificate.Subject);
//Console.WriteLine("颁发者: " + certificate.Issuer);
//Console.WriteLine("有效期: " + certificate.NotBefore + " - " + certificate.NotAfter);
//result = certificate;
//break;
}
catch (CryptographicException ex)
{
//捕获加密异常,如果证书需要密码,这里会抛出异常
throw new Exception("证书加载失败: " + ex.Message);
}
}
store.Close();
}
return result;
}
public override void SetUpstreamProxy(string upstreamProxyAddr) public override void SetUpstreamProxy(string upstreamProxyAddr)
{ {
if (string.IsNullOrWhiteSpace(upstreamProxyAddr)) return; if (string.IsNullOrWhiteSpace(upstreamProxyAddr)) return;
@@ -121,6 +187,11 @@ namespace BarrageGrab.Proxy
} }
} }
private bool CheckBrowser(string processName)
{
return AppSetting.Current.ProcessFilter.Contains(processName) && processName!="直播伴侣" && processName!= "douyin";
}
private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e) private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e)
{ {
string uri = e.HttpClient.Request.RequestUri.ToString(); string uri = e.HttpClient.Request.RequestUri.ToString();
@@ -208,7 +279,7 @@ namespace BarrageGrab.Proxy
if (uri.Contains(BARRAGE_POOL_PATH) && contentType.Contains("application/protobuffer")) if (uri.Contains(BARRAGE_POOL_PATH) && contentType.Contains("application/protobuffer"))
{ {
var payload = await e.GetResponseBody(); var payload = await e.GetResponseBody();
base.FireOnFetchResponse(new HttpResponseEventArgs() base.FireOnFetchResponse(new HttpResponseEventArgs()
{ {
HttpClient = e.HttpClient, HttpClient = e.HttpClient,
@@ -274,7 +345,7 @@ namespace BarrageGrab.Proxy
}); });
liveRoomInjectScript = scriptContext + liveRoomInjectScript; liveRoomInjectScript = scriptContext + liveRoomInjectScript;
var html = await e.GetResponseBodyAsString(); var html = await e.GetResponseBodyAsString();
var doc = new HtmlAgilityPack.HtmlDocument(); var doc = new HtmlDocument();
doc.LoadHtml(html); doc.LoadHtml(html);
if (!liveRoomInjectScript.IsNullOrWhiteSpace()) if (!liveRoomInjectScript.IsNullOrWhiteSpace())
@@ -311,7 +382,6 @@ namespace BarrageGrab.Proxy
AppRuntime.RoomCaches.AddRoomInfoCache(roominfo); AppRuntime.RoomCaches.AddRoomInfoCache(roominfo);
} }
try try
{ {
@@ -335,27 +405,11 @@ namespace BarrageGrab.Proxy
//给script标签 src加上时间戳避免缓存 //给script标签 src加上时间戳避免缓存
if (AppSetting.Current.DisableLivePageScriptCache) if (AppSetting.Current.DisableLivePageScriptCache)
{ {
var scripts = doc.DocumentNode.SelectNodes("//script[@src]"); ScriptAddTocks(doc);
if (scripts != null)
{
var ticks = DateTime.Now.Ticks;
foreach (var script in scripts)
{
var src = script.Attributes["src"].Value;
if (src.Contains("?"))
{
src += "&_t=" + ticks;
}
else
{
src += "?_t=" + ticks;
}
script.Attributes["src"].Value = src;
}
html = doc.DocumentNode.OuterHtml;
}
} }
html = doc.DocumentNode.OuterHtml;
e.SetResponseBodyString(html); e.SetResponseBodyString(html);
} }
@@ -395,6 +449,38 @@ namespace BarrageGrab.Proxy
} }
} }
//给部分脚本加上时间戳避免缓存
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<string, string> constVals) private string BuildContext(IDictionary<string, string> constVals)
{ {
@@ -415,6 +501,7 @@ namespace BarrageGrab.Proxy
var processid = e.HttpClient.ProcessId.Value; var processid = e.HttpClient.ProcessId.Value;
var processName = base.GetProcessName(processid); var processName = base.GetProcessName(processid);
var contentType = e.HttpClient.Response.ContentType ?? ""; var contentType = e.HttpClient.Response.ContentType ?? "";
var fileName = Path.GetFileName(urlNoQuery);
if (contentType == null) return; if (contentType == null) return;
if (!contentType.Trim().ToLower().Contains("application/javascript")) return; if (!contentType.Trim().ToLower().Contains("application/javascript")) return;
@@ -424,19 +511,17 @@ namespace BarrageGrab.Proxy
if (hostname == SCRIPT_HOST if (hostname == SCRIPT_HOST
//这俩个进程不需要注入 //这俩个进程不需要注入
&& processName != "直播伴侣" && processName != "douyin" && processName != "直播伴侣" && processName != "douyin"
&& fileName.StartsWith("island")
) )
{ {
var js = await e.GetResponseBodyAsString(); var js = await e.GetResponseBodyAsString();
//var reg2 = new Regex(@"if\(!N.DJ\(\)&&(?<variable>\S).current\)\{"); //版本1,已过时 var reg2 = new Regex(@"if\(!\((?<v1>\d,\w{1,2})\.DJ\)\(\)&&");
//if(!(0,k.DJ)()&amp;&amp;_.current){
var reg2 = new Regex(@"if\s*\(\s*\!\s*(?<v1>[\s\S]+\s*\.\s*DJ\s*\))\s*\(\s*\)\s*&\s*&\s*(?<v2>\S)\s*.\s*current\s*\)\s*\{");
var match = reg2.Match(js); var match = reg2.Match(js);
if (match.Success) if (match.Success)
{ {
js = reg2.Replace(js, "if(!${v1}()&&${v2}.current){return;"); js = reg2.Replace(js, "if(false &&");
e.SetResponseBodyString(js); e.SetResponseBodyString(js);
Logger.PrintColor($"已成功绕过JS页面无操作检测 {urlNoQuery}\n", ConsoleColor.Green); Logger.PrintColor($"已成功绕过页面无操作检测\n", ConsoleColor.Green);
} }
} }
@@ -479,6 +564,12 @@ namespace BarrageGrab.Proxy
string url = e.HttpClient.Request.RequestUri.ToString(); string url = e.HttpClient.Request.RequestUri.ToString();
string hostname = e.HttpClient.Request.RequestUri.Host; string hostname = e.HttpClient.Request.RequestUri.Host;
e.DecryptSsl = CheckHost(hostname);
}
//检测域名白名单
protected override bool CheckHost(string hostname)
{
//需要解析SSL的域名 放在这里,全开会导致性能问题,应只解析业务需要的域名 //需要解析SSL的域名 放在这里,全开会导致性能问题,应只解析业务需要的域名
var decryptSsls = new string[] var decryptSsls = new string[]
{ {
@@ -489,24 +580,11 @@ namespace BarrageGrab.Proxy
if (decryptSsls.Contains(hostname)) if (decryptSsls.Contains(hostname))
{ {
e.DecryptSsl = true; return true;
return;
} }
else
{
if (!CheckHost(hostname))
{
e.DecryptSsl = false;
}
}
}
//检测域名白名单 hostname = hostname.Trim().ToLower();
protected override bool CheckHost(string host) return base.CheckHost(hostname);
{
host = host.Trim().ToLower();
var succ = base.CheckHost(host);
return succ || host == SCRIPT_HOST || host == LIVE_HOST;
} }
//WebSocket 流读取 //WebSocket 流读取
@@ -585,14 +663,20 @@ namespace BarrageGrab.Proxy
/// </summary> /// </summary>
override public void Start() override public void Start()
{ {
proxyServer.Start(AppSetting.Current.UsedProxy); proxyServer.Start(false);
if (AppSetting.Current.UsedProxy) if (AppSetting.Current.UsedProxy)
{ {
base.RegisterSystemProxy(); base.RegisterSystemProxy();
Logger.LogInfo($"系统代理代理已启动,127.0.0.1:{base.ProxyPort}");
//使用其自带的系统代理设置可能会导致格式问题 //使用其自带的系统代理设置可能会导致格式问题
//proxyServer.SetAsSystemHttpProxy(explicitEndPoint); //proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
//proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); //proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
} }
else
{
Logger.LogInfo($"代理已启动(局域代理),127.0.0.1:{base.ProxyPort}");
}
} }
} }
} }
+32 -39
View File
@@ -201,7 +201,7 @@ namespace BarrageGrab
private void PrintMsg(Msg msg, PackMsgType barType) private void PrintMsg(Msg msg, PackMsgType barType)
{ {
var rinfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(msg.RoomId.ToString()); var rinfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(msg.RoomId.ToString());
var roomName = (rinfo?.Owner?.Nickname ?? ("直播间" + (msg.WebRoomId.IsNullOrWhiteSpace() ? msg.RoomId.ToString() : msg.WebRoomId))); var roomName = (rinfo?.Owner?.Nickname ?? ((msg.WebRoomId.IsNullOrWhiteSpace() ? msg.RoomId.ToString() : msg.WebRoomId)));
var text = $"{DateTime.Now.ToString("HH:mm:ss")} [{roomName}] [{barType}]"; var text = $"{DateTime.Now.ToString("HH:mm:ss")} [{roomName}] [{barType}]";
if (msg.User != null) if (msg.User != null)
@@ -347,48 +347,41 @@ namespace BarrageGrab
ogift.Name = findForData.name; ogift.Name = findForData.name;
} }
//判断礼物重复
if (msg.repeatEnd == 1 && giftCountCache.ContainsKey(key))
//Combo 为1时,表示为可连击礼物
//if (msg.Gift.Combo) //一堆礼物Combo 和实际可连击情况不匹配,例如亲吻,闪耀星辰 Combo =false,实际上是可连击的,抖音那帮程序员怕是看女主播冲昏头了
if (true)
{ {
//判断礼物重复 //清除缓存中的key
if (msg.repeatEnd == 1) if (msg.groupId > 0 )
{ {
//清除缓存中的key Tuple<int, DateTime> _;
if (msg.groupId > 0 && giftCountCache.ContainsKey(key)) giftCountCache.TryRemove(key, out _);
{
Tuple<int, DateTime> _;
giftCountCache.TryRemove(key, out _);
}
return;
} }
var backward = currCount <= lastCount; return;
if (currCount <= 0) currCount = 1;
if (giftCountCache.ContainsKey(key))
{
lastCount = giftCountCache[key].Item1;
backward = currCount <= lastCount;
if (!backward)
{
lock (giftCountCache)
{
giftCountCache[key] = Tuple.Create(currCount, DateTime.Now);
}
}
}
else
{
if (msg.groupId > 0 && !backward)
{
giftCountCache.TryAdd(key, Tuple.Create(currCount, DateTime.Now));
}
}
//比上次小,则说明先后顺序出了问题,直接丢掉,应为比它大的消息已经处理过了
if (backward) return;
} }
var backward = currCount <= lastCount;
if (currCount <= 0) currCount = 1;
if (giftCountCache.ContainsKey(key))
{
lastCount = giftCountCache[key].Item1;
backward = currCount <= lastCount;
if (!backward)
{
lock (giftCountCache)
{
giftCountCache[key] = Tuple.Create(currCount, DateTime.Now);
}
}
}
else
{
if (msg.groupId > 0 && !backward)
{
giftCountCache.TryAdd(key, Tuple.Create(currCount, DateTime.Now));
}
}
//比上次小,则说明先后顺序出了问题,直接丢掉,应为比它大的消息已经处理过了
if (backward) return;
var count = currCount - lastCount; var count = currCount - lastCount;
+100 -3
View File
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Costura.Fody.5.7.0\build\Costura.Fody.props" Condition="Exists('..\packages\Costura.Fody.5.7.0\build\Costura.Fody.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<ConcurrentGarbageCollection>false</ConcurrentGarbageCollection> <ConcurrentGarbageCollection>false</ConcurrentGarbageCollection>
@@ -29,6 +30,8 @@
<ApplicationVersion>1.0.0.%2a</ApplicationVersion> <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust> <UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled> <BootstrapperEnabled>true</BootstrapperEnabled>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@@ -70,6 +73,9 @@
<Reference Include="BrotliSharpLib, Version=0.3.2.0, Culture=neutral, PublicKeyToken=3f4e2a1cd615fcb7, processorArchitecture=MSIL"> <Reference Include="BrotliSharpLib, Version=0.3.2.0, Culture=neutral, PublicKeyToken=3f4e2a1cd615fcb7, processorArchitecture=MSIL">
<HintPath>..\packages\BrotliSharpLib.0.3.3\lib\net451\BrotliSharpLib.dll</HintPath> <HintPath>..\packages\BrotliSharpLib.0.3.3\lib\net451\BrotliSharpLib.dll</HintPath>
</Reference> </Reference>
<Reference Include="Costura, Version=5.7.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Costura.Fody.5.7.0\lib\netstandard1.0\Costura.dll</HintPath>
</Reference>
<Reference Include="Esprima, Version=3.0.4.0, Culture=neutral, PublicKeyToken=2e92ba9c8d81157f, processorArchitecture=MSIL"> <Reference Include="Esprima, Version=3.0.4.0, Culture=neutral, PublicKeyToken=2e92ba9c8d81157f, processorArchitecture=MSIL">
<HintPath>..\packages\Esprima.3.0.4\lib\net462\Esprima.dll</HintPath> <HintPath>..\packages\Esprima.3.0.4\lib\net462\Esprima.dll</HintPath>
<Private>True</Private> <Private>True</Private>
@@ -84,6 +90,9 @@
<HintPath>..\packages\Jint.3.0.1\lib\net462\Jint.dll</HintPath> <HintPath>..\packages\Jint.3.0.1\lib\net462\Jint.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Win32.Registry, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="Microsoft.Win32.Registry, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll</HintPath> <HintPath>..\packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll</HintPath>
</Reference> </Reference>
@@ -100,29 +109,93 @@
<HintPath>..\packages\protobuf-net.Core.3.1.22\lib\net462\protobuf-net.Core.dll</HintPath> <HintPath>..\packages\protobuf-net.Core.3.1.22\lib\net462\protobuf-net.Core.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.AppContext, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath>
</Reference>
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> <Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath> <HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Collections.Immutable, Version=1.2.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="System.Collections.Immutable, Version=1.2.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll</HintPath> <HintPath>..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath>
</Reference>
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.Tracing, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" /> <Reference Include="System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll</HintPath>
</Reference>
<Reference Include="System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.4.3.0\lib\net462\System.IO.dll</HintPath>
</Reference>
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
</Reference>
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> <Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath> <HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Net.Sockets, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" /> <Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath> <HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Reflection, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll</HintPath>
</Reference>
<Reference Include="System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath> <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Runtime.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.4.3.0\lib\net462\System.Runtime.InteropServices.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
</Reference>
<Reference Include="System.Security.AccessControl, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="System.Security.AccessControl, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll</HintPath> <HintPath>..\packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
</Reference>
<Reference Include="System.Security.Principal.Windows, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="System.Security.Principal.Windows, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll</HintPath> <HintPath>..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
</Reference> </Reference>
@@ -135,8 +208,10 @@
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
</Reference>
<Reference Include="Titanium.Web.Proxy, Version=1.0.1.0, Culture=neutral, PublicKeyToken=8e41e1f1c790d7cf, processorArchitecture=MSIL"> <Reference Include="Titanium.Web.Proxy, Version=1.0.1.0, Culture=neutral, PublicKeyToken=8e41e1f1c790d7cf, processorArchitecture=MSIL">
<HintPath>..\packages\Titanium.Web.Proxy.3.2.2-beta\lib\net461\Titanium.Web.Proxy.dll</HintPath> <HintPath>..\packages\Titanium.Web.Proxy.3.2.2-beta\lib\net461\Titanium.Web.Proxy.dll</HintPath>
</Reference> </Reference>
@@ -160,6 +235,7 @@
<DependentUpon>RoomDetail.cs</DependentUpon> <DependentUpon>RoomDetail.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="JsEngine.cs" /> <Compile Include="JsEngine.cs" />
<Compile Include="LiveCompanHelper.cs" />
<Compile Include="Logger.cs" /> <Compile Include="Logger.cs" />
<Compile Include="Modles\BusinessExecption.cs" /> <Compile Include="Modles\BusinessExecption.cs" />
<Compile Include="Modles\JsonEntity\BarrageMessages.cs" /> <Compile Include="Modles\JsonEntity\BarrageMessages.cs" />
@@ -194,6 +270,7 @@
<None Include="Properties\app.manifest" /> <None Include="Properties\app.manifest" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="FodyWeavers.xml" />
<Content Include="Scripts\engine\comPortFilter.js"> <Content Include="Scripts\engine\comPortFilter.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
@@ -221,6 +298,26 @@
<DependentUpon>RoomDetail.cs</DependentUpon> <DependentUpon>RoomDetail.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<COMReference Include="IWshRuntimeLibrary">
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Costura.Fody.5.7.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.5.7.0\build\Costura.Fody.props'))" />
<Error Condition="!Exists('..\packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.5.7.0\build\Costura.Fody.targets'))" />
<Error Condition="!Exists('..\packages\Fody.6.8.2\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.6.8.2\build\Fody.targets'))" />
</Target>
<Import Project="..\packages\Costura.Fody.5.7.0\build\Costura.Fody.targets" Condition="Exists('..\packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" />
<Import Project="..\packages\Fody.6.8.2\build\Fody.targets" Condition="Exists('..\packages\Fody.6.8.2\build\Fody.targets')" />
</Project> </Project>
+48
View File
@@ -2,23 +2,71 @@
<packages> <packages>
<package id="BouncyCastle.Cryptography" version="2.0.0" targetFramework="net48" /> <package id="BouncyCastle.Cryptography" version="2.0.0" targetFramework="net48" />
<package id="BrotliSharpLib" version="0.3.3" targetFramework="net48" /> <package id="BrotliSharpLib" version="0.3.3" targetFramework="net48" />
<package id="Costura.Fody" version="5.7.0" targetFramework="net462" developmentDependency="true" />
<package id="Esprima" version="3.0.4" targetFramework="net462" /> <package id="Esprima" version="3.0.4" targetFramework="net462" />
<package id="Fleck" version="1.2.0" targetFramework="net48" /> <package id="Fleck" version="1.2.0" targetFramework="net48" />
<package id="Fody" version="6.8.2" targetFramework="net462" developmentDependency="true" />
<package id="HtmlAgilityPack" version="1.11.51" targetFramework="net48" /> <package id="HtmlAgilityPack" version="1.11.51" targetFramework="net48" />
<package id="Jint" version="3.0.1" targetFramework="net462" /> <package id="Jint" version="3.0.1" targetFramework="net462" />
<package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net462" />
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net462" />
<package id="Microsoft.Win32.Registry" version="5.0.0" targetFramework="net48" /> <package id="Microsoft.Win32.Registry" version="5.0.0" targetFramework="net48" />
<package id="NETStandard.Library" version="1.6.1" targetFramework="net462" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" /> <package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
<package id="NLog" version="5.2.3" targetFramework="net48" /> <package id="NLog" version="5.2.3" targetFramework="net48" />
<package id="Portable.BouncyCastle" version="1.8.8" targetFramework="net48" /> <package id="Portable.BouncyCastle" version="1.8.8" targetFramework="net48" />
<package id="protobuf-net" version="3.1.22" targetFramework="net48" /> <package id="protobuf-net" version="3.1.22" targetFramework="net48" />
<package id="protobuf-net.Core" version="3.1.22" targetFramework="net48" /> <package id="protobuf-net.Core" version="3.1.22" targetFramework="net48" />
<package id="System.AppContext" version="4.3.0" targetFramework="net462" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" /> <package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Collections" version="4.3.0" targetFramework="net462" />
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net462" />
<package id="System.Collections.Immutable" version="1.7.1" targetFramework="net48" /> <package id="System.Collections.Immutable" version="1.7.1" targetFramework="net48" />
<package id="System.Console" version="4.3.0" targetFramework="net462" />
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net462" />
<package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net462" />
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net462" />
<package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net462" />
<package id="System.Globalization" version="4.3.0" targetFramework="net462" />
<package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net462" />
<package id="System.IO" version="4.3.0" targetFramework="net462" />
<package id="System.IO.Compression" version="4.3.0" targetFramework="net462" />
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net462" />
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net462" />
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net462" />
<package id="System.Linq" version="4.3.0" targetFramework="net462" />
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net462" />
<package id="System.Memory" version="4.5.5" targetFramework="net48" /> <package id="System.Memory" version="4.5.5" targetFramework="net48" />
<package id="System.Net.Http" version="4.3.0" targetFramework="net462" />
<package id="System.Net.Primitives" version="4.3.0" targetFramework="net462" />
<package id="System.Net.Sockets" version="4.3.0" targetFramework="net462" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" /> <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
<package id="System.ObjectModel" version="4.3.0" targetFramework="net462" />
<package id="System.Reflection" version="4.3.0" targetFramework="net462" />
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net462" />
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net462" />
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net462" />
<package id="System.Runtime" version="4.3.0" targetFramework="net462" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net48" /> <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net48" />
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net462" />
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="net462" />
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net462" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net462" />
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net462" />
<package id="System.Security.AccessControl" version="5.0.0" targetFramework="net48" /> <package id="System.Security.AccessControl" version="5.0.0" targetFramework="net48" />
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net462" />
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net462" />
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net462" />
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net462" />
<package id="System.Security.Principal.Windows" version="5.0.0" targetFramework="net48" /> <package id="System.Security.Principal.Windows" version="5.0.0" targetFramework="net48" />
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net462" />
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net462" />
<package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net462" />
<package id="System.Threading" version="4.3.0" targetFramework="net462" />
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net462" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" /> <package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net462" />
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net462" />
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net462" />
<package id="Titanium.Web.Proxy" version="3.2.2-beta" targetFramework="net48" /> <package id="Titanium.Web.Proxy" version="3.2.2-beta" targetFramework="net48" />
</packages> </packages>
+291
View File
@@ -0,0 +1,291 @@
# ruff: noqa: F401,F403,F405,E402,F541,E722
import asyncio
import websockets
import json
import os
import ctypes
import sys
import time
import winreg
import tkinter as tk
from tkinter import ttk
import customtkinter
import subprocess
import random
import threading
import atexit
import psutil
import queue
# 创建一个队列
gui_queue = queue.Queue()
# 创建一个线程安全的标志
stop_flag = threading.Event()
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
def disable_proxy():
internet_settings = winreg.OpenKey(
winreg.HKEY_CURRENT_USER,
r"Software\Microsoft\Windows\CurrentVersion\Internet Settings",
0,
winreg.KEY_ALL_ACCESS,
)
# 设置代理使能为0(禁用)
winreg.SetValueEx(internet_settings, "ProxyEnable", 0, winreg.REG_DWORD, 0)
# 清空代理服务器信息
winreg.SetValueEx(internet_settings, "ProxyServer", 0, winreg.REG_SZ, "")
winreg.CloseKey(internet_settings)
print("Proxy disabled.")
def initGame():
print("Init game.")
pass
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
self.title("dy-barrage-grab-log-window")
self.geometry("800x600")
self.grid_columnconfigure((0, 1), weight=1)
self.grid_rowconfigure(0, weight=1)
self.LogFrame = LogFrame(self)
self.LogFrame.grid(row=0, column=0, sticky="nsew")
class LogFrame(customtkinter.CTkFrame):
def __init__(self, master):
super().__init__(master)
# 创建一个Frame来包含treeview和滚动条
self.tree_frame = ttk.Frame(self)
self.tree_frame.grid(row=0, column=0, sticky="nsew", padx=50, pady=50)
# 创建一个滚动条
self.scrollbar = customtkinter.CTkScrollbar(self.tree_frame)
self.scrollbar.grid(row=0, column=1, sticky="ns")
self.treeview = ttk.Treeview(
self.tree_frame,
columns=("Type", "User ID", "User Nickname", "Content"),
show="headings",
height=20,
yscrollcommand=self.scrollbar.set, # 将滚动条与treeview关联
)
self.treeview.grid(row=0, column=0, sticky="nsew")
# 设置滚动条的命令为移动treeview
self.scrollbar.configure(command=self.treeview.yview)
# 设置列宽
self.treeview.column("Type", width=50)
self.treeview.column("User ID", width=100)
self.treeview.column("User Nickname", width=100)
self.treeview.column("Content", width=450)
self.treeview.heading("Type", text="Type")
self.treeview.heading("User ID", text="User ID")
self.treeview.heading("User Nickname", text="User Nickname")
self.treeview.heading("Content", text="Content")
# 设置不同类型的颜色
self.treeview.tag_configure("type1", foreground="black")
self.treeview.tag_configure("type2", foreground="cyan")
self.treeview.tag_configure("type3", foreground="gold")
self.treeview.tag_configure("type4", foreground="blue")
self.treeview.tag_configure("type5", foreground="red")
self.treeview.tag_configure("type6", foreground="purple")
self.treeview.tag_configure("type7", foreground="green")
self.treeview.tag_configure("type8", foreground="orange")
self.treeview.tag_configure("type9", foreground="gray")
# 添加更多类型的颜色配置...
def display_message(self, message):
parsed_message = json.loads(message)
message_type = parsed_message.get("Type")
data_str = parsed_message.get("Data", "{}")
try:
data = json.loads(data_str)
except json.JSONDecodeError:
print(f"Cannot parse 'Data' as JSON: {data_str}")
return
user = data.get("User", {})
if user is None:
# print(f"'User' is None in 'Data': {data_str}")
user = {"Id": "无", "Nickname": "无"}
user_id = user.get("Id", "")
user_nickname = user.get("Nickname", "")
content = data.get("Content", "")
# 根据类型设置颜色
color_tag = f"type{message_type}"
message_type_str = [
"无",
"弹幕",
"点赞",
"进房",
"关注",
"礼物",
"统计",
"粉团",
"分享",
"下播",
]
self.treeview.insert(
"",
"end",
values=(
message_type_str[message_type],
user_id,
user_nickname,
content,
),
tags=(color_tag,),
)
# async def send_ping(websocket):
# while True:
# try:
# if websocket.open:
# await websocket.ping()
# await asyncio.sleep(5)
# else:
# break
# except websockets.exceptions.ConnectionClosedOK:
# # 连接已关闭,尝试重新连接
# websocket = await websockets.connect("ws://127.0.0.1:8888")
async def receive_messages():
while True:
try:
async with websockets.connect(
"ws://127.0.0.1:8888", ping_timeout=None, ping_interval=None
) as websocket:
while True:
message = await websocket.recv()
if message is not None:
try:
json.loads(message)
app.LogFrame.display_message(message)
except json.JSONDecodeError:
print(
f"Received a message that could not be parsed as JSON: {message}"
)
except (
websockets.ConnectionClosed,
websockets.exceptions.ConnectionClosedError,
websockets.exceptions.ConnectionClosedOK,
) as e:
print(f"Connection closed, retrying...{e}")
continue
except Exception as e:
print(f"An error occurred on ws server: {e}")
continue
def main():
global listener_process
global app
# Check if the process is already running
for proc in psutil.process_iter():
if proc.name() == "WssBarrageServer.exe":
print("The process is already running.")
proc.kill()
time.sleep(1)
# Start a new process
# 将WssBarrageServer.exe放至同目录下dy-barrage-grab文件夹
# 获取当前脚本的绝对路径
script_dir = os.path.dirname(os.path.realpath(__file__))
# 构建WssBarrageServer.exe的绝对路径
exe_path = os.path.join(script_dir, "dy-barrage-grab", "WssBarrageServer.exe")
# 使用绝对路径启动进程
listener_process = subprocess.Popen(exe_path)
# 创建一个新的事件循环
loop = asyncio.new_event_loop()
# 设置这个事件循环为当前线程的事件循环
asyncio.set_event_loop(loop)
app = App()
# 点击关闭按钮时调用的函数
def on_close():
print("Closing...")
# 设置停止标志
stop_flag.set()
# 关闭WssBarrageServer
listener_process.terminate()
# 关闭代理
disable_proxy()
# 退出程序
os._exit(0)
# 设置关闭按钮的回调函数
app.protocol("WM_DELETE_WINDOW", on_close)
# 在事件循环中创建新的异步任务
loop.create_task(receive_messages())
def update():
# 更新Tkinter的界面
app.update()
# 在事件循环中定期调用update方法
loop.call_soon(update)
# 检查队列中是否有任务
while not gui_queue.empty():
# 获取任务并执行
task = gui_queue.get()
task()
# 在事件循环中定期调用update方法
loop.call_soon(update)
try:
# 运行事件循环
loop.run_forever()
except Exception as e:
print(f"An error occurred in loop: {e}")
finally:
# 关闭事件循环
loop.close()
if __name__ == "__main__":
if is_admin():
# 如果已经是管理员权限,那么直接运行你的代码
print("Running as administrator.")
pass
else:
# 如果不是管理员权限,那么以管理员权限重新启动程序
print("Running as non-administrator.")
ctypes.windll.shell32.ShellExecuteW(
None, "runas", sys.executable, " ".join(sys.argv), None, 1
)
# try:
main()
# except Exception as e:
# print(f"An error occurred: {e}")
# finally:
# # 这里结束进程
# listener_process.terminate()
# 注册一个函数,在程序结束时调用
def on_exit():
listener_process.terminate()
atexit.register(on_exit)
+65 -40
View File
@@ -1,20 +1,30 @@
# 📺 抖音弹幕监听器 <p style="text-align:center;font-size:3rem">📺 抖音弹幕监听器</p>
<p style="text-align:center">- 小白不圆 -</p>
## 🔉前文提要 ## 🔉前文提要
+ Github(受网络影响,更新很可能不及时)大佬请移步 [Gitee](https://gitee.com/haodong108/dy-barrage-grab) ,参与Issues讨论,QQ技术讨论群:<br> + Github(受网络影响,更新很可能不及时)大佬请移步 [Gitee](https://gitee.com/haodong108/dy-barrage-grab) ,参与Issues讨论,QQ技术讨论群:<br>
+ 群1: 819927029 (已满) + 群1: 819927029
+ 群2: 789875441 (新建) + 群2: 789875441 (新建)
+ 注: (进群前请先⭐**Star**,并填入答案,用于排除行外人员,特殊原因请私聊我),之前因满员踢掉的群员可申请群2。 + 注: (进群前请先⭐**Star**,并填入答案,用于排除行外人员,特殊原因请私聊我),之前因满员踢掉的群员可申请群2。
+ <span style="font-size:10px">开不起千人群😅</span>
+ 发行版下载地址在[这里](https://gitee.com/haodong108/dy-barrage-grab/releases),别下成源码包了!!,**决定下载使用前请先仔细阅读文档**,不要进群提问已经介绍到的问题 + 发行版下载地址在[这里](https://gitee.com/haodong108/dy-barrage-grab/releases),别下成源码包了!!,**决定下载使用前请先仔细阅读文档**,不要进群提问已经介绍到的问题
+ 💭 需要**多直播间超长稳定连接**、**自动私信**(支持群组,单发,支持多账号切换),**私信监听**、**自动关注**、**关注,粉丝群,作品点赞,评论监听**、**直播间发弹幕**、**获取榜单**、**直播间,用户主页信息**、**采集商品上架,连麦,PK等其他所有消息**、**作品评论(支持图片)**、 等功能的可以找我(QQ 1083092844)提供一些技术支持 (注:主要面向个人直播自动化,不面向恶意j流,不支持匿名直播间,想搞采集匿名的勿扰,加群也不会有人支持) + 💭 需要抖音日常操作协议化,包括**多直播间超长稳定连接**、**自动私信**(支持群组,单发,支持多账号切换),**私信监听、自动关注、粉丝群、作品点赞评论及监听、直播间发弹幕、获取直播间榜单、直播间更多消息事件、作品评论(支持图片)、发布作品** 等等功能的可以找我(Q1083092844)提供一些技术支持 (注:主要面向个人直播自动化,不面向恶意j流、水jun等,不支持匿名直播间,想搞他人直播间匿名采集的勿扰,加群也不会有人支持)
+ **LiveIdea** 支持dou音Web全自动化的本地WebApi服务。直播、引留解放双手,需要了解详情请加我 + 支持接单、定制等,dy相关优先,其他方面也可以找我帮忙转发定制
+ 支持接单,个人定制,dy相关优先,其他方面也可以找我帮忙转发定制,匿名直播间需求勿扰 + 如果好用,请<a href="#user-content-支持一下">捐赠</a>个仨瓜俩枣,白某谢过各位老板
+ 那年,我与TA不可告人的<a href="#user-content-支持一下">秘密</a>😏
## ⛳近期更新 ## ⛳近期更新
2024-09-28 v2.7.6
1. **[重要更新]** 支持免系统代理监听直播伴侣,需要在配置文件关闭`useproxy`选项,配置后监听web直播间可参考<a href="#user-content-实践指南">实践指南</a>新部分
2. 修复了 挂机检测Js拦截逻辑
3. 默认关闭 禁用JS文件缓存 配置项,提高网页加载速度
4. 礼物计数相关代码有一小处调整
5. 整合了dll为单个exe文件
2024-05-16 v2.7.5 2024-05-16 v2.7.5
1. **[重要修复]** 修复了弹幕轮询响应解析Payload读取报错的问题 1. **[重要修复]** 修复了弹幕轮询响应解析Payload读取报错的问题
@@ -55,23 +65,6 @@
3. 支持了控制台隐藏,推送器弹幕类型过滤,日志弹幕类型过滤,弹幕文件日志 (见<a href="#tag1">配置文件</a>) 3. 支持了控制台隐藏,推送器弹幕类型过滤,日志弹幕类型过滤,弹幕文件日志 (见<a href="#tag1">配置文件</a>)
4. 支持了更多的ws命令,见 [Command.cs](./BarrageGrab/Modles/JsonEntity/Command.cs) 4. 支持了更多的ws命令,见 [Command.cs](./BarrageGrab/Modles/JsonEntity/Command.cs)
2023-11-04 v2.6.9
1. 修复了因抖音版本升级导致的WebRoomId获取不到的问题,并做了多重处理
2023-09-24 v2.6.8
1. 添加了上游代理支持,现在可以将无关的请求转发到其他的代理地址!详见下方配置说明`upstreamProxy`
2. 内部添加了webRoomid 的缓存映射,只要打开直播间地址即可缓存WebRoomId和Roomid的映射关系,`WebRoomId`现已添加至ws弹幕流数据中!,需要注意直播伴侣端提取的弹幕当前不会有该字段,除非在开播后打开浏览器访问一次你的直播间
3. MsgPack 现在添加了进程名字段`ProcessName`
2023-08-17 v2.6.7
1. [重要更新] 支持浏览器/客户端 http 弹幕监听,这也会解决原先版本因网络波动使抖音客户端弹幕获取方式降级,而获取不到弹幕导致必须刷新页面重新连接的问题。
2. [重要更新] 原先的web/客户端 页面无操作检测逻辑因官方js变动而失效,本次更新修复且完善了该功能,现在会定时模拟全局按键、绕过js检测逻辑、置空Websocket.close 方法三重手段尽量避免断开连接。你也可以直接修改[直播页脚本](./BarrageGrab/Scripts/inject/livePage.js)而无需重新编译源码。
3. ws连接现在默认监听在0.0.0.0地址,可以从其他客户端连接。
4. 代理端口现在可选择不占用系统代理,便于某些用户直接使用浏览器代理获取弹幕(启动时携带参数,例如:"chrome.exe --proxy-server=127.0.0.1:8827",也可以在浏览器快捷方式-目标 引号之后附加该参数)
## 🖼️控制台截图 ## 🖼️控制台截图
[![控制台截图](https://s1.ax1x.com/2022/11/10/z9YYPU.png)](https://imgse.com/i/z9YYPU) [![控制台截图](https://s1.ax1x.com/2022/11/10/z9YYPU.png)](https://imgse.com/i/z9YYPU)
@@ -98,6 +91,8 @@
<add key="listenAny" value="true" /> <add key="listenAny" value="true" />
<!--系统代理端口--> <!--系统代理端口-->
<add key="proxyPort" value="8827" /> <add key="proxyPort" value="8827" />
<!--是否启用系统代理,若设置为false 则需要在程序手动指定代理地址 -->
<add key="usedProxy" value="true" />
<!--上游代理地址,例如开启了系统代理,但是需要将其他无关请求转发到VPN工具中,例如:127.0.0.1:11223,不要带http://--> <!--上游代理地址,例如开启了系统代理,但是需要将其他无关请求转发到VPN工具中,例如:127.0.0.1:11223,不要带http://-->
<add key="upstreamProxy" value="" /> <add key="upstreamProxy" value="" />
<!--在控制台输出弹幕--> <!--在控制台输出弹幕-->
@@ -110,8 +105,6 @@
<add key="logFilter" value="1,2,4,5,6,7,8" /> <add key="logFilter" value="1,2,4,5,6,7,8" />
<!--要进行过滤的Web房间ID,多个使用','分隔,根据缓存来过滤的,直播伴侣不支持 --> <!--要进行过滤的Web房间ID,多个使用','分隔,根据缓存来过滤的,直播伴侣不支持 -->
<add key="webRoomIds" value="940152769375" /> <add key="webRoomIds" value="940152769375" />
<!--是否启用系统代理,若设置为false 则需要在程序手动指定代理地址 -->
<add key="usedProxy" value="true" />
<!--开启内置的域名过滤,设置为false会解包所有https请求,cpu占用很高,建议在无法获取弹幕数据时调整 --> <!--开启内置的域名过滤,设置为false会解包所有https请求,cpu占用很高,建议在无法获取弹幕数据时调整 -->
<add key="filterHostName" value="true" /> <add key="filterHostName" value="true" />
<!--已知的弹幕域名列表 ','分隔 用作过滤规则中,凡是webcast开头的域名程序都会自动列入白名单--> <!--已知的弹幕域名列表 ','分隔 用作过滤规则中,凡是webcast开头的域名程序都会自动列入白名单-->
@@ -134,19 +127,20 @@
<add key="comPort" value="" /> <add key="comPort" value="" />
<!--启用自定义消息过滤,启用后可去程序根目录 Scripts/engine/comPortFilter.js 调整过滤规则 --> <!--启用自定义消息过滤,启用后可去程序根目录 Scripts/engine/comPortFilter.js 调整过滤规则 -->
<add key="useComPortFilter" value="true" /> <add key="useComPortFilter" value="true" />
<!--直播伴侣exe文件位置(除非程序找不到,否则请留空)-->
<add key="liveCompanPath" value=""/>
</appSettings> </appSettings>
``` ```
### 推送数据格式
+ 弹幕数据由WebSocket服务进行分发,使用Json格式进行推送,见项目 [BarrageMessages.cs](./BarrageGrab/Modles/JsonEntity/BarrageMessages.cs),如需调整请克隆项目后参照 [message.proto](./BarrageGrab/proto/message.proto) 进行源码修改调整,文件包含所有弹幕相关数据结构,可前往[ws在线测试](http://wstool.jackxiang.com/)网站,连接 ws://127.0.0.1:8888 进行测试
### 使用方法 ### 使用方法
1. 管理员身份启动本程序,第一次启动会提示安装自签名证书,程序启动后挂在后台不要关,不然再打开会监听不到正在进行中的直播弹幕。 1. 管理员身份启动本程序,第一次启动会提示安装自签名证书,程序启动后挂在后台不要关,程序无法中途监听已经建立连接的弹幕流
2. 打开浏览器进入任何直播间进行测试,没有问题再启动直播伴侣 2. 打开浏览器进入任何直播间,然后观察程序控制台中是否有弹幕滚动
3. 如果需要对接自己的应用程序,请先了解 [WebSocket](https://www.bilibili.com/video/BV1KN411n7WD/?share_source=copy_web&vd_source=39ebf42c923024b9eddeca32c9e46d16) ,然后进行对接,可前往[这里](http://wstool.jackxiang.com/)测试 3. 如果有请往下看,否则请参考诊断排查
4. 启动后程序控制台标题会显示 ws连接地址,如果需要对接自己的应用程序,请先了解 [WebSocket](https://www.bilibili.com/video/BV1KN411n7WD/?share_source=copy_web&vd_source=39ebf42c923024b9eddeca32c9e46d16) ,然后使用自己的程序进行对接,可前往[在线测试网站](http://wstool.jackxiang.com/)进行连接测试
5. 对于字段不理解,请参考 [实体类源码文件](./BarrageGrab/Modles/JsonEntity/BarrageMessages.cs) 的注释,或者加群询问
<a id="user-content-串口转发"></a>
<a id="user-content-串口转发"></a>
## 🔌 串口转发</i> ## 🔌 串口转发</i>
+ 配置串口:见<a href="#tag1">配置文件</a>`comPort`,配置发送串口以及波特率,不填则不启用 + 配置串口:见<a href="#tag1">配置文件</a>`comPort`,配置发送串口以及波特率,不填则不启用
+ 串口报文自定义:可在根目录`Scripts/engine/comPortFilter.js` 根据自己的需求配置转发报文,提供了一定的Bit转换函数,详见其注释 + 串口报文自定义:可在根目录`Scripts/engine/comPortFilter.js` 根据自己的需求配置转发报文,提供了一定的Bit转换函数,详见其注释
@@ -177,29 +171,59 @@
+ **弹幕断连** + **弹幕断连**
+ 如果浏览器总是连接一段时间后,就在在控制台看不到弹幕了,优先使用Chrome 和 Edge 浏览器,其他浏览器(例如360浏览器) 可能会存在该问题 + 如果浏览器总是连接一段时间后,就在在控制台看不到弹幕了,优先使用Chrome 和 Edge 浏览器,其他浏览器(例如360浏览器) 可能会存在该问题
+ 尝试打开配置文件 `forcePolling` 选项,情况获取会有所改善 + 尝试打开配置文件 `forcePolling` 选项,情况获取会有所改善
+ 其他可能是网络原因,或者直播间断连导致,正在想办法优化解决中。。。需要长时间连接可以找我使用其他方式,支持直连和轮询获取方式 + 其他可能是网络原因,或者直播间断连导致,正在想办法优化解决中。。。需要长时间连接可以找我使用其他方式,支持直连和轮询获取方式
+ **程序关闭后无法上网** + **程序关闭后无法上网**
+ 这是因为本程序运行时会占用系统代理,不正确的关闭方式可能会导致系统代理未能正确关闭,请前往找到 系统设置-网络和Internet-代理-使用代理服务器 并关闭它即可,也可管理员运行[关闭代理.bat](./关闭代理.bat) + 这是因为本程序运行时会占用系统代理,不正确的关闭方式可能会导致系统代理未能正确关闭,请前往找到 系统设置-网络和Internet-代理-使用代理服务器 并关闭它即可,也可管理员运行[关闭代理.bat](./关闭代理.bat)
+ **未开系统代理,但是无法监听到直播伴侣弹幕**
+ 之前可以突然不行,且刚刚升级直播伴侣,请重监听启程序和直播伴侣再次尝试
+ 如果一次都没成功,则需要检查启动菜单是否有直播伴侣的快捷方式,换言之则必须确保 `C:\ProgramData\Microsoft\Windows\Start Menu\Programs\直播伴侣.lnk` 文件存在,否则请前往配置文件显式指定`直播伴侣.exe`文件存储路径,见配置项`liveCompanPath`
<a id="user-content-实践指南"></a>
## 🎲 实践指南 ## 🎲 实践指南
### 日常使用
+ **隐藏控制台**:见配置文件 `hideConsole`<br><br> + **隐藏控制台**:见配置文件 `hideConsole`<br><br>
+ **远程控制程序**:例如远程关闭,隐藏/显示控制台,启用/关闭系统代理,可发送Json数据包 `{"Cmd":xx,"Data":xx}` 到ws推送地址,数据格式详见: [Command.cs](./BarrageGrab/Modles/JsonEntity/Command.cs)<br><br> + **远程控制程序**:例如远程关闭,隐藏/显示控制台,启用/关闭系统代理,可发送Json数据包 `{"Cmd":xx,"Data":xx}` 到ws推送地址,数据格式详见: [Command.cs](./BarrageGrab/Modles/JsonEntity/Command.cs)<br><br>
+ **启用弹幕文件日志**:见配置文件 `barrageFileLog`,启用后,抓到弹幕会记录在根目录 logs/弹幕日志 文件夹中,支持类型过滤,见`logFilter` 配置项<br><br> + **启用弹幕文件日志**:见配置文件 `barrageFileLog`,启用后,抓到弹幕会记录在根目录 logs/弹幕日志 文件夹中,支持类型过滤,见`logFilter` 配置项<br><br>
+ **UI界面**: 见配置文件 `showWindow ` (做的仓促,功能简陋)<br><br> + **UI界面**: 见配置文件 `showWindow ` (做的仓促,功能简陋)<br><br>
+ **上游代理**:一般用于自己有 代理工具/代理服务器,希望在使用本程序时访问外网不受到影响,见配置文件项`upstreamProxy` 将它改为你代理工具的代理地址<br><br> + **上游代理**:一般用于自己有 代理工具/代理服务器,希望在使用本程序时访问外网不受到影响,见配置文件项`upstreamProxy` 将它改为你代理工具的代理地址<br><br>
+ **局域代理**: 若是只需要监听了浏览器,且不想占用系统代理,可创建一个浏览器快捷方式,打开属性,并在exe文件路径后附加启动参数,`--proxy-server=127.0.0.1:8827`,例如:`"C:\\xxx\chrome.exe" --proxy-server=127.0.0.1:8827`<br><br> + **局域代理**: (请优先参考下文 **浏览器代理切换扩展**) 可创建一个浏览器快捷方式,打开属性,并在exe文件路径后附加启动参数,`--proxy-server=127.0.0.1:8827`,例如:`"C:\\xxx\chrome.exe" --proxy-server=127.0.0.1:8827`<br><br>
+ **直播间区分**: 推送包含 `Onwer`字段,用户描述主播基本信息,客户端可以优先使用其中的`SecUid`或者`Uid`作为直播间标识,若使用`WebRoomid`则需要注意直播伴侣进程需要特殊处理,因为直播伴侣推送的WebRoomid是用户的抖音号。`RoomId`只能作为场次标识,每次开播都会不一样,不可用作直播间唯一区分<br><br> + **直播间区分**: 推送包含 `Onwer`字段,用户描述主播基本信息,客户端可以优先使用其中的`SecUid`或者`Uid`作为直播间标识,若使用`WebRoomid`则需要注意直播伴侣进程需要特殊处理,因为直播伴侣推送的WebRoomid是用户的抖音号。`RoomId`只能作为场次标识,每次开播都会不一样,不可用作直播间唯一区分<br><br>
+ **直播间地址**: 冷知识,使用`https://live.douyin.com/<抖音号>` 也可以进入主播直播间 + **直播间地址**: 冷知识,使用`https://live.douyin.com/<抖音号>` 也可以进入主播直播间
### 浏览器代理切换扩展
若关闭了`usedProxy`开关,浏览器需要通过显示指定代理地址完成代理指向操作,此时可以通过浏览器扩展很好的完成这项功能,以Edge为例
1. 前往扩展商店 搜索 `switchyomega` 安装
[<img src="https://s21.ax1x.com/2024/09/28/pA1SSSg.png" alt="pA1SSSg.png" style="zoom: 50%;" />](https://imgse.com/i/pA1SSSg)
2. 添加弹幕代理
[<img src="https://s21.ax1x.com/2024/09/28/pA1SCOs.png" alt="pA1SCOs.png" style="zoom:50%;" />](https://imgse.com/i/pA1SCOs)
3. 配置代理地址,并保存,不要配置为ws服务端口地址,程序默认代理端口是**8827**
[<img src="https://s21.ax1x.com/2024/09/28/pA1SLjJ.png" alt="pA1SLjJ.png" style="zoom:50%;" />](https://imgse.com/i/pA1SLjJ)
4. 进入直播页,应用代理,完成!
[<img src="https://s21.ax1x.com/2024/09/28/pA1SXu9.png" alt="pA1SXu9.png" style="zoom:50%;" />](https://imgse.com/i/pA1SXu9)
5. Chrome 用户请自行百度搜索扩展安装方法
## ⚠️特别注意 ## ⚠️特别注意
@@ -227,8 +251,9 @@
+ 请详细阅读[免责声明](./免责声明.txt)条款后进行使用 + 请详细阅读[免责声明](./免责声明.txt)条款后进行使用
<a id="user-content-支持一下" class="anchor"></a> <a id="user-content-支持一下" class="anchor"></a>
## 🍻支持一下? ## 🍻支持一下?
开源不易啊老板 开源不易,老板
<p> <p>
<img src="./imgs/微信.png" alt="微信支付" style="zoom:70%;border-radius: 5px;" /> <img src="./imgs/微信.png" alt="微信支付" style="zoom:70%;border-radius: 5px;" />
</p> </p>