mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-05 06:16:05 +02:00
Linux: Change how AppImage moving is handled, add support for vrcx:\\
This commit is contained in:
@@ -147,13 +147,6 @@ namespace VRCX
|
|||||||
Program.VRCXVRInstance.ExecuteVrOverlayFunction(function, json);
|
Program.VRCXVRInstance.ExecuteVrOverlayFunction(function, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetLaunchCommand()
|
|
||||||
{
|
|
||||||
var command = StartupArgs.LaunchArguments.LaunchCommand;
|
|
||||||
StartupArgs.LaunchArguments.LaunchCommand = string.Empty;
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void FocusWindow()
|
public override void FocusWindow()
|
||||||
{
|
{
|
||||||
MainForm.Instance.Invoke(new Action(() => { MainForm.Instance.Focus_Window(); }));
|
MainForm.Instance.Invoke(new Action(() => { MainForm.Instance.Focus_Window(); }));
|
||||||
|
|||||||
@@ -61,6 +61,13 @@ namespace VRCX
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetLaunchCommand()
|
||||||
|
{
|
||||||
|
var command = StartupArgs.LaunchArguments.LaunchCommand;
|
||||||
|
StartupArgs.LaunchArguments.LaunchCommand = string.Empty;
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
public void IPCAnnounceStart()
|
public void IPCAnnounceStart()
|
||||||
{
|
{
|
||||||
IPCServer.Send(new IPCPacket
|
IPCServer.Send(new IPCPacket
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ namespace VRCX
|
|||||||
public abstract void ExecuteAppFunction(string function, string json);
|
public abstract void ExecuteAppFunction(string function, string json);
|
||||||
public abstract void ExecuteVrFeedFunction(string function, string json);
|
public abstract void ExecuteVrFeedFunction(string function, string json);
|
||||||
public abstract void ExecuteVrOverlayFunction(string function, string json);
|
public abstract void ExecuteVrOverlayFunction(string function, string json);
|
||||||
public abstract string GetLaunchCommand();
|
|
||||||
public abstract void FocusWindow();
|
public abstract void FocusWindow();
|
||||||
public abstract void ChangeTheme(int value);
|
public abstract void ChangeTheme(int value);
|
||||||
public abstract void DoFunny();
|
public abstract void DoFunny();
|
||||||
|
|||||||
@@ -64,11 +64,6 @@ namespace VRCX
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetLaunchCommand()
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void FocusWindow()
|
public override void FocusWindow()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace VRCX
|
|||||||
{
|
{
|
||||||
var compatToolMapping = new Dictionary<string, string>();
|
var compatToolMapping = new Dictionary<string, string>();
|
||||||
const string sectionHeader = "\"CompatToolMapping\"";
|
const string sectionHeader = "\"CompatToolMapping\"";
|
||||||
int sectionStart = vdfContent.IndexOf(sectionHeader);
|
int sectionStart = vdfContent.IndexOf(sectionHeader, StringComparison.Ordinal);
|
||||||
|
|
||||||
if (sectionStart == -1)
|
if (sectionStart == -1)
|
||||||
{
|
{
|
||||||
@@ -53,7 +53,7 @@ namespace VRCX
|
|||||||
return compatToolMapping;
|
return compatToolMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
int blockStart = vdfContent.IndexOf("{", sectionStart) + 1;
|
int blockStart = vdfContent.IndexOf('{', sectionStart) + 1;
|
||||||
int blockEnd = FindMatchingBracket(vdfContent, blockStart - 1);
|
int blockEnd = FindMatchingBracket(vdfContent, blockStart - 1);
|
||||||
|
|
||||||
if (blockStart == -1 || blockEnd == -1)
|
if (blockStart == -1 || blockEnd == -1)
|
||||||
@@ -317,6 +317,12 @@ namespace VRCX
|
|||||||
{
|
{
|
||||||
string winePath = GetVRChatWinePath();
|
string winePath = GetVRChatWinePath();
|
||||||
string winePrefix = _vrcPrefixPath;
|
string winePrefix = _vrcPrefixPath;
|
||||||
|
if (string.IsNullOrEmpty(winePath) || string.IsNullOrEmpty(winePrefix))
|
||||||
|
{
|
||||||
|
logger.Info("VRC Wine path was not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
string wineRegCommand = $"\"{winePath}\" reg {command}";
|
string wineRegCommand = $"\"{winePath}\" reg {command}";
|
||||||
ProcessStartInfo processStartInfo = GetWineProcessStartInfo(winePath, winePrefix, wineRegCommand);
|
ProcessStartInfo processStartInfo = GetWineProcessStartInfo(winePath, winePrefix, wineRegCommand);
|
||||||
using var process = Process.Start(processStartInfo);
|
using var process = Process.Start(processStartInfo);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using NLog.Targets;
|
|||||||
using System;
|
using System;
|
||||||
using System.Data.SQLite;
|
using System.Data.SQLite;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
@@ -224,6 +225,9 @@ namespace VRCX
|
|||||||
Application.SetCompatibleTextRenderingDefault(false);
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
|
|
||||||
logger.Info("{0} Starting...", Version);
|
logger.Info("{0} Starting...", Version);
|
||||||
|
logger.Info("Args: {0}", JsonSerializer.Serialize(StartupArgs.Args));
|
||||||
|
if (!string.IsNullOrEmpty(StartupArgs.LaunchArguments.LaunchCommand))
|
||||||
|
logger.Info("Launch Command: {0}", StartupArgs.LaunchArguments.LaunchCommand);
|
||||||
logger.Debug("Wine detection: {0}", Wine.GetIfWine());
|
logger.Debug("Wine detection: {0}", Wine.GetIfWine());
|
||||||
|
|
||||||
SQLiteLegacy.Instance.Init();
|
SQLiteLegacy.Instance.Init();
|
||||||
@@ -276,6 +280,9 @@ namespace VRCX
|
|||||||
Update.Check();
|
Update.Check();
|
||||||
|
|
||||||
logger.Info("{0} Starting...", Version);
|
logger.Info("{0} Starting...", Version);
|
||||||
|
logger.Info("Args: {0}", JsonSerializer.Serialize(StartupArgs.Args));
|
||||||
|
if (!string.IsNullOrEmpty(StartupArgs.LaunchArguments.LaunchCommand))
|
||||||
|
logger.Info("Launch Command: {0}", StartupArgs.LaunchArguments.LaunchCommand);
|
||||||
|
|
||||||
AppApiInstance = new AppApiElectron();
|
AppApiInstance = new AppApiElectron();
|
||||||
// ProcessMonitor.Instance.Init();
|
// ProcessMonitor.Instance.Init();
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using System.IO.Pipes;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Management;
|
using System.Management;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
#if !LINUX
|
#if !LINUX
|
||||||
@@ -24,9 +25,11 @@ namespace VRCX
|
|||||||
{
|
{
|
||||||
private const string SubProcessTypeArgument = "--type";
|
private const string SubProcessTypeArgument = "--type";
|
||||||
public static VrcxLaunchArguments LaunchArguments = new();
|
public static VrcxLaunchArguments LaunchArguments = new();
|
||||||
|
public static string[] Args;
|
||||||
|
|
||||||
public static void ArgsCheck(string[] args)
|
public static void ArgsCheck(string[] args)
|
||||||
{
|
{
|
||||||
|
Args = args;
|
||||||
Debug.Assert(Program.LaunchDebug = true);
|
Debug.Assert(Program.LaunchDebug = true);
|
||||||
|
|
||||||
LaunchArguments = ParseArgs(args);
|
LaunchArguments = ParseArgs(args);
|
||||||
@@ -78,6 +81,9 @@ namespace VRCX
|
|||||||
if (arg.StartsWith(VrcxLaunchArguments.LaunchCommandPrefix) && arg.Length > VrcxLaunchArguments.LaunchCommandPrefix.Length)
|
if (arg.StartsWith(VrcxLaunchArguments.LaunchCommandPrefix) && arg.Length > VrcxLaunchArguments.LaunchCommandPrefix.Length)
|
||||||
arguments.LaunchCommand = arg.Substring(VrcxLaunchArguments.LaunchCommandPrefix.Length);
|
arguments.LaunchCommand = arg.Substring(VrcxLaunchArguments.LaunchCommandPrefix.Length);
|
||||||
|
|
||||||
|
if (arg.StartsWith(VrcxLaunchArguments.LinuxLaunchCommandPrefix) && arg.Length > VrcxLaunchArguments.LinuxLaunchCommandPrefix.Length)
|
||||||
|
arguments.LaunchCommand = arg.Substring(VrcxLaunchArguments.LinuxLaunchCommandPrefix.Length);
|
||||||
|
|
||||||
if (arg.StartsWith(VrcxLaunchArguments.ConfigDirectoryPrefix) && arg.Length > VrcxLaunchArguments.ConfigDirectoryPrefix.Length)
|
if (arg.StartsWith(VrcxLaunchArguments.ConfigDirectoryPrefix) && arg.Length > VrcxLaunchArguments.ConfigDirectoryPrefix.Length)
|
||||||
arguments.ConfigDirectory = arg.Substring(VrcxLaunchArguments.ConfigDirectoryPrefix.Length + 1);
|
arguments.ConfigDirectory = arg.Substring(VrcxLaunchArguments.ConfigDirectoryPrefix.Length + 1);
|
||||||
|
|
||||||
@@ -96,6 +102,7 @@ namespace VRCX
|
|||||||
public bool IsDebug { get; set; } = false;
|
public bool IsDebug { get; set; } = false;
|
||||||
|
|
||||||
public const string LaunchCommandPrefix = "/uri=vrcx://";
|
public const string LaunchCommandPrefix = "/uri=vrcx://";
|
||||||
|
public const string LinuxLaunchCommandPrefix = "vrcx://";
|
||||||
public string LaunchCommand { get; set; } = null;
|
public string LaunchCommand { get; set; } = null;
|
||||||
|
|
||||||
public const string ConfigDirectoryPrefix = "--config";
|
public const string ConfigDirectoryPrefix = "--config";
|
||||||
|
|||||||
@@ -359,7 +359,6 @@ namespace VRCX
|
|||||||
public async Task<string> ExecuteJson(string options)
|
public async Task<string> ExecuteJson(string options)
|
||||||
{
|
{
|
||||||
var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(options);
|
var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(options);
|
||||||
Logger.Info(JsonConvert.SerializeObject(data));
|
|
||||||
var result = await Execute(data);
|
var result = await Execute(data);
|
||||||
return System.Text.Json.JsonSerializer.Serialize(new
|
return System.Text.Json.JsonSerializer.Serialize(new
|
||||||
{
|
{
|
||||||
|
|||||||
+126
-133
@@ -9,7 +9,7 @@ const {
|
|||||||
dialog,
|
dialog,
|
||||||
Notification
|
Notification
|
||||||
} = require('electron');
|
} = require('electron');
|
||||||
const { spawn } = require('child_process');
|
const { spawn, spawnSync } = require('child_process');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const https = require('https');
|
const https = require('https');
|
||||||
|
|
||||||
@@ -23,10 +23,12 @@ if (!isDotNetInstalled()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get launch arguments
|
// get launch arguments
|
||||||
|
let appImagePath = process.env.APPIMAGE;
|
||||||
const args = process.argv.slice(1);
|
const args = process.argv.slice(1);
|
||||||
const noInstall = args.some((val) => val === '--no-install');
|
const noInstall = args.includes('--no-install');
|
||||||
const x11 = args.some((val) => val === '--x11');
|
const x11 = args.includes('--x11');
|
||||||
const homePath = getHomePath();
|
const homePath = getHomePath();
|
||||||
|
tryRelaunchWithArgs(args);
|
||||||
tryCopyFromWinePrefix();
|
tryCopyFromWinePrefix();
|
||||||
|
|
||||||
const rootDir = app.getAppPath();
|
const rootDir = app.getAppPath();
|
||||||
@@ -52,8 +54,9 @@ ipcMain.handle('callDotNetMethod', (event, className, methodName, args) => {
|
|||||||
let mainWindow = undefined;
|
let mainWindow = undefined;
|
||||||
|
|
||||||
const VRCXStorage = interopApi.getDotNetObject('VRCXStorage');
|
const VRCXStorage = interopApi.getDotNetObject('VRCXStorage');
|
||||||
|
const hasAskedToMoveAppImage =
|
||||||
|
VRCXStorage.Get('VRCX_HasAskedToMoveAppImage') === 'true';
|
||||||
let isCloseToTray = VRCXStorage.Get('VRCX_CloseToTray') === 'true';
|
let isCloseToTray = VRCXStorage.Get('VRCX_CloseToTray') === 'true';
|
||||||
let appImagePath = process.env.APPIMAGE;
|
|
||||||
|
|
||||||
ipcMain.handle('applyWindowSettings', (event, position, size, state) => {
|
ipcMain.handle('applyWindowSettings', (event, position, size, state) => {
|
||||||
if (position) {
|
if (position) {
|
||||||
@@ -107,11 +110,16 @@ ipcMain.handle('notification:showNotification', (event, title, body, icon) => {
|
|||||||
|
|
||||||
ipcMain.handle('app:restart', () => {
|
ipcMain.handle('app:restart', () => {
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
const options = { args: process.argv.slice(1) };
|
const options = {
|
||||||
|
execPath: process.execPath,
|
||||||
|
args: process.argv.slice(1)
|
||||||
|
};
|
||||||
if (appImagePath) {
|
if (appImagePath) {
|
||||||
options.execPath = appImagePath;
|
options.execPath = appImagePath;
|
||||||
|
if (!x11 && !options.args.includes('--appimage-extract-and-run')) {
|
||||||
options.args.unshift('--appimage-extract-and-run');
|
options.args.unshift('--appimage-extract-and-run');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
app.relaunch(options);
|
app.relaunch(options);
|
||||||
app.exit(0);
|
app.exit(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -120,9 +128,12 @@ ipcMain.handle('app:restart', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function relaunchWithArgs(args) {
|
function tryRelaunchWithArgs(args) {
|
||||||
if (process.argv.includes('--ozone-platform-hint=auto')) {
|
if (
|
||||||
console.log('Already running with correct arguments');
|
process.platform !== 'linux' ||
|
||||||
|
x11 ||
|
||||||
|
args.includes('--ozone-platform-hint=auto')
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,14 +159,6 @@ function relaunchWithArgs(args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
if (
|
|
||||||
process.platform === 'linux' &&
|
|
||||||
!process.argv.includes('--ozone-platform-hint=auto') &&
|
|
||||||
!x11
|
|
||||||
) {
|
|
||||||
relaunchWithArgs(process.argv.slice(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
app.commandLine.appendSwitch('enable-speech-dispatcher');
|
app.commandLine.appendSwitch('enable-speech-dispatcher');
|
||||||
|
|
||||||
const x = parseInt(VRCXStorage.Get('VRCX_LocationX')) || 0;
|
const x = parseInt(VRCXStorage.Get('VRCX_LocationX')) || 0;
|
||||||
@@ -180,7 +183,7 @@ function createWindow() {
|
|||||||
const indexPath = path.join(rootDir, 'build/html/index.html');
|
const indexPath = path.join(rootDir, 'build/html/index.html');
|
||||||
mainWindow.loadFile(indexPath, { userAgent: version });
|
mainWindow.loadFile(indexPath, { userAgent: version });
|
||||||
|
|
||||||
// add proxy config
|
// add proxy config, doesn't work, thanks electron
|
||||||
// const proxy = VRCXStorage.Get('VRCX_Proxy');
|
// const proxy = VRCXStorage.Get('VRCX_Proxy');
|
||||||
// if (proxy) {
|
// if (proxy) {
|
||||||
// session.setProxy(
|
// session.setProxy(
|
||||||
@@ -294,35 +297,6 @@ function createTray() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
async function installVRCXappImageLauncher() {
|
|
||||||
const iconUrl =
|
|
||||||
'https://raw.githubusercontent.com/vrcx-team/VRCX/master/VRCX.png';
|
|
||||||
|
|
||||||
let targetIconName;
|
|
||||||
const desktopFiles = fs.readdirSync(
|
|
||||||
path.join(homePath, '.local/share/applications')
|
|
||||||
);
|
|
||||||
for (const file of desktopFiles) {
|
|
||||||
if (file.includes('appimagekit_') && file.includes('VRCX')) {
|
|
||||||
console.log('AppImageLauncher shortcut found:', file);
|
|
||||||
targetIconName = file.replace('.desktop', '.png');
|
|
||||||
targetIconName = targetIconName.replace('-', '_');
|
|
||||||
try {
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error deleting shortcut:', err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const iconPath = '~/.local/share/icons/' + targetIconName;
|
|
||||||
const expandedPath = iconPath.replace('~', process.env.HOME);
|
|
||||||
const targetIconPath = path.join(expandedPath);
|
|
||||||
await downloadIcon(iconUrl, targetIconPath);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
async function installVRCX() {
|
async function installVRCX() {
|
||||||
console.log('Home path:', homePath);
|
console.log('Home path:', homePath);
|
||||||
console.log('AppImage path:', appImagePath);
|
console.log('AppImage path:', appImagePath);
|
||||||
@@ -331,116 +305,88 @@ async function installVRCX() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (noInstall) {
|
if (noInstall) {
|
||||||
|
interopApi.getDotNetObject('Update').Init(appImagePath);
|
||||||
console.log('Skipping installation.');
|
console.log('Skipping installation.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// rename AppImage to VRCX.AppImage
|
||||||
let appImageLauncherInstalled = false;
|
const currentName = path.basename(appImagePath);
|
||||||
if (fs.existsSync('/usr/bin/AppImageLauncher')) {
|
const expectedName = 'VRCX.AppImage';
|
||||||
appImageLauncherInstalled = true;
|
if (currentName !== expectedName) {
|
||||||
}
|
const newPath = path.join(path.dirname(appImagePath), expectedName);
|
||||||
*/
|
|
||||||
|
|
||||||
if (appImagePath.startsWith(path.join(homePath, 'Applications'))) {
|
|
||||||
/*
|
|
||||||
if (appImageLauncherInstalled) {
|
|
||||||
installVRCXappImageLauncher();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
interopApi.getDotNetObject('Update').Init(appImagePath);
|
|
||||||
console.log('VRCX is already installed.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentName = path.basename(appImagePath);
|
|
||||||
let newName = 'VRCX.AppImage';
|
|
||||||
if (currentName !== newName) {
|
|
||||||
const newPath = path.join(path.dirname(appImagePath), newName);
|
|
||||||
try {
|
try {
|
||||||
|
// remove existing VRCX.AppImage
|
||||||
|
if (fs.existsSync(newPath)) {
|
||||||
|
fs.unlinkSync(newPath);
|
||||||
|
}
|
||||||
fs.renameSync(appImagePath, newPath);
|
fs.renameSync(appImagePath, newPath);
|
||||||
console.log('AppImage renamed to:', newPath);
|
console.log('AppImage renamed to:', newPath);
|
||||||
appImagePath = newPath;
|
appImagePath = newPath;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error renaming AppImage:', err);
|
console.error(`Error renaming AppImage ${newPath}`, err);
|
||||||
dialog.showErrorBox('VRCX', 'Failed to rename AppImage.');
|
dialog.showErrorBox('VRCX', `Failed to rename AppImage ${newPath}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
// ask to move AppImage to ~/Applications
|
||||||
process.env.APPIMAGE.startsWith(path.join(homePath, 'Applications')) &&
|
const appImageHomePath = `${homePath}/Applications/VRCX.AppImage`;
|
||||||
path.basename(process.env.APPIMAGE) === 'VRCX.AppImage'
|
if (!hasAskedToMoveAppImage && appImagePath !== appImageHomePath) {
|
||||||
) {
|
const result = dialog.showMessageBoxSync(mainWindow, {
|
||||||
interopApi.getDotNetObject('Update').Init(appImagePath);
|
type: 'question',
|
||||||
console.log('VRCX is already installed.');
|
title: 'VRCX',
|
||||||
return;
|
message: 'Do you want to install VRCX?',
|
||||||
|
detail: 'VRCX will be moved to your ~/Applications folder.',
|
||||||
|
buttons: ['No', 'Yes']
|
||||||
|
});
|
||||||
|
if (result === 0) {
|
||||||
|
console.log('Cancel AppImage move to ~/Applications');
|
||||||
|
// don't ask again
|
||||||
|
VRCXStorage.Set('VRCX_HasAskedToMoveAppImage', 'true');
|
||||||
|
VRCXStorage.Save();
|
||||||
}
|
}
|
||||||
|
if (result === 1) {
|
||||||
const targetPath = path.join(homePath, 'Applications');
|
console.log('Moving AppImage to ~/Applications');
|
||||||
console.log('Target Path:', targetPath);
|
|
||||||
|
|
||||||
// Create target directory if it doesn't exist
|
|
||||||
if (!fs.existsSync(targetPath)) {
|
|
||||||
fs.mkdirSync(targetPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetAppImagePath = path.join(targetPath, 'VRCX.AppImage');
|
|
||||||
|
|
||||||
// Move the AppImage to the target directory
|
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(targetAppImagePath)) {
|
const applicationsPath = path.join(homePath, 'Applications');
|
||||||
fs.unlinkSync(targetAppImagePath);
|
// create ~/Applications if it doesn't exist
|
||||||
|
if (!fs.existsSync(applicationsPath)) {
|
||||||
|
fs.mkdirSync(applicationsPath);
|
||||||
}
|
}
|
||||||
fs.renameSync(appImagePath, targetAppImagePath);
|
// remove existing VRCX.AppImage
|
||||||
appImagePath = targetAppImagePath;
|
if (fs.existsSync(appImageHomePath)) {
|
||||||
console.log('AppImage moved to:', targetAppImagePath);
|
fs.unlinkSync(appImageHomePath);
|
||||||
|
}
|
||||||
|
fs.renameSync(appImagePath, appImageHomePath);
|
||||||
|
appImagePath = appImageHomePath;
|
||||||
|
console.log('AppImage moved to:', appImageHomePath);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error moving AppImage:', err);
|
console.error(`Error moving AppImage ${appImageHomePath}`, err);
|
||||||
dialog.showErrorBox('VRCX', 'Failed to move AppImage.');
|
dialog.showErrorBox(
|
||||||
|
'VRCX',
|
||||||
|
`Failed to move AppImage ${appImageHomePath}`
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// inform .NET side about AppImage path
|
||||||
|
interopApi.getDotNetObject('Update').Init(appImagePath);
|
||||||
|
|
||||||
await createDesktopFile();
|
await createDesktopFile();
|
||||||
dialog.showMessageBox({
|
|
||||||
type: 'info',
|
|
||||||
title: 'VRCX',
|
|
||||||
message: 'VRCX has been installed successfully.',
|
|
||||||
detail: 'You can now find VRCX in your ~/Applications folder.'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createDesktopFile() {
|
async function createDesktopFile() {
|
||||||
// Download the icon and save it to the target directory
|
// Download the icon and save it to the target directory
|
||||||
|
const iconPath = path.join(homePath, '.local/share/icons/VRCX.png');
|
||||||
|
if (!fs.existsSync(iconPath)) {
|
||||||
const iconUrl =
|
const iconUrl =
|
||||||
'https://raw.githubusercontent.com/vrcx-team/VRCX/master/VRCX.png';
|
'https://raw.githubusercontent.com/vrcx-team/VRCX/master/VRCX.png';
|
||||||
const iconPath = path.join(homePath, '.local/share/icons/VRCX.png');
|
|
||||||
await downloadIcon(iconUrl, iconPath)
|
await downloadIcon(iconUrl, iconPath)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log('Icon downloaded and saved to:', iconPath);
|
console.log('Icon downloaded and saved to:', iconPath);
|
||||||
const desktopFile = `[Desktop Entry]
|
|
||||||
Name=VRCX
|
|
||||||
Comment=Friendship management tool for VRChat
|
|
||||||
Exec=${appImagePath} --ozone-platform-hint=auto
|
|
||||||
Icon=VRCX
|
|
||||||
Type=Application
|
|
||||||
Categories=Network;InstantMessaging;Game;
|
|
||||||
Terminal=false
|
|
||||||
StartupWMClass=VRCX
|
|
||||||
`;
|
|
||||||
|
|
||||||
const desktopFilePath = path.join(
|
|
||||||
homePath,
|
|
||||||
'.local/share/applications/VRCX.desktop'
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
fs.writeFileSync(desktopFilePath, desktopFile);
|
|
||||||
console.log('Desktop file created at:', desktopFilePath);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error creating desktop file:', err);
|
|
||||||
dialog.showErrorBox('VRCX', 'Failed to create desktop entry.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error('Error downloading icon:', err);
|
console.error('Error downloading icon:', err);
|
||||||
@@ -448,6 +394,57 @@ StartupWMClass=VRCX
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the desktop file
|
||||||
|
const desktopFilePath = path.join(
|
||||||
|
homePath,
|
||||||
|
'.local/share/applications/VRCX.desktop'
|
||||||
|
);
|
||||||
|
const dotDesktop = {
|
||||||
|
Name: 'VRCX',
|
||||||
|
Comment: 'Friendship management tool for VRChat',
|
||||||
|
Exec: `${appImagePath} --ozone-platform-hint=auto %U`,
|
||||||
|
Icon: 'VRCX',
|
||||||
|
Type: 'Application',
|
||||||
|
Categories: 'Network;InstantMessaging;Game;',
|
||||||
|
Terminal: 'false',
|
||||||
|
StartupWMClass: 'VRCX',
|
||||||
|
MimeType: 'x-scheme-handler/vrcx;'
|
||||||
|
};
|
||||||
|
const desktopFile =
|
||||||
|
'[Desktop Entry]\n' +
|
||||||
|
Object.entries(dotDesktop)
|
||||||
|
.map(([key, value]) => `${key}=${value}`)
|
||||||
|
.join('\n');
|
||||||
|
try {
|
||||||
|
// create/update the desktop file when needed
|
||||||
|
let existingDesktopFile = '';
|
||||||
|
if (fs.existsSync(desktopFilePath)) {
|
||||||
|
existingDesktopFile = fs.readFileSync(desktopFilePath, 'utf8');
|
||||||
|
}
|
||||||
|
if (existingDesktopFile !== desktopFile) {
|
||||||
|
fs.writeFileSync(desktopFilePath, desktopFile);
|
||||||
|
console.log('Desktop file created at:', desktopFilePath);
|
||||||
|
|
||||||
|
const result = spawnSync(
|
||||||
|
'xdg-mime',
|
||||||
|
['default', 'VRCX.desktop', 'x-scheme-handler/vrcx'],
|
||||||
|
{
|
||||||
|
encoding: 'utf-8'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (result.error) {
|
||||||
|
console.error('Error setting MIME type:', result.error);
|
||||||
|
} else {
|
||||||
|
console.log('MIME type set x-scheme-handler/vrcx');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error creating desktop file:', err);
|
||||||
|
dialog.showErrorBox('VRCX', 'Failed to create desktop entry.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function downloadIcon(url, targetPath) {
|
function downloadIcon(url, targetPath) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const file = fs.createWriteStream(targetPath);
|
const file = fs.createWriteStream(targetPath);
|
||||||
@@ -501,7 +498,7 @@ function getVersion() {
|
|||||||
|
|
||||||
// look for trailing git hash "-22bcd96" to indicate nightly build
|
// look for trailing git hash "-22bcd96" to indicate nightly build
|
||||||
var version = versionFile.split('-');
|
var version = versionFile.split('-');
|
||||||
console.log('Version:', version);
|
console.log('Version:', versionFile);
|
||||||
if (version.length > 0 && version[version.length - 1].length == 7) {
|
if (version.length > 0 && version[version.length - 1].length == 7) {
|
||||||
return `VRCX (Linux) Nightly ${versionFile}`;
|
return `VRCX (Linux) Nightly ${versionFile}`;
|
||||||
} else {
|
} else {
|
||||||
@@ -518,13 +515,9 @@ function isDotNetInstalled() {
|
|||||||
// Assume .NET is already installed on macOS
|
// Assume .NET is already installed on macOS
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const result = require('child_process').spawnSync(
|
const result = spawnSync('dotnet', ['--list-runtimes'], {
|
||||||
'dotnet',
|
|
||||||
['--list-runtimes'],
|
|
||||||
{
|
|
||||||
encoding: 'utf-8'
|
encoding: 'utf-8'
|
||||||
}
|
});
|
||||||
);
|
|
||||||
return result.stdout?.includes('.NETCore.App 9.0');
|
return result.stdout?.includes('.NETCore.App 9.0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user