Skip to content

Commit

Permalink
Merge pull request #8 from LeoChen98/feat-blacklist
Browse files Browse the repository at this point in the history
feat: Add blacklist support.
  • Loading branch information
LeoChen98 authored Dec 6, 2024
2 parents ceeaf12 + 0d6c685 commit 7ea79d2
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 7 deletions.
2 changes: 1 addition & 1 deletion ClashYamlParser/ClashYamlParser.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Company>zhangbudademao.com</Company>
<Copyright>Copyrights © 2024 zhangbudademao.com all rights reserved.</Copyright>
<Version>$(AssemblyVersion)</Version>
<AssemblyVersion>1.1.5.8</AssemblyVersion>
<AssemblyVersion>1.1.6.9</AssemblyVersion>
<VersionPrefix>$(AssemblyVersion)</VersionPrefix>
<VersionSuffix></VersionSuffix>
<FileVersion>$(AssemblyVersion)</FileVersion>
Expand Down
67 changes: 62 additions & 5 deletions ClashYamlParser/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@

ConcurrentQueue<string> log_temp = new();
string log_file = $"logs\\{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}.log";
List<string> blacklist = [];

await log($"{Assembly.GetExecutingAssembly().GetName().Version}", "version");
Timer log_wraper = new(async (o) => { await WrapLogAsync(); }, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
Timer blacklist_refresher = new(async (o) => { await LoadBlacklist(); }, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));

HttpListener server = new HttpListener();
server.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
Expand All @@ -33,6 +35,38 @@ await Task.Run(async () =>
await log("Application exited.", flush: true);
});

async Task LoadBlacklist()
{
if (!File.Exists("blacklist.txt"))
{
return;
}

string[] backup = new string[blacklist.Capacity];
blacklist.CopyTo(backup);
blacklist = new(blacklist.Capacity);
try
{
using HttpClient httpClient = new();
Regex regex = RegexDomain();
foreach (string line in await File.ReadAllLinesAsync("blacklist.txt"))
{
HttpResponseMessage response = await httpClient.GetAsync(line);
if (response.IsSuccessStatusCode)
{
foreach (Match m in regex.Matches(await response.Content.ReadAsStringAsync()))
{
blacklist.Add(string.Format("DOMAIN-SUFFIX,{0},REJECT", m.Value));
}
}
}
}
catch
{
blacklist = [.. backup];
}
}

async Task WrapLogAsync()
{
StringBuilder sb = new StringBuilder();
Expand Down Expand Up @@ -160,11 +194,10 @@ void SendResponseString(HttpListenerContext context, string? str_data = null, in

async Task<(string, string, string)> GetOriginYAMLAsync(string url)
{
using (HttpClient httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(url);
return (await response.Content.ReadAsStringAsync(), response.Content.Headers.ContentDisposition?.FileName ?? "clash.xaml", response.Headers.GetValues("Subscription-Userinfo").First());
}
using HttpClient httpClient = new();
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
return (await response.Content.ReadAsStringAsync(), response.Content.Headers.ContentDisposition?.FileName ?? "clash.xaml", response.Headers.GetValues("Subscription-Userinfo").First());
}

string CombineYAML(string origin_YAML, string parser_YAML)
Expand Down Expand Up @@ -199,9 +232,23 @@ string CombineYAML(string origin_YAML, string parser_YAML)
MergeConfig("rule-providers", parserDict, ref originDict);
MixObject(parserDict, ref originDict);

AddAdBlocker(ref originDict);

return serializer.Serialize(originDict);
}

void AddAdBlocker(ref Dictionary<string, object> originDict)
{
if (!originDict.TryGetValue("rules", out object? value))
{
originDict.Add("rules", blacklist);
}
else
{
(value as List<object>)!.InsertRange(0, blacklist);
}
}

void MergeConfig(string type, Dictionary<object, object> parserDict, ref Dictionary<string, object> originDict)
{
if (originDict.ContainsKey(type))
Expand Down Expand Up @@ -272,4 +319,14 @@ void MixObject(Dictionary<object, object> parserDict, ref Dictionary<string, obj
log($"mix-object: {obj.Key} failed, skipped.", "warning", true).GetAwaiter().GetResult();
}
}
}

partial class Program
{
#region Private Methods

[GeneratedRegex(@"\b((?:(?:[a-zA-Z0-9-]{1,63}\.)+(?:[a-zA-Z]{2,})))\b")]
private static partial Regex RegexDomain();

#endregion Private Methods
}
5 changes: 4 additions & 1 deletion README-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@
- 仅在 `Clash for Windows``Clash for Android`中测试通过。理论上可用于Clash的所有分支版本

## 开始使用
*一下提到的所有路径均为相对于 `ClashYamlParser.exe` 的根目录*.
*以下提到的所有路径均为相对于 `ClashYamlParser.exe` 的根目录*.
- 下载 [最新的发行](https://github.com/LeoChen98/ClashYamlParser/releases/latest) 文件。
- 根据 [Microsoft Learn](https://learn.microsoft.com/zh-cn/dotnet/fundamentals/runtime-libraries/system-net-httplistener) 的格式设置`domain.txt`,每行一个域名。
- 从Clash for Windows中复制parsers配置,新建并粘贴到 `parser.yaml`中。
- (如果需要使用SSL连接)使用 `netsh` 工具将对应证书绑定到端口。
- 用管理员权限运行 `ClashYamlParser.exe`
- 通过URL订阅配置。例如: `http(s)://example.com:port/clash/?url=your origin clash profile url`.

- *(可选)设置黑名单*:在运行目录中新建`blacklist.txt`文件,并向其中添加黑名单列表地址。(每行一个,仅支持http(s)地址,列表文件中所有符合域名规则的域名都会被加入黑名单,请注意不要采用携带其他信息的列表)


## 贡献
欢迎提出Issue和Pull Request,最好是直接提Pull Request。(懒死了.jpg)

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
- (If SSL connection needed) Bind the cert with the port using `netsh` tool.
- Run `ClashYamlParser.exe` with Administrator permission.
- Subcribe the profile via URL. Example: `http(s)://example.com:port/clash/?url=your origin clash profile url`.
- *(Optional)Add black list:* Add `blacklist.txt` under excutepath, list your blacklist source one each line.(Only http(s)link is supported, and all domain names in the list file that comply with domain name rules will be added to the blacklist.)

## How to contribute
Issues and pull requests are both welcome, **pull requests prefered**.
Expand Down

0 comments on commit 7ea79d2

Please sign in to comment.