diff --git a/BarrageGrab/App.config b/BarrageGrab/App.config index c096faf..e119cab 100644 --- a/BarrageGrab/App.config +++ b/BarrageGrab/App.config @@ -1,4 +1,4 @@ - + @@ -20,8 +20,8 @@ - - + + @@ -34,14 +34,18 @@ - - - - - - - - + + + + + + + + + + + + diff --git a/BarrageGrab/AppRuntime.cs b/BarrageGrab/AppRuntime.cs index 7e813f3..b949d2d 100644 --- a/BarrageGrab/AppRuntime.cs +++ b/BarrageGrab/AppRuntime.cs @@ -18,24 +18,35 @@ namespace BarrageGrab /// /// Ws弹幕服务示例 /// - public static WsBarrageService WssService { get; private set; } = new WsBarrageService(); + public static WsBarrageServer WsServer { get; private set; } /// /// 房间缓存信息 /// - public static RoomCacheManager RoomCaches { get; } = new RoomCacheManager(); + public static RoomCacheManager RoomCaches { get; private set; } + + /// + /// 串口服务 + /// + public static ComPortServer ComPortServer { get; private set; } /// /// 程序进程信息 /// public static Process CurrentProcess { get; private set; } = System.Diagnostics.Process.GetCurrentProcess(); - static AppRuntime() { } + public static void Init() + { + WsServer = new WsBarrageServer(); + RoomCaches = new RoomCacheManager(); + ComPortServer = new ComPortServer(WsServer); + } + /// /// 隐藏/显示 控制台 /// @@ -50,16 +61,6 @@ namespace BarrageGrab } } - public static void DisplayConsoleByTitle(bool show) - { - var hWnd = WinApi.FindWindow(null, Console.Title); - //var hWnd = WinApi.GetConsoleWindow(); - if (hWnd != IntPtr.Zero) - { - WinApi.ShowWindow(hWnd, show ? WinApi.CmdShow.SW_SHOW : WinApi.CmdShow.SW_HIDE); - } - } - /// /// 房间缓存管理器 /// diff --git a/BarrageGrab/Appsetting.cs b/BarrageGrab/AppSetting.cs similarity index 74% rename from BarrageGrab/Appsetting.cs rename to BarrageGrab/AppSetting.cs index 9890e5c..b5543e6 100644 --- a/BarrageGrab/Appsetting.cs +++ b/BarrageGrab/AppSetting.cs @@ -10,13 +10,13 @@ using System.Drawing; namespace BarrageGrab { - internal class Appsetting + internal class AppSetting { - private static readonly Appsetting ins = new Appsetting(); + private static readonly AppSetting ins = new AppSetting(); - public static Appsetting Current { get { return ins; } } + public static AppSetting Current { get { return ins; } } - public Appsetting() + public AppSetting() { try { @@ -24,7 +24,7 @@ namespace BarrageGrab WsProt = int.Parse(AppSettings["wsListenPort"]); PrintBarrage = AppSettings["printBarrage"].ToLower() == "true"; ProxyPort = int.Parse(AppSettings["proxyPort"]); - PrintFilter = Enum.GetValues(typeof(PackMsgType)).Cast().Where(w=>w>0).ToArray(); + PrintFilter = Enum.GetValues(typeof(PackMsgType)).Cast().Where(w => w > 0).ToArray(); PushFilter = Enum.GetValues(typeof(PackMsgType)).Cast().Where(w => w > 0).ToArray(); LogFilter = Enum.GetValues(typeof(PackMsgType)).Cast().Where(w => w > 0).ToArray(); FilterHostName = bool.Parse(AppSettings["filterHostName"].Trim()); @@ -39,26 +39,10 @@ namespace BarrageGrab ForcePolling = bool.Parse(AppSettings["forcePolling"].Trim()); PollingInterval = int.Parse(AppSettings["pollingInterval"].Trim()); DisableLivePageScriptCache = bool.Parse(AppSettings["disableLivePageScriptCache"].Trim()); - WebRoomIds = AppSettings["webRoomIds"].Trim().Split(',').Where(w=>!string.IsNullOrWhiteSpace(w)).Select(x => long.Parse(x)).ToArray(); + WebRoomIds = AppSettings["webRoomIds"].Trim().Split(',').Where(w => !string.IsNullOrWhiteSpace(w)).Select(x => long.Parse(x)).ToArray(); - var printFilter = AppSettings["printFilter"].Trim().ToLower(); - var pushFilter = AppSettings["pushFilter"].Trim().ToLower(); - var logFilter = AppSettings["logFilter"].Trim().ToLower(); - if (!string.IsNullOrWhiteSpace(printFilter)) - { - if (string.IsNullOrWhiteSpace(printFilter)) PrintFilter = new int[0]; - else PrintFilter = printFilter.Split(',').Select(x => int.Parse(x)).ToArray(); - } - if (!string.IsNullOrWhiteSpace(pushFilter)) - { - if (string.IsNullOrWhiteSpace(pushFilter)) PushFilter = new int[0]; - else PushFilter = pushFilter.Split(',').Select(x => int.Parse(x)).ToArray(); - } - if (!string.IsNullOrWhiteSpace(logFilter)) - { - if (string.IsNullOrWhiteSpace(logFilter)) LogFilter = new int[0]; - else LogFilter = logFilter.Split(',').Select(x => int.Parse(x)).ToArray(); - } + ConfigComPort(); + ConfigFilter(); } catch (Exception ex) { @@ -67,11 +51,55 @@ namespace BarrageGrab } } + + //com串口设置 + private void ConfigComPort() + { + var comPort = AppSettings["comPort"]; + if (!comPort.IsNullOrWhiteSpace()) + { + try + { + var spit = comPort.Split(':'); + ComPort = spit[0].Trim(); + ComBaudRate = int.Parse(spit[1].Trim()); + UseComPortFilter = bool.Parse(AppSettings["useComPortFilter"]); + } + catch (Exception ex) + { + throw new Exception("串口配置格式错误," + ex.Message, ex); + } + } + } + + //各种过滤器设置 + private void ConfigFilter() + { + var printFilter = AppSettings["printFilter"].Trim().ToLower(); + var pushFilter = AppSettings["pushFilter"].Trim().ToLower(); + var logFilter = AppSettings["logFilter"].Trim().ToLower(); + if (!string.IsNullOrWhiteSpace(printFilter)) + { + if (string.IsNullOrWhiteSpace(printFilter)) PrintFilter = new int[0]; + else PrintFilter = printFilter.Split(',').Select(x => int.Parse(x)).ToArray(); + } + if (!string.IsNullOrWhiteSpace(pushFilter)) + { + if (string.IsNullOrWhiteSpace(pushFilter)) PushFilter = new int[0]; + else PushFilter = pushFilter.Split(',').Select(x => int.Parse(x)).ToArray(); + } + if (!string.IsNullOrWhiteSpace(logFilter)) + { + if (string.IsNullOrWhiteSpace(logFilter)) LogFilter = new int[0]; + else LogFilter = logFilter.Split(',').Select(x => int.Parse(x)).ToArray(); + } + } + public void Save() { Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); - - config.AppSettings.Settings["wsListenPort"].Value = WsProt.ToString(); + + config.AppSettings.Settings["wsListenPort"].Value = WsProt.ToString(); config.AppSettings.Settings["printBarrage"].Value = PrintBarrage.ToString().ToLower(); config.AppSettings.Settings["printFilter"].Value = string.Join("", PrintFilter); config.AppSettings.Settings["pushFilter"].Value = string.Join("", PushFilter); @@ -80,7 +108,7 @@ namespace BarrageGrab config.AppSettings.Settings["listenAny"].Value = ListenAny.ToString().ToLower(); config.AppSettings.Settings["hideConsole"].Value = HideConsole.ToString().ToLower(); config.AppSettings.Settings["barrageFileLog"].Value = HideConsole.ToString().ToLower(); - + config.Save(ConfigurationSaveMode.Modified); ConfigurationManager.RefreshSection(config.AppSettings.SectionInformation.Name); } @@ -200,5 +228,20 @@ namespace BarrageGrab /// 禁用直播页面脚本缓存 /// public bool DisableLivePageScriptCache { get; private set; } = true; + + /// + /// 配置的串口 + /// + public string ComPort { get; set; } = string.Empty; + + /// + /// 波特率 + /// + public int ComBaudRate { get; set; } = 9600; + + /// + /// 是否启用串口过滤器脚本 + /// + public bool UseComPortFilter { get; set; } } } diff --git a/BarrageGrab/ComPortServer.cs b/BarrageGrab/ComPortServer.cs new file mode 100644 index 0000000..bbdda9a --- /dev/null +++ b/BarrageGrab/ComPortServer.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO.Ports; +using Jint; +using Jint.Runtime; +using System.Windows.Forms; + +namespace BarrageGrab +{ + public class ComPortServer : IDisposable + { + WsBarrageServer server; + SerialPort sendPort; + static Engine jsEngine = null; + + static ComPortServer() + { + if (AppSetting.Current.UseComPortFilter) + { + jsEngine = JsEngine.CreateNewEngine(); + var jsFile = JsEngine.GetJsFile("comPortFilter.js"); + jsEngine.Execute(jsFile); + } + } + + public ComPortServer(WsBarrageServer server) + { + string portName = AppSetting.Current.ComPort; + int baudRate = AppSetting.Current.ComBaudRate; + if (portName.IsNullOrWhiteSpace()) + { + return; + //throw new ArgumentNullException(nameof(portName)); + } + this.server = server; + server.OnPackMessage += Server_OnPackMessage; + server.OnClose += Server_OnClose; + sendPort = new SerialPort(portName, baudRate); + } + + private void Server_OnClose(object sender, EventArgs e) + { + this.Dispose(); + } + + private void Server_OnPackMessage(WsBarrageServer sender, WsBarrageServer.PackMsgEventArgs e) + { + if (!sendPort.IsOpen) return; + if (e == null) return; + if (!AppSetting.Current.UseComPortFilter) + { + var json = e.ToJson() + "\r\n"; + var jbuff = Encoding.UTF8.GetBytes(json); + Send(jbuff); + return; + } + var result = jsEngine.Invoke("onPackData", e.MsgType.GetHashCode(), e.Message); + var nocanTypes = new Types[] + { + Types.Null, + Types.Undefined, + Types.Empty, + Types.Symbol + }; + if (nocanTypes.Contains(result.Type)) return; + Func encode = (str) => Encoding.UTF8.GetBytes(str); + + byte[] buff = new byte[0]; + switch (result.Type) + { + case Types.Boolean: + buff = encode(result.AsBoolean().ToString().ToLower()); + break; + case Types.String: + buff = encode(result.AsString()); + break; + case Types.BigInt: + case Types.Number: + buff = BitConverter.GetBytes(result.AsNumber()); + break; + case Types.Object: + if (result.ToObject() is byte[]) + { + buff = result.AsArrayBuffer(); + } + break; + default: + break; + } + + if (buff.Length == 0) return; + Send(buff); + } + + //发送数据包 + private void Send(byte[] buff) + { + lock (this.sendPort) + { + sendPort.Write(buff, 0, buff.Length); + } + } + + /// + /// 打开串口并开始接收写入数据 + /// + public void OpenStart() + { + if (sendPort == null) throw new Exception("未成功初始化串口对象,请检查配置文件"); + try + { + sendPort.Open(); + } + catch (Exception ex) + { + sendPort.Close(); + sendPort.Dispose(); + sendPort = null; + throw ex; + } + } + + + public void Dispose() + { + if (sendPort == null) return; + sendPort.Close(); + sendPort.Dispose(); + sendPort = null; + jsEngine.Dispose(); + } + } +} diff --git a/BarrageGrab/Forms/FormView.cs b/BarrageGrab/Forms/FormView.cs index e743aac..b322e6b 100644 --- a/BarrageGrab/Forms/FormView.cs +++ b/BarrageGrab/Forms/FormView.cs @@ -20,9 +20,9 @@ namespace BarrageGrab { static int printCount = 0; - WsBarrageService barServer = AppRuntime.WssService; - WssBarrageGrab grab = AppRuntime.WssService.Grab; - ISystemProxy proxy = AppRuntime.WssService.Grab.Proxy; + WsBarrageServer barServer = AppRuntime.WsServer; + WssBarrageGrab grab = AppRuntime.WsServer.Grab; + ISystemProxy proxy = AppRuntime.WsServer.Grab.Proxy; public FormView() { @@ -32,7 +32,7 @@ namespace BarrageGrab AppRuntime.RoomCaches.OnCache += RoomCaches_OnCache; this.txb_wsaddr.Text = barServer.ServerLocation; this.txb_upstreamProxy.Text = proxy.HttpUpstreamProxy; - this.cbx_barrageLog.Checked = Appsetting.Current.BarrageLog; + this.cbx_barrageLog.Checked = AppSetting.Current.BarrageLog; InitTabPages(); } @@ -67,17 +67,17 @@ namespace BarrageGrab if (page == this.tabPage_Ws) { type = "ws"; - ck.Checked = Appsetting.Current.PushFilter.Contains(label.Key); + ck.Checked = AppSetting.Current.PushFilter.Contains(label.Key); } if (page == this.tabPage_Console) { type = "console"; - ck.Checked = Appsetting.Current.PrintFilter.Contains(label.Key); + ck.Checked = AppSetting.Current.PrintFilter.Contains(label.Key); } if (page == this.tabPage_Log) { type = "log"; - ck.Checked = Appsetting.Current.LogFilter.Contains(label.Key); + ck.Checked = AppSetting.Current.LogFilter.Contains(label.Key); } ck.Name = $"cbx_bartype_{type}_{label.Key}"; ck.CheckedChanged += Ck_CheckedChanged; @@ -94,17 +94,17 @@ namespace BarrageGrab var selected = GetCheckedBarTypes((FlowLayoutPanel)cbx.Parent); if (cbx.Parent.Parent == this.tabPage_Console) { - Appsetting.Current.PrintFilter = selected; + AppSetting.Current.PrintFilter = selected; } if (cbx.Parent.Parent == this.tabPage_Ws) { - Appsetting.Current.PushFilter = selected; + AppSetting.Current.PushFilter = selected; } if(cbx.Parent.Parent == this.tabPage_Log) { - Appsetting.Current.LogFilter = selected; + AppSetting.Current.LogFilter = selected; } - Appsetting.Current.Save(); + AppSetting.Current.Save(); } private int[] GetCheckedBarTypes(FlowLayoutPanel panel) @@ -167,11 +167,11 @@ namespace BarrageGrab })); } - private void WssService_OnPrint(object sender, WsBarrageService.PrintEventArgs e) + private void WssService_OnPrint(object sender, WsBarrageServer.PrintEventArgs e) { //将弹幕输出到richTextBox //颜色转换 - Color color = Appsetting.Current.ColorMap[e.MsgType].Item2; + Color color = AppSetting.Current.ColorMap[e.MsgType].Item2; string msg = e.Message; this.Invoke(new Action(() => @@ -218,8 +218,8 @@ namespace BarrageGrab try { proxy.SetUpstreamProxy(text); - Appsetting.Current.UpstreamProxy = text; - Appsetting.Current.Save(); + AppSetting.Current.UpstreamProxy = text; + AppSetting.Current.Save(); } catch (Exception ex) { @@ -231,8 +231,8 @@ namespace BarrageGrab private void cbx_barrageLog_CheckedChanged(object sender, EventArgs e) { var checker = (CheckBox)sender; - Appsetting.Current.BarrageLog = checker.Checked; - Appsetting.Current.Save(); + AppSetting.Current.BarrageLog = checker.Checked; + AppSetting.Current.Save(); } } } diff --git a/BarrageGrab/JsEngine.cs b/BarrageGrab/JsEngine.cs new file mode 100644 index 0000000..05ccd97 --- /dev/null +++ b/BarrageGrab/JsEngine.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using Jint; +using Newtonsoft.Json; +using Jint.Native; + +namespace BarrageGrab +{ + public static class JsEngine + { + public static Engine CreateNewEngine() + { + var jsonParse = new Func((obj) => + { + try + { + return JsonConvert.SerializeObject(JsonConvert.SerializeObject(obj)); + } + catch (Exception ex) + { + Logger.LogError("JS:" + ex.Message); + return null; + } + }); + + var engine = new Engine(); + engine.SetValue("console", new JsConsole()); + engine.SetValue("encoder", new JsEncoder(engine)); + + return engine; + } + + /// + /// 从engine 目录获取js 文件 + /// + /// + /// + public static string GetJsFile(string fileName) + { + var path = Path.Combine(AppContext.BaseDirectory, "Scripts", "engine", fileName); + if (!File.Exists(path)) throw new FileNotFoundException("不存在的文件", path); + return File.ReadAllText(path, Encoding.UTF8); + } + + class JsConsole + { + public void log(object obj) + { + if (obj == null) return; + Logger.PrintColor("JS: " + obj.ToString()); + } + + public void error(object obj) + { + if (obj == null) return; + Logger.LogError("JS: " + obj.ToString()); + } + + public void warn(object obj) + { + if (obj == null) return; + Logger.LogWarn("JS: " + obj.ToString()); + } + } + + class JsEncoder + { + Engine eng; + public JsEncoder(Engine eng) + { + this.eng = eng; + eng.Execute(@" + byteToUint8Array = function(arr){ + return new Uint8Array(arr); + }"); + } + + private JsValue ByteConvert(byte[] buff) + { + return eng.Invoke("byteToUint8Array", buff); + } + + public JsValue utf8ToBytes(string str) + { + byte[] res = new byte[0]; + if (str.IsNullOrWhiteSpace()) + { + res = new byte[0]; + } + else + { + res = Encoding.UTF8.GetBytes(str); + } + return ByteConvert(res); + } + + public JsValue utf32ToBytes(string str) + { + byte[] res = new byte[0]; + if (str.IsNullOrWhiteSpace()) + { + res = new byte[0]; + } + else + { + res = Encoding.UTF32.GetBytes(str); + } + return ByteConvert(res); + } + + public JsValue asciiToBytes(string str) + { + byte[] res = new byte[0]; + if (str.IsNullOrWhiteSpace()) + { + res = new byte[0]; + } + else + { + res = Encoding.ASCII.GetBytes(str); + } + return ByteConvert(res); + } + + public string utf8ToString(byte[] bytes) + { + if (bytes == null) return null; + return Encoding.UTF8.GetString(bytes); + } + + public string utf32ToString(byte[] bytes) + { + if (bytes == null) return null; + return Encoding.UTF32.GetString(bytes); + } + + public string asciiToString(byte[] bytes) + { + if (bytes == null) return null; + return Encoding.ASCII.GetString(bytes); + } + } + } +} diff --git a/BarrageGrab/Logger.cs b/BarrageGrab/Logger.cs index 32cd6bc..507e082 100644 --- a/BarrageGrab/Logger.cs +++ b/BarrageGrab/Logger.cs @@ -94,9 +94,9 @@ namespace BarrageGrab /// 弹幕内容 public static void LogBarrage(PackMsgType type, Msg msg) { - if (!Appsetting.Current.BarrageLog) return; + if (!AppSetting.Current.BarrageLog) return; if (type == PackMsgType.无) return; - if (Appsetting.Current.LogFilter.Any() && !Appsetting.Current.LogFilter.Contains(type.GetHashCode())) return; + if (AppSetting.Current.LogFilter.Any() && !AppSetting.Current.LogFilter.Contains(type.GetHashCode())) return; try { @@ -135,7 +135,7 @@ namespace BarrageGrab text += $" [{msg.User?.GenderToString()}] "; } - ConsoleColor color = Appsetting.Current.ColorMap[barType].Item1; + ConsoleColor color = AppSetting.Current.ColorMap[barType].Item1; var append = msg.Content; switch (barType) { diff --git a/BarrageGrab/Program.cs b/BarrageGrab/Program.cs index ba9e358..2ecb8e0 100644 --- a/BarrageGrab/Program.cs +++ b/BarrageGrab/Program.cs @@ -6,43 +6,78 @@ using System.Net; using System.Runtime.InteropServices; using System.Text; using System.Threading; +using System.IO; +using Jint.Runtime; +using System.Windows.Forms; namespace BarrageGrab { public class Program { + static FormView mainForm = null; + static bool exited = false; + static bool formExited = false; + static WinApi.ControlCtrlDelegate controlCtr = ControlCtrlHandle; + static void Main(string[] args) { + //JintTest(); + //Console.WriteLine("结束"); + //Console.ReadKey(); + //return; if (CheckAlreadyRunning()) { Logger.PrintColor("已经有一个监听程序在运行,按任意键退出..."); Console.ReadKey(); return; } + SetTitle("抖音弹幕监听推送"); - WinApi.SetConsoleCtrlHandler(cancelHandler, true);//捕获控制台关闭 + try + { + Init(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "程序初始化错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + exited = true; + } + + while (!exited) + { + Thread.Sleep(500); + } + + if (!AppRuntime.WsServer.IsDisposed) + { + AppRuntime.WsServer.Dispose(); + } + + Logger.PrintColor("服务器已关闭..."); + WinApi.SetConsoleCtrlHandler(controlCtr, false);//反注册捕获控制台关闭 + + } + + private static void Init() + { + AppRuntime.Init(); + WinApi.SetConsoleCtrlHandler(controlCtr, true);//捕获控制台关闭 WinApi.DisableQuickEditMode();//禁用控制台快速编辑模式 - if (WinApi.GetConsoleWindow() != IntPtr.Zero) + AppRuntime.DisplayConsole(!AppSetting.Current.HideConsole);//控制控制台可见 + AppRuntime.WsServer.Grab.Proxy.SetUpstreamProxy(AppSetting.Current.UpstreamProxy);//设置上游代理 + AppRuntime.WsServer.OnClose += (s, e) => { - Console.Title = "抖音弹幕监听推送"; - } - AppRuntime.DisplayConsole(!Appsetting.Current.HideConsole); - AppRuntime.WssService.Grab.Proxy.SetUpstreamProxy(Appsetting.Current.UpstreamProxy); + exited = true; + }; - bool exited = false; - bool formExited = false; - AppRuntime.WssService.StartListen(); - - Console.ForegroundColor = ConsoleColor.Green; - Logger.LogSucc($"{AppRuntime.WssService.ServerLocation} 弹幕服务已启动..."); - Console.ForegroundColor = ConsoleColor.Gray; - if (WinApi.GetConsoleWindow() != IntPtr.Zero) + //串口写入服务 + if (!AppSetting.Current.ComPort.IsNullOrWhiteSpace()) { - Console.Title = $"抖音弹幕监听推送 [{AppRuntime.WssService.ServerLocation}]"; + AppRuntime.ComPortServer.OpenStart(); } - FormView mainForm = null; - if (Appsetting.Current.ShowWindow) + //显示窗体 + if (AppSetting.Current.ShowWindow) { var uiThread = new Thread(new ThreadStart(() => { @@ -50,42 +85,29 @@ namespace BarrageGrab //开启消息循环 System.Windows.Forms.Application.Run(mainForm); formExited = true; + AppRuntime.WsServer.Dispose();//Close后自动释放资源 })); uiThread.SetApartmentState(ApartmentState.STA); uiThread.IsBackground = true; uiThread.Start(); } - AppRuntime.WssService.OnClose += (s, e) => - { - //退出程序 - exited = true; - }; - - while (!exited) - { - if (formExited && !exited) - { - AppRuntime.WssService.Close(); - } - Thread.Sleep(500); - } - - Logger.PrintColor("服务器已关闭..."); - - //if (!mainForm.IsDisposed) - //{ - // mainForm.Invoke(new Action(() => - // { - // mainForm.Close(); - // })); - //} - - //退出程序,不显示 按任意键退出 - //Environment.Exit(0); + AppRuntime.WsServer.StartListen();//启动WS以及代理服务 + Logger.LogSucc($"{AppRuntime.WsServer.ServerLocation} 弹幕服务已启动..."); + SetTitle($"抖音弹幕监听推送 [{AppRuntime.WsServer.ServerLocation}]"); } - private static WinApi.ControlCtrlDelegate cancelHandler = new WinApi.ControlCtrlDelegate((CtrlType) => + //检测设置控制台标题 + private static void SetTitle(string title) + { + if (WinApi.GetConsoleWindow() != IntPtr.Zero) + { + Console.Title = title; + } + } + + //监听控制台消息事件 + private static bool ControlCtrlHandle(int CtrlType) { switch (CtrlType) { @@ -95,11 +117,11 @@ namespace BarrageGrab break; case 2: Logger.PrintColor("2工具被强制关闭");//按控制台关闭按钮关闭 - AppRuntime.WssService.Close(); + AppRuntime.WsServer.Dispose(); break; } return false; - }); + } //检测程序是否多开 private static bool CheckAlreadyRunning() @@ -112,5 +134,40 @@ namespace BarrageGrab return !createdNew; } } + + private static void JintTest() + { + var jsEng = JsEngine.CreateNewEngine(); + var jsFile = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "Scripts", "engine", "comPortFilter.js"), Encoding.UTF8); + jsEng.Execute(jsFile); + var result = jsEng.Invoke("onPackData", 1, new + { + Aporp = 142, + Bprop = "48777", + Cprop = new string[] { "123" }, + Dprop = new Dictionary() + { + { "key1","value1" } + } + }); + + Console.WriteLine("返回类型:" + result.Type.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()); + } + } } } diff --git a/BarrageGrab/Proxy/SystemProxy.cs b/BarrageGrab/Proxy/SystemProxy.cs index fdcc8b9..661417c 100644 --- a/BarrageGrab/Proxy/SystemProxy.cs +++ b/BarrageGrab/Proxy/SystemProxy.cs @@ -32,7 +32,7 @@ namespace BarrageGrab.Proxy /// /// 代理端口 /// - public int ProxyPort { get { return Appsetting.Current.ProxyPort; } } + public int ProxyPort { get { return AppSetting.Current.ProxyPort; } } public abstract string HttpUpstreamProxy { get; } @@ -55,11 +55,11 @@ namespace BarrageGrab.Proxy { host = host.Trim().ToLower(); - if (!Appsetting.Current.FilterHostName) return true; + if (!AppSetting.Current.FilterHostName) return true; if (host.StartsWith("webcast")) return true; - if (Appsetting.Current.HostNameFilter.Any(a => a.Trim().ToLower() == host)) return true; + if (AppSetting.Current.HostNameFilter.Any(a => a.Trim().ToLower() == host)) return true; return false; } diff --git a/BarrageGrab/Proxy/TitaniumProxy.cs b/BarrageGrab/Proxy/TitaniumProxy.cs index dec702a..24a9bc4 100644 --- a/BarrageGrab/Proxy/TitaniumProxy.cs +++ b/BarrageGrab/Proxy/TitaniumProxy.cs @@ -212,7 +212,7 @@ namespace BarrageGrab.Proxy var scriptContext = BuildContext(new Dictionary() { {"PROCESS_NAME","'{processName}'"}, - {"AUTOPAUSE",Appsetting.Current.AutoPause.ToString().ToLower()} + {"AUTOPAUSE",AppSetting.Current.AutoPause.ToString().ToLower()} }); liveRoomInjectScript = scriptContext + liveRoomInjectScript; var html = await e.GetResponseBodyAsString(); @@ -275,7 +275,7 @@ namespace BarrageGrab.Proxy } //给script标签 src加上时间戳避免缓存 - if (Appsetting.Current.DisableLivePageScriptCache) + if (AppSetting.Current.DisableLivePageScriptCache) { var scripts = doc.DocumentNode.SelectNodes("//script[@src]"); if (scripts != null) @@ -311,7 +311,7 @@ namespace BarrageGrab.Proxy var scriptContext = BuildContext(new Dictionary() { {"PROCESS_NAME","'{processName}'"}, - {"AUTOPAUSE",Appsetting.Current.AutoPause.ToString().ToLower()} + {"AUTOPAUSE",AppSetting.Current.AutoPause.ToString().ToLower()} }); liveHoomInjectScript = scriptContext + liveHoomInjectScript; @@ -382,7 +382,7 @@ namespace BarrageGrab.Proxy } } - if (url.Contains(LIVE_SCRIPT_PATH) && Appsetting.Current.ForcePolling) + if (url.Contains(LIVE_SCRIPT_PATH) && AppSetting.Current.ForcePolling) { var reg = new Regex(@"if\s*\((?!this\.stopPolling)\)"); var js = await e.GetResponseBodyAsString(); @@ -393,7 +393,7 @@ namespace BarrageGrab.Proxy var pollingIntervalMatch = pollingIntervalReg.Match(js); if (pollingIntervalMatch.Success) { - var myValue = Appsetting.Current.PollingInterval; + var myValue = AppSetting.Current.PollingInterval; js = pollingIntervalReg.Replace(js, $"this.pollingInterval={myValue},"); Logger.PrintColor($"直播间已成功修改轮询间隔为{myValue}ms", ConsoleColor.Green); } @@ -515,7 +515,7 @@ namespace BarrageGrab.Proxy { proxyServer.Stop(); proxyServer.Dispose(); - if (Appsetting.Current.UsedProxy) + if (AppSetting.Current.UsedProxy) { CloseSystemProxy(); } @@ -526,8 +526,8 @@ namespace BarrageGrab.Proxy /// override public void Start() { - proxyServer.Start(Appsetting.Current.UsedProxy); - if (Appsetting.Current.UsedProxy) + proxyServer.Start(AppSetting.Current.UsedProxy); + if (AppSetting.Current.UsedProxy) { proxyServer.SetAsSystemHttpProxy(explicitEndPoint); proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); diff --git a/BarrageGrab/Scripts/engine/comPortFilter.js b/BarrageGrab/Scripts/engine/comPortFilter.js new file mode 100644 index 0000000..7dc0ecb --- /dev/null +++ b/BarrageGrab/Scripts/engine/comPortFilter.js @@ -0,0 +1,28 @@ +/** + * 注解:串口数据过滤脚本,可用于自定义配置串口的发送报文 + * Tip: 该脚本引擎为Jint,支持的语法请参考官方文档:https://github.com/sebastienros/jint + * 工具环境: + * 1.支持 console.log, console.error, console.warn 这些日志将被输出到控制台, 其中error日志将被记录到日志文件 + * 2.编码工具 encoder.utf8ToBytes(str),encoder.utf8ToString 字符串 和 Uint8Array 互转 + * encoder.utf32ToBytes(str),encoder.utf32ToString + * encoder.asciiToBytes(str),encoder.asciiToString + */ + + + +/** + * 这个函数由程序JS引擎调用,不要删除 + * @param {number} msgType 消息类型,如礼物,弹幕消息等,和程序内定义一致 + * @param {Object} msg 被WsBarrageServer简化后的消息对象,具体可参考Json实体文件 + * @returns {Uint8Array|string} 返回一个Uint8Array类型的数据,或者返回一个字符串,如果返回 null 则不发送数据。返回的数据将会被发送到串口 + */ +function onPackData(msgType, msg) { + let excludeMsgType = [3, 6, 0]; // 过滤掉进入直播间和统计信息 + if (excludeMsgType.includes(msgType)) return; + var result = msg.Content + "\r\n"; + return result; + // var buff = encoder.utf8ToBytes(result); + // var newjs = encoder.utf8ToString(buff); + // console.log(newjs); + // return newjs; +} diff --git a/BarrageGrab/WsBarrageService.cs b/BarrageGrab/WsBarrageServer.cs similarity index 85% rename from BarrageGrab/WsBarrageService.cs rename to BarrageGrab/WsBarrageServer.cs index 7b90193..9aed910 100644 --- a/BarrageGrab/WsBarrageService.cs +++ b/BarrageGrab/WsBarrageServer.cs @@ -20,20 +20,44 @@ using System.Collections.Concurrent; namespace BarrageGrab { + /// + /// WsBarrageServer 包装消息事件委托 + /// + public delegate void PackMessageEventHandler(WsBarrageServer sender, WsBarrageServer.PackMsgEventArgs e); + /// /// 弹幕服务 /// - public class WsBarrageService + public class WsBarrageServer:IDisposable { - WebSocketServer socketServer; - Dictionary socketList = new Dictionary(); - //礼物计数缓存 - ConcurrentDictionary> giftCountCache = new ConcurrentDictionary>(); - Timer dieout = new Timer(10000); - Timer giftCountTimer = new Timer(10000); - WssBarrageGrab grab = new WssBarrageGrab(); - Appsetting Appsetting = Appsetting.Current; - bool debug = false; + WebSocketServer socketServer; //Ws服务器对象 + Dictionary socketList = new Dictionary(); //客户端列表 + ConcurrentDictionary> giftCountCache = new ConcurrentDictionary>();//礼物计数缓存 + Timer dieout = new Timer(10000);//离线客户端清理计时器 + Timer giftCountTimer = new Timer(10000);//礼物缓存清理计时器 + WssBarrageGrab grab = new WssBarrageGrab();//弹幕解析器核心 + AppSetting Appsetting = AppSetting.Current;//全局配置文件实例 + static int printCount = 0; //控制台输出计数,用于判断清理控制台 + + /// + /// WS服务器启动地址 + /// + public string ServerLocation => socketServer.Location; + + /// + /// 数据内核 + /// + public WssBarrageGrab Grab => grab; + + /// + /// 控制台打印事件 + /// + public event EventHandler OnPrint; + + /// + /// 是否已经释放资源 + /// + public bool IsDisposed { get; private set; } = false; /// /// 服务关闭后触发 @@ -41,25 +65,12 @@ namespace BarrageGrab public event EventHandler OnClose; /// - /// WS服务器启动地址 + /// 消息包装完成后触发 /// - public string ServerLocation { get { return socketServer.Location; } } + public event PackMessageEventHandler OnPackMessage; - /// - /// 数据内核 - /// - public WssBarrageGrab Grab { get { return grab; } } - - /// - /// 控制台打印事件 - /// - public event EventHandler OnPrint; - - public WsBarrageService() + public WsBarrageServer() { -#if DEBUG - debug = true; -#endif var socket = new WebSocketServer($"ws://0.0.0.0:{Appsetting.WsProt}"); socket.RestartAfterListenError = true;//异常重启 @@ -81,6 +92,7 @@ namespace BarrageGrab giftCountTimer.Start(); } + //礼物缓存清理计时器回调 private void GiftCountTimer_Elapsed(object sender, ElapsedEventArgs e) { var now = DateTime.Now; @@ -91,20 +103,29 @@ namespace BarrageGrab { timeOutKeys.ForEach(key => { + Tuple _; giftCountCache.TryRemove(key, out _); - }); } } + //心跳淘汰计时器回调 + private void Dieout_Elapsed(object sender, ElapsedEventArgs e) + { + var now = DateTime.Now; + var dieoutKvs = socketList.Where(w => w.Value.LastPing.AddSeconds(dieout.Interval * 3) < now).ToList(); + dieoutKvs.ForEach(f => f.Value.Socket.Close()); + } + + //判断Rommid是否符合拦截规则 private bool CheckRoomId(long roomid) { - if (!Appsetting.Current.WebRoomIds.Any()) return true; + if (!AppSetting.Current.WebRoomIds.Any()) return true; var webrid = AppRuntime.RoomCaches.GetCachedWebRoomid(roomid.ToString()); if (webrid <= 0) return true; - - return Appsetting.Current.WebRoomIds.Contains(webrid); + + return AppSetting.Current.WebRoomIds.Contains(webrid); } //解析用户 @@ -141,7 +162,7 @@ namespace BarrageGrab return user; } - static int count = 0; + //打印消息 private void PrintMsg(Msg msg, PackMsgType barType) { var rinfo = AppRuntime.RoomCaches.GetCachedWebRoomInfo(msg.RoomId.ToString()); @@ -153,7 +174,7 @@ namespace BarrageGrab text += $" [{msg.User?.GenderToString()}] "; } - ConsoleColor color = Appsetting.Current.ColorMap[barType].Item1; + ConsoleColor color = AppSetting.Current.ColorMap[barType].Item1; var append = msg.Content; switch (barType) { @@ -164,13 +185,13 @@ namespace BarrageGrab text += append; - if (Appsetting.Current.BarrageLog) + if (AppSetting.Current.BarrageLog) { Logger.LogBarrage(barType, msg); } if (!Appsetting.PrintBarrage) return; - if (Appsetting.Current.PrintFilter.Any() && !Appsetting.Current.PrintFilter.Contains(barType.GetHashCode())) return; + if (AppSetting.Current.PrintFilter.Any() && !AppSetting.Current.PrintFilter.Contains(barType.GetHashCode())) return; OnPrint?.Invoke(this, new PrintEventArgs() { @@ -179,15 +200,28 @@ namespace BarrageGrab MsgType = barType }); - if (++count > 10000) + if (++printCount > 10000) { Console.Clear(); Logger.PrintColor("控制台已清理"); - count = 0; + printCount = 0; } Logger.PrintColor(text + "\n", color); } + //发送消息包装事件 + private async void FirePack(Msg msg, PackMsgType barType) + { + if (OnPackMessage == null) return; + var arg = new PackMsgEventArgs() + { + MsgType = barType, + Message = msg + }; + //异步执行 + OnPackMessage(this, arg); + } + //粉丝团 private void Grab_OnFansclubMessage(object sender, WssBarrageGrab.RoomMessageEventArgs e) { @@ -205,6 +239,7 @@ namespace BarrageGrab enty.Level = enty.User.FansClub.Level; var msgType = PackMsgType.粉丝团消息; + FirePack(enty, msgType); PrintMsg(enty, msgType); Broadcast(new BarrageMsgPack(enty.ToJson(), msgType, e.Process)); } @@ -228,6 +263,7 @@ namespace BarrageGrab }; var msgType = PackMsgType.直播间统计; + FirePack(enty, msgType); PrintMsg(enty, msgType); var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process); Broadcast(pack); @@ -252,6 +288,7 @@ namespace BarrageGrab //清除缓存中的key if (msg.groupId > 0 && giftCountCache.ContainsKey(key)) { + Tuple _; giftCountCache.TryRemove(key, out _); } return; @@ -297,8 +334,8 @@ namespace BarrageGrab GiftId = msg.giftId, GiftName = msg.Gift.Name, Combo = msg.Gift.Combo, - ImgUrl = msg.Gift.Image?.urlLists?.FirstOrDefault()??"", - User = GetUser(msg.User), + ImgUrl = msg.Gift.Image?.urlLists?.FirstOrDefault() ?? "", + User = GetUser(msg.User), ToUser = GetUser(msg.toUser) }; @@ -308,6 +345,7 @@ namespace BarrageGrab } var msgType = PackMsgType.礼物消息; + FirePack(enty, msgType); PrintMsg(enty, msgType); var pack = new BarrageMsgPack(enty.ToJson(), PackMsgType.礼物消息, e.Process); Broadcast(pack); @@ -329,6 +367,7 @@ namespace BarrageGrab }; var msgType = PackMsgType.关注消息; + FirePack(enty, msgType); PrintMsg(enty, msgType); var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process); var json = JsonConvert.SerializeObject(pack); @@ -358,6 +397,7 @@ namespace BarrageGrab }; var msgType = PackMsgType.直播间分享; + FirePack(enty, msgType); PrintMsg(enty, msgType); //shareTarget: (112:好友),(1微信)(2朋友圈)(3微博)(5:qq)(4:qq空间),shareType: 1 @@ -383,6 +423,7 @@ namespace BarrageGrab }; var msgType = PackMsgType.进直播间; + FirePack(enty, msgType); PrintMsg(enty, msgType); var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process); var json = JsonConvert.SerializeObject(pack); @@ -407,6 +448,7 @@ namespace BarrageGrab }; var msgType = PackMsgType.点赞消息; + FirePack(enty, msgType); PrintMsg(enty, msgType); var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process); Broadcast(pack); @@ -428,6 +470,7 @@ namespace BarrageGrab }; var msgType = PackMsgType.弹幕消息; + FirePack(enty, msgType); PrintMsg(enty, msgType); var pack = new BarrageMsgPack(enty.ToJson(), msgType, e.Process); @@ -453,6 +496,7 @@ namespace BarrageGrab }; var msgType = PackMsgType.下播; + FirePack(enty, msgType); PrintMsg(enty, msgType); pack = new BarrageMsgPack(enty.ToJson(), PackMsgType.下播, e.Process); } @@ -463,29 +507,7 @@ namespace BarrageGrab } } - //static int count = 0; - //private void Print(string msg, ConsoleColor color, PackMsgType bartype) - //{ - // if (!Appsetting.PrintFilter.Any(a => a == bartype.GetHashCode())) return; - // if (Appsetting.PrintBarrage) - // { - // if (++count > 1000) - // { - // Console.Clear(); - // Logger.PrintColor("控制台已清理"); - // } - // Logger.PrintColor($"{DateTime.Now.ToString("HH:mm:ss")} [{bartype.ToString()}] " + msg + "\n", color); - // count = 0; - // } - //} - - private void Dieout_Elapsed(object sender, ElapsedEventArgs e) - { - var now = DateTime.Now; - var dieoutKvs = socketList.Where(w => w.Value.LastPing.AddSeconds(dieout.Interval * 3) < now).ToList(); - dieoutKvs.ForEach(f => f.Value.Socket.Close()); - } - + //监听用户连接 private void Listen(IWebSocketConnection socket) { //客户端url @@ -511,7 +533,7 @@ namespace BarrageGrab switch (cmdPack.Cmd) { case CommandCode.Close: - this.Close(); + this.Dispose(); break; case CommandCode.EnableProxy: { @@ -553,7 +575,7 @@ namespace BarrageGrab public void Broadcast(BarrageMsgPack pack) { if (pack == null) return; - if (Appsetting.Current.PushFilter.Any() && !Appsetting.Current.PushFilter.Contains(pack.Type.GetHashCode())) return; + if (AppSetting.Current.PushFilter.Any() && !AppSetting.Current.PushFilter.Contains(pack.Type.GetHashCode())) return; var offLines = new List(); foreach (var item in socketList) @@ -577,23 +599,34 @@ namespace BarrageGrab /// public void StartListen() { - this.grab.Start(); //启动代理 - this.socketServer.Start(Listen);//启动监听 + try + { + this.grab.Start(); //启动代理 + this.socketServer.Start(Listen);//启动监听 + } + catch (Exception) + { + this.Dispose(); + throw; + } } /// /// 关闭服务器连接,并关闭系统代理 /// - public void Close() + public void Dispose() { socketList.Values.ToList().ForEach(f => f.Socket.Close()); socketList.Clear(); socketServer.Dispose(); grab.Dispose(); - + this.IsDisposed = true; this.OnClose?.Invoke(this, EventArgs.Empty); } + /// + /// 客户端套接字上下文 + /// class UserState { /// @@ -616,6 +649,9 @@ namespace BarrageGrab } } + /// + /// Print事件参数 + /// public class PrintEventArgs : EventArgs { public string Message { get; set; } @@ -624,5 +660,21 @@ namespace BarrageGrab public PackMsgType MsgType { get; set; } } + + /// + /// 消息包事件参数 + /// + public class PackMsgEventArgs + { + /// + /// 消息类型 + /// + public PackMsgType MsgType { get; set; } + + /// + /// 消息内容 + /// + public Msg Message { get; set; } + } } } diff --git a/BarrageGrab/WssBarrageGrab.cs b/BarrageGrab/WssBarrageGrab.cs index 4f524d0..4552e1a 100644 --- a/BarrageGrab/WssBarrageGrab.cs +++ b/BarrageGrab/WssBarrageGrab.cs @@ -19,7 +19,7 @@ namespace BarrageGrab { //ISystemProxy proxy = new FiddlerProxy(); ISystemProxy proxy = new TitaniumProxy(); - Appsetting appsetting = Appsetting.Current; + AppSetting appsetting = AppSetting.Current; /// /// 进入直播间 diff --git a/BarrageGrab/WssBarrageService.csproj b/BarrageGrab/WssBarrageService.csproj index 2eceb7c..ca3fd75 100644 --- a/BarrageGrab/WssBarrageService.csproj +++ b/BarrageGrab/WssBarrageService.csproj @@ -70,12 +70,20 @@ ..\packages\BrotliSharpLib.0.3.3\lib\net451\BrotliSharpLib.dll + + ..\packages\Esprima.3.0.4\lib\net462\Esprima.dll + True + ..\packages\Fleck.1.2.0\lib\net45\Fleck.dll ..\packages\HtmlAgilityPack.1.11.51\lib\Net45\HtmlAgilityPack.dll + + ..\packages\Jint.3.0.1\lib\net462\Jint.dll + True + ..\packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll @@ -135,7 +143,8 @@ - + + Form @@ -149,6 +158,7 @@ RoomDetail.cs + @@ -167,7 +177,7 @@ - + @@ -178,6 +188,9 @@ + + PreserveNewest + Always diff --git a/BarrageGrab/packages.config b/BarrageGrab/packages.config index 2e56486..e0afd29 100644 --- a/BarrageGrab/packages.config +++ b/BarrageGrab/packages.config @@ -2,9 +2,10 @@ - + +