mirror of
https://github.com/2dust/v2rayN.git
synced 2025-08-23 19:36:55 +00:00
Compare commits
6 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
45c987fd86 | ||
![]() |
7bec05ec23 | ||
![]() |
606b216cd0 | ||
![]() |
bb4f33559f | ||
![]() |
c7f3e53f28 | ||
![]() |
0035e836d7 |
13 changed files with 108 additions and 12 deletions
34
.github/workflows/build-linux.yml
vendored
34
.github/workflows/build-linux.yml
vendored
|
@ -99,3 +99,37 @@ jobs:
|
||||||
tag: ${{ github.event.inputs.release_tag }}
|
tag: ${{ github.event.inputs.release_tag }}
|
||||||
file_glob: true
|
file_glob: true
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|
||||||
|
# release RHEL package
|
||||||
|
- name: Package RPM (RHEL-family)
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
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
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
- name: Upload RPM artifacts
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
uses: actions/upload-artifact@v4.6.2
|
||||||
|
with:
|
||||||
|
name: v2rayN-rpm
|
||||||
|
path: |
|
||||||
|
${{ github.workspace }}/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_glob: true
|
||||||
|
prerelease: true
|
||||||
|
|
|
@ -332,6 +332,7 @@ download_xray() {
|
||||||
# Download Xray core and install to outdir/xray
|
# Download Xray core and install to outdir/xray
|
||||||
local outdir="$1" ver="${XRAY_VER:-}" url tmp zipname="xray.zip"
|
local outdir="$1" ver="${XRAY_VER:-}" url tmp zipname="xray.zip"
|
||||||
mkdir -p "$outdir"
|
mkdir -p "$outdir"
|
||||||
|
if [[ -n "${XRAY_VER:-}" ]]; then ver="${XRAY_VER}"; fi
|
||||||
if [[ -z "$ver" ]]; then
|
if [[ -z "$ver" ]]; then
|
||||||
ver="$(curl -fsSL https://api.github.com/repos/XTLS/Xray-core/releases/latest \
|
ver="$(curl -fsSL https://api.github.com/repos/XTLS/Xray-core/releases/latest \
|
||||||
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
||||||
|
@ -353,6 +354,7 @@ download_singbox() {
|
||||||
# Download sing-box core and install to outdir/sing-box
|
# Download sing-box core and install to outdir/sing-box
|
||||||
local outdir="$1" ver="${SING_VER:-}" url tmp tarname="singbox.tar.gz" bin
|
local outdir="$1" ver="${SING_VER:-}" url tmp tarname="singbox.tar.gz" bin
|
||||||
mkdir -p "$outdir"
|
mkdir -p "$outdir"
|
||||||
|
if [[ -n "${SING_VER:-}" ]]; then ver="${SING_VER}"; fi
|
||||||
if [[ -z "$ver" ]]; then
|
if [[ -z "$ver" ]]; then
|
||||||
ver="$(curl -fsSL https://api.github.com/repos/SagerNet/sing-box/releases/latest \
|
ver="$(curl -fsSL https://api.github.com/repos/SagerNet/sing-box/releases/latest \
|
||||||
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
||||||
|
@ -372,6 +374,22 @@ download_singbox() {
|
||||||
install -Dm755 "$bin" "$outdir/sing-box"
|
install -Dm755 "$bin" "$outdir/sing-box"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ---- NEW: download_mihomo (REQUIRED in --netcore mode) ----
|
||||||
|
download_mihomo() {
|
||||||
|
# Download mihomo into outroot/bin/mihomo/mihomo
|
||||||
|
local outroot="$1"
|
||||||
|
local url=""
|
||||||
|
if [[ "$RID_DIR" == "linux-arm64" ]]; then
|
||||||
|
url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-arm64/bin/mihomo/mihomo"
|
||||||
|
else
|
||||||
|
url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-64/bin/mihomo/mihomo"
|
||||||
|
fi
|
||||||
|
echo "[+] Download mihomo: $url"
|
||||||
|
mkdir -p "$outroot/bin/mihomo"
|
||||||
|
curl -fL "$url" -o "$outroot/bin/mihomo/mihomo"
|
||||||
|
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/xray/
|
||||||
unify_geo_layout() {
|
unify_geo_layout() {
|
||||||
local outroot="$1"
|
local outroot="$1"
|
||||||
|
@ -451,7 +469,8 @@ download_v2rayn_bundle() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f "$outroot/v2rayn.zip" 2>/dev/null || true
|
rm -f "$outroot/v2rayn.zip" 2>/dev/null || true
|
||||||
find "$outroot" -type d -name "mihomo" -prune -exec rm -rf {} + 2>/dev/null || true
|
# keep mihomo
|
||||||
|
# find "$outroot" -type d -name "mihomo" -prune -exec rm -rf {} + 2>/dev/null || true
|
||||||
|
|
||||||
local nested_dir
|
local nested_dir
|
||||||
nested_dir="$(find "$outroot" -maxdepth 1 -type d -name 'v2rayN-linux-*' | head -n1 || true)"
|
nested_dir="$(find "$outroot" -maxdepth 1 -type d -name 'v2rayN-linux-*' | head -n1 || true)"
|
||||||
|
@ -561,6 +580,8 @@ build_for_arch() {
|
||||||
download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)"
|
download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)"
|
||||||
fi
|
fi
|
||||||
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
|
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
|
||||||
|
# ---- REQUIRED: always fetch mihomo in netcore mode, per-arch ----
|
||||||
|
download_mihomo "$WORKDIR/$PKGROOT" || echo "[!] mihomo download failed (skipped)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Tarball
|
# Tarball
|
||||||
|
@ -583,6 +604,7 @@ Release: 1%{?dist}
|
||||||
Summary: v2rayN (Avalonia) GUI client for Linux (x86_64/aarch64)
|
Summary: v2rayN (Avalonia) GUI client for Linux (x86_64/aarch64)
|
||||||
License: GPL-3.0-only
|
License: GPL-3.0-only
|
||||||
URL: https://github.com/2dust/v2rayN
|
URL: https://github.com/2dust/v2rayN
|
||||||
|
BugURL: https://github.com/2dust/v2rayN/issues
|
||||||
ExclusiveArch: aarch64 x86_64
|
ExclusiveArch: aarch64 x86_64
|
||||||
Source0: __PKGROOT__.tar.gz
|
Source0: __PKGROOT__.tar.gz
|
||||||
|
|
||||||
|
@ -591,10 +613,11 @@ Requires: libX11, libXrandr, libXcursor, libXi, libXext, libxcb, libXrende
|
||||||
Requires: fontconfig, freetype, cairo, pango, mesa-libEGL, mesa-libGL
|
Requires: fontconfig, freetype, cairo, pango, mesa-libEGL, mesa-libGL
|
||||||
|
|
||||||
%description
|
%description
|
||||||
v2rayN GUI client built with Avalonia.
|
v2rayN Linux for Red Hat Enterprise Linux
|
||||||
Installs self-contained publish under /opt/v2rayN and a launcher 'v2rayn'.
|
Support vless / vmess / Trojan / http / socks / Anytls / Hysteria2 / Shadowsocks / tuic / WireGuard
|
||||||
Cores (if bundled): /opt/v2rayN/bin/xray, /opt/v2rayN/bin/sing_box.
|
Support Red Hat Enterprise Linux / Fedora Linux / Rocky Linux / AlmaLinux / CentOS
|
||||||
Geo files for Xray are placed at /opt/v2rayN/bin/xray; launcher will symlink them into user's XDG data dir on first run.
|
For more information, Please visit our website
|
||||||
|
https://github.com/2dust/v2rayN
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q -n __PKGROOT__
|
%setup -q -n __PKGROOT__
|
||||||
|
@ -645,7 +668,7 @@ cat > %{buildroot}%{_datadir}/applications/v2rayn.desktop << 'EOF'
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=v2rayN
|
Name=v2rayN
|
||||||
Comment=GUI client for Xray / sing-box
|
Comment=v2rayN for Red Hat Enterprise Linux
|
||||||
Exec=v2rayn
|
Exec=v2rayn
|
||||||
Icon=v2rayn
|
Icon=v2rayn
|
||||||
Terminal=false
|
Terminal=false
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.14.2</Version>
|
<Version>7.14.3</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace ServiceLib.Handler.Fmt;
|
namespace ServiceLib.Handler.Fmt;
|
||||||
|
|
||||||
public class HtmlPageFmt : BaseFmt
|
public class HtmlPageFmt : BaseFmt
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
<x:Double x:Key="IconButtonWidth">32</x:Double>
|
<x:Double x:Key="IconButtonWidth">32</x:Double>
|
||||||
<x:Double x:Key="IconButtonHeight">32</x:Double>
|
<x:Double x:Key="IconButtonHeight">32</x:Double>
|
||||||
|
<x:Double x:Key="MenuFlyoutMaxHeight">1000</x:Double>
|
||||||
|
|
||||||
<Thickness x:Key="Margin2">2</Thickness>
|
<Thickness x:Key="Margin2">2</Thickness>
|
||||||
<Thickness x:Key="MarginLr4">4,0</Thickness>
|
<Thickness x:Key="MarginLr4">4,0</Thickness>
|
||||||
|
|
|
@ -16,6 +16,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
|
@ -100,4 +101,9 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
||||||
{
|
{
|
||||||
ProcUtils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/dns/");
|
ProcUtils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/dns/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
btnCancel.Focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ public partial class FullConfigTemplateWindow : WindowBase<FullConfigTemplateVie
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
ViewModel = new FullConfigTemplateViewModel(UpdateViewHandler);
|
ViewModel = new FullConfigTemplateViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
|
@ -49,4 +50,8 @@ public partial class FullConfigTemplateWindow : WindowBase<FullConfigTemplateVie
|
||||||
{
|
{
|
||||||
ProcUtils.ProcessStart("https://github.com/2dust/v2rayN/wiki/Description-of-some-ui#%E5%AE%8C%E6%95%B4%E9%85%8D%E7%BD%AE%E6%A8%A1%E6%9D%BF%E8%AE%BE%E7%BD%AE");
|
ProcUtils.ProcessStart("https://github.com/2dust/v2rayN/wiki/Description-of-some-ui#%E5%AE%8C%E6%95%B4%E9%85%8D%E7%BD%AE%E6%A8%A1%E6%9D%BF%E8%AE%BE%E7%BD%AE");
|
||||||
}
|
}
|
||||||
|
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
btnCancel.Focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ public partial class GlobalHotkeySettingWindow : WindowBase<GlobalHotkeySettingV
|
||||||
btnReset.Click += btnReset_Click;
|
btnReset.Click += btnReset_Click;
|
||||||
|
|
||||||
HotkeyManager.Instance.IsPause = true;
|
HotkeyManager.Instance.IsPause = true;
|
||||||
|
Loaded += Window_Loaded;
|
||||||
this.Closing += (s, e) => HotkeyManager.Instance.IsPause = false;
|
this.Closing += (s, e) => HotkeyManager.Instance.IsPause = false;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
|
|
||||||
|
@ -134,4 +135,8 @@ public partial class GlobalHotkeySettingWindow : WindowBase<GlobalHotkeySettingV
|
||||||
|
|
||||||
return res.ToString();
|
return res.ToString();
|
||||||
}
|
}
|
||||||
|
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
btnCancel.Focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ServiceLib.Manager;
|
using ServiceLib.Manager;
|
||||||
using v2rayN.Desktop.Base;
|
using v2rayN.Desktop.Base;
|
||||||
|
@ -14,6 +15,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
Loaded += Window_Loaded;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
|
|
||||||
|
@ -209,4 +211,8 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
||||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
btnCancel.Focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
Loaded += Window_Loaded;
|
||||||
this.Closing += RoutingSettingWindow_Closing;
|
this.Closing += RoutingSettingWindow_Closing;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
this.KeyDown += RoutingSettingWindow_KeyDown;
|
this.KeyDown += RoutingSettingWindow_KeyDown;
|
||||||
|
@ -134,4 +135,8 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
btnCancel.Focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using DialogHostAvalonia;
|
using DialogHostAvalonia;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
|
@ -19,7 +20,9 @@ public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
menuClose.Click += menuClose_Click;
|
menuClose.Click += menuClose_Click;
|
||||||
|
Loaded += Window_Loaded;
|
||||||
this.Closing += SubSettingWindow_Closing;
|
this.Closing += SubSettingWindow_Closing;
|
||||||
|
this.KeyDown += SubSettingWindow_KeyDown;
|
||||||
ViewModel = new SubSettingViewModel(UpdateViewHandler);
|
ViewModel = new SubSettingViewModel(UpdateViewHandler);
|
||||||
lstSubscription.DoubleTapped += LstSubscription_DoubleTapped;
|
lstSubscription.DoubleTapped += LstSubscription_DoubleTapped;
|
||||||
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
|
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
|
||||||
|
@ -106,4 +109,16 @@ public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SubSettingWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.Escape)
|
||||||
|
{
|
||||||
|
menuClose_Click(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
lstSubscription.Focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using v2rayN.Manager;
|
|
||||||
|
|
||||||
namespace v2rayN.Manager;
|
namespace v2rayN.Manager;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue