Compare commits

...

32 Commits
1.3.7 ... 1.3.8

Author SHA1 Message Date
Amazing_DM
3db75738dc Update submodule 2020-02-07 21:20:06 +08:00
Amazing_DM
61666a180d 🐛 修复了一个允许创建空文件名模式的bug
🎨 现在只允许修改进程加速的模式
💬 更新部分中文翻译
2020-02-06 22:50:18 +08:00
Amazing_DM
b4199abc4a fix a bug 2020-02-06 13:41:56 +08:00
Amazing_DM
5958e353c2 Update submodule
Signed-off-by: Amazing_DM <amazingdmdd@gmail.com>
2020-02-06 13:22:07 +08:00
Amazing_DM
f5c6632a92 添加Tap-Driver
Signed-off-by: Amazing_DM <amazingdmdd@gmail.com>
2020-02-06 13:14:52 +08:00
Amazing_DM
1d38ea1746 Update submodule 2020-02-06 11:16:24 +08:00
Amazing_DM
3a048c76e1 Merge branch 'master' of https://github.com/NetchX/Netch 2020-02-05 21:58:49 +08:00
Amazing_DM
0b6b66461d fix a little bug 2020-02-05 21:33:29 +08:00
Connection Refused
bc7681bd0b Update README.zh-CN.md 2020-02-05 20:58:03 +08:00
Connection Refused
ee347b62bc Update README.md 2020-02-05 20:57:43 +08:00
Amazing_DM
1a5572ae2d 添加模式修改功能
订阅列表右键现在可以复制链接啦~
2020-02-05 20:17:49 +08:00
Amazing_DM
6b4368153c Merge pull request #244 from NormanBB/master
新增新手入门教程
2020-02-05 04:10:04 -06:00
NormanBB
4ec5cf2e23 Update Basic-usage.md 2020-02-05 16:26:53 +08:00
NormanBB
244b1fba29 Update README.zh-CN.md 2020-02-05 16:22:25 +08:00
NormanBB
079d390933 Update README.zh-CN.md 2020-02-05 16:03:59 +08:00
NormanBB
d2af068325 Update README.zh-CN.md 2020-02-05 16:00:10 +08:00
NormanBB
6445bf633e Update README.zh-CN.md 2020-02-05 15:39:19 +08:00
NormanBB
282957f8bd Update Basic-usage.md 2020-02-05 15:31:27 +08:00
NormanBB
5bb320a08c Add files via upload 2020-02-05 14:31:32 +08:00
NormanBB
4178d363a9 Update Basic-usage.md 2020-02-05 12:23:57 +08:00
NormanBB
20f232b086 Update README.zh-CN.md 2020-02-05 12:17:00 +08:00
NormanBB
bb365279d6 Create Basic-usage.md 2020-02-05 12:10:43 +08:00
NormanBB
e5126e728e Update README.zh-CN.md 2020-02-05 12:07:22 +08:00
Connection Refused
5c5318cd25 Update README.zh-CN.md 2020-02-04 12:49:21 +08:00
Connection Refused
3cef06a786 Update README.zh-CN.md 2020-02-04 12:48:52 +08:00
Connection Refused
15e5e4f735 Update README.md 2020-02-04 12:48:27 +08:00
Andy1999
6697d4454d 图太大了重新调整一下大小 2020-02-04 00:57:57 +08:00
Andy1999
9a047014cf 新增 NyanCAT 赞助商
豪华赞助
2020-02-04 00:56:34 +08:00
Connection Refused
af7b618551 Update README.zh-CN.md 2020-02-03 21:31:11 +08:00
Connection Refused
e01436c434 Update README.md 2020-02-03 21:30:59 +08:00
Tindy X
b312534d06 Fix a bug
Clean up codes.
2020-01-30 17:06:11 +08:00
Tindy X
54ab6618bd Update submodule 2020-01-30 17:01:05 +08:00
19 changed files with 792 additions and 704 deletions

View File

