Merge tag '7.15.7'
This commit is contained in:
106
.github/workflows/build-linux.yml
vendored
106
.github/workflows/build-linux.yml
vendored
@@ -9,6 +9,12 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- 'v*'
|
||||
- 'V*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
OutputArch: "linux-64"
|
||||
@@ -21,7 +27,6 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [Release]
|
||||
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
@@ -31,7 +36,7 @@ jobs:
|
||||
submodules: 'recursive'
|
||||
fetch-depth: '0'
|
||||
|
||||
- name: Setup
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5.0.0
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
@@ -39,13 +44,13 @@ jobs:
|
||||
- name: Build
|
||||
run: |
|
||||
cd v2rayN
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained=true -o $OutputPath64
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained=true -o $OutputPathArm64
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 --self-contained=true -p:PublishTrimmed=true -o $OutputPath64
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained=true -o "$OutputPath64"
|
||||
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained=true -o "$OutputPathArm64"
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 --self-contained=true -p:PublishTrimmed=true -o "$OutputPath64"
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishTrimmed=true -o "$OutputPathArm64"
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
uses: actions/upload-artifact@v5.0.0
|
||||
with:
|
||||
name: v2rayN-linux
|
||||
path: |
|
||||
@@ -56,8 +61,8 @@ jobs:
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
chmod 755 package-debian.sh
|
||||
./package-debian.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }}
|
||||
./package-debian.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }}
|
||||
./package-debian.sh "$OutputArch" "$OutputPath64" "${{ github.event.inputs.release_tag }}"
|
||||
./package-debian.sh "$OutputArchArm" "$OutputPathArm64" "${{ github.event.inputs.release_tag }}"
|
||||
|
||||
- name: Upload deb to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
@@ -68,28 +73,13 @@ jobs:
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
|
||||
- name: Package AppImage
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
chmod a+x package-appimage.sh
|
||||
./package-appimage.sh
|
||||
|
||||
- name: Upload AppImage to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
if: github.event.inputs.release_tag != ''
|
||||
with:
|
||||
file: ${{ github.workspace }}/v2rayN*.AppImage
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
|
||||
# release zip archive
|
||||
- name: Package release zip archive
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
chmod 755 package-release-zip.sh
|
||||
./package-release-zip.sh $OutputArch $OutputPath64
|
||||
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
||||
./package-release-zip.sh "$OutputArch" "$OutputPath64"
|
||||
./package-release-zip.sh "$OutputArchArm" "$OutputPathArm64"
|
||||
|
||||
- name: Upload zip archive to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
@@ -100,36 +90,62 @@ jobs:
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
|
||||
# release RHEL package
|
||||
- name: Package RPM (RHEL-family)
|
||||
if: github.event.inputs.release_tag != ''
|
||||
rpm:
|
||||
needs: build
|
||||
if: |
|
||||
(github.event_name == 'workflow_dispatch' && github.event.inputs.release_tag != '') ||
|
||||
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
|
||||
runs-on: ubuntu-24.04
|
||||
container:
|
||||
image: quay.io/almalinuxorg/10-base:latest
|
||||
options: --platform=linux/amd64/v2
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.inputs.release_tag != '' && github.event.inputs.release_tag || github.ref_name }}
|
||||
|
||||
steps:
|
||||
- name: Prepare tools (Red Hat)
|
||||
run: |
|
||||
chmod 755 package-rhel.sh
|
||||
# Build for both x86_64 and aarch64 in one go (explicit version passed; no --buildfrom)
|
||||
./package-rhel.sh "${{ github.event.inputs.release_tag }}" --arch all
|
||||
dnf -y makecache
|
||||
dnf -y install epel-release
|
||||
dnf -y install sudo git rpm-build rpmdevtools dnf-plugins-core rsync findutils tar gzip unzip which
|
||||
|
||||
- name: Checkout repo (for scripts)
|
||||
uses: actions/checkout@v5.0.0
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
fetch-depth: '0'
|
||||
|
||||
- name: Restore build artifacts
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: v2rayN-linux
|
||||
path: ${{ github.workspace }}/v2rayN/Release
|
||||
|
||||
- name: Ensure script permissions
|
||||
run: chmod 755 package-rhel.sh
|
||||
|
||||
- name: Package RPM (RHEL-family)
|
||||
run: ./package-rhel.sh "${RELEASE_TAG}" --arch all
|
||||
|
||||
- name: Collect RPMs into workspace
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
mkdir -p "${{ github.workspace }}/dist/rpm"
|
||||
rsync -av "$HOME/rpmbuild/RPMS/" "${{ github.workspace }}/dist/rpm/"
|
||||
# Rename to requested filenames
|
||||
find "${{ github.workspace }}/dist/rpm" -name "v2rayN-*-1.x86_64.rpm" -exec mv {} "${{ github.workspace }}/dist/rpm/v2rayN-linux-rhel-x64.rpm" \; || true
|
||||
find "${{ github.workspace }}/dist/rpm" -name "v2rayN-*-1.aarch64.rpm" -exec mv {} "${{ github.workspace }}/dist/rpm/v2rayN-linux-rhel-arm64.rpm" \; || true
|
||||
mkdir -p "$GITHUB_WORKSPACE/dist/rpm"
|
||||
rsync -av "$HOME/rpmbuild/RPMS/" "$GITHUB_WORKSPACE/dist/rpm/" || true
|
||||
find "$GITHUB_WORKSPACE/dist/rpm" -name "v2rayN-*-1*.x86_64.rpm" -exec mv {} "$GITHUB_WORKSPACE/dist/rpm/v2rayN-linux-rhel-64.rpm" \; || true
|
||||
find "$GITHUB_WORKSPACE/dist/rpm" -name "v2rayN-*-1*.aarch64.rpm" -exec mv {} "$GITHUB_WORKSPACE/dist/rpm/v2rayN-linux-rhel-arm64.rpm" \; || true
|
||||
echo "==== Dist tree ===="
|
||||
ls -R "$GITHUB_WORKSPACE/dist/rpm" || true
|
||||
|
||||
- name: Upload RPM artifacts
|
||||
if: github.event.inputs.release_tag != ''
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
uses: actions/upload-artifact@v5.0.0
|
||||
with:
|
||||
name: v2rayN-rpm
|
||||
path: |
|
||||
${{ github.workspace }}/dist/rpm/**/*.rpm
|
||||
path: dist/rpm/**/*.rpm
|
||||
|
||||
- name: Upload RPMs to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
if: github.event.inputs.release_tag != ''
|
||||
with:
|
||||
file: ${{ github.workspace }}/dist/rpm/**/*.rpm
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file: dist/rpm/**/*.rpm
|
||||
tag: ${{ env.RELEASE_TAG }}
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
|
||||
2
.github/workflows/build-osx.yml
vendored
2
.github/workflows/build-osx.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
uses: actions/upload-artifact@v5.0.0
|
||||
with:
|
||||
name: v2rayN-macos
|
||||
path: |
|
||||
|
||||
2
.github/workflows/build-windows-desktop.yml
vendored
2
.github/workflows/build-windows-desktop.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
uses: actions/upload-artifact@v5.0.0
|
||||
with:
|
||||
name: v2rayN-windows-desktop
|
||||
path: |
|
||||
|
||||
2
.github/workflows/build-windows.yml
vendored
2
.github/workflows/build-windows.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
uses: actions/upload-artifact@v5.0.0
|
||||
with:
|
||||
name: v2rayN-windows
|
||||
path: |
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Install deps
|
||||
sudo apt update -y
|
||||
sudo apt install -y libfuse2 wget file
|
||||
|
||||
# Get tools
|
||||
wget -qO appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
chmod +x appimagetool
|
||||
|
||||
# x86_64 AppDir
|
||||
APPDIR_X64="AppDir-x86_64"
|
||||
rm -rf "$APPDIR_X64"
|
||||
mkdir -p "$APPDIR_X64/usr/lib/v2rayN" "$APPDIR_X64/usr/bin" "$APPDIR_X64/usr/share/applications" "$APPDIR_X64/usr/share/pixmaps"
|
||||
cp -rf "$OutputPath64"/* "$APPDIR_X64/usr/lib/v2rayN" || true
|
||||
[ -f "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" ] && cp "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" "$APPDIR_X64/usr/share/pixmaps/v2rayN.png" || true
|
||||
[ -f "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" ] && cp "$APPDIR_X64/usr/lib/v2rayN/v2rayN.png" "$APPDIR_X64/v2rayN.png" || true
|
||||
|
||||
printf '%s\n' '#!/bin/sh' 'HERE="$(dirname "$(readlink -f "$0")")"' 'cd "$HERE/usr/lib/v2rayN"' 'exec "$HERE/usr/lib/v2rayN/v2rayN" "$@"' >"$APPDIR_X64/AppRun"
|
||||
chmod +x "$APPDIR_X64/AppRun"
|
||||
ln -sf usr/lib/v2rayN/v2rayN "$APPDIR_X64/usr/bin/v2rayN"
|
||||
cat >"$APPDIR_X64/v2rayN.desktop" <<EOF
|
||||
[Desktop Entry]
|
||||
Name=v2rayN
|
||||
Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||
Exec=v2rayN
|
||||
Icon=v2rayN
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Network;
|
||||
EOF
|
||||
install -Dm644 "$APPDIR_X64/v2rayN.desktop" "$APPDIR_X64/usr/share/applications/v2rayN.desktop"
|
||||
|
||||
ARCH=x86_64 ./appimagetool "$APPDIR_X64" "v2rayN-${OutputArch}.AppImage"
|
||||
file "v2rayN-${OutputArch}.AppImage" | grep -q 'x86-64'
|
||||
|
||||
# aarch64 AppDir
|
||||
APPDIR_ARM64="AppDir-aarch64"
|
||||
rm -rf "$APPDIR_ARM64"
|
||||
mkdir -p "$APPDIR_ARM64/usr/lib/v2rayN" "$APPDIR_ARM64/usr/bin" "$APPDIR_ARM64/usr/share/applications" "$APPDIR_ARM64/usr/share/pixmaps"
|
||||
cp -rf "$OutputPathArm64"/* "$APPDIR_ARM64/usr/lib/v2rayN" || true
|
||||
[ -f "$APPDIR_ARM64/usr/lib/v2rayN/v2rayN.png" ] && cp "$APPDIR_ARM64/usr/lib/v2rayN/v2rayN.png" "$APPDIR_ARM64/usr/share/pixmaps/v2rayN.png" || true
|
||||
[ -f "$APPDIR_ARM64/usr/lib/v2rayN/v2rayN.png" ] && cp "$APPDIR_ARM64/usr/lib/v2rayN/v2rayN.png" "$APPDIR_ARM64/v2rayN.png" || true
|
||||
|
||||
printf '%s\n' '#!/bin/sh' 'HERE="$(dirname "$(readlink -f "$0")")"' 'cd "$HERE/usr/lib/v2rayN"' 'exec "$HERE/usr/lib/v2rayN/v2rayN" "$@"' >"$APPDIR_ARM64/AppRun"
|
||||
chmod +x "$APPDIR_ARM64/AppRun"
|
||||
ln -sf usr/lib/v2rayN/v2rayN "$APPDIR_ARM64/usr/bin/v2rayN"
|
||||
cat >"$APPDIR_ARM64/v2rayN.desktop" <<EOF
|
||||
[Desktop Entry]
|
||||
Name=v2rayN
|
||||
Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||
Exec=v2rayN
|
||||
Icon=v2rayN
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Network;
|
||||
EOF
|
||||
install -Dm644 "$APPDIR_ARM64/v2rayN.desktop" "$APPDIR_ARM64/usr/share/applications/v2rayN.desktop"
|
||||
|
||||
# aarch64 runtime
|
||||
wget -qO runtime-aarch64 https://github.com/AppImage/AppImageKit/releases/download/continuous/runtime-aarch64
|
||||
chmod +x runtime-aarch64
|
||||
|
||||
# build aarch64 AppImage
|
||||
ARCH=aarch64 ./appimagetool --runtime-file ./runtime-aarch64 "$APPDIR_ARM64" "v2rayN-${OutputArchArm}.AppImage"
|
||||
file "v2rayN-${OutputArchArm}.AppImage" | grep -q 'ARM aarch64'
|
||||
@@ -45,7 +45,7 @@ Maintainer: Vlyaii <voronin9032n3@gmail.com>
|
||||
Homepage: https://git.vlyaii.ru/voronin9032/v2rayN
|
||||
Architecture: $Arch2
|
||||
Replaces: v2rayn
|
||||
Depends: libc6 (>= 2.35), desktop-file-utils, xdg-utils
|
||||
Depends: libc6 (>= 2.34), fontconfig (>= 2.13.1), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 8.32), bash (>= 5.1)
|
||||
Breaks: v2rayn
|
||||
Conflicts: v2rayn
|
||||
Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||
|
||||
@@ -19,6 +19,23 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ======================== Kernel version check (require >= 6.11) =======================
|
||||
MIN_KERNEL_MAJOR=6
|
||||
MIN_KERNEL_MINOR=11
|
||||
KERNEL_FULL=$(uname -r)
|
||||
KERNEL_MAJOR=$(echo "$KERNEL_FULL" | cut -d. -f1)
|
||||
KERNEL_MINOR=$(echo "$KERNEL_FULL" | cut -d. -f2)
|
||||
|
||||
echo "[INFO] Detected kernel version: $KERNEL_FULL"
|
||||
|
||||
if (( KERNEL_MAJOR < MIN_KERNEL_MAJOR )) || { (( KERNEL_MAJOR == MIN_KERNEL_MAJOR )) && (( KERNEL_MINOR < MIN_KERNEL_MINOR )); }; then
|
||||
echo "[ERROR] Kernel $KERNEL_FULL is too old. Requires Linux >= ${MIN_KERNEL_MAJOR}.${MIN_KERNEL_MINOR}."
|
||||
echo "Please upgrade your system or use a newer container (e.g. Fedora 42+, RHEL 10+, Debian 13+)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[OK] Kernel version >= ${MIN_KERNEL_MAJOR}.${MIN_KERNEL_MINOR}."
|
||||
|
||||
# ===== Config & Parse arguments =========================================================
|
||||
VERSION_ARG="${1:-}" # Pass version number like 7.13.8, or leave empty
|
||||
WITH_CORE="both" # Default: bundle both xray+sing-box
|
||||
@@ -264,8 +281,13 @@ ExclusiveArch: aarch64 x86_64
|
||||
Source0: __PKGROOT__.tar.gz
|
||||
|
||||
# Runtime dependencies (Avalonia / X11 / Fonts / GL)
|
||||
Requires: libX11, libXrandr, libXcursor, libXi, libXext, libxcb, libXrender, libXfixes, libXinerama, libxkbcommon
|
||||
Requires: fontconfig, freetype, cairo, pango, mesa-libEGL, mesa-libGL, xdg-utils
|
||||
Requires: freetype, cairo, pango, openssl, mesa-libEGL, mesa-libGL
|
||||
Requires: glibc >= 2.34
|
||||
Requires: fontconfig >= 2.13.1
|
||||
Requires: desktop-file-utils >= 0.26
|
||||
Requires: xdg-utils >= 1.1.3
|
||||
Requires: coreutils >= 8.32
|
||||
Requires: bash >= 5.1
|
||||
|
||||
Conflicts: v2rayN
|
||||
Obsoletes: v2rayN
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.15.6</Version>
|
||||
<Version>7.15.7</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -9,16 +9,16 @@
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.8" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.8" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.8" />
|
||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.8" />
|
||||
<PackageVersion Include="ReactiveUI.Avalonia" Version="11.3.8" />
|
||||
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
||||
<PackageVersion Include="Downloader" Version="4.0.3" />
|
||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.2" />
|
||||
<PackageVersion Include="MaterialDesignThemes" Version="5.3.0" />
|
||||
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
|
||||
<PackageVersion Include="QRCoder" Version="1.7.0" />
|
||||
<PackageVersion Include="ReactiveUI" Version="20.4.1" />
|
||||
<PackageVersion Include="ReactiveUI" Version="22.2.1" />
|
||||
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||
<PackageVersion Include="ReactiveUI.WPF" Version="20.4.1" />
|
||||
<PackageVersion Include="ReactiveUI.WPF" Version="22.2.1" />
|
||||
<PackageVersion Include="Semi.Avalonia" Version="11.3.7" />
|
||||
<PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" />
|
||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7" />
|
||||
|
||||
@@ -35,9 +35,13 @@ public class JsonUtils
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static T DeepCopy<T>(T obj)
|
||||
public static T? DeepCopy<T>(T? obj)
|
||||
{
|
||||
return Deserialize<T>(Serialize(obj, false))!;
|
||||
if (obj is null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
return Deserialize<T>(Serialize(obj, false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -67,7 +71,7 @@ public class JsonUtils
|
||||
/// </summary>
|
||||
/// <param name="strJson"></param>
|
||||
/// <returns></returns>
|
||||
public static JsonNode? ParseJson(string strJson)
|
||||
public static JsonNode? ParseJson(string? strJson)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -116,7 +120,7 @@ public class JsonUtils
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static string Serialize(object? obj, JsonSerializerOptions options)
|
||||
public static string Serialize(object? obj, JsonSerializerOptions? options)
|
||||
{
|
||||
var result = string.Empty;
|
||||
try
|
||||
@@ -125,7 +129,7 @@ public class JsonUtils
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result = JsonSerializer.Serialize(obj, options);
|
||||
result = JsonSerializer.Serialize(obj, options ?? _defaultSerializeOptions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -963,13 +963,13 @@ public class Utils
|
||||
|
||||
#region Platform
|
||||
|
||||
public static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
public static bool IsWindows() => OperatingSystem.IsWindows();
|
||||
|
||||
public static bool IsLinux() => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||
public static bool IsLinux() => OperatingSystem.IsLinux();
|
||||
|
||||
public static bool IsOSX() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
public static bool IsOSX() => OperatingSystem.IsMacOS();
|
||||
|
||||
public static bool IsNonWindows() => !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
public static bool IsNonWindows() => !OperatingSystem.IsWindows();
|
||||
|
||||
public static string GetExeName(string name)
|
||||
{
|
||||
@@ -994,11 +994,6 @@ public class Utils
|
||||
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('\\', '/');
|
||||
@@ -1008,11 +1003,6 @@ public class Utils
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p.Contains("/.mount_", StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (p.StartsWith("/opt/v2rayN", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -427,6 +427,7 @@ public class Global
|
||||
"zh-Hant",
|
||||
"en",
|
||||
"fa-Ir",
|
||||
"fr",
|
||||
"ru",
|
||||
"hu"
|
||||
];
|
||||
|
||||
@@ -34,7 +34,7 @@ public class CoreAdminManager
|
||||
StringBuilder sb = new();
|
||||
sb.AppendLine("#!/bin/bash");
|
||||
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
||||
sb.AppendLine($"sudo -S {cmdLine}");
|
||||
sb.AppendLine($"exec sudo -S -- {cmdLine}");
|
||||
var shFilePath = await FileManager.CreateLinuxShellFile("run_as_sudo.sh", sb.ToString(), true);
|
||||
|
||||
var procService = new ProcessService(
|
||||
|
||||
1599
v2rayN/ServiceLib/Resx/ResUI.fr.resx
Normal file
1599
v2rayN/ServiceLib/Resx/ResUI.fr.resx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -427,7 +427,7 @@
|
||||
<value>路由设置</value>
|
||||
</data>
|
||||
<data name="menuServers" xml:space="preserve">
|
||||
<value>配置文件</value>
|
||||
<value>配置项</value>
|
||||
</data>
|
||||
<data name="menuSetting" xml:space="preserve">
|
||||
<value>设置</value>
|
||||
|
||||
@@ -47,6 +47,18 @@ echo "============================================"
|
||||
echo "Starting termination of process $PID and all its children"
|
||||
echo "============================================"
|
||||
|
||||
# Try graceful termination first
|
||||
echo "Attempting graceful termination (SIGTERM) of PID: $PID"
|
||||
kill -15 "$PID" 2>/dev/null || true
|
||||
sleep 1
|
||||
# If still running, fall back to kill_children
|
||||
if ps -p $PID > /dev/null; then
|
||||
echo "Process $PID did not exit after SIGTERM; proceeding with forced termination of its children and itself"
|
||||
else
|
||||
echo "Process $PID exited cleanly after SIGTERM"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Find and kill all child processes
|
||||
kill_children "$PID"
|
||||
|
||||
|
||||
@@ -42,6 +42,20 @@ echo "============================================"
|
||||
echo "Starting termination of process $PID and all its descendants"
|
||||
echo "============================================"
|
||||
|
||||
# Try graceful termination first
|
||||
echo "Attempting graceful termination (SIGTERM) of PID: $PID"
|
||||
kill -15 "$PID" 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
# If still running, fall back to kill_descendants
|
||||
# Use the macOS-native 'kill -0' check
|
||||
if kill -0 $PID 2>/dev/null; then
|
||||
echo "Process $PID did not exit after SIGTERM; proceeding with forced termination of its descendants and itself"
|
||||
else
|
||||
echo "Process $PID exited cleanly after SIGTERM"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Find and kill all descendant processes
|
||||
kill_descendants "$PID"
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resx\ResUI.fr.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Resx\ResUI.hu.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
|
||||
@@ -10,15 +10,17 @@ public partial class App : Application
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
||||
|
||||
DataContext = StatusBarViewModel.Instance;
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
AppManager.Instance.InitComponents();
|
||||
if (!Design.IsDesignMode)
|
||||
{
|
||||
AppManager.Instance.InitComponents();
|
||||
DataContext = StatusBarViewModel.Instance;
|
||||
}
|
||||
|
||||
desktop.Exit += OnExit;
|
||||
desktop.MainWindow = new MainWindow();
|
||||
|
||||
@@ -3,7 +3,7 @@ global using System.Collections.Generic;
|
||||
global using System.Globalization;
|
||||
global using System.IO;
|
||||
global using System.Linq;
|
||||
global using System.Reactive.Disposables;
|
||||
global using System.Reactive.Disposables.Fluent;
|
||||
global using System.Reactive.Linq;
|
||||
global using System.Text;
|
||||
global using System.Threading;
|
||||
@@ -17,7 +17,7 @@ global using Avalonia.Markup.Xaml;
|
||||
global using Avalonia.Media;
|
||||
global using Avalonia.Media.Imaging;
|
||||
global using Avalonia.Platform;
|
||||
global using Avalonia.ReactiveUI;
|
||||
global using ReactiveUI.Avalonia;
|
||||
global using Avalonia.Styling;
|
||||
global using Avalonia.Threading;
|
||||
global using ReactiveUI;
|
||||
|
||||
@@ -54,12 +54,19 @@ internal class Program
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
{
|
||||
return AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
//.WithInterFont()
|
||||
.WithFontByDefault()
|
||||
.LogToTrace()
|
||||
.UseReactiveUI()
|
||||
.With(new MacOSPlatformOptions { ShowInDock = AppManager.Instance.Config.UiItem.MacOSShowInDock });
|
||||
var builder = AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
//.WithInterFont()
|
||||
.WithFontByDefault()
|
||||
.LogToTrace()
|
||||
.UseReactiveUI();
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
var showInDock = Design.IsDesignMode || AppManager.Instance.Config.UiItem.MacOSShowInDock;
|
||||
builder = builder.With(new MacOSPlatformOptions { ShowInDock = showInDock });
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||
}
|
||||
menuAddServerViaScan.IsVisible = false;
|
||||
|
||||
if (_config.UiItem.AutoHideStartup)
|
||||
if (_config.UiItem.AutoHideStartup && Utils.IsWindows())
|
||||
{
|
||||
this.WindowState = WindowState.Minimized;
|
||||
}
|
||||
@@ -402,9 +402,9 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||
public void ShowHideWindow(bool? blShow)
|
||||
{
|
||||
var bl = blShow ??
|
||||
Utils.IsLinux()
|
||||
(Utils.IsLinux()
|
||||
? (!_config.UiItem.ShowInTaskbar ^ (WindowState == WindowState.Minimized))
|
||||
: !_config.UiItem.ShowInTaskbar;
|
||||
: !_config.UiItem.ShowInTaskbar);
|
||||
if (bl)
|
||||
{
|
||||
this.Show();
|
||||
|
||||
@@ -75,6 +75,15 @@
|
||||
<PathIcon Data="{StaticResource SemiIconBolt}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<Button
|
||||
x:Name="menuMixedTestServer"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
Classes="IconButton Success"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuMixedTestServer}">
|
||||
<Button.Content>
|
||||
<PathIcon Data="{StaticResource building_ping}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
</WrapPanel>
|
||||
<DataGrid
|
||||
@@ -99,15 +108,12 @@
|
||||
<MenuItem x:Name="menuCopyServer" Header="{x:Static resx:ResUI.menuCopyServer}" />
|
||||
<MenuItem x:Name="menuRemoveServer" Header="{x:Static resx:ResUI.menuRemoveServer}" />
|
||||
<MenuItem x:Name="menuRemoveDuplicateServer" Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
|
||||
<MenuItem x:Name="menuRemoveInvalidServerResult" Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuMixedTestServer" Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
||||
<MenuItem x:Name="menuTcpingServer" Header="{x:Static resx:ResUI.menuTcpingServer}" />
|
||||
<MenuItem x:Name="menuRealPingServer" Header="{x:Static resx:ResUI.menuRealPingServer}" />
|
||||
<MenuItem x:Name="menuSpeedServer" Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuTestServerResult}">
|
||||
<MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||
<MenuItem x:Name="menuRemoveInvalidServerResult" Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuMoveToGroup" Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
||||
<MenuItem>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Avalonia.Desktop" />
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" />
|
||||
<PackageReference Include="ReactiveUI.Avalonia" />
|
||||
<PackageReference Include="MessageBox.Avalonia" />
|
||||
<PackageReference Include="Semi.Avalonia" />
|
||||
<PackageReference Include="Semi.Avalonia.AvaloniaEdit" />
|
||||
|
||||
@@ -26,11 +26,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub Action", "GitHub Act
|
||||
..\.github\workflows\build-osx.yml = ..\.github\workflows\build-osx.yml
|
||||
..\.github\workflows\build-windows-desktop.yml = ..\.github\workflows\build-windows-desktop.yml
|
||||
..\.github\workflows\build-windows.yml = ..\.github\workflows\build-windows.yml
|
||||
..\package-appimage.sh = ..\package-appimage.sh
|
||||
..\package-debian.sh = ..\package-debian.sh
|
||||
..\package-osx.sh = ..\package-osx.sh
|
||||
..\package-release-zip.sh = ..\package-release-zip.sh
|
||||
..\pkg2appimage.yml = ..\pkg2appimage.yml
|
||||
..\.github\workflows\winget-publish.yml = ..\.github\workflows\winget-publish.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
<File Path="../.github/workflows/build-windows-desktop.yml" />
|
||||
<File Path="../.github/workflows/build-windows.yml" />
|
||||
<File Path="../.github/workflows/winget-publish.yml" />
|
||||
<File Path="../package-appimage.sh" />
|
||||
<File Path="../package-debian.sh" />
|
||||
<File Path="../package-osx.sh" />
|
||||
<File Path="../package-release-zip.sh" />
|
||||
<File Path="../pkg2appimage.yml" />
|
||||
</Folder>
|
||||
<Folder Name="/Solution Files/">
|
||||
<File Path="Directory.Build.props" />
|
||||
|
||||
@@ -2,9 +2,9 @@ using System.Drawing;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace v2rayN;
|
||||
namespace v2rayN.Common;
|
||||
|
||||
public class QRCodeUtils
|
||||
public class QRCodeWindowsUtils
|
||||
{
|
||||
public static ImageSource? GetQRCode(string? strContent)
|
||||
{
|
||||
@@ -14,7 +14,7 @@ public class QRCodeUtils
|
||||
}
|
||||
try
|
||||
{
|
||||
var qrCodeImage = ServiceLib.Common.QRCodeUtils.GenQRCode(strContent);
|
||||
var qrCodeImage = QRCodeUtils.GenQRCode(strContent);
|
||||
return qrCodeImage is null ? null : ByteToImage(qrCodeImage);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -6,7 +6,7 @@ global using System.Diagnostics;
|
||||
global using System.Globalization;
|
||||
global using System.IO;
|
||||
global using System.Linq;
|
||||
global using System.Reactive.Disposables;
|
||||
global using System.Reactive.Disposables.Fluent;
|
||||
global using System.Reactive.Linq;
|
||||
global using System.Runtime.InteropServices;
|
||||
global using System.Text;
|
||||
@@ -31,3 +31,4 @@ global using ServiceLib.Manager;
|
||||
global using ServiceLib.Models;
|
||||
global using ServiceLib.Resx;
|
||||
global using ServiceLib.ViewModels;
|
||||
global using v2rayN.Common;
|
||||
|
||||
@@ -328,7 +328,7 @@ public partial class MainWindow
|
||||
|
||||
if (Application.Current?.MainWindow is Window window)
|
||||
{
|
||||
var bytes = QRCodeUtils.CaptureScreen(window);
|
||||
var bytes = QRCodeWindowsUtils.CaptureScreen(window);
|
||||
await ViewModel?.ScanScreenResult(bytes);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,15 @@
|
||||
ToolTip="{x:Static resx:ResUI.menuFastRealPing}">
|
||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="LightningBolt" />
|
||||
</Button>
|
||||
<Button
|
||||
x:Name="menuMixedTestServer"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="{StaticResource MarginLeftRight4}"
|
||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
||||
ToolTip="{x:Static resx:ResUI.menuMixedTestServer}">
|
||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Speedometer" />
|
||||
</Button>
|
||||
</WrapPanel>
|
||||
<DataGrid
|
||||
x:Name="lstProfiles"
|
||||
@@ -131,11 +140,11 @@
|
||||
x:Name="menuRemoveDuplicateServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
x:Name="menuMixedTestServer"
|
||||
x:Name="menuRemoveInvalidServerResult"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
||||
Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
x:Name="menuTcpingServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
@@ -148,16 +157,10 @@
|
||||
x:Name="menuSpeedServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuTestServerResult}">
|
||||
<MenuItem
|
||||
x:Name="menuSortServerResult"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||
<MenuItem
|
||||
x:Name="menuRemoveInvalidServerResult"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
x:Name="menuSortServerResult"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
x:Name="menuMoveToGroup"
|
||||
|
||||
@@ -170,7 +170,7 @@ public partial class ProfilesView
|
||||
|
||||
public async void ShareServer(string url)
|
||||
{
|
||||
var img = QRCodeUtils.GetQRCode(url);
|
||||
var img = QRCodeWindowsUtils.GetQRCode(url);
|
||||
var dialog = new QrcodeView()
|
||||
{
|
||||
imgQrcode = { Source = img },
|
||||
|
||||
@@ -64,7 +64,7 @@ public partial class SubSettingWindow
|
||||
{
|
||||
return;
|
||||
}
|
||||
var img = QRCodeUtils.GetQRCode(url);
|
||||
var img = QRCodeWindowsUtils.GetQRCode(url);
|
||||
var dialog = new QrcodeView()
|
||||
{
|
||||
imgQrcode = { Source = img },
|
||||
|
||||
Reference in New Issue
Block a user