Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec627bdb82 | ||
|
|
4606e78570 | ||
|
|
f00e968b8f | ||
|
|
a87a015c03 | ||
|
|
c559914ff7 | ||
|
|
436d95576e | ||
|
|
54e83391d0 | ||
|
|
3e0578f775 | ||
|
|
29a5abf4d6 | ||
|
|
b54c67d6f1 | ||
|
|
b49486cc23 | ||
|
|
b95830b3d5 | ||
|
|
8e0c5cb9aa |
@@ -28,7 +28,7 @@ Package: v2rayN
|
|||||||
Version: $Version
|
Version: $Version
|
||||||
Architecture: $Arch2
|
Architecture: $Arch2
|
||||||
Maintainer: https://github.com/2dust/v2rayN
|
Maintainer: https://github.com/2dust/v2rayN
|
||||||
Depends: desktop-file-utils
|
Depends: desktop-file-utils, xdg-utils
|
||||||
Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# ===== Require Red Hat Enterprise Linux/RockyLinux/AlmaLinux/CentOS OR Ubuntu/Debian ====
|
# == Require Red Hat Enterprise Linux/FedoraLinux/RockyLinux/AlmaLinux/CentOS OR Ubuntu/Debian ==
|
||||||
if [[ -r /etc/os-release ]]; then
|
if [[ -r /etc/os-release ]]; then
|
||||||
. /etc/os-release
|
. /etc/os-release
|
||||||
case "$ID" in
|
case "$ID" in
|
||||||
rhel|rocky|almalinux|centos|ubuntu|debian)
|
rhel|rocky|almalinux|fedora|centos|ubuntu|debian)
|
||||||
echo "[OK] Detected supported system: $NAME $VERSION_ID"
|
echo "[OK] Detected supported system: $NAME $VERSION_ID"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -390,25 +390,30 @@ download_mihomo() {
|
|||||||
chmod +x "$outroot/bin/mihomo/mihomo" || true
|
chmod +x "$outroot/bin/mihomo/mihomo" || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Move geo files to a unified path: outroot/bin/xray/
|
# Move geo files to a unified path: outroot/bin
|
||||||
unify_geo_layout() {
|
unify_geo_layout() {
|
||||||
local outroot="$1"
|
local outroot="$1"
|
||||||
mkdir -p "$outroot/bin/xray"
|
mkdir -p "$outroot/bin"
|
||||||
local srcs=( \
|
local names=( \
|
||||||
"$outroot/bin/geosite.dat" \
|
"geosite.dat" \
|
||||||
"$outroot/bin/geoip.dat" \
|
"geoip.dat" \
|
||||||
"$outroot/bin/geoip-only-cn-private.dat" \
|
"geoip-only-cn-private.dat" \
|
||||||
"$outroot/bin/Country.mmdb" \
|
"Country.mmdb" \
|
||||||
"$outroot/bin/geoip.metadb" \
|
"geoip.metadb" \
|
||||||
)
|
)
|
||||||
for s in "${srcs[@]}"; do
|
for n in "${names[@]}"; do
|
||||||
if [[ -f "$s" ]]; then
|
# If file exists under bin/xray/, move it up to bin/
|
||||||
mv -f "$s" "$outroot/bin/xray/$(basename "$s")"
|
if [[ -f "$outroot/bin/xray/$n" ]]; then
|
||||||
|
mv -f "$outroot/bin/xray/$n" "$outroot/bin/$n"
|
||||||
|
fi
|
||||||
|
# If file already in bin/, leave it as-is
|
||||||
|
if [[ -f "$outroot/bin/$n" ]]; then
|
||||||
|
:
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# Download geo/rule assets; then unify to bin/xray/
|
# Download geo/rule assets; then unify to bin/
|
||||||
download_geo_assets() {
|
download_geo_assets() {
|
||||||
local outroot="$1"
|
local outroot="$1"
|
||||||
local bin_dir="$outroot/bin"
|
local bin_dir="$outroot/bin"
|
||||||
@@ -442,7 +447,7 @@ download_geo_assets() {
|
|||||||
"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-geosite/$f" || true
|
"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-geosite/$f" || true
|
||||||
done
|
done
|
||||||
|
|
||||||
# Unify to bin/xray/
|
# Unify to bin/
|
||||||
unify_geo_layout "$outroot"
|
unify_geo_layout "$outroot"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,7 +485,7 @@ download_v2rayn_bundle() {
|
|||||||
rm -rf "$nested_dir"
|
rm -rf "$nested_dir"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Unify to bin/xray/
|
# Unify to bin/
|
||||||
unify_geo_layout "$outroot"
|
unify_geo_layout "$outroot"
|
||||||
|
|
||||||
echo "[+] Bundle extracted to $outroot"
|
echo "[+] Bundle extracted to $outroot"
|
||||||
@@ -610,7 +615,7 @@ Source0: __PKGROOT__.tar.gz
|
|||||||
|
|
||||||
# Runtime dependencies (Avalonia / X11 / Fonts / GL)
|
# Runtime dependencies (Avalonia / X11 / Fonts / GL)
|
||||||
Requires: libX11, libXrandr, libXcursor, libXi, libXext, libxcb, libXrender, libXfixes, libXinerama, libxkbcommon
|
Requires: libX11, libXrandr, libXcursor, libXi, libXext, libxcb, libXrender, libXfixes, libXinerama, libxkbcommon
|
||||||
Requires: fontconfig, freetype, cairo, pango, mesa-libEGL, mesa-libGL
|
Requires: fontconfig, freetype, cairo, pango, mesa-libEGL, mesa-libGL, xdg-utils
|
||||||
|
|
||||||
%description
|
%description
|
||||||
v2rayN Linux for Red Hat Enterprise Linux
|
v2rayN Linux for Red Hat Enterprise Linux
|
||||||
@@ -629,25 +634,13 @@ https://github.com/2dust/v2rayN
|
|||||||
install -dm0755 %{buildroot}/opt/v2rayN
|
install -dm0755 %{buildroot}/opt/v2rayN
|
||||||
cp -a * %{buildroot}/opt/v2rayN/
|
cp -a * %{buildroot}/opt/v2rayN/
|
||||||
|
|
||||||
# Launcher (prefer native ELF first, then DLL fallback; also create Geo symlinks for the user)
|
# Launcher (prefer native ELF first, then DLL fallback)
|
||||||
install -dm0755 %{buildroot}%{_bindir}
|
install -dm0755 %{buildroot}%{_bindir}
|
||||||
cat > %{buildroot}%{_bindir}/v2rayn << 'EOF'
|
cat > %{buildroot}%{_bindir}/v2rayn << 'EOF'
|
||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
DIR="/opt/v2rayN"
|
DIR="/opt/v2rayN"
|
||||||
|
|
||||||
# --- Symlink GEO files into user's XDG dir (first-run convenience) ---
|
|
||||||
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
|
||||||
USR_GEO_DIR="$XDG_DATA_HOME/v2rayN/bin"
|
|
||||||
SYS_XRAY_DIR="$DIR/bin/xray"
|
|
||||||
mkdir -p "$USR_GEO_DIR"
|
|
||||||
for f in geosite.dat geoip.dat geoip-only-cn-private.dat Country.mmdb; do
|
|
||||||
if [[ -f "$SYS_XRAY_DIR/$f" && ! -e "$USR_GEO_DIR/$f" ]]; then
|
|
||||||
ln -s "$SYS_XRAY_DIR/$f" "$USR_GEO_DIR/$f" || true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
# --- end GEO ---
|
|
||||||
|
|
||||||
# Prefer native apphost
|
# Prefer native apphost
|
||||||
if [[ -x "$DIR/v2rayN" ]]; then exec "$DIR/v2rayN" "$@"; fi
|
if [[ -x "$DIR/v2rayN" ]]; then exec "$DIR/v2rayN" "$@"; fi
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.14.8</Version>
|
<Version>7.14.10</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.5" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.6" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.5" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.3.6" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.5" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.6" />
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.5" />
|
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.6" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
||||||
<PackageVersion Include="Downloader" Version="4.0.3" />
|
<PackageVersion Include="Downloader" Version="4.0.3" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
||||||
|
|||||||
@@ -9,6 +9,31 @@ public class JsonUtils
|
|||||||
{
|
{
|
||||||
private static readonly string _tag = "JsonUtils";
|
private static readonly string _tag = "JsonUtils";
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions _defaultDeserializeOptions = new()
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true,
|
||||||
|
ReadCommentHandling = JsonCommentHandling.Skip
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions _defaultSerializeOptions = new()
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions _nullValueSerializeOptions = new()
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly JsonDocumentOptions _defaultDocumentOptions = new()
|
||||||
|
{
|
||||||
|
CommentHandling = JsonCommentHandling.Skip
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DeepCopy
|
/// DeepCopy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -34,11 +59,7 @@ public class JsonUtils
|
|||||||
{
|
{
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
var options = new JsonSerializerOptions
|
return JsonSerializer.Deserialize<T>(strJson, _defaultDeserializeOptions);
|
||||||
{
|
|
||||||
PropertyNameCaseInsensitive = true
|
|
||||||
};
|
|
||||||
return JsonSerializer.Deserialize<T>(strJson, options);
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -59,7 +80,7 @@ public class JsonUtils
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return JsonNode.Parse(strJson);
|
return JsonNode.Parse(strJson, nodeOptions: null, _defaultDocumentOptions);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -84,12 +105,7 @@ public class JsonUtils
|
|||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
var options = new JsonSerializerOptions
|
var options = nullValue ? _nullValueSerializeOptions : _defaultSerializeOptions;
|
||||||
{
|
|
||||||
WriteIndented = indented,
|
|
||||||
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
};
|
|
||||||
result = JsonSerializer.Serialize(obj, options);
|
result = JsonSerializer.Serialize(obj, options);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -331,6 +331,32 @@ public class Utils
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Dictionary<string, List<string>> ParseHostsToDictionary(string hostsContent)
|
||||||
|
{
|
||||||
|
var userHostsMap = hostsContent
|
||||||
|
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(line => line.Trim())
|
||||||
|
// skip full-line comments
|
||||||
|
.Where(line => !string.IsNullOrWhiteSpace(line) && !line.StartsWith("#"))
|
||||||
|
// strip inline comments (truncate at '#')
|
||||||
|
.Select(line =>
|
||||||
|
{
|
||||||
|
var index = line.IndexOf('#');
|
||||||
|
return index >= 0 ? line.Substring(0, index).Trim() : line;
|
||||||
|
})
|
||||||
|
// ensure line still contains valid parts
|
||||||
|
.Where(line => !string.IsNullOrWhiteSpace(line) && line.Contains(' '))
|
||||||
|
.Select(line => line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
.Where(parts => parts.Length >= 2)
|
||||||
|
.GroupBy(parts => parts[0])
|
||||||
|
.ToDictionary(
|
||||||
|
group => group.Key,
|
||||||
|
group => group.SelectMany(parts => parts.Skip(1)).ToList()
|
||||||
|
);
|
||||||
|
|
||||||
|
return userHostsMap;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion 转换函数
|
#endregion 转换函数
|
||||||
|
|
||||||
#region 数据检查
|
#region 数据检查
|
||||||
@@ -857,6 +883,55 @@ public class Utils
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsPackagedInstall()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (IsWindows() || IsOSX())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPIMAGE")))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var exePath = GetExePath();
|
||||||
|
var baseDir = string.IsNullOrEmpty(exePath) ? StartupPath() : Path.GetDirectoryName(exePath) ?? "";
|
||||||
|
var p = baseDir.Replace('\\', '/');
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(p))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.Contains("/.mount_", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.StartsWith("/opt/v2rayN", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.StartsWith("/usr/lib/v2rayN", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.StartsWith("/usr/share/v2rayN", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task<string?> GetLinuxUserId()
|
private static async Task<string?> GetLinuxUserId()
|
||||||
{
|
{
|
||||||
var arg = new List<string>() { "-c", "id -u" };
|
var arg = new List<string>() { "-c", "id -u" };
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ public class ClashFmt : BaseFmt
|
|||||||
{
|
{
|
||||||
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
{
|
{
|
||||||
if (Contains(strData, "port", "socks-port", "proxies"))
|
if (Contains(strData, "external-controller", "-port", "proxies"))
|
||||||
{
|
{
|
||||||
var fileName = WriteAllText(strData, "yaml");
|
var fileName = WriteAllText(strData, "yaml");
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
using ReactiveUI;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
public class CheckUpdateModel
|
public class CheckUpdateModel : ReactiveObject
|
||||||
{
|
{
|
||||||
public bool? IsSelected { get; set; }
|
public bool? IsSelected { get; set; }
|
||||||
public string? CoreType { get; set; }
|
public string? CoreType { get; set; }
|
||||||
public string? Remarks { get; set; }
|
[Reactive] public string? Remarks { get; set; }
|
||||||
public string? FileName { get; set; }
|
public string? FileName { get; set; }
|
||||||
public bool? IsFinished { get; set; }
|
public bool? IsFinished { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
using ReactiveUI;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
|
||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ClashProxyModel
|
public class ClashProxyModel : ReactiveObject
|
||||||
{
|
{
|
||||||
public string? Name { get; set; }
|
public string? Name { get; set; }
|
||||||
|
|
||||||
@@ -9,9 +12,9 @@ public class ClashProxyModel
|
|||||||
|
|
||||||
public string? Now { get; set; }
|
public string? Now { get; set; }
|
||||||
|
|
||||||
public int Delay { get; set; }
|
[Reactive] public int Delay { get; set; }
|
||||||
|
|
||||||
public string? DelayName { get; set; }
|
[Reactive] public string? DelayName { get; set; }
|
||||||
|
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,17 +94,7 @@ public partial class CoreConfigSingboxService
|
|||||||
|
|
||||||
if (!simpleDNSItem.Hosts.IsNullOrEmpty())
|
if (!simpleDNSItem.Hosts.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
var userHostsMap = simpleDNSItem.Hosts
|
var userHostsMap = Utils.ParseHostsToDictionary(simpleDNSItem.Hosts);
|
||||||
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(line => line.Trim())
|
|
||||||
.Where(line => !string.IsNullOrWhiteSpace(line) && line.Contains(' '))
|
|
||||||
.Select(line => line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries))
|
|
||||||
.Where(parts => parts.Length >= 2)
|
|
||||||
.GroupBy(parts => parts[0])
|
|
||||||
.ToDictionary(
|
|
||||||
group => group.Key,
|
|
||||||
group => group.SelectMany(parts => parts.Skip(1)).ToList()
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach (var kvp in userHostsMap)
|
foreach (var kvp in userHostsMap)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -71,6 +71,31 @@ public partial class CoreConfigSingboxService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hostsDomains = new List<string>();
|
||||||
|
var systemHostsMap = Utils.GetSystemHosts();
|
||||||
|
foreach (var kvp in systemHostsMap)
|
||||||
|
{
|
||||||
|
hostsDomains.Add(kvp.Key);
|
||||||
|
}
|
||||||
|
var dnsItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box);
|
||||||
|
if (dnsItem == null || dnsItem.Enabled == false)
|
||||||
|
{
|
||||||
|
var simpleDNSItem = _config.SimpleDNSItem;
|
||||||
|
if (!simpleDNSItem.Hosts.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
var userHostsMap = Utils.ParseHostsToDictionary(simpleDNSItem.Hosts);
|
||||||
|
foreach (var kvp in userHostsMap)
|
||||||
|
{
|
||||||
|
hostsDomains.Add(kvp.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
singboxConfig.route.rules.Add(new()
|
||||||
|
{
|
||||||
|
action = "resolve",
|
||||||
|
domain = hostsDomains,
|
||||||
|
});
|
||||||
|
|
||||||
singboxConfig.route.rules.Add(new()
|
singboxConfig.route.rules.Add(new()
|
||||||
{
|
{
|
||||||
outbound = Global.DirectTag,
|
outbound = Global.DirectTag,
|
||||||
@@ -343,6 +368,13 @@ public partial class CoreConfigSingboxService
|
|||||||
return Global.ProxyTag;
|
return Global.ProxyTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tag = Global.ProxyTag + node.IndexId.ToString();
|
||||||
|
if (singboxConfig.outbounds.Any(o => o.tag == tag)
|
||||||
|
|| (singboxConfig.endpoints != null && singboxConfig.endpoints.Any(e => e.tag == tag)))
|
||||||
|
{
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
var server = await GenServer(node);
|
var server = await GenServer(node);
|
||||||
if (server is null)
|
if (server is null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -261,17 +261,7 @@ public partial class CoreConfigV2rayService
|
|||||||
|
|
||||||
if (!simpleDNSItem.Hosts.IsNullOrEmpty())
|
if (!simpleDNSItem.Hosts.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
var userHostsMap = simpleDNSItem.Hosts
|
var userHostsMap = Utils.ParseHostsToDictionary(simpleDNSItem.Hosts);
|
||||||
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(line => line.Trim())
|
|
||||||
.Where(line => !string.IsNullOrWhiteSpace(line) && line.Contains(' '))
|
|
||||||
.Select(line => line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries))
|
|
||||||
.Where(parts => parts.Length >= 2)
|
|
||||||
.GroupBy(parts => parts[0])
|
|
||||||
.ToDictionary(
|
|
||||||
group => group.Key,
|
|
||||||
group => group.SelectMany(parts => parts.Skip(1)).ToList()
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach (var kvp in userHostsMap)
|
foreach (var kvp in userHostsMap)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -131,10 +131,16 @@ public partial class CoreConfigV2rayService
|
|||||||
return Global.ProxyTag;
|
return Global.ProxyTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tag = Global.ProxyTag + node.IndexId.ToString();
|
||||||
|
if (v2rayConfig.outbounds.Any(p => p.tag == tag))
|
||||||
|
{
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
await GenOutbound(node, outbound);
|
await GenOutbound(node, outbound);
|
||||||
outbound.tag = Global.ProxyTag + node.IndexId.ToString();
|
outbound.tag = tag;
|
||||||
v2rayConfig.outbounds.Add(outbound);
|
v2rayConfig.outbounds.Add(outbound);
|
||||||
|
|
||||||
return outbound.tag;
|
return outbound.tag;
|
||||||
|
|||||||
@@ -63,6 +63,16 @@ public class CheckUpdateViewModel : MyReactiveObject
|
|||||||
|
|
||||||
private CheckUpdateModel GetCheckUpdateModel(string coreType)
|
private CheckUpdateModel GetCheckUpdateModel(string coreType)
|
||||||
{
|
{
|
||||||
|
if (coreType == _v2rayN && Utils.IsPackagedInstall())
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
IsSelected = false,
|
||||||
|
CoreType = coreType,
|
||||||
|
Remarks = ResUI.menuCheckUpdate + " (Not Support)",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
IsSelected = _config.CheckUpdateItem.SelectedCoreTypes?.Contains(coreType) ?? true,
|
IsSelected = _config.CheckUpdateItem.SelectedCoreTypes?.Contains(coreType) ?? true,
|
||||||
@@ -104,6 +114,11 @@ public class CheckUpdateViewModel : MyReactiveObject
|
|||||||
}
|
}
|
||||||
else if (item.CoreType == _v2rayN)
|
else if (item.CoreType == _v2rayN)
|
||||||
{
|
{
|
||||||
|
if (Utils.IsPackagedInstall())
|
||||||
|
{
|
||||||
|
await UpdateView(_v2rayN, "Not Support");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
await CheckUpdateN(EnableCheckPreReleaseUpdate);
|
await CheckUpdateN(EnableCheckPreReleaseUpdate);
|
||||||
}
|
}
|
||||||
else if (item.CoreType == ECoreType.Xray.ToString())
|
else if (item.CoreType == ECoreType.Xray.ToString())
|
||||||
@@ -334,9 +349,6 @@ public class CheckUpdateViewModel : MyReactiveObject
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
found.Remarks = model.Remarks;
|
||||||
var itemCopy = JsonUtils.DeepCopy(found);
|
|
||||||
itemCopy.Remarks = model.Remarks;
|
|
||||||
CheckUpdateModels.Replace(found, itemCopy);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -391,7 +391,6 @@ public class ClashProxiesViewModel : MyReactiveObject
|
|||||||
|
|
||||||
public async Task ProxiesDelayTestResult(SpeedTestResult result)
|
public async Task ProxiesDelayTestResult(SpeedTestResult result)
|
||||||
{
|
{
|
||||||
//UpdateHandler(false, $"{item.name}={result}");
|
|
||||||
var detail = ProxyDetails.FirstOrDefault(it => it.Name == result.IndexId);
|
var detail = ProxyDetails.FirstOrDefault(it => it.Name == result.IndexId);
|
||||||
if (detail == null)
|
if (detail == null)
|
||||||
{
|
{
|
||||||
@@ -414,7 +413,6 @@ public class ClashProxiesViewModel : MyReactiveObject
|
|||||||
detail.Delay = _delayTimeout;
|
detail.Delay = _delayTimeout;
|
||||||
detail.DelayName = string.Empty;
|
detail.DelayName = string.Empty;
|
||||||
}
|
}
|
||||||
ProxyDetails.Replace(detail, JsonUtils.DeepCopy(detail));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion proxy function
|
#endregion proxy function
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ public class MainWindowViewModel : MyReactiveObject
|
|||||||
{
|
{
|
||||||
await StatisticsManager.Instance.Init(_config, UpdateStatisticsHandler);
|
await StatisticsManager.Instance.Init(_config, UpdateStatisticsHandler);
|
||||||
}
|
}
|
||||||
|
await RefreshServers();
|
||||||
|
|
||||||
BlReloadEnabled = true;
|
BlReloadEnabled = true;
|
||||||
await Reload();
|
await Reload();
|
||||||
@@ -487,7 +488,7 @@ public class MainWindowViewModel : MyReactiveObject
|
|||||||
}
|
}
|
||||||
else if (Utils.IsLinux())
|
else if (Utils.IsLinux())
|
||||||
{
|
{
|
||||||
ProcUtils.ProcessStart("nautilus", path);
|
ProcUtils.ProcessStart("xdg-open", path);
|
||||||
}
|
}
|
||||||
else if (Utils.IsOSX())
|
else if (Utils.IsOSX())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
SelectedMoveToGroup = new();
|
SelectedMoveToGroup = new();
|
||||||
|
|
||||||
await RefreshSubscriptions();
|
await RefreshSubscriptions();
|
||||||
await RefreshServers();
|
//await RefreshServers();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Init
|
#endregion Init
|
||||||
@@ -293,7 +293,6 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
{
|
{
|
||||||
item.SpeedVal = result.Speed ?? string.Empty;
|
item.SpeedVal = result.Speed ?? string.Empty;
|
||||||
}
|
}
|
||||||
//_profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateStatistics(ServerSpeedItem update)
|
public async Task UpdateStatistics(ServerSpeedItem update)
|
||||||
@@ -314,17 +313,6 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
item.TodayUp = Utils.HumanFy(update.TodayUp);
|
item.TodayUp = Utils.HumanFy(update.TodayUp);
|
||||||
item.TotalDown = Utils.HumanFy(update.TotalDown);
|
item.TotalDown = Utils.HumanFy(update.TotalDown);
|
||||||
item.TotalUp = Utils.HumanFy(update.TotalUp);
|
item.TotalUp = Utils.HumanFy(update.TotalUp);
|
||||||
|
|
||||||
//if (SelectedProfile?.IndexId == item.IndexId)
|
|
||||||
//{
|
|
||||||
// var temp = JsonUtils.DeepCopy(item);
|
|
||||||
// _profileItems.Replace(item, temp);
|
|
||||||
// SelectedProfile = temp;
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// _profileItems.Replace(item, JsonUtils.DeepCopy(item));
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|||||||
@@ -400,7 +400,7 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="400"
|
Width="400"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Watermark="1000:2000,3000:4000" />
|
Watermark="1000-2000,3000,4000" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
|
|||||||
@@ -38,9 +38,10 @@
|
|||||||
<WrapPanel Margin="4" DockPanel.Dock="Top">
|
<WrapPanel Margin="4" DockPanel.Dock="Top">
|
||||||
<ListBox
|
<ListBox
|
||||||
x:Name="lstGroup"
|
x:Name="lstGroup"
|
||||||
Margin="4,0"
|
Margin="{StaticResource MarginLr4}"
|
||||||
DisplayMemberBinding="{Binding Remarks}"
|
DisplayMemberBinding="{Binding Remarks}"
|
||||||
ItemsSource="{Binding SubItems}">
|
ItemsSource="{Binding SubItems}"
|
||||||
|
Theme="{DynamicResource ButtonRadioGroupListBox}">
|
||||||
<ListBox.ItemsPanel>
|
<ListBox.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<WrapPanel />
|
<WrapPanel />
|
||||||
@@ -89,20 +90,11 @@
|
|||||||
Binding="{Binding ConfigType}"
|
Binding="{Binding ConfigType}"
|
||||||
Header="{x:Static resx:ResUI.LvServiceType}"
|
Header="{x:Static resx:ResUI.LvServiceType}"
|
||||||
Tag="ConfigType" />
|
Tag="ConfigType" />
|
||||||
|
<DataGridTextColumn
|
||||||
<DataGridTemplateColumn SortMemberPath="Remarks" Tag="Remarks">
|
Width="120"
|
||||||
<DataGridTemplateColumn.Header>
|
Binding="{Binding Remarks}"
|
||||||
<TextBlock Text="{x:Static resx:ResUI.LvRemarks}" />
|
Header="{x:Static resx:ResUI.LvRemarks}"
|
||||||
</DataGridTemplateColumn.Header>
|
Tag="Remarks" />
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<StackPanel Margin="8,0" Orientation="Horizontal">
|
|
||||||
<TextBlock Text="{Binding Remarks}" />
|
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
|
||||||
</DataGridTemplateColumn>
|
|
||||||
|
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Width="120"
|
Width="120"
|
||||||
Binding="{Binding Address}"
|
Binding="{Binding Address}"
|
||||||
|
|||||||
@@ -112,7 +112,6 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
|||||||
});
|
});
|
||||||
|
|
||||||
RestoreUI();
|
RestoreUI();
|
||||||
ViewModel?.RefreshServers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void LstProfiles_Sorting(object? sender, DataGridColumnEventArgs e)
|
private async void LstProfiles_Sorting(object? sender, DataGridColumnEventArgs e)
|
||||||
|
|||||||
@@ -176,6 +176,7 @@
|
|||||||
<DataGrid
|
<DataGrid
|
||||||
x:Name="lstRules"
|
x:Name="lstRules"
|
||||||
AutoGenerateColumns="False"
|
AutoGenerateColumns="False"
|
||||||
|
Background="Transparent"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CanUserResizeColumns="True"
|
CanUserResizeColumns="True"
|
||||||
GridLinesVisibility="All"
|
GridLinesVisibility="All"
|
||||||
|
|||||||
@@ -92,6 +92,7 @@
|
|||||||
<DataGrid
|
<DataGrid
|
||||||
x:Name="lstRoutings"
|
x:Name="lstRoutings"
|
||||||
AutoGenerateColumns="False"
|
AutoGenerateColumns="False"
|
||||||
|
Background="Transparent"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CanUserResizeColumns="True"
|
CanUserResizeColumns="True"
|
||||||
GridLinesVisibility="All"
|
GridLinesVisibility="All"
|
||||||
|
|||||||
@@ -538,7 +538,7 @@
|
|||||||
Width="400"
|
Width="400"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
materialDesign:HintAssist.Hint="1000:2000,3000:4000"
|
materialDesign:HintAssist.Hint="1000-2000,3000,4000"
|
||||||
Style="{StaticResource DefTextBox}" />
|
Style="{StaticResource DefTextBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ public partial class ProfilesView
|
|||||||
});
|
});
|
||||||
|
|
||||||
RestoreUI();
|
RestoreUI();
|
||||||
ViewModel?.RefreshServers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Event
|
#region Event
|
||||||
|
|||||||
@@ -122,6 +122,8 @@ public partial class RoutingRuleSettingWindow
|
|||||||
|
|
||||||
private void RoutingRuleSettingWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
private void RoutingRuleSettingWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (!lstRules.IsKeyboardFocusWithin)
|
||||||
|
return;
|
||||||
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||||
{
|
{
|
||||||
if (e.Key == Key.A)
|
if (e.Key == Key.A)
|
||||||
|
|||||||
Reference in New Issue
Block a user