@@ -26,7 +26,7 @@ namespace Netch.Controllers
public const string Name = @"Netch"; public const string Name = @"Netch";
public const string Copyright = @"Copyright © 2019 - 2020"; public const string Copyright = @"Copyright © 2019 - 2020";
public const string Version = @"1.3.7"; public const string Version = @"1.3.8";
public async void Check(bool notifyNoFound, bool isPreRelease) public async void Check(bool notifyNoFound, bool isPreRelease)
{ {

View File

@@ -55,9 +55,6 @@ namespace Netch.Forms
this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox(); this.ConfigurationGroupBox = new System.Windows.Forms.GroupBox();
this.ProfileNameText = new System.Windows.Forms.TextBox(); this.ProfileNameText = new System.Windows.Forms.TextBox();
this.ProfileLabel = new System.Windows.Forms.Label(); this.ProfileLabel = new System.Windows.Forms.Label();
this.SpeedPictureBox = new System.Windows.Forms.PictureBox();
this.DeletePictureBox = new System.Windows.Forms.PictureBox();
this.EditPictureBox = new System.Windows.Forms.PictureBox();
this.ModeLabel = new System.Windows.Forms.Label(); this.ModeLabel = new System.Windows.Forms.Label();
this.ModeComboBox = new System.Windows.Forms.SearchComboBox(); this.ModeComboBox = new System.Windows.Forms.SearchComboBox();
this.ServerComboBox = new System.Windows.Forms.ComboBox(); this.ServerComboBox = new System.Windows.Forms.ComboBox();
@@ -75,14 +72,19 @@ namespace Netch.Forms
this.SettingsButton = new System.Windows.Forms.Button(); this.SettingsButton = new System.Windows.Forms.Button();
this.ProfileGroupBox = new System.Windows.Forms.GroupBox(); this.ProfileGroupBox = new System.Windows.Forms.GroupBox();
this.ProfileTable = new System.Windows.Forms.TableLayoutPanel(); this.ProfileTable = new System.Windows.Forms.TableLayoutPanel();
this.EditModePictureBox = new System.Windows.Forms.PictureBox();
this.SpeedPictureBox = new System.Windows.Forms.PictureBox();
this.DeletePictureBox = new System.Windows.Forms.PictureBox();
this.EditPictureBox = new System.Windows.Forms.PictureBox();
this.MenuStrip.SuspendLayout(); this.MenuStrip.SuspendLayout();
this.ConfigurationGroupBox.SuspendLayout(); this.ConfigurationGroupBox.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.SpeedPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.DeletePictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.EditPictureBox)).BeginInit();
this.StatusStrip.SuspendLayout(); this.StatusStrip.SuspendLayout();
this.NotifyMenu.SuspendLayout(); this.NotifyMenu.SuspendLayout();
this.ProfileGroupBox.SuspendLayout(); this.ProfileGroupBox.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.EditModePictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.SpeedPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.DeletePictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.EditPictureBox)).BeginInit();
this.SuspendLayout(); this.SuspendLayout();
// //
// MenuStrip // MenuStrip
@@ -262,6 +264,7 @@ namespace Netch.Forms
// //
// ConfigurationGroupBox // ConfigurationGroupBox
// //
this.ConfigurationGroupBox.Controls.Add(this.EditModePictureBox);
this.ConfigurationGroupBox.Controls.Add(this.ProfileNameText); this.ConfigurationGroupBox.Controls.Add(this.ProfileNameText);
this.ConfigurationGroupBox.Controls.Add(this.ProfileLabel); this.ConfigurationGroupBox.Controls.Add(this.ProfileLabel);
this.ConfigurationGroupBox.Controls.Add(this.SpeedPictureBox); this.ConfigurationGroupBox.Controls.Add(this.SpeedPictureBox);
@@ -294,39 +297,6 @@ namespace Netch.Forms
this.ProfileLabel.TabIndex = 10; this.ProfileLabel.TabIndex = 10;
this.ProfileLabel.Text = "Profile"; this.ProfileLabel.Text = "Profile";
// //
// SpeedPictureBox
//
this.SpeedPictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
this.SpeedPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("SpeedPictureBox.Image")));
this.SpeedPictureBox.Location = new System.Drawing.Point(562, 26);
this.SpeedPictureBox.Name = "SpeedPictureBox";
this.SpeedPictureBox.Size = new System.Drawing.Size(16, 16);
this.SpeedPictureBox.TabIndex = 9;
this.SpeedPictureBox.TabStop = false;
this.SpeedPictureBox.Click += new System.EventHandler(this.SpeedPictureBox_Click);
//
// DeletePictureBox
//
this.DeletePictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
this.DeletePictureBox.Image = ((System.Drawing.Image)(resources.GetObject("DeletePictureBox.Image")));
this.DeletePictureBox.Location = new System.Drawing.Point(540, 26);
this.DeletePictureBox.Name = "DeletePictureBox";
this.DeletePictureBox.Size = new System.Drawing.Size(16, 16);
this.DeletePictureBox.TabIndex = 8;
this.DeletePictureBox.TabStop = false;
this.DeletePictureBox.Click += new System.EventHandler(this.DeletePictureBox_Click);
//
// EditPictureBox
//
this.EditPictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
this.EditPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("EditPictureBox.Image")));
this.EditPictureBox.Location = new System.Drawing.Point(518, 26);
this.EditPictureBox.Name = "EditPictureBox";
this.EditPictureBox.Size = new System.Drawing.Size(16, 16);
this.EditPictureBox.TabIndex = 7;
this.EditPictureBox.TabStop = false;
this.EditPictureBox.Click += new System.EventHandler(this.EditPictureBox_Click);
//
// ModeLabel // ModeLabel
// //
this.ModeLabel.AutoSize = true; this.ModeLabel.AutoSize = true;
@@ -490,6 +460,52 @@ namespace Netch.Forms
this.ProfileTable.Size = new System.Drawing.Size(578, 43); this.ProfileTable.Size = new System.Drawing.Size(578, 43);
this.ProfileTable.TabIndex = 0; this.ProfileTable.TabIndex = 0;
// //
// EditModePictureBox
//
this.EditModePictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
this.EditModePictureBox.ErrorImage = global::Netch.Properties.Resources.edit;
this.EditModePictureBox.Image = global::Netch.Properties.Resources.edit;
this.EditModePictureBox.InitialImage = global::Netch.Properties.Resources.edit;
this.EditModePictureBox.Location = new System.Drawing.Point(518, 56);
this.EditModePictureBox.Name = "EditModePictureBox";
this.EditModePictureBox.Size = new System.Drawing.Size(16, 16);
this.EditModePictureBox.TabIndex = 12;
this.EditModePictureBox.TabStop = false;
this.EditModePictureBox.Click += new System.EventHandler(this.EditModePictureBox_Click);
//
// SpeedPictureBox
//
this.SpeedPictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
this.SpeedPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("SpeedPictureBox.Image")));
this.SpeedPictureBox.Location = new System.Drawing.Point(562, 26);
this.SpeedPictureBox.Name = "SpeedPictureBox";
this.SpeedPictureBox.Size = new System.Drawing.Size(16, 16);
this.SpeedPictureBox.TabIndex = 9;
this.SpeedPictureBox.TabStop = false;
this.SpeedPictureBox.Click += new System.EventHandler(this.SpeedPictureBox_Click);
//
// DeletePictureBox
//
this.DeletePictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
this.DeletePictureBox.Image = ((System.Drawing.Image)(resources.GetObject("DeletePictureBox.Image")));
this.DeletePictureBox.Location = new System.Drawing.Point(540, 26);
this.DeletePictureBox.Name = "DeletePictureBox";
this.DeletePictureBox.Size = new System.Drawing.Size(16, 16);
this.DeletePictureBox.TabIndex = 8;
this.DeletePictureBox.TabStop = false;
this.DeletePictureBox.Click += new System.EventHandler(this.DeletePictureBox_Click);
//
// EditPictureBox
//
this.EditPictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
this.EditPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("EditPictureBox.Image")));
this.EditPictureBox.Location = new System.Drawing.Point(518, 26);
this.EditPictureBox.Name = "EditPictureBox";
this.EditPictureBox.Size = new System.Drawing.Size(16, 16);
this.EditPictureBox.TabIndex = 7;
this.EditPictureBox.TabStop = false;
this.EditPictureBox.Click += new System.EventHandler(this.EditPictureBox_Click);
//
// MainForm // MainForm
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -515,14 +531,15 @@ namespace Netch.Forms
this.MenuStrip.PerformLayout(); this.MenuStrip.PerformLayout();
this.ConfigurationGroupBox.ResumeLayout(false); this.ConfigurationGroupBox.ResumeLayout(false);
this.ConfigurationGroupBox.PerformLayout(); this.ConfigurationGroupBox.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.SpeedPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.DeletePictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.EditPictureBox)).EndInit();
this.StatusStrip.ResumeLayout(false); this.StatusStrip.ResumeLayout(false);
this.StatusStrip.PerformLayout(); this.StatusStrip.PerformLayout();
this.NotifyMenu.ResumeLayout(false); this.NotifyMenu.ResumeLayout(false);
this.ProfileGroupBox.ResumeLayout(false); this.ProfileGroupBox.ResumeLayout(false);
this.ProfileGroupBox.PerformLayout(); this.ProfileGroupBox.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.EditModePictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.SpeedPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.DeletePictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.EditPictureBox)).EndInit();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@@ -573,5 +590,6 @@ namespace Netch.Forms
private System.Windows.Forms.GroupBox ProfileGroupBox; private System.Windows.Forms.GroupBox ProfileGroupBox;
private System.Windows.Forms.TableLayoutPanel ProfileTable; private System.Windows.Forms.TableLayoutPanel ProfileTable;
private System.Windows.Forms.ToolStripMenuItem ManageProcessModeToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem ManageProcessModeToolStripMenuItem;
private System.Windows.Forms.PictureBox EditModePictureBox;
} }
} }

View File

@@ -204,6 +204,17 @@ namespace Netch.Forms
SelectLastMode(); SelectLastMode();
} }
public void UpdateMode(Models.Mode NewMode, Models.Mode OldMode)
{
ModeComboBox.Items.Clear();
Global.ModeFiles.Remove(OldMode);
Global.ModeFiles.Add(NewMode);
var array = Global.ModeFiles.ToArray();
Array.Sort(array, (a, b) => string.Compare(a.Remark, b.Remark, StringComparison.Ordinal));
ModeComboBox.Items.AddRange(array);
SelectLastMode();
}
private void SaveConfigs() private void SaveConfigs()
{ {
@@ -1108,5 +1119,28 @@ namespace Netch.Forms
Global.Settings.profiles[index] = new Models.Profile(selectedServer, selectedMode, name); Global.Settings.profiles[index] = new Models.Profile(selectedServer, selectedMode, name);
} }
private void EditModePictureBox_Click(object sender, EventArgs e)
{
// 当前ModeComboBox中至少有一项
if (ModeComboBox.Items.Count > 0 && ModeComboBox.SelectedIndex != -1)
{
SaveConfigs();
var selectedMode = (Models.Mode)ModeComboBox.SelectedItem;
// 只允许修改进程加速的模式
if (selectedMode.Type == 0)
{
//Process.Start(Environment.CurrentDirectory + "\\mode\\" + selectedMode.FileName + ".txt");
Mode.Process process = new Mode.Process(selectedMode);
process.Text = "Edit Process Mode";
process.Show();
Hide();
}
}
else
{
MessageBox.Show(Utils.i18N.Translate("Please select an mode first"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
} }
} }

View File

@@ -160,6 +160,7 @@
this.RuleListBox.Name = "RuleListBox"; this.RuleListBox.Name = "RuleListBox";
this.RuleListBox.Size = new System.Drawing.Size(328, 123); this.RuleListBox.Size = new System.Drawing.Size(328, 123);
this.RuleListBox.TabIndex = 2; this.RuleListBox.TabIndex = 2;
this.RuleListBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.RuleListBox_MouseUp);
// //
// RemarkTextBox // RemarkTextBox
// //

View File

