diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..dd9d14d --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,145 @@ +name: Build and Release + +on: + push: + tags: + - 'v*' # 推送 tag 时触发,如 v1.0.0 + workflow_dispatch: # 允许手动触发 + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v2 + + - name: Setup NuGet + uses: NuGet/setup-nuget@v2 + + - name: Restore NuGet packages + run: nuget restore subs-check.win.gui.sln + + - name: Build project + run: msbuild subs-check.win.gui.csproj /p:Configuration=Release + + # 由于 subs-check.win.gui.csproj 的 PostBuildCleanup 目标会删除不必要的文件,因此这里直接打包 bin/Release 目录下的内容即可 + # - name: Package artifact + # run: | + # shopt -s extglob + # mkdir -p release + # cp -r bin/Release/*.exe release/ + # cp -r bin/Release/!(*.Wpf).dll release/ + # cp -r bin/Release/runtimes release/ + # cp -r bin/Release/zh release/ + # shell: bash + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: subs-check-win + path: bin/release/ + if-no-files-found: error # 如果没有文件,报错 + + release: + needs: build + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: master + + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: subs-check-win + path: release + + - name: Prepare tags (delete local tags then fetch remote tags cleanly) + id: tags + run: | + CURRENT_TAG="${GITHUB_REF#refs/tags/}" + echo "current_tag=$CURRENT_TAG" >> $GITHUB_OUTPUT + PREV_TAG=$(git tag --sort=-creatordate | grep -v "^${CURRENT_TAG}$" | head -n1 || true) + echo "prev_tag=$PREV_TAG" >> $GITHUB_OUTPUT + shell: bash + + - name: Create ZIP archive + run: | + cd release + zip -r subs-check-win.zip . + shell: bash + + # 用 git-cliff 生成并更新 CHANGELOG.md(范围:PREV_TAG..CURRENT_TAG) + - name: Generate changelog with git-cliff + uses: orhun/git-cliff-action@v4 + id: git-cliff + with: + config: cliff.toml + args: ${{ steps.tags.outputs.prev_tag && format('{0}..{1}', steps.tags.outputs.prev_tag, steps.tags.outputs.current_tag) || steps.tags.outputs.current_tag }} -o CHANGELOG.md + + # 用 git-cliff 生成 Release body(范围:PREV_TAG..CURRENT_TAG) + - name: Generate changelog with git-cliff (release body) + uses: orhun/git-cliff-action@v4 + id: git-cliff-release + with: + config: cliff-release.toml + args: ${{ steps.tags.outputs.prev_tag && format('{0}..{1}', steps.tags.outputs.prev_tag, steps.tags.outputs.current_tag) || steps.tags.outputs.current_tag }} + + - name: Generate update.xml + run: | + CURRENT_TAG="${{ steps.tags.outputs.current_tag }}" + VERSION="${CURRENT_TAG#v}" # 去掉开头的 v + + cat > update.xml < + + ${VERSION} + https://gh.39.al/https://github.com/sinspired/SubsCheck-Win-GUI/releases/download/${CURRENT_TAG}/subs-check-win.zip + https://gh.39.al/https://raw.githubusercontent.com/sinspired/SubsCheck-Win-GUI/master/CHANGELOG.md + true + subs-check.win.gui.exe + + EOF + + - name: Commit changelog and update.xml + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + git add CHANGELOG.md update.xml + if git diff --cached --quiet; then + echo "No changes in CHANGELOG.md or update.xml" + exit 0 + fi + + git commit -m "chore(release): update CHANGELOG.md and update.xml for ${{ steps.tags.outputs.current_tag }}" + git push + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + body: ${{ steps.git-cliff-release.outputs.content }} + files: release/subs-check-win.zip + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Send Telegram message on push + uses: appleboy/telegram-action@master + with: + to: ${{ secrets.TELEGRAM_CHAT_ID }} # 频道 ID + token: ${{ secrets.TELEGRAM_BOT_TOKEN }} # Bot Token + format: markdown + message: | + 💻 *subs-check_GUI for Windows 更新* + + 版本: `${{ github.ref_name }}` + 项目: `${{ github.repository }}` + + 🔗 [查看详情](https://github.com/${{ github.repository }}/releases/tag/${{ github.ref_name }}) \ No newline at end of file diff --git a/.gitignore b/.gitignore index 52d9dd1..dcd0354 100644 --- a/.gitignore +++ b/.gitignore @@ -361,4 +361,8 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd + +*.ini + +.wiki/ diff --git a/App.config b/App.config index ecdcf8a..4bfa005 100644 --- a/App.config +++ b/App.config @@ -1,6 +1,6 @@ - + diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..80811f3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +# 📝 Changelog + +[2.7.0.1] - 2026-01-02 + +🚀 Features + +- 添加 isp 类型检测选项 + +📚 Documentation + +- 更新软件运行截图 +- 更新 README + +⚙️ Miscellaneous Tasks + +- 更新软件信息 +- 更新控件提示 +- 修改部分文案 +- Bump version to 2.7.0.1 diff --git a/CheckUpdates.Designer.cs b/CheckUpdates.Designer.cs index 97dcaa1..0a1dc31 100644 --- a/CheckUpdates.Designer.cs +++ b/CheckUpdates.Designer.cs @@ -32,13 +32,13 @@ private void InitializeComponent() this.groupBox1 = new System.Windows.Forms.GroupBox(); this.label4 = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label(); - this.button1 = new System.Windows.Forms.Button(); + this.buttonUpdateGUI = new System.Windows.Forms.Button(); this.label2 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.label5 = new System.Windows.Forms.Label(); this.label6 = new System.Windows.Forms.Label(); - this.button2 = new System.Windows.Forms.Button(); + this.buttonUpdateCore = new System.Windows.Forms.Button(); this.label7 = new System.Windows.Forms.Label(); this.label8 = new System.Windows.Forms.Label(); this.timer1 = new System.Windows.Forms.Timer(this.components); @@ -51,60 +51,67 @@ private void InitializeComponent() // this.groupBox1.Controls.Add(this.label4); this.groupBox1.Controls.Add(this.label3); - this.groupBox1.Controls.Add(this.button1); + this.groupBox1.Controls.Add(this.buttonUpdateGUI); this.groupBox1.Controls.Add(this.label2); this.groupBox1.Controls.Add(this.label1); - this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Location = new System.Drawing.Point(22, 21); + this.groupBox1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(144, 89); + this.groupBox1.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBox1.Size = new System.Drawing.Size(264, 156); this.groupBox1.TabIndex = 0; this.groupBox1.TabStop = false; - this.groupBox1.Text = "SubsCheck Win GUI"; + this.groupBox1.Text = "GUI 程序"; // // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(77, 37); + this.label4.Location = new System.Drawing.Point(141, 65); + this.label4.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(53, 12); + this.label4.Size = new System.Drawing.Size(98, 21); this.label4.TabIndex = 4; this.label4.Text = "v0.0.0.0"; // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(77, 17); + this.label3.Location = new System.Drawing.Point(141, 30); + this.label3.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(53, 12); + this.label3.Size = new System.Drawing.Size(98, 21); this.label3.TabIndex = 3; this.label3.Text = "v0.0.0.0"; // - // button1 + // buttonUpdateGUI // - this.button1.Enabled = false; - this.button1.Location = new System.Drawing.Point(8, 57); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(122, 23); - this.button1.TabIndex = 2; - this.button1.Text = "正在获取版本"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); + this.buttonUpdateGUI.Enabled = false; + this.buttonUpdateGUI.Location = new System.Drawing.Point(15, 100); + this.buttonUpdateGUI.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.buttonUpdateGUI.Name = "buttonUpdateGUI"; + this.buttonUpdateGUI.Size = new System.Drawing.Size(224, 40); + this.buttonUpdateGUI.TabIndex = 2; + this.buttonUpdateGUI.Text = "正在获取版本"; + this.buttonUpdateGUI.UseVisualStyleBackColor = true; + this.buttonUpdateGUI.Click += new System.EventHandler(this.buttonUpdateGUI_Click); // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(10, 37); + this.label2.Location = new System.Drawing.Point(18, 65); + this.label2.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(65, 12); + this.label2.Size = new System.Drawing.Size(115, 21); this.label2.TabIndex = 1; this.label2.Text = "当前版本:"; // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(10, 17); + this.label1.Location = new System.Drawing.Point(18, 30); + this.label1.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(65, 12); + this.label1.Size = new System.Drawing.Size(115, 21); this.label1.TabIndex = 0; this.label1.Text = "最新版本:"; // @@ -112,12 +119,14 @@ private void InitializeComponent() // this.groupBox2.Controls.Add(this.label5); this.groupBox2.Controls.Add(this.label6); - this.groupBox2.Controls.Add(this.button2); + this.groupBox2.Controls.Add(this.buttonUpdateCore); this.groupBox2.Controls.Add(this.label7); this.groupBox2.Controls.Add(this.label8); - this.groupBox2.Location = new System.Drawing.Point(162, 12); + this.groupBox2.Location = new System.Drawing.Point(297, 21); + this.groupBox2.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(144, 89); + this.groupBox2.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBox2.Size = new System.Drawing.Size(264, 156); this.groupBox2.TabIndex = 5; this.groupBox2.TabStop = false; this.groupBox2.Text = "Subs-Check 内核"; @@ -125,73 +134,81 @@ private void InitializeComponent() // label5 // this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(77, 37); + this.label5.Location = new System.Drawing.Point(141, 65); + this.label5.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(53, 12); + this.label5.Size = new System.Drawing.Size(98, 21); this.label5.TabIndex = 4; this.label5.Text = "v0.0.0.0"; // // label6 // this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(77, 17); + this.label6.Location = new System.Drawing.Point(141, 30); + this.label6.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(53, 12); + this.label6.Size = new System.Drawing.Size(94, 21); this.label6.TabIndex = 3; this.label6.Text = "正在获取"; // - // button2 + // buttonUpdateCore // - this.button2.Enabled = false; - this.button2.Location = new System.Drawing.Point(8, 57); - this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(122, 23); - this.button2.TabIndex = 2; - this.button2.Text = "正在获取版本"; - this.button2.UseVisualStyleBackColor = true; - this.button2.Click += new System.EventHandler(this.button2_Click); + this.buttonUpdateCore.Enabled = false; + this.buttonUpdateCore.Location = new System.Drawing.Point(15, 100); + this.buttonUpdateCore.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.buttonUpdateCore.Name = "buttonUpdateCore"; + this.buttonUpdateCore.Size = new System.Drawing.Size(224, 40); + this.buttonUpdateCore.TabIndex = 2; + this.buttonUpdateCore.Text = "正在获取版本"; + this.buttonUpdateCore.UseVisualStyleBackColor = true; + this.buttonUpdateCore.Click += new System.EventHandler(this.buttonUpdateKernel_Click); // // label7 // this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(10, 37); + this.label7.Location = new System.Drawing.Point(18, 65); + this.label7.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(65, 12); + this.label7.Size = new System.Drawing.Size(115, 21); this.label7.TabIndex = 1; this.label7.Text = "当前版本:"; // // label8 // this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(10, 17); + this.label8.Location = new System.Drawing.Point(18, 30); + this.label8.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(65, 12); + this.label8.Size = new System.Drawing.Size(115, 21); this.label8.TabIndex = 0; this.label8.Text = "最新版本:"; // // timer1 // + this.timer1.Interval = 1000; this.timer1.Tick += new System.EventHandler(this.timer1_Tick); // // comboBox1 // this.comboBox1.FormattingEnabled = true; - this.comboBox1.Location = new System.Drawing.Point(12, 107); + this.comboBox1.Location = new System.Drawing.Point(22, 187); + this.comboBox1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.comboBox1.Name = "comboBox1"; - this.comboBox1.Size = new System.Drawing.Size(294, 20); + this.comboBox1.Size = new System.Drawing.Size(536, 29); this.comboBox1.TabIndex = 23; this.comboBox1.Visible = false; // // CheckUpdates // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 21F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.ClientSize = new System.Drawing.Size(319, 138); + this.ClientSize = new System.Drawing.Size(585, 242); this.Controls.Add(this.comboBox1); this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox1); + this.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "CheckUpdates"; @@ -212,13 +229,13 @@ private void InitializeComponent() private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.Label label4; private System.Windows.Forms.Label label3; - private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button buttonUpdateGUI; private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label1; private System.Windows.Forms.GroupBox groupBox2; private System.Windows.Forms.Label label5; private System.Windows.Forms.Label label6; - private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button buttonUpdateCore; private System.Windows.Forms.Label label7; private System.Windows.Forms.Label label8; private System.Windows.Forms.Timer timer1; diff --git a/CheckUpdates.cs b/CheckUpdates.cs index 44ccdb8..1076f83 100644 --- a/CheckUpdates.cs +++ b/CheckUpdates.cs @@ -1,11 +1,18 @@ -using Newtonsoft.Json.Linq; -using System; +using System; using System.Collections.Generic; using System.Data; using System.Linq; +using System.Net; using System.Net.Http; using System.Threading.Tasks; using System.Windows.Forms; + +using AutoUpdaterDotNET; + +using Newtonsoft.Json.Linq; + +using subs_check.win.gui.Properties; + using static System.Windows.Forms.VisualStyles.VisualStyleElement; namespace subs_check.win.gui @@ -20,12 +27,44 @@ public partial class CheckUpdates : Form public string 当前subsCheck版本号 { get; set; } public string 当前GUI版本号 { get; set; } public string 最新GUI版本号 { get; set; } + public bool EnableHighConcurrent { get; set; } + public bool EnableArch64 { get; set; } public CheckUpdates() { InitializeComponent(); + //注册自动更新订阅事件 + //AutoUpdater.CheckForUpdateEvent += AutoUpdaterOnCheckForUpdateEvent; } + ////自定义检查更新事件 + //private void AutoUpdaterOnCheckForUpdateEvent(UpdateInfoEventArgs args) + //{ + // if (args.Error == null) + // { + // if (args.IsUpdateAvailable) + // { + // // 如果你想显示标准更新窗口,请取消下面这行的注释 + // AutoUpdater.ShowUpdateForm(args); + // } + // } + // else + // { + // if (args.Error is WebException) + // { + // MessageBox.Show( + // @"无法连接到更新服务器。请检查您的网络连接并稍后重试。", + // @"更新检查失败", MessageBoxButtons.OK, MessageBoxIcon.Error); + // } + // else + // { + // MessageBox.Show(args.Error.Message, + // args.Error.GetType().ToString(), MessageBoxButtons.OK, + // MessageBoxIcon.Error); + // } + // } + //} + protected override void OnLoad(EventArgs e) { base.OnLoad(e); @@ -51,27 +90,20 @@ private async void timer1_Tick(object sender, EventArgs e) label5.Text = 当前subsCheck版本号; - if (comboBox1.Text == "自动选择") + if (EnableHighConcurrent) { - // 创建不包含"自动选择"的代理列表 - List proxyItems = new List(); - for (int j = 0; j < comboBox1.Items.Count; j++) - { - string proxyItem = comboBox1.Items[j].ToString(); - if (proxyItem != "自动选择") - proxyItems.Add(proxyItem); - } - - // 随机打乱列表顺序 - Random random = new Random(); - proxyItems = proxyItems.OrderBy(x => random.Next()).ToList(); - - // 异步检测可用代理 - githubProxyURL = await DetectGitHubProxyAsync(proxyItems); + groupBox2.Text = "Subs-Check 性能内核"; } else { - githubProxyURL = $"https://{comboBox1.Text}/"; + groupBox2.Text = "Subs-Check 原版内核"; + } + + var mainForm = Application.OpenForms["MainGui"] as MainGui; + if (mainForm != null) + { + githubProxyURL = await mainForm.GetGithubProxyUrlAsync(); + await mainForm.AutoCheckSysProxy(); } if (最新GUI版本号 != 当前GUI版本号) @@ -80,21 +112,26 @@ private async void timer1_Tick(object sender, EventArgs e) string upgradeExePath = System.IO.Path.Combine(Application.StartupPath, "Upgrade.exe"); if (System.IO.File.Exists(upgradeExePath)) { - button1.Text = "立即更新"; - button1.Enabled = true; + buttonUpdateGUI.Text = "更新原版"; + buttonUpdateGUI.Enabled = true; } else { - button1.Text = "缺少更新程序"; - button1.Enabled = false; + buttonUpdateGUI.Text = "立即更新 GUI"; + buttonUpdateGUI.Enabled = true; + buttonUpdateGUI.ForeColor = System.Drawing.Color.Green; + } } else { - button1.Text = "已是最新版本"; - button1.Enabled = false; + buttonUpdateGUI.Text = "已是最新版本"; + buttonUpdateGUI.Enabled = false; } + // 根据并发参数选择仓库 + string repoOwner = EnableHighConcurrent ? "sinspired" : "beck-8"; + using (HttpClient client = new HttpClient()) { try @@ -102,8 +139,9 @@ private async void timer1_Tick(object sender, EventArgs e) client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); client.Timeout = TimeSpan.FromSeconds(30); // 增加超时时间以适应下载需求 - string url = "https://api.github.com/repos/beck-8/subs-check/releases/latest"; - string 备用url = "https://api.github.cmliussss.net/repos/beck-8/subs-check/releases/latest"; + + string url = $"https://api.github.com/repos/{repoOwner}/subs-check/releases/latest"; + string 备用url = $"https://api.github.cmliussss.net/repos/{repoOwner}/subs-check/releases/latest"; HttpResponseMessage response = null; string responseBody = null; @@ -214,20 +252,21 @@ private async void timer1_Tick(object sender, EventArgs e) label6.Text = latestVersion; if (当前subsCheck版本号 != latestVersion) { - button2.Text = "立即更新"; - button2.Enabled = true; + buttonUpdateCore.ForeColor = System.Drawing.Color.Green; + buttonUpdateCore.Text = "立即更新"; + buttonUpdateCore.Enabled = true; } else { - button2.Text = "已是最新版本"; - button2.Enabled = false; + buttonUpdateCore.Text = "已是最新版本"; + buttonUpdateCore.Enabled = false; } } } catch (Exception ex) { - MessageBox.Show($"下载 subs-check.exe 时出错: {ex.Message}\n\n请前往 https://github.com/beck-8/subs-check/releases 自行下载!", + MessageBox.Show($"下载 subs-check.exe 时出错: {ex.Message}\n\n请前往 https://github.com/{repoOwner}/subs-check/releases 自行下载!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } @@ -270,7 +309,7 @@ private async Task DetectGitHubProxyAsync(List proxyItems) return detectedProxyURL; } - private void button2_Click(object sender, EventArgs e) + private void buttonUpdateKernel_Click(object sender, EventArgs e) { // 设置对话框结果为OK,表示用户点击了"立即更新"按钮 this.DialogResult = DialogResult.OK; @@ -279,10 +318,23 @@ private void button2_Click(object sender, EventArgs e) this.Close(); } - private void button1_Click(object sender, EventArgs e) + private void buttonUpdateGUI_Click(object sender, EventArgs e) { + if (buttonUpdateGUI.Text == "立即更新 GUI") + { + // 使用AutoUpdater进行更新检查 + //AutoUpdater.Mandatory = true; + //AutoUpdater.UpdateMode = Mode.Forced; + AutoUpdater.SetOwner(CheckUpdates.ActiveForm); + AutoUpdater.Icon = Resources.download; + AutoUpdater.ShowRemindLaterButton = false; + AutoUpdater.ReportErrors = true; + AutoUpdater.HttpUserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"; + AutoUpdater.Start("https://ghproxy.net/raw.githubusercontent.com/sinspired/subsCheck-Win-GUI/master/update.xml"); + return; + } //下载链接 - string downloadURL = $"{githubProxyURL}https://github.com/cmliu/SubsCheck-Win-GUI/releases/download/{最新GUI版本号}/SubsCheck_Win_GUI.zip"; + string downloadURL = $"{githubProxyURL}https://github.com/sinspired/SubsCheck-Win-GUI/releases/download/{最新GUI版本号}/SubsCheck_Win_GUI.zip"; //目标文件 string downloadEXE = "subs-check.win.gui.exe"; diff --git a/EditURLs.Designer.cs b/EditURLs.Designer.cs index 5153659..45f7c05 100644 --- a/EditURLs.Designer.cs +++ b/EditURLs.Designer.cs @@ -36,14 +36,16 @@ private void InitializeComponent() this.button4 = new System.Windows.Forms.Button(); this.timer1 = new System.Windows.Forms.Timer(this.components); this.comboBox1 = new System.Windows.Forms.ComboBox(); + this.button5 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // button1 // this.button1.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.button1.Location = new System.Drawing.Point(12, 415); + this.button1.Location = new System.Drawing.Point(22, 726); + this.button1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.Size = new System.Drawing.Size(138, 40); this.button1.TabIndex = 0; this.button1.Text = "保存"; this.button1.UseVisualStyleBackColor = true; @@ -51,19 +53,23 @@ private void InitializeComponent() // // textBox1 // - this.textBox1.Location = new System.Drawing.Point(12, 12); + this.textBox1.Location = new System.Drawing.Point(22, 21); + this.textBox1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBox1.MaxLength = 99999999; this.textBox1.Multiline = true; this.textBox1.Name = "textBox1"; this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.textBox1.Size = new System.Drawing.Size(776, 397); + this.textBox1.Size = new System.Drawing.Size(1419, 692); this.textBox1.TabIndex = 1; + this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged); // // button2 // this.button2.Enabled = false; - this.button2.Location = new System.Drawing.Point(174, 415); + this.button2.Location = new System.Drawing.Point(318, 726); + this.button2.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(75, 23); + this.button2.Size = new System.Drawing.Size(138, 40); this.button2.TabIndex = 2; this.button2.Text = "等待获取"; this.button2.UseVisualStyleBackColor = true; @@ -71,9 +77,10 @@ private void InitializeComponent() // // button3 // - this.button3.Location = new System.Drawing.Point(93, 415); + this.button3.Location = new System.Drawing.Point(170, 726); + this.button3.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.button3.Name = "button3"; - this.button3.Size = new System.Drawing.Size(75, 23); + this.button3.Size = new System.Drawing.Size(138, 40); this.button3.TabIndex = 3; this.button3.Text = "去重"; this.button3.UseVisualStyleBackColor = true; @@ -81,9 +88,10 @@ private void InitializeComponent() // // button4 // - this.button4.Location = new System.Drawing.Point(713, 415); + this.button4.Location = new System.Drawing.Point(1307, 726); + this.button4.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.button4.Name = "button4"; - this.button4.Size = new System.Drawing.Size(75, 23); + this.button4.Size = new System.Drawing.Size(138, 40); this.button4.TabIndex = 4; this.button4.Text = "返回"; this.button4.UseVisualStyleBackColor = true; @@ -96,23 +104,37 @@ private void InitializeComponent() // comboBox1 // this.comboBox1.FormattingEnabled = true; - this.comboBox1.Location = new System.Drawing.Point(255, 418); + this.comboBox1.Location = new System.Drawing.Point(468, 732); + this.comboBox1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.comboBox1.Name = "comboBox1"; - this.comboBox1.Size = new System.Drawing.Size(120, 20); + this.comboBox1.Size = new System.Drawing.Size(217, 29); this.comboBox1.TabIndex = 22; this.comboBox1.Visible = false; // + // button5 + // + this.button5.Location = new System.Drawing.Point(466, 726); + this.button5.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.button5.Name = "button5"; + this.button5.Size = new System.Drawing.Size(138, 40); + this.button5.TabIndex = 23; + this.button5.Text = "恢复默认值"; + this.button5.UseVisualStyleBackColor = true; + this.button5.Click += new System.EventHandler(this.button5_Click); + // // EditURLs // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 21F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(800, 450); + this.ClientSize = new System.Drawing.Size(1467, 788); + this.Controls.Add(this.button5); this.Controls.Add(this.comboBox1); this.Controls.Add(this.button4); this.Controls.Add(this.button3); this.Controls.Add(this.button2); this.Controls.Add(this.textBox1); this.Controls.Add(this.button1); + this.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.MinimizeBox = false; this.Name = "EditURLs"; this.ShowIcon = false; @@ -133,5 +155,6 @@ private void InitializeComponent() private System.Windows.Forms.Button button4; private System.Windows.Forms.Timer timer1; private System.Windows.Forms.ComboBox comboBox1; + private System.Windows.Forms.Button button5; } } \ No newline at end of file diff --git a/EditURLs.cs b/EditURLs.cs index cdc9f01..b6d67ea 100644 --- a/EditURLs.cs +++ b/EditURLs.cs @@ -1,49 +1,72 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Data; -using System.Drawing; using System.Linq; using System.Net.Http; -using System.Security.Policy; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; -using static System.Windows.Forms.VisualStyles.VisualStyleElement; namespace subs_check.win.gui { - public partial class EditURLs: Form + public partial class EditURLs : Form { - // 添加一个属性用于存储和传递文本内容 + // 属性 public string UrlContent { get; set; } public System.Windows.Forms.ComboBox.ObjectCollection githubProxys { get; set; } public string githubProxy { get; set; } - string githubProxyURL; - string SubsCheckURLs; + + private string githubProxyURL; + private string SubsCheckURLs; + private string UrlContentOriginal; + public Action LogAction { get; set; } + + // 默认 URL 列表 + private static readonly string[] DefaultUrls = + { + "https://raw.githubusercontent.com/snakem982/proxypool/main/source/clash-meta.yaml", + "https://raw.githubusercontent.com/snakem982/proxypool/main/source/clash-meta-2.yaml", + "https://raw.githubusercontent.com/go4sharing/sub/main/sub.yaml", + "https://raw.githubusercontent.com/SoliSpirit/v2ray-configs/main/all_configs.txt" + }; + + private string GetDefaultUrlContent() + { + return string.Join(Environment.NewLine, DefaultUrls); + } + public EditURLs() { InitializeComponent(); - // 设置textBox1的锚点为上、左、右 + // 设置控件锚点 textBox1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom; - // 设置button1、button2、button3的锚点为左、下 button1.Anchor = AnchorStyles.Left | AnchorStyles.Bottom; button2.Anchor = AnchorStyles.Left | AnchorStyles.Bottom; button3.Anchor = AnchorStyles.Left | AnchorStyles.Bottom; - - // 设置button4的锚点为右、下 button4.Anchor = AnchorStyles.Right | AnchorStyles.Bottom; + button5.Anchor = AnchorStyles.Right | AnchorStyles.Bottom; // 新增按钮:恢复默认值 + + if (!string.IsNullOrEmpty(UrlContent)) + { + UrlContentOriginal = UrlContent; + } } - // 加载窗体时处理传入的内容 protected override void OnLoad(EventArgs e) { base.OnLoad(e); - // 将传入的内容显示在textBox1中 - if (!string.IsNullOrEmpty(UrlContent)) textBox1.Text = UrlContent; + // 优先显示传入内容,否则显示默认值 + if (!string.IsNullOrEmpty(UrlContent)) + { + textBox1.Text = UrlContent; + } + else + { + textBox1.Text = GetDefaultUrlContent(); + } timer1.Enabled = true; @@ -60,10 +83,19 @@ protected override void OnLoad(EventArgs e) private void button1_Click(object sender, EventArgs e) { - // 将textBox1的内容保存到UrlContent属性 - UrlContent = textBox1.Text; + if (string.IsNullOrWhiteSpace(textBox1.Text)) + { + textBox1.Text = !string.IsNullOrEmpty(UrlContentOriginal) + ? UrlContentOriginal + : GetDefaultUrlContent(); + + textBox1.SelectionStart = textBox1.Text.Length; - // 设置对话框结果为OK并关闭窗口 + // 调用传入的日志方法 + LogAction?.Invoke("订阅池为空,恢复默认订阅池。"); + } + + UrlContent = textBox1.Text; this.DialogResult = DialogResult.OK; this.Close(); } @@ -75,31 +107,25 @@ private void button4_Click(object sender, EventArgs e) private void button3_Click(object sender, EventArgs e) { - // 确保有内容需要处理 if (string.IsNullOrWhiteSpace(textBox1.Text)) return; - // 按行分割文本 string[] lines = textBox1.Text.Split( new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); - // 去除每行首尾的空白字符 for (int i = 0; i < lines.Length; i++) { lines[i] = lines[i].Trim(); } - // 使用LINQ的Distinct()方法去重,并过滤掉空行 string[] uniqueLines = lines .Where(line => !string.IsNullOrWhiteSpace(line)) - .Distinct(StringComparer.OrdinalIgnoreCase) // 忽略大小写进行去重 + .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray(); - // 将去重后的内容设回textBox1 - textBox1.Text = string.Join(Environment.NewLine, uniqueLines) + "\n"; + textBox1.Text = string.Join(Environment.NewLine, uniqueLines) + Environment.NewLine; - // 可选:显示去重结果 int removed = lines.Length - uniqueLines.Length; if (removed > 0) { @@ -119,7 +145,6 @@ private async void timer1_Tick(object sender, EventArgs e) if (comboBox1.Text == "自动选择") { - // 创建不包含"自动选择"的代理列表 List proxyItems = new List(); for (int j = 0; j < comboBox1.Items.Count; j++) { @@ -128,11 +153,9 @@ private async void timer1_Tick(object sender, EventArgs e) proxyItems.Add(proxyItem); } - // 随机打乱列表顺序 Random random = new Random(); proxyItems = proxyItems.OrderBy(x => random.Next()).ToList(); - // 异步检测可用代理 githubProxyURL = await DetectGitHubProxyAsync(proxyItems); } else @@ -145,17 +168,15 @@ private async void timer1_Tick(object sender, EventArgs e) { using (HttpClient client = new HttpClient()) { - client.Timeout = TimeSpan.FromSeconds(5); // 设置5秒超时 + client.Timeout = TimeSpan.FromSeconds(5); client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); - // 使用异步方式检查URL可访问性 HttpResponseMessage response = await client.GetAsync(SubsCheckURLsURL); if (response.IsSuccessStatusCode) { button2.Text = "在线获取"; button2.Enabled = true; SubsCheckURLs = await response.Content.ReadAsStringAsync(); - //MessageBox.Show(SubsCheckURLs); } else { @@ -167,18 +188,15 @@ private async void timer1_Tick(object sender, EventArgs e) catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); - // 网络错误或其他异常情况 button2.Text = "获取失败"; button2.Enabled = false; } } - // 创建专用方法用于异步检测GitHub代理 private async Task DetectGitHubProxyAsync(List proxyItems) { string detectedProxyURL = ""; - // 遍历随机排序后的代理列表 foreach (string proxyItem in proxyItems) { string checkUrl = $"https://{proxyItem}/https://raw.githubusercontent.com/cmliu/SubsCheck-Win-GUI/master/packages.config"; @@ -187,15 +205,12 @@ private async Task DetectGitHubProxyAsync(List proxyItems) { using (HttpClient client = new HttpClient()) { - client.Timeout = TimeSpan.FromSeconds(5); // 设置5秒超时 - // 添加User-Agent头,避免被拒绝访问 + client.Timeout = TimeSpan.FromSeconds(5); client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); - // 使用异步方式 HttpResponseMessage response = await client.GetAsync(checkUrl); if (response.IsSuccessStatusCode) { - // 找到可用代理 detectedProxyURL = $"https://{proxyItem}/"; break; } @@ -203,7 +218,6 @@ private async Task DetectGitHubProxyAsync(List proxyItems) } catch (Exception ex) { - // 记录错误但继续尝试下一个 Console.WriteLine($"Error: {ex.Message}"); } } @@ -212,7 +226,6 @@ private async Task DetectGitHubProxyAsync(List proxyItems) private void button2_Click(object sender, EventArgs e) { - // 检查是否已成功获取在线内容 if (string.IsNullOrEmpty(SubsCheckURLs)) { MessageBox.Show("未能获取在线内容,请重试。", "获取失败", @@ -220,7 +233,6 @@ private void button2_Click(object sender, EventArgs e) return; } - // 显示带有"覆盖"和"追加"选项的对话框 DialogResult result = MessageBox.Show( "请选择如何处理获取到的内容:\n\n" + "- 点击【是】将覆盖当前内容\n" + @@ -230,11 +242,8 @@ private void button2_Click(object sender, EventArgs e) MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); - // 根据用户选择执行对应操作 if (result == DialogResult.Yes) { - // 覆盖操作 - // 确保所有换行符格式一致 (将单独的\n或\r替换为Windows风格的\r\n) string normalizedText = NormalizeLineEndings(SubsCheckURLs); textBox1.Text = normalizedText; MessageBox.Show("已用在线内容覆盖原有内容。", "感谢大自然的馈赠", @@ -242,35 +251,48 @@ private void button2_Click(object sender, EventArgs e) } else if (result == DialogResult.No) { - // 追加操作 - // 确保原有内容末尾有换行符 if (!textBox1.Text.EndsWith("\r\n") && !textBox1.Text.EndsWith("\n")) { textBox1.Text += Environment.NewLine; } - // 追加新内容,确保换行符格式一致 textBox1.Text += NormalizeLineEndings(SubsCheckURLs); MessageBox.Show("已将在线内容追加到原有内容后。", "感谢大自然的馈赠", MessageBoxButtons.OK, MessageBoxIcon.Information); } - - // 如果用户选择"取消",不执行任何操作 } - // 标准化文本中的换行符为Windows风格 (\r\n) private string NormalizeLineEndings(string text) { if (string.IsNullOrEmpty(text)) return string.Empty; - // 先将所有类型的换行符替换为\n text = text.Replace("\r\n", "\n").Replace("\r", "\n"); - // 然后将\n替换为\r\n text = text.Replace("\n", Environment.NewLine); return text; } + private void textBox1_TextChanged(object sender, EventArgs e) + { + //if (string.IsNullOrWhiteSpace(textBox1.Text)) + //{ + // textBox1.Text = !string.IsNullOrEmpty(UrlContentOriginal) + // ? UrlContentOriginal + // : GetDefaultUrlContent(); + + // textBox1.SelectionStart = textBox1.Text.Length; + //} + } + + // 恢复默认值按钮事件 + + private void button5_Click(object sender, EventArgs e) + { + textBox1.Text = GetDefaultUrlContent(); + + MessageBox.Show("已恢复为默认订阅地址。", "操作完成", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } } } diff --git a/Form1.Designer.cs b/Form1.Designer.cs deleted file mode 100644 index ff3352c..0000000 --- a/Form1.Designer.cs +++ /dev/null @@ -1,1546 +0,0 @@ -namespace subs_check.win.gui -{ - partial class Form1 - { - /// - /// 必需的设计器变量。 - /// - private System.ComponentModel.IContainer components = null; - - /// - /// 清理所有正在使用的资源。 - /// - /// 如果应释放托管资源,为 true;否则为 false。 - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows 窗体设计器生成的代码 - - /// - /// 设计器支持所需的方法 - 不要修改 - /// 使用代码编辑器修改此方法的内容。 - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); - this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components); - this.timer1 = new System.Windows.Forms.Timer(this.components); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.checkBox5 = new System.Windows.Forms.CheckBox(); - this.textBox11 = new System.Windows.Forms.TextBox(); - this.button7 = new System.Windows.Forms.Button(); - this.button6 = new System.Windows.Forms.Button(); - this.comboBox4 = new System.Windows.Forms.ComboBox(); - this.button3 = new System.Windows.Forms.Button(); - this.textBox1 = new System.Windows.Forms.TextBox(); - this.comboBox1 = new System.Windows.Forms.ComboBox(); - this.numericUpDown4 = new System.Windows.Forms.NumericUpDown(); - this.numericUpDown3 = new System.Windows.Forms.NumericUpDown(); - this.numericUpDown2 = new System.Windows.Forms.NumericUpDown(); - this.numericUpDown1 = new System.Windows.Forms.NumericUpDown(); - this.label7 = new System.Windows.Forms.Label(); - this.label6 = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); - this.button2 = new System.Windows.Forms.Button(); - this.button1 = new System.Windows.Forms.Button(); - this.label8 = new System.Windows.Forms.Label(); - this.numericUpDown6 = new System.Windows.Forms.NumericUpDown(); - this.numericUpDown5 = new System.Windows.Forms.NumericUpDown(); - this.label4 = new System.Windows.Forms.Label(); - this.label5 = new System.Windows.Forms.Label(); - this.numericUpDown7 = new System.Windows.Forms.NumericUpDown(); - this.label20 = new System.Windows.Forms.Label(); - this.groupBox2 = new System.Windows.Forms.GroupBox(); - this.linkLabel1 = new System.Windows.Forms.LinkLabel(); - this.button5 = new System.Windows.Forms.Button(); - this.richTextBox1 = new System.Windows.Forms.RichTextBox(); - this.groupBox3 = new System.Windows.Forms.GroupBox(); - this.button8 = new System.Windows.Forms.Button(); - this.textBox10 = new System.Windows.Forms.TextBox(); - this.checkBox4 = new System.Windows.Forms.CheckBox(); - this.numericUpDown8 = new System.Windows.Forms.NumericUpDown(); - this.checkBox3 = new System.Windows.Forms.CheckBox(); - this.button4 = new System.Windows.Forms.Button(); - this.checkBox1 = new System.Windows.Forms.CheckBox(); - this.checkBox2 = new System.Windows.Forms.CheckBox(); - this.comboBox5 = new System.Windows.Forms.ComboBox(); - this.label19 = new System.Windows.Forms.Label(); - this.comboBox3 = new System.Windows.Forms.ComboBox(); - this.label10 = new System.Windows.Forms.Label(); - this.comboBox2 = new System.Windows.Forms.ComboBox(); - this.label9 = new System.Windows.Forms.Label(); - this.progressBar1 = new System.Windows.Forms.ProgressBar(); - this.timer2 = new System.Windows.Forms.Timer(this.components); - this.groupBox4 = new System.Windows.Forms.GroupBox(); - this.textBox4 = new System.Windows.Forms.TextBox(); - this.label13 = new System.Windows.Forms.Label(); - this.textBox3 = new System.Windows.Forms.TextBox(); - this.label12 = new System.Windows.Forms.Label(); - this.textBox2 = new System.Windows.Forms.TextBox(); - this.label11 = new System.Windows.Forms.Label(); - this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); - this.groupBox5 = new System.Windows.Forms.GroupBox(); - this.textBox6 = new System.Windows.Forms.TextBox(); - this.label15 = new System.Windows.Forms.Label(); - this.textBox7 = new System.Windows.Forms.TextBox(); - this.label16 = new System.Windows.Forms.Label(); - this.groupBox6 = new System.Windows.Forms.GroupBox(); - this.textBox5 = new System.Windows.Forms.TextBox(); - this.label14 = new System.Windows.Forms.Label(); - this.textBox8 = new System.Windows.Forms.TextBox(); - this.label17 = new System.Windows.Forms.Label(); - this.textBox9 = new System.Windows.Forms.TextBox(); - this.label18 = new System.Windows.Forms.Label(); - this.timer3 = new System.Windows.Forms.Timer(this.components); - this.timer4 = new System.Windows.Forms.Timer(this.components); - this.groupBox1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown4)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown3)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown2)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown6)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown5)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown7)).BeginInit(); - this.groupBox2.SuspendLayout(); - this.groupBox3.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown8)).BeginInit(); - this.groupBox4.SuspendLayout(); - this.groupBox5.SuspendLayout(); - this.groupBox6.SuspendLayout(); - this.SuspendLayout(); - // - // notifyIcon1 - // - this.notifyIcon1.BalloonTipTitle = "Subs-Check"; - this.notifyIcon1.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon1.Icon"))); - this.notifyIcon1.Text = "Subs-Check:未运行"; - this.notifyIcon1.Visible = true; - this.notifyIcon1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon1_MouseClick); - // - // timer1 - // - this.timer1.Enabled = true; - this.timer1.Interval = 1; - this.timer1.Tick += new System.EventHandler(this.timer1_Tick); - // - // groupBox1 - // - this.groupBox1.Controls.Add(this.checkBox5); - this.groupBox1.Controls.Add(this.textBox11); - this.groupBox1.Controls.Add(this.button7); - this.groupBox1.Controls.Add(this.button6); - this.groupBox1.Controls.Add(this.comboBox4); - this.groupBox1.Controls.Add(this.button3); - this.groupBox1.Controls.Add(this.textBox1); - this.groupBox1.Controls.Add(this.comboBox1); - this.groupBox1.Controls.Add(this.numericUpDown4); - this.groupBox1.Controls.Add(this.numericUpDown3); - this.groupBox1.Controls.Add(this.numericUpDown2); - this.groupBox1.Controls.Add(this.numericUpDown1); - this.groupBox1.Controls.Add(this.label7); - this.groupBox1.Controls.Add(this.label6); - this.groupBox1.Controls.Add(this.label3); - this.groupBox1.Controls.Add(this.label2); - this.groupBox1.Controls.Add(this.label1); - this.groupBox1.Controls.Add(this.button2); - this.groupBox1.Controls.Add(this.button1); - this.groupBox1.Controls.Add(this.label8); - this.groupBox1.Location = new System.Drawing.Point(13, 13); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(174, 484); - this.groupBox1.TabIndex = 0; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "参数设置"; - // - // checkBox5 - // - this.checkBox5.AutoSize = true; - this.checkBox5.Location = new System.Drawing.Point(91, 428); - this.checkBox5.Name = "checkBox5"; - this.checkBox5.Size = new System.Drawing.Size(72, 16); - this.checkBox5.TabIndex = 30; - this.checkBox5.Text = "开机自启"; - this.checkBox5.UseVisualStyleBackColor = true; - this.checkBox5.CheckedChanged += new System.EventHandler(this.checkBox5_CheckedChanged); - // - // textBox11 - // - this.textBox11.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.textBox11.Location = new System.Drawing.Point(9, 343); - this.textBox11.Name = "textBox11"; - this.textBox11.Size = new System.Drawing.Size(154, 21); - this.textBox11.TabIndex = 21; - this.textBox11.Text = "0 */2 * * *"; - this.textBox11.Visible = false; - this.textBox11.DoubleClick += new System.EventHandler(this.切换cron表达式); - this.textBox11.Leave += new System.EventHandler(this.textBox11_Leave); - // - // button7 - // - this.button7.Enabled = false; - this.button7.Location = new System.Drawing.Point(7, 399); - this.button7.Name = "button7"; - this.button7.Size = new System.Drawing.Size(75, 23); - this.button7.TabIndex = 30; - this.button7.Text = "🔀未启动"; - this.button7.UseVisualStyleBackColor = true; - this.button7.Click += new System.EventHandler(this.button7_Click); - // - // button6 - // - this.button6.Enabled = false; - this.button6.Location = new System.Drawing.Point(88, 399); - this.button6.Name = "button6"; - this.button6.Size = new System.Drawing.Size(75, 23); - this.button6.TabIndex = 29; - this.button6.Text = "访问WebUI"; - this.button6.UseVisualStyleBackColor = true; - this.button6.Click += new System.EventHandler(this.button6_Click); - // - // comboBox4 - // - this.comboBox4.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.comboBox4.FormattingEnabled = true; - this.comboBox4.Items.AddRange(new object[] { - "通用订阅", - "Clash"}); - this.comboBox4.Location = new System.Drawing.Point(8, 372); - this.comboBox4.Name = "comboBox4"; - this.comboBox4.Size = new System.Drawing.Size(74, 20); - this.comboBox4.TabIndex = 19; - // - // button3 - // - this.button3.Enabled = false; - this.button3.Location = new System.Drawing.Point(88, 370); - this.button3.Name = "button3"; - this.button3.Size = new System.Drawing.Size(75, 23); - this.button3.TabIndex = 18; - this.button3.Text = "复制订阅"; - this.button3.UseVisualStyleBackColor = true; - this.button3.Click += new System.EventHandler(this.button3_Click); - // - // textBox1 - // - this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.textBox1.Location = new System.Drawing.Point(9, 179); - this.textBox1.Multiline = true; - this.textBox1.Name = "textBox1"; - this.textBox1.ReadOnly = true; - this.textBox1.Size = new System.Drawing.Size(154, 185); - this.textBox1.TabIndex = 17; - this.textBox1.Text = resources.GetString("textBox1.Text"); - this.textBox1.WordWrap = false; - this.textBox1.Click += new System.EventHandler(this.textBox1_DoubleClick); - this.textBox1.DoubleClick += new System.EventHandler(this.textBox1_DoubleClick); - // - // comboBox1 - // - this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.comboBox1.FormattingEnabled = true; - this.comboBox1.Items.AddRange(new object[] { - "本地", - "gist", - "r2", - "webdav"}); - this.comboBox1.Location = new System.Drawing.Point(105, 135); - this.comboBox1.Name = "comboBox1"; - this.comboBox1.Size = new System.Drawing.Size(58, 20); - this.comboBox1.TabIndex = 16; - this.comboBox1.TextChanged += new System.EventHandler(this.comboBox1_TextChanged); - // - // numericUpDown4 - // - this.numericUpDown4.Location = new System.Drawing.Point(105, 106); - this.numericUpDown4.Maximum = new decimal(new int[] { - 20480, - 0, - 0, - 0}); - this.numericUpDown4.Minimum = new decimal(new int[] { - 128, - 0, - 0, - 0}); - this.numericUpDown4.Name = "numericUpDown4"; - this.numericUpDown4.Size = new System.Drawing.Size(58, 21); - this.numericUpDown4.TabIndex = 13; - this.numericUpDown4.Value = new decimal(new int[] { - 1024, - 0, - 0, - 0}); - this.numericUpDown4.ValueChanged += new System.EventHandler(this.numericUpDown4_ValueChanged); - // - // numericUpDown3 - // - this.numericUpDown3.Location = new System.Drawing.Point(105, 77); - this.numericUpDown3.Maximum = new decimal(new int[] { - 10000, - 0, - 0, - 0}); - this.numericUpDown3.Minimum = new decimal(new int[] { - 1000, - 0, - 0, - 0}); - this.numericUpDown3.Name = "numericUpDown3"; - this.numericUpDown3.Size = new System.Drawing.Size(58, 21); - this.numericUpDown3.TabIndex = 12; - this.numericUpDown3.Value = new decimal(new int[] { - 5000, - 0, - 0, - 0}); - this.numericUpDown3.ValueChanged += new System.EventHandler(this.numericUpDown3_ValueChanged); - // - // numericUpDown2 - // - this.numericUpDown2.Location = new System.Drawing.Point(105, 48); - this.numericUpDown2.Maximum = new decimal(new int[] { - 1440, - 0, - 0, - 0}); - this.numericUpDown2.Minimum = new decimal(new int[] { - 30, - 0, - 0, - 0}); - this.numericUpDown2.Name = "numericUpDown2"; - this.numericUpDown2.Size = new System.Drawing.Size(58, 21); - this.numericUpDown2.TabIndex = 11; - this.numericUpDown2.Value = new decimal(new int[] { - 120, - 0, - 0, - 0}); - this.numericUpDown2.DoubleClick += new System.EventHandler(this.切换cron表达式); - // - // numericUpDown1 - // - this.numericUpDown1.Location = new System.Drawing.Point(105, 19); - this.numericUpDown1.Maximum = new decimal(new int[] { - 1024, - 0, - 0, - 0}); - this.numericUpDown1.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.numericUpDown1.Name = "numericUpDown1"; - this.numericUpDown1.Size = new System.Drawing.Size(58, 21); - this.numericUpDown1.TabIndex = 10; - this.numericUpDown1.Value = new decimal(new int[] { - 32, - 0, - 0, - 0}); - this.numericUpDown1.ValueChanged += new System.EventHandler(this.numericUpDown1_ValueChanged); - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(7, 137); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(65, 12); - this.label7.TabIndex = 8; - this.label7.Text = "保存方法:"; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(7, 108); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(101, 12); - this.label6.TabIndex = 5; - this.label6.Text = "测速下限(KB/s):"; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(7, 79); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(101, 12); - this.label3.TabIndex = 4; - this.label3.Text = "超时时间(毫秒):"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(7, 50); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(101, 12); - this.label2.TabIndex = 3; - this.label2.Text = "检查间隔(分钟):"; - this.label2.DoubleClick += new System.EventHandler(this.切换cron表达式); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(7, 21); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(77, 12); - this.label1.TabIndex = 2; - this.label1.Text = "并发线程数:"; - // - // button2 - // - this.button2.Location = new System.Drawing.Point(88, 450); - this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(75, 23); - this.button2.TabIndex = 1; - this.button2.Text = "高级设置∧"; - this.button2.UseVisualStyleBackColor = true; - this.button2.Click += new System.EventHandler(this.button2_Click); - // - // button1 - // - this.button1.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.button1.Location = new System.Drawing.Point(7, 428); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 45); - this.button1.TabIndex = 0; - this.button1.Text = "▶️ 启动"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // label8 - // - this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(7, 164); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(161, 12); - this.label8.TabIndex = 9; - this.label8.Text = "节点池订阅链接(点击编辑):"; - this.label8.Click += new System.EventHandler(this.textBox1_DoubleClick); - // - // numericUpDown6 - // - this.numericUpDown6.Location = new System.Drawing.Point(281, 19); - this.numericUpDown6.Maximum = new decimal(new int[] { - 65535, - 0, - 0, - 0}); - this.numericUpDown6.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.numericUpDown6.Name = "numericUpDown6"; - this.numericUpDown6.Size = new System.Drawing.Size(58, 21); - this.numericUpDown6.TabIndex = 15; - this.numericUpDown6.Value = new decimal(new int[] { - 8199, - 0, - 0, - 0}); - this.numericUpDown6.ValueChanged += new System.EventHandler(this.numericUpDown6_ValueChanged); - // - // numericUpDown5 - // - this.numericUpDown5.Location = new System.Drawing.Point(281, 45); - this.numericUpDown5.Maximum = new decimal(new int[] { - 10, - 0, - 0, - 0}); - this.numericUpDown5.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.numericUpDown5.Name = "numericUpDown5"; - this.numericUpDown5.Size = new System.Drawing.Size(58, 21); - this.numericUpDown5.TabIndex = 14; - this.numericUpDown5.Value = new decimal(new int[] { - 10, - 0, - 0, - 0}); - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(191, 21); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(89, 12); - this.label4.TabIndex = 7; - this.label4.Text = "HTTP服务端口:"; - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(191, 48); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(89, 12); - this.label5.TabIndex = 6; - this.label5.Text = "测速时间(秒):"; - // - // numericUpDown7 - // - this.numericUpDown7.Location = new System.Drawing.Point(441, 19); - this.numericUpDown7.Maximum = new decimal(new int[] { - 65535, - 0, - 0, - 0}); - this.numericUpDown7.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.numericUpDown7.Name = "numericUpDown7"; - this.numericUpDown7.Size = new System.Drawing.Size(58, 21); - this.numericUpDown7.TabIndex = 21; - this.numericUpDown7.Value = new decimal(new int[] { - 8299, - 0, - 0, - 0}); - this.numericUpDown7.ValueChanged += new System.EventHandler(this.numericUpDown6_ValueChanged); - // - // label20 - // - this.label20.AutoSize = true; - this.label20.Location = new System.Drawing.Point(345, 21); - this.label20.Name = "label20"; - this.label20.Size = new System.Drawing.Size(95, 12); - this.label20.TabIndex = 20; - this.label20.Text = "Sub-Store端口:"; - // - // groupBox2 - // - this.groupBox2.Controls.Add(this.linkLabel1); - this.groupBox2.Controls.Add(this.button5); - this.groupBox2.Controls.Add(this.richTextBox1); - this.groupBox2.Location = new System.Drawing.Point(193, 13); - this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(600, 484); - this.groupBox2.TabIndex = 1; - this.groupBox2.TabStop = false; - this.groupBox2.Text = "实时日志"; - // - // linkLabel1 - // - this.linkLabel1.AutoSize = true; - this.linkLabel1.Location = new System.Drawing.Point(460, 2); - this.linkLabel1.Name = "linkLabel1"; - this.linkLabel1.Size = new System.Drawing.Size(137, 12); - this.linkLabel1.TabIndex = 21; - this.linkLabel1.TabStop = true; - this.linkLabel1.Text = "关于 SubsCheck Win GUI"; - this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); - // - // button5 - // - this.button5.Location = new System.Drawing.Point(515, 450); - this.button5.Name = "button5"; - this.button5.Size = new System.Drawing.Size(75, 23); - this.button5.TabIndex = 20; - this.button5.Text = "更新内核"; - this.button5.UseVisualStyleBackColor = true; - this.button5.Visible = false; - this.button5.Click += new System.EventHandler(this.button5_Click); - // - // richTextBox1 - // - this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill; - this.richTextBox1.Location = new System.Drawing.Point(3, 17); - this.richTextBox1.Name = "richTextBox1"; - this.richTextBox1.ReadOnly = true; - this.richTextBox1.Size = new System.Drawing.Size(594, 464); - this.richTextBox1.TabIndex = 0; - this.richTextBox1.Text = ""; - this.richTextBox1.DoubleClick += new System.EventHandler(this.richTextBox1_DoubleClick); - // - // groupBox3 - // - this.groupBox3.Controls.Add(this.button8); - this.groupBox3.Controls.Add(this.textBox10); - this.groupBox3.Controls.Add(this.checkBox4); - this.groupBox3.Controls.Add(this.numericUpDown8); - this.groupBox3.Controls.Add(this.checkBox3); - this.groupBox3.Controls.Add(this.button4); - this.groupBox3.Controls.Add(this.checkBox1); - this.groupBox3.Controls.Add(this.numericUpDown6); - this.groupBox3.Controls.Add(this.checkBox2); - this.groupBox3.Controls.Add(this.numericUpDown5); - this.groupBox3.Controls.Add(this.comboBox5); - this.groupBox3.Controls.Add(this.label19); - this.groupBox3.Controls.Add(this.comboBox3); - this.groupBox3.Controls.Add(this.label10); - this.groupBox3.Controls.Add(this.label4); - this.groupBox3.Controls.Add(this.comboBox2); - this.groupBox3.Controls.Add(this.label9); - this.groupBox3.Controls.Add(this.label5); - this.groupBox3.Controls.Add(this.numericUpDown7); - this.groupBox3.Controls.Add(this.label20); - this.groupBox3.Location = new System.Drawing.Point(13, 503); - this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(780, 103); - this.groupBox3.TabIndex = 2; - this.groupBox3.TabStop = false; - this.groupBox3.Text = "高级设置"; - this.groupBox3.Visible = false; - // - // button8 - // - this.button8.Location = new System.Drawing.Point(695, 43); - this.button8.Name = "button8"; - this.button8.Size = new System.Drawing.Size(75, 23); - this.button8.TabIndex = 29; - this.button8.Text = "补充参数"; - this.button8.UseVisualStyleBackColor = true; - this.button8.Click += new System.EventHandler(this.button8_Click); - // - // textBox10 - // - this.textBox10.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.textBox10.Enabled = false; - this.textBox10.Location = new System.Drawing.Point(141, 73); - this.textBox10.Name = "textBox10"; - this.textBox10.PasswordChar = '*'; - this.textBox10.Size = new System.Drawing.Size(110, 21); - this.textBox10.TabIndex = 6; - this.textBox10.Text = "admin"; - this.textBox10.Enter += new System.EventHandler(this.textBox10_Enter); - this.textBox10.Leave += new System.EventHandler(this.textBox10_Leave); - // - // checkBox4 - // - this.checkBox4.AutoSize = true; - this.checkBox4.Location = new System.Drawing.Point(9, 75); - this.checkBox4.Name = "checkBox4"; - this.checkBox4.Size = new System.Drawing.Size(138, 16); - this.checkBox4.TabIndex = 28; - this.checkBox4.Text = "启用WebUI API密钥:"; - this.checkBox4.UseVisualStyleBackColor = true; - this.checkBox4.CheckedChanged += new System.EventHandler(this.checkBox4_CheckedChanged); - // - // numericUpDown8 - // - this.numericUpDown8.Enabled = false; - this.numericUpDown8.Location = new System.Drawing.Point(122, 45); - this.numericUpDown8.Maximum = new decimal(new int[] { - 65535, - 0, - 0, - 0}); - this.numericUpDown8.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.numericUpDown8.Name = "numericUpDown8"; - this.numericUpDown8.Size = new System.Drawing.Size(58, 21); - this.numericUpDown8.TabIndex = 22; - this.numericUpDown8.Value = new decimal(new int[] { - 100, - 0, - 0, - 0}); - // - // checkBox3 - // - this.checkBox3.AutoSize = true; - this.checkBox3.Location = new System.Drawing.Point(9, 48); - this.checkBox3.Name = "checkBox3"; - this.checkBox3.Size = new System.Drawing.Size(108, 16); - this.checkBox3.TabIndex = 27; - this.checkBox3.Text = "节点保存数目:"; - this.checkBox3.UseVisualStyleBackColor = true; - this.checkBox3.CheckedChanged += new System.EventHandler(this.checkBox3_CheckedChanged); - // - // button4 - // - this.button4.Location = new System.Drawing.Point(695, 71); - this.button4.Name = "button4"; - this.button4.Size = new System.Drawing.Size(75, 23); - this.button4.TabIndex = 26; - this.button4.Text = "检查更新"; - this.button4.UseVisualStyleBackColor = true; - this.button4.Click += new System.EventHandler(this.button4_Click); - // - // checkBox1 - // - this.checkBox1.AutoSize = true; - this.checkBox1.Checked = true; - this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkBox1.Location = new System.Drawing.Point(9, 20); - this.checkBox1.Name = "checkBox1"; - this.checkBox1.Size = new System.Drawing.Size(96, 16); - this.checkBox1.TabIndex = 22; - this.checkBox1.Text = "节点地址查询"; - this.checkBox1.UseVisualStyleBackColor = true; - this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged); - // - // checkBox2 - // - this.checkBox2.AutoSize = true; - this.checkBox2.Location = new System.Drawing.Point(106, 20); - this.checkBox2.Name = "checkBox2"; - this.checkBox2.Size = new System.Drawing.Size(84, 16); - this.checkBox2.TabIndex = 25; - this.checkBox2.Text = "流媒体检测"; - this.checkBox2.UseVisualStyleBackColor = true; - this.checkBox2.CheckedChanged += new System.EventHandler(this.checkBox2_CheckedChanged); - // - // comboBox5 - // - this.comboBox5.FormattingEnabled = true; - this.comboBox5.Items.AddRange(new object[] { - "[内置]布丁狗的订阅转换", - "[内置]ACL4SSR_Online_Full", - "https://raw.githubusercontent.com/mihomo-party-org/override-hub/main/yaml/布丁狗的订阅转" + - "换.yaml", - "https://raw.githubusercontent.com/mihomo-party-org/override-hub/main/yaml/ACL4SSR" + - "_Online_Full.yaml", - "https://raw.githubusercontent.com/mihomo-party-org/override-hub/main/yaml/ACL4SSR" + - "_Online_Full_WithIcon.yaml", - "https://raw.githubusercontent.com/mihomo-party-org/override-hub/main/yaml/添加直连规则." + - "yaml", - "https://fastly.jsdelivr.net/gh/mihomo-party-org/override-hub@main/yaml/布丁狗的订阅转换.y" + - "aml", - "https://fastly.jsdelivr.net/gh/mihomo-party-org/override-hub@main/yaml/ACL4SSR_On" + - "line_Full.yaml", - "https://fastly.jsdelivr.net/gh/mihomo-party-org/override-hub@main/yaml/ACL4SSR_On" + - "line_Full_WithIcon.yaml", - "https://fastly.jsdelivr.net/gh/mihomo-party-org/override-hub@main/yaml/添加直连规则.yam" + - "l"}); - this.comboBox5.Location = new System.Drawing.Point(414, 73); - this.comboBox5.Name = "comboBox5"; - this.comboBox5.Size = new System.Drawing.Size(275, 20); - this.comboBox5.TabIndex = 24; - this.comboBox5.SelectedIndexChanged += new System.EventHandler(this.comboBox5_SelectedIndexChanged); - // - // label19 - // - this.label19.AutoSize = true; - this.label19.Location = new System.Drawing.Point(260, 76); - this.label19.Name = "label19"; - this.label19.Size = new System.Drawing.Size(149, 12); - this.label19.TabIndex = 23; - this.label19.Text = "Clash订阅 覆写配置文件:"; - // - // comboBox3 - // - this.comboBox3.FormattingEnabled = true; - this.comboBox3.Items.AddRange(new object[] { - "自动选择", - "1.github.010716.xyz", - "113355.kabaka.xyz", - "80888888.xyz", - "aa.w0x7ce.eu", - "acc.meiqer.com", - "api-ghp.fjy.zone", - "armg1.jyhk.tk", - "armg2.jyhk.tk", - "b.yesican.top", - "bakht1.jsdelivr.fyi", - "bakht2.jsdelivr.fyi", - "bakht3.jsdelivr.fyi", - "booster.ookkk.ggff.net", - "c.gatepro.cn", - "cc.ikakatoo.us", - "ccgit1.5gyh.cf", - "ccgit2.5gyh.cf", - "cdn-gh.141888.xyz", - "cfghproxy.165683.xyz", - "chirophy.online", - "choner.eu.org", - "d.scyun.top", - "daili.6dot.cn", - "dh.guluy.top", - "dh.jeblove.com", - "dl.github.mirror.shalo.link", - "dnsvip.uk", - "docker.bkxhkoo.com", - "docker.ppp.ac.cn", - "down.avi.gs", - "download.ojbk.one", - "download.serein.cc", - "f.shenbing.nyc.mn", - "fastgithub.starryfun.icu", - "file.justgame.top", - "ft.v1k1.xin", - "fuck-flow.nobige.cn", - "g.108964.xyz", - "g.blfrp.cn", - "g.bravexist.cn", - "g.down.0ms.net", - "g.jscdn.cn", - "g.yeyuqiufeng.cn", - "gh.136361.xyz", - "gh.13x.plus", - "gh.19121912.xyz", - "gh.193.gs", - "gh.220106.xyz", - "gh.222322.xyz", - "gh.244224659.xyz", - "gh.2i.gs", - "gh.316688.xyz", - "gh.321122.xyz", - "gh.334433.xyz", - "gh.39.al", - "gh.518298.xyz", - "gh.52099520.xyz", - "gh.654535.xyz", - "gh.777000.best", - "gh.799154.xyz", - "gh.860686.xyz", - "gh.8p.gs", - "gh.960980.xyz", - "gh.accn.eu.org", - "gh.amirrors.com", - "gh.andiest.com", - "gh.aurzex.top", - "gh.avmine.com", - "gh.b52m.cn", - "gh.bhexo.cn", - "gh.cdn.fullcone.cn", - "gh.chewable.eu.org", - "gh.chillwaytech.com", - "gh.cnbattle.com", - "gh.crond.dev", - "gh.dev.438250.xyz", - "gh.duang.io", - "gh.duckcc.com", - "gh.dwsy.link", - "gh.ecdn.ip-ddns.com", - "gh.flewsea.news", - "gh.flewsea.pw", - "gh.flyrr.cc", - "gh.gongyi.tk", - "gh.gorun.eu.org", - "gh.gxb.pub", - "gh.haloless.com", - "gh.heshiheng.top", - "gh.hitcs.cc", - "gh.i3.pw", - "gh.ibridge.eu.org", - "gh.iinx.top", - "gh.j8.work", - "gh.jadelive.top", - "gh.jscdn.cn", - "gh.jxq.io", - "gh.kejilion.pro", - "gh.kemon.ai", - "gh.kmxm.online", - "gh.lib.cx", - "gh.lkwplus.com", - "gh.lux1983.com", - "gh.luzy.top", - "gh.lyh.moe", - "gh.miaomiao.video", - "gh.micedns.cloudns.org", - "gh.mirror.190211.xyz", - "gh.mirror.coolfeature.top", - "gh.moetools.net", - "gh.momonomi.xyz", - "gh.mrskye.cn", - "gh.mtx72.cc", - "gh.nekhill.top", - "gh.nekorect.eu.org", - "gh.nextfuture.top", - "gh.oevery.me", - "gh.oneproxy.top", - "gh.opsproxy.com", - "gh.osspub.cn", - "gh.padao.fun", - "gh.prlrr.com", - "gh.pylas.xyz", - "gh.qptf.eu.org", - "gh.qsd.onl", - "gh.qsq.one", - "gh.rem.asia", - "gh.riye.de", - "gh.scy.ink", - "gh.someo.top", - "gh.stanl.ee", - "gh.stewitch.com", - "gh.suite.eu.org", - "gh.tbw.wiki", - "gh.tou.lu", - "gh.tryxd.cn", - "gh.uclort.com", - "gh.wglee.org", - "gh.wowforever.xyz", - "gh.wuuu.cc", - "gh.wwang.de", - "gh.wygg.us.kg", - "gh.xbzza.cn", - "gh.xda.plus", - "gh.yahool.com.cn", - "gh.yushum.com", - "ghac.760710.xyz", - "ghacc.cpuhk.eu.org", - "ghb.wglee.org", - "gh-boost.oneboy.app", - "gh-deno.mocn.top", - "ghfast.top", - "ghjs.131412.eu.org", - "ghp.618032.xyz", - "ghp.9e6.site", - "ghp.dnsplus.uk", - "ghp.fit2.fun", - "ghp.imc.re", - "ghp.jokeme.top", - "ghp.lanchonghai.com", - "ghp.miaostay.com", - "ghp.opendatahub.xyz", - "ghp.pbren.com", - "ghp.src.moe", - "ghp.tryanks.com", - "ghp.vatery.com", - "ghp.xiaopan.ai", - "ghp.ybot.xin", - "ghp.yeye.f5.si", - "ghproxy.0081024.xyz", - "ghproxy.053000.xyz", - "ghproxy.200502.xyz", - "ghproxy.943689.xyz", - "ghproxy.alltobid.cc", - "ghproxy.amayakite.xyz", - "ghproxy.bugungu.top", - "gh-proxy.dorz.tech", - "ghproxy.dsdog.tk", - "ghproxy.ducknet.work", - "ghproxy.gopher.ink", - "ghproxy.gpnu.org", - "ghproxy.hoshizukimio.top", - "gh-proxy.iflyelf.com", - "ghproxy.imoyuapp.win", - "gh-proxy.jacksixth.top", - "gh-proxy.jmper.me", - "ghproxy.joylian.com", - "gh-proxy.just520.top", - "ghproxy.licardo.vip", - "gh-proxy.mereith.com", - "ghproxy.minge.dev", - "ghproxy.missfuture.eu.org", - "ghproxy.moweilong.com", - "ghproxy.nanakorobi.com", - "ghproxy.net", - "gh-proxy.not.icu", - "ghproxy.ownyuan.top", - "gh-proxy.rxliuli.com", - "ghproxy.sakuramoe.dev", - "ghproxy.smallfawn.work", - "ghproxy.sveir.xyz", - "ghproxy.temoa.fun", - "ghproxy.thefoxnet.com", - "ghproxy.tracemouse.top", - "ghproxy.txq.life", - "ghproxy.viper.pub", - "ghproxy.vyronlee-lab.com", - "ghproxy.weizhiwen.net", - "ghproxy.wjsphy.top", - "ghproxy.workers.haoutil.com", - "ghproxy.xiaohei-studio-chatgpt-proxy.com.cn", - "gh-proxy.yuntao.me", - "git.1999111.xyz", - "git.22345678.xyz", - "git.40609891.xyz", - "git.5gyh.cf", - "git.988896.xyz", - "git.aaltozz.info", - "git.acap.cc", - "git.amoluo.win", - "git.anye.in", - "git.binbow.link", - "git.blaow.cloudns.org", - "git.closersyu.top", - "git.ifso.site", - "git.imvery.moe", - "git.ixdd.de", - "git.ldvx.de", - "git.lincloud.pro", - "git.liunasc.xyz", - "git.llvho.com", - "git.loushi.site", - "git.lzzz.ink", - "git.maomao.ovh", - "git.mokoc.live", - "git.niege.app", - "git.nyar.work", - "git.o8.cx", - "git.outtw.com", - "git.ppp.ac.cn", - "git.repcz.link", - "git.txaff.com", - "git.verynb.org", - "git.wsl.icu", - "git.wyy.sh", - "git.xiny.eu.org", - "git.xuantan.icu", - "git.zlong.eu.org", - "git3.openapi.site", - "git-clone.ccrui.dev", - "github.08050611.xyz", - "github.143760.xyz", - "github.170011.xyz", - "github.17263241.xyz", - "github.180280.xyz", - "github.197909.xyz", - "github.19890821.xyz", - "github.201068.xyz", - "github.333033.xyz", - "github.4240333.xyz", - "github.564456.xyz", - "github.732086.xyz", - "github.776884.xyz", - "github.789056.xyz", - "github.818668.xyz", - "github.8void.sbs", - "github.9394961.xyz", - "github.960118.xyz", - "github.abyss.moe", - "github.atzzz.com", - "github.axcio.dns-dynamic.net", - "github.boki.moe", - "github.boringhex.top", - "github.bullb.net", - "github.c1g.top", - "github.cf.xihale.top", - "github.chasun.top", - "github.chuancey.eu.org", - "github.cnxiaobai.com", - "github.computerqwq.top", - "github.cswklt.top", - "github.ctios.cn", - "github.ddlink.asia", - "github.dockerspeed.site", - "github.eejsq.net", - "github.ffffffff0x.com", - "github.gdzja.site", - "github.haodiy.xyz", - "github.hhh.sd", - "github.hi.edu.rs", - "github.hostscc.top", - "github.hx208.top", - "github.ilxyz.xyz", - "github.intellisensing.tech", - "github.jerryliang.win", - "github.jimmyshjj.top", - "github.jinenyy.vip", - "github.jscdn.cn", - "github.kidos.top", - "github.kuugo.top", - "github.lao.plus", - "github.mayx.eu.org", - "github.mirror.qlnu-sec.cn", - "github.mirror.vurl.eu.org", - "github.mirrors.hikafeng.com", - "github.mistudio.top", - "github.orangbus.cn", - "github.pipers.cn", - "github.proxy.zerozone.tech", - "github.pxy.lnsee.com", - "github.quickso.net", - "github.ruxi.org", - "github.sagolu.top", - "github.serein.cc", - "github.snakexgc.com", - "github.space520.eu.org", - "github.sssss.work", - "github.static.cv", - "github.suyijun.top", - "github.try255.com", - "github.unipus.site", - "github.verynb.org", - "github.vipchanel.com", - "github.widiazine.top", - "github.workers.lv10.ren", - "github.workersnail.com", - "github.xin-yu.cloud", - "github.xiongmx.com", - "github.xwb009.xyz", - "github.xxlab.tech", - "github.xxqq.de", - "github.xykcloud.com", - "github.yeep6.eu.org", - "github.ylyhtools.top", - "github.yoloarea.com", - "github.yunfile.fun", - "github.zhaolele.top", - "github.zhou2008.cn", - "github.zhulin240520.buzz", - "github.zyhmifan.top", - "githubacc.caiaiwan.com", - "githubapi.jjchizha.com", - "githubgo.856798.xyz", - "github-proxy.ai-lulu.top", - "github-proxy.caoayu.top", - "github-proxy.explorexd.uk", - "github-proxy.fjiabinc.cn", - "github-proxy.sharefree.site", - "githubproxy.unix.do", - "github-quick.1ms.dev", - "github-raw-download.nekhill.top", - "githubsg.lilyya.top", - "gitproxy.mrhjx.cn", - "gitproxy.ozoo.top", - "godlike.ezpull.top", - "gp.19841106.xyz", - "gp.dahe.now.cc", - "gp.daxei.now.cc", - "g-p.loli.us", - "gp.ownorigin.top", - "gt.changqqq.xyz", - "gxb.pub", - "hay.uxio.cn", - "hg.19840228.top", - "hh.newhappy.cf", - "hk.114914.xyz", - "hub.12138.3653655.xyz", - "hub.326998.xyz", - "hub.885666.xyz", - "hub.fnas64.xin", - "hub.jeblove.com", - "hub.naloong.de", - "hub.vps.861020.xyz", - "hub.vvn.me", - "hub.why-ing.top", - "hub.xjl.ch", - "jh.ussh.net", - "jias.ayanjiu.top", - "jiasu.iwtriptqt1016.eu.org", - "jiasughapi.lingjun.cc", - "jiasuqi.167889.xyz", - "jisuan.xyz", - "js.wd666.cloudns.biz", - "l0l0l.cc", - "m.seafood.loan", - "mc.cn.eu.org", - "mdv.162899.xyz", - "micromatrix.gq", - "mip.cnzzla.com", - "my.iiso.site", - "my.losesw.live", - "mygh.api.xiaomao.eu.org", - "nav.253874.net", - "nav.cxycsx.vip", - "nav.gjcloak.xyz", - "nav.hgd1999.com", - "nav.hoiho.cn", - "nav.syss.fun", - "nav.tossp.com", - "nav.wxapp.xyz", - "nav.yyxw.tk", - "navs.itmax.cn", - "neoz.chat", - "noad.keliyan.top", - "node2.txq.life", - "or.tianba.eu.org", - "p.jackyu.cn", - "privateghproxy.iil.im", - "proxy.191027.xyz", - "proxy.atoposs.com", - "proxy.ccc8.vip", - "proxy.dragontea.cc", - "proxy.fakups.cn", - "proxydl.lcayun.cn", - "proxy-gh.1l1.icu", - "q-github.cnxiaobai.com", - "ql.l50.top", - "raw.nmd.im", - "rst.567812.xyz", - "static.kaixinwu.vip", - "static.yiwangmeng.com", - "t.992699.xyz", - "tpe.corpa.me", - "tube.20140301.xyz", - "vps.pansen626.com", - "wfgithub.xiaonuomi.ie.eu.org"}); - this.comboBox3.Location = new System.Drawing.Point(600, 19); - this.comboBox3.Name = "comboBox3"; - this.comboBox3.Size = new System.Drawing.Size(170, 20); - this.comboBox3.TabIndex = 21; - this.comboBox3.Leave += new System.EventHandler(this.comboBox3_Leave); - // - // label10 - // - this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(505, 21); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(89, 12); - this.label10.TabIndex = 20; - this.label10.Text = "Github Proxy:"; - // - // comboBox2 - // - this.comboBox2.FormattingEnabled = true; - this.comboBox2.Items.AddRange(new object[] { - "https://github.com/AaronFeng753/Waifu2x-Extension-GUI/releases/download/v2.21.12/" + - "Waifu2x-Extension-GUI-v2.21.12-Portable.7z", - "https://github.com/2dust/v2rayN/releases/download/7.10.4/v2rayN-windows-64-deskto" + - "p.zip", - "https://github.com/VSCodium/vscodium/releases/download/1.98.0.25067/codium-1.98.0" + - ".25067-el9.aarch64.rpm"}); - this.comboBox2.Location = new System.Drawing.Point(414, 45); - this.comboBox2.Name = "comboBox2"; - this.comboBox2.Size = new System.Drawing.Size(275, 20); - this.comboBox2.TabIndex = 19; - this.comboBox2.Text = "https://github.com/AaronFeng753/Waifu2x-Extension-GUI/releases/download/v2.21.12/" + - "Waifu2x-Extension-GUI-v2.21.12-Portable.7z"; - // - // label9 - // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(344, 48); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(65, 12); - this.label9.TabIndex = 18; - this.label9.Text = "测速地址:"; - // - // progressBar1 - // - this.progressBar1.Location = new System.Drawing.Point(13, 3); - this.progressBar1.Name = "progressBar1"; - this.progressBar1.Size = new System.Drawing.Size(780, 3); - this.progressBar1.TabIndex = 3; - // - // timer2 - // - this.timer2.Interval = 2000; - this.timer2.Tick += new System.EventHandler(this.timer2_Tick); - // - // groupBox4 - // - this.groupBox4.Controls.Add(this.textBox4); - this.groupBox4.Controls.Add(this.label13); - this.groupBox4.Controls.Add(this.textBox3); - this.groupBox4.Controls.Add(this.label12); - this.groupBox4.Controls.Add(this.textBox2); - this.groupBox4.Controls.Add(this.label11); - this.groupBox4.Location = new System.Drawing.Point(13, 612); - this.groupBox4.Name = "groupBox4"; - this.groupBox4.Size = new System.Drawing.Size(780, 51); - this.groupBox4.TabIndex = 4; - this.groupBox4.TabStop = false; - this.groupBox4.Text = "Gist 上传参数"; - this.groupBox4.Visible = false; - // - // textBox4 - // - this.textBox4.Location = new System.Drawing.Point(467, 18); - this.textBox4.Name = "textBox4"; - this.textBox4.Size = new System.Drawing.Size(306, 21); - this.textBox4.TabIndex = 5; - // - // label13 - // - this.label13.AutoSize = true; - this.label13.Location = new System.Drawing.Point(359, 21); - this.label13.Name = "label13"; - this.label13.Size = new System.Drawing.Size(113, 12); - this.label13.TabIndex = 4; - this.label13.Text = "API Mirror(可选):"; - // - // textBox3 - // - this.textBox3.Location = new System.Drawing.Point(253, 18); - this.textBox3.Name = "textBox3"; - this.textBox3.PasswordChar = '*'; - this.textBox3.Size = new System.Drawing.Size(100, 21); - this.textBox3.TabIndex = 3; - this.textBox3.Enter += new System.EventHandler(this.textBox3_Enter); - this.textBox3.Leave += new System.EventHandler(this.textBox3_Leave); - // - // label12 - // - this.label12.AutoSize = true; - this.label12.Location = new System.Drawing.Point(168, 21); - this.label12.Name = "label12"; - this.label12.Size = new System.Drawing.Size(89, 12); - this.label12.TabIndex = 2; - this.label12.Text = "Github Token:"; - // - // textBox2 - // - this.textBox2.Location = new System.Drawing.Point(62, 18); - this.textBox2.Name = "textBox2"; - this.textBox2.Size = new System.Drawing.Size(100, 21); - this.textBox2.TabIndex = 1; - // - // label11 - // - this.label11.AutoSize = true; - this.label11.Location = new System.Drawing.Point(7, 21); - this.label11.Name = "label11"; - this.label11.Size = new System.Drawing.Size(59, 12); - this.label11.TabIndex = 0; - this.label11.Text = "Gist ID:"; - // - // toolTip1 - // - this.toolTip1.AutoPopDelay = 5000; - this.toolTip1.InitialDelay = 500; - this.toolTip1.ReshowDelay = 500; - this.toolTip1.ShowAlways = true; - // - // groupBox5 - // - this.groupBox5.Controls.Add(this.textBox6); - this.groupBox5.Controls.Add(this.label15); - this.groupBox5.Controls.Add(this.textBox7); - this.groupBox5.Controls.Add(this.label16); - this.groupBox5.Location = new System.Drawing.Point(13, 669); - this.groupBox5.Name = "groupBox5"; - this.groupBox5.Size = new System.Drawing.Size(780, 51); - this.groupBox5.TabIndex = 6; - this.groupBox5.TabStop = false; - this.groupBox5.Text = "R2 上传参数"; - this.groupBox5.Visible = false; - // - // textBox6 - // - this.textBox6.Location = new System.Drawing.Point(467, 18); - this.textBox6.Name = "textBox6"; - this.textBox6.PasswordChar = '*'; - this.textBox6.Size = new System.Drawing.Size(306, 21); - this.textBox6.TabIndex = 3; - this.textBox6.Text = "1234567890"; - this.textBox6.Enter += new System.EventHandler(this.textBox3_Enter); - this.textBox6.Leave += new System.EventHandler(this.textBox3_Leave); - // - // label15 - // - this.label15.AutoSize = true; - this.label15.Location = new System.Drawing.Point(382, 21); - this.label15.Name = "label15"; - this.label15.Size = new System.Drawing.Size(89, 12); - this.label15.TabIndex = 2; - this.label15.Text = "Worker Token:"; - // - // textBox7 - // - this.textBox7.Location = new System.Drawing.Point(88, 18); - this.textBox7.Name = "textBox7"; - this.textBox7.Size = new System.Drawing.Size(285, 21); - this.textBox7.TabIndex = 1; - this.textBox7.Text = "https://example.worker.dev"; - this.textBox7.Leave += new System.EventHandler(this.textBox7_Leave); - // - // label16 - // - this.label16.AutoSize = true; - this.label16.Location = new System.Drawing.Point(7, 21); - this.label16.Name = "label16"; - this.label16.Size = new System.Drawing.Size(77, 12); - this.label16.TabIndex = 0; - this.label16.Text = "Worker URL:"; - // - // groupBox6 - // - this.groupBox6.Controls.Add(this.textBox5); - this.groupBox6.Controls.Add(this.label14); - this.groupBox6.Controls.Add(this.textBox8); - this.groupBox6.Controls.Add(this.label17); - this.groupBox6.Controls.Add(this.textBox9); - this.groupBox6.Controls.Add(this.label18); - this.groupBox6.Location = new System.Drawing.Point(13, 726); - this.groupBox6.Name = "groupBox6"; - this.groupBox6.Size = new System.Drawing.Size(780, 51); - this.groupBox6.TabIndex = 6; - this.groupBox6.TabStop = false; - this.groupBox6.Text = "Webdav 上传参数"; - this.groupBox6.Visible = false; - // - // textBox5 - // - this.textBox5.Location = new System.Drawing.Point(467, 18); - this.textBox5.Name = "textBox5"; - this.textBox5.Size = new System.Drawing.Size(306, 21); - this.textBox5.TabIndex = 5; - this.textBox5.Text = "https://example.com/dav/"; - // - // label14 - // - this.label14.AutoSize = true; - this.label14.Location = new System.Drawing.Point(382, 21); - this.label14.Name = "label14"; - this.label14.Size = new System.Drawing.Size(77, 12); - this.label14.TabIndex = 4; - this.label14.Text = "Webdav URL:"; - // - // textBox8 - // - this.textBox8.Location = new System.Drawing.Point(257, 18); - this.textBox8.Name = "textBox8"; - this.textBox8.PasswordChar = '*'; - this.textBox8.Size = new System.Drawing.Size(110, 21); - this.textBox8.TabIndex = 3; - this.textBox8.Text = "admin"; - this.textBox8.Enter += new System.EventHandler(this.textBox3_Enter); - this.textBox8.Leave += new System.EventHandler(this.textBox3_Leave); - // - // label17 - // - this.label17.AutoSize = true; - this.label17.Location = new System.Drawing.Point(186, 21); - this.label17.Name = "label17"; - this.label17.Size = new System.Drawing.Size(65, 12); - this.label17.TabIndex = 2; - this.label17.Text = "Password:"; - // - // textBox9 - // - this.textBox9.Location = new System.Drawing.Point(70, 18); - this.textBox9.Name = "textBox9"; - this.textBox9.Size = new System.Drawing.Size(110, 21); - this.textBox9.TabIndex = 1; - this.textBox9.Text = "admin"; - // - // label18 - // - this.label18.AutoSize = true; - this.label18.Location = new System.Drawing.Point(7, 21); - this.label18.Name = "label18"; - this.label18.Size = new System.Drawing.Size(65, 12); - this.label18.TabIndex = 0; - this.label18.Text = "Username:"; - // - // timer3 - // - this.timer3.Interval = 86400000; - this.timer3.Tick += new System.EventHandler(this.timer3_Tick); - // - // timer4 - // - this.timer4.Interval = 1000; - this.timer4.Tick += new System.EventHandler(this.timer4_Tick); - // - // Form1 - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSize = true; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.ClientSize = new System.Drawing.Size(800, 784); - this.Controls.Add(this.groupBox6); - this.Controls.Add(this.groupBox5); - this.Controls.Add(this.groupBox4); - this.Controls.Add(this.groupBox3); - this.Controls.Add(this.groupBox2); - this.Controls.Add(this.groupBox1); - this.Controls.Add(this.progressBar1); - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.MaximizeBox = false; - this.Name = "Form1"; - this.Text = "SubsCheck Win GUI"; - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown4)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown3)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown2)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown6)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown5)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown7)).EndInit(); - this.groupBox2.ResumeLayout(false); - this.groupBox2.PerformLayout(); - this.groupBox3.ResumeLayout(false); - this.groupBox3.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown8)).EndInit(); - this.groupBox4.ResumeLayout(false); - this.groupBox4.PerformLayout(); - this.groupBox5.ResumeLayout(false); - this.groupBox5.PerformLayout(); - this.groupBox6.ResumeLayout(false); - this.groupBox6.PerformLayout(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.NotifyIcon notifyIcon1; - private System.Windows.Forms.Timer timer1; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.GroupBox groupBox2; - private System.Windows.Forms.Button button2; - private System.Windows.Forms.Button button1; - private System.Windows.Forms.GroupBox groupBox3; - private System.Windows.Forms.Label label8; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Label label6; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.NumericUpDown numericUpDown6; - private System.Windows.Forms.NumericUpDown numericUpDown5; - private System.Windows.Forms.NumericUpDown numericUpDown4; - private System.Windows.Forms.NumericUpDown numericUpDown3; - private System.Windows.Forms.NumericUpDown numericUpDown2; - private System.Windows.Forms.NumericUpDown numericUpDown1; - private System.Windows.Forms.TextBox textBox1; - private System.Windows.Forms.ComboBox comboBox1; - private System.Windows.Forms.ComboBox comboBox2; - private System.Windows.Forms.Label label9; - private System.Windows.Forms.ComboBox comboBox3; - private System.Windows.Forms.Label label10; - private System.Windows.Forms.CheckBox checkBox1; - private System.Windows.Forms.RichTextBox richTextBox1; - private System.Windows.Forms.ProgressBar progressBar1; - private System.Windows.Forms.Button button3; - private System.Windows.Forms.Timer timer2; - private System.Windows.Forms.GroupBox groupBox4; - private System.Windows.Forms.TextBox textBox4; - private System.Windows.Forms.Label label13; - private System.Windows.Forms.TextBox textBox3; - private System.Windows.Forms.Label label12; - private System.Windows.Forms.TextBox textBox2; - private System.Windows.Forms.Label label11; - private System.Windows.Forms.ToolTip toolTip1; - private System.Windows.Forms.GroupBox groupBox5; - private System.Windows.Forms.TextBox textBox6; - private System.Windows.Forms.Label label15; - private System.Windows.Forms.TextBox textBox7; - private System.Windows.Forms.Label label16; - private System.Windows.Forms.GroupBox groupBox6; - private System.Windows.Forms.TextBox textBox5; - private System.Windows.Forms.Label label14; - private System.Windows.Forms.TextBox textBox8; - private System.Windows.Forms.Label label17; - private System.Windows.Forms.TextBox textBox9; - private System.Windows.Forms.Label label18; - private System.Windows.Forms.Button button5; - private System.Windows.Forms.ComboBox comboBox4; - private System.Windows.Forms.NumericUpDown numericUpDown7; - private System.Windows.Forms.Label label20; - private System.Windows.Forms.Label label19; - private System.Windows.Forms.ComboBox comboBox5; - private System.Windows.Forms.CheckBox checkBox2; - private System.Windows.Forms.Timer timer3; - private System.Windows.Forms.Button button4; - private System.Windows.Forms.NumericUpDown numericUpDown8; - private System.Windows.Forms.CheckBox checkBox3; - private System.Windows.Forms.TextBox textBox10; - private System.Windows.Forms.CheckBox checkBox4; - private System.Windows.Forms.Button button6; - private System.Windows.Forms.Timer timer4; - private System.Windows.Forms.Button button7; - private System.Windows.Forms.TextBox textBox11; - private System.Windows.Forms.LinkLabel linkLabel1; - private System.Windows.Forms.Button button8; - private System.Windows.Forms.CheckBox checkBox5; - } -} - diff --git a/Form1.cs b/Form1.cs deleted file mode 100644 index fa095ad..0000000 --- a/Form1.cs +++ /dev/null @@ -1,3205 +0,0 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net.Http; -using System.Net.NetworkInformation; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace subs_check.win.gui -{ - public partial class Form1: Form - { - //string 版本号; - string 标题; - private Process subsCheckProcess = null; - string nodeInfo;//进度 - private Icon originalNotifyIcon; // 保存原始图标 - private ToolStripMenuItem startMenuItem; - private ToolStripMenuItem stopMenuItem; - string githubProxyURL = ""; - int run = 0; - string 当前subsCheck版本号 = "未知版本"; - string 当前GUI版本号 = "未知版本"; - string 最新GUI版本号 = "未知版本"; - private string nextCheckTime = null;// 用于存储下次检查时间 - string WebUIapiKey = "CMLiussss"; - int downloading = 0; - public Form1() - { - InitializeComponent(); - originalNotifyIcon = notifyIcon1.Icon; - - toolTip1.SetToolTip(numericUpDown1, "并发线程数:推荐 宽带峰值/50M。"); - toolTip1.SetToolTip(numericUpDown2, "检查间隔时间(分钟):放置后台的时候,下次自动测速的间隔时间。\n\n 双击切换 使用「cron表达式」"); - toolTip1.SetToolTip(label2, "检查间隔时间(分钟):放置后台的时候,下次自动测速的间隔时间。\n\n 双击切换 使用「cron表达式」"); - - toolTip1.SetToolTip(numericUpDown3, "超时时间(毫秒):节点的最大延迟。"); - toolTip1.SetToolTip(numericUpDown4, "最低测速结果舍弃(KB/s)。"); - toolTip1.SetToolTip(numericUpDown5, "下载测试时间(s):与下载链接大小相关,默认最大测试10s。"); - toolTip1.SetToolTip(numericUpDown6, "本地监听端口:用于直接返回测速结果的节点信息,方便 Sub-Store 实现订阅转换。"); - toolTip1.SetToolTip(numericUpDown7, "Sub-Store监听端口:用于订阅订阅转换。\n注意:除非你知道你在干什么,否则不要将你的 Sub-Store 暴露到公网,否则可能会被滥用"); - toolTip1.SetToolTip(textBox1, "节点池订阅地址:支持 Link、Base64、Clash 格式的订阅链接。"); - toolTip1.SetToolTip(checkBox1, "以节点IP查询位置重命名节点。\n质量差的节点可能造成IP查询失败,造成整体检查速度稍微变慢。"); - toolTip1.SetToolTip(checkBox2, "是否开启流媒体检测,其中IP欺诈依赖'节点地址查询',内核版本需要 v2.0.8 以上\n\n示例:美国1 | ⬇️ 5.6MB/s |0%|Netflix|Disney|Openai\n风控值:0% (使用ping0.cc标准)\n流媒体解锁:Netflix、Disney、Openai"); - toolTip1.SetToolTip(comboBox3, "GitHub 代理:代理订阅 GitHub raw 节点池。"); - toolTip1.SetToolTip(comboBox2, "测速地址:注意 并发数*节点速度<最大网速 否则测速结果不准确\n尽量不要使用Speedtest,Cloudflare提供的下载链接,因为很多节点屏蔽测速网站。"); - toolTip1.SetToolTip(textBox7, "将测速结果推送到Worker的地址。"); - toolTip1.SetToolTip(textBox6, "Worker令牌。"); - toolTip1.SetToolTip(comboBox1, "测速结果的保存方法。"); - toolTip1.SetToolTip(textBox2, "Gist ID:注意!非Github用户名!"); - toolTip1.SetToolTip(textBox3, "Github TOKEN"); - - toolTip1.SetToolTip(comboBox4, "通用订阅:内置了Sub-Store程序,自适应订阅格式。\nClash订阅:带规则的 Mihomo、Clash 订阅格式。"); - toolTip1.SetToolTip(comboBox5, "生成带规则的 Clash 订阅所需的覆写规则文件"); - - toolTip1.SetToolTip(checkBox3, "保存几个成功的节点,不选代表不限制,内核版本需要 v2.1.0 以上\n如果你的并发数量超过这个参数,那么成功的结果可能会大于这个数值"); - toolTip1.SetToolTip(numericUpDown8, "保存几个成功的节点,不选代表不限制,内核版本需要 v2.1.0 以上\n如果你的并发数量超过这个参数,那么成功的结果可能会大于这个数值"); - - toolTip1.SetToolTip(textBox11, "支持标准cron表达式,如:\n 0 */2 * * * 表示每2小时的整点执行\n 0 0 */2 * * 表示每2天的0点执行\n 0 0 1 * * 表示每月1日0点执行\n */30 * * * * 表示每30分钟执行一次\n\n 双击切换 使用「分钟倒计时」"); - - toolTip1.SetToolTip(checkBox5, "开机启动:勾选后,程序将在Windows启动时自动运行"); - // 设置通知图标的上下文菜单 - SetupNotifyIconContextMenu(); - } - - private void SetupNotifyIconContextMenu() - { - // 创建上下文菜单 - ContextMenuStrip contextMenu = new ContextMenuStrip(); - - // 创建"▶️ 启动"菜单项 - startMenuItem = new ToolStripMenuItem("启动"); - startMenuItem.Click += (sender, e) => - { - if (button1.Text == "▶️ 启动") - { - button1_Click(sender, e); - } - }; - - // 创建"⏹️ 停止"菜单项 - stopMenuItem = new ToolStripMenuItem("停止"); - stopMenuItem.Click += (sender, e) => - { - if (button1.Text == "⏹️ 停止") - { - button1_Click(sender, e); - } - }; - stopMenuItem.Enabled = false; // 初始状态下禁用 - - // 创建"退出"菜单项 - ToolStripMenuItem exitMenuItem = new ToolStripMenuItem("退出"); - exitMenuItem.Click += async (sender, e) => - { - try - { - // 如果程序正在运行,先停止它 - if (subsCheckProcess != null && !subsCheckProcess.HasExited) - { - await KillNodeProcessAsync(); - StopSubsCheckProcess(); - } - - // 确保通知图标被移除 - notifyIcon1.Visible = false; - - // 使用更直接的退出方式 - Environment.Exit(0); - } - catch (Exception ex) - { - MessageBox.Show($"退出程序时发生错误: {ex.Message}", "错误", - MessageBoxButtons.OK, MessageBoxIcon.Error); - - // 如果仍然失败,尝试强制退出 - System.Diagnostics.Process.GetCurrentProcess().Kill(); - } - }; - - // 将菜单项添加到上下文菜单 - contextMenu.Items.Add(startMenuItem); - contextMenu.Items.Add(stopMenuItem); - contextMenu.Items.Add(new ToolStripSeparator()); // 分隔线 - contextMenu.Items.Add(exitMenuItem); - - // 将上下文菜单分配给通知图标 - notifyIcon1.ContextMenuStrip = contextMenu; - - // 确保通知图标可见 - notifyIcon1.Visible = true; - } - - protected override void OnFormClosing(FormClosingEventArgs e) - { - if (e.CloseReason == CloseReason.UserClosing) - { - // 取消关闭操作 - e.Cancel = true; - // 调用隐藏窗口方法 - 隐藏窗口(); - } - } - - private async void timer1_Tick(object sender, EventArgs e)//初始化 - { - timer1.Enabled = false; - if (button2.Text == "高级设置∧") button2_Click(sender, e); - // 检查并创建config文件夹 - string executablePath = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); - string configFolderPath = System.IO.Path.Combine(executablePath, "config"); - if (!System.IO.Directory.Exists(configFolderPath)) - { - // 文件不存在,可以给用户反馈 - string 免责声明 = "SubsCheck-Win-GUI 项目仅供教育、研究和安全测试目的而设计和开发。本项目旨在为安全研究人员、学术界人士及技术爱好者提供一个探索和实践网络通信技术的工具。\r\n在下载和使用本项目代码时,使用者必须严格遵守其所适用的法律和规定。使用者有责任确保其行为符合所在地区的法律框架、规章制度及其他相关规定。\r\n\r\n使用条款\r\n\r\n教育与研究用途:本软件仅可用于网络技术和编程领域的学习、研究和安全测试。\r\n禁止非法使用:严禁将 SubsCheck-Win-GUI 用于任何非法活动或违反使用者所在地区法律法规的行为。\r\n使用时限:基于学习和研究目的,建议用户在完成研究或学习后,或在安装后的24小时内,删除本软件及所有相关文件。\r\n免责声明:SubsCheck-Win-GUI 的创建者和贡献者不对因使用或滥用本软件而导致的任何损害或法律问题负责。\r\n用户责任:用户对使用本软件的方式以及由此产生的任何后果完全负责。\r\n无技术支持:本软件的创建者不提供任何技术支持或使用协助。\r\n知情同意:使用 SubsCheck-Win-GUI 即表示您已阅读并理解本免责声明,并同意受其条款的约束。\r\n\r\n请记住:本软件的主要目的是促进学习、研究和安全测试。创作者不支持或认可任何其他用途。使用者应当在合法和负责任的前提下使用本工具。\r\n\r\n同意以上条款请点击\"是 / Yes\",否则程序将退出。"; - - // 显示带有 "同意" 和 "拒绝" 选项的对话框 - DialogResult result = MessageBox.Show(免责声明, "SubsCheck-Win-GUI 免责声明", MessageBoxButtons.YesNo, MessageBoxIcon.Question); - - // 如果用户点击 "拒绝" (对应于 No 按钮) - if (result == DialogResult.No) - { - // 退出程序 - Environment.Exit(0); // 立即退出程序 - } - System.IO.Directory.CreateDirectory(configFolderPath); - } - - FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location); - 当前GUI版本号 = "v" + myFileVersionInfo.FileVersion; - 最新GUI版本号 = 当前GUI版本号; - 标题 = "SubsCheck Win GUI " + 当前GUI版本号; - this.Text = 标题;// + " TG:CMLiussss BY:CM喂饭 干货满满"; - comboBox1.Text = "本地"; - comboBox4.Text = "通用订阅"; - ReadConfig(); - - if (CheckCommandLineParameter("-auto")) - { - Log("检测到开机启动,准备执行任务..."); - button1_Click(this, EventArgs.Empty); - this.Hide(); - notifyIcon1.Visible = true; - } else await CheckGitHubVersionAsync(); - } - - private async Task CheckGitHubVersionAsync() - { - try - { - // 首先检查是否有网络连接 - if (!IsNetworkAvailable()) - { - return; // 静默返回,不显示错误 - } - - var result = await 获取版本号("https://api.github.com/repos/cmliu/SubsCheck-Win-GUI/releases/latest"); - if (result.Item1 != "未知版本") - { - string latestVersion = result.Item1; - if (latestVersion != 当前GUI版本号) - { - 最新GUI版本号 = latestVersion; - 标题 = "SubsCheck Win GUI " + 当前GUI版本号 + $" 发现新版本: {最新GUI版本号} 请及时更新!"; - this.Text = 标题; - } - } - } - catch - { - // 静默处理任何其他异常 - return; - } - } - - // 添加检查网络连接的辅助方法 - private bool IsNetworkAvailable() - { - try - { - return NetworkInterface.GetIsNetworkAvailable(); - } - catch - { - return false; // 如果无法检查网络状态,假设网络不可用 - } - } - - private async void ReadConfig()//读取配置文件 - { - checkBox5.CheckedChanged -= checkBox5_CheckedChanged;// 临时移除事件处理器,防止触发事件 - try - { - string executablePath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); - string configFilePath = Path.Combine(executablePath, "config", "config.yaml"); - - if (File.Exists(configFilePath)) - { - // 读取YAML文件内容 - string yamlContent = File.ReadAllText(configFilePath); - - // 使用YamlDotNet解析YAML - var deserializer = new YamlDotNet.Serialization.Deserializer(); - var config = deserializer.Deserialize>(yamlContent); - - // 使用新函数获取整数值并设置UI控件 - int? concurrentValue = 读取config整数(config, "concurrent"); - if (concurrentValue.HasValue) numericUpDown1.Value = concurrentValue.Value; - - int? checkIntervalValue = 读取config整数(config, "check-interval"); - if (checkIntervalValue.HasValue) numericUpDown2.Value = checkIntervalValue.Value; - - int? timeoutValue = 读取config整数(config, "timeout"); - if (timeoutValue.HasValue) numericUpDown3.Value = timeoutValue.Value; - - int? minspeedValue = 读取config整数(config, "min-speed"); - if (minspeedValue.HasValue) numericUpDown4.Value = minspeedValue.Value; - - int? downloadtimeoutValue = 读取config整数(config, "download-timeout"); - if (downloadtimeoutValue.HasValue) numericUpDown5.Value = downloadtimeoutValue.Value; - - string speedTestUrl = 读取config字符串(config, "speed-test-url"); - if (speedTestUrl != null) comboBox2.Text = speedTestUrl; - - string savemethod = 读取config字符串(config, "save-method"); - if (savemethod != null) - { - if (savemethod == "local") comboBox1.Text = "本地"; - else comboBox1.Text = savemethod; - } - - string listenport = 读取config字符串(config, "listen-port"); - if (listenport != null) - { - // 查找最后一个冒号的位置 - int colonIndex = listenport.LastIndexOf(':'); - if (colonIndex >= 0 && colonIndex < listenport.Length - 1) - { - // 提取冒号后面的部分作为端口号 - string portStr = listenport.Substring(colonIndex + 1); - if (decimal.TryParse(portStr, out decimal port)) - { - numericUpDown6.Value = port; - } - } - } - - /* - int? substoreport = 读取config整数(config, "sub-store-port"); - if (substoreport.HasValue) numericUpDown7.Value = substoreport.Value; - */ - - string substoreport = 读取config字符串(config, "sub-store-port"); - if (substoreport != null) - { - // 查找最后一个冒号的位置 - int colonIndex = substoreport.LastIndexOf(':'); - if (colonIndex >= 0 && colonIndex < substoreport.Length - 1) - { - // 提取冒号后面的部分作为端口号 - string portStr = substoreport.Substring(colonIndex + 1); - if (decimal.TryParse(portStr, out decimal port)) - { - numericUpDown7.Value = port; - } - } - } - - string githubproxy = 读取config字符串(config, "githubproxy"); - if (githubproxy != null) comboBox3.Text = githubproxy; - - const string githubRawPrefix = "https://raw.githubusercontent.com/"; - - string mihomoOverwriteUrl = 读取config字符串(config, "mihomo-overwrite-url"); - int mihomoOverwriteUrlIndex = mihomoOverwriteUrl.IndexOf(githubRawPrefix); - if (mihomoOverwriteUrl != null) - { - if (mihomoOverwriteUrl.Contains("http://127.0.0")) - { - if (mihomoOverwriteUrl.EndsWith("bdg.yaml", StringComparison.OrdinalIgnoreCase)) - { - comboBox5.Text = "[内置]布丁狗的订阅转换"; - await ProcessComboBox5Selection(); - } - else if (mihomoOverwriteUrl.EndsWith("ACL4SSR_Online_Full.yaml", StringComparison.OrdinalIgnoreCase)) - { - comboBox5.Text = "[内置]ACL4SSR_Online_Full"; - await ProcessComboBox5Selection(); - } - } - else if (mihomoOverwriteUrlIndex > 0) comboBox5.Text = mihomoOverwriteUrl.Substring(mihomoOverwriteUrlIndex); - else comboBox5.Text = mihomoOverwriteUrl; - } - - // 处理URLs,检查是否包含GitHub raw链接 - List subUrls = 读取config列表(config, "sub-urls"); - if (subUrls != null && subUrls.Count > 0) - { - // 创建一个新的过滤后的列表 - var filteredUrls = new List(); - - for (int i = 0; i < subUrls.Count; i++) - { - // 排除本地URL - string localUrlPattern = $"http://127.0.0.1:{numericUpDown6.Value}/all.yaml"; - if (!subUrls[i].Equals(localUrlPattern, StringComparison.OrdinalIgnoreCase)) - { - // 处理GitHub raw链接 - int index = subUrls[i].IndexOf(githubRawPrefix); - if (index > 0) // 如果找到且不在字符串开头 - { - // 只保留从githubRawPrefix开始的部分 - filteredUrls.Add(subUrls[i].Substring(index)); - } - else - { - // 如果不是GitHub链接,直接添加 - filteredUrls.Add(subUrls[i]); - } - } - } - - // 将过滤后的列表中的每个URL放在单独的行上 - textBox1.Text = string.Join(Environment.NewLine, filteredUrls); - } - - string renamenode = 读取config字符串(config, "rename-node"); - if (renamenode != null && renamenode == "true") checkBox1.Checked = true; - else checkBox1.Checked = false; - - string mediacheck = 读取config字符串(config, "media-check"); - if (mediacheck != null && mediacheck == "true") checkBox2.Checked = true; - else checkBox2.Checked = false; - - string githubgistid = 读取config字符串(config, "github-gist-id"); - if (githubgistid != null) textBox2.Text = githubgistid; - string githubtoken = 读取config字符串(config, "github-token"); - if (githubtoken != null) textBox3.Text = githubtoken; - - string githubapimirror = 读取config字符串(config, "github-api-mirror"); - if (githubapimirror != null) textBox4.Text = githubapimirror; - - string workerurl = 读取config字符串(config, "worker-url"); - if (workerurl != null) textBox7.Text = workerurl; - string workertoken = 读取config字符串(config, "worker-token"); - if (workertoken != null) textBox6.Text = workertoken; - - string webdavusername = 读取config字符串(config, "webdav-username"); - if (webdavusername != null) textBox9.Text = webdavusername; - string webdavpassword = 读取config字符串(config, "webdav-password"); - if (webdavpassword != null) textBox8.Text = webdavpassword; - string webdavurl = 读取config字符串(config, "webdav-url"); - if (webdavurl != null) textBox5.Text = webdavurl; - - string subscheckversion = 读取config字符串(config, "subscheck-version"); - if (subscheckversion != null) 当前subsCheck版本号 = subscheckversion; - - int? successlimit = 读取config整数(config, "success-limit"); - if (successlimit.HasValue) - { - if (successlimit.Value == 0) - { - checkBox3.Checked = false; - numericUpDown8.Enabled = false; - } - else - { - checkBox3.Checked = true; - numericUpDown8.Enabled = true; - numericUpDown8.Value = successlimit.Value; - } - } - - string enablewebui = 读取config字符串(config, "enable-web-ui"); - if (enablewebui != null && enablewebui == "true") checkBox4.Checked = true; - else checkBox4.Checked = false; - - string apikey = 读取config字符串(config, "api-key"); - if (apikey != null) - { - if (apikey == GetComputerNameMD5()) - { - checkBox4.Checked = false; - string oldapikey = 读取config字符串(config, "old-api-key"); - if (oldapikey != null) - { - textBox10.Text = oldapikey; - } - else - { - textBox10.PasswordChar = '\0'; - textBox10.Text = "请输入密钥"; - textBox10.ForeColor = Color.Gray; - } - } - else - { - textBox10.Text = apikey; - } - } - - string cronexpression = 读取config字符串(config, "cron-expression"); - if (cronexpression != null) - { - textBox11.Text = cronexpression; - string cronDescription = GetCronExpressionDescription(textBox11.Text); - textBox11.Location = new Point(9, 48); - textBox11.Visible = true; - label2.Visible = false; - numericUpDown2.Visible = false; - } - - string guiauto = 读取config字符串(config, "gui-auto"); - if (guiauto != null && guiauto == "true") checkBox5.Checked = true; - else checkBox5.Checked = false; - } - else - { - comboBox3.Text = "自动选择"; - comboBox5.Text = "[内置]布丁狗的订阅转换"; - } - } - catch (Exception ex) - { - MessageBox.Show($"读取配置文件时发生错误: {ex.Message}", "错误", - MessageBoxButtons.OK, MessageBoxIcon.Error); - } - checkBox5.CheckedChanged += checkBox5_CheckedChanged;// 重新绑定事件处理器 - } - - private int? 读取config整数(Dictionary config, string fieldName) - { - // 检查是否存在指定字段且不为null - if (config.ContainsKey(fieldName) && config[fieldName] != null) - { - int value; - if (int.TryParse(config[fieldName].ToString(), out value)) - return value; - } - return null; - } - - private string 读取config字符串(Dictionary config, string fieldName) - { - // 检查是否存在指定字段且不为null - if (config.ContainsKey(fieldName) && config[fieldName] != null) - { - return config[fieldName].ToString(); - } - return null; - } - - private List 读取config列表(Dictionary config, string fieldName) - { - // 检查是否存在指定字段且不为null - if (config.ContainsKey(fieldName) && config[fieldName] != null) - { - // 尝试将对象转换为列表 - if (config[fieldName] is List listItems) - { - return listItems.Select(item => item?.ToString()).Where(s => !string.IsNullOrEmpty(s)).ToList(); - } - } - return null; - } - - private async Task SaveConfig(bool githubProxyCheck = true)//保存配置文件 - { - try - { - string executablePath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); - string configFilePath = Path.Combine(executablePath, "config", "config.yaml"); - - // 创建配置字典 - var config = new Dictionary(); - - // 从UI控件获取值并添加到字典中 - config["concurrent"] = (int)numericUpDown1.Value; - config["check-interval"] = (int)numericUpDown2.Value; - if (textBox11.Visible) config["cron-expression"] = textBox11.Text; - config["timeout"] = (int)numericUpDown3.Value; - config["min-speed"] = (int)numericUpDown4.Value; - config["download-timeout"] = (int)numericUpDown5.Value; - - if (!string.IsNullOrEmpty(comboBox2.Text)) config["speed-test-url"] = comboBox2.Text; - - // 保存save-method,将"本地"转换为"local" - config["save-method"] = comboBox1.Text == "本地" ? "local" : comboBox1.Text; - - // 保存gist参数 - config["github-gist-id"] = textBox2.Text; - config["github-token"] = textBox3.Text; - - config["github-api-mirror"] = textBox4.Text; - - // 保存r2参数 - config["worker-url"] = textBox7.Text; - config["worker-token"] = textBox6.Text; - - // 保存webdav参数 - config["webdav-username"] = textBox9.Text; - config["webdav-password"] = textBox8.Text; - config["webdav-url"] = textBox5.Text; - - // 保存enable-web-ui - config["enable-web-ui"] = true; - - // 保存listen-port - if (checkBox4.Checked) - { - WebUIapiKey = textBox10.Text; - config["listen-port"] = $@":{numericUpDown6.Value}"; - } - else - { - WebUIapiKey = GetComputerNameMD5(); - config["listen-port"] = $@"127.0.0.1:{numericUpDown6.Value}"; - if (textBox10.Text != "请输入密钥") config["old-api-key"] = textBox10.Text; - } - config["api-key"] = WebUIapiKey; - - // 保存sub-store-port - config["sub-store-port"] = $@":{numericUpDown7.Value}"; - - string githubRawPrefix = "https://raw.githubusercontent.com/"; - if (githubProxyCheck) - { - // 检查并处理 GitHub Raw URLs - if (comboBox3.Text == "自动选择") - { - // 创建不包含"自动选择"的代理列表 - List proxyItems = new List(); - for (int j = 0; j < comboBox3.Items.Count; j++) - { - string proxyItem = comboBox3.Items[j].ToString(); - if (proxyItem != "自动选择") - proxyItems.Add(proxyItem); - } - - // 随机打乱列表顺序 - Random random = new Random(); - proxyItems = proxyItems.OrderBy(x => random.Next()).ToList(); - - // 异步检测可用代理 - githubProxyURL = await DetectGitHubProxyAsync(proxyItems); - } - } - - if (comboBox3.Text != "自动选择") githubProxyURL = $"https://{comboBox3.Text}/"; - config["githubproxy"] = comboBox3.Text; - config["github-proxy"] = githubProxyURL; - - // 保存sub-urls列表 - List subUrls = new List(); - string allyamlFilePath = System.IO.Path.Combine(executablePath, "output", "all.yaml"); - if (System.IO.File.Exists(allyamlFilePath)) - { - subUrls.Add($"http://127.0.0.1:{numericUpDown6.Value}/all.yaml"); - Log("已加载上次测试结果。"); - } - - if (!string.IsNullOrEmpty(textBox1.Text)) - { - subUrls.AddRange(textBox1.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).ToList()); - // 处理URLs - for (int i = 0; i < subUrls.Count; i++) - { - if (subUrls[i].StartsWith(githubRawPrefix) && !string.IsNullOrEmpty(githubProxyURL)) - { - // 替换为代理 URL 格式 - //subUrls[i] = githubProxyURL + githubRawPrefix + subUrls[i].Substring(githubRawPrefix.Length); - // 使用subs-check内置github-proxy参数 - subUrls[i] = githubRawPrefix + subUrls[i].Substring(githubRawPrefix.Length); - } - } - } - - config["sub-urls"] = subUrls; - - // 处理配置文件下载与配置 - if (comboBox5.Text.Contains("[内置]")) - { - // 确定文件名和下载URL - string fileName; - string downloadFilePath; - string downloadUrl; - string displayName; - - if (comboBox5.Text.Contains("[内置]布丁狗")) - { - fileName = "bdg.yaml"; - displayName = "[内置]布丁狗的订阅转换"; - downloadUrl = "https://raw.githubusercontent.com/cmliu/ACL4SSR/main/yaml/bdg.yaml"; - } - else // [内置]ACL4SSR - { - fileName = "ACL4SSR_Online_Full.yaml"; - displayName = "[内置]ACL4SSR_Online_Full"; - downloadUrl = "https://raw.githubusercontent.com/beck-8/override-hub/main/yaml/ACL4SSR_Online_Full.yaml"; - } - - // 确保output文件夹存在 - string outputFolderPath = Path.Combine(executablePath, "output"); - if (!Directory.Exists(outputFolderPath)) - { - Directory.CreateDirectory(outputFolderPath); - } - - // 确定文件完整路径 - downloadFilePath = Path.Combine(outputFolderPath, fileName); - if (!File.Exists(downloadFilePath)) await ProcessComboBox5Selection(); - - // 检查文件是否存在 - if (!File.Exists(downloadFilePath)) - { - Log($"{displayName} 覆写配置文件 未找到,将使用在线版本。"); - config["mihomo-overwrite-url"] = githubProxyURL + downloadUrl; - } - else - { - Log($"{displayName} 覆写配置文件 加载成功。"); - config["mihomo-overwrite-url"] = $"http://127.0.0.1:{numericUpDown6.Value}/{fileName}"; - } - } - else if (comboBox5.Text.StartsWith(githubRawPrefix)) config["mihomo-overwrite-url"] = githubProxyURL + comboBox5.Text; - else config["mihomo-overwrite-url"] = comboBox5.Text != "" ? comboBox5.Text : $"http://127.0.0.1:{numericUpDown6.Value}/ACL4SSR_Online_Full.yaml"; - - config["rename-node"] = checkBox1.Checked;//以节点IP查询位置重命名节点 - config["media-check"] = checkBox2.Checked;//是否开启流媒体检测 - config["keep-success-proxies"] = false; - config["print-progress"] = false;//是否显示进度 - config["sub-urls-retry"] = 3;//重试次数(获取订阅失败后重试次数) - config["subscheck-version"] = 当前subsCheck版本号;//当前subsCheck版本号 - - config["gui-auto"] = checkBox5.Checked;//是否开机自启 - - //保存几个成功的节点,为0代表不限制 - if (checkBox3.Checked) config["success-limit"] = (int)numericUpDown8.Value; - else config["success-limit"] = 0; - - // 使用YamlDotNet序列化配置 - var serializer = new YamlDotNet.Serialization.SerializerBuilder() - .WithIndentedSequences() // 使序列化结果更易读 - .Build(); - - string yamlContent = serializer.Serialize(config); - - // 确保配置目录存在 - string configDirPath = Path.GetDirectoryName(configFilePath); - if (!Directory.Exists(configDirPath)) - Directory.CreateDirectory(configDirPath); - - string moreYamlPath = Path.Combine(configDirPath, "more.yaml"); - if (File.Exists(moreYamlPath)) - { - // 读取more.yaml的内容 - string moreYamlContent = File.ReadAllText(moreYamlPath); - - // 确保more.yaml内容以换行开始 - if (!moreYamlContent.StartsWith("\n") && !moreYamlContent.StartsWith("\r\n")) - { - yamlContent += "\n"; // 添加换行符作为分隔 - } - - // 将more.yaml的内容追加到要写入的config.yaml内容后 - yamlContent += moreYamlContent; - - Log($"已将补充参数配置 more.yaml 内容追加到配置文件"); - } - // 写入YAML文件 - File.WriteAllText(configFilePath, yamlContent); - } - catch (Exception ex) - { - MessageBox.Show($"保存配置文件时发生错误: {ex.Message}", "错误", - MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - private void button2_Click(object sender, EventArgs e) - { - if (button2.Text == "高级设置∧") - { - button2.Text = "高级设置∨"; - groupBox3.Visible = false; - } - else - { - button2.Text = "高级设置∧"; - groupBox3.Visible = true; - } - 判断保存类型(); - } - - private async void button1_Click(object sender, EventArgs e) - { - button1.Enabled = false; - if (button1.Text == "▶️ 启动") - { - if (checkBox4.Checked && textBox10.Text == "请输入密钥") - { - MessageBox.Show("您已启用WebUI,请设置WebUI API密钥!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; - } - run = 1; - if (button3.Enabled==false) - { - string executablePath = Path.GetDirectoryName(Application.ExecutablePath); - string allyamlFilePath = Path.Combine(executablePath, "output", "all.yaml"); - button3.Enabled = File.Exists(allyamlFilePath); - } - - numericUpDown1.Enabled = false; - numericUpDown2.Enabled = false; - textBox11.Enabled = false; - numericUpDown3.Enabled = false; - numericUpDown4.Enabled = false; - numericUpDown5.Enabled = false; - numericUpDown6.Enabled = false; - numericUpDown7.Enabled = false; - comboBox1.Enabled = false; - textBox1.Enabled = false; - groupBox3.Enabled = false; - groupBox4.Enabled = false; - groupBox5.Enabled = false; - groupBox6.Enabled = false; - if (checkBox4.Checked) button6.Enabled = true; - button1.Text = "⏹️ 停止"; - //timer3.Enabled = true; - // 清空 richTextBox1 - richTextBox1.Clear(); - await KillNodeProcessAsync(); - await SaveConfig(); - - if (run == 1) - { - // 更新菜单项的启用状态 - startMenuItem.Enabled = false; - stopMenuItem.Enabled = true; - - // 清空 richTextBox1 - //richTextBox1.Clear(); - - notifyIcon1.Text = "SubsCheck: 已就绪"; - - // 启动 subs-check.exe 程序 - StartSubsCheckProcess(); - } - } - else - { - run = 0; - Log("任务停止"); - progressBar1.Value = 0; - groupBox2.Text = "实时日志"; - notifyIcon1.Text = "SubsCheck: 未运行"; - // 停止 subs-check.exe 程序 - StopSubsCheckProcess(); - // 结束 Sub-Store - await KillNodeProcessAsync(); - if (checkBox4.Checked) ReadConfig(); - button3.Enabled = false; - numericUpDown1.Enabled = true; - numericUpDown2.Enabled = true; - textBox11.Enabled = true; - numericUpDown3.Enabled = true; - numericUpDown4.Enabled = true; - numericUpDown5.Enabled = true; - numericUpDown6.Enabled = true; - numericUpDown7.Enabled = true; - comboBox1.Enabled = true; - textBox1.Enabled = true; - groupBox3.Enabled = true; - groupBox4.Enabled = true; - groupBox5.Enabled = true; - groupBox6.Enabled = true; - button6.Enabled = false; - button1.Text = "▶️ 启动"; - //timer3.Enabled = false; - // 更新菜单项的启用状态 - startMenuItem.Enabled = true; - stopMenuItem.Enabled = false; - } - if (downloading == 0) button1.Enabled = true; - } - - private async Task DownloadSubsCheckEXE() - { - button1.Enabled = false; - downloading = 1; - try - { - Log("正在检查网络连接..."); - - // 首先检查是否有网络连接 - if (!IsNetworkAvailable()) - { - Log("网络连接不可用,无法下载核心文件。", true); - MessageBox.Show("缺少 subs-check.exe 核心文件。\n\n您可以前往 https://github.com/beck-8/subs-check/releases 自行下载!", - "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); - return; - } - - var result = await 获取版本号("https://api.github.com/repos/beck-8/subs-check/releases/latest", true); - if (result.Item1 != "未知版本") - { - // 创建不使用系统代理的 HttpClientHandler - HttpClientHandler handler = new HttpClientHandler - { - UseProxy = false, - Proxy = null - }; - - // 使用自定义 handler 创建 HttpClient - using (HttpClient client = new HttpClient(handler)) - { - try - { - string latestVersion = result.Item1; - JArray assets = result.Item2; - Log($"subs-check.exe 最新版本为: {latestVersion} "); - // 查找Windows i386版本的资源 - string downloadUrl = null; - - foreach (var asset in assets) - { - if (asset["name"].ToString() == "subs-check_Windows_i386.zip") - { - downloadUrl = asset["browser_download_url"].ToString(); - break; - } - } - - if (downloadUrl != null) - { - string 代理下载链接 = githubProxyURL + downloadUrl; - string 原生下载链接 = 代理下载链接; - // 计算"https://"在下载链接中出现的次数 - int httpsCount = 0; - int lastIndex = -1; - int currentIndex = 0; - - // 查找所有"https://"出现的位置 - while ((currentIndex = 代理下载链接.IndexOf("https://", currentIndex)) != -1) - { - httpsCount++; - lastIndex = currentIndex; - currentIndex += 8; // "https://".Length = 8 - } - - // 如果"https://"出现2次或以上,提取最后一个"https://"之后的内容 - if (httpsCount >= 2 && lastIndex != -1) - { - 原生下载链接 = 代理下载链接.Substring(lastIndex); - } - - string executablePath = Path.GetDirectoryName(Application.ExecutablePath); - - // 创建下载请求 - 优化的多级尝试下载逻辑 - Log("开始下载文件..."); - bool downloadSuccess = false; - string zipFilePath = Path.Combine(executablePath, "subs-check_Windows_i386.zip"); - string failureReason = ""; - - // 如果文件已存在,先删除 - if (File.Exists(zipFilePath)) File.Delete(zipFilePath); - - // 第一次尝试:使用代理下载链接 + 当前HttpClient(不使用系统代理) - try - { - Log($"[尝试1/4] 使用代理下载链接:{代理下载链接}"); - downloadSuccess = await DownloadFileAsync(client, 代理下载链接, zipFilePath); - } - catch (Exception ex) - { - Log($"[尝试1/4] 失败: {ex.Message}", true); - failureReason = ex.Message; - } - - // 如果第一次尝试失败,且代理链接与原生链接不同,使用原生下载链接尝试 - if (!downloadSuccess && 代理下载链接 != 原生下载链接) - { - try - { - Log($"[尝试2/4] 使用原生下载链接:{原生下载链接}"); - downloadSuccess = await DownloadFileAsync(client, 原生下载链接, zipFilePath); - } - catch (Exception ex) - { - Log($"[尝试2/4] 失败: {ex.Message}", true); - failureReason = ex.Message; - } - } - - // 如果前面的尝试都失败,创建使用系统代理的HttpClient再次尝试 - if (!downloadSuccess) - { - try - { - Log("[尝试3/4] 使用系统代理 + 代理下载链接"); - using (HttpClient proxyClient = new HttpClient()) - { - proxyClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); - proxyClient.Timeout = TimeSpan.FromSeconds(30); - - downloadSuccess = await DownloadFileAsync(proxyClient, 代理下载链接, zipFilePath); - } - } - catch (Exception ex) - { - Log($"[尝试3/4] 失败: {ex.Message}", true); - failureReason = ex.Message; - } - - // 最后一次尝试:使用系统代理 + 原生链接(如果不同) - if (!downloadSuccess && 代理下载链接 != 原生下载链接) - { - try - { - Log("[尝试4/4] 使用系统代理 + 原生下载链接"); - using (HttpClient proxyClient = new HttpClient()) - { - proxyClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); - proxyClient.Timeout = TimeSpan.FromSeconds(30); - - downloadSuccess = await DownloadFileAsync(proxyClient, 原生下载链接, zipFilePath); - } - } - catch (Exception ex) - { - Log($"[尝试4/4] 失败: {ex.Message}", true); - failureReason = ex.Message; - } - } - } - - if (downloadSuccess) - { - Log("下载完成,正在解压文件..."); - - // 解压文件的代码保持不变 - using (System.IO.Compression.ZipArchive archive = System.IO.Compression.ZipFile.OpenRead(zipFilePath)) - { - // 查找subs-check.exe - System.IO.Compression.ZipArchiveEntry exeEntry = archive.Entries.FirstOrDefault( - entry => entry.Name.Equals("subs-check.exe", StringComparison.OrdinalIgnoreCase)); - - if (exeEntry != null) - { - string exeFilePath = Path.Combine(executablePath, "subs-check.exe"); - - // 如果文件已存在,先删除 - if (File.Exists(exeFilePath)) - { - File.Delete(exeFilePath); - } - - // 解压文件 - exeEntry.ExtractToFile(exeFilePath); - 当前subsCheck版本号 = latestVersion; - Log($"subs-check.exe {当前subsCheck版本号} 已就绪!"); - - await SaveConfig(false); - - // 删除下载的zip文件 - //File.Delete(zipFilePath); - } - else - { - Log("无法在压缩包中找到 subs-check.exe 文件。", true); - } - } - } - else - { - // 所有尝试都失败 - Log($"所有下载尝试均失败,最后错误: {failureReason}", true); - MessageBox.Show($"下载 subs-check.exe 失败,请检查网络连接后重试。\n\n可尝试更换 Github Proxy 后,点击「检查更新」>「更新内核」。\n或前往 https://github.com/beck-8/subs-check/releases 自行下载!", - "下载失败", MessageBoxButtons.OK, MessageBoxIcon.Error); - progressBar1.Value = 0; - } - - // 解压文件 - using (System.IO.Compression.ZipArchive archive = System.IO.Compression.ZipFile.OpenRead(zipFilePath)) - { - // 查找subs-check.exe - System.IO.Compression.ZipArchiveEntry exeEntry = archive.Entries.FirstOrDefault( - entry => entry.Name.Equals("subs-check.exe", StringComparison.OrdinalIgnoreCase)); - - if (exeEntry != null) - { - string exeFilePath = Path.Combine(executablePath, "subs-check.exe"); - - // 如果文件已存在,先删除 - if (File.Exists(exeFilePath)) - { - File.Delete(exeFilePath); - } - - // 解压文件 - exeEntry.ExtractToFile(exeFilePath); - 当前subsCheck版本号 = latestVersion; - Log($"subs-check.exe {当前subsCheck版本号} 已就绪!"); - - await SaveConfig(false); - // 这里保留原有行为,不修改button1.Enabled - - // 删除下载的zip文件 - //File.Delete(zipFilePath); - } - else - { - Log("无法在压缩包中找到 subs-check.exe 文件。", true); - } - } - } - else - { - Log("无法找到适用于 Windows i386 的下载链接。", true); - MessageBox.Show("未能找到适用的 subs-check.exe 下载链接。\n\n可尝试更换 Github Proxy 后,点击「检查更新」>「更新内核」。\n或前往 https://github.com/beck-8/subs-check/releases 自行下载!", - "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - } - catch (Exception ex) - { - Log($"下载过程中出错: {ex.Message}", true); - MessageBox.Show($"下载 subs-check.exe 时出错: {ex.Message}\n\n可尝试更换 Github Proxy 后,点击「检查更新」>「更新内核」。\n或前往 https://github.com/beck-8/subs-check/releases 自行下载!", - "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - } - } - catch (Exception ex) - { - Log($"初始化下载过程出错: {ex.Message}", true); - MessageBox.Show($"下载准备过程出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - - button1.Enabled = true; - downloading = 0; - } - - /// - /// 获取最新版本号和对应的下载链接 - /// - /// API请求URL - /// 是否在日志中输出信息 - /// 包含最新版本号和下载链接的元组 - private async Task<(string LatestVersion, JArray assets)> 获取版本号(string 版本号URL, bool 是否输出log = false) - { - string latestVersion = "未知版本"; - JArray assets = null; - - // 创建不使用系统代理的 HttpClientHandler - HttpClientHandler handler = new HttpClientHandler - { - UseProxy = false, - Proxy = null - }; - - // 使用自定义 handler 创建 HttpClient - using (HttpClient client = new HttpClient(handler)) - { - client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); - client.Timeout = TimeSpan.FromSeconds(30); // 增加超时时间以适应下载需求 - - if (是否输出log) Log("正在获取最新版本 subs-check.exe 内核下载地址..."); - string url = 版本号URL; - string 备用url = 版本号URL.Replace("api.github.com", "api.github.cmliussss.net"); - - HttpResponseMessage response = null; - string responseBody = null; - JObject json = null; - - // 先尝试主URL - try - { - response = await client.GetAsync(url); - - // 如果主URL请求成功返回有效数据 - if (response.IsSuccessStatusCode) - { - responseBody = await response.Content.ReadAsStringAsync(); - json = JObject.Parse(responseBody); - if (是否输出log) Log("成功从主API获取版本信息"); - } - // 如果主URL请求不成功但没有抛出异常 - else - { - if (是否输出log) Log($"主API请求失败 HTTP {(int)response.StatusCode},尝试备用API..."); - response = await client.GetAsync(备用url); - - if (response.IsSuccessStatusCode) - { - responseBody = await response.Content.ReadAsStringAsync(); - json = JObject.Parse(responseBody); - if (是否输出log) Log("成功从备用API获取版本信息"); - } - else - { - if (是否输出log) Log($"备用API也请求失败: HTTP {(int)response.StatusCode}", true); - return (latestVersion, assets); // 两个URL都失败,提前退出 - } - } - } - // 捕获网络请求异常(如连接超时、无法解析域名等) - catch (HttpRequestException ex) - { - if (是否输出log) Log($"主API请求出错: {ex.Message},尝试备用API..."); - try - { - response = await client.GetAsync(备用url); - if (response.IsSuccessStatusCode) - { - responseBody = await response.Content.ReadAsStringAsync(); - json = JObject.Parse(responseBody); - if (是否输出log) Log("成功从备用API获取版本信息"); - } - else - { - if (是否输出log) Log($"备用API也请求失败: HTTP {(int)response.StatusCode}", true); - return (latestVersion, assets); // 备用URL也失败,提前退出 - } - } - catch (Exception backupEx) - { - if (是否输出log) Log($"备用API请求也出错: {backupEx.Message}", true); - return (latestVersion, assets); // 连备用URL也异常,提前退出 - } - } - // 捕获JSON解析异常 - catch (Newtonsoft.Json.JsonException ex) - { - if (是否输出log) Log($"解析JSON数据出错: {ex.Message}", true); - try - { - response = await client.GetAsync(备用url); - if (response.IsSuccessStatusCode) - { - responseBody = await response.Content.ReadAsStringAsync(); - json = JObject.Parse(responseBody); - if (是否输出log) Log("成功从备用API获取版本信息"); - } - } - catch (Exception backupEx) - { - if (是否输出log) Log($"备用API请求也出错: {backupEx.Message}", true); - return (latestVersion, assets); // 连备用URL也有问题,提前退出 - } - } - // 捕获其他所有异常 - catch (Exception ex) - { - if (是否输出log) Log($"获取版本信息时出现未预期的错误: {ex.Message}", true); - try - { - response = await client.GetAsync(备用url); - if (response.IsSuccessStatusCode) - { - responseBody = await response.Content.ReadAsStringAsync(); - json = JObject.Parse(responseBody); - if (是否输出log) Log("成功从备用URL获取版本信息"); - } - } - catch (Exception backupEx) - { - if (是否输出log) Log($"备用API请求也出错: {backupEx.Message}", true); - return (latestVersion, assets); // 连备用URL也有问题,提前退出 - } - } - - // 如果成功获取了JSON数据,继续处理 - if (json != null) - { - latestVersion = json["tag_name"].ToString(); - assets = (JArray)json["assets"]; - } - } - - return (latestVersion, assets); - } - - - private async void StartSubsCheckProcess() - { - try - { - // 重置进度条 - progressBar1.Value = 0; - groupBox2.Text = "实时日志"; - using (MemoryStream ms = new MemoryStream(Properties.Resources.going)) - { - notifyIcon1.Icon = new Icon(ms); - } - - // 获取当前应用程序目录 - string executablePath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); - string subsCheckPath = Path.Combine(executablePath, "subs-check.exe"); - - // 检查是否有其他subs-check.exe进程正在运行,并强制结束它们 - try - { - Process[] processes = Process.GetProcessesByName("subs-check"); - if (processes.Length > 0) - { - Log("发现正在运行的subs-check.exe进程,正在强制结束..."); - foreach (Process process in processes) - { - // 确保不是当前应用程序的进程 - if (process != subsCheckProcess) - { - try - { - process.Kill(); - process.WaitForExit(); - Log($"成功结束subs-check.exe进程(ID: {process.Id})"); - } - catch (Exception ex) - { - Log($"结束subs-check.exe进程时出错(ID: {process.Id}): {ex.Message}", true); - } - } - } - } - } - catch (Exception ex) - { - Log($"检查运行中的subs-check.exe进程时出错: {ex.Message}", true); - } - - // 检查文件是否存在 - if (!File.Exists(subsCheckPath)) - { - Log("没有找到 subs-check.exe 文件。", true); - await DownloadSubsCheckEXE(); // 使用异步等待 - } - - // 创建进程启动信息 - ProcessStartInfo startInfo = new ProcessStartInfo - { - FileName = subsCheckPath, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true, - WorkingDirectory = executablePath, - StandardOutputEncoding = Encoding.UTF8, - StandardErrorEncoding = Encoding.UTF8 - }; - - // 创建进程 - subsCheckProcess = new Process { StartInfo = startInfo }; - - // 设置输出和错误数据接收事件处理 - subsCheckProcess.OutputDataReceived += SubsCheckProcess_OutputDataReceived; - subsCheckProcess.ErrorDataReceived += SubsCheckProcess_OutputDataReceived; - - // 启动进程 - subsCheckProcess.Start(); - - // 开始异步读取输出 - subsCheckProcess.BeginOutputReadLine(); - subsCheckProcess.BeginErrorReadLine(); - - // 设置进程退出事件处理 - subsCheckProcess.EnableRaisingEvents = true; - subsCheckProcess.Exited += SubsCheckProcess_Exited; - - Log($"subs-check.exe {当前subsCheck版本号} 已启动..."); - timer4.Enabled = true; - } - catch (Exception ex) - { - Log($"启动 subs-check.exe 时出错: {ex.Message}", true); - button1.Text = "▶️ 启动"; - } - } - - - private void StopSubsCheckProcess() - { - timer4.Enabled = false; - if (subsCheckProcess != null && !subsCheckProcess.HasExited) - { - try - { - // 尝试正常关闭进程 - subsCheckProcess.Kill(); - subsCheckProcess.WaitForExit(); - Log("subs-check.exe 已停止"); - notifyIcon1.Icon = originalNotifyIcon; - button7.Enabled = false; - button7.Text = "🔀未启动"; - } - catch (Exception ex) - { - Log($"停止 subs-check.exe 时出错: {ex.Message}", true); - } - finally - { - subsCheckProcess.Dispose(); - subsCheckProcess = null; - } - } - } - - private void SubsCheckProcess_OutputDataReceived(object sender, DataReceivedEventArgs e) - { - if (!string.IsNullOrEmpty(e.Data)) - { - // 由于此事件在另一个线程中触发,需要使用 Invoke 在 UI 线程上更新控件 - BeginInvoke(new Action(() => - { - // 过滤ANSI转义序列 - string cleanText = RemoveAnsiEscapeCodes(e.Data); - - // 检查是否包含"下次检查时间"信息 - if (cleanText.Contains("下次检查时间:")) - { - if (button3.Enabled == false) - { - string executablePath = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); - string outputFolderPath = System.IO.Path.Combine(executablePath, "output"); - if (System.IO.Directory.Exists(outputFolderPath)) - { - string allyamlFilePath = System.IO.Path.Combine(outputFolderPath, "all.yaml"); - if (System.IO.File.Exists(allyamlFilePath)) button3.Enabled = true; - } - } - // 提取完整的下次检查时间信息 - int startIndex = cleanText.IndexOf("下次检查时间:"); - nextCheckTime = cleanText.Substring(startIndex); - } - - if (!cleanText.StartsWith("[GIN]")) - { - // 如果不是进度行,则添加到日志中 - richTextBox1.AppendText(cleanText + "\r\n"); - // 滚动到最底部 - richTextBox1.SelectionStart = richTextBox1.Text.Length; - richTextBox1.ScrollToCaret(); - } - - /* - // 检查是否是进度信息行 - if (cleanText.StartsWith("进度: [")) - { - // 解析百分比 - int percentIndex = cleanText.IndexOf('%'); - if (percentIndex > 0) - { - // 查找百分比前面的数字部分 - int startIndex = cleanText.LastIndexOfAny(new char[] { ' ', '>' }, percentIndex) + 1; - string percentText = cleanText.Substring(startIndex, percentIndex - startIndex); - - if (double.TryParse(percentText, out double percentValue)) - { - // 更新进度条,将百分比值(0-100)设置给进度条 - progressBar1.Value = (int)Math.Round(percentValue); - } - } - - // 解析节点信息部分(例如:(12/6167) 可用: 0) - int infoStartIndex = cleanText.IndexOf('('); - if (infoStartIndex > 0) - { - string fullNodeInfo = cleanText.Substring(infoStartIndex); - - // 提取最重要的信息:节点数量和可用数量 - int endIndex = fullNodeInfo.IndexOf("2025-"); // 查找日期部分开始位置 - if (endIndex > 0) - { - nodeInfo = fullNodeInfo.Substring(0, endIndex).Trim(); - } - else - { - // 如果找不到日期部分,则取前30个字符 - nodeInfo = fullNodeInfo.Length > 30 ? fullNodeInfo.Substring(0, 30) + "..." : fullNodeInfo; - } - - groupBox2.Text = "实时日志 " + nodeInfo; - - // 确保通知图标文本不超过63个字符 - string notifyText = "SubsCheck: " + nodeInfo; - if (notifyText.Length > 63) - { - notifyText = notifyText.Substring(0, 60) + "..."; - } - notifyIcon1.Text = notifyText; - } - - // 更新lastProgressLine,但不向richTextBox添加文本 - lastProgressLine = cleanText; - } - else - { - // 如果不是进度行,则添加到日志中 - richTextBox1.AppendText(cleanText + "\r\n"); - // 滚动到最底部 - richTextBox1.SelectionStart = richTextBox1.Text.Length; - richTextBox1.ScrollToCaret(); - } - */ - })); - } - } - - - // 添加一个方法来过滤ANSI转义序列 - private string RemoveAnsiEscapeCodes(string input) - { - // 匹配ANSI转义序列的正则表达式 - // 这将匹配类似 "[2m"、"[0m"、"[92m" 等格式的ANSI颜色代码 - return System.Text.RegularExpressions.Regex.Replace(input, @"\x1B\[[0-9;]*[mGK]", string.Empty); - } - - private void SubsCheckProcess_Exited(object sender, EventArgs e) - { - // 进程退出时,在 UI 线程上更新控件 - BeginInvoke(new Action(() => - { - Log("subs-check.exe 已退出"); - button1.Text = "▶️ 启动"; - - // 更新菜单项的启用状态 - startMenuItem.Enabled = true; - stopMenuItem.Enabled = false; - - // 重新启用控件 - numericUpDown1.Enabled = true; - numericUpDown2.Enabled = true; - numericUpDown3.Enabled = true; - numericUpDown4.Enabled = true; - numericUpDown5.Enabled = true; - numericUpDown6.Enabled = true; - textBox1.Enabled = true; - groupBox3.Enabled = true; - })); - } - - /// - /// 获取本地局域网IP地址,如果有多个则让用户选择 - /// - /// 用户选择的IP地址,如果未选择则返回127.0.0.1 - private string GetLocalLANIP() - { - try - { - // 获取所有网卡的IP地址 - List lanIPs = new List(); - - // 获取所有网络接口 - foreach (System.Net.NetworkInformation.NetworkInterface ni in System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()) - { - // 排除loopback、虚拟网卡和非活动网卡 - if (ni.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback && - ni.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up) - { - // 获取该网卡的所有IP地址 - foreach (System.Net.NetworkInformation.UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses) - { - // 只添加IPv4地址且不是回环地址 - if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && - !System.Net.IPAddress.IsLoopback(ip.Address)) - { - lanIPs.Add(ip.Address.ToString()); - } - } - } - } - - // 如果没有找到任何IP地址,返回本地回环地址 - if (lanIPs.Count == 0) - { - return "127.0.0.1"; - } - // 如果只找到一个IP地址,直接返回 - else if (lanIPs.Count == 1) - { - return lanIPs[0]; - } - // 如果有多个IP地址,让用户选择 - else - { - // 创建选择窗口 - Form selectForm = new Form(); - selectForm.Text = "选择局域网IP地址"; - selectForm.StartPosition = FormStartPosition.CenterParent; - /* - selectForm.Width = 520; // 保持宽度 - selectForm.Height = 320; // 增加高度以容纳额外的警告标签 - selectForm.FormBorderStyle = FormBorderStyle.FixedDialog; - */ - selectForm.AutoSize = true; // 启用自动大小调整 - selectForm.AutoSizeMode = AutoSizeMode.GrowAndShrink; // 根据内容调整大小 - selectForm.FormBorderStyle = FormBorderStyle.FixedSingle; // 使用固定但可调整的边框 - selectForm.ShowIcon = false; - selectForm.MaximizeBox = false; - selectForm.MinimizeBox = false; - - // 添加说明标签 - Label label = new Label(); - label.Text = "发现多个局域网IP地址:\n\n" + - "· 仅在本机访问:直接点击【取消】,将使用127.0.0.1\n\n" + - "· 局域网内其他设备访问:请在下面列表中选择一个正确的局域网IP"; - label.Location = new Point(15, 10); - label.AutoSize = true; - label.MaximumSize = new Size(380, 0); // 设置最大宽度,允许自动换行 - selectForm.Controls.Add(label); - - // 计算标签高度以正确放置列表框 - int labelHeight = label.Height + 20; - - // 添加IP地址列表框 - ListBox listBox = new ListBox(); - listBox.Location = new Point(15, labelHeight); - listBox.Width = 380; - listBox.Height = 130; // 保持列表框高度 - foreach (string ip in lanIPs) - { - listBox.Items.Add(ip); - } - // 查找非".1"结尾的IP地址,如果所有IP都以".1"结尾,则使用第一个IP - int selectedIndex = 0; - for (int i = 0; i < lanIPs.Count; i++) - { - if (!lanIPs[i].EndsWith(".1")) - { - selectedIndex = i; - break; - } - } - - // 设置选中的索引 - listBox.SelectedIndex = selectedIndex; - selectForm.Controls.Add(listBox); - - // 添加警告标签(放在列表框下方) - Label warningLabel = new Label(); - warningLabel.Text = "注意:选择错误的IP会导致局域网内其他设备无法访问。\n\n   推荐您可以先尝试使用非“.1”结尾的IP!"; - warningLabel.Location = new Point(15, labelHeight + listBox.Height + 10); - warningLabel.AutoSize = true; - warningLabel.ForeColor = Color.Red; // 警告文本使用红色 - selectForm.Controls.Add(warningLabel); - - // 计算按钮位置(居中排布) - int buttonY = labelHeight + listBox.Height + warningLabel.Height + 20; - int buttonTotalWidth = 75 * 2 + 15; // 两个按钮的宽度加间距 - int buttonStartX = (selectForm.ClientSize.Width - buttonTotalWidth) / 2; - - // 添加确定按钮 - Button okButton = new Button(); - okButton.Text = "确定"; - okButton.DialogResult = DialogResult.OK; - okButton.Location = new Point(buttonStartX, buttonY); - okButton.Width = 75; - selectForm.Controls.Add(okButton); - selectForm.AcceptButton = okButton; - - // 添加取消按钮 - Button cancelButton = new Button(); - cancelButton.Text = "取消"; - cancelButton.DialogResult = DialogResult.Cancel; - cancelButton.Location = new Point(buttonStartX + 90, buttonY); - cancelButton.Width = 75; - selectForm.Controls.Add(cancelButton); - selectForm.CancelButton = cancelButton; - - // 显示选择窗口 - if (selectForm.ShowDialog() == DialogResult.OK) - { - return listBox.SelectedItem.ToString(); - } - else - { - return "127.0.0.1"; // 如果用户取消,返回本地回环地址 - } - } - - - } - catch (Exception ex) - { - MessageBox.Show($"获取局域网IP地址时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - return "127.0.0.1"; - } - } - - private void button3_Click(object sender, EventArgs e) - { - string 本地IP = GetLocalLANIP(); - try - { - // 构造URL - string url = comboBox4.Text == "Clash" ? $"http://{本地IP}:{numericUpDown7.Value}/api/file/mihomo" : $"http://{本地IP}:{numericUpDown7.Value}/download/sub"; - - // 将URL复制到剪贴板 - Clipboard.SetText(url); - button3.Text = "复制成功"; - timer2.Enabled = true; - // 可选:显示提示消息 - //MessageBox.Show($"URL已复制到剪贴板:\n{url}", "复制成功", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - catch (Exception ex) - { - MessageBox.Show($"复制到剪贴板时出错:{ex.Message}", "错误", - MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - private void timer2_Tick(object sender, EventArgs e) - { - button3.Text = "复制订阅"; - } - - private void comboBox3_Leave(object sender, EventArgs e) - { - // 检查是否有内容 - if (string.IsNullOrWhiteSpace(comboBox3.Text)) - { - comboBox3.Text = "自动选择"; - return; - } - - string input = comboBox3.Text.Trim(); - - // 检查是否存在 "://" 协议部分 - int protocolIndex = input.IndexOf("://"); - if (protocolIndex >= 0) - { - // 保留 "://" 之后的内容 - input = input.Substring(protocolIndex + 3); - } - - // 检查是否存在 "/" 路径部分 - int pathIndex = input.IndexOf('/'); - if (pathIndex >= 0) - { - // 只保留 "/" 之前的域名部分 - input = input.Substring(0, pathIndex); - } - - // 更新 comboBox3 的文本 - comboBox3.Text = input; - } - - private void 判断保存类型() - { - if (comboBox1.Text == "本地" || button2.Text == "高级设置∨") - { - groupBox4.Visible = false; - groupBox5.Visible = false; - groupBox6.Visible = false; - } - else if (comboBox1.Text == "gist" && button2.Text == "高级设置∧") - { - groupBox4.Visible = true; - - groupBox5.Visible = false; - groupBox6.Visible = false; - } - else if (comboBox1.Text == "r2" && button2.Text == "高级设置∧") - { - groupBox5.Location = groupBox4.Location; - groupBox5.Visible = true; - - groupBox4.Visible = false; - groupBox6.Visible = false; - } - else if (comboBox1.Text == "webdav" && button2.Text == "高级设置∧") - { - groupBox6.Location = groupBox4.Location; - groupBox6.Visible = true; - - groupBox4.Visible = false; - groupBox5.Visible = false; - } - } - - private void comboBox1_TextChanged(object sender, EventArgs e) - { - 判断保存类型(); - if(!(comboBox1.Text == "本地" || comboBox1.Text == "") && button2.Text == "高级设置∨") button2_Click(sender, e); - } - - private void textBox3_Enter(object sender, EventArgs e) - { - textBox3.PasswordChar = '\0'; - textBox6.PasswordChar = '\0'; - textBox8.PasswordChar = '\0'; - } - - private void textBox3_Leave(object sender, EventArgs e) - { - textBox3.PasswordChar = '*'; - textBox6.PasswordChar = '*'; - textBox8.PasswordChar = '*'; - } - - private void textBox10_Enter(object sender, EventArgs e) - { - textBox10.PasswordChar = '\0'; - if (textBox10.Text == "请输入密钥") - { - textBox10.Text = ""; - textBox10.ForeColor = Color.Black; - } - } - - private void textBox10_Leave(object sender, EventArgs e) - { - - if (textBox10.Text == "") - { - textBox10.PasswordChar = '\0'; - textBox10.Text = "请输入密钥"; - textBox10.ForeColor = Color.Gray; - } - else - { - textBox10.ForeColor = Color.Black; - textBox10.PasswordChar = '*'; - } - } - - private void textBox7_Leave(object sender, EventArgs e) - { - // 检查是否有内容 - if (string.IsNullOrWhiteSpace(textBox7.Text)) - return; - - string input = textBox7.Text.Trim(); - - try - { - // 尝试解析为 URI - Uri uri = new Uri(input); - - // 构建基础 URL (scheme + authority) - string baseUrl = $"{uri.Scheme}://{uri.Authority}"; - - // 更新 textBox7 的文本为基础 URL - textBox7.Text = baseUrl; - } - catch (UriFormatException) - { - // 如果输入的不是有效 URI,尝试使用简单的字符串处理 - // 查找双斜杠后的第一个斜杠 - int schemeIndex = input.IndexOf("://"); - if (schemeIndex >= 0) - { - int pathStartIndex = input.IndexOf('/', schemeIndex + 3); - if (pathStartIndex >= 0) - { - // 截取到路径开始之前 - textBox7.Text = input.Substring(0, pathStartIndex); - } - } - } - } - - private void Log(string message, bool isError = false) - { - string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); - string logType = isError ? "ERR" : "INF"; - richTextBox1.AppendText($"{timestamp} {logType} {message}\r\n"); - - if (richTextBox1.IsHandleCreated) - { - richTextBox1.BeginInvoke((MethodInvoker)(() => - { - // 滚动到最底部 - richTextBox1.SelectionStart = richTextBox1.Text.Length; - richTextBox1.ScrollToCaret(); - })); - } - } - - private void 恢复窗口() - { - // 首先显示窗体 - this.Show(); - - // 强制停止当前布局逻辑 - this.SuspendLayout(); - - // 恢复窗口状态 - this.WindowState = FormWindowState.Normal; - - // 强制重新布局 - this.ResumeLayout(true); // 参数true表示立即执行布局 - - // 调用刷新布局的方法 - this.PerformLayout(); - - // 处理WindowsForms消息队列中的所有挂起消息 - Application.DoEvents(); - - // 激活窗口(使其获得焦点) - this.Activate(); - } - - private void 隐藏窗口() - { - // 隐藏窗体(从任务栏消失) - this.Hide(); - - // 确保通知图标可见 - notifyIcon1.Visible = true; - - // 可选:显示气泡提示 - notifyIcon1.ShowBalloonTip(1000, "SubsCheck", "程序已最小化到系统托盘", ToolTipIcon.Info); - } - - private void notifyIcon1_MouseClick(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) - { - // 检查窗口是否可见 - if (this.Visible) - { - // 如果窗口当前可见,则隐藏窗口 - 隐藏窗口(); - } - else - { - // 如果窗口当前不可见,则恢复窗口 - 恢复窗口(); - } - } - } - - // 创建专用方法用于异步检测GitHub代理 - private async Task DetectGitHubProxyAsync(List proxyItems) - { - bool proxyFound = false; - string detectedProxyURL = ""; - - Log("检测可用 GitHub 代理..."); - - // 遍历随机排序后的代理列表 - foreach (string proxyItem in proxyItems) - { - string checkUrl = $"https://{proxyItem}/https://raw.githubusercontent.com/cmliu/SubsCheck-Win-GUI/master/packages.config"; - Log($"正在测试 GitHub 代理: {proxyItem}"); - richTextBox1.Refresh(); - - try - { - using (HttpClient client = new HttpClient()) - { - client.Timeout = TimeSpan.FromSeconds(5); // 设置5秒超时 - // 添加User-Agent头,避免被拒绝访问 - client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); - - // 使用异步方式 - HttpResponseMessage response = await client.GetAsync(checkUrl); - if (response.IsSuccessStatusCode) - { - // 找到可用代理 - detectedProxyURL = $"https://{proxyItem}/"; - Log($"找到可用 GitHub 代理: {proxyItem}"); - proxyFound = true; - break; - } - } - } - catch (Exception ex) - { - // 记录错误但继续尝试下一个 - Log($"代理 {proxyItem} 测试失败: {ex.Message}", true); - richTextBox1.Refresh(); - } - } - - // 如果没有找到可用的代理 - if (!proxyFound) - { - Log("未找到可用的 GitHub 代理,请在高级设置中手动设置。", true); - MessageBox.Show("未找到可用的 GitHub 代理。\n\n请打开高级设置手动填入一个可用的Github Proxy,或检查您的网络连接。", - "代理检测失败", - MessageBoxButtons.OK, - MessageBoxIcon.Warning); - } - - return detectedProxyURL; - } - - private async void button5_Click(object sender, EventArgs e) - { - try - { - button5.Enabled = false; - button1.Enabled = false; - // 清空日志 - richTextBox1.Clear(); - Log("开始检查和下载最新版本的 subs-check.exe..."); - - // 获取当前应用程序目录 - string executablePath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); - string subsCheckPath = Path.Combine(executablePath, "subs-check.exe"); - - // 检查文件是否存在 - if (File.Exists(subsCheckPath)) - { - Log($"发现 subs-check.exe,正在删除..."); - - try - { - // 首先检查是否有进程正在运行 - Process[] processes = Process.GetProcessesByName("subs-check"); - if (processes.Length > 0) - { - Log("发现正在运行的 subs-check.exe 进程,正在强制结束..."); - foreach (Process process in processes) - { - try - { - process.Kill(); - process.WaitForExit(); - Log($"成功结束 subs-check.exe 进程(ID: {process.Id})"); - } - catch (Exception ex) - { - Log($"结束进程时出错(ID: {process.Id}): {ex.Message}", true); - } - } - } - - // 删除文件 - File.Delete(subsCheckPath); - Log("成功删除旧版本 subs-check.exe"); - } - catch (Exception ex) - { - Log($"删除 subs-check.exe 时出错: {ex.Message}", true); - MessageBox.Show($"无法删除现有的 subs-check.exe 文件: {ex.Message}\n\n请手动删除后重试,或者检查文件是否被其他程序占用。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - button5.Enabled = true; - return; - } - } - else - { - Log("未找到现有的 subs-check.exe 文件,将直接下载最新版本"); - } - - // 检测可用的 GitHub 代理 - if (!string.IsNullOrEmpty(comboBox3.Text) && comboBox3.Text == "自动选择") - { - // 创建不包含"自动选择"的代理列表 - List proxyItems = new List(); - for (int j = 0; j < comboBox3.Items.Count; j++) - { - string proxyItem = comboBox3.Items[j].ToString(); - if (proxyItem != "自动选择") - proxyItems.Add(proxyItem); - } - - // 随机打乱列表顺序 - Random random = new Random(); - proxyItems = proxyItems.OrderBy(x => random.Next()).ToList(); - - // 异步检测可用代理 - githubProxyURL = await DetectGitHubProxyAsync(proxyItems); - - // 如果未能找到可用代理,提示用户 - if (string.IsNullOrEmpty(githubProxyURL)) - { - Log("未能找到可用的 GitHub 代理,下载可能会失败", true); - } - } - else if (!string.IsNullOrEmpty(comboBox3.Text)) - { - githubProxyURL = $"https://{comboBox3.Text}/"; - Log($"使用指定的 GitHub 代理: {comboBox3.Text}"); - } - else - { - Log("未设置 GitHub 代理,将尝试直接下载", true); - } - - // 下载最新版本的 subs-check.exe - await DownloadSubsCheckEXE(); - - // 完成 - Log("内核更新完成!"); - } - catch (Exception ex) - { - Log($"操作过程中出错: {ex.Message}", true); - MessageBox.Show($"处理过程中出现错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - finally - { - button5.Enabled = true; - button1.Enabled = true; - } - } - - private decimal 订阅端口; - private decimal SubStore端口; - private void numericUpDown6_ValueChanged(object sender, EventArgs e) - { - // 检查numericUpDown7是否存在并且与numericUpDown6的值相等 - if (numericUpDown6.Value == numericUpDown7.Value) - { - // 显示警告消息 - MessageBox.Show("订阅端口 和 Sub-Store端口 不能相同!", - "端口冲突", - MessageBoxButtons.OK, - MessageBoxIcon.Warning); - - // 将numericUpDown6的值恢复为更改前的值 - numericUpDown6.Value = 订阅端口; - numericUpDown7.Value = SubStore端口; - } - else - { - // 保存当前值作为下次比较的基准 - 订阅端口 = numericUpDown6.Value; - SubStore端口 = numericUpDown7.Value; - } - } - - /// - /// 异步检测并强制终止所有程序目录下的output\node.exe进程 - /// - private async Task KillNodeProcessAsync() - { - try - { - Log("检查 node.exe 进程状态..."); - - // 获取当前应用程序的执行目录 - string executablePath = Path.GetDirectoryName(Application.ExecutablePath); - string nodeExePath = Path.Combine(executablePath, "output", "node.exe"); - - // 获取所有node.exe进程 - Process[] nodeProcesses = Process.GetProcessesByName("node"); - - if (nodeProcesses.Length == 0) - { - Log("未发现运行中的 node.exe 进程"); - return; - } - - Log($"发现 {nodeProcesses.Length} 个 node.exe 进程,开始检查并终止匹配路径的进程..."); - - int terminatedCount = 0; - - foreach (Process process in nodeProcesses) - { - try - { - // 使用Task.Run将可能耗时的操作放在后台线程执行 - string processPath = await Task.Run(() => { - try - { - return process.MainModule?.FileName; - } - catch (Exception) - { - return null; - } - }); - - // 检查是否匹配我们要查找的node.exe路径 - if (!string.IsNullOrEmpty(processPath) && - processPath.Equals(nodeExePath, StringComparison.OrdinalIgnoreCase)) - { - // 找到匹配的进程,终止它 - Log($"发现匹配路径的 node.exe 进程(ID: {process.Id}),正在强制结束..."); - - await Task.Run(() => { - process.Kill(); - process.WaitForExit(); - }); - - Log($"成功结束 node.exe 进程(ID: {process.Id})"); - terminatedCount++; - } - } - catch (Exception ex) - { - // 访问进程信息时可能会因为权限问题抛出异常 - Log($"访问或终止进程(ID: {process.Id})时出错: {ex.Message}", true); - } - } - - if (terminatedCount > 0) - { - Log($"总共终止了 {terminatedCount} 个匹配路径的 node.exe 进程"); - } - else - { - Log("未发现需要终止的 node.exe 进程"); - } - } - catch (Exception ex) - { - Log($"检查或终止 node.exe 进程时出错: {ex.Message}", true); - } - } - - private async void textBox1_DoubleClick(object sender, EventArgs e) - { - if (textBox1.Enabled) - { - // 创建EditURLs窗口的实例 - EditURLs editURLsForm = new EditURLs(); - - // 传递当前textBox1的内容到EditURLs窗口 - editURLsForm.UrlContent = textBox1.Text + "\n"; - editURLsForm.githubProxys = comboBox3.Items; - editURLsForm.githubProxy = comboBox3.Text; - // 显示对话框并等待结果 - DialogResult result = editURLsForm.ShowDialog(); - - // 如果用户点击了"保存并关闭"按钮(返回DialogResult.OK) - if (result == DialogResult.OK) - { - // 获取编辑后的内容,按行拆分,过滤空行 - string[] lines = editURLsForm.UrlContent.Split( - new[] { "\r\n", "\r", "\n" }, - StringSplitOptions.RemoveEmptyEntries); - - // 去除每行首尾的空白字符 - for (int i = 0; i < lines.Length; i++) - { - lines[i] = lines[i].Trim(); - } - - // 再次过滤掉空行 - lines = lines.Where(line => !string.IsNullOrWhiteSpace(line)).ToArray(); - - // 将处理后的内容更新到Form1的textBox1 - textBox1.Text = string.Join(Environment.NewLine, lines); - await SaveConfig(false); - Log("已保存订阅地址列表。"); - } - } - - } - - private void checkBox1_CheckedChanged(object sender, EventArgs e) - { - if (checkBox1.Checked == false) checkBox2.Checked = false; - } - - private void checkBox2_CheckedChanged(object sender, EventArgs e) - { - if (checkBox2.Checked == true) checkBox1.Checked = true; - } - - private async void timer3_Tick(object sender, EventArgs e) - { - if (button1.Text == "⏹️ 停止") - { - Log("subs-check.exe 运行时满24小时,自动重启清理内存占用。"); - // 停止 subs-check.exe 程序 - StopSubsCheckProcess(); - // 结束 Sub-Store - await KillNodeProcessAsync(); - // 重新启动 subs-check.exe 程序 - StartSubsCheckProcess(); - numericUpDown1.Enabled = false; - numericUpDown2.Enabled = false; - numericUpDown3.Enabled = false; - numericUpDown4.Enabled = false; - numericUpDown5.Enabled = false; - numericUpDown6.Enabled = false; - numericUpDown7.Enabled = false; - comboBox1.Enabled = false; - textBox1.Enabled = false; - groupBox3.Enabled = false; - groupBox4.Enabled = false; - groupBox5.Enabled = false; - groupBox6.Enabled = false; - button1.Text = "⏹️ 停止"; - } - } - - private void button4_Click(object sender, EventArgs e) - { - // 创建 CheckUpdates 窗口实例 - CheckUpdates checkUpdatesForm = new CheckUpdates(); - - // 传递必要的数据和状态 - checkUpdatesForm.githubProxys = comboBox3.Items; - checkUpdatesForm.githubProxy = comboBox3.Text; - - checkUpdatesForm.当前subsCheck版本号 = 当前subsCheck版本号; - checkUpdatesForm.当前GUI版本号 = 当前GUI版本号; - checkUpdatesForm.最新GUI版本号 = 最新GUI版本号; - - // 为 CheckUpdates 的 button2 添加点击事件处理程序 - checkUpdatesForm.FormClosed += (s, args) => { - // 移除事件处理,避免内存泄漏 - if (checkUpdatesForm.DialogResult == DialogResult.OK) - { - // 如果返回OK结果,表示按钮被点击并需要更新内核 - button5_Click(this, EventArgs.Empty); - } - }; - - // 设置 button2 点击后关闭窗口并返回 DialogResult.OK - // 这需要在 CheckUpdates.cs 中修改 button2_Click 方法 - - // 显示 CheckUpdates 窗口 - checkUpdatesForm.ShowDialog(); - } - - private void checkBox3_CheckedChanged(object sender, EventArgs e) - { - if (checkBox3.Checked) numericUpDown8.Enabled = true; - else numericUpDown8.Enabled = false; - } - - private async void comboBox5_SelectedIndexChanged(object sender, EventArgs e) - { - if (comboBox5.Text.Contains("[内置]")) await ProcessComboBox5Selection(true); - } - - private async Task ProcessComboBox5Selection(bool 汇报Log = false) - { - // 确定文件名和下载URL - string fileName; - string downloadFilePath; - string downloadUrl; - string displayName; - string executablePath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); - if (comboBox5.Text.Contains("[内置]布丁狗")) - { - fileName = "bdg.yaml"; - displayName = "[内置]布丁狗的订阅转换"; - downloadUrl = "https://raw.githubusercontent.com/cmliu/ACL4SSR/main/yaml/bdg.yaml"; - } - else // [内置]ACL4SSR - { - fileName = "ACL4SSR_Online_Full.yaml"; - displayName = "[内置]ACL4SSR_Online_Full"; - downloadUrl = "https://raw.githubusercontent.com/beck-8/override-hub/main/yaml/ACL4SSR_Online_Full.yaml"; - } - - // 确保output文件夹存在 - string outputFolderPath = Path.Combine(executablePath, "output"); - if (!Directory.Exists(outputFolderPath)) - { - Directory.CreateDirectory(outputFolderPath); - } - - // 确定文件完整路径 - downloadFilePath = Path.Combine(outputFolderPath, fileName); - - // 检查文件是否存在 - if (!File.Exists(downloadFilePath)) - { - Log($"{displayName} 覆写配置文件 未找到,正在下载..."); - - // 重置进度条 - progressBar1.Value = 0; - - // 添加GitHub代理前缀如果有 - string fullDownloadUrl = githubProxyURL + downloadUrl; - - try - { - // 创建不使用系统代理的HttpClientHandler - using (HttpClientHandler handler = new HttpClientHandler { UseProxy = false, Proxy = null }) - using (HttpClient client = new HttpClient(handler)) - { - client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); - client.Timeout = TimeSpan.FromSeconds(15); // 设置15秒超时 - - // 先获取文件大小 - HttpResponseMessage headResponse = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, fullDownloadUrl)); - long totalBytes = headResponse.Content.Headers.ContentLength ?? 0; - - // 如果无法获取文件大小,显示不确定进度 - if (totalBytes == 0) - { - Console.WriteLine($"无法获取 {displayName} 文件大小,将显示不确定进度"); - } - - // 创建下载请求并获取响应流 - using (var response = await client.GetAsync(fullDownloadUrl, HttpCompletionOption.ResponseHeadersRead)) - { - if (response.IsSuccessStatusCode) - { - using (var contentStream = await response.Content.ReadAsStreamAsync()) - using (var fileStream = new FileStream(downloadFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true)) - { - byte[] buffer = new byte[8192]; - long totalBytesRead = 0; - int bytesRead; - - while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0) - { - await fileStream.WriteAsync(buffer, 0, bytesRead); - totalBytesRead += bytesRead; - - // 更新进度条 - if (totalBytes > 0) - { - int progressPercentage = (int)((totalBytesRead * 100) / totalBytes); - // 确保进度值在有效范围内 (0-100) - progressPercentage = Math.Min(100, Math.Max(0, progressPercentage)); - progressBar1.Value = progressPercentage; - } - } - - // 确保进度条显示100% - progressBar1.Value = 100; - } - - Log($"{displayName} 覆写配置文件 下载成功"); - } - else - { - Log($"{displayName} 覆写配置文件 下载失败: HTTP {(int)response.StatusCode} {response.ReasonPhrase}", true); - } - } - } - } - catch (Exception ex) - { - Log($"{displayName} 覆写配置文件 下载失败: {ex.Message}", true); - // 出错时重置进度条 - progressBar1.Value = 0; - } - } - else - { - if (汇报Log) Log($"{displayName} 覆写配置文件 已就绪。"); - } - } - - private void numericUpDown1_ValueChanged(object sender, EventArgs e) - { - if (numericUpDown1.Value > 128) - { - string warningMessage = - "⚠️ 高并发风险提醒 ⚠️\n\n" + - "您设置的并发数值过高,可能导致:\n\n" + - "• 运营商判定为异常流量并限制网络\n" + - "• 路由器性能压力过大\n" + - "• 测速结果不准确\n\n" + - "并发数设置建议:\n" + - "• 宽带峰值/50Mbps:一般对网络无影响\n" + - "• 宽带峰值/25Mbps:可能会影响同网络下载任务\n" + - "• 宽带峰值/10Mbps:可能会影响同网络下其他设备的上网体验\n"; - - Log(warningMessage); - } - } - - private void checkBox4_CheckedChanged(object sender, EventArgs e) - { - if(checkBox4.Checked) textBox10.Enabled = true; - else textBox10.Enabled = false; - } - - private void button6_Click(object sender, EventArgs e) - { - string 本地IP = GetLocalLANIP(); - try - { - // 构造URL - string url = $"http://{本地IP}:{numericUpDown6.Value}/admin"; - - // 使用系统默认浏览器打开URL - System.Diagnostics.Process.Start(url); - - Log($"正在浏览器中打开 Subs-Check 配置管理: {url}"); - } - catch (Exception ex) - { - Log($"打开浏览器失败: {ex.Message}", true); - MessageBox.Show($"打开浏览器时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - /// - /// 获取API状态信息并返回包含6个元素的字符串数组 - /// - /// - /// 包含6个元素的字符串数组: - /// [0] - 状态类型 ("checking"/"idle"/"error") - /// [1] - 状态图标类别 ("primary"/"success"/"danger") - /// [2] - 状态文本 ("正在检测中..."/"空闲"/"获取状态失败") - /// [3] - 节点总数 (proxyCount或"N/A") - /// [4] - 进度百分比 (progress或"N/A") - /// [5] - 可用节点数量 (available或"N/A") - /// - private async Task GetApiStatusAsync() - { - string[] resultArray = new string[6]; - string baseUrl = $"http://127.0.0.1:{numericUpDown6.Value}"; - - try - { - using (HttpClient client = new HttpClient()) - { - // 设置基础URL - client.BaseAddress = new Uri(baseUrl); - - // 添加API密钥请求头 - client.DefaultRequestHeaders.Add("X-API-Key", WebUIapiKey); - - // 设置超时时间 - client.Timeout = TimeSpan.FromSeconds(5); - - // 发送请求 - HttpResponseMessage response = await client.GetAsync("/api/status"); - - // 检查响应状态 - if (response.IsSuccessStatusCode) - { - // 读取响应内容 - string content = await response.Content.ReadAsStringAsync(); - - // 解析JSON - JObject data = JObject.Parse(content); - - if (data["checking"] != null && data["checking"].Value()) - { - // 正在检测状态 - resultArray[0] = "checking"; - resultArray[1] = "primary"; - resultArray[2] = "正在检测中..."; - - // 提取节点数据 - resultArray[3] = data["proxyCount"]?.ToString() ?? "0"; - resultArray[4] = data["progress"]?.ToString() ?? "0"; - resultArray[5] = data["available"]?.ToString() ?? "0"; - } - else - { - // 空闲状态 - resultArray[0] = "idle"; - resultArray[1] = "success"; - resultArray[2] = "空闲"; - - // 空闲时相关数据设为N/A - resultArray[3] = "N/A"; - resultArray[4] = "N/A"; - resultArray[5] = "N/A"; - } - } - else - { - // 请求失败,例如未授权 - resultArray[0] = "error"; - resultArray[1] = "danger"; - resultArray[2] = $"API请求失败: {(int)response.StatusCode}"; - resultArray[3] = "N/A"; - resultArray[4] = "N/A"; - resultArray[5] = "N/A"; - } - } - } - catch (Exception ex) - { - // 发生异常 - resultArray[0] = "error"; - resultArray[1] = "danger"; - resultArray[2] = $"获取状态失败: {ex.Message}"; - resultArray[3] = "N/A"; - resultArray[4] = "N/A"; - resultArray[5] = "N/A"; - - // 可选:记录错误到日志 - Log($"获取API状态失败: {ex.Message}", true); - } - - return resultArray; - } - - private async void timer4_Tick(object sender, EventArgs e) - { - //if (!button7.Enabled) button7.Enabled = true; - string[] subscheck状态 = await GetApiStatusAsync(); - string 状态类型 = subscheck状态[0]; - string 状态图标类别 = subscheck状态[1]; - string 状态文本 = subscheck状态[2]; - string 节点总数 = subscheck状态[3]; - string 进度百分比 = subscheck状态[4]; - string 可用节点数量 = subscheck状态[5]; - // 更新状态文本 - - if (状态类型 == "checking") - { - button7.Text = "⏸️ 暂停"; - nodeInfo = $"({进度百分比}/{节点总数}) 可用: {可用节点数量}"; - int nodeTotal = int.Parse(节点总数); - if (nodeTotal > 0) { - int 进度条百分比 = int.Parse(进度百分比) * 100 / nodeTotal; - progressBar1.Value = 进度条百分比; - if (!button7.Enabled) button7.Enabled = true; - } - - // 确保通知图标文本不超过63个字符 - string notifyText = "SubsCheck: " + nodeInfo; - if (notifyText.Length > 63) - { - notifyText = notifyText.Substring(0, 60) + "..."; - } - notifyIcon1.Text = notifyText; - textBox1.Enabled = false; - } - else if (状态类型 == "idle") - { - button7.Text = "⏯️ 开始"; - progressBar1.Value = 100; - nodeInfo = $"等待{nextCheckTime}"; - notifyIcon1.Text = "SubsCheck: 已就绪\n" + nextCheckTime; ; - textBox1.Enabled = true; - } - else if (状态类型 == "error") - { - button7.Text = "🔀 未知"; - nodeInfo = 状态文本; - } - groupBox2.Text = $"实时日志 {nodeInfo}"; - } - - private async void button7_Click(object sender, EventArgs e) - { - button7.Enabled = false; - timer4.Enabled = false; - - try - { - bool isSuccess; - - if (button7.Text == "⏯️ 开始") - { - isSuccess = await SendApiRequestAsync("/api/trigger-check", "节点检查"); - if (isSuccess) - { - button7.Text = "⏸️ 暂停"; - textBox1.Enabled = false; // 检查开始后禁用订阅编辑 - } - } - else // "⏸️ 暂停" - { - isSuccess = await SendApiRequestAsync("/api/force-close", "强制关闭"); - } - - // 如果请求失败,更新按钮状态为未知 - if (!isSuccess) button7.Text = "🔀 未知"; - } - finally - { - // 无论成功失败都重新启用定时器和按钮 - timer4.Enabled = true; - timer4.Start(); - //button7.Enabled = true; - } - } - - /// - /// 发送API请求到SubsCheck服务 - /// - /// API端点路径 - /// 操作名称(用于日志) - /// 操作是否成功 - private async Task SendApiRequestAsync(string endpoint, string operationName) - { - try - { - // 获取API基础地址和API密钥 - string baseUrl = $"http://127.0.0.1:{numericUpDown6.Value}"; - - using (HttpClient client = new HttpClient()) - { - client.BaseAddress = new Uri(baseUrl); - client.DefaultRequestHeaders.Add("X-API-Key", WebUIapiKey); - client.Timeout = TimeSpan.FromSeconds(10); - - // 发送POST请求 - HttpResponseMessage response = await client.PostAsync(endpoint, new StringContent("")); - - // 检查响应状态 - if (response.IsSuccessStatusCode) - { - Log($"成功{operationName}"); - return true; - } - else - { - string errorContent = await response.Content.ReadAsStringAsync(); - Log($"{operationName}失败: HTTP {(int)response.StatusCode} {response.ReasonPhrase}\n{errorContent}", true); - return false; - } - } - } - catch (Exception ex) - { - Log($"{operationName}时发生错误: {ex.Message}", true); - return false; - } - } - - private void textBox11_Leave(object sender, EventArgs e) - { - if (IsValidCronExpression(textBox11.Text)) - { - // 计算并显示cron表达式的说明 - string cronDescription = GetCronExpressionDescription(textBox11.Text); - // 可以用工具提示或者消息框显示,这里使用消息框 - //MessageBox.Show(cronDescription, "Cron表达式说明", MessageBoxButtons.OK, MessageBoxIcon.Information); - Log($"Cron表达式说明 {cronDescription}"); - } - else - { - MessageBox.Show("请输入有效的cron表达式,例如:*/30 * * * *", "无效的cron表达式", - MessageBoxButtons.OK, MessageBoxIcon.Warning); - textBox11.Focus(); - textBox11.Text = "0 */2 * * *"; // 恢复默认值 - } - } - - /// - /// 验证输入文本是否是合法的cron表达式 - /// - /// 如果是合法的cron表达式,则返回true;否则返回false - private bool IsValidCronExpression(string cron表达式) - { - string cronExpression = cron表达式.Trim(); - - // 如果是空字符串,则不是有效表达式 - if (string.IsNullOrWhiteSpace(cronExpression)) - return false; - - // 分割cron表达式为5个部分:分钟 小时 日期 月份 星期 - string[] parts = cronExpression.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - - // cron表达式必须有5个部分 - if (parts.Length != 5) - return false; - - try - { - // 验证每个部分 - // 分钟 (0-59) - if (!IsValidCronField(parts[0], 0, 59)) - return false; - - // 小时 (0-23) - if (!IsValidCronField(parts[1], 0, 23)) - return false; - - // 日期 (1-31) - if (!IsValidCronField(parts[2], 1, 31)) - return false; - - // 月份 (1-12) - if (!IsValidCronField(parts[3], 1, 12)) - return false; - - // 星期 (0-7,0和7都表示星期日) - if (!IsValidCronField(parts[4], 0, 7)) - return false; - - return true; - } - catch - { - return false; - } - } - - /// - /// 验证cron表达式中的单个字段是否合法 - /// - /// 字段值 - /// 最小允许值 - /// 最大允许值 - /// 如果字段合法,则返回true;否则返回false - private bool IsValidCronField(string field, int min, int max) - { - // 处理通配符 "*" - if (field == "*") - return true; - - // 处理步长 "*/n" - if (field.StartsWith("*/")) - { - string stepStr = field.Substring(2); - if (int.TryParse(stepStr, out int step)) - return step > 0 && step <= max; - return false; - } - - // 处理范围 "n-m" - if (field.Contains("-")) - { - string[] range = field.Split('-'); - if (range.Length != 2) - return false; - - if (int.TryParse(range[0], out int start) && int.TryParse(range[1], out int end)) - return start >= min && end <= max && start <= end; - return false; - } - - // 处理列表 "n,m,k" - if (field.Contains(",")) - { - string[] values = field.Split(','); - foreach (string item in values) - { - if (!int.TryParse(item, out int itemValue) || itemValue < min || itemValue > max) - return false; - } - return true; - } - - // 处理单个数字 - if (int.TryParse(field, out int fieldValue)) - return fieldValue >= min && fieldValue <= max; - - return false; - } - - /// - /// 获取cron表达式的友好文本说明 - /// - /// 要解析的cron表达式 - /// 返回cron表达式的执行时间说明 - private string GetCronExpressionDescription(string cron表达式) - { - try - { - string cronExpression = cron表达式.Trim(); - string[] parts = cronExpression.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - - if (parts.Length != 5) - return "无效的cron表达式"; - - // 分别解析每个部分 - string minuteDesc = ParseCronPart(parts[0], "分钟", 0, 59); - string hourDesc = ParseCronPart(parts[1], "小时", 0, 23); - string dayDesc = ParseCronPart(parts[2], "日", 1, 31); - string monthDesc = ParseCronPart(parts[3], "月", 1, 12); - string weekDesc = ParseCronPart(parts[4], "星期", 0, 7, true); - - // 组合最终说明 - string description = "执行时间: "; - - // 月份 - if (monthDesc != "每月") - description += monthDesc + "的"; - - // 星期与日期的关系 - if (parts[2] == "*" && parts[4] != "*") - description += weekDesc + "的"; - else if (parts[2] != "*" && parts[4] == "*") - description += dayDesc; - else if (parts[2] != "*" && parts[4] != "*") - description += $"{dayDesc}或{weekDesc}"; - else - description += "每天"; - - // 时间(小时:分钟) - description += $"{hourDesc}{minuteDesc}"; - - return description; - } - catch - { - return "无法解析cron表达式"; - } - } - - /// - /// 解析cron表达式的单个部分 - /// - private string ParseCronPart(string part, string unit, int min, int max, bool isWeekday = false) - { - // 处理星号,表示每个时间单位 - if (part == "*") - { - return $"每{unit}"; - } - - // 处理步长 */n - if (part.StartsWith("*/")) - { - int step = int.Parse(part.Substring(2)); - return $"每{step}{unit}"; - } - - // 处理范围 n-m - if (part.Contains("-")) - { - string[] range = part.Split('-'); - int start = int.Parse(range[0]); - int end = int.Parse(range[1]); - - if (isWeekday) - { - string[] weekdays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" }; - return $"从{weekdays[start]}到{weekdays[end]}"; - } - - return $"从{start}{unit}到{end}{unit}"; - } - - // 处理列表 n,m,k - if (part.Contains(",")) - { - string[] values = part.Split(','); - if (isWeekday) - { - string[] weekdays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" }; - return string.Join("、", values.Select(v => weekdays[int.Parse(v)])); - } - return $"{string.Join("、", values)}{unit}"; - } - - // 处理单个数字 - int value = int.Parse(part); - if (isWeekday) - { - string[] weekdays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" }; - return weekdays[value]; - } - return $"{value}{unit}"; - } - - private void 切换cron表达式(object sender, EventArgs e) - { - if (textBox11.Visible) - { - textBox11.Visible = false; - label2.Visible = true; - numericUpDown2.Visible = true; - Log("下次检查时间间隔 使用分钟倒计时"); - } - else - { - textBox11.Location = new Point(9, 48); - textBox11.Visible = true; - label2.Visible = false; - numericUpDown2.Visible = false; - Log("下次检查时间间隔 使用cron表达式"); - } - } - - /// - /// 获取计算机名的MD5哈希值 - /// - /// 返回计算机名的MD5哈希字符串(32位小写) - private string GetComputerNameMD5() - { - try - { - // 获取计算机名 - string computerName = System.Environment.MachineName; - - // 引入必要的命名空间 - using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create()) - { - // 将计算机名转换为字节数组 - byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(computerName); - - // 计算MD5哈希值 - byte[] hashBytes = md5.ComputeHash(inputBytes); - - // 将字节数组转换为十六进制字符串 - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < hashBytes.Length; i++) - { - sb.Append(hashBytes[i].ToString("x2")); - } - - return sb.ToString(); - } - } - catch (Exception ex) - { - Log($"计算计算机名MD5时出错: {ex.Message}", true); - return "CMLiussss"; - } - } - - // 添加辅助下载方法 - async Task DownloadFileAsync(HttpClient httpClient, string url, string filePath) - { - try - { - // 获取文件大小 - HttpResponseMessage headResponse = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, url)); - headResponse.EnsureSuccessStatusCode(); // 确保请求成功 - long totalBytes = headResponse.Content.Headers.ContentLength ?? 0; - - // 下载文件 - using (var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead)) - { - response.EnsureSuccessStatusCode(); // 确保请求成功 - - using (var contentStream = await response.Content.ReadAsStreamAsync()) - using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true)) - { - byte[] buffer = new byte[8192]; - long totalBytesRead = 0; - int bytesRead; - - while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0) - { - await fileStream.WriteAsync(buffer, 0, bytesRead); - totalBytesRead += bytesRead; - - // 更新进度条 - if (totalBytes > 0) - { - int progressPercentage = (int)((totalBytesRead * 100) / totalBytes); - progressPercentage = Math.Min(100, Math.Max(0, progressPercentage)); - progressBar1.Value = progressPercentage; - } - } - } - } - - return true; // 下载成功 - } - catch - { - throw; // 重新抛出异常,让调用者处理 - } - } - - private static about aboutWindow = null; - private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - // 检查窗口是否已经打开 - if (aboutWindow != null && !aboutWindow.IsDisposed) - { - // 窗口已经存在,激活它 - aboutWindow.Activate(); - return; - } - - // 需要创建新窗口 - this.BeginInvoke(new Action(() => - { - // 创建about窗口实例 - aboutWindow = new about(); - - // 传递版本号信息 - aboutWindow.GuiVersion = 当前GUI版本号; - aboutWindow.CoreVersion = 当前subsCheck版本号; - - // 添加窗口关闭时的处理,清除静态引用 - aboutWindow.FormClosed += (s, args) => aboutWindow = null; - - // 非模态显示窗口 - aboutWindow.Show(this); - - // 设置TopMost确保窗口显示在最前面 - aboutWindow.TopMost = true; - })); - } - - private void button8_Click(object sender, EventArgs e) - { - try - { - // 创建MoreYAML窗口实例 - MoreYAML moreYamlWindow = new MoreYAML(); - - // 显示为模态对话框,这会阻塞主线程直到窗口关闭 - DialogResult result = moreYamlWindow.ShowDialog(this); - - // 如果需要,可以处理对话框的返回结果 - if (result == DialogResult.OK) - { - // 用户点击了"确定"或某种完成操作的按钮 - Log("补充参数配置已成功保存到 more.yaml 文件!设置已应用"); - } - } - catch (Exception ex) - { - Log($"打开MoreYAML窗口时出错: {ex.Message}", true); - MessageBox.Show($"打开MoreYAML窗口时出错: {ex.Message}", "错误", - MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - private async void checkBox5_CheckedChanged(object sender, EventArgs e) - { - checkBox5.Enabled = false; - try - { - // 获取当前应用程序的可执行文件路径 - string appPath = Application.ExecutablePath; - // 获取应用程序名称(不包含扩展名) - string appName = Path.GetFileNameWithoutExtension(appPath); - // 获取启动文件夹的路径 - string startupFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup); - // 快捷方式文件的完整路径 - string shortcutPath = Path.Combine(startupFolderPath, $"{appName}.lnk"); - - if (checkBox5.Checked) - { - // 检查启动文件夹中是否已存在该快捷方式 - if (File.Exists(shortcutPath)) - { - Log("开机启动项已存在,无需重复创建"); - } - else - { - // 创建快捷方式 - CreateShortcut(appPath, shortcutPath, "-auto"); - Log("已成功创建开机启动项,下次电脑启动时将自动运行程序"); - } - } - else - { - // 删除启动项 - if (File.Exists(shortcutPath)) - { - File.Delete(shortcutPath); - Log("已移除开机启动项,下次开机将不会自动启动"); - } - } - } - catch (Exception ex) - { - Log($"设置开机启动项时出错: {ex.Message}", true); - MessageBox.Show($"设置开机启动项失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - - // 恢复CheckBox状态,避免UI状态与实际状态不一致 - checkBox5.CheckedChanged -= checkBox5_CheckedChanged; - checkBox5.Checked = !checkBox5.Checked; - checkBox5.CheckedChanged += checkBox5_CheckedChanged; - } - checkBox5.Enabled = true; - await SaveConfig(false); - } - - /// - /// 创建指向指定路径应用程序的快捷方式 - /// - /// 目标应用程序的完整路径 - /// 要创建的快捷方式的完整路径 - /// 可选的启动参数 - private void CreateShortcut(string targetPath, string shortcutPath, string arguments = "") - { - // 使用COM接口创建快捷方式 - Type t = Type.GetTypeFromProgID("WScript.Shell"); - dynamic shell = Activator.CreateInstance(t); - var shortcut = shell.CreateShortcut(shortcutPath); - - shortcut.TargetPath = targetPath; - if (!string.IsNullOrEmpty(arguments)) - shortcut.Arguments = arguments; // 设置启动参数 - - shortcut.WorkingDirectory = Path.GetDirectoryName(targetPath); - shortcut.WindowStyle = 7; // 最小化启动: 7, 正常启动: 1, 最大化启动: 3 - shortcut.Description = "SubsCheck Win GUI自启动快捷方式"; - shortcut.IconLocation = targetPath + ",0"; // 使用应用程序自身的图标 - - // 保存快捷方式 - shortcut.Save(); - - // 释放COM对象 - System.Runtime.InteropServices.Marshal.FinalReleaseComObject(shortcut); - System.Runtime.InteropServices.Marshal.FinalReleaseComObject(shell); - } - - /// - /// 检查启动参数中是否包含指定的参数 - /// - /// 要检查的参数名称,例如"-autoup" - /// 如果存在指定参数,则返回true;否则返回false - private bool CheckCommandLineParameter(string parameterName) - { - // 获取命令行参数数组 - string[] args = Environment.GetCommandLineArgs(); - - // 遍历所有参数,检查是否有匹配的参数 - foreach (string arg in args) - { - // 不区分大小写比较 - if (string.Equals(arg, parameterName, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; - } - - private void richTextBox1_DoubleClick(object sender, EventArgs e) - { - // 检查是否有日志内容 - if (richTextBox1.TextLength > 0) - { - // 显示确认对话框,询问用户是否要清空日志 - DialogResult result = MessageBox.Show( - "是否要清空当前日志?", - "清空日志确认", - MessageBoxButtons.YesNo, - MessageBoxIcon.Question, - MessageBoxDefaultButton.Button2); // 默认选择"否"按钮 - - if (result == DialogResult.Yes) - { - // 清空richTextBox1内容 - richTextBox1.Clear(); - // 记录一条清空日志的操作信息 - Log("日志已清空"); - } - } - } - - private void numericUpDown4_ValueChanged(object sender, EventArgs e) - { - if (numericUpDown4.Value > 4096) - { - string warningMessage = - "⚠️ 测速下限设置提醒 ⚠️\n\n" + - "您设置的测速下限值过高,可能导致:\n\n" + - "• 可用节点数量显著减少\n" + - "• 部分低速但稳定的节点被过滤\n" + - "测速下限设置建议:\n" + - "• 日常浏览:512-1024 KB/s\n" + - "• 视频观看:1024-2048 KB/s\n" + - "• 大文件下载:根据实际需求设置\n"; - - Log(warningMessage); - } - } - - private void numericUpDown3_ValueChanged(object sender, EventArgs e) - { - if (numericUpDown3.Value < 5000) - { - string warningMessage = - "⚠️ 超时时间设置提醒 ⚠️\n\n" + - "该超时时间并非延迟时间,除非您的网络极其优秀,否则超时时间过低会导致无可用节点。\n\n" + - "• 超时时间是真连接测试的最大等待时间\n" + - "• 设置过低会导致大部分节点连接失败\n" + - "• 推荐设置不低于5000ms\n\n" + - "建议超时时间设置:\n" + - "• 普通网络环境:5000± ms\n" + - "• 极好网络环境:3000± ms\n"; - - Log(warningMessage); - } - - } - } -} diff --git a/MainGui.Designer.cs b/MainGui.Designer.cs new file mode 100644 index 0000000..66196b6 --- /dev/null +++ b/MainGui.Designer.cs @@ -0,0 +1,2060 @@ +namespace subs_check.win.gui +{ + partial class MainGui + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 窗体设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainGui)); + this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components); + this.timerinitial = new System.Windows.Forms.Timer(this.components); + this.groupBoxComonSettings = new System.Windows.Forms.GroupBox(); + this.numericUpDownMinSpeed = new System.Windows.Forms.NumericUpDown(); + this.numericUpDownTimeout = new System.Windows.Forms.NumericUpDown(); + this.numericUpDownInterval = new System.Windows.Forms.NumericUpDown(); + this.numericUpDownConcurrent = new System.Windows.Forms.NumericUpDown(); + this.comboBoxSaveMethod = new System.Windows.Forms.ComboBox(); + this.checkBoxSwitchArch64 = new System.Windows.Forms.CheckBox(); + this.textBoxCron = new System.Windows.Forms.TextBox(); + this.labelConcurrent = new System.Windows.Forms.Label(); + this.labelInterval = new System.Windows.Forms.Label(); + this.labelTimeout = new System.Windows.Forms.Label(); + this.labelMinSpped = new System.Windows.Forms.Label(); + this.labelSaveMethod = new System.Windows.Forms.Label(); + this.checkBoxHighConcurrent = new System.Windows.Forms.CheckBox(); + this.comboBoxSubscriptionType = new System.Windows.Forms.ComboBox(); + this.buttonCopySubscriptionUrl = new System.Windows.Forms.Button(); + this.buttonTriggerCheck = new System.Windows.Forms.Button(); + this.buttonWebUi = new System.Windows.Forms.Button(); + this.checkBoxStartup = new System.Windows.Forms.CheckBox(); + this.labelCron = new System.Windows.Forms.Label(); + this.labelSubUrls = new System.Windows.Forms.Label(); + this.textBoxSubsUrls = new System.Windows.Forms.TextBox(); + this.buttonStartCheck = new System.Windows.Forms.Button(); + this.buttonAdvanceSettings = new System.Windows.Forms.Button(); + this.numericUpDownWebUIPort = new System.Windows.Forms.NumericUpDown(); + this.numericUpDownDLTimehot = new System.Windows.Forms.NumericUpDown(); + this.labelWebUIPort = new System.Windows.Forms.Label(); + this.labelDownloadTimeout = new System.Windows.Forms.Label(); + this.numericUpDownSubStorePort = new System.Windows.Forms.NumericUpDown(); + this.labelSubstorePort = new System.Windows.Forms.Label(); + this.groupBoxLog = new System.Windows.Forms.GroupBox(); + this.linkLabelAbout = new System.Windows.Forms.LinkLabel(); + this.buttonUpdateKernel = new System.Windows.Forms.Button(); + this.labelLogNodeInfo = new System.Windows.Forms.Label(); + this.richTextBoxAllLog = new System.Windows.Forms.RichTextBox(); + this.groupBoxAdvanceSettings = new System.Windows.Forms.GroupBox(); + this.checkBoxSubsStats = new System.Windows.Forms.CheckBox(); + this.comboBoxOverwriteUrls = new System.Windows.Forms.ComboBox(); + this.textBoxSubStorePath = new System.Windows.Forms.TextBox(); + this.labelSubstoreParh = new System.Windows.Forms.Label(); + this.numericUpDownTotalBandwidthLimit = new System.Windows.Forms.NumericUpDown(); + this.numericUpDownSuccessLimit = new System.Windows.Forms.NumericUpDown(); + this.numericUpDownDownloadMb = new System.Windows.Forms.NumericUpDown(); + this.comboBoxSysProxy = new System.Windows.Forms.ComboBox(); + this.comboBoxSpeedtestUrl = new System.Windows.Forms.ComboBox(); + this.comboBoxGithubProxyUrl = new System.Windows.Forms.ComboBox(); + this.labelOverwriteUrls = new System.Windows.Forms.Label(); + this.labelDownloadMb = new System.Windows.Forms.Label(); + this.textBoxWebUiAPIKey = new System.Windows.Forms.TextBox(); + this.checkBoxEnableWebUI = new System.Windows.Forms.CheckBox(); + this.checkBoxEnableRenameNode = new System.Windows.Forms.CheckBox(); + this.label1 = new System.Windows.Forms.Label(); + this.checkBoxEnableMediaCheck = new System.Windows.Forms.CheckBox(); + this.checkBoxKeepSucced = new System.Windows.Forms.CheckBox(); + this.checkBoxTotalBandwidthLimit = new System.Windows.Forms.CheckBox(); + this.buttonCheckUpdate = new System.Windows.Forms.Button(); + this.buttonMoreSettings = new System.Windows.Forms.Button(); + this.labelGithubProxyUrl = new System.Windows.Forms.Label(); + this.labelSpeedtestUrl = new System.Windows.Forms.Label(); + this.checkBoxEnableSuccessLimit = new System.Windows.Forms.CheckBox(); + this.progressBarAll = new System.Windows.Forms.ProgressBar(); + this.timerCopySubscriptionUrl = new System.Windows.Forms.Timer(this.components); + this.groupBoxGist = new System.Windows.Forms.GroupBox(); + this.textBox4 = new System.Windows.Forms.TextBox(); + this.label13 = new System.Windows.Forms.Label(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.label12 = new System.Windows.Forms.Label(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.label11 = new System.Windows.Forms.Label(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.groupBoxR2 = new System.Windows.Forms.GroupBox(); + this.textBox6 = new System.Windows.Forms.TextBox(); + this.label15 = new System.Windows.Forms.Label(); + this.textBox7 = new System.Windows.Forms.TextBox(); + this.label16 = new System.Windows.Forms.Label(); + this.groupBoxWebdav = new System.Windows.Forms.GroupBox(); + this.textBox5 = new System.Windows.Forms.TextBox(); + this.label14 = new System.Windows.Forms.Label(); + this.textBox8 = new System.Windows.Forms.TextBox(); + this.label17 = new System.Windows.Forms.Label(); + this.textBox9 = new System.Windows.Forms.TextBox(); + this.label18 = new System.Windows.Forms.Label(); + this.timerRestartSchedule = new System.Windows.Forms.Timer(this.components); + this.timerRefresh = new System.Windows.Forms.Timer(this.components); + this.groupBoxPipeConcurrent = new System.Windows.Forms.GroupBox(); + this.numericUpDownPipeMedia = new System.Windows.Forms.NumericUpDown(); + this.labelPipeMedia = new System.Windows.Forms.Label(); + this.numericUpDownPipeSpeed = new System.Windows.Forms.NumericUpDown(); + this.labelPipeSpeed = new System.Windows.Forms.Label(); + this.checkBoxPipeAuto = new System.Windows.Forms.CheckBox(); + this.numericUpDownPipeAlive = new System.Windows.Forms.NumericUpDown(); + this.labelPipeAlive = new System.Windows.Forms.Label(); + this.groupBoxEnhance = new System.Windows.Forms.GroupBox(); + this.checkBoxDropBadCFNodes = new System.Windows.Forms.CheckBox(); + this.checkBoxEhanceTag = new System.Windows.Forms.CheckBox(); + this.checkBoxIspCheck = new System.Windows.Forms.CheckBox(); + this.groupBoxComonSettings.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownMinSpeed)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownTimeout)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownInterval)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownConcurrent)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownWebUIPort)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownDLTimehot)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownSubStorePort)).BeginInit(); + this.groupBoxLog.SuspendLayout(); + this.groupBoxAdvanceSettings.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownTotalBandwidthLimit)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownSuccessLimit)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownDownloadMb)).BeginInit(); + this.groupBoxGist.SuspendLayout(); + this.groupBoxR2.SuspendLayout(); + this.groupBoxWebdav.SuspendLayout(); + this.groupBoxPipeConcurrent.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPipeMedia)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPipeSpeed)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPipeAlive)).BeginInit(); + this.groupBoxEnhance.SuspendLayout(); + this.SuspendLayout(); + // + // notifyIcon1 + // + this.notifyIcon1.BalloonTipTitle = "Subs-Check"; + this.notifyIcon1.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon1.Icon"))); + this.notifyIcon1.Text = "Subs-Check:未运行"; + this.notifyIcon1.Visible = true; + this.notifyIcon1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon1_MouseClick); + // + // timerinitial + // + this.timerinitial.Enabled = true; + this.timerinitial.Interval = 1; + this.timerinitial.Tick += new System.EventHandler(this.timerinitial_Tick); + // + // groupBoxComonSettings + // + this.groupBoxComonSettings.Controls.Add(this.numericUpDownMinSpeed); + this.groupBoxComonSettings.Controls.Add(this.numericUpDownTimeout); + this.groupBoxComonSettings.Controls.Add(this.numericUpDownInterval); + this.groupBoxComonSettings.Controls.Add(this.numericUpDownConcurrent); + this.groupBoxComonSettings.Controls.Add(this.comboBoxSaveMethod); + this.groupBoxComonSettings.Controls.Add(this.checkBoxSwitchArch64); + this.groupBoxComonSettings.Controls.Add(this.textBoxCron); + this.groupBoxComonSettings.Controls.Add(this.labelConcurrent); + this.groupBoxComonSettings.Controls.Add(this.labelInterval); + this.groupBoxComonSettings.Controls.Add(this.labelTimeout); + this.groupBoxComonSettings.Controls.Add(this.labelMinSpped); + this.groupBoxComonSettings.Controls.Add(this.labelSaveMethod); + this.groupBoxComonSettings.Controls.Add(this.checkBoxHighConcurrent); + this.groupBoxComonSettings.Controls.Add(this.comboBoxSubscriptionType); + this.groupBoxComonSettings.Controls.Add(this.buttonCopySubscriptionUrl); + this.groupBoxComonSettings.Controls.Add(this.buttonTriggerCheck); + this.groupBoxComonSettings.Controls.Add(this.buttonWebUi); + this.groupBoxComonSettings.Controls.Add(this.checkBoxStartup); + this.groupBoxComonSettings.Controls.Add(this.labelCron); + this.groupBoxComonSettings.Controls.Add(this.labelSubUrls); + this.groupBoxComonSettings.Controls.Add(this.textBoxSubsUrls); + this.groupBoxComonSettings.Controls.Add(this.buttonStartCheck); + this.groupBoxComonSettings.Controls.Add(this.buttonAdvanceSettings); + this.groupBoxComonSettings.Location = new System.Drawing.Point(26, 14); + this.groupBoxComonSettings.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxComonSettings.Name = "groupBoxComonSettings"; + this.groupBoxComonSettings.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxComonSettings.Size = new System.Drawing.Size(319, 768); + this.groupBoxComonSettings.TabIndex = 0; + this.groupBoxComonSettings.TabStop = false; + this.groupBoxComonSettings.Text = "参数设置"; + // + // numericUpDownMinSpeed + // + this.numericUpDownMinSpeed.Location = new System.Drawing.Point(197, 180); + this.numericUpDownMinSpeed.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownMinSpeed.Maximum = new decimal(new int[] { + 20480, + 0, + 0, + 0}); + this.numericUpDownMinSpeed.Minimum = new decimal(new int[] { + 128, + 0, + 0, + 0}); + this.numericUpDownMinSpeed.Name = "numericUpDownMinSpeed"; + this.numericUpDownMinSpeed.Size = new System.Drawing.Size(106, 31); + this.numericUpDownMinSpeed.TabIndex = 13; + this.numericUpDownMinSpeed.Value = new decimal(new int[] { + 128, + 0, + 0, + 0}); + this.numericUpDownMinSpeed.ValueChanged += new System.EventHandler(this.numericUpDownMinSpeed_ValueChanged); + // + // numericUpDownTimeout + // + this.numericUpDownTimeout.Location = new System.Drawing.Point(197, 131); + this.numericUpDownTimeout.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownTimeout.Maximum = new decimal(new int[] { + 10000, + 0, + 0, + 0}); + this.numericUpDownTimeout.Minimum = new decimal(new int[] { + 1000, + 0, + 0, + 0}); + this.numericUpDownTimeout.Name = "numericUpDownTimeout"; + this.numericUpDownTimeout.Size = new System.Drawing.Size(106, 31); + this.numericUpDownTimeout.TabIndex = 12; + this.numericUpDownTimeout.Value = new decimal(new int[] { + 6000, + 0, + 0, + 0}); + this.numericUpDownTimeout.ValueChanged += new System.EventHandler(this.numericUpDownTimeout_ValueChanged); + // + // numericUpDownInterval + // + this.numericUpDownInterval.Location = new System.Drawing.Point(197, 82); + this.numericUpDownInterval.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownInterval.Maximum = new decimal(new int[] { + 1440, + 0, + 0, + 0}); + this.numericUpDownInterval.Minimum = new decimal(new int[] { + 30, + 0, + 0, + 0}); + this.numericUpDownInterval.Name = "numericUpDownInterval"; + this.numericUpDownInterval.Size = new System.Drawing.Size(106, 31); + this.numericUpDownInterval.TabIndex = 11; + this.numericUpDownInterval.Value = new decimal(new int[] { + 720, + 0, + 0, + 0}); + this.numericUpDownInterval.DoubleClick += new System.EventHandler(this.切换cron表达式); + // + // numericUpDownConcurrent + // + this.numericUpDownConcurrent.Location = new System.Drawing.Point(197, 33); + this.numericUpDownConcurrent.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownConcurrent.Maximum = new decimal(new int[] { + 1024, + 0, + 0, + 0}); + this.numericUpDownConcurrent.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDownConcurrent.Name = "numericUpDownConcurrent"; + this.numericUpDownConcurrent.Size = new System.Drawing.Size(106, 31); + this.numericUpDownConcurrent.TabIndex = 10; + this.numericUpDownConcurrent.Value = new decimal(new int[] { + 32, + 0, + 0, + 0}); + this.numericUpDownConcurrent.ValueChanged += new System.EventHandler(this.numericUpDownConcurrent_ValueChanged); + // + // comboBoxSaveMethod + // + this.comboBoxSaveMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBoxSaveMethod.FormattingEnabled = true; + this.comboBoxSaveMethod.Items.AddRange(new object[] { + "本地", + "gist", + "r2", + "webdav"}); + this.comboBoxSaveMethod.Location = new System.Drawing.Point(197, 230); + this.comboBoxSaveMethod.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.comboBoxSaveMethod.Name = "comboBoxSaveMethod"; + this.comboBoxSaveMethod.Size = new System.Drawing.Size(106, 29); + this.comboBoxSaveMethod.TabIndex = 16; + this.comboBoxSaveMethod.TextChanged += new System.EventHandler(this.comboBoxSaveMethod_TextChanged); + // + // checkBoxSwitchArch64 + // + this.checkBoxSwitchArch64.AutoSize = true; + this.checkBoxSwitchArch64.Location = new System.Drawing.Point(170, 539); + this.checkBoxSwitchArch64.Name = "checkBoxSwitchArch64"; + this.checkBoxSwitchArch64.Size = new System.Drawing.Size(111, 25); + this.checkBoxSwitchArch64.TabIndex = 38; + this.checkBoxSwitchArch64.Text = "x64内核"; + this.checkBoxSwitchArch64.UseVisualStyleBackColor = true; + this.checkBoxSwitchArch64.CheckedChanged += new System.EventHandler(this.checkBoxSwitchArch64_CheckedChanged); + // + // textBoxCron + // + this.textBoxCron.AcceptsReturn = true; + this.textBoxCron.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest; + this.textBoxCron.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.HistoryList; + this.textBoxCron.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.textBoxCron.Location = new System.Drawing.Point(89, 496); + this.textBoxCron.Margin = new System.Windows.Forms.Padding(5); + this.textBoxCron.Name = "textBoxCron"; + this.textBoxCron.Size = new System.Drawing.Size(214, 31); + this.textBoxCron.TabIndex = 21; + this.textBoxCron.Text = "0 4,16 * * *"; + this.textBoxCron.Visible = false; + this.textBoxCron.DoubleClick += new System.EventHandler(this.切换cron表达式); + this.textBoxCron.Leave += new System.EventHandler(this.textBoxCron_Leave); + // + // labelConcurrent + // + this.labelConcurrent.AutoSize = true; + this.labelConcurrent.Location = new System.Drawing.Point(13, 38); + this.labelConcurrent.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelConcurrent.Name = "labelConcurrent"; + this.labelConcurrent.Size = new System.Drawing.Size(136, 21); + this.labelConcurrent.TabIndex = 2; + this.labelConcurrent.Text = "并发线程数:"; + // + // labelInterval + // + this.labelInterval.AutoSize = true; + this.labelInterval.Location = new System.Drawing.Point(13, 87); + this.labelInterval.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelInterval.Name = "labelInterval"; + this.labelInterval.Size = new System.Drawing.Size(179, 21); + this.labelInterval.TabIndex = 3; + this.labelInterval.Text = "检查间隔(分钟):"; + this.labelInterval.DoubleClick += new System.EventHandler(this.切换cron表达式); + // + // labelTimeout + // + this.labelTimeout.AutoSize = true; + this.labelTimeout.Location = new System.Drawing.Point(13, 136); + this.labelTimeout.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelTimeout.Name = "labelTimeout"; + this.labelTimeout.Size = new System.Drawing.Size(179, 21); + this.labelTimeout.TabIndex = 4; + this.labelTimeout.Text = "超时时间(毫秒):"; + // + // labelMinSpped + // + this.labelMinSpped.AutoSize = true; + this.labelMinSpped.Location = new System.Drawing.Point(13, 185); + this.labelMinSpped.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelMinSpped.Name = "labelMinSpped"; + this.labelMinSpped.Size = new System.Drawing.Size(181, 21); + this.labelMinSpped.TabIndex = 5; + this.labelMinSpped.Text = "测速下限(KB/s):"; + // + // labelSaveMethod + // + this.labelSaveMethod.AutoSize = true; + this.labelSaveMethod.Location = new System.Drawing.Point(13, 234); + this.labelSaveMethod.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelSaveMethod.Name = "labelSaveMethod"; + this.labelSaveMethod.Size = new System.Drawing.Size(115, 21); + this.labelSaveMethod.TabIndex = 8; + this.labelSaveMethod.Text = "保存方法:"; + // + // checkBoxHighConcurrent + // + this.checkBoxHighConcurrent.AutoSize = true; + this.checkBoxHighConcurrent.Location = new System.Drawing.Point(18, 539); + this.checkBoxHighConcurrent.Name = "checkBoxHighConcurrent"; + this.checkBoxHighConcurrent.Size = new System.Drawing.Size(141, 25); + this.checkBoxHighConcurrent.TabIndex = 39; + this.checkBoxHighConcurrent.Text = "高性能模式"; + this.checkBoxHighConcurrent.UseVisualStyleBackColor = true; + this.checkBoxHighConcurrent.CheckedChanged += new System.EventHandler(this.checkBoxHighConcurrent_CheckedChanged); + // + // comboBoxSubscriptionType + // + this.comboBoxSubscriptionType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBoxSubscriptionType.FormattingEnabled = true; + this.comboBoxSubscriptionType.Items.AddRange(new object[] { + "通用订阅", + "Clash"}); + this.comboBoxSubscriptionType.Location = new System.Drawing.Point(15, 578); + this.comboBoxSubscriptionType.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.comboBoxSubscriptionType.Name = "comboBoxSubscriptionType"; + this.comboBoxSubscriptionType.Size = new System.Drawing.Size(144, 29); + this.comboBoxSubscriptionType.TabIndex = 19; + // + // buttonCopySubscriptionUrl + // + this.buttonCopySubscriptionUrl.Enabled = false; + this.buttonCopySubscriptionUrl.Location = new System.Drawing.Point(165, 575); + this.buttonCopySubscriptionUrl.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.buttonCopySubscriptionUrl.Name = "buttonCopySubscriptionUrl"; + this.buttonCopySubscriptionUrl.Size = new System.Drawing.Size(138, 40); + this.buttonCopySubscriptionUrl.TabIndex = 18; + this.buttonCopySubscriptionUrl.Text = "复制订阅"; + this.buttonCopySubscriptionUrl.UseVisualStyleBackColor = true; + this.buttonCopySubscriptionUrl.Click += new System.EventHandler(this.buttonCopySubscriptionUrl_Click); + // + // buttonTriggerCheck + // + this.buttonTriggerCheck.Enabled = false; + this.buttonTriggerCheck.Location = new System.Drawing.Point(13, 625); + this.buttonTriggerCheck.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.buttonTriggerCheck.Name = "buttonTriggerCheck"; + this.buttonTriggerCheck.Size = new System.Drawing.Size(146, 40); + this.buttonTriggerCheck.TabIndex = 30; + this.buttonTriggerCheck.Text = "🔀未启动"; + this.buttonTriggerCheck.UseVisualStyleBackColor = true; + this.buttonTriggerCheck.Click += new System.EventHandler(this.buttonTriggerCheck_Click); + // + // buttonWebUi + // + this.buttonWebUi.Enabled = false; + this.buttonWebUi.Location = new System.Drawing.Point(165, 625); + this.buttonWebUi.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.buttonWebUi.Name = "buttonWebUi"; + this.buttonWebUi.Size = new System.Drawing.Size(138, 40); + this.buttonWebUi.TabIndex = 29; + this.buttonWebUi.Text = "访问WebUI"; + this.buttonWebUi.UseVisualStyleBackColor = true; + this.buttonWebUi.Click += new System.EventHandler(this.buttonWebUi_Click); + // + // checkBoxStartup + // + this.checkBoxStartup.AutoSize = true; + this.checkBoxStartup.Location = new System.Drawing.Point(170, 676); + this.checkBoxStartup.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.checkBoxStartup.Name = "checkBoxStartup"; + this.checkBoxStartup.Size = new System.Drawing.Size(120, 25); + this.checkBoxStartup.TabIndex = 30; + this.checkBoxStartup.Text = "开机自启"; + this.checkBoxStartup.UseVisualStyleBackColor = true; + this.checkBoxStartup.CheckedChanged += new System.EventHandler(this.checkBoxStartup_CheckedChanged); + // + // labelCron + // + this.labelCron.AutoSize = true; + this.labelCron.Location = new System.Drawing.Point(13, 501); + this.labelCron.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelCron.Name = "labelCron"; + this.labelCron.Size = new System.Drawing.Size(73, 21); + this.labelCron.TabIndex = 40; + this.labelCron.Text = "计划:"; + this.labelCron.Visible = false; + this.labelCron.DoubleClick += new System.EventHandler(this.切换cron表达式); + // + // labelSubUrls + // + this.labelSubUrls.AutoSize = true; + this.labelSubUrls.Location = new System.Drawing.Point(13, 278); + this.labelSubUrls.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelSubUrls.Name = "labelSubUrls"; + this.labelSubUrls.Size = new System.Drawing.Size(284, 21); + this.labelSubUrls.TabIndex = 9; + this.labelSubUrls.Text = "节点池订阅链接(点击编辑):"; + this.labelSubUrls.Click += new System.EventHandler(this.textBoxSubsUrls_DoubleClick); + // + // textBoxSubsUrls + // + this.textBoxSubsUrls.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.textBoxSubsUrls.Location = new System.Drawing.Point(17, 304); + this.textBoxSubsUrls.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBoxSubsUrls.Multiline = true; + this.textBoxSubsUrls.Name = "textBoxSubsUrls"; + this.textBoxSubsUrls.ReadOnly = true; + this.textBoxSubsUrls.Size = new System.Drawing.Size(286, 223); + this.textBoxSubsUrls.TabIndex = 17; + this.textBoxSubsUrls.Text = resources.GetString("textBoxSubsUrls.Text"); + this.textBoxSubsUrls.WordWrap = false; + this.textBoxSubsUrls.Click += new System.EventHandler(this.textBoxSubsUrls_DoubleClick); + this.textBoxSubsUrls.DoubleClick += new System.EventHandler(this.textBoxSubsUrls_DoubleClick); + // + // buttonStartCheck + // + this.buttonStartCheck.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.buttonStartCheck.Location = new System.Drawing.Point(13, 676); + this.buttonStartCheck.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.buttonStartCheck.Name = "buttonStartCheck"; + this.buttonStartCheck.Size = new System.Drawing.Size(146, 79); + this.buttonStartCheck.TabIndex = 0; + this.buttonStartCheck.Text = "▶️ 启动"; + this.buttonStartCheck.UseVisualStyleBackColor = true; + this.buttonStartCheck.Click += new System.EventHandler(this.buttonStartCheck_Click); + // + // buttonAdvanceSettings + // + this.buttonAdvanceSettings.Location = new System.Drawing.Point(165, 715); + this.buttonAdvanceSettings.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.buttonAdvanceSettings.Name = "buttonAdvanceSettings"; + this.buttonAdvanceSettings.Size = new System.Drawing.Size(138, 40); + this.buttonAdvanceSettings.TabIndex = 1; + this.buttonAdvanceSettings.Text = "高级设置∧"; + this.buttonAdvanceSettings.UseVisualStyleBackColor = true; + this.buttonAdvanceSettings.Click += new System.EventHandler(this.buttonAdvanceSettings_Click); + // + // numericUpDownWebUIPort + // + this.numericUpDownWebUIPort.Location = new System.Drawing.Point(632, 127); + this.numericUpDownWebUIPort.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownWebUIPort.Maximum = new decimal(new int[] { + 65535, + 0, + 0, + 0}); + this.numericUpDownWebUIPort.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDownWebUIPort.Name = "numericUpDownWebUIPort"; + this.numericUpDownWebUIPort.Size = new System.Drawing.Size(87, 31); + this.numericUpDownWebUIPort.TabIndex = 15; + this.numericUpDownWebUIPort.Value = new decimal(new int[] { + 8199, + 0, + 0, + 0}); + this.numericUpDownWebUIPort.ValueChanged += new System.EventHandler(this.numericUpDownWebUIPort_ValueChanged); + // + // numericUpDownDLTimehot + // + this.numericUpDownDLTimehot.Location = new System.Drawing.Point(632, 79); + this.numericUpDownDLTimehot.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownDLTimehot.Maximum = new decimal(new int[] { + 10, + 0, + 0, + 0}); + this.numericUpDownDLTimehot.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDownDLTimehot.Name = "numericUpDownDLTimehot"; + this.numericUpDownDLTimehot.Size = new System.Drawing.Size(87, 31); + this.numericUpDownDLTimehot.TabIndex = 14; + this.numericUpDownDLTimehot.Value = new decimal(new int[] { + 10, + 0, + 0, + 0}); + // + // labelWebUIPort + // + this.labelWebUIPort.AutoSize = true; + this.labelWebUIPort.Location = new System.Drawing.Point(465, 132); + this.labelWebUIPort.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelWebUIPort.Name = "labelWebUIPort"; + this.labelWebUIPort.Size = new System.Drawing.Size(170, 21); + this.labelWebUIPort.TabIndex = 7; + this.labelWebUIPort.Text = "HTTP 服务端口:"; + // + // labelDownloadTimeout + // + this.labelDownloadTimeout.AutoSize = true; + this.labelDownloadTimeout.Location = new System.Drawing.Point(465, 84); + this.labelDownloadTimeout.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelDownloadTimeout.Name = "labelDownloadTimeout"; + this.labelDownloadTimeout.Size = new System.Drawing.Size(158, 21); + this.labelDownloadTimeout.TabIndex = 6; + this.labelDownloadTimeout.Text = "测速时间(秒):"; + // + // numericUpDownSubStorePort + // + this.numericUpDownSubStorePort.Location = new System.Drawing.Point(632, 175); + this.numericUpDownSubStorePort.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownSubStorePort.Maximum = new decimal(new int[] { + 65535, + 0, + 0, + 0}); + this.numericUpDownSubStorePort.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDownSubStorePort.Name = "numericUpDownSubStorePort"; + this.numericUpDownSubStorePort.Size = new System.Drawing.Size(87, 31); + this.numericUpDownSubStorePort.TabIndex = 21; + this.numericUpDownSubStorePort.Value = new decimal(new int[] { + 8299, + 0, + 0, + 0}); + this.numericUpDownSubStorePort.ValueChanged += new System.EventHandler(this.numericUpDownWebUIPort_ValueChanged); + // + // labelSubstorePort + // + this.labelSubstorePort.AutoSize = true; + this.labelSubstorePort.Location = new System.Drawing.Point(465, 180); + this.labelSubstorePort.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelSubstorePort.Name = "labelSubstorePort"; + this.labelSubstorePort.Size = new System.Drawing.Size(172, 21); + this.labelSubstorePort.TabIndex = 20; + this.labelSubstorePort.Text = "Sub-Store端口:"; + // + // groupBoxLog + // + this.groupBoxLog.CausesValidation = false; + this.groupBoxLog.Controls.Add(this.linkLabelAbout); + this.groupBoxLog.Controls.Add(this.buttonUpdateKernel); + this.groupBoxLog.Controls.Add(this.labelLogNodeInfo); + this.groupBoxLog.Controls.Add(this.richTextBoxAllLog); + this.groupBoxLog.Location = new System.Drawing.Point(354, 14); + this.groupBoxLog.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxLog.Name = "groupBoxLog"; + this.groupBoxLog.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxLog.Size = new System.Drawing.Size(1100, 768); + this.groupBoxLog.TabIndex = 1; + this.groupBoxLog.TabStop = false; + // + // linkLabelAbout + // + this.linkLabelAbout.AutoSize = true; + this.linkLabelAbout.Location = new System.Drawing.Point(850, 0); + this.linkLabelAbout.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.linkLabelAbout.Name = "linkLabelAbout"; + this.linkLabelAbout.Size = new System.Drawing.Size(250, 21); + this.linkLabelAbout.TabIndex = 21; + this.linkLabelAbout.TabStop = true; + this.linkLabelAbout.Text = "关于 SubsCheck Win GUI"; + this.linkLabelAbout.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelAbout_LinkClicked); + // + // buttonUpdateKernel + // + this.buttonUpdateKernel.Location = new System.Drawing.Point(956, 802); + this.buttonUpdateKernel.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.buttonUpdateKernel.Name = "buttonUpdateKernel"; + this.buttonUpdateKernel.Size = new System.Drawing.Size(138, 40); + this.buttonUpdateKernel.TabIndex = 20; + this.buttonUpdateKernel.Text = "更新内核"; + this.buttonUpdateKernel.UseVisualStyleBackColor = true; + this.buttonUpdateKernel.Visible = false; + this.buttonUpdateKernel.Click += new System.EventHandler(this.buttonUpdateKernel_Click); + // + // labelLogNodeInfo + // + this.labelLogNodeInfo.AutoSize = true; + this.labelLogNodeInfo.Location = new System.Drawing.Point(0, 0); + this.labelLogNodeInfo.Name = "labelLogNodeInfo"; + this.labelLogNodeInfo.Size = new System.Drawing.Size(94, 21); + this.labelLogNodeInfo.TabIndex = 22; + this.labelLogNodeInfo.Text = "实时日志"; + // + // richTextBoxAllLog + // + this.richTextBoxAllLog.BackColor = System.Drawing.Color.WhiteSmoke; + this.richTextBoxAllLog.Dock = System.Windows.Forms.DockStyle.Fill; + this.richTextBoxAllLog.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.richTextBoxAllLog.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.richTextBoxAllLog.Location = new System.Drawing.Point(6, 29); + this.richTextBoxAllLog.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.richTextBoxAllLog.Name = "richTextBoxAllLog"; + this.richTextBoxAllLog.ReadOnly = true; + this.richTextBoxAllLog.Size = new System.Drawing.Size(1088, 734); + this.richTextBoxAllLog.TabIndex = 0; + this.richTextBoxAllLog.Text = ""; + this.richTextBoxAllLog.DoubleClick += new System.EventHandler(this.richTextBoxAllLog_DoubleClick); + // + // groupBoxAdvanceSettings + // + this.groupBoxAdvanceSettings.Controls.Add(this.checkBoxIspCheck); + this.groupBoxAdvanceSettings.Controls.Add(this.checkBoxSubsStats); + this.groupBoxAdvanceSettings.Controls.Add(this.comboBoxOverwriteUrls); + this.groupBoxAdvanceSettings.Controls.Add(this.textBoxSubStorePath); + this.groupBoxAdvanceSettings.Controls.Add(this.labelSubstoreParh); + this.groupBoxAdvanceSettings.Controls.Add(this.numericUpDownTotalBandwidthLimit); + this.groupBoxAdvanceSettings.Controls.Add(this.numericUpDownSuccessLimit); + this.groupBoxAdvanceSettings.Controls.Add(this.numericUpDownSubStorePort); + this.groupBoxAdvanceSettings.Controls.Add(this.numericUpDownWebUIPort); + this.groupBoxAdvanceSettings.Controls.Add(this.numericUpDownDownloadMb); + this.groupBoxAdvanceSettings.Controls.Add(this.numericUpDownDLTimehot); + this.groupBoxAdvanceSettings.Controls.Add(this.comboBoxSysProxy); + this.groupBoxAdvanceSettings.Controls.Add(this.comboBoxSpeedtestUrl); + this.groupBoxAdvanceSettings.Controls.Add(this.comboBoxGithubProxyUrl); + this.groupBoxAdvanceSettings.Controls.Add(this.labelSubstorePort); + this.groupBoxAdvanceSettings.Controls.Add(this.labelOverwriteUrls); + this.groupBoxAdvanceSettings.Controls.Add(this.labelWebUIPort); + this.groupBoxAdvanceSettings.Controls.Add(this.labelDownloadMb); + this.groupBoxAdvanceSettings.Controls.Add(this.textBoxWebUiAPIKey); + this.groupBoxAdvanceSettings.Controls.Add(this.labelDownloadTimeout); + this.groupBoxAdvanceSettings.Controls.Add(this.checkBoxEnableWebUI); + this.groupBoxAdvanceSettings.Controls.Add(this.checkBoxEnableRenameNode); + this.groupBoxAdvanceSettings.Controls.Add(this.label1); + this.groupBoxAdvanceSettings.Controls.Add(this.checkBoxEnableMediaCheck); + this.groupBoxAdvanceSettings.Controls.Add(this.checkBoxKeepSucced); + this.groupBoxAdvanceSettings.Controls.Add(this.checkBoxTotalBandwidthLimit); + this.groupBoxAdvanceSettings.Controls.Add(this.buttonCheckUpdate); + this.groupBoxAdvanceSettings.Controls.Add(this.buttonMoreSettings); + this.groupBoxAdvanceSettings.Controls.Add(this.labelGithubProxyUrl); + this.groupBoxAdvanceSettings.Controls.Add(this.labelSpeedtestUrl); + this.groupBoxAdvanceSettings.Controls.Add(this.checkBoxEnableSuccessLimit); + this.groupBoxAdvanceSettings.Location = new System.Drawing.Point(26, 792); + this.groupBoxAdvanceSettings.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxAdvanceSettings.Name = "groupBoxAdvanceSettings"; + this.groupBoxAdvanceSettings.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxAdvanceSettings.Size = new System.Drawing.Size(1430, 216); + this.groupBoxAdvanceSettings.TabIndex = 2; + this.groupBoxAdvanceSettings.TabStop = false; + this.groupBoxAdvanceSettings.Text = "高级设置"; + this.groupBoxAdvanceSettings.Visible = false; + // + // checkBoxSubsStats + // + this.checkBoxSubsStats.AutoSize = true; + this.checkBoxSubsStats.Location = new System.Drawing.Point(192, 130); + this.checkBoxSubsStats.Name = "checkBoxSubsStats"; + this.checkBoxSubsStats.Size = new System.Drawing.Size(120, 25); + this.checkBoxSubsStats.TabIndex = 43; + this.checkBoxSubsStats.Text = "统计订阅"; + this.checkBoxSubsStats.UseVisualStyleBackColor = true; + this.checkBoxSubsStats.CheckedChanged += new System.EventHandler(this.checkBoxSubsStats_CheckedChanged); + // + // comboBoxOverwriteUrls + // + this.comboBoxOverwriteUrls.FormattingEnabled = true; + this.comboBoxOverwriteUrls.Items.AddRange(new object[] { + "[内置]布丁狗的订阅转换", + "[内置]ACL4SSR_Online_Full", + "https://raw.githubusercontent.com/mihomo-party-org/override-hub/main/yaml/布丁狗的订阅转" + + "换.yaml", + "https://raw.githubusercontent.com/mihomo-party-org/override-hub/main/yaml/ACL4SSR" + + "_Online_Full.yaml", + "https://raw.githubusercontent.com/mihomo-party-org/override-hub/main/yaml/ACL4SSR" + + "_Online_Full_WithIcon.yaml", + "https://raw.githubusercontent.com/mihomo-party-org/override-hub/main/yaml/添加直连规则." + + "yaml", + "https://fastly.jsdelivr.net/gh/mihomo-party-org/override-hub@main/yaml/布丁狗的订阅转换.y" + + "aml", + "https://fastly.jsdelivr.net/gh/mihomo-party-org/override-hub@main/yaml/ACL4SSR_On" + + "line_Full.yaml", + "https://fastly.jsdelivr.net/gh/mihomo-party-org/override-hub@main/yaml/ACL4SSR_On" + + "line_Full_WithIcon.yaml", + "https://fastly.jsdelivr.net/gh/mihomo-party-org/override-hub@main/yaml/添加直连规则.yam" + + "l"}); + this.comboBoxOverwriteUrls.Location = new System.Drawing.Point(914, 128); + this.comboBoxOverwriteUrls.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.comboBoxOverwriteUrls.Name = "comboBoxOverwriteUrls"; + this.comboBoxOverwriteUrls.Size = new System.Drawing.Size(504, 29); + this.comboBoxOverwriteUrls.TabIndex = 24; + this.comboBoxOverwriteUrls.SelectedIndexChanged += new System.EventHandler(this.comboBoxOverwriteUrls_SelectedIndexChanged); + // + // textBoxSubStorePath + // + this.textBoxSubStorePath.BackColor = System.Drawing.SystemColors.Window; + this.textBoxSubStorePath.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.textBoxSubStorePath.ForeColor = System.Drawing.SystemColors.WindowFrame; + this.textBoxSubStorePath.Location = new System.Drawing.Point(914, 175); + this.textBoxSubStorePath.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBoxSubStorePath.Name = "textBoxSubStorePath"; + this.textBoxSubStorePath.Size = new System.Drawing.Size(144, 31); + this.textBoxSubStorePath.TabIndex = 41; + this.textBoxSubStorePath.Text = "请输入路径"; + this.textBoxSubStorePath.Enter += new System.EventHandler(this.textBoxSubStorePath_Enter); + this.textBoxSubStorePath.Leave += new System.EventHandler(this.textBoxSubStorePath_Leave); + // + // labelSubstoreParh + // + this.labelSubstoreParh.AutoSize = true; + this.labelSubstoreParh.Location = new System.Drawing.Point(735, 180); + this.labelSubstoreParh.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelSubstoreParh.Name = "labelSubstoreParh"; + this.labelSubstoreParh.Size = new System.Drawing.Size(183, 21); + this.labelSubstoreParh.TabIndex = 42; + this.labelSubstoreParh.Text = "Sub-Store 路径:"; + // + // numericUpDownTotalBandwidthLimit + // + this.numericUpDownTotalBandwidthLimit.Enabled = false; + this.numericUpDownTotalBandwidthLimit.Location = new System.Drawing.Point(365, 79); + this.numericUpDownTotalBandwidthLimit.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownTotalBandwidthLimit.Maximum = new decimal(new int[] { + 1000, + 0, + 0, + 0}); + this.numericUpDownTotalBandwidthLimit.Name = "numericUpDownTotalBandwidthLimit"; + this.numericUpDownTotalBandwidthLimit.Size = new System.Drawing.Size(87, 31); + this.numericUpDownTotalBandwidthLimit.TabIndex = 37; + this.numericUpDownTotalBandwidthLimit.Value = new decimal(new int[] { + 12, + 0, + 0, + 0}); + this.numericUpDownTotalBandwidthLimit.ValueChanged += new System.EventHandler(this.NumericUpDownTotalBandwidthLimit_ValueChanged); + // + // numericUpDownSuccessLimit + // + this.numericUpDownSuccessLimit.Enabled = false; + this.numericUpDownSuccessLimit.Location = new System.Drawing.Point(365, 31); + this.numericUpDownSuccessLimit.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownSuccessLimit.Maximum = new decimal(new int[] { + 65535, + 0, + 0, + 0}); + this.numericUpDownSuccessLimit.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDownSuccessLimit.Name = "numericUpDownSuccessLimit"; + this.numericUpDownSuccessLimit.Size = new System.Drawing.Size(87, 31); + this.numericUpDownSuccessLimit.TabIndex = 22; + this.numericUpDownSuccessLimit.Value = new decimal(new int[] { + 100, + 0, + 0, + 0}); + // + // numericUpDownDownloadMb + // + this.numericUpDownDownloadMb.Location = new System.Drawing.Point(632, 31); + this.numericUpDownDownloadMb.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownDownloadMb.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDownDownloadMb.Name = "numericUpDownDownloadMb"; + this.numericUpDownDownloadMb.Size = new System.Drawing.Size(87, 31); + this.numericUpDownDownloadMb.TabIndex = 30; + this.numericUpDownDownloadMb.Value = new decimal(new int[] { + 20, + 0, + 0, + 0}); + // + // comboBoxSysProxy + // + this.comboBoxSysProxy.AutoCompleteCustomSource.AddRange(new string[] { + "127.0.0.1:7890", + "127.0.0.1:10808", + "127.0.0.1:10809", + "127.0.0.1:7891", + "127.0.0.1:1080", + "127.0.0.1:8080", + "127.0.0.1:443"}); + this.comboBoxSysProxy.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend; + this.comboBoxSysProxy.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.HistoryList; + this.comboBoxSysProxy.FormattingEnabled = true; + this.comboBoxSysProxy.ImeMode = System.Windows.Forms.ImeMode.Close; + this.comboBoxSysProxy.Items.AddRange(new object[] { + "自动检测", + "127.0.0.1:443", + "127.0.0.1:7890", + "127.0.0.1:7891", + "127.0.0.1:1080", + "127.0.0.1:8080", + "127.0.0.1:10808", + "127.0.0.1:10809", + "127.0.0.1:3067", + "127.0.0.1:2080", + "127.0.0.1:1194", + "127.0.0.1:1082", + "127.0.0.1:12334", + "127.0.0.1:12335"}); + this.comboBoxSysProxy.Location = new System.Drawing.Point(848, 32); + this.comboBoxSysProxy.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.comboBoxSysProxy.Name = "comboBoxSysProxy"; + this.comboBoxSysProxy.Size = new System.Drawing.Size(210, 29); + this.comboBoxSysProxy.TabIndex = 39; + // + // comboBoxSpeedtestUrl + // + this.comboBoxSpeedtestUrl.FormattingEnabled = true; + this.comboBoxSpeedtestUrl.Items.AddRange(new object[] { + "不测速", + "https://github.com/2dust/v2rayN/releases/download/7.15.7/v2rayN-windows-64-SelfCo" + + "ntained.zip", + "https://github.com/AaronFeng753/Waifu2x-Extension-GUI/releases/download/v2.21.12/" + + "Waifu2x-Extension-GUI-v2.21.12-Portable.7z", + "https://github.com/2dust/v2rayN/releases/download/7.10.4/v2rayN-windows-64-deskto" + + "p.zip", + "https://github.com/VSCodium/vscodium/releases/download/1.98.0.25067/codium-1.98.0" + + ".25067-el9.aarch64.rpm"}); + this.comboBoxSpeedtestUrl.Location = new System.Drawing.Point(848, 80); + this.comboBoxSpeedtestUrl.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.comboBoxSpeedtestUrl.Name = "comboBoxSpeedtestUrl"; + this.comboBoxSpeedtestUrl.Size = new System.Drawing.Size(570, 29); + this.comboBoxSpeedtestUrl.TabIndex = 19; + this.comboBoxSpeedtestUrl.Text = "不测速"; + // + // comboBoxGithubProxyUrl + // + this.comboBoxGithubProxyUrl.FormattingEnabled = true; + this.comboBoxGithubProxyUrl.Items.AddRange(new object[] { + "自动选择", + "1.github.010716.xyz", + "113355.kabaka.xyz", + "80888888.xyz", + "aa.w0x7ce.eu", + "acc.meiqer.com", + "api-ghp.fjy.zone", + "armg1.jyhk.tk", + "armg2.jyhk.tk", + "b.yesican.top", + "bakht1.jsdelivr.fyi", + "bakht2.jsdelivr.fyi", + "bakht3.jsdelivr.fyi", + "booster.ookkk.ggff.net", + "c.gatepro.cn", + "cc.ikakatoo.us", + "ccgit1.5gyh.cf", + "ccgit2.5gyh.cf", + "cdn-gh.141888.xyz", + "cfghproxy.165683.xyz", + "chirophy.online", + "choner.eu.org", + "d.scyun.top", + "daili.6dot.cn", + "dh.guluy.top", + "dh.jeblove.com", + "dl.github.mirror.shalo.link", + "dnsvip.uk", + "docker.bkxhkoo.com", + "docker.ppp.ac.cn", + "down.avi.gs", + "download.ojbk.one", + "download.serein.cc", + "f.shenbing.nyc.mn", + "fastgithub.starryfun.icu", + "file.justgame.top", + "ft.v1k1.xin", + "fuck-flow.nobige.cn", + "g.108964.xyz", + "g.blfrp.cn", + "g.bravexist.cn", + "g.down.0ms.net", + "g.jscdn.cn", + "g.yeyuqiufeng.cn", + "gh.136361.xyz", + "gh.13x.plus", + "gh.19121912.xyz", + "gh.193.gs", + "gh.220106.xyz", + "gh.222322.xyz", + "gh.244224659.xyz", + "gh.2i.gs", + "gh.316688.xyz", + "gh.321122.xyz", + "gh.334433.xyz", + "gh.39.al", + "gh.518298.xyz", + "gh.52099520.xyz", + "gh.654535.xyz", + "gh.777000.best", + "gh.799154.xyz", + "gh.860686.xyz", + "gh.8p.gs", + "gh.960980.xyz", + "gh.accn.eu.org", + "gh.amirrors.com", + "gh.andiest.com", + "gh.aurzex.top", + "gh.avmine.com", + "gh.b52m.cn", + "gh.bhexo.cn", + "gh.cdn.fullcone.cn", + "gh.chewable.eu.org", + "gh.chillwaytech.com", + "gh.cnbattle.com", + "gh.crond.dev", + "gh.dev.438250.xyz", + "gh.duang.io", + "gh.duckcc.com", + "gh.dwsy.link", + "gh.ecdn.ip-ddns.com", + "gh.flewsea.news", + "gh.flewsea.pw", + "gh.flyrr.cc", + "gh.gongyi.tk", + "gh.gorun.eu.org", + "gh.gxb.pub", + "gh.haloless.com", + "gh.heshiheng.top", + "gh.hitcs.cc", + "gh.i3.pw", + "gh.ibridge.eu.org", + "gh.iinx.top", + "gh.j8.work", + "gh.jadelive.top", + "gh.jscdn.cn", + "gh.jxq.io", + "gh.kejilion.pro", + "gh.kemon.ai", + "gh.kmxm.online", + "gh.lib.cx", + "gh.lkwplus.com", + "gh.lux1983.com", + "gh.luzy.top", + "gh.lyh.moe", + "gh.miaomiao.video", + "gh.micedns.cloudns.org", + "gh.mirror.190211.xyz", + "gh.mirror.coolfeature.top", + "gh.moetools.net", + "gh.momonomi.xyz", + "gh.mrskye.cn", + "gh.mtx72.cc", + "gh.nekhill.top", + "gh.nekorect.eu.org", + "gh.nextfuture.top", + "gh.oevery.me", + "gh.oneproxy.top", + "gh.opsproxy.com", + "gh.osspub.cn", + "gh.padao.fun", + "gh.prlrr.com", + "gh.pylas.xyz", + "gh.qptf.eu.org", + "gh.qsd.onl", + "gh.qsq.one", + "gh.rem.asia", + "gh.riye.de", + "gh.scy.ink", + "gh.someo.top", + "gh.stanl.ee", + "gh.stewitch.com", + "gh.suite.eu.org", + "gh.tbw.wiki", + "gh.tou.lu", + "gh.tryxd.cn", + "gh.uclort.com", + "gh.wglee.org", + "gh.wowforever.xyz", + "gh.wuuu.cc", + "gh.wwang.de", + "gh.wygg.us.kg", + "gh.xbzza.cn", + "gh.xda.plus", + "gh.yahool.com.cn", + "gh.yushum.com", + "ghac.760710.xyz", + "ghacc.cpuhk.eu.org", + "ghb.wglee.org", + "gh-boost.oneboy.app", + "gh-deno.mocn.top", + "ghfast.top", + "ghjs.131412.eu.org", + "ghp.618032.xyz", + "ghp.9e6.site", + "ghp.dnsplus.uk", + "ghp.fit2.fun", + "ghp.imc.re", + "ghp.jokeme.top", + "ghp.lanchonghai.com", + "ghp.miaostay.com", + "ghp.opendatahub.xyz", + "ghp.pbren.com", + "ghp.src.moe", + "ghp.tryanks.com", + "ghp.vatery.com", + "ghp.xiaopan.ai", + "ghp.ybot.xin", + "ghp.yeye.f5.si", + "ghproxy.0081024.xyz", + "ghproxy.053000.xyz", + "ghproxy.200502.xyz", + "ghproxy.943689.xyz", + "ghproxy.alltobid.cc", + "ghproxy.amayakite.xyz", + "ghproxy.bugungu.top", + "gh-proxy.dorz.tech", + "ghproxy.dsdog.tk", + "ghproxy.ducknet.work", + "ghproxy.gopher.ink", + "ghproxy.gpnu.org", + "ghproxy.hoshizukimio.top", + "gh-proxy.iflyelf.com", + "ghproxy.imoyuapp.win", + "gh-proxy.jacksixth.top", + "gh-proxy.jmper.me", + "ghproxy.joylian.com", + "gh-proxy.just520.top", + "ghproxy.licardo.vip", + "gh-proxy.mereith.com", + "ghproxy.minge.dev", + "ghproxy.missfuture.eu.org", + "ghproxy.moweilong.com", + "ghproxy.nanakorobi.com", + "ghproxy.net", + "gh-proxy.not.icu", + "ghproxy.ownyuan.top", + "gh-proxy.rxliuli.com", + "ghproxy.sakuramoe.dev", + "ghproxy.smallfawn.work", + "ghproxy.sveir.xyz", + "ghproxy.temoa.fun", + "ghproxy.thefoxnet.com", + "ghproxy.tracemouse.top", + "ghproxy.txq.life", + "ghproxy.viper.pub", + "ghproxy.vyronlee-lab.com", + "ghproxy.weizhiwen.net", + "ghproxy.wjsphy.top", + "ghproxy.workers.haoutil.com", + "ghproxy.xiaohei-studio-chatgpt-proxy.com.cn", + "gh-proxy.yuntao.me", + "git.1999111.xyz", + "git.22345678.xyz", + "git.40609891.xyz", + "git.5gyh.cf", + "git.988896.xyz", + "git.aaltozz.info", + "git.acap.cc", + "git.amoluo.win", + "git.anye.in", + "git.binbow.link", + "git.blaow.cloudns.org", + "git.closersyu.top", + "git.ifso.site", + "git.imvery.moe", + "git.ixdd.de", + "git.ldvx.de", + "git.lincloud.pro", + "git.liunasc.xyz", + "git.llvho.com", + "git.loushi.site", + "git.lzzz.ink", + "git.maomao.ovh", + "git.mokoc.live", + "git.niege.app", + "git.nyar.work", + "git.o8.cx", + "git.outtw.com", + "git.ppp.ac.cn", + "git.repcz.link", + "git.txaff.com", + "git.verynb.org", + "git.wsl.icu", + "git.wyy.sh", + "git.xiny.eu.org", + "git.xuantan.icu", + "git.zlong.eu.org", + "git3.openapi.site", + "git-clone.ccrui.dev", + "github.08050611.xyz", + "github.143760.xyz", + "github.170011.xyz", + "github.17263241.xyz", + "github.180280.xyz", + "github.197909.xyz", + "github.19890821.xyz", + "github.201068.xyz", + "github.333033.xyz", + "github.4240333.xyz", + "github.564456.xyz", + "github.732086.xyz", + "github.776884.xyz", + "github.789056.xyz", + "github.818668.xyz", + "github.8void.sbs", + "github.9394961.xyz", + "github.960118.xyz", + "github.abyss.moe", + "github.atzzz.com", + "github.axcio.dns-dynamic.net", + "github.boki.moe", + "github.boringhex.top", + "github.bullb.net", + "github.c1g.top", + "github.cf.xihale.top", + "github.chasun.top", + "github.chuancey.eu.org", + "github.cnxiaobai.com", + "github.computerqwq.top", + "github.cswklt.top", + "github.ctios.cn", + "github.ddlink.asia", + "github.dockerspeed.site", + "github.eejsq.net", + "github.ffffffff0x.com", + "github.gdzja.site", + "github.haodiy.xyz", + "github.hhh.sd", + "github.hi.edu.rs", + "github.hostscc.top", + "github.hx208.top", + "github.ilxyz.xyz", + "github.intellisensing.tech", + "github.jerryliang.win", + "github.jimmyshjj.top", + "github.jinenyy.vip", + "github.jscdn.cn", + "github.kidos.top", + "github.kuugo.top", + "github.lao.plus", + "github.mayx.eu.org", + "github.mirror.qlnu-sec.cn", + "github.mirror.vurl.eu.org", + "github.mirrors.hikafeng.com", + "github.mistudio.top", + "github.orangbus.cn", + "github.pipers.cn", + "github.proxy.zerozone.tech", + "github.pxy.lnsee.com", + "github.quickso.net", + "github.ruxi.org", + "github.sagolu.top", + "github.serein.cc", + "github.snakexgc.com", + "github.space520.eu.org", + "github.sssss.work", + "github.static.cv", + "github.suyijun.top", + "github.try255.com", + "github.unipus.site", + "github.verynb.org", + "github.vipchanel.com", + "github.widiazine.top", + "github.workers.lv10.ren", + "github.workersnail.com", + "github.xin-yu.cloud", + "github.xiongmx.com", + "github.xwb009.xyz", + "github.xxlab.tech", + "github.xxqq.de", + "github.xykcloud.com", + "github.yeep6.eu.org", + "github.ylyhtools.top", + "github.yoloarea.com", + "github.yunfile.fun", + "github.zhaolele.top", + "github.zhou2008.cn", + "github.zhulin240520.buzz", + "github.zyhmifan.top", + "githubacc.caiaiwan.com", + "githubapi.jjchizha.com", + "githubgo.856798.xyz", + "github-proxy.ai-lulu.top", + "github-proxy.caoayu.top", + "github-proxy.explorexd.uk", + "github-proxy.fjiabinc.cn", + "github-proxy.sharefree.site", + "githubproxy.unix.do", + "github-quick.1ms.dev", + "github-raw-download.nekhill.top", + "githubsg.lilyya.top", + "gitproxy.mrhjx.cn", + "gitproxy.ozoo.top", + "godlike.ezpull.top", + "gp.19841106.xyz", + "gp.dahe.now.cc", + "gp.daxei.now.cc", + "g-p.loli.us", + "gp.ownorigin.top", + "gt.changqqq.xyz", + "gxb.pub", + "hay.uxio.cn", + "hg.19840228.top", + "hh.newhappy.cf", + "hk.114914.xyz", + "hub.12138.3653655.xyz", + "hub.326998.xyz", + "hub.885666.xyz", + "hub.fnas64.xin", + "hub.jeblove.com", + "hub.naloong.de", + "hub.vps.861020.xyz", + "hub.vvn.me", + "hub.why-ing.top", + "hub.xjl.ch", + "jh.ussh.net", + "jias.ayanjiu.top", + "jiasu.iwtriptqt1016.eu.org", + "jiasughapi.lingjun.cc", + "jiasuqi.167889.xyz", + "jisuan.xyz", + "js.wd666.cloudns.biz", + "l0l0l.cc", + "m.seafood.loan", + "mc.cn.eu.org", + "mdv.162899.xyz", + "micromatrix.gq", + "mip.cnzzla.com", + "my.iiso.site", + "my.losesw.live", + "mygh.api.xiaomao.eu.org", + "nav.253874.net", + "nav.cxycsx.vip", + "nav.gjcloak.xyz", + "nav.hgd1999.com", + "nav.hoiho.cn", + "nav.syss.fun", + "nav.tossp.com", + "nav.wxapp.xyz", + "nav.yyxw.tk", + "navs.itmax.cn", + "neoz.chat", + "noad.keliyan.top", + "node2.txq.life", + "or.tianba.eu.org", + "p.jackyu.cn", + "privateghproxy.iil.im", + "proxy.191027.xyz", + "proxy.atoposs.com", + "proxy.ccc8.vip", + "proxy.dragontea.cc", + "proxy.fakups.cn", + "proxydl.lcayun.cn", + "proxy-gh.1l1.icu", + "q-github.cnxiaobai.com", + "ql.l50.top", + "raw.nmd.im", + "rst.567812.xyz", + "static.kaixinwu.vip", + "static.yiwangmeng.com", + "t.992699.xyz", + "tpe.corpa.me", + "tube.20140301.xyz", + "vps.pansen626.com", + "wfgithub.xiaonuomi.ie.eu.org"}); + this.comboBoxGithubProxyUrl.Location = new System.Drawing.Point(1231, 32); + this.comboBoxGithubProxyUrl.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.comboBoxGithubProxyUrl.Name = "comboBoxGithubProxyUrl"; + this.comboBoxGithubProxyUrl.Size = new System.Drawing.Size(187, 29); + this.comboBoxGithubProxyUrl.TabIndex = 21; + this.comboBoxGithubProxyUrl.Leave += new System.EventHandler(this.comboBoxGithubProxyUrl_Leave); + // + // labelOverwriteUrls + // + this.labelOverwriteUrls.AutoSize = true; + this.labelOverwriteUrls.Location = new System.Drawing.Point(735, 132); + this.labelOverwriteUrls.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelOverwriteUrls.Name = "labelOverwriteUrls"; + this.labelOverwriteUrls.Size = new System.Drawing.Size(181, 21); + this.labelOverwriteUrls.TabIndex = 23; + this.labelOverwriteUrls.Text = "Clash 覆写配置:"; + // + // labelDownloadMb + // + this.labelDownloadMb.AutoSize = true; + this.labelDownloadMb.Location = new System.Drawing.Point(465, 36); + this.labelDownloadMb.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelDownloadMb.Name = "labelDownloadMb"; + this.labelDownloadMb.Size = new System.Drawing.Size(159, 21); + this.labelDownloadMb.TabIndex = 31; + this.labelDownloadMb.Text = "测速大小(MB):"; + // + // textBoxWebUiAPIKey + // + this.textBoxWebUiAPIKey.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.textBoxWebUiAPIKey.Enabled = false; + this.textBoxWebUiAPIKey.Location = new System.Drawing.Point(255, 175); + this.textBoxWebUiAPIKey.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBoxWebUiAPIKey.Name = "textBoxWebUiAPIKey"; + this.textBoxWebUiAPIKey.PasswordChar = '*'; + this.textBoxWebUiAPIKey.Size = new System.Drawing.Size(197, 31); + this.textBoxWebUiAPIKey.TabIndex = 6; + this.textBoxWebUiAPIKey.Text = "admin"; + this.textBoxWebUiAPIKey.Enter += new System.EventHandler(this.textBoxWebUiAPIKey_Enter); + this.textBoxWebUiAPIKey.Leave += new System.EventHandler(this.textBoxWebUiAPIKey_Leave); + // + // checkBoxEnableWebUI + // + this.checkBoxEnableWebUI.AutoSize = true; + this.checkBoxEnableWebUI.Location = new System.Drawing.Point(18, 178); + this.checkBoxEnableWebUI.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.checkBoxEnableWebUI.Name = "checkBoxEnableWebUI"; + this.checkBoxEnableWebUI.Size = new System.Drawing.Size(239, 25); + this.checkBoxEnableWebUI.TabIndex = 28; + this.checkBoxEnableWebUI.Text = "自定义 WebUI 密钥:"; + this.checkBoxEnableWebUI.UseVisualStyleBackColor = true; + this.checkBoxEnableWebUI.CheckedChanged += new System.EventHandler(this.checkBoxEnableWebUI_CheckedChanged); + // + // checkBoxEnableRenameNode + // + this.checkBoxEnableRenameNode.AutoSize = true; + this.checkBoxEnableRenameNode.Checked = true; + this.checkBoxEnableRenameNode.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBoxEnableRenameNode.Location = new System.Drawing.Point(18, 34); + this.checkBoxEnableRenameNode.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.checkBoxEnableRenameNode.Name = "checkBoxEnableRenameNode"; + this.checkBoxEnableRenameNode.Size = new System.Drawing.Size(162, 25); + this.checkBoxEnableRenameNode.TabIndex = 22; + this.checkBoxEnableRenameNode.Text = "节点地址查询"; + this.checkBoxEnableRenameNode.UseVisualStyleBackColor = true; + this.checkBoxEnableRenameNode.CheckedChanged += new System.EventHandler(this.checkBoxEnableRenameNode_CheckedChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(735, 36); + this.label1.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(115, 21); + this.label1.TabIndex = 40; + this.label1.Text = "系统代理:"; + // + // checkBoxEnableMediaCheck + // + this.checkBoxEnableMediaCheck.AutoSize = true; + this.checkBoxEnableMediaCheck.Location = new System.Drawing.Point(18, 82); + this.checkBoxEnableMediaCheck.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.checkBoxEnableMediaCheck.Name = "checkBoxEnableMediaCheck"; + this.checkBoxEnableMediaCheck.Size = new System.Drawing.Size(141, 25); + this.checkBoxEnableMediaCheck.TabIndex = 25; + this.checkBoxEnableMediaCheck.Text = "流媒体检测"; + this.checkBoxEnableMediaCheck.UseVisualStyleBackColor = true; + this.checkBoxEnableMediaCheck.CheckedChanged += new System.EventHandler(this.checkBoxEnableMediaCheck_CheckedChanged); + // + // checkBoxKeepSucced + // + this.checkBoxKeepSucced.AutoSize = true; + this.checkBoxKeepSucced.Location = new System.Drawing.Point(18, 130); + this.checkBoxKeepSucced.Name = "checkBoxKeepSucced"; + this.checkBoxKeepSucced.Size = new System.Drawing.Size(162, 25); + this.checkBoxKeepSucced.TabIndex = 38; + this.checkBoxKeepSucced.Text = "保留成功节点"; + this.checkBoxKeepSucced.UseVisualStyleBackColor = true; + // + // checkBoxTotalBandwidthLimit + // + this.checkBoxTotalBandwidthLimit.AutoSize = true; + this.checkBoxTotalBandwidthLimit.Location = new System.Drawing.Point(192, 82); + this.checkBoxTotalBandwidthLimit.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.checkBoxTotalBandwidthLimit.Name = "checkBoxTotalBandwidthLimit"; + this.checkBoxTotalBandwidthLimit.Size = new System.Drawing.Size(185, 25); + this.checkBoxTotalBandwidthLimit.TabIndex = 36; + this.checkBoxTotalBandwidthLimit.Text = "带宽限制MB/s:"; + this.checkBoxTotalBandwidthLimit.UseVisualStyleBackColor = true; + this.checkBoxTotalBandwidthLimit.CheckedChanged += new System.EventHandler(this.checkBoxTotalBandwidthLimit_CheckedChanged); + // + // buttonCheckUpdate + // + this.buttonCheckUpdate.BackColor = System.Drawing.SystemColors.Control; + this.buttonCheckUpdate.FlatAppearance.BorderSize = 0; + this.buttonCheckUpdate.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.buttonCheckUpdate.ForeColor = System.Drawing.SystemColors.ControlText; + this.buttonCheckUpdate.Location = new System.Drawing.Point(1280, 170); + this.buttonCheckUpdate.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.buttonCheckUpdate.Name = "buttonCheckUpdate"; + this.buttonCheckUpdate.Size = new System.Drawing.Size(138, 40); + this.buttonCheckUpdate.TabIndex = 26; + this.buttonCheckUpdate.Text = "检查更新"; + this.buttonCheckUpdate.UseVisualStyleBackColor = true; + this.buttonCheckUpdate.Click += new System.EventHandler(this.buttonCheckUpdate_Click); + // + // buttonMoreSettings + // + this.buttonMoreSettings.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.buttonMoreSettings.Location = new System.Drawing.Point(1130, 170); + this.buttonMoreSettings.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.buttonMoreSettings.Name = "buttonMoreSettings"; + this.buttonMoreSettings.Size = new System.Drawing.Size(138, 40); + this.buttonMoreSettings.TabIndex = 29; + this.buttonMoreSettings.Text = "补充参数"; + this.buttonMoreSettings.UseVisualStyleBackColor = true; + this.buttonMoreSettings.Click += new System.EventHandler(this.buttonMoreSettings_Click); + // + // labelGithubProxyUrl + // + this.labelGithubProxyUrl.AutoSize = true; + this.labelGithubProxyUrl.Location = new System.Drawing.Point(1070, 36); + this.labelGithubProxyUrl.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelGithubProxyUrl.Name = "labelGithubProxyUrl"; + this.labelGithubProxyUrl.Size = new System.Drawing.Size(163, 21); + this.labelGithubProxyUrl.TabIndex = 20; + this.labelGithubProxyUrl.Text = "Github Proxy:"; + // + // labelSpeedtestUrl + // + this.labelSpeedtestUrl.AutoSize = true; + this.labelSpeedtestUrl.Location = new System.Drawing.Point(735, 84); + this.labelSpeedtestUrl.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelSpeedtestUrl.Name = "labelSpeedtestUrl"; + this.labelSpeedtestUrl.Size = new System.Drawing.Size(115, 21); + this.labelSpeedtestUrl.TabIndex = 18; + this.labelSpeedtestUrl.Text = "测速地址:"; + // + // checkBoxEnableSuccessLimit + // + this.checkBoxEnableSuccessLimit.AutoSize = true; + this.checkBoxEnableSuccessLimit.Location = new System.Drawing.Point(192, 34); + this.checkBoxEnableSuccessLimit.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.checkBoxEnableSuccessLimit.Name = "checkBoxEnableSuccessLimit"; + this.checkBoxEnableSuccessLimit.Size = new System.Drawing.Size(183, 25); + this.checkBoxEnableSuccessLimit.TabIndex = 27; + this.checkBoxEnableSuccessLimit.Text = "节点限制数量:"; + this.checkBoxEnableSuccessLimit.UseVisualStyleBackColor = true; + this.checkBoxEnableSuccessLimit.CheckedChanged += new System.EventHandler(this.checkBoxEnableSuccessLimit_CheckedChanged); + // + // progressBarAll + // + this.progressBarAll.Location = new System.Drawing.Point(0, 0); + this.progressBarAll.Margin = new System.Windows.Forms.Padding(0); + this.progressBarAll.Name = "progressBarAll"; + this.progressBarAll.Size = new System.Drawing.Size(1466, 4); + this.progressBarAll.Step = 1; + this.progressBarAll.Style = System.Windows.Forms.ProgressBarStyle.Continuous; + this.progressBarAll.TabIndex = 3; + this.toolTip1.SetToolTip(this.progressBarAll, "检测进度"); + this.progressBarAll.Visible = false; + // + // timerCopySubscriptionUrl + // + this.timerCopySubscriptionUrl.Interval = 2000; + this.timerCopySubscriptionUrl.Tick += new System.EventHandler(this.timerCopySubscriptionUrl_Tick); + // + // groupBoxGist + // + this.groupBoxGist.Controls.Add(this.textBox4); + this.groupBoxGist.Controls.Add(this.label13); + this.groupBoxGist.Controls.Add(this.textBox3); + this.groupBoxGist.Controls.Add(this.label12); + this.groupBoxGist.Controls.Add(this.textBox2); + this.groupBoxGist.Controls.Add(this.label11); + this.groupBoxGist.Location = new System.Drawing.Point(26, 1103); + this.groupBoxGist.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxGist.Name = "groupBoxGist"; + this.groupBoxGist.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxGist.Size = new System.Drawing.Size(1430, 79); + this.groupBoxGist.TabIndex = 4; + this.groupBoxGist.TabStop = false; + this.groupBoxGist.Text = "Gist 上传参数"; + this.groupBoxGist.Visible = false; + // + // textBox4 + // + this.textBox4.Location = new System.Drawing.Point(830, 32); + this.textBox4.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBox4.Name = "textBox4"; + this.textBox4.Size = new System.Drawing.Size(584, 31); + this.textBox4.TabIndex = 5; + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(633, 37); + this.label13.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(205, 21); + this.label13.TabIndex = 4; + this.label13.Text = "API Mirror(可选):"; + // + // textBox3 + // + this.textBox3.Location = new System.Drawing.Point(464, 32); + this.textBox3.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBox3.Name = "textBox3"; + this.textBox3.PasswordChar = '*'; + this.textBox3.Size = new System.Drawing.Size(157, 31); + this.textBox3.TabIndex = 3; + this.textBox3.Enter += new System.EventHandler(this.textBox3_Enter); + this.textBox3.Leave += new System.EventHandler(this.textBox3_Leave); + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(308, 37); + this.label12.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(163, 21); + this.label12.TabIndex = 2; + this.label12.Text = "Github Token:"; + // + // textBox2 + // + this.textBox2.Location = new System.Drawing.Point(114, 32); + this.textBox2.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBox2.Name = "textBox2"; + this.textBox2.Size = new System.Drawing.Size(185, 31); + this.textBox2.TabIndex = 1; + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(13, 37); + this.label11.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(108, 21); + this.label11.TabIndex = 0; + this.label11.Text = "Gist ID:"; + // + // toolTip1 + // + this.toolTip1.AutoPopDelay = 5000; + this.toolTip1.InitialDelay = 500; + this.toolTip1.ReshowDelay = 500; + this.toolTip1.ShowAlways = true; + // + // groupBoxR2 + // + this.groupBoxR2.Controls.Add(this.textBox6); + this.groupBoxR2.Controls.Add(this.label15); + this.groupBoxR2.Controls.Add(this.textBox7); + this.groupBoxR2.Controls.Add(this.label16); + this.groupBoxR2.Location = new System.Drawing.Point(26, 1192); + this.groupBoxR2.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxR2.Name = "groupBoxR2"; + this.groupBoxR2.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxR2.Size = new System.Drawing.Size(1430, 79); + this.groupBoxR2.TabIndex = 6; + this.groupBoxR2.TabStop = false; + this.groupBoxR2.Text = "R2 上传参数"; + this.groupBoxR2.Visible = false; + // + // textBox6 + // + this.textBox6.Location = new System.Drawing.Point(794, 32); + this.textBox6.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBox6.Name = "textBox6"; + this.textBox6.PasswordChar = '*'; + this.textBox6.Size = new System.Drawing.Size(620, 31); + this.textBox6.TabIndex = 3; + this.textBox6.Text = "1234567890"; + this.textBox6.Enter += new System.EventHandler(this.textBox3_Enter); + this.textBox6.Leave += new System.EventHandler(this.textBox3_Leave); + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(633, 37); + this.label15.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(163, 21); + this.label15.TabIndex = 2; + this.label15.Text = "Worker Token:"; + // + // textBox7 + // + this.textBox7.Location = new System.Drawing.Point(161, 32); + this.textBox7.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBox7.Name = "textBox7"; + this.textBox7.Size = new System.Drawing.Size(460, 31); + this.textBox7.TabIndex = 1; + this.textBox7.Text = "https://example.worker.dev"; + this.textBox7.Leave += new System.EventHandler(this.textBox7_Leave); + // + // label16 + // + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(13, 37); + this.label16.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(141, 21); + this.label16.TabIndex = 0; + this.label16.Text = "Worker URL:"; + // + // groupBoxWebdav + // + this.groupBoxWebdav.Controls.Add(this.textBox5); + this.groupBoxWebdav.Controls.Add(this.label14); + this.groupBoxWebdav.Controls.Add(this.textBox8); + this.groupBoxWebdav.Controls.Add(this.label17); + this.groupBoxWebdav.Controls.Add(this.textBox9); + this.groupBoxWebdav.Controls.Add(this.label18); + this.groupBoxWebdav.Location = new System.Drawing.Point(26, 1281); + this.groupBoxWebdav.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxWebdav.Name = "groupBoxWebdav"; + this.groupBoxWebdav.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBoxWebdav.Size = new System.Drawing.Size(1430, 79); + this.groupBoxWebdav.TabIndex = 6; + this.groupBoxWebdav.TabStop = false; + this.groupBoxWebdav.Text = "Webdav 上传参数"; + this.groupBoxWebdav.Visible = false; + // + // textBox5 + // + this.textBox5.Location = new System.Drawing.Point(768, 32); + this.textBox5.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBox5.Name = "textBox5"; + this.textBox5.Size = new System.Drawing.Size(646, 31); + this.textBox5.TabIndex = 5; + this.textBox5.Text = "https://example.com/dav/"; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(633, 37); + this.label14.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(141, 21); + this.label14.TabIndex = 4; + this.label14.Text = "Webdav URL:"; + // + // textBox8 + // + this.textBox8.Location = new System.Drawing.Point(424, 32); + this.textBox8.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBox8.Name = "textBox8"; + this.textBox8.PasswordChar = '*'; + this.textBox8.Size = new System.Drawing.Size(197, 31); + this.textBox8.TabIndex = 3; + this.textBox8.Text = "admin"; + this.textBox8.Enter += new System.EventHandler(this.textBox3_Enter); + this.textBox8.Leave += new System.EventHandler(this.textBox3_Leave); + // + // label17 + // + this.label17.AutoSize = true; + this.label17.Location = new System.Drawing.Point(308, 37); + this.label17.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(119, 21); + this.label17.TabIndex = 2; + this.label17.Text = "Password:"; + // + // textBox9 + // + this.textBox9.Location = new System.Drawing.Point(128, 32); + this.textBox9.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.textBox9.Name = "textBox9"; + this.textBox9.Size = new System.Drawing.Size(171, 31); + this.textBox9.TabIndex = 1; + this.textBox9.Text = "admin"; + // + // label18 + // + this.label18.AutoSize = true; + this.label18.Location = new System.Drawing.Point(13, 37); + this.label18.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(119, 21); + this.label18.TabIndex = 0; + this.label18.Text = "Username:"; + // + // timerRestartSchedule + // + this.timerRestartSchedule.Interval = 86400000; + this.timerRestartSchedule.Tick += new System.EventHandler(this.timerRestartSchedule_Tick); + // + // timerRefresh + // + this.timerRefresh.Tick += new System.EventHandler(this.timerRefresh_Tick); + // + // groupBoxPipeConcurrent + // + this.groupBoxPipeConcurrent.Controls.Add(this.numericUpDownPipeMedia); + this.groupBoxPipeConcurrent.Controls.Add(this.labelPipeMedia); + this.groupBoxPipeConcurrent.Controls.Add(this.numericUpDownPipeSpeed); + this.groupBoxPipeConcurrent.Controls.Add(this.labelPipeSpeed); + this.groupBoxPipeConcurrent.Controls.Add(this.checkBoxPipeAuto); + this.groupBoxPipeConcurrent.Controls.Add(this.numericUpDownPipeAlive); + this.groupBoxPipeConcurrent.Controls.Add(this.labelPipeAlive); + this.groupBoxPipeConcurrent.Location = new System.Drawing.Point(26, 1016); + this.groupBoxPipeConcurrent.Name = "groupBoxPipeConcurrent"; + this.groupBoxPipeConcurrent.Size = new System.Drawing.Size(967, 79); + this.groupBoxPipeConcurrent.TabIndex = 7; + this.groupBoxPipeConcurrent.TabStop = false; + this.groupBoxPipeConcurrent.Text = "流水线并发 参数"; + // + // numericUpDownPipeMedia + // + this.numericUpDownPipeMedia.Location = new System.Drawing.Point(830, 36); + this.numericUpDownPipeMedia.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownPipeMedia.Maximum = new decimal(new int[] { + 1000, + 0, + 0, + 0}); + this.numericUpDownPipeMedia.Name = "numericUpDownPipeMedia"; + this.numericUpDownPipeMedia.Size = new System.Drawing.Size(106, 31); + this.numericUpDownPipeMedia.TabIndex = 43; + this.numericUpDownPipeMedia.ValueChanged += new System.EventHandler(this.numericUpDownPipeMedia_ValueChanged); + // + // labelPipeMedia + // + this.labelPipeMedia.AutoSize = true; + this.labelPipeMedia.Location = new System.Drawing.Point(633, 41); + this.labelPipeMedia.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelPipeMedia.Name = "labelPipeMedia"; + this.labelPipeMedia.Size = new System.Drawing.Size(199, 21); + this.labelPipeMedia.TabIndex = 42; + this.labelPipeMedia.Text = "流媒体检测并发数:"; + // + // numericUpDownPipeSpeed + // + this.numericUpDownPipeSpeed.Location = new System.Drawing.Point(513, 36); + this.numericUpDownPipeSpeed.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownPipeSpeed.Maximum = new decimal(new int[] { + 500, + 0, + 0, + 0}); + this.numericUpDownPipeSpeed.Name = "numericUpDownPipeSpeed"; + this.numericUpDownPipeSpeed.Size = new System.Drawing.Size(106, 31); + this.numericUpDownPipeSpeed.TabIndex = 41; + this.numericUpDownPipeSpeed.ValueChanged += new System.EventHandler(this.numericUpDownPipeSpeed_ValueChanged); + // + // labelPipeSpeed + // + this.labelPipeSpeed.AutoSize = true; + this.labelPipeSpeed.Location = new System.Drawing.Point(387, 41); + this.labelPipeSpeed.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelPipeSpeed.Name = "labelPipeSpeed"; + this.labelPipeSpeed.Size = new System.Drawing.Size(136, 21); + this.labelPipeSpeed.TabIndex = 40; + this.labelPipeSpeed.Text = "下载并发数:"; + // + // checkBoxPipeAuto + // + this.checkBoxPipeAuto.AutoSize = true; + this.checkBoxPipeAuto.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.checkBoxPipeAuto.Location = new System.Drawing.Point(18, 39); + this.checkBoxPipeAuto.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.checkBoxPipeAuto.Name = "checkBoxPipeAuto"; + this.checkBoxPipeAuto.Size = new System.Drawing.Size(99, 25); + this.checkBoxPipeAuto.TabIndex = 38; + this.checkBoxPipeAuto.Text = "自适应"; + this.checkBoxPipeAuto.UseVisualStyleBackColor = true; + this.checkBoxPipeAuto.CheckedChanged += new System.EventHandler(this.checkBoxPipeAuto_CheckedChanged); + // + // numericUpDownPipeAlive + // + this.numericUpDownPipeAlive.Location = new System.Drawing.Point(264, 36); + this.numericUpDownPipeAlive.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.numericUpDownPipeAlive.Maximum = new decimal(new int[] { + 5000, + 0, + 0, + 0}); + this.numericUpDownPipeAlive.Name = "numericUpDownPipeAlive"; + this.numericUpDownPipeAlive.Size = new System.Drawing.Size(106, 31); + this.numericUpDownPipeAlive.TabIndex = 39; + this.numericUpDownPipeAlive.Tag = ""; + this.numericUpDownPipeAlive.ValueChanged += new System.EventHandler(this.numericUpDownPipeAlive_ValueChanged); + // + // labelPipeAlive + // + this.labelPipeAlive.AutoSize = true; + this.labelPipeAlive.Location = new System.Drawing.Point(135, 41); + this.labelPipeAlive.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.labelPipeAlive.Name = "labelPipeAlive"; + this.labelPipeAlive.Size = new System.Drawing.Size(136, 21); + this.labelPipeAlive.TabIndex = 38; + this.labelPipeAlive.Text = "测活并发数:"; + // + // groupBoxEnhance + // + this.groupBoxEnhance.Controls.Add(this.checkBoxDropBadCFNodes); + this.groupBoxEnhance.Controls.Add(this.checkBoxEhanceTag); + this.groupBoxEnhance.Location = new System.Drawing.Point(999, 1016); + this.groupBoxEnhance.Name = "groupBoxEnhance"; + this.groupBoxEnhance.Size = new System.Drawing.Size(457, 79); + this.groupBoxEnhance.TabIndex = 44; + this.groupBoxEnhance.TabStop = false; + this.groupBoxEnhance.Text = "Enhance 参数"; + // + // checkBoxDropBadCFNodes + // + this.checkBoxDropBadCFNodes.AutoSize = true; + this.checkBoxDropBadCFNodes.Location = new System.Drawing.Point(201, 38); + this.checkBoxDropBadCFNodes.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.checkBoxDropBadCFNodes.Name = "checkBoxDropBadCFNodes"; + this.checkBoxDropBadCFNodes.Size = new System.Drawing.Size(205, 25); + this.checkBoxDropBadCFNodes.TabIndex = 39; + this.checkBoxDropBadCFNodes.Text = "丢弃低质量CF节点"; + this.checkBoxDropBadCFNodes.UseVisualStyleBackColor = true; + // + // checkBoxEhanceTag + // + this.checkBoxEhanceTag.AutoSize = true; + this.checkBoxEhanceTag.Location = new System.Drawing.Point(18, 39); + this.checkBoxEhanceTag.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.checkBoxEhanceTag.Name = "checkBoxEhanceTag"; + this.checkBoxEhanceTag.Size = new System.Drawing.Size(162, 25); + this.checkBoxEhanceTag.TabIndex = 38; + this.checkBoxEhanceTag.Text = "增强位置标签"; + this.checkBoxEhanceTag.UseVisualStyleBackColor = true; + // + // checkBoxIspCheck + // + this.checkBoxIspCheck.AutoSize = true; + this.checkBoxIspCheck.Location = new System.Drawing.Point(346, 130); + this.checkBoxIspCheck.Name = "checkBoxIspCheck"; + this.checkBoxIspCheck.Size = new System.Drawing.Size(111, 25); + this.checkBoxIspCheck.TabIndex = 44; + this.checkBoxIspCheck.Text = "ISP类型"; + this.checkBoxIspCheck.UseVisualStyleBackColor = true; + this.checkBoxIspCheck.CheckedChanged += new System.EventHandler(this.checkBoxIspCheck_CheckedChanged); + // + // MainGui + // + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 21F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.BackColor = System.Drawing.SystemColors.Control; + this.ClientSize = new System.Drawing.Size(1466, 1374); + this.Controls.Add(this.groupBoxLog); + this.Controls.Add(this.groupBoxComonSettings); + this.Controls.Add(this.groupBoxAdvanceSettings); + this.Controls.Add(this.groupBoxPipeConcurrent); + this.Controls.Add(this.groupBoxEnhance); + this.Controls.Add(this.groupBoxGist); + this.Controls.Add(this.groupBoxR2); + this.Controls.Add(this.groupBoxWebdav); + this.Controls.Add(this.progressBarAll); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.MaximizeBox = false; + this.Name = "MainGui"; + this.Text = "SubsCheck Win GUI"; + this.groupBoxComonSettings.ResumeLayout(false); + this.groupBoxComonSettings.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownMinSpeed)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownTimeout)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownInterval)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownConcurrent)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownWebUIPort)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownDLTimehot)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownSubStorePort)).EndInit(); + this.groupBoxLog.ResumeLayout(false); + this.groupBoxLog.PerformLayout(); + this.groupBoxAdvanceSettings.ResumeLayout(false); + this.groupBoxAdvanceSettings.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownTotalBandwidthLimit)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownSuccessLimit)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownDownloadMb)).EndInit(); + this.groupBoxGist.ResumeLayout(false); + this.groupBoxGist.PerformLayout(); + this.groupBoxR2.ResumeLayout(false); + this.groupBoxR2.PerformLayout(); + this.groupBoxWebdav.ResumeLayout(false); + this.groupBoxWebdav.PerformLayout(); + this.groupBoxPipeConcurrent.ResumeLayout(false); + this.groupBoxPipeConcurrent.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPipeMedia)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPipeSpeed)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPipeAlive)).EndInit(); + this.groupBoxEnhance.ResumeLayout(false); + this.groupBoxEnhance.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.NotifyIcon notifyIcon1; + private System.Windows.Forms.Timer timerinitial; + private System.Windows.Forms.GroupBox groupBoxComonSettings; + private System.Windows.Forms.GroupBox groupBoxLog; + private System.Windows.Forms.Label labelLogNodeInfo; + private System.Windows.Forms.Button buttonAdvanceSettings; + private System.Windows.Forms.Button buttonStartCheck; + private System.Windows.Forms.GroupBox groupBoxAdvanceSettings; + private System.Windows.Forms.Label labelSubUrls; + private System.Windows.Forms.Label labelSaveMethod; + private System.Windows.Forms.Label labelWebUIPort; + private System.Windows.Forms.Label labelDownloadTimeout; + private System.Windows.Forms.Label labelMinSpped; + private System.Windows.Forms.Label labelTimeout; + private System.Windows.Forms.Label labelInterval; + private System.Windows.Forms.Label labelCron; + private System.Windows.Forms.Label labelConcurrent; + private System.Windows.Forms.NumericUpDown numericUpDownWebUIPort; + private System.Windows.Forms.NumericUpDown numericUpDownDLTimehot; + private System.Windows.Forms.NumericUpDown numericUpDownMinSpeed; + private System.Windows.Forms.NumericUpDown numericUpDownTimeout; + private System.Windows.Forms.NumericUpDown numericUpDownInterval; + private System.Windows.Forms.NumericUpDown numericUpDownConcurrent; + private System.Windows.Forms.TextBox textBoxSubsUrls; + private System.Windows.Forms.ComboBox comboBoxSaveMethod; + private System.Windows.Forms.ComboBox comboBoxSpeedtestUrl; + private System.Windows.Forms.Label labelSpeedtestUrl; + private System.Windows.Forms.ComboBox comboBoxGithubProxyUrl; + private System.Windows.Forms.Label labelGithubProxyUrl; + private System.Windows.Forms.CheckBox checkBoxEnableRenameNode; + private System.Windows.Forms.RichTextBox richTextBoxAllLog; + private System.Windows.Forms.ProgressBar progressBarAll; + private System.Windows.Forms.Button buttonCopySubscriptionUrl; + private System.Windows.Forms.Timer timerCopySubscriptionUrl; + private System.Windows.Forms.GroupBox groupBoxGist; + private System.Windows.Forms.TextBox textBox4; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.ToolTip toolTip1; + private System.Windows.Forms.GroupBox groupBoxR2; + private System.Windows.Forms.TextBox textBox6; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.TextBox textBox7; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.GroupBox groupBoxWebdav; + private System.Windows.Forms.TextBox textBox5; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.TextBox textBox8; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.TextBox textBox9; + private System.Windows.Forms.Label label18; + private System.Windows.Forms.Button buttonUpdateKernel; + private System.Windows.Forms.ComboBox comboBoxSubscriptionType; + private System.Windows.Forms.NumericUpDown numericUpDownSubStorePort; + private System.Windows.Forms.Label labelSubstorePort; + private System.Windows.Forms.Label labelOverwriteUrls; + private System.Windows.Forms.ComboBox comboBoxOverwriteUrls; + private System.Windows.Forms.CheckBox checkBoxEnableMediaCheck; + private System.Windows.Forms.Timer timerRestartSchedule; + private System.Windows.Forms.Button buttonCheckUpdate; + private System.Windows.Forms.NumericUpDown numericUpDownSuccessLimit; + private System.Windows.Forms.TextBox textBoxWebUiAPIKey; + private System.Windows.Forms.CheckBox checkBoxEnableWebUI; + private System.Windows.Forms.Button buttonWebUi; + private System.Windows.Forms.Timer timerRefresh; + private System.Windows.Forms.Button buttonTriggerCheck; + private System.Windows.Forms.TextBox textBoxCron; + private System.Windows.Forms.LinkLabel linkLabelAbout; + private System.Windows.Forms.Button buttonMoreSettings; + private System.Windows.Forms.CheckBox checkBoxStartup; + private System.Windows.Forms.NumericUpDown numericUpDownDownloadMb; + private System.Windows.Forms.Label labelDownloadMb; + private System.Windows.Forms.CheckBox checkBoxTotalBandwidthLimit; + private System.Windows.Forms.NumericUpDown numericUpDownTotalBandwidthLimit; + private System.Windows.Forms.CheckBox checkBoxSwitchArch64; + private System.Windows.Forms.CheckBox checkBoxHighConcurrent; + private System.Windows.Forms.GroupBox groupBoxPipeConcurrent; + private System.Windows.Forms.NumericUpDown numericUpDownPipeAlive; + private System.Windows.Forms.Label labelPipeAlive; + private System.Windows.Forms.CheckBox checkBoxPipeAuto; + private System.Windows.Forms.NumericUpDown numericUpDownPipeMedia; + private System.Windows.Forms.Label labelPipeMedia; + private System.Windows.Forms.NumericUpDown numericUpDownPipeSpeed; + private System.Windows.Forms.Label labelPipeSpeed; + private System.Windows.Forms.GroupBox groupBoxEnhance; + private System.Windows.Forms.CheckBox checkBoxEhanceTag; + private System.Windows.Forms.CheckBox checkBoxDropBadCFNodes; + private System.Windows.Forms.CheckBox checkBoxKeepSucced; + private System.Windows.Forms.ComboBox comboBoxSysProxy; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.CheckBox checkBoxEnableSuccessLimit; + private System.Windows.Forms.Label labelSubstoreParh; + private System.Windows.Forms.TextBox textBoxSubStorePath; + private System.Windows.Forms.CheckBox checkBoxSubsStats; + private System.Windows.Forms.CheckBox checkBoxIspCheck; + } +} + diff --git a/MainGui.cs b/MainGui.cs new file mode 100644 index 0000000..ed23342 --- /dev/null +++ b/MainGui.cs @@ -0,0 +1,4680 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Management; +using System.Net; +using System.Net.Http; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +using AutoUpdaterDotNET; + +using Newtonsoft.Json.Linq; + +using static subs_check.win.gui.Proxy; + +namespace subs_check.win.gui +{ + public partial class MainGui : Form + { + //string 版本号; + string 标题; + private Process subsCheckProcess = null; + string nodeInfo;//进度 + private Icon originalNotifyIcon; // 保存原始图标 + private ToolStripMenuItem startMenuItem; + private ToolStripMenuItem stopMenuItem; + string githubProxyURL = ""; + string sysProxyURL = ""; + int run = 0; + + string currentKernel = "原版内核"; + string currentArch = "i386"; + string 当前GUI版本号 = "未知版本"; + string 最新GUI版本号 = "未知版本"; + string 当前subsCheck版本号 = "未知版本"; + string 最新内核版本号 = "未知版本"; + private string nextCheckTime = null;// 用于存储下次检查时间 + string WebUIapiKey = "CMLiussss"; + int downloading = 0; + private SysProxyResult SysProxySetting = null; + + private DateTime _lastCheckTime = DateTime.MinValue; + + private static DateTime _lastGetGithubProxyRunTime = DateTime.MinValue; + private static string _lastGithubProxyUrl = null; + + // ——用于避免无意义的重复 UI 重绘—— + private string _lastLogLabelNodeInfoText = string.Empty; + private string _lastNotifyText = string.Empty; + + // 存储groupBox原始位置 + private Point _pipeOriginalLocation; + private Point _enhanceOriginalLocation; + private bool _originalLocationSaved = false; + + // 存储媒体解锁平台数组 + private List selectedPlatforms = new List(); + + // 是否需要选择媒体解锁平台 + private bool NeedSelectPlatforms = true; + + public MainGui() + { + InitializeComponent(); + + this.Shown += MainGui_Shown; + + originalNotifyIcon = notifyIcon1.Icon; + + // 设置提示信息 + toolTip1.SetToolTip(numericUpDownConcurrent, "并发线程数:推荐 宽带峰值/50M。\n\n如启用高性能模式而未单独设置分段并发数,将使用该值计算自适应并发数.\n启用高性能模式后,此值可安全设置,下载速度会被限制在一个较小的值,同时加快检测速度"); + toolTip1.SetToolTip(numericUpDownInterval, "检查间隔时间(分钟):放置后台的时候,下次自动测速的间隔时间。\n\n 双击切换 使用「cron表达式」"); + toolTip1.SetToolTip(labelInterval, "检查间隔时间(分钟):放置后台的时候,下次自动测速的间隔时间。\n\n 双击切换 使用「cron表达式」"); + toolTip1.SetToolTip(labelCron, "双击切换 使用「分钟倒计时」"); + toolTip1.SetToolTip(textBoxCron, "支持标准cron表达式,如:\n 0 */2 * * * 表示每2小时的整点执行\n 0 0 */2 * * 表示每2天的0点执行\n 0 0 1 * * 表示每月1日0点执行\n */30 * * * * 表示每30分钟执行一次\n\n 双击切换 使用「分钟倒计时」"); + toolTip1.SetToolTip(numericUpDownTimeout, "超时时间(毫秒):节点的最大延迟。"); + toolTip1.SetToolTip(numericUpDownMinSpeed, "最低测速结果舍弃(KB/s)。"); + + toolTip1.SetToolTip(checkBoxHighConcurrent, "启用高性能内核。\n将同时开启以下功能:\n1. 测活、测速、媒体检测独立并发设置;\n2. 持久化保存并加载历次成功节点;\n3. 统计订阅信息,包括可用节点数量,成功率;\n4. 增强位置标签;\n5. 全新设计的WebUI,一键进入sub-store"); + toolTip1.SetToolTip(checkBoxSwitchArch64, "启用64位版本内核。"); + + toolTip1.SetToolTip(buttonTriggerCheck, "⏯️开始检测:发送开始检测信号,开始检测;\n⏸️结束检测:发送停止信号,内核保持后台运行。"); + + toolTip1.SetToolTip(buttonStartCheck, "启动内核检测进程。"); + + toolTip1.SetToolTip(checkBoxPipeAuto, "auto: 切换自适应流水线分段并发模式。"); + toolTip1.SetToolTip(numericUpDownPipeAlive, "测活任务并发数:\n取决于CPU和路由器芯片性能,建议设置 100-1000。\n\n量力而行!"); + toolTip1.SetToolTip(numericUpDownPipeSpeed, "测速任务并发数。\n建议设置 10-32。"); + toolTip1.SetToolTip(numericUpDownPipeMedia, "流媒体检测任务并发数。\n建议设置100-200。"); + + toolTip1.SetToolTip(checkBoxEhanceTag, "开启增强位置标签:\n- 无法访问 CF 的 CF 节点: HK⁻¹\r\n- 正常访问 CF: a.出口位置与cdn位置一致: HK¹⁺; b.位置不一致: HK¹-US⁰\r\n- 非 CF 节点,直接显示: HK²\r\n- 未获取到位置: HKˣ (使用原方案)\r\n- 前两位字母是实际浏览网站识别的位置,-US⁰为使用CF CDN服务的网站识别的位置,比如GPT, X等。"); + toolTip1.SetToolTip(checkBoxDropBadCFNodes, "丢弃无法访问CF CDN网站的节点。\r\n- 这类节点可以正常访问YouTube、Google等网站。\r\n- 无法访问cloudflare及使用了CDN服务的网站,比如Twitter、claude等。\r\n- 开启会导致节点数量大幅减少。"); + + + toolTip1.SetToolTip(comboBoxSubscriptionType, "通用订阅:内置了Sub-Store程序,自适应订阅格式。\nClash订阅:带规则的 Mihomo、Clash 订阅格式。\nSingbox:带规则的singbox订阅,需匹配版本"); + toolTip1.SetToolTip(comboBoxOverwriteUrls, "生成带规则的 Clash 订阅所需的覆写规则文件"); + + toolTip1.SetToolTip(checkBoxStartup, "开机启动:勾选后,程序将在Windows启动时自动运行"); + toolTip1.SetToolTip(buttonAdvanceSettings, "高级设置:展开更多设置参数项"); + + toolTip1.SetToolTip(buttonMoreSettings, "更多参数: 添加GUI未涵盖的参数项"); + toolTip1.SetToolTip(buttonCheckUpdate, "检查GUI和内核版本更新"); + + toolTip1.SetToolTip(numericUpDownDLTimehot, "下载测试时间(s):与下载链接大小相关,默认最大测试10s。"); + toolTip1.SetToolTip(numericUpDownWebUIPort, "本地监听端口:用于WebUi,返回软件运行信息等。"); + toolTip1.SetToolTip(numericUpDownSubStorePort, "Sub-Store监听端口:用于订阅转换。\n注意:\n请设置sub-store-path以防止被扫描主机"); + toolTip1.SetToolTip(textBoxSubStorePath, "Sub-Store自定义路径\n设置path之后,可以安全暴露到公网,开启订阅分享功能。\r\n# 订阅示例:http://127.0.0.1:8299/{sub-store-path}/api/file/mihomo\r\n# WebUI 支持分享订阅,直接复制订阅链接"); + + toolTip1.SetToolTip(numericUpDownDownloadMb, "下载测试限制(MB):当达到下载数据大小时,停止下载,可节省测速流量,减少测速测死的概率"); + toolTip1.SetToolTip(textBoxSubsUrls, "节点池订阅地址:支持 Link、Base64、Clash 格式的订阅链接。"); + toolTip1.SetToolTip(checkBoxEnableRenameNode, "以节点IP查询位置重命名节点。\n质量差的节点可能造成IP查询失败,造成整体检查速度稍微变慢。"); + toolTip1.SetToolTip(checkBoxEnableMediaCheck, "是否开启流媒体检测,其中IP欺诈依赖'节点地址查询',内核版本需要 v2.0.8 以上\n\n示例:美国1 | ⬇️ 5.6MB/s |0%|Netflix|Disney|Openai\n风控值:0% (使用ping0.cc标准)\n流媒体解锁:Netflix、Disney、Openai"); + toolTip1.SetToolTip(comboBoxSysProxy, "系统代理设置: 适用于拉取代理、消息推送、文件上传等等。"); + toolTip1.SetToolTip(comboBoxGithubProxyUrl, "GitHub 代理:代理订阅 GitHub raw 节点池。"); + toolTip1.SetToolTip(comboBoxSpeedtestUrl, "测速地址:注意 并发数*节点速度<最大网速 否则测速结果不准确\n尽量不要使用Speedtest,Cloudflare提供的下载链接,因为很多节点屏蔽测速网站。\n可选择 random 使用随机测速地址\n大部分机场屏蔽测速,建议不测速或设置较低的速度上限,实际使用可能更好"); + toolTip1.SetToolTip(textBox7, "将测速结果推送到Worker的地址。"); + toolTip1.SetToolTip(textBox6, "Worker令牌。"); + toolTip1.SetToolTip(comboBoxSaveMethod, "测速结果的保存方法。"); + toolTip1.SetToolTip(textBox2, "Gist ID:注意!非Github用户名!"); + toolTip1.SetToolTip(textBox3, "Github TOKEN"); + + toolTip1.SetToolTip(checkBoxEnableSuccessLimit, "保存几个成功的节点,不选代表不限制,内核版本需要 v2.1.0 以上\n如果你的并发数量超过这个参数,那么成功的结果可能会大于这个数值"); + toolTip1.SetToolTip(checkBoxTotalBandwidthLimit, "总的下载速度限制,不选代表不限制"); + toolTip1.SetToolTip(numericUpDownSuccessLimit, "保存几个成功的节点,不选代表不限制,内核版本需要 v2.1.0 以上\n如果你的并发数量超过这个参数,那么成功的结果可能会大于这个数值"); + + toolTip1.SetToolTip(numericUpDownTotalBandwidthLimit, "总的下载速度限制,不选代表不限制"); + + toolTip1.SetToolTip(labelCron, "双击切换 使用「分钟倒计时」"); + + toolTip1.SetToolTip(textBoxCron, "支持标准cron表达式,如:\n 0 */2 * * * 表示每2小时的整点执行\n 0 0 */2 * * 表示每2天的0点执行\n 0 0 1 * * 表示每月1日0点执行\n */30 * * * * 表示每30分钟执行一次\n\n 双击切换 使用「分钟倒计时」"); + + toolTip1.SetToolTip(checkBoxKeepSucced, "勾选会保留成功节点以便下次使用(持久化存储)\n1. 将加载上次成功节点;\n2. 将加载历次检测成功节点。"); + toolTip1.SetToolTip(checkBoxSubsStats, "仅在 “高性能模式“可用”。\n勾选会在 /output/stats 文件夹生成每个订阅链接内的节点数量,可用节点数量以及成功率。"); + toolTip1.SetToolTip(checkBoxIspCheck, "是否执行 isp 类型检测\n检测是否 原生/广播IP,以及住宅、机房等类型\n将为节点添加类似 [原生|机房]的标签"); + + toolTip1.SetToolTip(checkBoxEnableWebUI, "勾选后启用WebUI管理界面\n建议启用\n开启后可一键管理sub-store\n建议使用 Cloudflare Tunel隧道 映射主机端口\r\n可使用域名编辑、管理配置,开始、结束检测任务\n本地管理地址: http://127.0.0.1:8199/admin\n"); + toolTip1.SetToolTip(buttonWebUi, "更方便的subs-check管理面板\n可一键分享订阅\n支持一键进入sub-store\n支持远程管理"); + toolTip1.SetToolTip(textBoxWebUiAPIKey, "Web控制面板的api-key"); + // 设置通知图标的上下文菜单 + SetupNotifyIconContextMenu(); + } + + private async void MainGui_Shown(object sender, EventArgs e) + { + // 先检查系统代理 + await AutoCheckSysProxy(); + + // 再初始化 AutoUpdater + AutoUpdater.CheckForUpdateEvent += AutoUpdaterOnCheckForUpdateEvent; + AutoUpdater.ApplicationExitEvent += AutoUpdater_ApplicationExitEvent; + + AutoUpdater.Icon = Properties.Resources.download; + AutoUpdater.ShowRemindLaterButton = false; + AutoUpdater.ReportErrors = true; + AutoUpdater.HttpUserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"; + + AutoUpdater.Start("https://gh.39.al/raw.githubusercontent.com/sinspired/subsCheck-Win-GUI/master/update.xml"); + } + + // 更新程序退出事件处理器 + private async void AutoUpdater_ApplicationExitEvent() + { + StopSubsCheckProcess(); + await KillNodeProcessAsync(); + Application.Exit(); + } + + //自定义检查更新事件 + private void AutoUpdaterOnCheckForUpdateEvent(UpdateInfoEventArgs args) + { + if (args.Error == null) + { + if (args.IsUpdateAvailable) + { + // 如果你想显示标准更新窗口,请取消下面这行的注释 + AutoUpdater.ShowUpdateForm(args); + } + } + else + { + if (args.Error is WebException) + { + MessageBox.Show( + @"无法连接到更新服务器。请检查您的网络连接并稍后重试。", + @"更新检查失败", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + else + { + MessageBox.Show(args.Error.Message, + args.Error.GetType().ToString(), MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + } + + public async Task AutoCheckSysProxy(bool noRepeat = true) + { + // 如果10秒内已经执行过,直接返回 + if ((DateTime.Now - _lastCheckTime).TotalSeconds < 10 && noRepeat) + { + //Log("10秒内已检测过系统代理,跳过执行", GetRichTextBoxAllLog()); + return; + } + + _lastCheckTime = DateTime.Now; // 更新执行时间 + + // 自动检测系统代理 + string configProxy = comboBoxSysProxy.Text; + if (configProxy == "自动检测" || string.IsNullOrEmpty(configProxy) || configProxy == "http://" || configProxy == "https://") + { + configProxy = ""; + } + + if ((!configProxy.StartsWith("http://") || !configProxy.StartsWith("https://")) && configProxy != "") + { + configProxy = "http://" + configProxy; + } + + SysProxySetting = await Proxy.GetSysProxyAsync(configProxy); + + if (SysProxySetting != null && SysProxySetting.IsAvailable) + { + if (comboBoxSysProxy.Text == SysProxySetting.Address) + { + Log("设置系统代理: " + SysProxySetting.Address, GetRichTextBoxAllLog()); + } + else + { + string input = SysProxySetting.Address?.Trim() ?? string.Empty; + + // 检查是否存在 "://" 协议部分 + int protocolIndex = input.IndexOf("://"); + if (protocolIndex >= 0) + { + input = input.Substring(protocolIndex + 3); + } + + // 检查是否存在 "/" 路径部分 + int pathIndex = input.IndexOf('/'); + if (pathIndex >= 0) + { + input = input.Substring(0, pathIndex); + } + + comboBoxSysProxy.Text = input; + Log("检测到可用系统代理并设置: " + SysProxySetting.Address, GetRichTextBoxAllLog()); + + //await SaveConfig(false); + } + } + else + { + Log("未发现系统代理或系统代理不可用", GetRichTextBoxAllLog()); + } + } + + //临时禁用/恢复控件重绘 + [System.Runtime.InteropServices.DllImport("user32.dll")] + private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); + private const int WM_SETREDRAW = 0x000B; + + private void SuspendRedraw(Control c) + { + if (c != null && c.IsHandleCreated) + SendMessage(c.Handle, WM_SETREDRAW, (IntPtr)0, IntPtr.Zero); + } + + private void ResumeRedraw(Control c) + { + if (c != null && c.IsHandleCreated) + { + SendMessage(c.Handle, WM_SETREDRAW, (IntPtr)1, IntPtr.Zero); + c.Invalidate(); + } + } + + private void SetupNotifyIconContextMenu() + { + // 创建上下文菜单 + ContextMenuStrip contextMenu = new ContextMenuStrip(); + + // 创建"▶️ 启动"菜单项 + startMenuItem = new ToolStripMenuItem("启动"); + startMenuItem.Click += (sender, e) => + { + if (buttonStartCheck.Text == "▶️ 启动") + { + buttonStartCheck.ForeColor = Color.Black; + buttonStartCheck_Click(sender, e); + } + }; + + // 创建"⏹️ 停止"菜单项 + stopMenuItem = new ToolStripMenuItem("停止"); + stopMenuItem.Click += (sender, e) => + { + if (buttonStartCheck.Text == "⏹️ 停止") + { + buttonStartCheck.ForeColor = Color.Red; + buttonStartCheck_Click(sender, e); + } + }; + stopMenuItem.Enabled = false; // 初始状态下禁用 + + // 创建"退出"菜单项 + ToolStripMenuItem exitMenuItem = new ToolStripMenuItem("退出"); + exitMenuItem.Click += async (sender, e) => + { + try + { + // 如果程序正在运行,先停止它 + if (subsCheckProcess != null && !subsCheckProcess.HasExited) + { + await KillNodeProcessAsync(); + StopSubsCheckProcess(); + } + + // 确保通知图标被移除 + notifyIcon1.Visible = false; + + // 使用更直接的退出方式 + Environment.Exit(0); + } + catch (Exception ex) + { + MessageBox.Show($"退出程序时发生错误: {ex.Message}", "错误", + MessageBoxButtons.OK, MessageBoxIcon.Error); + + // 如果仍然失败,尝试强制退出 + System.Diagnostics.Process.GetCurrentProcess().Kill(); + } + }; + + // 将菜单项添加到上下文菜单 + contextMenu.Items.Add(startMenuItem); + contextMenu.Items.Add(stopMenuItem); + contextMenu.Items.Add(new ToolStripSeparator()); // 分隔线 + contextMenu.Items.Add(exitMenuItem); + + // 将上下文菜单分配给通知图标 + notifyIcon1.ContextMenuStrip = contextMenu; + + // 确保通知图标可见 + notifyIcon1.Visible = true; + } + + protected override void OnFormClosing(FormClosingEventArgs e) + { + if (e.CloseReason == CloseReason.UserClosing) + { + // 取消关闭操作 + e.Cancel = true; + // 调用隐藏窗口方法 + 隐藏窗口(); + } + } + + private async void timerinitial_Tick(object sender, EventArgs e)//初始化 + { + timerinitial.Enabled = false; + if (buttonAdvanceSettings.Text == "高级设置∧") buttonAdvanceSettings_Click(sender, e); + // 检查并创建config文件夹 + string executablePath = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); + string configFolderPath = System.IO.Path.Combine(executablePath, "config"); + if (!System.IO.Directory.Exists(configFolderPath)) + { + // 文件不存在,可以给用户反馈 + string 免责声明 = "SubsCheck-Win-GUI 项目仅供教育、研究和安全测试目的而设计和开发。本项目旨在为安全研究人员、学术界人士及技术爱好者提供一个探索和实践网络通信技术的工具。\r\n在下载和使用本项目代码时,使用者必须严格遵守其所适用的法律和规定。使用者有责任确保其行为符合所在地区的法律框架、规章制度及其他相关规定。\r\n\r\n使用条款\r\n\r\n教育与研究用途:本软件仅可用于网络技术和编程领域的学习、研究和安全测试。\r\n禁止非法使用:严禁将 SubsCheck-Win-GUI 用于任何非法活动或违反使用者所在地区法律法规的行为。\r\n使用时限:基于学习和研究目的,建议用户在完成研究或学习后,或在安装后的24小时内,删除本软件及所有相关文件。\r\n免责声明:SubsCheck-Win-GUI 的创建者和贡献者不对因使用或滥用本软件而导致的任何损害或法律问题负责。\r\n用户责任:用户对使用本软件的方式以及由此产生的任何后果完全负责。\r\n无技术支持:本软件的创建者不提供任何技术支持或使用协助。\r\n知情同意:使用 SubsCheck-Win-GUI 即表示您已阅读并理解本免责声明,并同意受其条款的约束。\r\n\r\n请记住:本软件的主要目的是促进学习、研究和安全测试。创作者不支持或认可任何其他用途。使用者应当在合法和负责任的前提下使用本工具。\r\n\r\n同意以上条款请点击\"是 / Yes\",否则程序将退出。"; + + // 显示带有 "同意" 和 "拒绝" 选项的对话框 + DialogResult result = MessageBox.Show(免责声明, "SubsCheck-Win-GUI 免责声明", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + + // 如果用户点击 "拒绝" (对应于 No 按钮) + if (result == DialogResult.No) + { + // 退出程序 + Environment.Exit(0); // 立即退出程序 + } + System.IO.Directory.CreateDirectory(configFolderPath); + } + + FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location); + 当前GUI版本号 = "v" + myFileVersionInfo.FileVersion; + 最新GUI版本号 = 当前GUI版本号; + 标题 = "SubsCheck Win GUI " + 当前GUI版本号; + this.Text = 标题;// + " TG:CMLiussss BY:CM喂饭 干货满满"; + comboBoxSaveMethod.Text = "本地"; + comboBoxSubscriptionType.Text = "通用订阅"; + + ReadConfig(); + + if (checkBoxHighConcurrent.Checked) + { + groupBoxGist.Location = new Point(groupBoxGist.Location.X, groupBoxGist.Location.Y + groupBoxPipeConcurrent.Height); + groupBoxR2.Location = groupBoxGist.Location; + groupBoxWebdav.Location = groupBoxGist.Location; + } + + if (CheckCommandLineParameter("-auto")) + { + Log("检测到开机启动,准备执行任务...", GetRichTextBoxAllLog()); + buttonStartCheck_Click(this, EventArgs.Empty); + this.Hide(); + notifyIcon1.Visible = true; + } + else await CheckGitHubVersionAsync(); + } + + private async Task CheckGitHubVersionAsync() + { + try + { + // 首先检查网络(你已有 IsNetworkAvailable() 方法) + if (!IsNetworkAvailable()) + return; + + // 并行获取 GUI 和 Kernel 的最新版本(更快) + var taskGui = 获取版本号("https://api.github.com/repos/sinspired/SubsCheck-Win-GUI/releases/latest"); + + // 动态决定使用哪个仓库(checkBoxHighConcurrent 为 true 时使用 sinspired,否则使用 beck-8) + string repoOwner = checkBoxHighConcurrent.Checked ? "sinspired" : "beck-8"; + string apiUrl = $"https://api.github.com/repos/{repoOwner}/subs-check/releases/latest"; + var taskKernel = 获取版本号(apiUrl); + + await Task.WhenAll(taskGui, taskKernel); + + string latestGui = taskGui.Result.Item1; + string latestKernel = taskKernel.Result.Item1; + + bool hasNewGui = false; + bool hasNewKernel = false; + string newTitle = $"SubsCheck Win GUI {当前GUI版本号}"; + + // ========= 检查 GUI 更新 ========= + if (latestGui != "未知版本" && !string.Equals(latestGui, 当前GUI版本号, StringComparison.OrdinalIgnoreCase)) + { + // 尝试用 Version 类精确比较 + if (TryParseVersion(latestGui, out Version vLatest) && + TryParseVersion(当前GUI版本号, out Version vCurrent) && + vLatest > vCurrent) + { + hasNewGui = true; + 最新GUI版本号 = latestGui; + } + else if (string.Compare(latestGui.TrimStart('v'), 当前GUI版本号.TrimStart('v'), StringComparison.OrdinalIgnoreCase) > 0) + { + // 回退到字符串比较(带 v 或不带 v 都支持) + hasNewGui = true; + 最新GUI版本号 = latestGui; + } + } + + // ========= 检查 Kernel 更新 ========= + if (latestKernel != "未知版本" && !string.Equals(latestKernel, 当前subsCheck版本号, StringComparison.OrdinalIgnoreCase)) + { + if (TryParseVersion(latestKernel, out Version vLatestK) && + TryParseVersion(当前subsCheck版本号, out Version vCurrentK) && + vLatestK > vCurrentK) + { + hasNewKernel = true; + 最新内核版本号 = latestKernel; // 假设你有这个字段,没有就新建一个 string 最新内核版本号; + } + else if (string.Compare(latestKernel.TrimStart('v'), 当前subsCheck版本号.TrimStart('v'), StringComparison.OrdinalIgnoreCase) > 0) + { + hasNewKernel = true; + 最新内核版本号 = latestKernel; + } + } + + // ========= 生成标题提示 ========= + if (hasNewGui && hasNewKernel) + { + newTitle += $" 有新版本!GUI → {最新GUI版本号} 内核 → {最新内核版本号}"; + } + else if (hasNewGui) + { + newTitle += $" 发现新GUI版本: {最新GUI版本号} 请及时更新!"; + } + else if (hasNewKernel) + { + newTitle += $" 发现新内核版本: {最新内核版本号} 请更新内核!"; + } + + if (hasNewGui || hasNewKernel) + { + // 检查更新按钮颜色 + buttonCheckUpdate.ForeColor = Color.LimeGreen; + buttonCheckUpdate.Text = "有新版本"; + + 标题 = newTitle; + this.Text = 标题; // 更新窗口标题 + // 可选:这里再弹个小气泡提示更友好 + notifyIcon1.ShowBalloonTip(8000, "SubsCheck 更新提醒", + hasNewGui && hasNewKernel ? $"GUI 和内核均有新版本!\nGUI: {最新GUI版本号}\n内核: {最新内核版本号}" + : hasNewGui ? $"GUI 有新版本:{最新GUI版本号}" + : $"内核有新版本:{最新内核版本号}", ToolTipIcon.Info); + } + } + catch + { + // 所有异常静默处理,不打扰用户 + } + } + + // 辅助方法:安全解析版本号(自动去掉 v 前缀) + private bool TryParseVersion(string input, out Version version) + { + version = null; + if (string.IsNullOrWhiteSpace(input)) return false; + + string clean = input.TrimStart('v', 'V'); + return Version.TryParse(clean, out version); + } + + // 添加检查网络连接的辅助方法 + private bool IsNetworkAvailable() + { + try + { + return NetworkInterface.GetIsNetworkAvailable(); + } + catch + { + return false; // 如果无法检查网络状态,假设网络不可用 + } + } + + private async void ReadConfig()//读取配置文件 + { + checkBoxStartup.CheckedChanged -= checkBoxStartup_CheckedChanged;// 临时移除事件处理器,防止触发事件 + try + { + string executablePath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); + string configFilePath = Path.Combine(executablePath, "config", "config.yaml"); + + if (File.Exists(configFilePath)) + { + // 读取YAML文件内容 + string yamlContent = File.ReadAllText(configFilePath); + + // 使用YamlDotNet解析YAML + var deserializer = new YamlDotNet.Serialization.Deserializer(); + var config = deserializer.Deserialize>(yamlContent); + + + // 变量放在前面,以防后续读取时未定义 + string subscheckArch = 读取config字符串(config, "subscheck-arch"); + if (!string.IsNullOrWhiteSpace(subscheckArch)) currentArch = subscheckArch; + + string subscheckKernel = 读取config字符串(config, "subscheck-kernel"); + if (!string.IsNullOrWhiteSpace(subscheckKernel)) currentKernel = subscheckKernel; + + string githubproxy = 读取config字符串(config, "githubproxy"); + if (githubproxy != null) comboBoxGithubProxyUrl.Text = githubproxy; + + const string githubRawPrefix = "https://raw.githubusercontent.com/"; + + // 使用新函数获取整数值并设置UI控件 + int? concurrentValue = 读取config整数(config, "concurrent"); + if (concurrentValue.HasValue) numericUpDownConcurrent.Value = concurrentValue.Value; + + // 临时禁用事件 + numericUpDownPipeAlive.ValueChanged -= numericUpDownPipeAlive_ValueChanged; + numericUpDownPipeSpeed.ValueChanged -= numericUpDownPipeSpeed_ValueChanged; + numericUpDownPipeMedia.ValueChanged -= numericUpDownPipeMedia_ValueChanged; + + // 测活/测速/流媒体阶段并发数(先赋值到控件,再从控件读取最终值,保证非 null) + int? aliveConcurrentValue = 读取config整数(config, "alive-concurrent"); + if (aliveConcurrentValue.HasValue) numericUpDownPipeAlive.Value = aliveConcurrentValue.Value; + + int? speedConcurrentValue = 读取config整数(config, "speed-concurrent"); + if (speedConcurrentValue.HasValue) numericUpDownPipeSpeed.Value = speedConcurrentValue.Value; + + int? mediaConcurrentValue = 读取config整数(config, "media-concurrent"); + if (mediaConcurrentValue.HasValue) numericUpDownPipeMedia.Value = mediaConcurrentValue.Value; + + // 根据各阶段并发数切换设置项, 如果任一为0, 则启用自适应高性能 + switchPipeAutoConcurrent(); // 现在控件已被赋值,函数可以安全读取 numericUpDown 的值 + + // 重新启用事件 + numericUpDownPipeAlive.ValueChanged += numericUpDownPipeAlive_ValueChanged; + numericUpDownPipeSpeed.ValueChanged += numericUpDownPipeSpeed_ValueChanged; + numericUpDownPipeMedia.ValueChanged += numericUpDownPipeMedia_ValueChanged; + + // Enhance-tag 相关设置(稳健解析 "true"/"false") + string enhanceTagRaw = 读取config字符串(config, "enhanced-tag"); + bool enhanceTagFlag = false; + if (!string.IsNullOrWhiteSpace(enhanceTagRaw)) + { + bool.TryParse(enhanceTagRaw.Trim(), out enhanceTagFlag); + } + checkBoxEhanceTag.Checked = enhanceTagFlag; + + // 丢弃低质量的 cf 节点 + string dropBadCFRaw = 读取config字符串(config, "drop-bad-cf-nodes"); + bool dropBadCFFlag = false; + if (!string.IsNullOrWhiteSpace(dropBadCFRaw)) + { + bool.TryParse(dropBadCFRaw.Trim(), out dropBadCFFlag); + } + checkBoxDropBadCFNodes.Checked = dropBadCFFlag; + + // 读取 enable-high-concurrent,并解析为 bool + string enableHighConcurrentRaw = 读取config字符串(config, "enable-high-concurrent"); + bool enableHighConcurrentFlag = false; + if (!string.IsNullOrWhiteSpace(enableHighConcurrentRaw)) + { + bool.TryParse(enableHighConcurrentRaw.Trim(), out enableHighConcurrentFlag); + } + + // 决定是否启用高性能:只要显式开启 或 drop/enhance 为 true 或 三阶段并发均 > 0 + bool needHighConcurrent = enableHighConcurrentFlag + || dropBadCFFlag + || enhanceTagFlag + || (aliveConcurrentValue > 0 && speedConcurrentValue > 0 && mediaConcurrentValue > 0); + + checkBoxHighConcurrent.Checked = needHighConcurrent; + + if (checkBoxHighConcurrent.Checked) + { + if (!comboBoxSubscriptionType.Items.Contains("Singbox1.11")) + { + comboBoxSubscriptionType.Items.AddRange(new object[] { "Singbox1.11" }); + } + if (!comboBoxSubscriptionType.Items.Contains("Singbox1.12")) + { + comboBoxSubscriptionType.Items.AddRange(new object[] { "Singbox1.12" }); + } + } + + // 根据是否启用高性能,调整界面布局 + string sysproxy; + if (!checkBoxHighConcurrent.Checked) + { + sysproxy = 读取config字符串(config, "proxy"); + if (sysproxy == null || sysproxy == "") + { + sysproxy = 读取config字符串(config, "system-proxy"); + } + } + else + { + sysproxy = 读取config字符串(config, "system-proxy"); + if (sysproxy == null || sysproxy == "") + { + sysproxy = 读取config字符串(config, "proxy"); + } + } + if (sysproxy != null) + { + string input = sysproxy.Trim(); + + // 检查是否存在 "://" 协议部分 + int protocolIndex = input.IndexOf("://"); + if (protocolIndex >= 0) + { + // 保留 "://" 之后的内容 + input = input.Substring(protocolIndex + 3); + } + + // 检查是否存在 "/" 路径部分 + int pathIndex = input.IndexOf('/'); + if (pathIndex >= 0) + { + // 只保留 "/" 之前的域名部分 + input = input.Substring(0, pathIndex); + } + + // 更新 comboBox3 的文本 + sysproxy = input; + comboBoxSysProxy.Text = sysproxy; + } + else + { + comboBoxSysProxy.Text = "自动检测"; + } + + string switchX64 = 读取config字符串(config, "switch-x64"); + if (switchX64 != null && switchX64 == "true") checkBoxSwitchArch64.Checked = true; + else checkBoxSwitchArch64.Checked = false; + + + int? checkIntervalValue = 读取config整数(config, "check-interval"); + if (checkIntervalValue.HasValue) numericUpDownInterval.Value = checkIntervalValue.Value; + + int? timeoutValue = 读取config整数(config, "timeout"); + if (timeoutValue.HasValue) numericUpDownTimeout.Value = timeoutValue.Value; + + int? minspeedValue = 读取config整数(config, "min-speed"); + if (minspeedValue.HasValue) numericUpDownMinSpeed.Value = minspeedValue.Value; + + int? downloadtimeoutValue = 读取config整数(config, "download-timeout"); + if (downloadtimeoutValue.HasValue) numericUpDownDLTimehot.Value = downloadtimeoutValue.Value; + + int? downloadLimitSizeValue = 读取config整数(config, "download-mb"); + if (downloadLimitSizeValue.HasValue) numericUpDownDownloadMb.Value = downloadLimitSizeValue.Value; + + int? downloadLimitSpeedValue = 读取config整数(config, "total-speed-limit"); + if (downloadLimitSpeedValue.HasValue) numericUpDownTotalBandwidthLimit.Value = downloadLimitSpeedValue.Value; + + string speedTestUrl = 读取config字符串(config, "speed-test-url"); + if (checkBoxHighConcurrent.Checked && !comboBoxSpeedtestUrl.Items.Contains("random")) + { + // 只有当列表里至少有1个元素时,才能插在第2个位置(索引1) + // 否则只能插在第1个位置(索引0) + int insertIndex = comboBoxSpeedtestUrl.Items.Count > 0 ? 1 : 0; + + comboBoxSpeedtestUrl.Items.Insert(insertIndex, "random"); + } + else + { + comboBoxSpeedtestUrl.Items.Remove("random"); + if (comboBoxSpeedtestUrl.Text == "random") comboBoxSpeedtestUrl.Text = "不测速"; + } + + if (speedTestUrl != null) + { + if (speedTestUrl == "") + { + comboBoxSpeedtestUrl.Text = "不测速"; + + } + else + { + comboBoxSpeedtestUrl.Items.Add(speedTestUrl); + comboBoxSpeedtestUrl.Text = speedTestUrl; + } + } + else + { + comboBoxSpeedtestUrl.Text = "不测速"; + } + + string listenport = 读取config字符串(config, "listen-port"); + if (listenport != null) + { + // 查找最后一个冒号的位置 + int colonIndex = listenport.LastIndexOf(':'); + if (colonIndex >= 0 && colonIndex < listenport.Length - 1) + { + // 提取冒号后面的部分作为端口号 + string portStr = listenport.Substring(colonIndex + 1); + if (decimal.TryParse(portStr, out decimal port)) + { + numericUpDownWebUIPort.Value = port; + } + } + } + + /* + int? substoreport = 读取config整数(config, "sub-store-port"); + if (substoreport.HasValue) numericUpDown7.Value = substoreport.Value; + */ + + string substoreport = 读取config字符串(config, "sub-store-port"); + if (substoreport != null) + { + // 查找最后一个冒号的位置 + int colonIndex = substoreport.LastIndexOf(':'); + if (colonIndex >= 0 && colonIndex < substoreport.Length - 1) + { + // 提取冒号后面的部分作为端口号 + string portStr = substoreport.Substring(colonIndex + 1); + if (decimal.TryParse(portStr, out decimal port)) + { + numericUpDownSubStorePort.Value = port; + } + } + } + + string mihomoOverwriteUrl = 读取config字符串(config, "mihomo-overwrite-url"); + int mihomoOverwriteUrlIndex = mihomoOverwriteUrl.IndexOf(githubRawPrefix); + if (mihomoOverwriteUrl != null) + { + if (mihomoOverwriteUrl.Contains("http://127.0.0")) + { + if (mihomoOverwriteUrl.EndsWith("bdg.yaml", StringComparison.OrdinalIgnoreCase)) + { + comboBoxOverwriteUrls.Text = "[内置]布丁狗的订阅转换"; + await comboBoxOverwriteUrlsSelection(); + } + else if (mihomoOverwriteUrl.EndsWith("ACL4SSR_Online_Full.yaml", StringComparison.OrdinalIgnoreCase)) + { + comboBoxOverwriteUrls.Text = "[内置]ACL4SSR_Online_Full"; + await comboBoxOverwriteUrlsSelection(); + } + } + else if (mihomoOverwriteUrlIndex > 0) comboBoxOverwriteUrls.Text = mihomoOverwriteUrl.Substring(mihomoOverwriteUrlIndex); + else comboBoxOverwriteUrls.Text = mihomoOverwriteUrl; + } + + // 处理URLs,检查是否包含GitHub raw链接 + List subUrls = 读取config列表(config, "sub-urls"); + if (subUrls != null && subUrls.Count > 0) + { + // 创建一个新的过滤后的列表 + var filteredUrls = new List(); + + for (int i = 0; i < subUrls.Count; i++) + { + // 排除本地URL + string localUrlPattern = $"http://127.0.0.1:{numericUpDownWebUIPort.Value}/all.yaml"; + if (!subUrls[i].Equals(localUrlPattern, StringComparison.OrdinalIgnoreCase)) + { + // 处理GitHub raw链接 + int index = subUrls[i].IndexOf(githubRawPrefix); + if (index > 0) // 如果找到且不在字符串开头 + { + // 只保留从githubRawPrefix开始的部分 + filteredUrls.Add(subUrls[i].Substring(index)); + } + else + { + // 如果不是GitHub链接,直接添加 + filteredUrls.Add(subUrls[i]); + } + } + } + string extraURL01 = "https://raw.githubusercontent.com/officialputuid/KangProxy/KangProxy/xResults/old-data/RAW.txt"; + string extraURL02 = "https://raw.githubusercontent.com/officialputuid/KangProxy/KangProxy/xResults/Proxies.txt"; + if (checkBoxHighConcurrent.Checked) + { + if (filteredUrls.Contains(extraURL01) == false) filteredUrls.Add(extraURL01); + if (filteredUrls.Contains(extraURL02) == false) filteredUrls.Add(extraURL02); + } + else + { + if (filteredUrls.Contains(extraURL01) == true) filteredUrls.Remove(extraURL01); + if (filteredUrls.Contains(extraURL02) == true) filteredUrls.Remove(extraURL02); + } + + // 将过滤后的列表中的每个URL放在单独的行上 + textBoxSubsUrls.Text = string.Join(Environment.NewLine, filteredUrls); + } + + string renamenode = 读取config字符串(config, "rename-node"); + if (renamenode != null && renamenode == "true") checkBoxEnableRenameNode.Checked = true; + else checkBoxEnableRenameNode.Checked = false; + + List platforms = 读取config列表(config, "platforms"); + if (platforms != null && platforms.Count > 0) + { + selectedPlatforms = platforms; + NeedSelectPlatforms = false; + } + else + { + selectedPlatforms = new List(); + } + + string mediacheck = 读取config字符串(config, "media-check"); + if (mediacheck != null && mediacheck == "true") checkBoxEnableMediaCheck.Checked = true; + else checkBoxEnableMediaCheck.Checked = false; + + string githubapimirror = 读取config字符串(config, "github-api-mirror"); + if (githubapimirror != null) textBox4.Text = githubapimirror; + + + string savemethod = 读取config字符串(config, "save-method"); + if (savemethod != null) + { + if (savemethod == "local") comboBoxSaveMethod.Text = "本地"; + else comboBoxSaveMethod.Text = savemethod; + } + + string githubgistid = 读取config字符串(config, "github-gist-id"); + if (githubgistid != null) textBox2.Text = githubgistid; + string githubtoken = 读取config字符串(config, "github-token"); + if (githubtoken != null) textBox3.Text = githubtoken; + + string workerurl = 读取config字符串(config, "worker-url"); + if (workerurl != null) textBox7.Text = workerurl; + string workertoken = 读取config字符串(config, "worker-token"); + if (workertoken != null) textBox6.Text = workertoken; + + string webdavusername = 读取config字符串(config, "webdav-username"); + if (webdavusername != null) textBox9.Text = webdavusername; + string webdavpassword = 读取config字符串(config, "webdav-password"); + if (webdavpassword != null) textBox8.Text = webdavpassword; + string webdavurl = 读取config字符串(config, "webdav-url"); + if (webdavurl != null) textBox5.Text = webdavurl; + + string subscheckversion = 读取config字符串(config, "subscheck-version"); + if (subscheckversion != null) 当前subsCheck版本号 = subscheckversion; + + string keepSucced = 读取config字符串(config, "keep-success-proxies"); + if (keepSucced != null && keepSucced == "true") checkBoxKeepSucced.Checked = true; + else checkBoxKeepSucced.Checked = false; + + string SubsStats = 读取config字符串(config, "sub-urls-stats"); + if (SubsStats != null && SubsStats == "true") checkBoxSubsStats.Checked = true; + else checkBoxSubsStats.Checked = false; + + string ispCheck = 读取config字符串(config, "isp-check"); + if (ispCheck != null && ispCheck == "true") checkBoxIspCheck.Checked = true; + else checkBoxIspCheck.Checked = false; + + int? successlimit = 读取config整数(config, "success-limit"); + if (successlimit.HasValue) + { + if (successlimit.Value == 0) + { + checkBoxEnableSuccessLimit.Checked = false; + numericUpDownSuccessLimit.Enabled = false; + } + else + { + checkBoxEnableSuccessLimit.Checked = true; + numericUpDownSuccessLimit.Enabled = true; + numericUpDownSuccessLimit.Value = successlimit.Value; + } + } + + int? totalspeedlimit = 读取config整数(config, "total-speed-limit"); + if (totalspeedlimit.HasValue) + { + if (totalspeedlimit.Value == 0) + { + checkBoxTotalBandwidthLimit.Checked = false; + numericUpDownTotalBandwidthLimit.Enabled = false; + } + else + { + checkBoxTotalBandwidthLimit.Checked = true; + numericUpDownTotalBandwidthLimit.Enabled = true; + numericUpDownTotalBandwidthLimit.Value = totalspeedlimit.Value; + } + } + + string enablewebui = 读取config字符串(config, "enable-web-ui"); + if (enablewebui != null && enablewebui == "true") checkBoxEnableWebUI.Checked = true; + else checkBoxEnableWebUI.Checked = false; + + string apikey = 读取config字符串(config, "api-key"); + if (apikey != null) + { + if (apikey == GetComputerNameMD5()) + { + checkBoxEnableWebUI.Checked = false; + string oldapikey = 读取config字符串(config, "old-api-key"); + if (oldapikey != null) + { + textBoxWebUiAPIKey.Text = oldapikey; + } + else + { + textBoxWebUiAPIKey.PasswordChar = '\0'; + textBoxWebUiAPIKey.Text = "请输入密钥"; + textBoxWebUiAPIKey.ForeColor = Color.Gray; + } + } + else + { + textBoxWebUiAPIKey.Text = apikey; + } + } + + string substorePath = 读取config字符串(config, "sub-store-path"); + if (!string.IsNullOrEmpty(substorePath)) + { + if (substorePath.StartsWith("/")) substorePath = substorePath.Substring(1); + + textBoxSubStorePath.Text = substorePath; + } + else + { + textBoxSubStorePath.Text = GetComputerNameMD5(); + } + + string cronexpression = 读取config字符串(config, "cron-expression"); + if (cronexpression != null) + { + textBoxCron.Text = cronexpression; + string cronDescription = GetCronExpressionDescription(textBoxCron.Text); + labelCron.Location = new Point(labelCron.Location.X, labelInterval.Location.Y); + textBoxCron.Location = new Point(textBoxCron.Location.X, numericUpDownInterval.Location.Y); + labelCron.Visible = true; + textBoxCron.Visible = true; + labelInterval.Visible = false; + numericUpDownInterval.Visible = false; + } + + string guiauto = 读取config字符串(config, "gui-auto"); + if (guiauto != null && guiauto == "true") checkBoxStartup.Checked = true; + else checkBoxStartup.Checked = false; + } + else + { + comboBoxGithubProxyUrl.Text = "自动选择"; + comboBoxSysProxy.Text = "自动检测"; + + comboBoxOverwriteUrls.Text = "[内置]布丁狗的订阅转换"; + + } + } + catch (Exception ex) + { + MessageBox.Show($"读取配置文件时发生错误: {ex.Message}", "错误", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + checkBoxStartup.CheckedChanged += checkBoxStartup_CheckedChanged;// 重新绑定事件处理器 + } + + private int? 读取config整数(Dictionary config, string fieldName) + { + // 检查是否存在指定字段且不为null + if (config.ContainsKey(fieldName) && config[fieldName] != null) + { + int value; + if (int.TryParse(config[fieldName].ToString(), out value)) + return value; + } + return null; + } + + private string 读取config字符串(Dictionary config, string fieldName) + { + // 检查是否存在指定字段且不为null + if (config.ContainsKey(fieldName) && config[fieldName] != null) + { + return config[fieldName].ToString(); + } + return null; + } + + private List 读取config列表(Dictionary config, string fieldName) + { + // 检查是否存在指定字段且不为null + if (config.ContainsKey(fieldName) && config[fieldName] != null) + { + // 尝试将对象转换为列表 + if (config[fieldName] is List listItems) + { + return listItems.Select(item => item?.ToString()).Where(s => !string.IsNullOrEmpty(s)).ToList(); + } + } + return null; + } + + private async Task SaveConfig(bool githubProxyCheck = true)//保存配置文件 + { + try + { + string executablePath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); + string configFilePath = Path.Combine(executablePath, "config", "config.yaml"); + + // 创建配置字典 + var config = new Dictionary(); + + // 从UI控件获取值并添加到字典中 + config["concurrent"] = (int)numericUpDownConcurrent.Value; + + + // 测活阶段并发数 + config["alive-concurrent"] = (int)numericUpDownPipeAlive.Value; + config["speed-concurrent"] = (int)numericUpDownPipeSpeed.Value; + config["media-concurrent"] = (int)numericUpDownPipeMedia.Value; + // Enhance-tag相关设置 + config["enhanced-tag"] = checkBoxEhanceTag.Checked; + // 丢弃低质量的cf节点 + config["drop-bad-cf-nodes"] = checkBoxDropBadCFNodes.Checked; + + + config["check-interval"] = (int)numericUpDownInterval.Value; + if (textBoxCron.Visible) config["cron-expression"] = textBoxCron.Text; + config["timeout"] = (int)numericUpDownTimeout.Value; + config["min-speed"] = (int)numericUpDownMinSpeed.Value; + config["download-timeout"] = (int)numericUpDownDLTimehot.Value; + config["download-mb"] = (int)numericUpDownDownloadMb.Value; + config["total-speed-limit"] = (int)numericUpDownTotalBandwidthLimit.Value; + + + if (!string.IsNullOrEmpty(comboBoxSpeedtestUrl.Text)) + { + string testURL = comboBoxSpeedtestUrl.Text; + if (comboBoxSpeedtestUrl.Text == "不测速") testURL = ""; + config["speed-test-url"] = testURL; + } + // 保存save-method,将"本地"转换为"local" + config["save-method"] = comboBoxSaveMethod.Text == "本地" ? "local" : comboBoxSaveMethod.Text; + + // 保存gist参数 + config["github-gist-id"] = textBox2.Text; + config["github-token"] = textBox3.Text; + + config["github-api-mirror"] = textBox4.Text; + + // 保存r2参数 + config["worker-url"] = textBox7.Text; + config["worker-token"] = textBox6.Text; + + // 保存webdav参数 + config["webdav-username"] = textBox9.Text; + config["webdav-password"] = textBox8.Text; + config["webdav-url"] = textBox5.Text; + + // 保存enable-web-ui + config["enable-web-ui"] = true; + + // 保存listen-port + if (checkBoxEnableWebUI.Checked) + { + WebUIapiKey = textBoxWebUiAPIKey.Text; + config["listen-port"] = $@":{numericUpDownWebUIPort.Value}"; + } + else + { + WebUIapiKey = GetComputerNameMD5(); + config["listen-port"] = $@":{numericUpDownWebUIPort.Value}"; + if (textBoxWebUiAPIKey.Text != "请输入密钥") config["old-api-key"] = textBoxWebUiAPIKey.Text; + } + config["api-key"] = WebUIapiKey; + + string substorePath = textBoxSubStorePath.Text.Trim(); + // 如果不是以 "/" 开头,则补上 + if (!substorePath.StartsWith("/")) substorePath = "/" + substorePath; + // 如果是默认提示文字或仅有 "/",则清空 + if (substorePath == "/请输入路径" || substorePath == "/") substorePath = ""; + + if (checkBoxHighConcurrent.Checked && substorePath == "") + { + substorePath = GetComputerNameMD5(); + } + + config["sub-store-path"] = substorePath; + + // 保存sub-store-port + config["sub-store-port"] = $@":{numericUpDownSubStorePort.Value}"; + + string githubRawPrefix = "https://raw.githubusercontent.com/"; + if (githubProxyCheck) + { + // 检查并处理 GitHub Raw URLs + githubProxyURL = await GetGithubProxyUrlAsync(); + } + + if (comboBoxGithubProxyUrl.Text != "自动选择") githubProxyURL = $"https://{comboBoxGithubProxyUrl.Text}/"; + config["githubproxy"] = comboBoxGithubProxyUrl.Text; + config["github-proxy"] = githubProxyURL; + + if (comboBoxSysProxy.Text != "自动检测") sysProxyURL = $"http://{comboBoxSysProxy.Text}"; + if (checkBoxHighConcurrent.Checked) + { + config["system-proxy"] = sysProxyURL; + config["proxy"] = sysProxyURL; + } + else + { + config["proxy"] = sysProxyURL; + config["system-proxy"] = sysProxyURL; + } + + // 保存订阅列表 + List subUrls = new List(); + // 使用 HashSet 来快速判重(不区分大小写),只比较主干部分(去掉 fragment) + var seen = new HashSet(StringComparer.OrdinalIgnoreCase); + + string allyamlFilePath = System.IO.Path.Combine(executablePath, "output", "all.yaml"); + if (System.IO.File.Exists(allyamlFilePath) && checkBoxKeepSucced.Checked && !checkBoxHighConcurrent.Checked) + { + string succedProxiesUrl = $"http://127.0.0.1:{Convert.ToInt32(numericUpDownWebUIPort.Value)}/all.yaml#KeepSucced"; + string succedProxiesUrlKey = succedProxiesUrl.Split('#')[0]; + if (seen.Add(succedProxiesUrlKey)) + { + subUrls.Add(succedProxiesUrl); + } + Log("已加载上次测试结果。", GetRichTextBoxAllLog()); + } + else + { + Log("不加载上次测试结果。", GetRichTextBoxAllLog()); + } + + if (!string.IsNullOrWhiteSpace(textBoxSubsUrls.Text)) + { + var lines = textBoxSubsUrls.Text + .Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) + .Select(s => s.Trim()) + .Where(s => !string.IsNullOrEmpty(s)); + + foreach (var line in lines) + { + string key = line.Split('#')[0]; + if (seen.Add(key)) + { + subUrls.Add(line); + } + } + + for (int i = 0; i < subUrls.Count; i++) + { + var url = subUrls[i]; + if (url.StartsWith(githubRawPrefix, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(githubProxyURL)) + { + subUrls[i] = githubRawPrefix + url.Substring(githubRawPrefix.Length); + } + } + } + + config["sub-urls"] = subUrls; + + // 处理配置文件下载与配置 + if (comboBoxOverwriteUrls.Text.Contains("[内置]")) + { + // 确定文件名和下载URL + string fileName; + string downloadFilePath; + string downloadUrl; + string displayName; + + if (comboBoxOverwriteUrls.Text.Contains("[内置]布丁狗")) + { + fileName = "bdg.yaml"; + displayName = "[内置]布丁狗的订阅转换"; + downloadUrl = "https://raw.githubusercontent.com/cmliu/ACL4SSR/main/yaml/bdg.yaml"; + } + else // [内置]ACL4SSR + { + fileName = "ACL4SSR_Online_Full.yaml"; + displayName = "[内置]ACL4SSR_Online_Full"; + downloadUrl = "https://raw.githubusercontent.com/beck-8/override-hub/main/yaml/ACL4SSR_Online_Full.yaml"; + } + + // 确保output文件夹存在 + string outputFolderPath = Path.Combine(executablePath, "output"); + if (!Directory.Exists(outputFolderPath)) + { + Directory.CreateDirectory(outputFolderPath); + } + + // 确定文件完整路径 + downloadFilePath = Path.Combine(outputFolderPath, fileName); + if (!File.Exists(downloadFilePath)) await comboBoxOverwriteUrlsSelection(); + + // 检查文件是否存在 + if (!File.Exists(downloadFilePath)) + { + Log($"{displayName} 覆写配置文件 未找到,将使用在线版本。", GetRichTextBoxAllLog()); + config["mihomo-overwrite-url"] = githubProxyURL + downloadUrl; + } + else + { + Log($"{displayName} 覆写配置文件 加载成功。", GetRichTextBoxAllLog()); + config["mihomo-overwrite-url"] = $"http://127.0.0.1:{numericUpDownWebUIPort.Value}/{fileName}"; + } + + } + else if (comboBoxOverwriteUrls.Text.StartsWith(githubRawPrefix)) config["mihomo-overwrite-url"] = githubProxyURL + comboBoxOverwriteUrls.Text; + else config["mihomo-overwrite-url"] = comboBoxOverwriteUrls.Text != "" ? comboBoxOverwriteUrls.Text : $"http://127.0.0.1:{numericUpDownWebUIPort.Value}/ACL4SSR_Online_Full.yaml"; + + config["enable-high-concurrent"] = checkBoxHighConcurrent.Checked;//使用自适应高性能版本 + config["switch-x64"] = checkBoxSwitchArch64.Checked;//是否使用x64内核 + config["rename-node"] = checkBoxEnableRenameNode.Checked;//以节点IP查询位置重命名节点 + config["media-check"] = checkBoxEnableMediaCheck.Checked;//是否开启流媒体检测 + + if (selectedPlatforms != null && selectedPlatforms.Count > 0) + { + config["platforms"] = selectedPlatforms;// 保存平台数组 + } + + config["keep-success-proxies"] = checkBoxKeepSucced.Checked;//是否保留成功的节点 + config["sub-urls-stats"] = checkBoxSubsStats.Checked;//是否统计节点信息 + config["isp-check"] = checkBoxIspCheck.Checked;//是否启用ISP检测 + config["print-progress"] = false;//是否显示进度 + config["sub-urls-retry"] = 3;//重试次数(获取订阅失败后重试次数) + config["subscheck-version"] = 当前subsCheck版本号;//当前subsCheck版本号 + config["subscheck-arch"] = currentArch; //当前subsCheck架构 + config["subscheck-kernel"] = currentKernel; //当前内核 + + config["gui-auto"] = checkBoxStartup.Checked;//是否开机自启 + + //保存几个成功的节点,为0代表不限制 + if (checkBoxEnableSuccessLimit.Checked) config["success-limit"] = (int)numericUpDownSuccessLimit.Value; + else config["success-limit"] = 0; + + //下载速度限制,为0代表不限制 + if (checkBoxTotalBandwidthLimit.Checked) config["total-speed-limit"] = (int)numericUpDownTotalBandwidthLimit.Value; + else config["total-speed-limit"] = 0; + + // 使用YamlDotNet序列化配置 + var serializer = new YamlDotNet.Serialization.SerializerBuilder() + .WithIndentedSequences() // 使序列化结果更易读 + .Build(); + + + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder() + .Build(); + + string yamlContent = serializer.Serialize(config); + + // 确保配置目录存在 + string configDirPath = Path.GetDirectoryName(configFilePath); + if (!Directory.Exists(configDirPath)) + Directory.CreateDirectory(configDirPath); + + string moreYamlPath = Path.Combine(configDirPath, "more.yaml"); + if (File.Exists(moreYamlPath)) + { + // 读取more.yaml的内容 + string moreYamlContent = File.ReadAllText(moreYamlPath); + + // 解析主配置和补充配置 + var Config = deserializer.Deserialize>(yamlContent); + var moreConfig = deserializer.Deserialize>(moreYamlContent); + + if (Config == null) Config = new Dictionary(); + if (moreConfig == null) moreConfig = new Dictionary(); + + // 检查并记录冲突的键 + var conflictKeys = new List(); + var mergedKeys = new List(); + + foreach (var kvp in moreConfig) + { + if (Config.ContainsKey(kvp.Key)) + { + conflictKeys.Add(kvp.Key); + Log($"发现重复键 '{kvp.Key}',使用GUI配置", GetRichTextBoxAllLog()); + } + else + { + Config[kvp.Key] = kvp.Value; + mergedKeys.Add(kvp.Key); + } + } + + // 重新序列化合并后的配置 + yamlContent = serializer.Serialize(Config); + + + Log($"已将补充参数配置 more.yaml 内容追加到配置文件", GetRichTextBoxAllLog()); + } + // 写入YAML文件 + File.WriteAllText(configFilePath, yamlContent); + } + catch (Exception ex) + { + MessageBox.Show($"保存配置文件时发生错误: {ex.Message}", "错误", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void buttonAdvanceSettings_Click(object sender, EventArgs e) + { + if (!_originalLocationSaved) + { + _originalLocationSaved = true; + _pipeOriginalLocation = groupBoxPipeConcurrent.Location; + _enhanceOriginalLocation = groupBoxEnhance.Location; + } + //展开状态 + if (buttonAdvanceSettings.Text == "高级设置∧") + { + buttonAdvanceSettings.Text = "高级设置∨"; + groupBoxAdvanceSettings.Visible = false; + if (!checkBoxHighConcurrent.Checked) + { + groupBoxPipeConcurrent.Visible = false; + groupBoxEnhance.Visible = false; + + groupBoxGist.Location = _pipeOriginalLocation; + groupBoxR2.Location = _pipeOriginalLocation; + groupBoxWebdav.Location = _pipeOriginalLocation; + } + else + { + groupBoxPipeConcurrent.Visible = true; + groupBoxEnhance.Visible = true; + + groupBoxPipeConcurrent.Location = groupBoxAdvanceSettings.Location; + groupBoxEnhance.Location = new Point(groupBoxEnhance.Location.X, groupBoxAdvanceSettings.Location.Y); + } + } + else + { + // 收缩状态 + buttonAdvanceSettings.Text = "高级设置∧"; + groupBoxAdvanceSettings.Visible = true; + if (!checkBoxHighConcurrent.Checked) + { + groupBoxPipeConcurrent.Visible = false; + groupBoxEnhance.Visible = false; + } + else + { + groupBoxPipeConcurrent.Visible = true; + groupBoxEnhance.Visible = true; + groupBoxPipeConcurrent.Location = _pipeOriginalLocation; + groupBoxEnhance.Location = _enhanceOriginalLocation; + } + } + 判断保存类型(); + } + + private async void buttonStartCheck_Click(object sender, EventArgs e) + { + buttonStartCheck.Enabled = false; + if (buttonStartCheck.Text == "▶️ 启动") + { + toolTip1.SetToolTip(buttonStartCheck, "启动检测流程!"); + buttonStartCheck.ForeColor = Color.Black; + if (checkBoxEnableWebUI.Checked && textBoxWebUiAPIKey.Text == "请输入密钥") + { + MessageBox.Show("您已启用WebUI,请设置WebUI API密钥!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + if (checkBoxHighConcurrent.Checked && textBoxSubStorePath.Text == "请输入路径") + { + MessageBox.Show("请设置Sub-Store路径!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + run = 1; + if (buttonCopySubscriptionUrl.Enabled == false) + { + string executablePath = Path.GetDirectoryName(Application.ExecutablePath); + string allyamlFilePath = Path.Combine(executablePath, "output", "all.yaml"); + buttonCopySubscriptionUrl.Enabled = File.Exists(allyamlFilePath); + } + + numericUpDownConcurrent.Enabled = false; + numericUpDownInterval.Enabled = false; + labelCron.Enabled = false; + textBoxCron.Enabled = false; + numericUpDownTimeout.Enabled = false; + numericUpDownMinSpeed.Enabled = false; + numericUpDownDLTimehot.Enabled = false; + numericUpDownDownloadMb.Enabled = false; + numericUpDownTotalBandwidthLimit.Enabled = false; + numericUpDownWebUIPort.Enabled = false; + numericUpDownSubStorePort.Enabled = false; + + + // 运行时禁用流水线并发和增强标签相关设置项 + groupBoxPipeConcurrent.Enabled = false; + groupBoxEnhance.Enabled = false; + checkBoxHighConcurrent.Enabled = false; + checkBoxSwitchArch64.Enabled = false; + + comboBoxSaveMethod.Enabled = false; + textBoxSubsUrls.Enabled = false; + groupBoxAdvanceSettings.Enabled = false; + groupBoxGist.Enabled = false; + groupBoxR2.Enabled = false; + groupBoxWebdav.Enabled = false; + if (checkBoxEnableWebUI.Checked) buttonWebUi.Enabled = true; + buttonStartCheck.Text = "⌛检测代理"; + toolTip1.SetToolTip(buttonStartCheck, "正在检测可用github代理"); + + //timer3.Enabled = true; + // 清空 richTextBox1 + richTextBoxAllLog.Clear(); + await KillNodeProcessAsync(); + await SaveConfig(); + + if (run == 1) + { + // 更新菜单项的启用状态 + startMenuItem.Enabled = false; + stopMenuItem.Enabled = true; + + // 清空 richTextBox1 + //richTextBox1.Clear(); + + notifyIcon1.Text = "SubsCheck: 已就绪"; + + // 启动 subs-check.exe 程序 + buttonStartCheck.ForeColor = Color.Red; + buttonStartCheck.Text = "⏹️ 停止"; + toolTip1.SetToolTip(buttonStartCheck, "停止内核检测进程!"); + + await AutoCheckSysProxy(); + StartSubsCheckProcess(); + } + } + else + { + run = 0; + Log("任务停止", GetRichTextBoxAllLog()); + progressBarAll.Value = 0; + progressBarAll.Visible = false; + labelLogNodeInfo.Text = "实时日志"; + notifyIcon1.Text = "SubsCheck: 未运行"; + // 停止 subs-check.exe 程序 + StopSubsCheckProcess(); + // 结束 Sub-Store + await KillNodeProcessAsync(); + if (checkBoxEnableWebUI.Checked) ReadConfig(); + buttonCopySubscriptionUrl.Enabled = false; + numericUpDownConcurrent.Enabled = true; + numericUpDownInterval.Enabled = true; + labelCron.Enabled = true; + textBoxCron.Enabled = true; + numericUpDownTimeout.Enabled = true; + numericUpDownMinSpeed.Enabled = true; + numericUpDownDLTimehot.Enabled = true; + numericUpDownDownloadMb.Enabled = true; + numericUpDownTotalBandwidthLimit.Enabled = true; + numericUpDownWebUIPort.Enabled = true; + numericUpDownSubStorePort.Enabled = true; + + // 重新启用 + groupBoxPipeConcurrent.Enabled = true; + groupBoxEnhance.Enabled = true; + checkBoxHighConcurrent.Enabled = true; + checkBoxSwitchArch64.Enabled = true; + + comboBoxSaveMethod.Enabled = true; + textBoxSubsUrls.Enabled = true; + groupBoxAdvanceSettings.Enabled = true; + groupBoxGist.Enabled = true; + groupBoxR2.Enabled = true; + groupBoxWebdav.Enabled = true; + buttonWebUi.Enabled = false; + buttonStartCheck.Text = "▶️ 启动"; + buttonStartCheck.ForeColor = Color.Black; + toolTip1.SetToolTip(buttonStartCheck, "启动检测流程!"); + //timer3.Enabled = false; + // 更新菜单项的启用状态 + startMenuItem.Enabled = true; + stopMenuItem.Enabled = false; + } + if (downloading == 0) buttonStartCheck.Enabled = true; + } + + public async Task DownloadSubsCheckEXE() + { + buttonStartCheck.Enabled = false; + downloading = 1; + try + { + Log("正在检查网络连接...", GetRichTextBoxAllLog()); + + // 动态决定使用哪个仓库(checkBoxHighConcurrent 为 true 时使用 sinspired,否则使用 beck-8) + string repoOwner = checkBoxHighConcurrent.Checked ? "sinspired" : "beck-8"; + string apiUrl = $"https://api.github.com/repos/{repoOwner}/subs-check/releases/latest"; + string releasesPageUrl = $"https://github.com/{repoOwner}/subs-check/releases"; + // 决定目标资源名称:64位优先 (amd64),否则 i386 + string desiredArchToken = checkBoxSwitchArch64.Checked ? "x86_64" : "i386"; + string desiredKernel = checkBoxHighConcurrent.Checked ? "高性能内核" : "原版内核"; + string desiredAssetName = $"subs-check_Windows_{desiredArchToken}.zip"; + + // 首先检查是否有网络连接 + if (!IsNetworkAvailable()) + { + Log("网络连接不可用,无法下载核心文件。", GetRichTextBoxAllLog(), true); + MessageBox.Show($"缺少 subs-check.exe 核心文件。\n\n您可以前往 {releasesPageUrl} 自行下载!", + "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + await AutoCheckSysProxy(); + var result = await 获取版本号(apiUrl, true); + if (result.Item1 == "未知版本") + { + // 无版本信息 + return; + } + + // 创建不使用系统代理的 HttpClientHandler + HttpClientHandler handler = new HttpClientHandler + { + UseProxy = false, + Proxy = null + }; + + // 使用自定义 handler 创建 HttpClient + using (HttpClient client = new HttpClient(handler)) + { + try + { + string latestVersion = result.Item1; + JArray assets = result.Item2; + Log($"subs-check.exe 最新版本为: {latestVersion} ", GetRichTextBoxAllLog()); + + // 先尝试精确匹配期望文件名;找不到则回退为任意包含 "Windows" 且包含 arch token 的条目; + // 若仍找不到,再回退为任意包含 "Windows" 的资源。 + string downloadUrl = null; + foreach (var asset in assets) + { + if (asset["name"]?.ToString().Equals(desiredAssetName, StringComparison.OrdinalIgnoreCase) == true) + { + downloadUrl = asset["browser_download_url"].ToString(); + break; + } + } + + if (downloadUrl == null) + { + foreach (var asset in assets) + { + string name = asset["name"]?.ToString() ?? ""; + if (name.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) >= 0 && + name.IndexOf(desiredArchToken, StringComparison.OrdinalIgnoreCase) >= 0) + { + downloadUrl = asset["browser_download_url"].ToString(); + break; + } + } + } + + if (downloadUrl == null) + { + // 最后退化:任何 Windows 包 + foreach (var asset in assets) + { + string name = asset["name"]?.ToString() ?? ""; + if (name.IndexOf("Windows", StringComparison.OrdinalIgnoreCase) >= 0) + { + downloadUrl = asset["browser_download_url"].ToString(); + break; + } + } + } + + if (downloadUrl == null) + { + Log("无法找到适用于 Windows 的下载链接。", GetRichTextBoxAllLog(), true); + MessageBox.Show($"未能找到适用的 subs-check.exe 下载链接。\n\n可尝试更换 Github Proxy 后,点击「检查更新」>「更新内核」。\n或前往 {releasesPageUrl} 自行下载!", + "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + string executablePath = Path.GetDirectoryName(Application.ExecutablePath); + string zipFilePath = Path.Combine(executablePath, desiredAssetName); + + // 如果文件已存在,先删除 + if (File.Exists(zipFilePath)) File.Delete(zipFilePath); + + Log("开始下载内核文件...", GetRichTextBoxAllLog()); + + + // 优先尝试 GitHub 代理,再尝试系统代理,最后使用无代理直连 + var (downloadSuccess, failureReason) = await TryDownloadWithStrategiesAsync( + downloadUrl, + zipFilePath, + new[] { DownloadStrategy.SystemProxy, DownloadStrategy.GithubProxy, DownloadStrategy.Direct }); + + + // 如果所有尝试失败 + if (!downloadSuccess) + { + Log($"所有下载尝试均失败,最后错误: {failureReason}", GetRichTextBoxAllLog(), true); + MessageBox.Show( + $"下载 subs-check.exe 失败,请检查网络连接后重试。\n\n可尝试更换 Github Proxy 后,点击「检查更新」>「更新内核」。\n或前往 {releasesPageUrl} 自行下载!", + "下载失败", MessageBoxButtons.OK, MessageBoxIcon.Error); + + progressBarAll.Value = 0; + progressBarAll.Visible = false; + return; + } + + + // 下载成功 -> 解压并查找 subs-check.exe + Log("下载完成,正在解压文件...", GetRichTextBoxAllLog()); + // 解压文件 + using (System.IO.Compression.ZipArchive archive = System.IO.Compression.ZipFile.OpenRead(zipFilePath)) + { + // 查找subs-check.exe + var exeEntry = archive.Entries.FirstOrDefault( + entry => entry.Name.Equals("subs-check.exe", StringComparison.OrdinalIgnoreCase)); + + if (exeEntry != null) + { + string exeFilePath = Path.Combine(executablePath, "subs-check.exe"); + // 如果文件已存在,先删除 + if (File.Exists(exeFilePath)) File.Delete(exeFilePath); + + // 解压文件 + exeEntry.ExtractToFile(exeFilePath); + currentKernel = desiredKernel; + currentArch = desiredArchToken; + + 当前subsCheck版本号 = $"{latestVersion}"; + + Log($"{currentKernel}({currentArch}): subs-check.exe {当前subsCheck版本号} 已就绪!", GetRichTextBoxAllLog()); + + buttonCheckUpdate.ForeColor = Color.Black; + buttonCheckUpdate.Text = "检查更新"; + string defaultTitle = $"SubsCheck Win GUI {当前GUI版本号}"; + 标题 = defaultTitle; + this.Text = 标题; + + await SaveConfig(false); + + // 可选:删除 zip 文件(注释状态保留原样) + //File.Delete(zipFilePath); + } + else + { + Log("无法在压缩包中找到 subs-check.exe 文件。", GetRichTextBoxAllLog(), true); + } + } + } + catch (Exception ex) + { + Log($"下载过程中出错: {ex.Message}", GetRichTextBoxAllLog(), true); + MessageBox.Show($"下载 subs-check.exe 时出错: {ex.Message}\n\n可尝试更换 Github Proxy 后,点击「检查更新」>「更新内核」。\n或前往 {releasesPageUrl} 自行下载!", + "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + catch (Exception ex) + { + Log($"初始化下载过程出错: {ex.Message}", GetRichTextBoxAllLog(), true); + MessageBox.Show($"下载准备过程出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + buttonStartCheck.Enabled = true; + downloading = 0; + } + } + + + /// + /// 获取最新版本号和对应的下载链接 + /// + /// API请求URL + /// 是否在日志中输出信息 + /// 包含最新版本号和下载链接的元组 + private async Task<(string LatestVersion, JArray assets)> 获取版本号(string 版本号URL, bool 是否输出log = false) + { + string latestVersion = "未知版本"; + JArray assets = null; + + // 创建不使用系统代理的 HttpClientHandler + HttpClientHandler handler = new HttpClientHandler + { + UseProxy = false, + Proxy = null + }; + + // 使用自定义 handler 创建 HttpClient + using (HttpClient client = new HttpClient(handler)) + { + client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); + client.Timeout = TimeSpan.FromSeconds(30); // 增加超时时间以适应下载需求 + + if (是否输出log) Log("正在获取最新版本 subs-check.exe 内核下载地址...", GetRichTextBoxAllLog()); + string url = 版本号URL; + string 备用url = 版本号URL.Replace("api.github.com", "api.github.cmliussss.net"); + + HttpResponseMessage response = null; + string responseBody = null; + JObject json = null; + + // 先尝试主URL + try + { + response = await client.GetAsync(url); + + // 如果主URL请求成功返回有效数据 + if (response.IsSuccessStatusCode) + { + responseBody = await response.Content.ReadAsStringAsync(); + json = JObject.Parse(responseBody); + if (是否输出log) Log("成功从主API获取版本信息", GetRichTextBoxAllLog()); + } + // 如果主URL请求不成功但没有抛出异常 + else + { + if (是否输出log) Log($"主API请求失败 HTTP {(int)response.StatusCode},尝试备用API...", GetRichTextBoxAllLog()); + response = await client.GetAsync(备用url); + + if (response.IsSuccessStatusCode) + { + responseBody = await response.Content.ReadAsStringAsync(); + json = JObject.Parse(responseBody); + if (是否输出log) Log("成功从备用API获取版本信息", GetRichTextBoxAllLog()); + } + else + { + if (是否输出log) Log($"备用API也请求失败: HTTP {(int)response.StatusCode}", GetRichTextBoxAllLog(), true); + return (latestVersion, assets); // 两个URL都失败,提前退出 + } + } + } + // 捕获网络请求异常(如连接超时、无法解析域名等) + catch (HttpRequestException ex) + { + if (是否输出log) Log($"主API请求出错: {ex.Message},尝试备用API...", GetRichTextBoxAllLog()); + try + { + response = await client.GetAsync(备用url); + if (response.IsSuccessStatusCode) + { + responseBody = await response.Content.ReadAsStringAsync(); + json = JObject.Parse(responseBody); + if (是否输出log) Log("成功从备用API获取版本信息", GetRichTextBoxAllLog()); + } + else + { + if (是否输出log) Log($"备用API也请求失败: HTTP {(int)response.StatusCode}", GetRichTextBoxAllLog(), true); + return (latestVersion, assets); // 备用URL也失败,提前退出 + } + } + catch (Exception backupEx) + { + if (是否输出log) Log($"备用API请求也出错: {backupEx.Message}", GetRichTextBoxAllLog(), true); + return (latestVersion, assets); // 连备用URL也异常,提前退出 + } + } + // 捕获JSON解析异常 + catch (Newtonsoft.Json.JsonException ex) + { + if (是否输出log) Log($"解析JSON数据出错: {ex.Message}", GetRichTextBoxAllLog(), true); + try + { + response = await client.GetAsync(备用url); + if (response.IsSuccessStatusCode) + { + responseBody = await response.Content.ReadAsStringAsync(); + json = JObject.Parse(responseBody); + if (是否输出log) Log("成功从备用API获取版本信息", GetRichTextBoxAllLog()); + } + } + catch (Exception backupEx) + { + if (是否输出log) Log($"备用API请求也出错: {backupEx.Message}", GetRichTextBoxAllLog(), true); + return (latestVersion, assets); // 连备用URL也有问题,提前退出 + } + } + // 捕获其他所有异常 + catch (Exception ex) + { + if (是否输出log) Log($"获取版本信息时出现未预期的错误: {ex.Message}", GetRichTextBoxAllLog(), true); + try + { + response = await client.GetAsync(备用url); + if (response.IsSuccessStatusCode) + { + responseBody = await response.Content.ReadAsStringAsync(); + json = JObject.Parse(responseBody); + if (是否输出log) Log("成功从备用URL获取版本信息", GetRichTextBoxAllLog()); + } + } + catch (Exception backupEx) + { + if (是否输出log) Log($"备用API请求也出错: {backupEx.Message}", GetRichTextBoxAllLog(), true); + return (latestVersion, assets); // 连备用URL也有问题,提前退出 + } + } + + // 如果成功获取了JSON数据,继续处理 + if (json != null) + { + latestVersion = json["tag_name"].ToString(); + assets = (JArray)json["assets"]; + } + } + + return (latestVersion, assets); + } + + + private async void StartSubsCheckProcess() + { + try + { + // 重置进度条 + progressBarAll.Value = 0; + progressBarAll.Visible = true; + progressBarAll.Enabled = true; + labelLogNodeInfo.Text = "实时日志"; + using (MemoryStream ms = new MemoryStream(Properties.Resources.going)) + { + notifyIcon1.Icon = new Icon(ms); + } + + // 获取当前应用程序目录 + string executablePath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); + string subsCheckPath = Path.Combine(executablePath, "subs-check.exe"); + // 设置一个环境变量以表明是有GUI启动的 + + Environment.SetEnvironmentVariable("START_FROM_GUI", "true"); + + // 检查是否有其他subs-check.exe进程正在运行,并强制结束它们 + try + { + Process[] processes = Process.GetProcessesByName("subs-check"); + if (processes.Length > 0) + { + Log("发现正在运行的subs-check.exe进程,正在强制结束...", GetRichTextBoxAllLog()); + foreach (Process process in processes) + { + // 确保不是当前应用程序的进程 + if (process != subsCheckProcess) + { + try + { + process.Kill(); + process.WaitForExit(); + Log($"成功结束subs-check.exe进程(ID: {process.Id})", GetRichTextBoxAllLog()); + } + catch (Exception ex) + { + Log($"结束subs-check.exe进程时出错(ID: {process.Id}): {ex.Message}", GetRichTextBoxAllLog(), true); + } + } + } + } + } + catch (Exception ex) + { + Log($"检查运行中的subs-check.exe进程时出错: {ex.Message}", GetRichTextBoxAllLog(), true); + } + + // 检查文件是否存在 + if (!File.Exists(subsCheckPath)) + { + Log("没有找到 subs-check.exe 文件。", GetRichTextBoxAllLog(), true); + await DownloadSubsCheckEXE(); // 使用异步等待 + } + + // 创建进程启动信息 + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = subsCheckPath, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + WorkingDirectory = executablePath, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8 + }; + + // 创建进程 + subsCheckProcess = new Process { StartInfo = startInfo }; + + // 设置输出和错误数据接收事件处理 + subsCheckProcess.OutputDataReceived += SubsCheckProcess_OutputDataReceived; + subsCheckProcess.ErrorDataReceived += SubsCheckProcess_OutputDataReceived; + + // 启动进程 + subsCheckProcess.Start(); + + // 开始异步读取输出 + subsCheckProcess.BeginOutputReadLine(); + subsCheckProcess.BeginErrorReadLine(); + + // 设置进程退出事件处理 + subsCheckProcess.EnableRaisingEvents = true; + subsCheckProcess.Exited += SubsCheckProcess_Exited; + + Log($"subs-check.exe {当前subsCheck版本号} 已启动...", GetRichTextBoxAllLog()); + timerRefresh.Enabled = true; + + // 启动进程后就可以使用WebUI + buttonWebUi.Enabled = true; + + // 如果使用cron表达式,启用手动检测按钮 + if (textBoxCron.Visible == true) + { + buttonTriggerCheck.Enabled = true; + } + } + catch (Exception ex) + { + Log($"启动 subs-check.exe 时出错: {ex.Message}", GetRichTextBoxAllLog(), true); + buttonStartCheck.Text = "▶️ 启动"; + buttonStartCheck.ForeColor = Color.Black; + } + } + + + private void StopSubsCheckProcess() + { + timerRefresh.Enabled = false; + if (subsCheckProcess != null && !subsCheckProcess.HasExited) + { + try + { + // 尝试正常关闭进程 + subsCheckProcess.Kill(); + subsCheckProcess.WaitForExit(); + Log("subs-check.exe 已停止", GetRichTextBoxAllLog()); + notifyIcon1.Icon = originalNotifyIcon; + buttonTriggerCheck.Enabled = false; + buttonTriggerCheck.Text = "🔀未启动"; + } + catch (Exception ex) + { + Log($"停止 subs-check.exe 时出错: {ex.Message}", GetRichTextBoxAllLog(), true); + } + finally + { + subsCheckProcess.Dispose(); + subsCheckProcess = null; + // 结束进程后禁用WebUI + buttonWebUi.Enabled = false; + } + } + } + + private void SubsCheckProcess_OutputDataReceived(object sender, DataReceivedEventArgs e) + { + if (string.IsNullOrEmpty(e.Data)) return; + + var state = this.Tag as Tuple, System.Windows.Forms.Timer>; + if (state == null) + { + // 首次初始化在 UI 线程完成 + BeginInvoke(new Action(() => + { + var st2 = this.Tag as Tuple, System.Windows.Forms.Timer>; + if (st2 != null) + { + st2.Item1.Enqueue(e.Data); + // 启动定时器(如果尚未运行) + if (!st2.Item2.Enabled) st2.Item2.Start(); + return; + } + + var q = new System.Collections.Concurrent.ConcurrentQueue(); + var t = new System.Windows.Forms.Timer { Interval = 200 }; // 可调:80-200ms + t.Tick += (s, ev) => + { + // 若无新日志,立即停表避免空转重绘 + if (q.IsEmpty) + { + try { if (t.Enabled) t.Stop(); } catch { } + return; + } + + var sb = new System.Text.StringBuilder(); + + while (q.TryDequeue(out var rawLine)) + { + string clean = RemoveAnsiEscapeCodes(rawLine); + + // 过滤掉空白行与 [GIN] 行,避免无意义刷新 + if (string.IsNullOrWhiteSpace(clean)) continue; + if (clean.StartsWith("[GIN]")) continue; + + // 一次性“下次检查时间” + if (clean.Contains("下次检查时间:")) + { + if (!buttonCopySubscriptionUrl.Enabled) + { + string executablePath = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); + string outputFolderPath = System.IO.Path.Combine(executablePath, "output"); + if (System.IO.Directory.Exists(outputFolderPath)) + { + string allyamlFilePath = System.IO.Path.Combine(outputFolderPath, "all.yaml"); + if (System.IO.File.Exists(allyamlFilePath)) buttonCopySubscriptionUrl.Enabled = true; + } + } + int startIndex = clean.IndexOf("下次检查时间:"); + var lineOnly = clean.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None)[0]; + nextCheckTime = lineOnly.Substring(startIndex); + } + + sb.AppendLine(clean); + } + + // 若本轮没有有效输出,停止计时器并退出 + if (sb.Length == 0) + { + try { if (q.IsEmpty && t.Enabled) t.Stop(); } catch { } + return; + } + + // 批量追加时暂时禁用重绘,减少闪烁 + SuspendRedraw(richTextBoxAllLog); + try + { + richTextBoxAllLog.AppendText(sb.ToString()); + richTextBoxAllLog.SelectionStart = richTextBoxAllLog.TextLength; + richTextBoxAllLog.ScrollToCaret(); + } + finally + { + ResumeRedraw(richTextBoxAllLog); + } + + // 若已消费完,停止定时器 + if (q.IsEmpty) + { + try { if (t.Enabled) t.Stop(); } catch { } + } + }; + + t.Start(); + this.Tag = Tuple.Create(q, t); + + // 入队并确保定时器在 UI 线程已启动 + q.Enqueue(e.Data); + })); + + return; + } + + // 已初始化:直接入队(非 UI 线程安全) + state.Item1.Enqueue(e.Data); + + // 确保定时器正在运行(使用 BeginInvoke 在 UI 线程安全地检查/启动) + BeginInvoke(new Action(() => + { + Tuple, System.Windows.Forms.Timer> st = this.Tag as Tuple, System.Windows.Forms.Timer>; + if (st != null && !st.Item2.Enabled) + { + st.Item2.Start(); + } + })); + } + + + /* + // 检查是否是进度信息行 + if (cleanText.StartsWith("进度: [")) + { + // 解析百分比 + int percentIndex = cleanText.IndexOf('%'); + if (percentIndex > 0) + { + // 查找百分比前面的数字部分 + int startIndex = cleanText.LastIndexOfAny(new char[] { ' ', '>' }, percentIndex) + 1; + string percentText = cleanText.Substring(startIndex, percentIndex - startIndex); + + if (double.TryParse(percentText, out double percentValue)) + { + // 更新进度条,将百分比值(0-100)设置给进度条 + progressBar1.Value = (int)Math.Round(percentValue); + } + } + + // 解析节点信息部分(例如:(12/6167) 可用: 0) + int infoStartIndex = cleanText.IndexOf('('); + if (infoStartIndex > 0) + { + string fullNodeInfo = cleanText.Substring(infoStartIndex); + + // 提取最重要的信息:节点数量和可用数量 + int endIndex = fullNodeInfo.IndexOf("2025-"); // 查找日期部分开始位置 + if (endIndex > 0) + { + nodeInfo = fullNodeInfo.Substring(0, endIndex).Trim(); + } + else + { + // 如果找不到日期部分,则取前30个字符 + nodeInfo = fullNodeInfo.Length > 30 ? fullNodeInfo.Substring(0, 30) + "..." : fullNodeInfo; + } + + groupBox2.Text = "实时日志 " + nodeInfo; + + // 确保通知图标文本不超过63个字符 + string notifyText = "SubsCheck: " + nodeInfo; + if (notifyText.Length > 63) + { + notifyText = notifyText.Substring(0, 60) + "..."; + } + notifyIcon1.Text = notifyText; + } + + // 更新lastProgressLine,但不向richTextBox添加文本 + lastProgressLine = cleanText; + } + else + { + // 如果不是进度行,则添加到日志中 + richTextBox1.AppendText(cleanText + "\r\n"); + // 滚动到最底部 + richTextBox1.SelectionStart = richTextBox1.Text.Length; + richTextBox1.ScrollToCaret(); + } + */ + + + // 添加一个方法来过滤ANSI转义序列 + private string RemoveAnsiEscapeCodes(string input) + { + // 匹配ANSI转义序列的正则表达式 + // 这将匹配类似 "[2m"、"[0m"、"[92m" 等格式的ANSI颜色代码 + return System.Text.RegularExpressions.Regex.Replace(input, @"\x1B\[[0-9;]*[mGK]", string.Empty); + } + + private void SubsCheckProcess_Exited(object sender, EventArgs e) + { + // 进程退出时,在 UI 线程上更新控件 + BeginInvoke(new Action(() => + { + Log("subs-check.exe 已退出", GetRichTextBoxAllLog()); + buttonStartCheck.Text = "▶️ 启动"; + buttonStartCheck.ForeColor = Color.Black; + + // 更新菜单项的启用状态 + startMenuItem.Enabled = true; + stopMenuItem.Enabled = false; + + // 重新启用控件 + numericUpDownConcurrent.Enabled = true; + numericUpDownInterval.Enabled = true; + numericUpDownTimeout.Enabled = true; + numericUpDownMinSpeed.Enabled = true; + numericUpDownDLTimehot.Enabled = true; + numericUpDownDownloadMb.Enabled = true; + numericUpDownTotalBandwidthLimit.Enabled = true; + numericUpDownWebUIPort.Enabled = true; + textBoxSubsUrls.Enabled = true; + groupBoxAdvanceSettings.Enabled = true; + // 重新启用 + groupBoxPipeConcurrent.Enabled = true; + groupBoxEnhance.Enabled = true; + checkBoxHighConcurrent.Enabled = true; + checkBoxSwitchArch64.Enabled = true; + })); + } + + /// + /// 获取本地局域网IP地址,如果有多个则让用户选择 + /// + /// 用户选择的IP地址,如果未选择则返回127.0.0.1 + private string GetLocalLANIP() + { + try + { + // 获取所有网卡的IP地址 + List lanIPs = new List(); + + // 获取所有网络接口 + foreach (System.Net.NetworkInformation.NetworkInterface ni in System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()) + { + // 排除loopback、虚拟网卡和非活动网卡 + if (ni.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback && + ni.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up) + { + // 获取该网卡的所有IP地址 + foreach (System.Net.NetworkInformation.UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses) + { + // 只添加IPv4地址且不是回环地址 + if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && + !System.Net.IPAddress.IsLoopback(ip.Address)) + { + lanIPs.Add(ip.Address.ToString()); + } + } + } + } + + // 如果没有找到任何IP地址,返回本地回环地址 + if (lanIPs.Count == 0) + { + return "127.0.0.1"; + } + // 如果只找到一个IP地址,直接返回 + else if (lanIPs.Count == 1) + { + return lanIPs[0]; + } + // 如果有多个IP地址,让用户选择 + else + { + // 创建选择窗口 + using (Form selectForm = new Form()) // 使用 using 确保资源释放 + { + selectForm.Text = "选择局域网IP地址"; + selectForm.Font = new Font("宋体", 9F); // 统一字体 + selectForm.FormBorderStyle = FormBorderStyle.FixedDialog; + selectForm.StartPosition = FormStartPosition.CenterParent; + selectForm.MaximizeBox = false; + selectForm.MinimizeBox = false; + selectForm.AutoSize = true; + selectForm.AutoSizeMode = AutoSizeMode.GrowAndShrink; + selectForm.Padding = new Padding(15); // 窗体边缘留白 + + // 主布局容器:垂直排列所有元素 + var mainLayout = new TableLayoutPanel + { + Dock = DockStyle.Fill, + AutoSize = true, + AutoSizeMode = AutoSizeMode.GrowAndShrink, + ColumnCount = 1, + RowCount = 4, // 说明文本、列表、警告、按钮组 + Padding = new Padding(0) + }; + + // 1. 说明标签 + Label label = new Label(); + label.Text = "发现多个局域网IP地址:\n\n" + + "- 仅在本机访问:直接点击【取消】,将使用127.0.0.1\n" + + "- 局域网内其他设备访问:请在下面列表中选择一个正确的局域网IP"; + label.AutoSize = true; + label.MaximumSize = new Size(550, 0); // 限制最大宽度,自动换行 + label.Margin = new Padding(0, 0, 0, 20); // 下边距 + + // 2. IP列表框 + ListBox listBox = new ListBox(); + listBox.Width = 550; // 稍微加宽 + listBox.Height = 160; + listBox.Font = new Font("Verdana", 10F); // IP地址用英文字体显示更清晰 + foreach (string ip in lanIPs) + { + listBox.Items.Add(ip); + } + + // 智能选择逻辑:优先选非 .1 结尾的 + int selectedIndex = 0; + for (int i = 0; i < lanIPs.Count; i++) + { + if (!lanIPs[i].EndsWith(".1")) + { + selectedIndex = i; + break; + } + } + if (listBox.Items.Count > 0) + listBox.SelectedIndex = selectedIndex; + + // 3. 警告标签 + Label warningLabel = new Label(); + warningLabel.Text = "注意:\n\n选择错误的IP会导致局域网内其他设备无法访问。\n推荐您可以先尝试使用非“.1”结尾的IP!"; + warningLabel.AutoSize = true; + warningLabel.ForeColor = Color.Red; + warningLabel.MaximumSize = new Size(550, 0); + warningLabel.Margin = new Padding(0, 20, 0, 25); // 上下边距 + + // 4. 按钮区域 (使用 FlowLayoutPanel 居中对齐) + FlowLayoutPanel buttonPanel = new FlowLayoutPanel + { + AutoSize = true, + FlowDirection = FlowDirection.LeftToRight, + Anchor = AnchorStyles.Top | AnchorStyles.Bottom, // 在单元格内居中需要配合父级设置 + Dock = DockStyle.Fill, + Padding = new Padding(0), + Margin = new Padding(0) + }; + // 让 FlowLayoutPanel 内容居中比较特殊,这里用 Margin 手动推 或者将 Panel 居中 + // 简单做法:直接让 mainLayout 的这一行居中 + + Button okButton = new Button(); + okButton.Text = "确定"; + okButton.DialogResult = DialogResult.OK; + okButton.Size = new Size(100, 32); // 【关键修改】增加宽度和高度 + okButton.Cursor = Cursors.Hand; + + Button cancelButton = new Button(); + cancelButton.Text = "取消"; + cancelButton.DialogResult = DialogResult.Cancel; + cancelButton.Size = new Size(100, 32); // 增加宽度和高度 + cancelButton.Margin = new Padding(20, 0, 0, 0); // 按钮间距 + cancelButton.Cursor = Cursors.Hand; + + buttonPanel.Controls.Add(okButton); + buttonPanel.Controls.Add(cancelButton); + + // 将按钮面板放入主布局,并设置居中 + mainLayout.Controls.Add(label, 0, 0); + mainLayout.Controls.Add(listBox, 0, 1); + mainLayout.Controls.Add(warningLabel, 0, 2); + mainLayout.Controls.Add(buttonPanel, 0, 3); + + // 设置按钮面板在单元格内居中 + mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + mainLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + // 这种写法是为了让 buttonPanel 在 TableLayout 的单元格里居中 + buttonPanel.Anchor = AnchorStyles.None; + + selectForm.Controls.Add(mainLayout); + selectForm.AcceptButton = okButton; + selectForm.CancelButton = cancelButton; + + // 显示逻辑 + if (selectForm.ShowDialog() == DialogResult.OK && listBox.SelectedItem != null) + { + return listBox.SelectedItem.ToString(); + } + else + { + return "127.0.0.1"; + } + } + } + } + catch (Exception ex) + { + MessageBox.Show($"获取局域网IP地址时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + return "127.0.0.1"; + } + } + + private void buttonCopySubscriptionUrl_Click(object sender, EventArgs e) + { + string 本地IP = GetLocalLANIP(); + try + { + string subPath = textBoxSubStorePath.Text.Trim(); + subPath = !string.IsNullOrEmpty(subPath) && subPath != "请输入路径" + ? (subPath.StartsWith("/") ? subPath : "/" + subPath) + : string.Empty; + + string baseSubStoreUrl = $"http://{本地IP}:{numericUpDownSubStorePort.Value}{subPath}"; + string url; + + if (comboBoxSubscriptionType.Text == "Clash") + { + url = $"{baseSubStoreUrl}/api/file/mihomo"; + } + else if (comboBoxSubscriptionType.Text == "Singbox1.11" && checkBoxHighConcurrent.Checked) + { + url = $"{baseSubStoreUrl}/api/file/singbox-1.11"; + } + else if (comboBoxSubscriptionType.Text == "Singbox1.12" && checkBoxHighConcurrent.Checked) + { + url = $"{baseSubStoreUrl}/api/file/singbox-1.12"; + } + else + { + url = $"{baseSubStoreUrl}/download/sub"; + } + + // 将URL复制到剪贴板 + Clipboard.SetText(url); + buttonCopySubscriptionUrl.Text = "复制成功"; + timerCopySubscriptionUrl.Enabled = true; + // 可选:显示提示消息 + //MessageBox.Show($"URL已复制到剪贴板:\n{url}", "复制成功", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + catch (Exception ex) + { + MessageBox.Show($"复制到剪贴板时出错:{ex.Message}", "错误", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void timerCopySubscriptionUrl_Tick(object sender, EventArgs e) + { + buttonCopySubscriptionUrl.Text = "复制订阅"; + } + + private void comboBox2_Leave(object sender, EventArgs e) + { + // 检查是否有内容 + if (string.IsNullOrWhiteSpace(comboBoxSpeedtestUrl.Text)) + { + comboBoxSpeedtestUrl.Text = "不测速"; + return; + } + + string input = comboBoxSpeedtestUrl.Text.Trim(); + + // 更新 comboBox2 的文本和选项 + comboBoxSpeedtestUrl.Items.Add(input); + comboBoxSpeedtestUrl.Text = input; + } + + private void comboBoxSysProxy_Leave(object sender, EventArgs e) + { + // 检查是否有内容 + if (string.IsNullOrWhiteSpace(comboBoxSysProxy.Text)) + { + comboBoxSysProxy.Text = "自动检测"; + return; + } + + string input = comboBoxSysProxy.Text.Trim(); + + // 检查是否存在 "://" 协议部分 + int protocolIndex = input.IndexOf("://"); + if (protocolIndex >= 0) + { + // 保留 "://" 之后的内容 + input = input.Substring(protocolIndex + 3); + } + + // 检查是否存在 "/" 路径部分 + int pathIndex = input.IndexOf('/'); + if (pathIndex >= 0) + { + // 只保留 "/" 之前的域名部分 + input = input.Substring(0, pathIndex); + } + + // 更新 comboBox3 的文本 + comboBoxSysProxy.Text = input; + } + + private void comboBoxGithubProxyUrl_Leave(object sender, EventArgs e) + { + // 检查是否有内容 + if (string.IsNullOrWhiteSpace(comboBoxGithubProxyUrl.Text)) + { + comboBoxGithubProxyUrl.Text = "自动选择"; + return; + } + + string input = comboBoxGithubProxyUrl.Text.Trim(); + + // 检查是否存在 "://" 协议部分 + int protocolIndex = input.IndexOf("://"); + if (protocolIndex >= 0) + { + // 保留 "://" 之后的内容 + input = input.Substring(protocolIndex + 3); + } + + // 检查是否存在 "/" 路径部分 + int pathIndex = input.IndexOf('/'); + if (pathIndex >= 0) + { + // 只保留 "/" 之前的域名部分 + input = input.Substring(0, pathIndex); + } + + // 更新 comboBox3 的文本 + comboBoxGithubProxyUrl.Text = input; + } + + private void 判断保存类型() + { + if (comboBoxSaveMethod.Text == "本地" || buttonAdvanceSettings.Text == "高级设置∨") + { + groupBoxGist.Visible = false; + groupBoxR2.Visible = false; + groupBoxWebdav.Visible = false; + } + else if (comboBoxSaveMethod.Text == "gist" && buttonAdvanceSettings.Text == "高级设置∧") + { + if (!checkBoxHighConcurrent.Checked) + { + groupBoxGist.Location = _pipeOriginalLocation; + } + + groupBoxGist.Visible = true; + + groupBoxR2.Visible = false; + groupBoxWebdav.Visible = false; + } + else if (comboBoxSaveMethod.Text == "r2" && buttonAdvanceSettings.Text == "高级设置∧") + { + if (!checkBoxHighConcurrent.Checked) + { + groupBoxR2.Location = _pipeOriginalLocation; + } + groupBoxR2.Location = groupBoxGist.Location; + groupBoxR2.Visible = true; + + groupBoxGist.Visible = false; + groupBoxWebdav.Visible = false; + } + else if (comboBoxSaveMethod.Text == "webdav" && buttonAdvanceSettings.Text == "高级设置∧") + { + if (!checkBoxHighConcurrent.Checked) + { + groupBoxWebdav.Location = _pipeOriginalLocation; + } + groupBoxWebdav.Location = groupBoxGist.Location; + groupBoxWebdav.Visible = true; + + groupBoxGist.Visible = false; + groupBoxR2.Visible = false; + } + } + + private void comboBoxSaveMethod_TextChanged(object sender, EventArgs e) + { + 判断保存类型(); + if (!(comboBoxSaveMethod.Text == "本地" || comboBoxSaveMethod.Text == "") && buttonAdvanceSettings.Text == "高级设置∨") buttonAdvanceSettings_Click(sender, e); + } + + private void textBox3_Enter(object sender, EventArgs e) + { + textBox3.PasswordChar = '\0'; + textBox6.PasswordChar = '\0'; + textBox8.PasswordChar = '\0'; + } + + private void textBox3_Leave(object sender, EventArgs e) + { + textBox3.PasswordChar = '*'; + textBox6.PasswordChar = '*'; + textBox8.PasswordChar = '*'; + } + + private void textBoxWebUiAPIKey_Enter(object sender, EventArgs e) + { + textBoxWebUiAPIKey.PasswordChar = '\0'; + if (textBoxWebUiAPIKey.Text == "请输入密钥") + { + textBoxWebUiAPIKey.Text = ""; + textBoxWebUiAPIKey.ForeColor = Color.Black; + } + } + + private void textBoxWebUiAPIKey_Leave(object sender, EventArgs e) + { + + if (textBoxWebUiAPIKey.Text == "") + { + textBoxWebUiAPIKey.PasswordChar = '\0'; + textBoxWebUiAPIKey.Text = "请输入密钥"; + textBoxWebUiAPIKey.ForeColor = Color.Gray; + } + else + { + textBoxWebUiAPIKey.ForeColor = Color.Black; + textBoxWebUiAPIKey.PasswordChar = '*'; + } + } + + private void textBoxSubStorePath_Enter(object sender, EventArgs e) + { + textBoxSubStorePath.PasswordChar = '\0'; + if (textBoxSubStorePath.Text == "请输入路径") + { + textBoxSubStorePath.Text = ""; + textBoxSubStorePath.ForeColor = Color.Black; + } + } + + private void textBoxSubStorePath_Leave(object sender, EventArgs e) + { + + if (textBoxSubStorePath.Text == "") + { + textBoxSubStorePath.PasswordChar = '\0'; + textBoxSubStorePath.Text = "请输入路径"; + textBoxSubStorePath.ForeColor = Color.Gray; + } + else + { + textBoxSubStorePath.ForeColor = Color.Black; + textBoxSubStorePath.PasswordChar = '*'; + } + } + private void textBox7_Leave(object sender, EventArgs e) + { + // 检查是否有内容 + if (string.IsNullOrWhiteSpace(textBox7.Text)) + return; + + string input = textBox7.Text.Trim(); + + try + { + // 尝试解析为 URI + Uri uri = new Uri(input); + + // 构建基础 URL (scheme + authority) + string baseUrl = $"{uri.Scheme}://{uri.Authority}"; + + // 更新 textBox7 的文本为基础 URL + textBox7.Text = baseUrl; + } + catch (UriFormatException) + { + // 如果输入的不是有效 URI,尝试使用简单的字符串处理 + // 查找双斜杠后的第一个斜杠 + int schemeIndex = input.IndexOf("://"); + if (schemeIndex >= 0) + { + int pathStartIndex = input.IndexOf('/', schemeIndex + 3); + if (pathStartIndex >= 0) + { + // 截取到路径开始之前 + textBox7.Text = input.Substring(0, pathStartIndex); + } + } + } + } + + private RichTextBox GetRichTextBoxAllLog() + { + return richTextBoxAllLog; + } + + public void Log(string message, RichTextBox richTextBoxAllLog, bool isError = false) + { + string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + string logType = isError ? "ERR" : "INF"; + richTextBoxAllLog.AppendText($"{timestamp} {logType} {message}\r\n"); + + if (richTextBoxAllLog.IsHandleCreated) + { + richTextBoxAllLog.BeginInvoke((MethodInvoker)(() => + { + // 滚动到最底部 + richTextBoxAllLog.SelectionStart = richTextBoxAllLog.Text.Length; + richTextBoxAllLog.ScrollToCaret(); + })); + } + } + + private void 恢复窗口() + { + // 首先显示窗体 + this.Show(); + + // 强制停止当前布局逻辑 + this.SuspendLayout(); + + // 恢复窗口状态 + this.WindowState = FormWindowState.Normal; + + // 强制重新布局 + this.ResumeLayout(true); // 参数true表示立即执行布局 + + // 调用刷新布局的方法 + this.PerformLayout(); + + // 处理WindowsForms消息队列中的所有挂起消息 + Application.DoEvents(); + + // 激活窗口(使其获得焦点) + this.Activate(); + } + + private void 隐藏窗口() + { + // 隐藏窗体(从任务栏消失) + this.Hide(); + + // 确保通知图标可见 + notifyIcon1.Visible = true; + + // 可选:显示气泡提示 + notifyIcon1.ShowBalloonTip(1000, "SubsCheck", "程序已最小化到系统托盘", ToolTipIcon.Info); + } + + private void notifyIcon1_MouseClick(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + // 检查窗口是否可见 + if (this.Visible) + { + // 如果窗口当前可见,则隐藏窗口 + 隐藏窗口(); + } + else + { + // 如果窗口当前不可见,则恢复窗口 + 恢复窗口(); + } + } + } + + // 创建专用方法用于异步检测GitHub代理 + private async Task DetectGitHubProxyAsync(List proxyItems) + { + bool proxyFound = false; + string detectedProxyURL = ""; + + Log("检测可用 GitHub 代理...", GetRichTextBoxAllLog()); + + // 遍历随机排序后的代理列表 + foreach (string proxyItem in proxyItems) + { + string checkUrl = $"https://{proxyItem}/https://raw.githubusercontent.com/sinspired/SubsCheck-Win-GUI/master/packages.config"; + Log($"正在测试 GitHub 代理: {proxyItem}", GetRichTextBoxAllLog()); + richTextBoxAllLog.Refresh(); + + try + { + using (HttpClient client = new HttpClient()) + { + client.Timeout = TimeSpan.FromSeconds(5); // 设置5秒超时 + // 添加User-Agent头,避免被拒绝访问 + client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); + + // 使用异步方式 + HttpResponseMessage response = await client.GetAsync(checkUrl); + if (response.IsSuccessStatusCode) + { + // 找到可用代理 + detectedProxyURL = $"https://{proxyItem}/"; + //richTextBoxAllLog.Clear(); 暂时禁用 + Log($"找到可用 GitHub 代理: {proxyItem}", GetRichTextBoxAllLog()); + proxyFound = true; + break; + } + } + } + catch (Exception ex) + { + // 记录错误但继续尝试下一个 + Log($"代理 {proxyItem} 测试失败: {ex.Message}", GetRichTextBoxAllLog(), true); + richTextBoxAllLog.Refresh(); + } + } + + // 如果没有找到可用的代理 + if (!proxyFound) + { + Log("未找到可用的 GitHub 代理,请在高级设置中手动设置。", GetRichTextBoxAllLog(), true); + MessageBox.Show("未找到可用的 GitHub 代理。\n\n请打开高级设置手动填入一个可用的Github Proxy,或检查您的网络连接。", + "代理检测失败", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + } + + return detectedProxyURL; + } + + private async void buttonUpdateKernel_Click(object sender, EventArgs e) + { + try + { + buttonUpdateKernel.Enabled = false; + buttonStartCheck.Enabled = false; + // 清空日志 + richTextBoxAllLog.Clear(); + Log("开始检查和下载最新版本的 subs-check.exe...", GetRichTextBoxAllLog()); + + // 获取当前应用程序目录 + string executablePath = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath); + string subsCheckPath = Path.Combine(executablePath, "subs-check.exe"); + + // 检查文件是否存在 + if (File.Exists(subsCheckPath)) + { + Log($"发现 subs-check.exe,正在删除...", GetRichTextBoxAllLog()); + + try + { + // 首先检查是否有进程正在运行 + Process[] processes = Process.GetProcessesByName("subs-check"); + if (processes.Length > 0) + { + Log("发现正在运行的 subs-check.exe 进程,正在强制结束...", GetRichTextBoxAllLog()); + foreach (Process process in processes) + { + try + { + process.Kill(); + process.WaitForExit(); + Log($"成功结束 subs-check.exe 进程(ID: {process.Id})", GetRichTextBoxAllLog()); + } + catch (Exception ex) + { + Log($"结束进程时出错(ID: {process.Id}): {ex.Message}", GetRichTextBoxAllLog(), true); + } + } + } + + // 删除文件 + File.Delete(subsCheckPath); + Log("成功删除旧版本 subs-check.exe", GetRichTextBoxAllLog()); + } + catch (Exception ex) + { + Log($"删除 subs-check.exe 时出错: {ex.Message}", GetRichTextBoxAllLog(), true); + MessageBox.Show($"无法删除现有的 subs-check.exe 文件: {ex.Message}\n\n请手动删除后重试,或者检查文件是否被其他程序占用。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + buttonUpdateKernel.Enabled = true; + return; + } + } + else + { + Log("未找到现有的 subs-check.exe 文件,将直接下载最新版本", GetRichTextBoxAllLog()); + } + + //// 检测可用的 GitHub 代理 + //githubProxyURL = await GetGithubProxyUrlAsync(); + //if (githubProxyURL == "") + //{ + // Log("未设置 GitHub 代理,将尝试直接下载", GetRichTextBoxAllLog(), true); + //} + + // 下载最新版本的 subs-check.exe + await DownloadSubsCheckEXE(); + + // 完成 + Log("内核更新完成!", GetRichTextBoxAllLog()); + } + catch (Exception ex) + { + Log($"操作过程中出错: {ex.Message}", GetRichTextBoxAllLog(), true); + MessageBox.Show($"处理过程中出现错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + buttonUpdateKernel.Enabled = true; + buttonStartCheck.Enabled = true; + } + } + + private decimal 订阅端口; + private decimal SubStore端口; + private void numericUpDownWebUIPort_ValueChanged(object sender, EventArgs e) + { + // 检查numericUpDown7是否存在并且与numericUpDown6的值相等 + if (numericUpDownWebUIPort.Value == numericUpDownSubStorePort.Value) + { + // 显示警告消息 + MessageBox.Show("订阅端口 和 Sub-Store端口 不能相同!", + "端口冲突", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + + // 将numericUpDown6的值恢复为更改前的值 + numericUpDownWebUIPort.Value = 订阅端口; + numericUpDownSubStorePort.Value = SubStore端口; + } + else + { + // 保存当前值作为下次比较的基准 + 订阅端口 = numericUpDownWebUIPort.Value; + SubStore端口 = numericUpDownSubStorePort.Value; + } + } + + + private async Task KillNodeProcessAsync() + { + try + { + Log("检查 node.exe 进程状态...", GetRichTextBoxAllLog()); + + // 获取当前应用程序的执行目录 + string executablePath = Path.GetDirectoryName(Application.ExecutablePath); + string nodeExePath_old = Path.Combine(executablePath, "output", "node.exe"); + string nodeExePath_new = Path.Combine(executablePath, "output", "sub-store", "node.exe"); + + // 初始化要检查的路径数组 + string[] nodeExePaths = new string[] { nodeExePath_old, nodeExePath_new }; + + // 获取所有 node.exe 进程 + Process[] nodeProcesses = Process.GetProcessesByName("node"); + + if (nodeProcesses.Length == 0) + { + Log("未发现运行中的 node.exe 进程", GetRichTextBoxAllLog()); + return; + } + + Log($"发现 {nodeProcesses.Length} 个 node.exe 进程,开始检查并终止匹配路径的进程...", GetRichTextBoxAllLog()); + + int terminatedCount = 0; + + foreach (Process process in nodeProcesses) + { + try + { + // 使用 WMI 获取进程路径,避免 32/64 位访问冲突 + string processPath = await Task.Run(() => GetProcessPathByWmi(process.Id)); + + // 检查是否匹配我们要查找的 node.exe 路径 + foreach (var nodeExePath in nodeExePaths) + { + if (!string.IsNullOrEmpty(processPath) && + processPath.Equals(nodeExePath, StringComparison.OrdinalIgnoreCase)) + { + Log($"发现匹配路径的 node.exe 进程(ID: {process.Id}),正在强制结束...", GetRichTextBoxAllLog()); + + await Task.Run(() => + { + process.Kill(); + process.WaitForExit(); + }); + + Log($"成功结束 node.exe 进程(ID: {process.Id})", GetRichTextBoxAllLog()); + terminatedCount++; + } + } + } + catch (Exception ex) + { + Log($"访问或终止进程(ID: {process.Id})时出错: {ex.Message}", GetRichTextBoxAllLog(), true); + } + } + + if (terminatedCount > 0) + { + Log($"总共终止了 {terminatedCount} 个匹配路径的 node.exe 进程", GetRichTextBoxAllLog()); + } + else + { + Log("未发现需要终止的 node.exe 进程", GetRichTextBoxAllLog()); + } + } + catch (Exception ex) + { + Log($"检查或终止 node.exe 进程时出错: {ex.Message}", GetRichTextBoxAllLog(), true); + } + } + + /// + /// 使用 WMI 获取指定进程的可执行文件路径 + /// 这样可以避免 32 位进程访问 64 位进程 MainModule 时的异常 + /// + private string GetProcessPathByWmi(int processId) + { + try + { + using (var searcher = new ManagementObjectSearcher( + $"SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = {processId}")) + { + foreach (ManagementObject obj in searcher.Get()) + { + return obj["ExecutablePath"]?.ToString(); + } + } + } + catch + { + // 忽略异常,返回 null + } + return null; + } + + private async void textBoxSubsUrls_DoubleClick(object sender, EventArgs e) + { + if (textBoxSubsUrls.Enabled) + { + // 创建EditURLs窗口的实例 + EditURLs editURLsForm = new EditURLs(); + + // 传递当前textBox1的内容到EditURLs窗口 + editURLsForm.UrlContent = textBoxSubsUrls.Text + "\n"; + editURLsForm.githubProxys = comboBoxGithubProxyUrl.Items; + editURLsForm.githubProxy = comboBoxGithubProxyUrl.Text; + editURLsForm.LogAction = (msg) => Log(msg, richTextBoxAllLog); // 传递主窗体的 Log 方法 + // 显示对话框并等待结果 + DialogResult result = editURLsForm.ShowDialog(); + + // 如果用户点击了"保存并关闭"按钮(返回DialogResult.OK) + if (result == DialogResult.OK) + { + // 获取编辑后的内容,按行拆分,过滤空行 + string[] lines = editURLsForm.UrlContent.Split( + new[] { "\r\n", "\r", "\n" }, + StringSplitOptions.RemoveEmptyEntries); + + // 去除每行首尾的空白字符 + for (int i = 0; i < lines.Length; i++) + { + lines[i] = lines[i].Trim(); + } + + // 再次过滤掉空行 + lines = lines.Where(line => !string.IsNullOrWhiteSpace(line)).ToArray(); + + // 将处理后的内容更新到Form1的textBox1 + textBoxSubsUrls.Text = string.Join(Environment.NewLine, lines); + await SaveConfig(false); + Log("已保存订阅地址列表。", GetRichTextBoxAllLog()); + } + } + + } + + private void checkBoxEnableRenameNode_CheckedChanged(object sender, EventArgs e) + { + if (checkBoxEnableRenameNode.Checked == false) checkBoxEnableMediaCheck.Checked = false; + } + + + private void checkBoxEnableMediaCheck_CheckedChanged(object sender, EventArgs e) + { + if (checkBoxEnableMediaCheck.Checked) + { + // 启用流媒体检测时,自动启用重命名节点 + checkBoxEnableRenameNode.Checked = true; + + if (NeedSelectPlatforms) + { + using (var selector = new PlatformSelectorForm(selectedPlatforms)) + { + if (selector.ShowDialog() == DialogResult.OK) + { + // 只更新变量,不直接写文件 + selectedPlatforms = selector.SelectedPlatforms; + if (selectedPlatforms.Count == 0) + { + checkBoxEnableMediaCheck.Checked = false; + } + } + } + } + else + { + NeedSelectPlatforms = true; + } + } + } + + + + private async void timerRestartSchedule_Tick(object sender, EventArgs e) + { + if (buttonStartCheck.Text == "⏹️ 停止") + { + buttonStartCheck.ForeColor = Color.Red; + Log("subs-check.exe 运行时满24小时,自动重启清理内存占用。", GetRichTextBoxAllLog()); + // 停止 subs-check.exe 程序 + StopSubsCheckProcess(); + // 结束 Sub-Store + await KillNodeProcessAsync(); + // 重新启动 subs-check.exe 程序 + StartSubsCheckProcess(); + numericUpDownConcurrent.Enabled = false; + numericUpDownInterval.Enabled = false; + numericUpDownTimeout.Enabled = false; + numericUpDownMinSpeed.Enabled = false; + numericUpDownDLTimehot.Enabled = false; + numericUpDownDownloadMb.Enabled = false; + numericUpDownTotalBandwidthLimit.Enabled = false; + numericUpDownWebUIPort.Enabled = false; + numericUpDownSubStorePort.Enabled = false; + comboBoxSaveMethod.Enabled = false; + textBoxSubsUrls.Enabled = false; + groupBoxAdvanceSettings.Enabled = false; + groupBoxGist.Enabled = false; + groupBoxR2.Enabled = false; + groupBoxWebdav.Enabled = false; + buttonStartCheck.Text = "⏹️ 停止"; + buttonStartCheck.ForeColor = Color.Red; + } + } + + private void buttonCheckUpdate_Click(object sender, EventArgs e) + { + // 创建 CheckUpdates 窗口实例 + CheckUpdates checkUpdatesForm = new CheckUpdates(); + + // 传递必要的数据和状态 + checkUpdatesForm.githubProxys = comboBoxGithubProxyUrl.Items; + checkUpdatesForm.githubProxy = comboBoxGithubProxyUrl.Text; + + checkUpdatesForm.当前subsCheck版本号 = 当前subsCheck版本号; + checkUpdatesForm.当前GUI版本号 = 当前GUI版本号; + checkUpdatesForm.最新GUI版本号 = 最新GUI版本号; + checkUpdatesForm.EnableHighConcurrent = checkBoxHighConcurrent.Checked; + checkUpdatesForm.EnableArch64 = checkBoxSwitchArch64.Checked; + + + + // 为 CheckUpdates 的 button2 添加点击事件处理程序 + checkUpdatesForm.FormClosed += (s, args) => + { + // 移除事件处理,避免内存泄漏 + if (checkUpdatesForm.DialogResult == DialogResult.OK) + { + // 如果返回OK结果,表示按钮被点击并需要更新内核 + buttonUpdateKernel_Click(this, EventArgs.Empty); + } + }; + + // 设置 button2 点击后关闭窗口并返回 DialogResult.OK + // 这需要在 CheckUpdates.cs 中修改 buttonUpdateKernel_Click 方法 + + // 显示 CheckUpdates 窗口 + checkUpdatesForm.ShowDialog(); + } + + private void checkBoxEnableSuccessLimit_CheckedChanged(object sender, EventArgs e) + { + if (checkBoxEnableSuccessLimit.Checked) numericUpDownSuccessLimit.Enabled = true; + else numericUpDownSuccessLimit.Enabled = false; + } + + private void checkBoxTotalBandwidthLimit_CheckedChanged(object sender, EventArgs e) + { + if (checkBoxTotalBandwidthLimit.Checked) numericUpDownTotalBandwidthLimit.Enabled = true; + else + { + numericUpDownTotalBandwidthLimit.Enabled = false; + numericUpDownTotalBandwidthLimit.Value = 0; + } + } + + private async void comboBoxOverwriteUrls_SelectedIndexChanged(object sender, EventArgs e) + { + if (comboBoxOverwriteUrls.Text.Contains("[内置]")) await comboBoxOverwriteUrlsSelection(true); + } + + private async Task comboBoxOverwriteUrlsSelection(bool 汇报Log = false) + { + // 确定文件名和下载URL + string fileName, downloadUrl, displayName; + string executablePath = Path.GetDirectoryName(Application.ExecutablePath); + + if (comboBoxOverwriteUrls.Text.Contains("[内置]布丁狗")) + { + fileName = "bdg.yaml"; + displayName = "[内置]布丁狗的订阅转换"; + downloadUrl = "https://raw.githubusercontent.com/cmliu/ACL4SSR/main/yaml/bdg.yaml"; + } + else + { + fileName = "ACL4SSR_Online_Full.yaml"; + displayName = "[内置]ACL4SSR_Online_Full"; + downloadUrl = "https://raw.githubusercontent.com/beck-8/override-hub/main/yaml/ACL4SSR_Online_Full.yaml"; + } + + string outputFolderPath = Path.Combine(executablePath, "output"); + Directory.CreateDirectory(outputFolderPath); + + string downloadFilePath = Path.Combine(outputFolderPath, fileName); + + if (File.Exists(downloadFilePath)) + { + if (汇报Log) Log($"{displayName} 覆写配置文件 已就绪。", GetRichTextBoxAllLog()); + return; + } + + Log($"{displayName} 覆写配置文件 未找到,正在下载...", GetRichTextBoxAllLog()); + progressBarAll.Value = 0; + progressBarAll.Visible = true; + + // 优先尝试 GitHub 带来,再尝试系统代理,最后使用无代理直连 + var (success, lastError) = await TryDownloadWithStrategiesAsync( + downloadUrl, + downloadFilePath, + new[] { DownloadStrategy.GithubProxy, DownloadStrategy.SystemProxy, DownloadStrategy.Direct }, + false); + + if (!success) + { + Log($"{displayName} 覆写配置文件 下载失败: {lastError}", GetRichTextBoxAllLog(), true); + } + else + { + //richTextBoxAllLog.Clear(); + Log($"{displayName} 覆写配置文件 下载成功", GetRichTextBoxAllLog()); + } + } + + /// + /// 下载策略 + /// + enum DownloadStrategy + { + GithubProxy, + SystemProxy, + Direct + } + + private async Task<(bool success, string lastError)> TryDownloadWithStrategiesAsync( + string downloadUrl, + string downloadFilePath, + IEnumerable strategyOrder, + bool noRepeat = true) + { + bool success = false; + string lastError = ""; + + // 策略映射表 + var strategyFuncs = new Dictionary>>() + { + [DownloadStrategy.GithubProxy] = async () => + { + string githubProxyURL = await GetGithubProxyUrlAsync(); + if (githubProxyURL == "") + { + return (false, null); // null 表示跳过 + } + return (false, githubProxyURL + downloadUrl); + }, + [DownloadStrategy.SystemProxy] = async () => + { + if (SysProxySetting != null) + await AutoCheckSysProxy(noRepeat); + return SysProxySetting.IsAvailable ? (true, downloadUrl) : (true, null); // null 表示跳过 + }, + [DownloadStrategy.Direct] = () => Task.FromResult((false, downloadUrl)) + }; + + var strategies = strategyOrder.ToList(); + int totalTries = strategies.Count; + + for (int i = 0; i < totalTries && !success; i++) + { + var strategy = strategies[i]; + try + { + var (useSysProxy, url) = await strategyFuncs[strategy](); + + if (url == null) + { + Log($"[尝试{i + 1}/{totalTries}] 策略 {strategy} 不可用,跳过检测。", GetRichTextBoxAllLog(), true); + continue; // 直接跳过 + } + + using (HttpClientHandler handler = new HttpClientHandler + { + UseProxy = useSysProxy, + Proxy = useSysProxy ? WebRequest.DefaultWebProxy : null + }) + using (HttpClient client = new HttpClient(handler)) + { + client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86)"); + client.Timeout = TimeSpan.FromSeconds(15); + + success = await DownloadFileWithProgressAsync(client, url, downloadFilePath); + } + } + catch (Exception ex) + { + lastError = ex.Message; + Log($"[尝试{i + 1}/{totalTries}] 使用 {strategy} 下载失败: {ex.Message}", GetRichTextBoxAllLog(), true); + } + } + + return (success, lastError); + } + + + /// + /// 下载文件并更新进度条 + /// + private async Task DownloadFileWithProgressAsync(HttpClient httpClient, string url, string filePath) + { + try + { + // 获取文件大小 + HttpResponseMessage headResponse = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, url)); + headResponse.EnsureSuccessStatusCode(); // 确保请求成功 + long totalBytes = headResponse.Content.Headers.ContentLength ?? 0; + + // 下载文件 + using (var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead)) + { + response.EnsureSuccessStatusCode(); // 确保请求成功 + + using (var contentStream = await response.Content.ReadAsStreamAsync()) + using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true)) + { + byte[] buffer = new byte[8192]; + long totalBytesRead = 0; + int bytesRead; + + while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + await fileStream.WriteAsync(buffer, 0, bytesRead); + totalBytesRead += bytesRead; + + // 更新进度条 + if (totalBytes > 0) + { + int progressPercentage = (int)((totalBytesRead * 100) / totalBytes); + progressPercentage = Math.Min(100, Math.Max(0, progressPercentage)); + progressBarAll.Enabled = true; + progressBarAll.Visible = true; + progressBarAll.Value = progressPercentage; + } + } + } + } + progressBarAll.Value = 0; + progressBarAll.Visible = false; + return true; // 下载成功 + } + catch + { + throw; // 重新抛出异常,让调用者处理 + } + } + + + private void numericUpDownConcurrent_ValueChanged(object sender, EventArgs e) + { + if (checkBoxHighConcurrent.Checked) + { + Log("已启用流水线高性能模式✨\n- 此值将作为计算测活-测速-流媒体检测各阶段并发数的基准.\n- 内核已启用衰减算法,可放心设置", GetRichTextBoxAllLog()); + } + else + { + if (numericUpDownConcurrent.Value > 128) + { + string warningMessage = + "⚠️ 高并发风险提醒 ⚠️\n\n" + + "您设置的并发数值过高,可能导致:\n\n" + + "• 运营商判定为异常流量并限制网络\n" + + "• 路由器性能压力过大\n" + + "• 测速结果不准确\n\n" + + "并发数设置建议:\n" + + "• 宽带峰值/50Mbps:一般对网络无影响\n" + + "• 宽带峰值/25Mbps:可能会影响同网络下载任务\n" + + "• 宽带峰值/10Mbps:可能会影响同网络下其他设备的上网体验\n"; + + Log(warningMessage, GetRichTextBoxAllLog()); + } + } + } + + private void checkBoxEnableWebUI_CheckedChanged(object sender, EventArgs e) + { + if (checkBoxEnableWebUI.Checked) textBoxWebUiAPIKey.Enabled = true; + else textBoxWebUiAPIKey.Enabled = false; + } + + private void buttonWebUi_Click(object sender, EventArgs e) + { + string 本地IP = GetLocalLANIP(); + try + { + // 构造URL + string url = $"http://{本地IP}:{numericUpDownWebUIPort.Value}/admin"; + + // 使用系统默认浏览器打开URL + System.Diagnostics.Process.Start(url); + + Log($"正在浏览器中打开 Subs-Check 配置管理: {url}", GetRichTextBoxAllLog()); + } + catch (Exception ex) + { + Log($"打开浏览器失败: {ex.Message}", GetRichTextBoxAllLog(), true); + MessageBox.Show($"打开浏览器时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// + /// 获取API状态信息并返回包含6个元素的字符串数组 + /// + /// + /// 包含6个元素的字符串数组: + /// [0] - 状态类型 ("checking"/"idle"/"error") + /// [1] - 状态图标类别 ("primary"/"success"/"danger") + /// [2] - 状态文本 ("正在检测中..."/"空闲"/"获取状态失败") + /// [3] - 节点总数 (proxyCount或"N/A") + /// [4] - 进度百分比 (progress或"N/A") + /// [5] - 可用节点数量 (available或"N/A") + /// + private async Task GetApiStatusAsync() + { + string[] resultArray = new string[6]; + string baseUrl = $"http://127.0.0.1:{numericUpDownWebUIPort.Value}"; + + try + { + using (HttpClient client = new HttpClient()) + { + // 设置基础URL + client.BaseAddress = new Uri(baseUrl); + + // 添加API密钥请求头 + client.DefaultRequestHeaders.Add("X-API-Key", WebUIapiKey); + + // 设置超时时间 + client.Timeout = TimeSpan.FromSeconds(5); + + // 发送请求 + HttpResponseMessage response = await client.GetAsync("/api/status"); + + // 检查响应状态 + if (response.IsSuccessStatusCode) + { + // 读取响应内容 + string content = await response.Content.ReadAsStringAsync(); + + // 解析JSON + JObject data = JObject.Parse(content); + + if (data["checking"] != null && data["checking"].Value()) + { + // 正在检测状态 + resultArray[0] = "checking"; + resultArray[1] = "primary"; + resultArray[2] = "正在检测中..."; + + // 提取节点数据 + resultArray[3] = data["proxyCount"]?.ToString() ?? "0"; + resultArray[4] = data["progress"]?.ToString() ?? "0"; + resultArray[5] = data["available"]?.ToString() ?? "0"; + } + else + { + // 空闲状态 + resultArray[0] = "idle"; + resultArray[1] = "success"; + resultArray[2] = "空闲"; + + // 空闲时相关数据设为N/A + resultArray[3] = "N/A"; + resultArray[4] = "N/A"; + resultArray[5] = "N/A"; + } + } + else + { + // 请求失败,例如未授权 + resultArray[0] = "error"; + resultArray[1] = "danger"; + resultArray[2] = $"API请求失败: {(int)response.StatusCode}"; + resultArray[3] = "N/A"; + resultArray[4] = "N/A"; + resultArray[5] = "N/A"; + } + } + } + catch (Exception ex) + { + // 发生异常 + resultArray[0] = "error"; + resultArray[1] = "danger"; + resultArray[2] = $"获取状态失败: {ex.Message}"; + resultArray[3] = "N/A"; + resultArray[4] = "N/A"; + resultArray[5] = "N/A"; + + // 可选:记录错误到日志 + // Log($"获取API状态失败: {ex.Message}", GetRichTextBoxAllLog(), true); + } + + return resultArray; + } + + /// + /// 获取内核当前版本和最新版本 + /// + private async Task GetKernelVersionAsync() + { + // 1. 类型转换检查 + if (numericUpDownWebUIPort.Value <= 0 || numericUpDownWebUIPort.Value > 65535) + return new string[] { null, null }; + + // 2. 【关键修改】将 decimal 强转为 int + int port = (int)numericUpDownWebUIPort.Value; + var url = $"http://127.0.0.1:{port}/admin/version"; + + try + { + using (var client = new HttpClient { Timeout = TimeSpan.FromSeconds(8) }) + { + client.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0"); + + // 3. 异步请求 + string json = await client.GetStringAsync(url).ConfigureAwait(false); + + // 4. 解析 JSON (确保已引用 Newtonsoft.Json) + var data = JObject.Parse(json); + + return new string[] + { + data["version"]?.Value()?.Trim(), + data["latest_version"]?.Value()?.Trim() + }; + } + } + catch + { + return new string[] { null, null }; + } + } + + private async void timerRefresh_Tick(object sender, EventArgs e) + { + //if (!button7.Enabled) button7.Enabled = true; + string[] subscheck状态 = await GetApiStatusAsync(); + + string 状态类型 = subscheck状态[0]; + string 状态图标类别 = subscheck状态[1]; + string 状态文本 = subscheck状态[2]; + string 节点总数 = subscheck状态[3]; + string 进度百分比 = subscheck状态[4]; + string 可用节点数量 = subscheck状态[5]; + + string[] kernelVersion = await GetKernelVersionAsync(); + string currentKernelVersion = kernelVersion[0]; + string latestKernelVersion = kernelVersion[1]; + + string defaultTitle = $"SubsCheck Win GUI {当前GUI版本号}"; + if (currentKernelVersion != null && latestKernelVersion != null) + { + if (TryParseVersion(latestKernelVersion, out Version vLatestK) && + TryParseVersion(currentKernelVersion, out Version vCurrentK) && + vLatestK > vCurrentK) + { + // 内核有新版 + string newTitle = defaultTitle; + newTitle += $" 发现新内核版本: {vLatestK} 请更新内核!"; + + // 检查更新按钮颜色 + buttonCheckUpdate.Enabled = true; + buttonCheckUpdate.ForeColor = Color.LimeGreen; + buttonCheckUpdate.Text = "有新版本"; + + 标题 = newTitle; + this.Text = 标题; // 更新窗口标题 + } + else + { + // 检查更新按钮颜色 + buttonCheckUpdate.ForeColor = Color.Black; + buttonCheckUpdate.Text = "检查更新"; + 标题 = defaultTitle; + this.Text = 标题; // 更新窗口标题 + } + } + else + { + // 检查更新按钮颜色 + buttonCheckUpdate.ForeColor = Color.Black; + buttonCheckUpdate.Text = "检查更新"; + 标题 = defaultTitle; + this.Text = 标题; // 更新窗口标题 + } + + + // 更新状态文本 + if (状态类型 == "checking") + { + buttonTriggerCheck.Text = buttonTriggerCheck.Text == "⌛获取订阅" ? buttonTriggerCheck.Text : "⌛获取订阅"; + labelLogNodeInfo.ForeColor = Color.Black; + nodeInfo = $"({进度百分比}/{节点总数}) 可用: {可用节点数量}"; + + int.TryParse(节点总数, out int nodeTotal); + int.TryParse(进度百分比, out int curr); + + if (nodeTotal > 0) + { + int 进度条百分比 = curr * 100 / nodeTotal; + if (进度条百分比 < 0) 进度条百分比 = 0; + if (进度条百分比 > 100) 进度条百分比 = 100; + + progressBarAll.Enabled = true; + progressBarAll.Visible = true; + progressBarAll.Value = 进度条百分比; + + if (!buttonTriggerCheck.Enabled) buttonTriggerCheck.Enabled = true; + buttonTriggerCheck.Text = "⏸️结束检测"; + buttonTriggerCheck.ForeColor = HexToRgbColor("#6633f4"); + labelLogNodeInfo.ForeColor = Color.Black; + } + + // 仅在文本变化时更新 NotifyIcon,避免频繁重绘 + string notifyText = "SubsCheck: " + nodeInfo; + if (notifyText.Length > 63) notifyText = notifyText.Substring(0, 60) + "..."; + if (_lastNotifyText != notifyText) + { + _lastNotifyText = notifyText; + notifyIcon1.Text = notifyText; + } + + if (textBoxSubsUrls.Enabled) textBoxSubsUrls.Enabled = false; // 仅在需要时改变 + } + else if (状态类型 == "idle") + { + if (buttonTriggerCheck.Text != "⏯️开始检测") buttonTriggerCheck.Text = "⏯️开始检测"; + buttonTriggerCheck.ForeColor = HexToRgbColor("#35bc00"); + //labelLogNodeInfo.Text = $"{nextCheckTime}"; + //labelLogNodeInfo.ForeColor = Color.Green; + + progressBarAll.Visible = false; + + + string idleNotify = "SubsCheck: 已就绪\n" + nextCheckTime; + if (_lastNotifyText != idleNotify) + { + nodeInfo = $"{nextCheckTime}"; + _lastNotifyText = idleNotify; + notifyIcon1.Text = idleNotify; + } + + if (!textBoxSubsUrls.Enabled) textBoxSubsUrls.Enabled = true; + } + else if (状态类型 == "error") + { + if (buttonTriggerCheck.Text != "🔀 未知") buttonTriggerCheck.Text = "🔀 未知"; + nodeInfo = 状态文本; + labelLogNodeInfo.Text = "实时日志"; + labelLogNodeInfo.ForeColor = Color.Black; + } + + // 仅在标题文字确实变化时更新,避免父容器反复重绘引起的闪烁 + string groupTitle = $"实时日志 {nodeInfo}"; + if (_lastLogLabelNodeInfoText != groupTitle) + { + _lastLogLabelNodeInfoText = groupTitle; + labelLogNodeInfo.Text = groupTitle; + } + } + + private async void buttonTriggerCheck_Click(object sender, EventArgs e) + { + buttonTriggerCheck.Enabled = false; + timerRefresh.Enabled = false; + + try + { + bool isSuccess; + + if (buttonTriggerCheck.Text == "⏯️开始检测") + { + buttonTriggerCheck.ForeColor = HexToRgbColor("#00BFFF"); + //labelLogNodeInfo.Text = $"启动检测"; + labelLogNodeInfo.ForeColor = Color.Black; + + await AutoCheckSysProxy(); + isSuccess = await SendApiRequestAsync("/api/trigger-check", "发送手动检查信号"); + if (isSuccess) + { + buttonTriggerCheck.Text = "⏸️结束检测"; + buttonTriggerCheck.Enabled = false; + labelLogNodeInfo.ForeColor = Color.Black; + textBoxSubsUrls.Enabled = false; // 检查开始后禁用订阅编辑 + } + } + else // "⏸️结束检测" + { + labelLogNodeInfo.ForeColor = Color.Black; + isSuccess = await SendApiRequestAsync("/api/force-close", "发送提前结束检测信号"); + } + + // 如果请求失败,更新按钮状态为未知 + if (!isSuccess) buttonTriggerCheck.Text = "🔀 未知"; + buttonTriggerCheck.ForeColor = Color.Gray; + labelLogNodeInfo.ForeColor = Color.Black; + } + finally + { + // 无论成功失败都重新启用定时器和按钮 + timerRefresh.Enabled = true; + timerRefresh.Start(); + //button7.Enabled = true; + } + } + + /// + /// 发送API请求到SubsCheck服务 + /// + /// API端点路径 + /// 操作名称(用于日志) + /// 操作是否成功 + private async Task SendApiRequestAsync(string endpoint, string operationName) + { + try + { + // 获取API基础地址和API密钥 + string baseUrl = $"http://127.0.0.1:{numericUpDownWebUIPort.Value}"; + + using (HttpClient client = new HttpClient()) + { + client.BaseAddress = new Uri(baseUrl); + client.DefaultRequestHeaders.Add("X-API-Key", WebUIapiKey); + client.Timeout = TimeSpan.FromSeconds(10); + + // 发送POST请求 + HttpResponseMessage response = await client.PostAsync(endpoint, new StringContent("")); + + // 检查响应状态 + if (response.IsSuccessStatusCode) + { + Log($"成功{operationName}", GetRichTextBoxAllLog()); + return true; + } + else + { + string errorContent = await response.Content.ReadAsStringAsync(); + Log($"{operationName}失败: HTTP {(int)response.StatusCode} {response.ReasonPhrase}\n{errorContent}", GetRichTextBoxAllLog(), true); + return false; + } + } + } + catch (Exception ex) + { + Log($"{operationName}时发生错误: {ex.Message}", GetRichTextBoxAllLog(), true); + return false; + } + } + + private void textBoxCron_Leave(object sender, EventArgs e) + { + if (IsValidCronExpression(textBoxCron.Text)) + { + // 计算并显示cron表达式的说明 + string cronDescription = GetCronExpressionDescription(textBoxCron.Text); + // 可以用工具提示或者消息框显示,这里使用消息框 + //MessageBox.Show(cronDescription, "Cron表达式说明", MessageBoxButtons.OK, MessageBoxIcon.Information); + Log($"Cron表达式说明 {cronDescription}", GetRichTextBoxAllLog()); + } + else + { + MessageBox.Show("请输入有效的cron表达式,例如:*/30 * * * *", "无效的cron表达式", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + textBoxCron.Focus(); + textBoxCron.Text = "0 */2 * * *"; // 恢复默认值 + } + } + + /// + /// 验证输入文本是否是合法的cron表达式 + /// + /// 如果是合法的cron表达式,则返回true;否则返回false + private bool IsValidCronExpression(string cron表达式) + { + string cronExpression = cron表达式.Trim(); + + // 如果是空字符串,则不是有效表达式 + if (string.IsNullOrWhiteSpace(cronExpression)) + return false; + + // 分割cron表达式为5个部分:分钟 小时 日期 月份 星期 + string[] parts = cronExpression.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + + // cron表达式必须有5个部分 + if (parts.Length != 5) + return false; + + try + { + // 验证每个部分 + // 分钟 (0-59) + if (!IsValidCronField(parts[0], 0, 59)) + return false; + + // 小时 (0-23) + if (!IsValidCronField(parts[1], 0, 23)) + return false; + + // 日期 (1-31) + if (!IsValidCronField(parts[2], 1, 31)) + return false; + + // 月份 (1-12) + if (!IsValidCronField(parts[3], 1, 12)) + return false; + + // 星期 (0-7,0和7都表示星期日) + if (!IsValidCronField(parts[4], 0, 7)) + return false; + + return true; + } + catch + { + return false; + } + } + + /// + /// 验证cron表达式中的单个字段是否合法 + /// + /// 字段值 + /// 最小允许值 + /// 最大允许值 + /// 如果字段合法,则返回true;否则返回false + private bool IsValidCronField(string field, int min, int max) + { + // 处理通配符 "*" + if (field == "*") + return true; + + // 处理步长 "*/n" + if (field.StartsWith("*/")) + { + string stepStr = field.Substring(2); + if (int.TryParse(stepStr, out int step)) + return step > 0 && step <= max; + return false; + } + + // 处理范围 "n-m" + if (field.Contains("-")) + { + string[] range = field.Split('-'); + if (range.Length != 2) + return false; + + if (int.TryParse(range[0], out int start) && int.TryParse(range[1], out int end)) + return start >= min && end <= max && start <= end; + return false; + } + + // 处理列表 "n,m,k" + if (field.Contains(",")) + { + string[] values = field.Split(','); + foreach (string item in values) + { + if (!int.TryParse(item, out int itemValue) || itemValue < min || itemValue > max) + return false; + } + return true; + } + + // 处理单个数字 + if (int.TryParse(field, out int fieldValue)) + return fieldValue >= min && fieldValue <= max; + + return false; + } + + /// + /// 获取cron表达式的友好文本说明 + /// + /// 要解析的cron表达式 + /// 返回cron表达式的执行时间说明 + private string GetCronExpressionDescription(string cron表达式) + { + try + { + string cronExpression = cron表达式.Trim(); + string[] parts = cronExpression.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + + if (parts.Length != 5) + return "无效的cron表达式"; + + // 分别解析每个部分 + string minuteDesc = ParseCronPart(parts[0], "分钟", 0, 59); + string hourDesc = ParseCronPart(parts[1], "小时", 0, 23); + string dayDesc = ParseCronPart(parts[2], "日", 1, 31); + string monthDesc = ParseCronPart(parts[3], "月", 1, 12); + string weekDesc = ParseCronPart(parts[4], "星期", 0, 7, true); + + // 组合最终说明 + string description = "执行时间: "; + + // 月份 + if (monthDesc != "每月") + description += monthDesc + "的"; + + // 星期与日期的关系 + if (parts[2] == "*" && parts[4] != "*") + description += weekDesc + "的"; + else if (parts[2] != "*" && parts[4] == "*") + description += dayDesc; + else if (parts[2] != "*" && parts[4] != "*") + description += $"{dayDesc}或{weekDesc}"; + else + description += "每天"; + + // 时间(小时:分钟) + description += $"{hourDesc}{minuteDesc}"; + + return description; + } + catch + { + return "无法解析cron表达式"; + } + } + + /// + /// 解析cron表达式的单个部分 + /// + private string ParseCronPart(string part, string unit, int min, int max, bool isWeekday = false) + { + // 处理星号,表示每个时间单位 + if (part == "*") + { + return $"每{unit}"; + } + + // 处理步长 */n + if (part.StartsWith("*/")) + { + int step = int.Parse(part.Substring(2)); + return $"每{step}{unit}"; + } + + // 处理范围 n-m + if (part.Contains("-")) + { + string[] range = part.Split('-'); + int start = int.Parse(range[0]); + int end = int.Parse(range[1]); + + if (isWeekday) + { + string[] weekdays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" }; + return $"从{weekdays[start]}到{weekdays[end]}"; + } + + return $"从{start}{unit}到{end}{unit}"; + } + + // 处理列表 n,m,k + if (part.Contains(",")) + { + string[] values = part.Split(','); + if (isWeekday) + { + string[] weekdays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" }; + return string.Join("、", values.Select(v => weekdays[int.Parse(v)])); + } + return $"{string.Join("、", values)}{unit}"; + } + + // 处理单个数字 + int value = int.Parse(part); + if (isWeekday) + { + string[] weekdays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" }; + return weekdays[value]; + } + return $"{value}{unit}"; + } + + private void 切换cron表达式(object sender, EventArgs e) + { + if (textBoxCron.Visible) + { + labelCron.Visible = false; + textBoxCron.Visible = false; + labelInterval.Visible = true; + numericUpDownInterval.Visible = true; + Log("下次检查时间间隔 使用分钟倒计时", GetRichTextBoxAllLog()); + } + else + { + labelCron.Location = new Point(labelCron.Location.X, labelInterval.Location.Y); + textBoxCron.Location = new Point(textBoxCron.Location.X, numericUpDownInterval.Location.Y); + labelCron.Visible = true; + textBoxCron.Visible = true; + labelInterval.Visible = false; + numericUpDownInterval.Visible = false; + Log("下次检查时间间隔 使用cron表达式", GetRichTextBoxAllLog()); + } + } + + /// + /// 获取计算机名的MD5哈希值 + /// + /// 返回计算机名的MD5哈希字符串(32位小写) + private string GetComputerNameMD5() + { + try + { + // 获取计算机名 + string computerName = System.Environment.MachineName; + + // 引入必要的命名空间 + using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create()) + { + // 将计算机名转换为字节数组 + byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(computerName); + + // 计算MD5哈希值 + byte[] hashBytes = md5.ComputeHash(inputBytes); + + // 将字节数组转换为十六进制字符串 + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < hashBytes.Length; i++) + { + sb.Append(hashBytes[i].ToString("x2")); + } + + return sb.ToString(); + } + } + catch (Exception ex) + { + Log($"计算计算机名MD5时出错: {ex.Message}", GetRichTextBoxAllLog(), true); + return "CMLiussss"; + } + } + + private static about aboutWindow = null; + private void linkLabelAbout_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + // 检查窗口是否已经打开 + if (aboutWindow != null && !aboutWindow.IsDisposed) + { + // 窗口已经存在,激活它 + aboutWindow.Activate(); + return; + } + + // 需要创建新窗口 + this.BeginInvoke(new Action(() => + { + // 创建about窗口实例 + aboutWindow = new about(); + + // 传递版本号信息 + aboutWindow.GuiVersion = 当前GUI版本号; + aboutWindow.CoreVersion = 当前subsCheck版本号; + + // 添加窗口关闭时的处理,清除静态引用 + aboutWindow.FormClosed += (s, args) => aboutWindow = null; + + // 非模态显示窗口 + aboutWindow.Show(this); + + // 设置TopMost确保窗口显示在最前面 + aboutWindow.TopMost = true; + })); + } + + private void buttonMoreSettings_Click(object sender, EventArgs e) + { + try + { + // 创建MoreYAML窗口实例 + MoreYAML moreYamlWindow = new MoreYAML(); + + // 显示为模态对话框,这会阻塞主线程直到窗口关闭 + DialogResult result = moreYamlWindow.ShowDialog(this); + + // 如果需要,可以处理对话框的返回结果 + if (result == DialogResult.OK) + { + // 用户点击了"确定"或某种完成操作的按钮 + Log("补充参数配置已成功保存到 more.yaml 文件!设置已应用", GetRichTextBoxAllLog()); + } + } + catch (Exception ex) + { + Log($"打开MoreYAML窗口时出错: {ex.Message}", GetRichTextBoxAllLog(), true); + MessageBox.Show($"打开MoreYAML窗口时出错: {ex.Message}", "错误", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private async void checkBoxStartup_CheckedChanged(object sender, EventArgs e) + { + checkBoxStartup.Enabled = false; + try + { + // 获取当前应用程序的可执行文件路径 + string appPath = Application.ExecutablePath; + // 获取应用程序名称(不包含扩展名) + string appName = Path.GetFileNameWithoutExtension(appPath); + // 获取启动文件夹的路径 + string startupFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup); + // 快捷方式文件的完整路径 + string shortcutPath = Path.Combine(startupFolderPath, $"{appName}.lnk"); + + if (checkBoxStartup.Checked) + { + // 检查启动文件夹中是否已存在该快捷方式 + if (File.Exists(shortcutPath)) + { + Log("开机启动项已存在,无需重复创建", GetRichTextBoxAllLog()); + } + else + { + // 创建快捷方式 + CreateShortcut(appPath, shortcutPath, "-auto"); + Log("已成功创建开机启动项,下次电脑启动时将自动运行程序", GetRichTextBoxAllLog()); + } + } + else + { + // 删除启动项 + if (File.Exists(shortcutPath)) + { + File.Delete(shortcutPath); + Log("已移除开机启动项,下次开机将不会自动启动", GetRichTextBoxAllLog()); + } + } + } + catch (Exception ex) + { + Log($"设置开机启动项时出错: {ex.Message}", GetRichTextBoxAllLog(), true); + MessageBox.Show($"设置开机启动项失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + + // 恢复CheckBox状态,避免UI状态与实际状态不一致 + checkBoxStartup.CheckedChanged -= checkBoxStartup_CheckedChanged; + checkBoxStartup.Checked = !checkBoxStartup.Checked; + checkBoxStartup.CheckedChanged += checkBoxStartup_CheckedChanged; + } + checkBoxStartup.Enabled = true; + await SaveConfig(false); + } + + /// + /// 创建指向指定路径应用程序的快捷方式 + /// + /// 目标应用程序的完整路径 + /// 要创建的快捷方式的完整路径 + /// 可选的启动参数 + private void CreateShortcut(string targetPath, string shortcutPath, string arguments = "") + { + // 使用COM接口创建快捷方式 + Type t = Type.GetTypeFromProgID("WScript.Shell"); + dynamic shell = Activator.CreateInstance(t); + var shortcut = shell.CreateShortcut(shortcutPath); + + shortcut.TargetPath = targetPath; + if (!string.IsNullOrEmpty(arguments)) + shortcut.Arguments = arguments; // 设置启动参数 + + shortcut.WorkingDirectory = Path.GetDirectoryName(targetPath); + shortcut.WindowStyle = 7; // 最小化启动: 7, 正常启动: 1, 最大化启动: 3 + shortcut.Description = "SubsCheck Win GUI自启动快捷方式"; + shortcut.IconLocation = targetPath + ",0"; // 使用应用程序自身的图标 + + // 保存快捷方式 + shortcut.Save(); + + // 释放COM对象 + System.Runtime.InteropServices.Marshal.FinalReleaseComObject(shortcut); + System.Runtime.InteropServices.Marshal.FinalReleaseComObject(shell); + } + + /// + /// 检查启动参数中是否包含指定的参数 + /// + /// 要检查的参数名称,例如"-autoup" + /// 如果存在指定参数,则返回true;否则返回false + private bool CheckCommandLineParameter(string parameterName) + { + // 获取命令行参数数组 + string[] args = Environment.GetCommandLineArgs(); + + // 遍历所有参数,检查是否有匹配的参数 + foreach (string arg in args) + { + // 不区分大小写比较 + if (string.Equals(arg, parameterName, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } + + private void richTextBoxAllLog_DoubleClick(object sender, EventArgs e) + { + // 检查是否有日志内容 + if (richTextBoxAllLog.TextLength > 0) + { + // 显示确认对话框,询问用户是否要清空日志 + DialogResult result = MessageBox.Show( + "是否要清空当前日志?", + "清空日志确认", + MessageBoxButtons.YesNo, + MessageBoxIcon.Question, + MessageBoxDefaultButton.Button2); // 默认选择"否"按钮 + + if (result == DialogResult.Yes) + { + // 清空richTextBox1内容 + richTextBoxAllLog.Clear(); + // 记录一条清空日志的操作信息 + Log("日志已清空", GetRichTextBoxAllLog()); + } + } + } + + private void numericUpDownMinSpeed_ValueChanged(object sender, EventArgs e) + { + if (numericUpDownMinSpeed.Value > 4096) + { + string warningMessage = + "⚠️ 测速下限设置提醒 ⚠️\n\n" + + "您设置的测速下限值过高,可能导致:\n\n" + + "• 可用节点数量显著减少\n" + + "• 部分低速但稳定的节点被过滤\n" + + "测速下限设置建议:\n" + + "• 日常浏览:512-1024 KB/s\n" + + "• 视频观看:1024-2048 KB/s\n" + + "• 大文件下载:根据实际需求设置\n"; + + Log(warningMessage, GetRichTextBoxAllLog()); + } + } + + private void numericUpDownTimeout_ValueChanged(object sender, EventArgs e) + { + if (numericUpDownTimeout.Value < 5000) + { + string warningMessage = + "⚠️ 超时时间设置提醒 ⚠️\n\n" + + "该超时时间并非延迟时间,除非您的网络极其优秀,否则超时时间过低会导致无可用节点。\n\n" + + "• 超时时间是真连接测试的最大等待时间\n" + + "• 设置过低会导致大部分节点连接失败\n" + + "• 推荐设置不低于5000ms\n\n" + + "建议超时时间设置:\n" + + "• 普通网络环境:5000± ms\n" + + "• 极好网络环境:3000± ms\n"; + + Log(warningMessage, GetRichTextBoxAllLog()); + } + + } + + // 获取 githubproxy 地址(带 30 分钟间隔限制) + public async Task GetGithubProxyUrlAsync() + { + const string AUTO = "自动选择"; + if (comboBoxGithubProxyUrl == null) return githubProxyURL; + + // 如果上次运行时间距今不足 1 分钟,直接返回上次结果(若有) + if (_lastGithubProxyUrl != null && (DateTime.Now - _lastGetGithubProxyRunTime).TotalMinutes < 1) + { + Log($"GitHub Proxy:{_lastGithubProxyUrl}", GetRichTextBoxAllLog()); + return _lastGithubProxyUrl; + } + + // 如已指定 githubproxy,直接返回结果 + var text = (comboBoxGithubProxyUrl.Text ?? ""); + if (text != AUTO && text.Length > 0) + { + _lastGithubProxyUrl = $"https://{text}/"; + _lastGetGithubProxyRunTime = DateTime.Now; + return _lastGithubProxyUrl; + } + + // 随机候选列表 + var candidates = comboBoxGithubProxyUrl.Items + .OfType() + .Where(s => !string.IsNullOrWhiteSpace(s) && s != AUTO) + .OrderBy(_ => Guid.NewGuid()) + .ToList(); + + if (!candidates.Any()) + { + _lastGithubProxyUrl = githubProxyURL; + _lastGetGithubProxyRunTime = DateTime.Now; + return _lastGithubProxyUrl; + } + + try + { + var detected = await DetectGitHubProxyAsync(candidates); + _lastGithubProxyUrl = string.IsNullOrWhiteSpace(detected) ? githubProxyURL : detected; + } + catch + { + _lastGithubProxyUrl = githubProxyURL; + } + + // 更新最后运行时间 + _lastGetGithubProxyRunTime = DateTime.Now; + return _lastGithubProxyUrl; + } + + // 切换高性能内核和原版内核设置项 + private void SwitchHighConcurrentLayout(bool EnableHighConcurrent) + { + bool collapsed = buttonAdvanceSettings.Text == "高级设置∨"; + groupBoxPipeConcurrent.Visible = EnableHighConcurrent; + groupBoxEnhance.Visible = EnableHighConcurrent; + if (collapsed) + { + if (EnableHighConcurrent) + { + if (!_originalLocationSaved) + { + _originalLocationSaved = true; + _pipeOriginalLocation = groupBoxPipeConcurrent.Location; + _enhanceOriginalLocation = groupBoxEnhance.Location; + } + groupBoxPipeConcurrent.Location = groupBoxAdvanceSettings.Location; + groupBoxEnhance.Location = new Point(groupBoxEnhance.Location.X, groupBoxAdvanceSettings.Location.Y); + } + } + else + { + if (EnableHighConcurrent) + { + groupBoxPipeConcurrent.Location = _pipeOriginalLocation; + groupBoxEnhance.Location = _enhanceOriginalLocation; + groupBoxGist.Location = new Point(groupBoxGist.Location.X, _pipeOriginalLocation.Y + groupBoxPipeConcurrent.Height); + groupBoxR2.Location = groupBoxGist.Location; + groupBoxWebdav.Location = groupBoxGist.Location; + } + else + { + groupBoxGist.Location = _pipeOriginalLocation; groupBoxR2.Location = groupBoxGist.Location; groupBoxWebdav.Location = groupBoxGist.Location; + } + } + } + + // 状态变更检查、统一获取 proxy、更新并保存 + private async void checkBoxHighConcurrent_CheckedChanged(object sender, EventArgs e) + { + bool EnableHighConcurrent = checkBoxHighConcurrent.Checked; + + + // 先进行控件切换 + SwitchHighConcurrentLayout(EnableHighConcurrent); + + // 判断是否需要下载新内核 + string want = EnableHighConcurrent ? "高性能内核" : "原版内核"; + if (currentKernel != want) + { + if (EnableHighConcurrent && !checkBoxSwitchArch64.Checked) + { + DialogResult result = MessageBox.Show( + $"建议使用现代的 x64 架构,以实现更高性能\n\n" + + "· 点击【确定】将使用 x64 内核\n\n" + + "· 点击【取消】将使用 i386 内核\n\n", + "内核架构选择", + MessageBoxButtons.OKCancel, + MessageBoxIcon.Information); + + if (result == DialogResult.OK) + { + //临时禁用事件 + checkBoxSwitchArch64.CheckedChanged -= checkBoxSwitchArch64_CheckedChanged; + checkBoxSwitchArch64.Checked = true; + // 恢复事件 + checkBoxSwitchArch64.CheckedChanged += checkBoxSwitchArch64_CheckedChanged; + } + else + { + //临时禁用事件 + checkBoxSwitchArch64.CheckedChanged -= checkBoxSwitchArch64_CheckedChanged; + checkBoxSwitchArch64.Checked = false; + // 恢复事件 + checkBoxSwitchArch64.CheckedChanged += checkBoxSwitchArch64_CheckedChanged; + } + if (checkBoxHighConcurrent.Checked) + { + if (!comboBoxSubscriptionType.Items.Contains("Singbox1.11")) + { + comboBoxSubscriptionType.Items.AddRange(new object[] { "Singbox1.11" }); + } + if (!comboBoxSubscriptionType.Items.Contains("Singbox1.12")) + { + comboBoxSubscriptionType.Items.AddRange(new object[] { "Singbox1.12" }); + } + } + } + + checkBoxSwitchArch64.Enabled = false; + checkBoxHighConcurrent.Enabled = false; + buttonCheckUpdate.Enabled = false; + + Log(EnableHighConcurrent ? "切换为 高性能 内核,可单独设置测活-测速-媒体检测各阶段并发数,大幅提高性能" : "切换为 原版 内核", GetRichTextBoxAllLog()); + await DownloadSubsCheckEXE();// 若要后台并行改为 _ = DownloadSubsCheckEXE(); + currentKernel = want; + if (!EnableHighConcurrent) + { + ReadConfig(); + if (comboBoxSpeedtestUrl.Text == "random") comboBoxSpeedtestUrl.Text = "不测速"; + comboBoxSpeedtestUrl.Items.Remove("random"); + numericUpDownPipeAlive.Value = 0; numericUpDownPipeSpeed.Value = 0; numericUpDownPipeMedia.Value = 0; + } + else if (!comboBoxSpeedtestUrl.Items.Contains("random")) + { + ReadConfig(); + // 只有当列表里至少有1个元素时,才能插在第2个位置(索引1) + // 否则只能插在第1个位置(索引0) + int insertIndex = comboBoxSpeedtestUrl.Items.Count > 0 ? 1 : 0; + + comboBoxSpeedtestUrl.Items.Insert(insertIndex, "random"); + } + + checkBoxSwitchArch64.Enabled = true; + checkBoxHighConcurrent.Enabled = true; + buttonCheckUpdate.Enabled = true; + } + Log(EnableHighConcurrent ? "已切换高性能内核,测活-测速-媒体检测 流水线式并发运行。" : "使用原版内核。", GetRichTextBoxAllLog()); + } + + // x64 按钮切换事件 + private async void checkBoxSwitchArch64_CheckedChanged(object sender, EventArgs e) + { + bool useX64 = checkBoxSwitchArch64.Checked; + string want = useX64 ? "x86_64" : "i386"; + if (currentArch != want) + { + checkBoxSwitchArch64.Enabled = false; + checkBoxHighConcurrent.Enabled = false; + buttonCheckUpdate.Enabled = false; + githubProxyURL = await GetGithubProxyUrlAsync(); + Log(useX64 ? "切换为 x64 内核,内存占用更高,但CPU占用可能较低" : "切换为 i386 内核,内存占用更低,但CPU占用可能更高", GetRichTextBoxAllLog()); + await DownloadSubsCheckEXE(); + currentArch = want; + checkBoxSwitchArch64.Enabled = true; + checkBoxHighConcurrent.Enabled = true; + buttonCheckUpdate.Enabled = true; + } + Log(useX64 ? "使用64位内核,如内存占用较高,可在[高级设置]切换" : "使用32位内核,如CPU占用较高,可在[高级设置]切换", GetRichTextBoxAllLog()); + } + + // 计算一个推荐并发参数 + private (int alive, int speed, int media) CalcSimpleConcurrent() + { + int baseVal = (int)numericUpDownConcurrent.Value; + int aliveConc = baseVal * 4; + int speedConc = baseVal; + int mediaConc = baseVal * 2; + + // alive 最小为 200 + aliveConc = Math.Max(aliveConc, 200); + // media 最大为 100 + mediaConc = Math.Min(mediaConc, 100); + + // 处理总带宽限制与最小速度 + double totalBw = (double)numericUpDownTotalBandwidthLimit.Value; // 用户设定的总带宽(单位与逻辑由你定义) + double minSpeed = (double)numericUpDownMinSpeed.Value; // 单个连接的最小速度 + + if (totalBw <= 0) + { + // 无带宽限制时,给 speed 一个保守上限 + speedConc = Math.Min(speedConc, 32); + } + else if (minSpeed > 0) + { + // 估算在 minSpeed 情况下能支持的最大并发数(向下取整) + int estimated = (int)Math.Floor(totalBw / minSpeed); + estimated = Math.Max(1, estimated); // 至少为 1 + speedConc = Math.Max(speedConc, estimated); // 把 speedConc 限制到估算值 + } + else + { + speedConc = Math.Min(speedConc, 32); + } + + speedConc = Math.Max(1, speedConc); + + return (aliveConc, speedConc, mediaConc); + } + + // 类成员:唯一的程序化修改旗标(防重入/防循环) + private bool _inProgrammaticChange = false; + + // 安全写入 NumericUpDown(避免超出 Min/Max 导致异常) + private void SetNumericUpDownValueSafe(NumericUpDown ctrl, int value) + { + if (ctrl == null) return; + int min = (int)ctrl.Minimum; + int max = (int)ctrl.Maximum; + if (value < min) value = min; + if (value > max) value = max; + if ((decimal)value != ctrl.Value) // 只有值变化时才赋值,减少不必要触发 + ctrl.Value = (decimal)value; + } + + // switchPipeAutoConcurrent:根据当前 numericUpDown 的值决定是否为自动模式 + private void switchPipeAutoConcurrent() + { + // 计算是否进入自动模式(任一为 0 则自动) + bool anyZero = (int)numericUpDownPipeAlive.Value <= 0 + || (int)numericUpDownPipeSpeed.Value <= 0 + || (int)numericUpDownPipeMedia.Value <= 0; + + // 在程序化修改期间抑制事件响应 + _inProgrammaticChange = true; + try + { + if (anyZero) + { + // 进入自适应:禁用控件并把值统一为 0(只在必要时写入) + numericUpDownPipeAlive.Enabled = false; + numericUpDownPipeSpeed.Enabled = false; + numericUpDownPipeMedia.Enabled = false; + + SetNumericUpDownValueSafe(numericUpDownPipeAlive, 0); + SetNumericUpDownValueSafe(numericUpDownPipeSpeed, 0); + SetNumericUpDownValueSafe(numericUpDownPipeMedia, 0); + + if (!checkBoxPipeAuto.Checked) checkBoxPipeAuto.Checked = true; // 程序化设置 + } + else + { + // 退出自适应:启用控件,但不要覆盖用户已经设置的数值 + numericUpDownPipeAlive.Enabled = true; + numericUpDownPipeSpeed.Enabled = true; + numericUpDownPipeMedia.Enabled = true; + + if (checkBoxPipeAuto.Checked) checkBoxPipeAuto.Checked = false; // 程序化设置 + } + } + finally + { + _inProgrammaticChange = false; + } + } + + // checkBoxPipeAuto_CheckedChanged:用户点击或程序化修改都会走这里,使用 guard 来区分 + private void checkBoxPipeAuto_CheckedChanged(object sender, EventArgs e) + { + if (_inProgrammaticChange) return; // 如果是程序化触发,直接忽略 + + _inProgrammaticChange = true; + try + { + if (checkBoxPipeAuto.Checked) + { + // 切到自适应:禁用并清零 + numericUpDownPipeAlive.Enabled = false; + numericUpDownPipeSpeed.Enabled = false; + numericUpDownPipeMedia.Enabled = false; + + SetNumericUpDownValueSafe(numericUpDownPipeAlive, 0); + SetNumericUpDownValueSafe(numericUpDownPipeSpeed, 0); + SetNumericUpDownValueSafe(numericUpDownPipeMedia, 0); + Log("并发检测模式: 自适应分段流水线(内核自带衰减算法)", GetRichTextBoxAllLog()); + } + else + { + // 退出自适应:启用并使用推荐值(推荐值从函数获得) + numericUpDownPipeAlive.Enabled = true; + numericUpDownPipeSpeed.Enabled = true; + numericUpDownPipeMedia.Enabled = true; + + var (alive, speed, media) = CalcSimpleConcurrent(); + + SetNumericUpDownValueSafe(numericUpDownPipeAlive, alive); + SetNumericUpDownValueSafe(numericUpDownPipeSpeed, speed); + SetNumericUpDownValueSafe(numericUpDownPipeMedia, media); + Log($"默认并发参数: 测活: {alive}, 测速: {speed}, 流媒体: {media} [根据并发数 {numericUpDownConcurrent.Value} 计算]", GetRichTextBoxAllLog()); + } + } + finally + { + _inProgrammaticChange = false; + } + } + + // ValueChanged 事件:只有用户交互时才触发 switchPipeAutoConcurrent(guard 防止程序化导致二次处理) + private void numericUpDownPipeAlive_ValueChanged(object sender, EventArgs e) + { + if (_inProgrammaticChange) return; + switchPipeAutoConcurrent(); + Log($"已设置流水线并发检测参数: Alive: {numericUpDownPipeAlive.Value}, Speed: {numericUpDownPipeSpeed.Value}, Media: {numericUpDownPipeMedia.Value}", GetRichTextBoxAllLog()); + } + private void numericUpDownPipeSpeed_ValueChanged(object sender, EventArgs e) + { + if (_inProgrammaticChange) return; + switchPipeAutoConcurrent(); + Log($"已设置流水线并发检测参数: Alive: {numericUpDownPipeAlive.Value}, Speed: {numericUpDownPipeSpeed.Value}, Media: {numericUpDownPipeMedia.Value}", GetRichTextBoxAllLog()); + } + private void numericUpDownPipeMedia_ValueChanged(object sender, EventArgs e) + { + if (_inProgrammaticChange) return; + switchPipeAutoConcurrent(); + Log($"已设置流水线并发检测参数: Alive: {numericUpDownPipeAlive.Value}, Speed: {numericUpDownPipeSpeed.Value}, Media: {numericUpDownPipeMedia.Value}", GetRichTextBoxAllLog()); + } + + private void NumericUpDownTotalBandwidthLimit_ValueChanged(object sender, EventArgs e) + { + float calcBandWidth = (float)numericUpDownTotalBandwidthLimit.Value * 8; + if (calcBandWidth > 0) + { + Log($"当前设置下载速度限制带宽 {calcBandWidth} 兆。", GetRichTextBoxAllLog()); + toolTip1.SetToolTip(numericUpDownTotalBandwidthLimit, $"总下载速度限制(MB/s):\n建议设置为 <=带宽/8, \n比如你是 200 兆的宽带, 支持的最大下载速度 200/8 = 25 MB/s, 可以设置为 20。\n\n当前设置下载速度对应带宽 {calcBandWidth}"); + } + } + public static Color HexToRgbColor(String hexColour) + { + Color colour = new Color(); + try + { + colour = ColorTranslator.FromHtml(hexColour); + } + catch (System.Exception) + { + return Color.Empty; + } + return colour; + } + + private void checkBoxSubsStats_CheckedChanged(object sender, EventArgs e) + { + if (checkBoxHighConcurrent.Checked) + { + Log("开启订阅链接统计,将在 ./output/stats 下生成订阅数量、可用节点数量、成功率等文件", GetRichTextBoxAllLog()); + } + else + { + Log("当前内核不支持订阅链接统计,请切换 Subs-Check性能版!", GetRichTextBoxAllLog()); + MessageBox.Show( + this, // 如果你在 Form 类里可以直接传 this,让弹窗属于当前窗口 + "当前内核不支持订阅链接统计功能!\r\n\r\n请勾选 “高性能模式”\n切换到 【Subs-Check 性能版】", + "温馨提示", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + } + + private void checkBoxIspCheck_CheckedChanged(object sender, EventArgs e) + { + if (checkBoxHighConcurrent.Checked) + { + Log("开启 isp 类型检测,检测是否原生/广播IP,以及住宅、机房等类型;将为节点添加类似 [原生|机房] 的标签", GetRichTextBoxAllLog()); + } + else + { + Log("当前内核不支持 isp 类型检测,请切换 Subs-Check性能版!", GetRichTextBoxAllLog()); + MessageBox.Show( + this, // 如果你在 Form 类里可以直接传 this,让弹窗属于当前窗口 + "当前内核不支持 isp 类型检测!\r\n\r\n请勾选 “高性能模式”\n切换到 【Subs-Check 性能版】", + "温馨提示", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + } + } +} \ No newline at end of file diff --git a/Form1.resx b/MainGui.resx similarity index 99% rename from Form1.resx rename to MainGui.resx index c367db0..c3120ae 100644 --- a/Form1.resx +++ b/MainGui.resx @@ -3465,26 +3465,32 @@ 8ZBk6w0zXkiXmGb795jdrR8Fo/3iU+0ts/2GUBRFUXKE/wXQTDn6LYQ2BAAAAABJRU5ErkJggg== - - 136, 17 + + 354, 19 - + https://raw.githubusercontent.com/snakem982/proxypool/main/source/clash-meta.yaml https://raw.githubusercontent.com/snakem982/proxypool/main/source/clash-meta-2.yaml https://raw.githubusercontent.com/go4sharing/sub/main/sub.yaml https://raw.githubusercontent.com/SoliSpirit/v2ray-configs/main/all_configs.txt - - 228, 17 + + 196, 21 + + + 822, 19 - 320, 17 + 196, 21 + + + 533, 19 - - 423, 17 + + 1149, 19 - - 515, 17 + + 72 diff --git a/MoreYAML.Designer.cs b/MoreYAML.Designer.cs index d749cb4..31314d6 100644 --- a/MoreYAML.Designer.cs +++ b/MoreYAML.Designer.cs @@ -31,9 +31,9 @@ private void InitializeComponent() System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MoreYAML)); this.button1 = new System.Windows.Forms.Button(); this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.button2 = new System.Windows.Forms.Button(); - this.textBox1 = new System.Windows.Forms.TextBox(); this.linkLabel1 = new System.Windows.Forms.LinkLabel(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button2 = new System.Windows.Forms.Button(); this.button3 = new System.Windows.Forms.Button(); this.groupBox1.SuspendLayout(); this.SuspendLayout(); @@ -41,9 +41,10 @@ private void InitializeComponent() // button1 // this.button1.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.button1.Location = new System.Drawing.Point(12, 415); + this.button1.Location = new System.Drawing.Point(22, 726); + this.button1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.Size = new System.Drawing.Size(138, 40); this.button1.TabIndex = 0; this.button1.Text = "保存"; this.button1.UseVisualStyleBackColor = true; @@ -53,52 +54,58 @@ private void InitializeComponent() // this.groupBox1.Controls.Add(this.linkLabel1); this.groupBox1.Controls.Add(this.textBox1); - this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Location = new System.Drawing.Point(22, 21); + this.groupBox1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(776, 397); + this.groupBox1.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.groupBox1.Size = new System.Drawing.Size(1423, 695); this.groupBox1.TabIndex = 1; this.groupBox1.TabStop = false; this.groupBox1.Text = "YAML"; // - // button2 + // linkLabel1 // - this.button2.Location = new System.Drawing.Point(713, 415); - this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(75, 23); - this.button2.TabIndex = 2; - this.button2.Text = "返回"; - this.button2.UseVisualStyleBackColor = true; - this.button2.Click += new System.EventHandler(this.button2_Click); + this.linkLabel1.AutoSize = true; + this.linkLabel1.Location = new System.Drawing.Point(1072, 0); + this.linkLabel1.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.linkLabel1.Name = "linkLabel1"; + this.linkLabel1.Size = new System.Drawing.Size(342, 21); + this.linkLabel1.TabIndex = 1; + this.linkLabel1.TabStop = true; + this.linkLabel1.Text = "更多请参考 config.yaml 参数文档"; + this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); // // textBox1 // this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.textBox1.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.textBox1.Location = new System.Drawing.Point(6, 13); + this.textBox1.Location = new System.Drawing.Point(11, 23); + this.textBox1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.textBox1.Multiline = true; this.textBox1.Name = "textBox1"; this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.textBox1.Size = new System.Drawing.Size(764, 378); + this.textBox1.Size = new System.Drawing.Size(1399, 660); this.textBox1.TabIndex = 0; this.textBox1.Text = resources.GetString("textBox1.Text"); this.textBox1.UseWaitCursor = true; // - // linkLabel1 + // button2 // - this.linkLabel1.AutoSize = true; - this.linkLabel1.Location = new System.Drawing.Point(585, 0); - this.linkLabel1.Name = "linkLabel1"; - this.linkLabel1.Size = new System.Drawing.Size(191, 12); - this.linkLabel1.TabIndex = 1; - this.linkLabel1.TabStop = true; - this.linkLabel1.Text = "更多请参考 config.yaml 参数文档"; - this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); + this.button2.Location = new System.Drawing.Point(1307, 726); + this.button2.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(138, 40); + this.button2.TabIndex = 2; + this.button2.Text = "返回"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); // // button3 // - this.button3.Location = new System.Drawing.Point(93, 415); + this.button3.Location = new System.Drawing.Point(170, 726); + this.button3.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.button3.Name = "button3"; - this.button3.Size = new System.Drawing.Size(75, 23); + this.button3.Size = new System.Drawing.Size(138, 40); this.button3.TabIndex = 3; this.button3.Text = "重置"; this.button3.UseVisualStyleBackColor = true; @@ -106,13 +113,14 @@ private void InitializeComponent() // // MoreYAML // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 21F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(800, 450); + this.ClientSize = new System.Drawing.Size(1467, 788); this.Controls.Add(this.button3); this.Controls.Add(this.button2); this.Controls.Add(this.groupBox1); this.Controls.Add(this.button1); + this.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5); this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "MoreYAML"; diff --git a/MoreYAML.cs b/MoreYAML.cs index bfbc919..aa6270b 100644 --- a/MoreYAML.cs +++ b/MoreYAML.cs @@ -78,7 +78,7 @@ private void button2_Click(object sender, EventArgs e) private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - Process.Start("https://github.com/beck-8/subs-check/blob/master/config/config.example.yaml"); + Process.Start("https://github.com/sinspired/subs-check/blob/master/config/config.example.yaml"); } private void button1_Click(object sender, EventArgs e) diff --git a/MoreYAML.resx b/MoreYAML.resx index 017016f..305f1c0 100644 --- a/MoreYAML.resx +++ b/MoreYAML.resx @@ -121,17 +121,67 @@ # 节点前缀,依赖rename-node为true才生效 node-prefix: "" +# 配置通知渠道,将自动发送检测结果通知,新版本通知 +# 复制 https://vercel.com/new/clone?repository-url=https://github.com/sinspired/apprise_vercel 到浏览器 +# 按提示部署,建议为 Vercel 项目设置自定义域名(国内访问 Vercel 可能受限)。 # 填写搭建的apprise API server 地址 -# https://notify.xxxx.us.kg/notify -apprise-api-server: "" -# 填写通知目标 +# 示例:https://notify.xxxx.us.kg/notify +# 内置apprise服务,不想搭建仅需填写 recipient-url 即可 +apprise-api-server: "https://apprised.netlib.re/notify" +# 通知渠道 # 支持100+ 个通知渠道,详细格式请参照 https://github.com/caronc/apprise -recipient-url: - # telegram格式:tgram://<bot_token>/<chat_id> +# 格式参考: +# telegram格式:tgram://{bot_token}/{chat_id} +# 钉钉格式:dingtalk://{Secret}@{ApiKey} +# QQ邮箱:mailto://{QQ号}:{邮箱授权码}@qq.com +# 邮箱授权码:设置-账号-POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务-开通-继续获取授权码 +recipient-url: # - tgram://xxxxxx/-1002149239223 - # 钉钉格式:dingtalk://<secret>@<dd_token>/<chat_id> - # - dingtalk://xxxxxx@xxxxxxx/123123 + # - dingtalk://xxxxxx@xxxxxxx + # - mailto://xxxxx:xxxxxx@qq.com + # 自定义通知标题 -notify-title: "🔔 节点状态更新" +notify-title: "🔔 节点状态更新" + +# 符合条件节点数量的占比,低于此值会将订阅链接打印出来,用于排查质量差的订阅 +success-rate: 0 + +# 是否开启新版本更新 +# 支持启动时检查更新及定时更新任务,无缝升级新版本 +# 支持apprise API通知渠道 +# true: 自动更新; false: 不更新 +update: false +# 定时检查更新 +# "0 0,9,21 * * *" 默认每天0点,9点,21点检查更新 +cron-check-update: "0 0,9,21 * * *" +# 使用预发布版本 +prerelease: false + +# 只测试指定协议的节点 +node-type: + # - ss + # - vmess + # - vless + +# singbox规则配置 +# json文件为分流规则 +# js脚本用来根据规则对节点进行处理 +# singbox每个版本规则不兼容,须根据客户端版本选择合适的规则 +# singbox latest 版本配置 +singbox-latest: + version: 1.12 + json: + - https://raw.githubusercontent.com/sinspired/sub-store-template/main/1.12.x/sing-box.json + js: + - https://raw.githubusercontent.com/sinspired/sub-store-template/main/1.12.x/sing-box.js + +# singbox 1.11 版本配置(iOS 兼容) +singbox-old: + version: 1.11 + json: + - https://raw.githubusercontent.com/sinspired/sub-store-template/main/1.11.x/sing-box.json + js: + - https://raw.githubusercontent.com/sinspired/sub-store-template/main/1.11.x/sing-box.js + \ No newline at end of file diff --git a/PlatformSelectorForm.Designer.cs b/PlatformSelectorForm.Designer.cs new file mode 100644 index 0000000..89e2df3 --- /dev/null +++ b/PlatformSelectorForm.Designer.cs @@ -0,0 +1,39 @@ +namespace subs_check.win.gui +{ + partial class PlatformSelectorForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Text = "PlatformSelectorForm"; + } + + #endregion + } +} \ No newline at end of file diff --git a/PlatformSelectorForm.cs b/PlatformSelectorForm.cs new file mode 100644 index 0000000..3209264 --- /dev/null +++ b/PlatformSelectorForm.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace subs_check.win.gui +{ + public partial class PlatformSelectorForm : Form + { + // 公开属性获取结果 + public List SelectedPlatforms { get; private set; } = new List(); + + // 保存 CheckBox 的引用,避免在 Click 事件中遍历 UI 树 + private List _checkBoxList = new List(); + + private readonly string[] _platforms = + { + "iprisk", "openai", "gemini", "youtube", + "tiktok", "netflix", "disney", "x" + }; + + public PlatformSelectorForm(List preSelected) + { + InitializeComponent(); + InitializeCustomComponents(preSelected); + } + + private void InitializeCustomComponents(List preSelected) + { + // 1. 窗体基础设置 + this.Text = "媒体解锁检测"; + this.Font = new Font("宋体", 9F); + this.FormBorderStyle = FormBorderStyle.FixedDialog; + this.StartPosition = FormStartPosition.CenterParent; + this.MinimizeBox = false; + this.MaximizeBox = false; + this.AutoSize = true; + this.AutoSizeMode = AutoSizeMode.GrowAndShrink; + this.BackColor = Color.WhiteSmoke; + + // 2. 主布局:两列 (左侧列表 | 右侧按钮) + var mainLayout = new TableLayoutPanel + { + Dock = DockStyle.Fill, + AutoSize = true, + AutoSizeMode = AutoSizeMode.GrowAndShrink, + ColumnCount = 2, + RowCount = 1, + Padding = new Padding(0) // 移除外边距,由内部控件控制 + }; + + // 左列自适应,右列固定宽度 + mainLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + mainLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 140F)); + + // ==================== 左侧:复选框列表区域 ==================== + var listPanel = new FlowLayoutPanel + { + FlowDirection = FlowDirection.TopDown, + AutoSize = true, + AutoSizeMode = AutoSizeMode.GrowAndShrink, + WrapContents = false, + Padding = new Padding(20, 20, 20, 20), + Dock = DockStyle.Fill + }; + + _checkBoxList.Clear(); + foreach (var platform in _platforms) + { + var cb = new CheckBox + { + Text = GetFriendlyName(platform), + // 虽然窗体设置了宋体,但为了可读性,建议内容控件稍微大一点 + Font = new Font("宋体", 9F), + AutoSize = true, + Margin = new Padding(5, 8, 5, 8), // 增加垂直间距 + Cursor = Cursors.Hand, + Checked = preSelected != null && preSelected.Contains(platform), + Tag = platform + }; + + _checkBoxList.Add(cb); + listPanel.Controls.Add(cb); + } + + // ==================== 右侧:按钮区域 ==================== + var actionPanel = new FlowLayoutPanel + { + FlowDirection = FlowDirection.TopDown, + AutoSize = true, + Dock = DockStyle.Fill, + Padding = new Padding(15, 25, 15, 20), // 上边距加大,与列表对齐 + BackColor = Color.FromArgb(245, 246, 247) // 浅灰背景,区分功能区 + }; + + var btnOk = CreateStyledButton("确定", DialogResult.OK, Color.FromArgb(0, 120, 215), Color.White); + btnOk.Click += BtnOk_Click; + + var btnCancel = CreateStyledButton("取消", DialogResult.Cancel, Color.White, Color.Black); + // 取消按钮加个边框色 + btnCancel.FlatAppearance.BorderColor = Color.FromArgb(200, 200, 200); + btnCancel.FlatAppearance.BorderSize = 1; + + actionPanel.Controls.Add(btnOk); + actionPanel.Controls.Add(btnCancel); + + // ==================== 组装 ==================== + mainLayout.Controls.Add(listPanel, 0, 0); + mainLayout.Controls.Add(actionPanel, 1, 0); + + this.Controls.Add(mainLayout); + + this.AcceptButton = btnOk; + this.CancelButton = btnCancel; + } + + /// + /// 创建统一风格的按钮 + /// + private Button CreateStyledButton(string text, DialogResult result, Color bg, Color fg) + { + var btn = new Button + { + Text = text, + DialogResult = result, + Size = new Size(100, 36), + Font = new Font("宋体", 10F), // 按钮也使用宋体 + FlatStyle = FlatStyle.Flat, + BackColor = bg, + ForeColor = fg, + Margin = new Padding(0, 0, 0, 15), // 按钮之间的间距 + Cursor = Cursors.Hand + }; + + btn.FlatAppearance.BorderSize = 0; + + // 简单的悬停效果逻辑 + if (bg != Color.White) + { + // 深色按钮变亮 + btn.FlatAppearance.MouseOverBackColor = ControlPaint.Light(bg); + } + else + { + // 浅色按钮变灰 + btn.FlatAppearance.MouseOverBackColor = Color.FromArgb(230, 230, 230); + } + + return btn; + } + + private string GetFriendlyName(string key) + { + switch (key) + { + case "x": return "X(Twitter)"; + case "iprisk": return "IPRisk(风控)"; + case "openai": return "OpenAI/ChatGPT"; + case "gemini": return "Gemini"; + case "youtube": return "YouTube"; + case "tiktok": return "TikTok"; + case "netflix": return "Netflix"; + case "disney": return "Disney+"; + default: return char.ToUpper(key[0]) + key.Substring(1); + } + } + + private void BtnOk_Click(object sender, EventArgs e) + { + // 优化:直接遍历已保存的 List,无需在控件树中查找 + SelectedPlatforms = _checkBoxList + .Where(cb => cb.Checked) + .Select(cb => cb.Tag.ToString()) + .ToList(); + } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs index 66ef724..2db094a 100644 --- a/Program.cs +++ b/Program.cs @@ -1,13 +1,16 @@ using System; +using System.Reflection; using System.Threading; using System.Windows.Forms; +using subs_check.win.gui.Properties; + namespace subs_check.win.gui { static class Program { // 定义一个全局唯一的标识符,使用项目名称作为互斥体的名称 - private static string appMutexName = "cmliu/SubsCheck-Win-GUI"; + private static string appMutexName = "sinspired/SubsCheck-Win-GUI"; private static Mutex mutex; /// @@ -27,11 +30,21 @@ static void Main() return; } + ////启动时检查更新 + ////AutoUpdater.Mandatory = true; + ////AutoUpdater.UpdateMode = Mode.Forced; + //AutoUpdater.SetOwner(MainGui.ActiveForm); + //AutoUpdater.Icon = Resources.download; + //AutoUpdater.ShowRemindLaterButton = false; + //AutoUpdater.ReportErrors = true; + //AutoUpdater.HttpUserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"; + //AutoUpdater.Start("https://gh.39.al/raw.githubusercontent.com/sinspired/subsCheck-Win-GUI/master/update.xml"); + try { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new Form1()); + Application.Run(new MainGui()); } finally { diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index d7dcef7..60aed19 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -6,9 +6,9 @@ // 控制。更改这些特性值可修改 // 与程序集关联的信息。 [assembly: AssemblyTitle("SubsCheck Win GUI")] -[assembly: AssemblyDescription("")] +[assembly: AssemblyDescription("SubsCheck 为 Windows 用户设计的 GUI 程序界面。修复字体模糊,兼容新旧dpi设备,新增高性能、64位内核,新增历次检测可用节点,添加新内核特性。")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("TG:CMLiussss")] +[assembly: AssemblyCompany("TG:sinspired")] [assembly: AssemblyProduct("SubsCheck Win GUI")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] @@ -29,5 +29,5 @@ // 生成号 // 修订号 // -[assembly: AssemblyVersion("2.0.1.7")] -[assembly: AssemblyFileVersion("2.0.1.7")] +[assembly: AssemblyVersion("2.7.0.1")] +[assembly: AssemblyFileVersion("2.7.0.1")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index f6989a7..a8b8733 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace subs_check.win.gui.Properties { // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen // (以 /str 作为命令选项),或重新生成 VS 项目。 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -60,6 +60,16 @@ internal Resources() { } } + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap download { + get { + object obj = ResourceManager.GetObject("download", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// 查找 System.Byte[] 类型的本地化资源。 /// diff --git a/Properties/Resources.resx b/Properties/Resources.resx index 071264b..2864a5c 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -118,6 +118,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\download.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\going.ico;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs index a96d2cb..7c0da05 100644 --- a/Properties/Settings.Designer.cs +++ b/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace subs_check.win.gui.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.13.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/Properties/Settings.settings b/Properties/Settings.settings deleted file mode 100644 index 3964565..0000000 --- a/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Proxy.cs b/Proxy.cs new file mode 100644 index 0000000..7a8b654 --- /dev/null +++ b/Proxy.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace subs_check.win.gui +{ + internal class Proxy + { + // 常见代理端口 + private static readonly List CommonProxies = new List + { + "http://127.0.0.1:7890", + "http://127.0.0.1:7891", + "http://127.0.0.1:1080", + "http://127.0.0.1:8080", + "http://127.0.0.1:10808", + "http://127.0.0.1:10809", + "http://127.0.0.1:3067", + "http://127.0.0.1:2080", + "http://127.0.0.1:1194", + "http://127.0.0.1:1082", + "http://127.0.0.1:12334", + "http://127.0.0.1:12335" + }; + + public class SysProxyResult + { + public bool IsAvailable { get; set; } + public string Address { get; set; } + } + + /// + /// 检测系统代理是否可用,并设置环境变量 + /// + public static Task GetSysProxyAsync(string configProxy) + { + return FindAvailableSysProxyAsync(configProxy, CommonProxies) + .ContinueWith(t => + { + string proxy = t.Result; + if (!string.IsNullOrEmpty(proxy)) + { + Environment.SetEnvironmentVariable("HTTP_PROXY", proxy); + Environment.SetEnvironmentVariable("HTTPS_PROXY", proxy); + + Console.WriteLine("系统代理可用: " + proxy); + return new SysProxyResult + { + IsAvailable = true, + Address = proxy + }; + } + + Console.WriteLine("未找到可用代理,将不设置代理"); + return new SysProxyResult + { + IsAvailable = false, + Address = string.Empty + }; + }); + } + + + /// + /// 检测代理是否可用(要求 Google 204 和 GitHub Raw 都成功) + /// + private static async Task IsSysProxyAvailableAsync(string proxy, CancellationToken token = default) + { + try + { + var proxyUri = new Uri(proxy); + var handler = new HttpClientHandler + { + Proxy = new WebProxy(proxyUri), + UseProxy = true + }; + + using (var client = new HttpClient(handler)) + { + client.Timeout = TimeSpan.FromSeconds(10); + client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win32; x86) AppleWebKit/537.36 (KHTML, like Gecko) cmliu/SubsCheck-Win-GUI"); + + var testTasks = new[] + { + client.GetAsync("https://www.google.com/generate_204", token), + client.GetAsync("https://raw.githubusercontent.com/github/gitignore/main/Go.gitignore", token) + }; + + var responses = await Task.WhenAll(testTasks); + return responses[0].StatusCode == HttpStatusCode.NoContent && responses[1].StatusCode == HttpStatusCode.OK; + } + } + catch (OperationCanceledException) + { + return false; // Expected cancellation + } + catch + { + return false; + } + } + + /// + /// 优先检测配置文件中的代理,不可用则并发检测常见端口 + /// + private static async Task FindAvailableSysProxyAsync(string configProxy, List candidates) + { + // Step 1: 优先检测配置文件中的代理 + if (!string.IsNullOrEmpty(configProxy) && await IsSysProxyAvailableAsync(configProxy)) + { + return configProxy; + } + + // Step 2: 并发检测候选代理 + var cts = new CancellationTokenSource(); + var runningTasks = new List>(); + foreach (var p in candidates) + { + runningTasks.Add(Task.Run(async () => + { + if (await IsSysProxyAvailableAsync(p, cts.Token)) + { + return p; + } + return null; + }, cts.Token)); + } + + while (runningTasks.Any()) + { + var completedTask = await Task.WhenAny(runningTasks); + runningTasks.Remove(completedTask); + + try + { + string result = await completedTask; + if (!string.IsNullOrEmpty(result)) + { + cts.Cancel(); // 找到一个就取消其他任务 + return result; // 立即返回结果 + } + } + catch (OperationCanceledException) + { + // This task was canceled because another one finished first. Ignore. + } + // Other exceptions can be logged if needed. + } + + return string.Empty; + } + } +} diff --git a/README.md b/README.md index 2b72784..c7eed2c 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,102 @@ # 🚀 SubsCheck-Win-GUI -首先声明,这款软件并非我原创开发。Subs-Check是由 [bestruirui](https://github.com/bestruirui/BestSub) 原创、由 [beck-8](https://github.com/beck-8/subs-check) 进行二次开发,而我所编写的 GUI 仅是在这两位开发者的原始版本基础上进行的 **二次开发**。 -- **视频教程:[永久免费0门槛!小白也有无限高速代理节点!](https://youtu.be/sS9Tuf1PCyc)** -- **数字签名:[关于项目报毒说明](https://www.youtube.com/watch?v=4906t5zygAE&t=123s)** -- **Telegram交流群:[@CMLiussss](https://t.me/CMLiussss)** +[![GUI 版本](https://img.shields.io/github/v/release/sinspired/SubsCheck-Win-GUI?logo=github)](https://github.com/sinspired/SubsCheck-Win-GUI/releases) +[![内核](https://img.shields.io/github/v/release/sinspired/subs-check?display_name=release&style=social&logo=github&label=subs-check性能版)](https://github.com/sinspired/subs-check/releases/latest) -# ⚠️ 免责声明 -本项目仅供学习、研究与安全测试使用,请勿用于任何非法活动。使用前请确保您已了解并遵守所在地的法律法规。 +本项目基于CM的大量工作,已提PR。支持高并发内核切换,支持64位;支持高dpi显示器,解决界面字体模糊等问题;添加下载大小限制,降低节点被测死的概率;新内核支持一键管理 `sub-store` -### 📋 使用条款 +## ✨ 新增功能 + +- [x] 🖥️ 修复界面模糊,支持 **高 DPI 缩放** +- [x] ⚡ 自动检测并设置系统代理 +- [x] 🔄 增加 **自适应高并发内核切换**,减少无谓的生命浪费 +- [x] 🧩 增加 **i386/64 位内核切换** +- [x] 🔧 新增 **性能版内核参数** +- [x] 🚀 优化 **自动更新机制** +- [x] 🌐 现代化 WebUI,优化移动端访问体验 +- [x] 🛠️ 一键管理 `**sub-store**` +- [x] 📊 统计订阅链接总数、可用节点数量、成功率 +- [x] ✅ 添加媒体解锁平台 多选窗口 +- [x] 📡 支持检测 isp 类型,原生/广播IP,住宅/机房等,节点添加类似 `[原生|住宅]` 的标签 +- [ ] 🌙 支持深色模式 + +> [!TIP] +> 功能更新频繁,请务必查看最新的 [配置文件示例](https://github.com/sinspired/subs-check/blob/main/config/config.example.yaml) 以获取最新功能支持。 + +- **内核地址**:[subs-check 性能版,支持 Docker 部署](https://github.com/sinspired/subs-check) +- **Telegram 交流群**:[@Sinspired](https://t.me/subs_check_pro) -- **教育与研究用途**:本软件仅可用于网络技术和编程领域的学习、研究和安全测试。 -- **禁止非法使用**:严禁将 **SubsCheck-Win-GUI** 用于任何非法活动或违反使用者所在地区法律法规的行为。 -- **使用时限**:基于学习和研究目的,建议用户在完成研究或学习后,或在安装后的**24小时内,删除本软件及所有相关文件。** -- **免责声明**:**SubsCheck-Win-GUI** 的创建者和贡献者不对因使用或滥用本软件而导致的任何损害或法律问题负责。 -- **用户责任**:**用户对使用本软件的方式以及由此产生的任何后果完全负责。** -- **无技术支持**:本软件的创建者不提供任何技术支持或使用协助。 -- **知情同意**:使用 **SubsCheck-Win-GUI** 即表示您已阅读并理解本免责声明,并同意受其条款的约束。 +## ⚠️ 免责声明 + +本项目仅供 **学习、研究与安全测试** 使用,请勿用于任何非法活动。使用前请确保您已了解并遵守所在地的法律法规。 + +### 📋 使用条款 -> [!WARNING] -> **请记住**:本软件的主要目的是促进学习、研究和安全测试。作者不支持或认可任何其他用途。使用者应当在合法和负责任的前提下使用本工具。 +- **教育与研究用途**:仅限学习、研究和安全测试 +- **禁止非法使用**:严禁用于违法行为 +- **使用时限**:建议安装后 **24 小时内删除** +- **免责声明**:作者不对任何损害或法律问题负责 +- **用户责任**:用户需自行承担使用后果 +- **无技术支持**:作者不提供技术支持 +- **知情同意**:使用即表示同意上述条款 ---- +> [!WARNING] +> 本软件的主要目的是促进学习、研究和安全测试。请在合法和负责任的前提下使用。 ![GUI](./gui.png) ## 🖥️ 系统要求 -- **操作系统**: Windows 10/11 (32位/64位) -- **.NET 框架**: .NET Framework 4.7.2 或更高版本 -> [!CAUTION] -> **系统兼容性说明**: 本软件不支持Windows 7及更早版本。因为核心组件subs-check使用Go语言编译,而Go 1.19及以后版本已正式放弃对Windows 7的支持。 +- **操作系统**: Windows 10/11 (32位/64位) +- **.NET 框架**: .NET Framework 4.7.2 或更高版本 -## 💾 测速结果 保存方法 +> [!CAUTION] +> 不支持 Windows 7 及更早版本(Go 1.19+ 已放弃支持)。 -- **本地**:将结果保存到本地,默认保存到可执行文件目录下的 output 文件夹 -- **r2**:将结果保存到 cloudflare r2 存储桶 [配置方法](https://github.com/beck-8/subs-check/blob/master/doc/r2.md) -- **gist**:将结果保存到 github gist [配置方法](https://github.com/beck-8/subs-check/blob/master/doc/gist.md) -- **webdav**:将结果保存到 webdav 服务器 [配置方法](https://github.com/beck-8/subs-check/blob/master/doc/webdav.md) +## 💾 测速结果保存方式 -## 📦 关于 Github Proxy -- **Github Proxy**:本项目使用了 `Github Proxy` 来加速 GUI 必要内容的加载。 -> [!Tip] -> 你也可以通过 https://github.com/cmliu/CF-Workers-GitHub 项目来搭建自己专属的 **Github Proxy**。 +- **本地**:保存到 `output` 文件夹 +- **r2**:保存到 Cloudflare R2 存储桶 → [配置方法](https://github.com/sinspired/subs-check/blob/master/doc/r2.md) +- **gist**:保存到 GitHub Gist → [配置方法](https://github.com/sinspired/subs-check/blob/master/doc/gist.md) +- **webdav**:保存到 WebDAV 服务器 → [配置方法](https://github.com/sinspired/subs-check/blob/master/doc/webdav.md) + +## 📦 Github Proxy + +本项目使用 `Github Proxy` 加速 GUI 必要内容加载。 +你也可以通过 [CF-Workers-GitHub](https://github.com/cmliu/CF-Workers-GitHub) 搭建自己的代理。 + +## 📁 文件结构 -## 📁 GUI 文件结构 ```shell -subs-check.win.gui.exe # GUI本体 -subs-check.exe # subs-check x86_32位 内核本体  -subs-check_Windows_i386.zip # subs-check x86_32位 内核压缩包  -Upgrade.exe # 升级程序 -Upgrade.ini # 升级配置文件 -config - ├─ config.yaml # subs-check 配置文件  - └─ more.yaml # 补充YAML参数配置文件  -output - ├─ ACL4SSR_Online_Full.yaml # ACL4SSR_Online_Full.yaml 覆写配置文件 - ├─ all.yaml # yaml格式 测试结果 - ├─ base64.txt # base64格式 测试结果 - ├─ bdg.yaml # 布丁狗的订阅转换.yaml 覆写配置文件 - ├─ mihomo.yaml # clash订阅文件 带分流规则 - ├─ node.exe # sub-store 服务 - ├─ root.json # sub-store 配置文件 - ├─ sub-store.bundle.js # sub-store js文件 - ├─ sub-store.json # sub-store json文件 +subs-check.win.gui.exe # GUI 主程序 +subs-check.exe # subs-check x86_32 内核 +subs-check_Windows_i386.zip # subs-check 内核压缩包 +config/ + ├─ config.yaml # 主配置文件 + └─ more.yaml # 补充参数配置文件 +output/ + ├─ all.yaml # 上次成功测试结果 + ├─ history.yaml # 历次成功测试结果 + ├─ base64.txt # Base64 格式结果 + ├─ mihomo.yaml # Clash 订阅文件 + ├─ sub-store.* # sub-store 相关文件 └─ sub-store.log # sub-store 日志 -Newtonsoft.Json.dll # 验证版本信息组件 -Newtonsoft.Json.xml # 验证版本信息组件 -YamlDotNet.dll # yaml读写组件 -YamlDotNet.xml # yaml读写组件 +AutoUpdater.NET.dll # 自动更新依赖 +Microsoft.Web.WebView2.* # WebView2 组件 +Newtonsoft.Json.dll # JSON 组件 +YamlDotNet.dll # YAML 组件 ``` ## ⭐ Star 星星走起 + [![Stargazers over time](https://starchart.cc/cmliu/SubsCheck-Win-GUI.svg?variant=adaptive)](https://starchart.cc/cmliu/SubsCheck-Win-GUI) ## 💻 已适配客户端 - - [v2rayN](https://github.com/2dust/v2rayN) - - [mihomo-party](https://github.com/mihomo-party-org/mihomo-party),[FlClash](https://github.com/chen08209/FlClash),[clash-verge-rev](https://github.com/clash-verge-rev/clash-verge-rev),[Clash Nyanpasu](https://github.com/keiko233/clash-nyanpasu) -# 🙏 致谢 +- [v2rayN](https://github.com/2dust/v2rayN) +- [singbox](https://github.com/SagerNet/sing-box) +- [mihomo-party](https://github.com/mihomo-party-org/mihomo-party),[FlClash](https://github.com/chen08209/FlClash),[clash-verge-rev](https://github.com/clash-verge-rev/clash-verge-rev),[Clash Nyanpasu](https://github.com/keiko233/clash-nyanpasu) + +## 🙏 致谢 + [beck-8](https://github.com/beck-8/subs-check)、[bestruirui](https://github.com/bestruirui/BestSub)、[Sub-Store](https://github.com/sub-store-org/Sub-Store)、GPT diff --git a/Resources/download.png b/Resources/download.png new file mode 100644 index 0000000..6f43f2d Binary files /dev/null and b/Resources/download.png differ diff --git a/about.Designer.cs b/about.Designer.cs index 35b0307..d9ad29c 100644 --- a/about.Designer.cs +++ b/about.Designer.cs @@ -118,7 +118,7 @@ private void InitializeComponent() this.linkLabel1.Size = new System.Drawing.Size(257, 12); this.linkLabel1.TabIndex = 6; this.linkLabel1.TabStop = true; - this.linkLabel1.Text = "https://github.com/cmliu/SubsCheck-Win-GUI"; + this.linkLabel1.Text = "https://github.com/sinspired/SubsCheck-Win-GUI"; this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); // // label6 @@ -374,7 +374,7 @@ private void InitializeComponent() this.ShowIcon = false; this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "关于 SubsCheck Win GUI"; + this.Text = "关于 "; this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); this.groupBox2.ResumeLayout(false); diff --git a/about.cs b/about.cs index c728cb4..d9acc00 100644 --- a/about.cs +++ b/about.cs @@ -37,12 +37,12 @@ private void linkLabel4_LinkClicked(object sender, LinkLabelLinkClickedEventArgs private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - Process.Start("https://github.com/cmliu/SubsCheck-Win-GUI"); + Process.Start("https://github.com/sinspired/SubsCheck-Win-GUI"); } private void linkLabel5_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - Process.Start("https://github.com/beck-8/subs-check"); + Process.Start("https://github.com/sinspired/subs-check"); } private void linkLabel6_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) diff --git a/app.manifest b/app.manifest new file mode 100644 index 0000000..5e5656b --- /dev/null +++ b/app.manifest @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + + + + + + + + + + + + + diff --git a/cliff-release.toml b/cliff-release.toml new file mode 100644 index 0000000..ae097bb --- /dev/null +++ b/cliff-release.toml @@ -0,0 +1,100 @@ +# git-cliff ~ default configuration file +# https://git-cliff.org/docs/configuration +# +# Lines starting with "#" are comments. +# Configuration options are organized into tables and keys. +# See documentation for more information on available options. + +[changelog] +# template for the changelog header +header = """ +# 📝 Changelog\n +""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ + +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + - [`{{ commit.id | truncate(length=7, end="") }}`](/commit/{{ commit.id }}) {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ + {% if commit.breaking %}[**breaking**] {% endif %}\ + {{ commit.message | upper_first }}\ + {% if commit.remote.pr_number %} in #{{ commit.remote.pr_number }}{%- endif %}\ + {% endfor %}\n + {% for commit in commits %} + {%- if commit.body and commit.body is matching("^(\\d+\\.|-|\\*)") -%} + {% for line in commit.body | split(pat="\n") %} + {% if line is matching("^(\\d+\\.|-|\\*)") %} + >{{ line }} + {% endif %} + {% endfor %} + {%- endif -%} + {% endfor %} +{% endfor %}\n + +{%- if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %} + ## New Contributors +{%- endif -%} + +{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %} + * @{{ contributor.username }} made their first contribution + {%- if contributor.pr_number %} in \ + [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \ + {%- endif %} +{%- endfor %}\n +""" +# template for the changelog footer +footer = """ + +""" +# remove the leading and trailing s +trim = true +# postprocessors +postprocessors = [ + { pattern = '', replace = "https://github.com/sinspired/SubsCheck-Win-GUI" }, # replace repository URL +] +# render body even when there are no releases to process +# render_always = true +# output file path +# output = "test.md" + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = true +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [ + # Replace issue numbers + { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))" }, + # Check spelling of the commit with https://github.com/crate-ci/typos + # If the spelling is incorrect, it will be automatically fixed. + #{ pattern = '.*', replace_command = 'typos --write-changes -' }, +] +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^feat", group = "🚀 Features" }, + { message = "^fix", group = "🐛 Bug Fixes" }, + { message = "^doc|^docs", group = "📚 Documentation" }, + { message = "^perf", group = "⚡ Performance" }, + { message = "^refactor", group = "🚜 Refactor" }, + { message = "^style", group = "🎨 Styling" }, + { message = "^test", group = "🧪 Testing" }, + { message = "^chore\\(release\\): prepare for", skip = true }, + { message = "^chore\\(deps.*\\)", skip = true }, + { message = "^chore\\(pr\\)", skip = true }, + { message = "^chore\\(pull\\)", skip = true }, + { message = "^chore|^ci", group = "⚙️ Miscellaneous Tasks" }, + { body = ".*security", group = "🛡️ Security" }, + { message = "^revert", group = "◀️ Revert" }, + { message = ".*", group = "💼 Other" }, +] +# filter out the commits that are not matched by commit parsers +filter_commits = false +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "oldest" diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 0000000..5596a83 --- /dev/null +++ b/cliff.toml @@ -0,0 +1,96 @@ +# git-cliff ~ configuration file +# https://git-cliff.org/docs/configuration + + +[changelog] +# template for the changelog header +header = """ +# 📝 Changelog\n +""" +# A Tera template to be rendered for each release in the changelog. +# See https://keats.github.io/tera/docs/#introduction +body = """ +{% if version %}\ + [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else %}\ + [unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ + {% if commit.breaking %}[**breaking**] {% endif %}\ + {{ commit.message | upper_first }}\ + {% endfor %} +{% endfor %} +""" +# Remove leading and trailing whitespaces from the changelog's body. +trim = true +# Render body even when there are no releases to process. +render_always = true +# An array of regex based postprocessors to modify the changelog. +postprocessors = [ + # Replace the placeholder with a URL. + #{ pattern = '', replace = "https://github.com/orhun/git-cliff" }, +] +# render body even when there are no releases to process +# render_always = true +# output file path +# output = "test.md" + +[git] +# Parse commits according to the conventional commits specification. +# See https://www.conventionalcommits.org +conventional_commits = true +# Exclude commits that do not match the conventional commits specification. +filter_unconventional = true +# Require all commits to be conventional. +# Takes precedence over filter_unconventional. +require_conventional = false +# Split commits on newlines, treating each line as an individual commit. +split_commits = false +# An array of regex based parsers to modify commit messages prior to further processing. +commit_preprocessors = [ + # Replace issue numbers with link templates to be updated in `changelog.postprocessors`. + #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))"}, + # Check spelling of the commit message using https://github.com/crate-ci/typos. + # If the spelling is incorrect, it will be fixed automatically. + #{ pattern = '.*', replace_command = 'typos --write-changes -' }, +] +# Prevent commits that are breaking from being excluded by commit parsers. +protect_breaking_commits = false +# An array of regex based parsers for extracting data from the commit message. +# Assigns commits to groups. +# Optionally sets the commit's scope and can decide to exclude commits from further processing. +commit_parsers = [ + { message = "^feat", group = "🚀 Features" }, + { message = "^fix", group = "🐛 Bug Fixes" }, + { message = "^doc", group = "📚 Documentation" }, + { message = "^perf", group = "⚡ Performance" }, + { message = "^refactor", group = "🚜 Refactor" }, + { message = "^style", group = "🎨 Styling" }, + { message = "^test", group = "🧪 Testing" }, + { message = "^chore\\(release\\): prepare for", skip = true }, + { message = "^chore\\(deps.*\\)", skip = true }, + { message = "^chore\\(pr\\)", skip = true }, + { message = "^chore\\(pull\\)", skip = true }, + { message = "^chore|^ci", group = "⚙️ Miscellaneous Tasks" }, + { body = ".*security", group = "🛡️ Security" }, + { message = "^revert", group = "◀️ Revert" }, + { message = ".*", group = "💼 Other" }, +] +# Exclude commits that are not matched by any commit parser. +filter_commits = false +# An array of link parsers for extracting external references, and turning them into URLs, using regex. +link_parsers = [] +# Include only the tags that belong to the current branch. +use_branch_tags = true +# Order releases topologically instead of chronologically. +topo_order = false +# Order releases topologically instead of chronologically. +topo_order_commits = true +# Order of commits in each group/release within the changelog. +# Allowed values: newest, oldest +sort_commits = "oldest" +# Process submodules commits +recurse_submodules = false diff --git a/gui.png b/gui.png index adea5b1..2df2b86 100644 Binary files a/gui.png and b/gui.png differ diff --git a/packages.config b/packages.config index 3c95071..dce3d59 100644 --- a/packages.config +++ b/packages.config @@ -1,5 +1,7 @@  - - + + + + \ No newline at end of file diff --git a/subs-check.win.gui.csproj b/subs-check.win.gui.csproj index eae8cb8..ac2df30 100644 --- a/subs-check.win.gui.csproj +++ b/subs-check.win.gui.csproj @@ -8,11 +8,28 @@ WinExe subs_check.win.gui subs-check.win.gui - v4.7.2 + v4.8 512 true true + + + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true AnyCPU @@ -23,6 +40,7 @@ DEBUG;TRACE prompt 4 + false AnyCPU @@ -39,14 +57,50 @@ subs_check.win.gui.Program + + + + app.manifest + + + + + + + + + + + + + + + + + + packages\Autoupdater.NET.Official.1.9.2\lib\net462\AutoUpdater.NET.dll + + + packages\Microsoft.Web.WebView2.1.0.2592.51\lib\net462\Microsoft.Web.WebView2.Core.dll + + + packages\Microsoft.Web.WebView2.1.0.2592.51\lib\net462\Microsoft.Web.WebView2.WinForms.dll + + + packages\Microsoft.Web.WebView2.1.0.2592.51\lib\net462\Microsoft.Web.WebView2.Wpf.dll + - packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll + + + + @@ -56,6 +110,7 @@ + packages\YamlDotNet.16.3.0\lib\net47\YamlDotNet.dll @@ -79,11 +134,11 @@ EditURLs.cs - + Form - - Form1.cs + + MainGui.cs Form @@ -91,8 +146,15 @@ MoreYAML.cs + + Form + + + PlatformSelectorForm.cs + + about.cs @@ -101,9 +163,10 @@ EditURLs.cs + Designer - - Form1.cs + + MainGui.cs MoreYAML.cs @@ -113,6 +176,7 @@ Designer Resources.Designer.cs + SettingsSingleFileGenerator @@ -136,5 +200,24 @@ + + + False + Microsoft .NET Framework 4.7.2 %28x86 和 x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + \ No newline at end of file diff --git a/update.xml b/update.xml new file mode 100644 index 0000000..f7c57b4 --- /dev/null +++ b/update.xml @@ -0,0 +1,8 @@ + + + 2.7.0.1 + https://gh.39.al/https://github.com/sinspired/SubsCheck-Win-GUI/releases/download/v2.7.0.1/subs-check-win.zip + https://gh.39.al/https://raw.githubusercontent.com/sinspired/SubsCheck-Win-GUI/master/CHANGELOG.md + true + subs-check.win.gui.exe +