@@ -7,11 +7,45 @@ namespace Netch.Forms.Mode
{ {
public partial class Process : Form public partial class Process : Form
{ {
//用于判断当前窗口是否为编辑模式
private Boolean EditMode = false;
//被编辑模式坐标
private Models.Mode EditMode_Old = null;
/// <summary>
/// 编辑模式
/// </summary>
/// <param name="mode">模式</param>
public Process(Models.Mode mode)
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;
EditMode_Old = mode;
this.Text = "Edit Process Mode";
//循环填充已有规则
mode.Rule.ForEach(i => RuleListBox.Items.Add(i));
EditMode = true;
StaySameButton.Enabled = false;
TimeDataButton.Enabled = false;
FilenameTextBox.Enabled = false;
FilenameLabel.Enabled = false;
UseCustomFilenameBox.Enabled = false;
FilenameTextBox.Text = mode.FileName;
RemarkTextBox.Text = mode.Remark;
}
public Process() public Process()
{ {
InitializeComponent(); InitializeComponent();
CheckForIllegalCrossThreadCalls = false; CheckForIllegalCrossThreadCalls = false;
EditMode = false;
EditMode_Old = null;
} }
/// <summary> /// <summary>
@@ -91,6 +125,27 @@ namespace Netch.Forms.Mode
Global.MainForm.Show(); Global.MainForm.Show();
} }
/// <summary>
/// listBox右键菜单
/// </summary>
private void RuleListBox_MouseUp(object sender, MouseEventArgs e)
{
ContextMenuStrip strip = new ContextMenuStrip();
strip.Items.Add(Utils.i18N.Translate("Delete"));
if (e.Button == MouseButtons.Right)
{
strip.Show(this.RuleListBox, e.Location);//鼠标右键按下弹出菜单
strip.MouseClick += new MouseEventHandler(deleteRule_Click);
}
}
void deleteRule_Click(object sender, EventArgs e)
{
if (RuleListBox.SelectedIndex != -1)
{
RuleListBox.Items.RemoveAt(RuleListBox.SelectedIndex);
}
}
private void AddButton_Click(object sender, EventArgs e) private void AddButton_Click(object sender, EventArgs e)
{ {
if (!string.IsNullOrWhiteSpace(ProcessNameTextBox.Text)) if (!string.IsNullOrWhiteSpace(ProcessNameTextBox.Text))
@@ -133,6 +188,49 @@ namespace Netch.Forms.Mode
} }
private void ControlButton_Click(object sender, EventArgs e) private void ControlButton_Click(object sender, EventArgs e)
{
if (EditMode)
{
// 编辑模式
if (RuleListBox.Items.Count != 0)
{
var mode = new Models.Mode
{
BypassChina = false,
FileName = FilenameTextBox.Text,
Type = 0,
Remark = RemarkTextBox.Text
};
var text = $"# {RemarkTextBox.Text}, 0\r\n";
foreach (var item in RuleListBox.Items)
{
var process = item as string;
mode.Rule.Add(process);
text += process + "\r\n";
}
text = text.Substring(0, text.Length - 2);
if (!Directory.Exists("mode"))
{
Directory.CreateDirectory("mode");
}
File.WriteAllText(Path.Combine("mode", FilenameTextBox.Text) + ".txt", text);
MessageBox.Show(Utils.i18N.Translate("Mode updated successfully"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
Global.MainForm.UpdateMode(mode, EditMode_Old);
Close();
}
else
{
MessageBox.Show(Utils.i18N.Translate("Unable to add empty rule"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
else
{ {
// 自定义文件名 // 自定义文件名
if (UseCustomFilenameBox.Checked) if (UseCustomFilenameBox.Checked)
@@ -156,6 +254,11 @@ namespace Netch.Forms.Mode
if (!string.IsNullOrWhiteSpace(RemarkTextBox.Text)) if (!string.IsNullOrWhiteSpace(RemarkTextBox.Text))
{ {
if (Global.Settings.ModeFileNameType == 0 && string.IsNullOrWhiteSpace(FilenameTextBox.Text))
{
MessageBox.Show(Utils.i18N.Translate("Please enter a mode filename"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var ModeFilename = Path.Combine("mode", FilenameTextBox.Text); var ModeFilename = Path.Combine("mode", FilenameTextBox.Text);
// 如果文件已存在,返回 // 如果文件已存在,返回
@@ -206,7 +309,7 @@ namespace Netch.Forms.Mode
{ {
MessageBox.Show(Utils.i18N.Translate("Please enter a mode remark"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information); MessageBox.Show(Utils.i18N.Translate("Please enter a mode remark"), Utils.i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
} }
}
} }
private void UseCustomFileNameBox_CheckedChanged(object sender, EventArgs e) private void UseCustomFileNameBox_CheckedChanged(object sender, EventArgs e)

View File

@@ -45,6 +45,7 @@
this.UserAgentHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.UserAgentHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.pContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.pContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.CopyLinkToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.UseSelectedServerCheckBox = new System.Windows.Forms.CheckBox(); this.UseSelectedServerCheckBox = new System.Windows.Forms.CheckBox();
this.AddSubscriptionBox.SuspendLayout(); this.AddSubscriptionBox.SuspendLayout();
this.pContextMenuStrip.SuspendLayout(); this.pContextMenuStrip.SuspendLayout();
@@ -169,6 +170,8 @@
// //
this.pContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.pContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.DeleteToolStripMenuItem}); this.DeleteToolStripMenuItem});
this.pContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.CopyLinkToolStripMenuItem});
this.pContextMenuStrip.Name = "pContextMenuStrip"; this.pContextMenuStrip.Name = "pContextMenuStrip";
this.pContextMenuStrip.Size = new System.Drawing.Size(114, 26); this.pContextMenuStrip.Size = new System.Drawing.Size(114, 26);
// //
@@ -179,6 +182,13 @@
this.DeleteToolStripMenuItem.Text = "Delete"; this.DeleteToolStripMenuItem.Text = "Delete";
this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.DeleteToolStripMenuItem_Click); this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.DeleteToolStripMenuItem_Click);
// //
// CopyLinkToolStripMenuItem
//
this.CopyLinkToolStripMenuItem.Name = "CopyLinkToolStripMenuItem";
this.CopyLinkToolStripMenuItem.Size = new System.Drawing.Size(113, 22);
this.CopyLinkToolStripMenuItem.Text = "CopyLink";
this.CopyLinkToolStripMenuItem.Click += new System.EventHandler(this.CopyLinkToolStripMenuItem_Click);
//
// UseSelectedServerCheckBox // UseSelectedServerCheckBox
// //
this.UseSelectedServerCheckBox.AutoSize = true; this.UseSelectedServerCheckBox.AutoSize = true;
@@ -229,6 +239,7 @@
private System.Windows.Forms.ColumnHeader LinkColumnHeader; private System.Windows.Forms.ColumnHeader LinkColumnHeader;
private System.Windows.Forms.ContextMenuStrip pContextMenuStrip; private System.Windows.Forms.ContextMenuStrip pContextMenuStrip;
private System.Windows.Forms.ToolStripMenuItem DeleteToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem DeleteToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem CopyLinkToolStripMenuItem;
private System.Windows.Forms.Label UserAgentLabel; private System.Windows.Forms.Label UserAgentLabel;
private System.Windows.Forms.TextBox UserAgentTextBox; private System.Windows.Forms.TextBox UserAgentTextBox;
private System.Windows.Forms.ColumnHeader UserAgentHeader; private System.Windows.Forms.ColumnHeader UserAgentHeader;

View File

@@ -1,4 +1,5 @@
using System; using Netch.Models;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Windows.Forms; using System.Windows.Forms;
@@ -41,6 +42,7 @@ namespace Netch.Forms
LinkColumnHeader.Text = Utils.i18N.Translate(LinkColumnHeader.Text); LinkColumnHeader.Text = Utils.i18N.Translate(LinkColumnHeader.Text);
UseSelectedServerCheckBox.Text = Utils.i18N.Translate(UseSelectedServerCheckBox.Text); UseSelectedServerCheckBox.Text = Utils.i18N.Translate(UseSelectedServerCheckBox.Text);
DeleteToolStripMenuItem.Text = Utils.i18N.Translate(DeleteToolStripMenuItem.Text); DeleteToolStripMenuItem.Text = Utils.i18N.Translate(DeleteToolStripMenuItem.Text);
CopyLinkToolStripMenuItem.Text = Utils.i18N.Translate(CopyLinkToolStripMenuItem.Text);
RemarkLabel.Text = Utils.i18N.Translate(RemarkLabel.Text); RemarkLabel.Text = Utils.i18N.Translate(RemarkLabel.Text);
LinkLabel.Text = Utils.i18N.Translate(LinkLabel.Text); LinkLabel.Text = Utils.i18N.Translate(LinkLabel.Text);
AddButton.Text = Utils.i18N.Translate(AddButton.Text); AddButton.Text = Utils.i18N.Translate(AddButton.Text);
@@ -56,7 +58,18 @@ namespace Netch.Forms
{ {
Global.MainForm.Show(); Global.MainForm.Show();
} }
private void CopyLinkToolStripMenuItem_Click(object sender, EventArgs e)
{
if (SubscribeLinkListView.SelectedItems.Count > 0)
{
for (var i = SubscribeLinkListView.SelectedItems.Count - 1; i >= 0; i--)
{
var item = SubscribeLinkListView.SelectedItems[i];
var link = Global.Settings.SubscribeLink[item.Index];
Clipboard.SetText(link.Link);
}
}
}
private void DeleteToolStripMenuItem_Click(object sender, EventArgs e) private void DeleteToolStripMenuItem_Click(object sender, EventArgs e)
{ {
if (MessageBox.Show(Utils.i18N.Translate("Delete or not ? Will clean up the corresponding group of items in the server list"), Utils.i18N.Translate("Information"), MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK) if (MessageBox.Show(Utils.i18N.Translate("Delete or not ? Will clean up the corresponding group of items in the server list"), Utils.i18N.Translate("Information"), MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)

View File

@@ -68,7 +68,7 @@
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="@ECHO OFF&#xD;&#xA;RD /S /Q $(TargetDir)bin &gt; NUL 2&gt;&amp;1&#xD;&#xA;RD /S /Q $(TargetDir)i18n &gt; NUL 2&gt;&amp;1&#xD;&#xA;RD /S /Q $(TargetDir)mode &gt; NUL 2&gt;&amp;1&#xD;&#xA;&#xD;&#xA;MKDIR $(TargetDir)bin &gt; NUL 2&gt;&amp;1&#xD;&#xA;MKDIR $(TargetDir)i18n &gt; NUL 2&gt;&amp;1&#xD;&#xA;MKDIR $(TargetDir)mode &gt; NUL 2&gt;&amp;1&#xD;&#xA;&#xD;&#xA;COPY /Y $(SolutionDir)binaries\$(PlatformName)\* $(TargetDir)bin &gt; NUL 2&gt;&amp;1&#xD;&#xA;COPY /Y $(SolutionDir)binaries\* $(TargetDir)bin &gt; NUL 2&gt;&amp;1&#xD;&#xA;MOVE /Y $(TargetDir)bin\nfapinet.dll $(TargetDir)nfapinet.dll &gt; NUL 2&gt;&amp;1&#xD;&#xA;COPY /Y $(SolutionDir)translations\i18n\* $(TargetDir)i18n &gt; NUL 2&gt;&amp;1&#xD;&#xA;COPY /Y $(SolutionDir)modes\mode\*.txt $(TargetDir)mode &gt; NUL 2&gt;&amp;1" /> <Exec Command="@ECHO OFF&#xD;&#xA;RD /S /Q $(TargetDir)bin &gt; NUL 2&gt;&amp;1&#xD;&#xA;RD /S /Q $(TargetDir)i18n &gt; NUL 2&gt;&amp;1&#xD;&#xA;RD /S /Q $(TargetDir)mode &gt; NUL 2&gt;&amp;1&#xD;&#xA;&#xD;&#xA;MKDIR $(TargetDir)bin &gt; NUL 2&gt;&amp;1&#xD;&#xA;MKDIR $(TargetDir)i18n &gt; NUL 2&gt;&amp;1&#xD;&#xA;MKDIR $(TargetDir)mode &gt; NUL 2&gt;&amp;1&#xD;&#xA;&#xD;&#xA;COPY /Y $(SolutionDir)binaries\$(PlatformName)\* $(TargetDir)bin &gt; NUL 2&gt;&amp;1&#xD;&#xA;COPY /Y $(SolutionDir)binaries\* $(TargetDir)bin &gt; NUL 2&gt;&amp;1&#xD;&#xA;MOVE /Y $(TargetDir)bin\nfapinet.dll $(TargetDir)nfapinet.dll &gt; NUL 2&gt;&amp;1&#xD;&#xA;COPY /Y $(SolutionDir)translations\i18n\* $(TargetDir)i18n &gt; NUL 2&gt;&amp;1&#xD;&#xA;COPY /Y $(SolutionDir)modes\mode\*.txt $(TargetDir)mode &gt; NUL 2&gt;&amp;1&#xD;&#xA;MKDIR $(TargetDir)bin\tap-driver &gt; NUL 2&gt;&amp;1&#xD;&#xA;COPY /Y $(SolutionDir)binaries\$(PlatformName)\tap-driver\* $(TargetDir)bin\tap-driver &gt; NUL 2&gt;&amp;1" />
</Target> </Target>
</Project> </Project>

View File

@@ -30,6 +30,7 @@
"Mode": "模式", "Mode": "模式",
"Create Process Mode": "创建进程模式", "Create Process Mode": "创建进程模式",
"Manage Process Mode": "管理进程模式", "Manage Process Mode": "管理进程模式",
"Edit Process Mode": "修改进程模式",
"Address": "地址", "Address": "地址",
"Username": "用户名", "Username": "用户名",
@@ -100,12 +101,16 @@
"Please enter an process name (xxx.exe)": "请输入一个进程名xxx.exe", "Please enter an process name (xxx.exe)": "请输入一个进程名xxx.exe",
"Scan completed": "扫描完成", "Scan completed": "扫描完成",
"Mode added successfully": "模式添加成功", "Mode added successfully": "模式添加成功",
"Mode updated successfully": "模式修改成功",
"Unable to add empty rule": "无法添加空规则", "Unable to add empty rule": "无法添加空规则",
"Please enter a mode remark": "请输入模式的备注", "Please enter a mode remark": "请输入模式的备注",
"File already exists.\n Please Change the filename": "文件名已存在,请修改文件名",
"Please enter a mode filename": "请输入模式的文件名",
"Link": "链接", "Link": "链接",
"Use Selected Server To Update Subscription": "使用选中的服务器更新订阅", "Use Selected Server To Update Subscription": "使用选中的服务器更新订阅",
"Delete": "删除", "Delete": "删除",
"CopyLink": "复制链接",
"Delete or not ? Will clean up the corresponding group of items in the server list": "是否删除?将会清理服务器列表中对应组的项目", "Delete or not ? Will clean up the corresponding group of items in the server list": "是否删除?将会清理服务器列表中对应组的项目",
"Remark can not be empty": "备注不可为空", "Remark can not be empty": "备注不可为空",
"Link can not be empty": "链接不可为空", "Link can not be empty": "链接不可为空",
@@ -125,6 +130,7 @@
"Global Bypass IPs": "全局直连 IP", "Global Bypass IPs": "全局直连 IP",
"Port value illegal. Try again.": "端口值非法。请重试。", "Port value illegal. Try again.": "端口值非法。请重试。",
"Check update when opened": "打开软件时检查更新", "Check update when opened": "打开软件时检查更新",
"TUN/TAP driver is not detected. Is it installed now?": "未检测到TUN/TAP驱动是否现在安装",
"Profile": "配置名", "Profile": "配置名",
"Profiles": "配置", "Profiles": "配置",

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
@@ -145,9 +146,24 @@ namespace Netch.Utils
Global.TUNTAP.ComponentID = TUNTAP.GetComponentID(); Global.TUNTAP.ComponentID = TUNTAP.GetComponentID();
if (string.IsNullOrEmpty(Global.TUNTAP.ComponentID)) if (string.IsNullOrEmpty(Global.TUNTAP.ComponentID))
{ {
MessageBox.Show(i18N.Translate("Please install TAP-Windows and create an TUN/TAP adapter manually"), i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information); if (MessageBox.Show(i18N.Translate("TUN/TAP driver is not detected. Is it installed now?"), i18N.Translate("Information"), MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
{
//安装Tap Driver
Process installProcess = new Process();
installProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
installProcess.StartInfo.FileName = Path.Combine("bin/tap-driver", "install.bat");
installProcess.Start();
installProcess.WaitForExit();
installProcess.Close();
Global.TUNTAP.ComponentID = TUNTAP.GetComponentID();
}
else {
return false; return false;
} }
//MessageBox.Show(i18N.Translate("Please install TAP-Windows and create an TUN/TAP adapter manually"), i18N.Translate("Information"), MessageBoxButtons.OK, MessageBoxIcon.Information);
// return false;
}
var name = TUNTAP.GetName(Global.TUNTAP.ComponentID); var name = TUNTAP.GetName(Global.TUNTAP.ComponentID);
foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces()) foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces())

View File

@@ -47,7 +47,7 @@ namespace Netch.Utils
foreach (var line in text.GetLines()) foreach (var line in text.GetLines())
{ {
var servers = ParseLine(line); var servers = ParseLine(line);
if (line != null) if (servers != null)
{ {
list.AddRange(servers); list.AddRange(servers);
} }
@@ -109,110 +109,7 @@ namespace Netch.Utils
{ {
var data = new Server(); var data = new Server();
data.Type = "SS"; data.Type = "SS";
/*
try
{
if(!text.Contains("/?"))
{
var finder = new Regex(@"ss://(?<base64>[A-Za-z0-9+-/=_]+)(?:#(?<tag>\S+))?", RegexOptions.IgnoreCase);
var parser = new Regex(@"^((?<method>.+?):(?<password>.*)@(?<hostname>.+?):(?<port>\d+?))$", RegexOptions.IgnoreCase);
var match = finder.Match(text);
if (!match.Success)
{
throw new FormatException();
}
var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value;
if (!String.IsNullOrEmpty(tag))
{
data.Remark = HttpUtility.UrlDecode(tag);
}
match = parser.Match(URLSafeBase64Decode(base64));
if (!match.Success)
{
throw new FormatException();
}
data.Address = match.Groups["hostname"].Value;
data.Port = int.Parse(match.Groups["port"].Value);
data.Password = match.Groups["password"].Value;
data.EncryptMethod = match.Groups["method"].Value;
}
else
{
if (text.Contains("#"))
{
data.Remark = HttpUtility.UrlDecode(text.Split('#')[1]);
text = text.Split('#')[0];
}
var finder = new Regex(@"ss://(?<base64>.+?)@(?<server>.+?):(?<port>\d+?)/\?plugin=(?<plugin>.+)");
var parser = new Regex(@"^(?<method>.+?):(?<password>.+)$");
var match = finder.Match(text);
if (!match.Success)
{
throw new FormatException();
}
data.Address = match.Groups["server"].Value;
data.Port = int.Parse(match.Groups["port"].Value);
var plugins = HttpUtility.UrlDecode(match.Groups["plugin"].Value).Split(';');
if (plugins[0] == "obfs-local")
plugins[0] = "simple-obfs";
var base64 = URLSafeBase64Decode(match.Groups["base64"].Value);
match = parser.Match(base64);
if (!match.Success)
{
throw new FormatException();
}
data.EncryptMethod = match.Groups["method"].Value;
data.Password = match.Groups["password"].Value;
data.Plugin = plugins[0];
data.PluginOption = plugins[1];
}
if (!Global.EncryptMethods.SS.Contains(data.EncryptMethod))
{
Logging.Info(String.Format("不支持的 SS 加密方式:{0}", data.EncryptMethod));
return null;
}
list.Add(data);
}
catch (FormatException)
{
try
{
var uri = new Uri(text);
var userinfo = URLSafeBase64Decode(uri.UserInfo).Split(new char[] { ':' }, 2);
if (userinfo.Length != 2)
{
return null;
}
data.Remark = uri.GetComponents(UriComponents.Fragment, UriFormat.Unescaped);
data.Address = uri.IdnHost;
data.Port = uri.Port;
data.Password = userinfo[1];
data.EncryptMethod = userinfo[0];
if (!Global.EncryptMethods.SS.Contains(data.EncryptMethod))
{
Logging.Info(String.Format("不支持的 SS 加密方式:{0}", data.EncryptMethod));
return null;
}
list.Add(data);
}
catch (UriFormatException)
{
return null;
}
}
*/
text = text.Replace("/?", "?"); text = text.Replace("/?", "?");
try try
{ {
@@ -337,81 +234,7 @@ namespace Netch.Utils
data.Type = "SSR"; data.Type = "SSR";
text = text.Substring(6); text = text.Substring(6);
/*
var shadowsocksr = URLSafeBase64Decode(text).Split(':');
if (shadowsocksr.Length > 6)
{
var buff = "";
for (int i = 0; i < shadowsocksr.Length - 5; i++)
{
buff += shadowsocksr[i];
buff += ":";
}
data.Address = buff.Substring(0, buff.Length - 1).Trim();
}
else
{
data.Address = shadowsocksr[0];
}
data.Port = int.Parse(shadowsocksr[shadowsocksr.Length - 5]);
data.Protocol = shadowsocksr[shadowsocksr.Length - 4];
if (!Global.Protocols.Contains(data.Protocol))
{
Logging.Info(String.Format("不支持的 SSR 协议:{0}", data.Protocol));
return null;
}
data.EncryptMethod = shadowsocksr[shadowsocksr.Length - 3];
if (!Global.EncryptMethods.SSR.Contains(data.EncryptMethod))
{
Logging.Info(String.Format("不支持的 SSR 加密方式:{0}", data.EncryptMethod));
return null;
}
data.OBFS = shadowsocksr[shadowsocksr.Length - 2];
if (!Global.OBFSs.Contains(data.OBFS))
{
Logging.Info(String.Format("不支持的 SSR 混淆:{0}", data.OBFS));
return null;
}
var info = shadowsocksr[shadowsocksr.Length - 1].Split('/');
data.Password = URLSafeBase64Decode(info[0]);
var dict = new Dictionary<string, string>();
if (info.Length > 1 && info[1].Length > 1)
{
foreach (var str in info[1].Substring(1).Split('&'))
{
var splited = str.Split('=');
dict.Add(splited[0], splited[1]);
}
}
if (dict.ContainsKey("remarks"))
{
data.Remark = URLSafeBase64Decode(dict["remarks"]);
}
if (dict.ContainsKey("protoparam"))
{
data.ProtocolParam = URLSafeBase64Decode(dict["protoparam"]);
}
if (dict.ContainsKey("obfsparam"))
{
data.OBFSParam = URLSafeBase64Decode(dict["obfsparam"]);
}
if (data.EncryptMethod != "none" && data.Protocol == "origin" && data.OBFS == "plain")
{
data.Type = "SS";
}
*/
var parser = new Regex(@"^(?<server>.+):(?<port>(-?\d+?)):(?<protocol>.+?):(?<method>.+?):(?<obfs>.+?):(?<password>.+?)/\?(?<info>.*)$"); var parser = new Regex(@"^(?<server>.+):(?<port>(-?\d+?)):(?<protocol>.+?):(?<method>.+?):(?<obfs>.+?):(?<password>.+?)/\?(?<info>.*)$");
var match = parser.Match(URLSafeBase64Decode(text)); var match = parser.Match(URLSafeBase64Decode(text));

View File

@@ -22,10 +22,15 @@ As well, Netch avoid the restricted NAT problem caused by SSTap. You can use an
## Sponsor ## Sponsor
开发不易,以下为恰饭时间 开发不易,以下为恰饭时间
[![ManSora](docs/sponsor/mansora.jpg)](https://www.mansora.net/cart.php) [![NyanCAT](docs/sponsor/nyancat.jpg)](https://nyancat.info)
[![Across-GFW](docs/sponsor/across-gfw.jpg)](https://across-gfw.com/register?aff=4739)
这是我所选择的服务器提供商IPLC 专线翻墙、稳定、速度快、价格便宜。欢迎大家使用我的推广链接前去注册:[这里](https://across-gfw.com/register?aff=4739) NyanCAT Network全中转高质量节点多条低倍率节点保证流量无忧节点极低延迟涵盖五大洲。Netflix 视频党,游戏党,海外回国党必备,无需年付,月付 19 元起
[Telegram 群组](https://t.me/NyanCaaaat)
[![ManSora](docs/sponsor/mansora.jpg)](https://www.mansora.net/cart.php)
[![Across-GFW](docs/sponsor/across-gfw.jpg)](https://geckoiplc.com/register?aff=4739)
这是我所选择的服务器提供商IPLC 专线翻墙、稳定、速度快、价格便宜。欢迎大家使用我的推广链接前去注册:[这里](https://geckoiplc.com/register?aff=4739)
## Screenshots ## Screenshots

42
docs/Basic-usage.md Normal file
View File

@@ -0,0 +1,42 @@
# 新手入门
**Version : 1.3.7**
[下载地址](https://github.com/NetchX/Netch/releases)
## 主界面
![主界面](screenshots/main.zh-CN.png)
## 添加服务器
> Netch 目前仅支持以下代理协议ShadowsocksVMessSocks5ShadowsockR。
首先,点击`服务器`增加所需服务器
<img width="50%" height="50%" src="screenshots/Add-server.png">
可手动添加单个服务器,或者通过剪切板链接添加单个服务器。也可通过订阅链接批量添加。
点击 `订阅` ` 管理订阅链接` 进入以下界面。
<img width="50%" height="50%" src="screenshots/Add-link.jpg">
填写备注与链接,点击添加,然后保存。保存后点击 `订阅` ` 从订阅链接更新服务器`。完成服务器添加。添加完服务器后可对服务器进行修改,删除和测速。
## 选择模式
> 此处需要会一点英语,比如你应该知道`吃鸡`的英文名称是`PlayerUnknown's Battlegrounds`
1.3.7 上线了模式搜索功能,即在模式框里输入字符即可搜索,使用英文名称进行搜索,搜索到所需的模式后单击选择,启用模式。相对应的游戏即可被加速
若没有所需的模式,请选择`[3] Bypass LAN and China (TUN/TAP)`的模式。此模式需要安装 [Tap-Windows](https://github.com/OpenVPN/tap-windows) 适配器,如果 Netch 提示没有该适配器,可以直接安装 [Tap-Windows](https://build.openvpn.net/downloads/releases/latest/tap-windows-latest-stable.exe) 来获得该适配器
关于更多的模式说明,详见[进阶用法](https://github.com/NormanBB/NetchMode/blob/master/docs/README.zh-CN.md)。
选择完模式后,点击启用,游戏已被代理。这一步需在开启游戏前完成。
## 配置说明
目前netch支持自定义四个配置填入配置名选择相应的服务器和游戏模式按下`Ctrl`与鼠标左键,即可保存当前配置。下次使用时,点击配置名即可快速启用。
~~如果你还觉得不会用可以去用SStap (逃~~

View File

@@ -1,5 +1,6 @@
# Netch # Netch
[![](https://img.shields.io/badge/Telegram-频道-blue.svg)](https://t.me/Netch) [![](https://img.shields.io/badge/Telegram-频道-blue.svg)](https://t.me/Netch)
> ~~issue已关有问题可进tele群问不保证回答不保证解决咕~~
游戏加速工具 游戏加速工具
@@ -8,8 +9,10 @@
- [TOC](#toc) - [TOC](#toc)
- [简介](#%e7%ae%80%e4%bb%8b) - [简介](#%e7%ae%80%e4%bb%8b)
- [赞助商](#%e8%b5%9e%e5%8a%a9%e5%95%86) - [赞助商](#%e8%b5%9e%e5%8a%a9%e5%95%86)
- [截图](#%e6%88%aa%e5%9b%be) - [新手入门](Basic-usage.md)
- [进阶用法](https://github.com/NormanBB/NetchMode/blob/master/docs/README.zh-CN.md)
- [依赖](#%e4%be%9d%e8%b5%96) - [依赖](#%e4%be%9d%e8%b5%96)
- [语言支持](#语言支持)
## 简介 ## 简介
@@ -20,16 +23,29 @@ Netch 是一款 Windows 平台的开源游戏加速工具Netch 可以实现
## 赞助商 ## 赞助商
开发不易,以下为恰饭时间 开发不易,以下为恰饭时间
[![NyanCAT](sponsor/nyancat.jpg)](https://nyancat.info)
NyanCAT Network全中转高质量节点多条低倍率节点保证流量无忧节点极低延迟涵盖五大洲。Netflix 视频党,游戏党,海外回国党必备,无需年付,月付 19 元起
[Telegram 群组](https://t.me/NyanCaaaat)
[![ManSora](sponsor/mansora.jpg)](https://www.mansora.net/cart.php) [![ManSora](sponsor/mansora.jpg)](https://www.mansora.net/cart.php)
[![Across-GFW](sponsor/across-gfw.jpg)](https://across-gfw.com/register?aff=4739) [![Across-GFW](sponsor/across-gfw.jpg)](https://geckoiplc.com/register?aff=4739)
这是我所选择的服务器提供商IPLC 专线翻墙、稳定、速度快、价格便宜。欢迎大家使用我的推广链接前去注册:[这里](https://across-gfw.com/register?aff=4739) 这是我所选择的服务器提供商IPLC 专线翻墙、稳定、速度快、价格便宜。欢迎大家使用我的推广链接前去注册:[这里](https://geckoiplc.com/register?aff=4739)
## 截图 ## 新手入门
![主界面](screenshots/main.zh-CN.png) [新手入门教程](Basic-usage.md)
## 进阶用法
[进阶教程](https://github.com/NormanBB/NetchMode/blob/master/docs/README.zh-CN.md)
## 依赖 ## 依赖
- [Visual C++ 运行库合集](https://www.google.com/search?q=Visual+C%2B%2B+%E8%BF%90%E8%A1%8C%E5%BA%93%E5%90%88%E9%9B%86)
- [.NET Framework 4.8](https://dotnet.microsoft.com/download/dotnet-framework/thank-you/net48-offline-installer)
- [TAP-Windows](https://build.openvpn.net/downloads/releases/tap-windows-9.21.2.exe)
## 语言支持
Netch 支持多种语言,在启动时会根据系统语言选择自身语言。如果需要手动切换语言,可以在启动时加入命令行参数,命令行参数为目前支持的语言代码,可以去 [NetchTranslation/i18n](https://github.com/NetchX/NetchTranslation/tree/master/i18n) 文件夹下查看外部支持的语言代码文件。Netch 目前内置 en-USzh-CN外置 zh-TW。欢迎大家为 [NetchTranslation](https://github.com/NetchX/NetchTranslation) 提供其他语言的翻译
- Microsoft Visual C++ 运行库合集
- [.NET Framework 4.8](https://dotnet.microsoft.com/download/dotnet-framework/net48)

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
docs/sponsor/nyancat.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

2
modes

Submodule modes updated: cff55c0541...6c2c744529