mirror of
https://gitlab.com/vyla-entertainment/home.git
synced 2026-11-14 14:17:25 -05:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d799da3d2a | |||
| f4aaf2fa7c | |||
| 8ce4edc251 | |||
| bef6fd2326 | |||
| 774f9a5e03 | |||
| 250e7972f2 | |||
| 5082d51ebc | |||
| ed66b894c1 | |||
| 11d6c346e8 | |||
| c986194e64 | |||
| 33e285953c | |||
| f46869f967 | |||
| b19e6b21c9 | |||
| c8ea2598b9 | |||
| e3257b8a3a |
3
DOCUEMENTATION/FIXES.md
Normal file
3
DOCUEMENTATION/FIXES.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
If someone get's a Webview2 error, they need to download the WebView2Loader.dll and drag it in bin
|
||||||
|
|
||||||
|
bin\WebView2Loader.dll
|
||||||
38
README.md
38
README.md
@@ -1,30 +1,24 @@
|
|||||||
# Vyla Home Engine
|
# Vyla Home
|
||||||
|
|
||||||
A high-performance, locally executed environment for the Vyla media ecosystem. Built on the Tauri v2 framework, Vyla Home acts as a secure native bridge between local microservices and a lightweight WebView2 rendering engine.
|
A desktop application that provides a fast, secure, and private way to access the Vyla media ecosystem. Vyla Home runs everything locally on your computer, giving you quick access to streaming services without relying on external servers.
|
||||||
|
|
||||||
## Architecture & Security
|
## What It Does
|
||||||
|
|
||||||
Vyla Home is designed around complete local isolation to maximize speed, privacy, and reliability:
|
Vyla Home is a native desktop app that:
|
||||||
|
|
||||||
- **Zero External Reverse-Proxies**: All routing, API endpoints, and authentication middleware run strictly on local loopback interfaces (`127.0.0.1`), eliminating ISP throttling and data-center IP bans.
|
- **Runs locally** - All services run on your computer for maximum privacy and speed
|
||||||
- **Native Memory Management**: Background Node.js lifecycle states are managed directly via OS-level memory handles (bypassing slow shell wrappers) for instant startup and teardown.
|
- **Manages streaming services** - Handles authentication and streaming APIs automatically
|
||||||
- **Cryptographic Obfuscation**: Client configurations and credentials are secured on-disk via hardware-derived AES-256-GCM encryption.
|
- **Updates automatically** - Keeps itself up to date with the latest features and fixes
|
||||||
- **Automated Integrity Patching**: Payloads are dynamically verified using SHA-256 checksums and patched in-memory via C-level buffer scans.
|
- **Works offline** - Core functionality doesn't require constant internet connectivity
|
||||||
|
- **Keeps your data secure** - Your credentials and settings are encrypted and stored locally
|
||||||
|
|
||||||
## Build Requirements
|
## How It Works
|
||||||
|
|
||||||
- [Rust](https://www.rust-lang.org/) (Latest Stable)
|
When you launch Vyla Home, it:
|
||||||
- [Node.js](https://nodejs.org/) (v20+ LTS)
|
|
||||||
- Tauri CLI (`npm install -g @tauri-apps/cli`)
|
|
||||||
|
|
||||||
## Compilation
|
1. Starts the necessary background services (media player server)
|
||||||
|
2. Loads your saved settings and credentials (encrypted for security)
|
||||||
|
3. Checks for updates and installs them if available
|
||||||
|
4. Opens the user interface in a secure, embedded browser window
|
||||||
|
|
||||||
The build pipeline has been optimized with Fat LTO and aggressive panic aborts to generate the smallest possible binary footprint.
|
Everything happens on your machine - your data never leaves your computer except when communicating directly with streaming services.
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install
|
|
||||||
|
|
||||||
npm run build:payload
|
|
||||||
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
@@ -5,7 +5,7 @@ const AdmZip = require('adm-zip');
|
|||||||
const { execSync } = require('child_process');
|
const { execSync } = require('child_process');
|
||||||
|
|
||||||
const BUILD_DIR = path.join(__dirname, 'dist-build');
|
const BUILD_DIR = path.join(__dirname, 'dist-build');
|
||||||
const REPOS = ['frontend', 'player', 'auth-proxy', 'stream-api'];
|
const REPOS = ['frontend', 'player'];
|
||||||
|
|
||||||
const TEMP_EXTRACT_DIR = path.join(__dirname, 'temp-validation-extract');
|
const TEMP_EXTRACT_DIR = path.join(__dirname, 'temp-validation-extract');
|
||||||
|
|
||||||
@@ -14,8 +14,6 @@ const GITLAB_GROUP = 'vyla-entertainment';
|
|||||||
const REPO_CONFIG = {
|
const REPO_CONFIG = {
|
||||||
'frontend': { name: 'frontend', branch: 'main' },
|
'frontend': { name: 'frontend', branch: 'main' },
|
||||||
'player': { name: 'player', branch: 'main' },
|
'player': { name: 'player', branch: 'main' },
|
||||||
'auth-proxy': { name: 'auth-proxy', branch: 'main' },
|
|
||||||
'stream-api': { name: 'stream-api', branch: 'main' },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const clonedRepos = new Set();
|
const clonedRepos = new Set();
|
||||||
@@ -174,9 +172,7 @@ function validatePayload(zipPath) {
|
|||||||
zip.extractAllTo(TEMP_EXTRACT_DIR, true);
|
zip.extractAllTo(TEMP_EXTRACT_DIR, true);
|
||||||
|
|
||||||
const requiredFiles = [
|
const requiredFiles = [
|
||||||
'player/index.html',
|
'player/server.js',
|
||||||
'auth-proxy/server.js',
|
|
||||||
'stream-api/server.js',
|
|
||||||
'frontend/index.html'
|
'frontend/index.html'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
{
|
{
|
||||||
"player": {
|
"player": {
|
||||||
"TMDB_KEY": "YOUR_TMDB_KEY_HERE",
|
"TMDB_KEY": "YOUR_TMDB_KEY_HERE"
|
||||||
"API_KEY": "YOUR_API_KEY_HERE"
|
|
||||||
},
|
|
||||||
"auth-proxy": {
|
|
||||||
"VITE_API_KEY": "YOUR_VITE_API_KEY_HERE",
|
|
||||||
"PROXY_VITE_API_KEY": "YOUR_PROXY_VITE_API_KEY_HERE"
|
|
||||||
},
|
|
||||||
"stream-api": {
|
|
||||||
"TMDB_API_KEY": "YOUR_TMDB_API_KEY_HERE",
|
|
||||||
"GA_MEASUREMENT_ID": "YOUR_GA_MEASUREMENT_ID_HERE",
|
|
||||||
"GA_API_SECRET": "YOUR_GA_API_SECRET_HERE",
|
|
||||||
"TOKEN_SECRET": "YOUR_TOKEN_SECRET_HERE"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,5 @@
|
|||||||
{
|
{
|
||||||
"player": {
|
"player": {
|
||||||
"PORT": "3001",
|
"PORT": "3000"
|
||||||
"BASE_URL": "http://localhost:7860",
|
|
||||||
"BYPASS_AUTH": "true"
|
|
||||||
},
|
|
||||||
"auth-proxy": {
|
|
||||||
"PORT": "3000",
|
|
||||||
"VITE_BASE_URL": "http://localhost:7860",
|
|
||||||
"DEV_BYPASS_AUTH": "true"
|
|
||||||
},
|
|
||||||
"stream-api": {
|
|
||||||
"PORT": "7860",
|
|
||||||
"PROXY_URL": "https://txt.primebox.workers.dev",
|
|
||||||
"PROXY_STREAMS": "true",
|
|
||||||
"ENABLE_DEBUG_ROUTE": "true",
|
|
||||||
"BYPASS_AUTH": "true",
|
|
||||||
"TOKEN_SECRET": "vyla_default_secure_token_secret_local_dev_32chars"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,40 +2,17 @@
|
|||||||
"frontend": [
|
"frontend": [
|
||||||
{
|
{
|
||||||
"find": "https://player.vyla.cc",
|
"find": "https://player.vyla.cc",
|
||||||
"replace": "http://localhost:3001"
|
"replace": "http://localhost:3000"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"find": "http://player.vyla.cc",
|
"find": "http://player.vyla.cc",
|
||||||
"replace": "http://localhost:3001"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"find": "https://api.vyla.cc",
|
|
||||||
"replace": "http://localhost:7860"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"find": "https://auth.vyla.cc",
|
|
||||||
"replace": "http://localhost:3000"
|
"replace": "http://localhost:3000"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"player": [
|
"player": [
|
||||||
{
|
|
||||||
"find": "https://api.vyla.cc",
|
|
||||||
"replace": "http://localhost:7860"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"find": "https://auth.vyla.cc",
|
|
||||||
"replace": "http://localhost:3000"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"find": "https://player.vyla.cc",
|
"find": "https://player.vyla.cc",
|
||||||
"replace": "http://localhost:4890"
|
"replace": "http://localhost:4890"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"auth-proxy": [
|
|
||||||
{
|
|
||||||
"find": "https://player.vyla.cc",
|
|
||||||
"replace": "http://localhost:3001"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stream-api": []
|
|
||||||
}
|
}
|
||||||
@@ -4,9 +4,7 @@ const path = require('path');
|
|||||||
|
|
||||||
const REPOS = {
|
const REPOS = {
|
||||||
frontend: { branch: 'main' },
|
frontend: { branch: 'main' },
|
||||||
player: { branch: 'main' },
|
player: { branch: 'main' }
|
||||||
'stream-api': { branch: 'main' },
|
|
||||||
'auth-proxy': { branch: 'main' }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const GITLAB_GROUP = 'vyla-entertainment';
|
const GITLAB_GROUP = 'vyla-entertainment';
|
||||||
|
|||||||
130
main.js
130
main.js
@@ -34,8 +34,6 @@ debugLog("--- Node.js Process Started ---");
|
|||||||
let serviceManager;
|
let serviceManager;
|
||||||
let expressApp;
|
let expressApp;
|
||||||
let expressServer;
|
let expressServer;
|
||||||
let playerExpressApp;
|
|
||||||
let playerExpressServer;
|
|
||||||
|
|
||||||
debugLog(`AppData Dir: ${APPDATA_DIR}`);
|
debugLog(`AppData Dir: ${APPDATA_DIR}`);
|
||||||
|
|
||||||
@@ -217,27 +215,51 @@ async function start() {
|
|||||||
let localSha = patcher.getCurrentSha();
|
let localSha = patcher.getCurrentSha();
|
||||||
debugLog(`Is First Run: ${isFirstRun}, Local Version: ${localVersion}, Local SHA: ${localSha}`);
|
debugLog(`Is First Run: ${isFirstRun}, Local Version: ${localVersion}, Local SHA: ${localSha}`);
|
||||||
|
|
||||||
const localZipPath = path.join(__dirname, 'update-payload.zip');
|
function findLocalZip() {
|
||||||
const localManifestPath = path.join(__dirname, 'manifest.json');
|
const searchRoots = [__dirname, process.cwd()];
|
||||||
let localZipManifest = null;
|
for (const root of searchRoots) {
|
||||||
|
let cur = root;
|
||||||
if (fs.existsSync(localZipPath) && fs.existsSync(localManifestPath)) {
|
for (let i = 0; i < 6; i++) {
|
||||||
try { localZipManifest = JSON.parse(fs.readFileSync(localManifestPath, 'utf8')); } catch (e) { }
|
const zp = path.join(cur, 'update-payload.zip');
|
||||||
|
if (fs.existsSync(zp)) {
|
||||||
|
const mp = path.join(cur, 'manifest.json');
|
||||||
|
return { zipPath: zp, manifestPath: fs.existsSync(mp) ? mp : null };
|
||||||
|
}
|
||||||
|
const parent = path.dirname(cur);
|
||||||
|
if (parent === cur) break;
|
||||||
|
cur = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localZipManifest && (isFirstRun || localZipManifest.sha256 !== localSha)) {
|
const localFound = findLocalZip();
|
||||||
debugLog("New local payload detected! Applying local build...");
|
let localZipPath = localFound ? localFound.zipPath : null;
|
||||||
|
let localManifestPath = localFound ? localFound.manifestPath : null;
|
||||||
|
let localZipManifest = null;
|
||||||
|
|
||||||
|
if (localManifestPath) {
|
||||||
|
try {
|
||||||
|
localZipManifest = JSON.parse(fs.readFileSync(localManifestPath, 'utf8'));
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localZipPath && (isFirstRun || (localZipManifest && localZipManifest.sha256 !== localSha))) {
|
||||||
|
debugLog(`Applying local development payload from: ${localZipPath}`);
|
||||||
sendToTauri('status', { message: 'Extracting local development payload...' });
|
sendToTauri('status', { message: 'Extracting local development payload...' });
|
||||||
patcher.purgeOldCode();
|
patcher.purgeOldCode();
|
||||||
patcher.extractZipPayload(localZipPath);
|
patcher.extractZipPayload(localZipPath);
|
||||||
patcher.applyPatches(getReplacementsConfig());
|
patcher.applyPatches(getReplacementsConfig());
|
||||||
patcher.bridgeCredentials(serviceManager.credentialManager);
|
patcher.bridgeCredentials(serviceManager.credentialManager);
|
||||||
patcher.saveCurrentVersion(localZipManifest.version, localZipManifest.sha256);
|
|
||||||
|
const ver = localZipManifest ? localZipManifest.version : '1.1.32';
|
||||||
|
const sha = localZipManifest ? localZipManifest.sha256 : null;
|
||||||
|
patcher.saveCurrentVersion(ver, sha);
|
||||||
serviceManager.envConfig = getEnvConfig();
|
serviceManager.envConfig = getEnvConfig();
|
||||||
|
|
||||||
isFirstRun = false;
|
isFirstRun = false;
|
||||||
localVersion = localZipManifest.version;
|
localVersion = ver;
|
||||||
localSha = localZipManifest.sha256;
|
localSha = sha;
|
||||||
debugLog("Local payload applied successfully.");
|
debugLog("Local payload applied successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,18 +269,43 @@ async function start() {
|
|||||||
debugLog("Fetching updates from updateClient...");
|
debugLog("Fetching updates from updateClient...");
|
||||||
release = await updateClient.checkForUpdates();
|
release = await updateClient.checkForUpdates();
|
||||||
debugLog(`Update check finished. Found: ${release ? release.version : 'None'}`);
|
debugLog(`Update check finished. Found: ${release ? release.version : 'None'}`);
|
||||||
|
|
||||||
|
let appPkgVer = '0.0.0';
|
||||||
|
try {
|
||||||
|
appPkgVer = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')).version || '0.0.0';
|
||||||
|
} catch (e) { }
|
||||||
|
|
||||||
|
if (release && release.version) {
|
||||||
|
const rVer = release.version.replace('v', '').split('.').map(Number);
|
||||||
|
const aVer = appPkgVer.split('.').map(Number);
|
||||||
|
let isOlder = false;
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
if ((rVer[i] || 0) < (aVer[i] || 0)) { isOlder = true; break; }
|
||||||
|
if ((rVer[i] || 0) > (aVer[i] || 0)) { break; }
|
||||||
|
}
|
||||||
|
if (isOlder) {
|
||||||
|
debugLog(`Remote version ${release.version} is older than local package ${appPkgVer}. Ignoring remote release.`);
|
||||||
|
release = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugLog(`Update check failed (offline?): ${e.message}`);
|
debugLog(`Update check failed (offline?): ${e.message}`);
|
||||||
sendToTauri('status', { message: `Update server check skipped (${e.message})` });
|
sendToTauri('status', { message: `Update server check skipped (${e.message})` });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizeVer = (v) => (v || '').toString().replace(/^v/, '').trim();
|
||||||
|
|
||||||
if (release) {
|
if (release) {
|
||||||
const hasUpdate = release.version !== localVersion || (release.sha256 && release.sha256 !== localSha);
|
const isNewerSha = release.sha256 && localSha && release.sha256 !== localSha;
|
||||||
|
const isDifferentVer = normalizeVer(release.version) !== normalizeVer(localVersion);
|
||||||
|
const hasUpdate = (isDifferentVer || isNewerSha) && !localZipPath;
|
||||||
|
|
||||||
if (isFirstRun) {
|
if (isFirstRun) {
|
||||||
debugLog("First run. Installing remote build...");
|
debugLog("First run with no local payload. Installing remote build...");
|
||||||
sendToTauri('status', { message: 'First run detected. Preparing initial installation...' });
|
sendToTauri('status', { message: 'First run detected. Preparing initial installation...' });
|
||||||
await installBuild(release);
|
await installBuild(release);
|
||||||
} else if (hasUpdate) {
|
} else if (hasUpdate) {
|
||||||
|
|
||||||
debugLog("Update available. Prompting user...");
|
debugLog("Update available. Prompting user...");
|
||||||
sendToTauri('status', { message: `New update available (${release.version}). Awaiting confirmation...` });
|
sendToTauri('status', { message: `New update available (${release.version}). Awaiting confirmation...` });
|
||||||
|
|
||||||
@@ -327,51 +374,21 @@ async function start() {
|
|||||||
|
|
||||||
sendToTauri('status', { message: 'Validating critical components...' });
|
sendToTauri('status', { message: 'Validating critical components...' });
|
||||||
if (!patcher.verifyExtraction()) {
|
if (!patcher.verifyExtraction()) {
|
||||||
throw new Error('No application files found. Check your internet connection and try again.');
|
throw new Error('No application files found. Ensure you run "npm run build:payload" to generate the local development payload.');
|
||||||
}
|
}
|
||||||
|
|
||||||
sendToTauri('status', { message: 'Loading encrypted credentials...' });
|
sendToTauri('status', { message: 'Loading encrypted credentials...' });
|
||||||
serviceManager.credentialManager.loadCredentials();
|
serviceManager.credentialManager.loadCredentials();
|
||||||
|
|
||||||
sendToTauri('status', { message: 'Starting background services (auth-proxy, stream-api)...' });
|
sendToTauri('status', { message: 'Starting background services (player)...' });
|
||||||
await serviceManager.startServices([
|
await serviceManager.startServices([
|
||||||
{ name: 'auth-proxy', relativeDir: 'auth-proxy' },
|
{ name: 'player', relativeDir: 'player', startScript: 'server.js' }
|
||||||
{ name: 'stream-api', relativeDir: 'stream-api' },
|
|
||||||
]);
|
]);
|
||||||
debugLog("Backend services spawn requested.");
|
debugLog("Backend services spawn requested.");
|
||||||
|
|
||||||
sendToTauri('status', { message: 'Binding player web server on port 3001...' });
|
sendToTauri('status', { message: 'Waiting for microservices to bind port 3000...' });
|
||||||
const playerDir = path.join(APPDATA_DIR, 'player');
|
await serviceManager.waitForPorts([3000]);
|
||||||
playerExpressApp = express();
|
debugLog("Port 3000 is ready.");
|
||||||
playerExpressApp.use((req, res, next) => {
|
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
|
||||||
res.header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
|
|
||||||
res.header('Access-Control-Allow-Headers', '*');
|
|
||||||
if (req.method === 'OPTIONS') return res.sendStatus(200);
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
playerExpressApp.get('/__tauri_cmd/:cmd', (req, res) => {
|
|
||||||
debugLog(`[PLAYER-SERVER:3001] Command received: ${req.params.cmd} (window: ${req.query.window || 'main'})`);
|
|
||||||
sendToTauri('tauri-cmd', { cmd: req.params.cmd, url: req.query.url, window: req.query.window });
|
|
||||||
res.sendStatus(200);
|
|
||||||
});
|
|
||||||
playerExpressApp.use(sameTabNavMiddleware(playerDir));
|
|
||||||
playerExpressApp.use(express.static(playerDir, {
|
|
||||||
etag: false,
|
|
||||||
setHeaders: (res) => {
|
|
||||||
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
playerExpressApp.get('*', (req, res) => {
|
|
||||||
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
|
|
||||||
res.sendFile(path.join(playerDir, 'index.html'));
|
|
||||||
});
|
|
||||||
playerExpressServer = playerExpressApp.listen(3001, '127.0.0.1');
|
|
||||||
debugLog("Player Express running on 3001");
|
|
||||||
|
|
||||||
sendToTauri('status', { message: 'Waiting for microservices to bind ports (3000, 3001, 7860)...' });
|
|
||||||
await serviceManager.waitForPorts([3000, 3001, 7860]);
|
|
||||||
debugLog("Ports 3000, 3001, 7860 are ready.");
|
|
||||||
|
|
||||||
sendToTauri('status', { message: 'Binding UI server on port 4890...' });
|
sendToTauri('status', { message: 'Binding UI server on port 4890...' });
|
||||||
const frontendDir = path.join(APPDATA_DIR, 'frontend');
|
const frontendDir = path.join(APPDATA_DIR, 'frontend');
|
||||||
@@ -396,6 +413,12 @@ async function start() {
|
|||||||
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
|
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
expressApp.use(express.static(path.join(frontendDir, 'src'), {
|
||||||
|
etag: false,
|
||||||
|
setHeaders: (res) => {
|
||||||
|
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
|
||||||
|
}
|
||||||
|
}));
|
||||||
expressApp.get('*', (req, res) => {
|
expressApp.get('*', (req, res) => {
|
||||||
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
|
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
|
||||||
res.sendFile(path.join(frontendDir, 'index.html'));
|
res.sendFile(path.join(frontendDir, 'index.html'));
|
||||||
@@ -403,11 +426,8 @@ async function start() {
|
|||||||
|
|
||||||
const FRONTEND_PORT = 4890;
|
const FRONTEND_PORT = 4890;
|
||||||
expressApp.use('/build', express.static(path.join(__dirname, 'build')));
|
expressApp.use('/build', express.static(path.join(__dirname, 'build')));
|
||||||
if (playerExpressApp) {
|
|
||||||
playerExpressApp.use('/build', express.static(path.join(__dirname, 'build')));
|
|
||||||
}
|
|
||||||
|
|
||||||
expressServer = expressApp.listen(FRONTEND_PORT, '127.0.0.1', () => {
|
expressServer = expressApp.listen(FRONTEND_PORT, () => {
|
||||||
sendToTauri('status', { message: 'All backend services running and healthy.' });
|
sendToTauri('status', { message: 'All backend services running and healthy.' });
|
||||||
debugLog("Frontend Express running on 4890. Sending READY to Tauri.");
|
debugLog("Frontend Express running on 4890. Sending READY to Tauri.");
|
||||||
sendToTauri('ready', { url: `http://localhost:${FRONTEND_PORT}` });
|
sendToTauri('ready', { url: `http://localhost:${FRONTEND_PORT}` });
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vyla-home",
|
"name": "vyla-home",
|
||||||
"version": "1.1.25",
|
"version": "1.1.33",
|
||||||
"description": "Vyla Home Desktop App Launcher",
|
"description": "Vyla Home Desktop App Launcher",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -99,9 +99,7 @@ class Patcher {
|
|||||||
|
|
||||||
verifyExtraction() {
|
verifyExtraction() {
|
||||||
const requiredFiles = [
|
const requiredFiles = [
|
||||||
'player/index.html',
|
'player/server.js',
|
||||||
'auth-proxy/server.js',
|
|
||||||
'stream-api/server.js',
|
|
||||||
'frontend/index.html'
|
'frontend/index.html'
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -155,7 +153,7 @@ class Patcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applyPatches(replacements) {
|
applyPatches(replacements) {
|
||||||
const targetDirs = ['frontend', 'player', 'auth-proxy', 'stream-api'];
|
const targetDirs = ['frontend', 'player'];
|
||||||
for (const dirName of targetDirs) {
|
for (const dirName of targetDirs) {
|
||||||
const dirPath = path.join(this.appDataPath, dirName);
|
const dirPath = path.join(this.appDataPath, dirName);
|
||||||
if (!fs.existsSync(dirPath)) continue;
|
if (!fs.existsSync(dirPath)) continue;
|
||||||
|
|||||||
@@ -40,18 +40,16 @@ class ServiceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tokenSecret = process.env.TOKEN_SECRET ||
|
let tokenSecret = process.env.TOKEN_SECRET ||
|
||||||
process.env.STREAM_API_TOKEN_SECRET ||
|
this.credentialManager.getCredential('player', 'TOKEN_SECRET');
|
||||||
this.credentialManager.getCredential('stream-api', 'TOKEN_SECRET');
|
|
||||||
|
|
||||||
if (!tokenSecret || tokenSecret.length < 32) {
|
if (!tokenSecret || tokenSecret.length < 32) {
|
||||||
tokenSecret = require('crypto').randomBytes(32).toString('hex');
|
tokenSecret = require('crypto').randomBytes(32).toString('hex');
|
||||||
this.credentialManager.setCredential('stream-api', 'TOKEN_SECRET', tokenSecret);
|
this.credentialManager.setCredential('player', 'TOKEN_SECRET', tokenSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
const env = {
|
const env = {
|
||||||
...process.env,
|
...process.env,
|
||||||
TOKEN_SECRET: tokenSecret,
|
TOKEN_SECRET: tokenSecret,
|
||||||
STREAM_API_TOKEN_SECRET: tokenSecret,
|
|
||||||
...(this.envConfig[name] || {}),
|
...(this.envConfig[name] || {}),
|
||||||
...(this.credentialManager.getServiceCredentials(name) || {})
|
...(this.credentialManager.getServiceCredentials(name) || {})
|
||||||
};
|
};
|
||||||
|
|||||||
69
src-tauri/Cargo.lock
generated
69
src-tauri/Cargo.lock
generated
@@ -270,7 +270,7 @@ version = "0.6.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
|
checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -762,7 +762,7 @@ dependencies = [
|
|||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"block2",
|
"block2",
|
||||||
"libc",
|
"libc",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2079,7 +2079,7 @@ dependencies = [
|
|||||||
"dpi",
|
"dpi",
|
||||||
"gtk",
|
"gtk",
|
||||||
"keyboard-types",
|
"keyboard-types",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
@@ -2157,6 +2157,22 @@ dependencies = [
|
|||||||
"syn 2.0.119",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc-sys"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
|
||||||
|
dependencies = [
|
||||||
|
"objc-sys",
|
||||||
|
"objc2-encode",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2"
|
name = "objc2"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
@@ -2175,7 +2191,7 @@ checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"block2",
|
"block2",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
@@ -2187,7 +2203,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c"
|
checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2197,7 +2213,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa"
|
checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2209,7 +2225,7 @@ checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"dispatch2",
|
"dispatch2",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2220,7 +2236,7 @@ checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"dispatch2",
|
"dispatch2",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-io-surface",
|
"objc2-io-surface",
|
||||||
]
|
]
|
||||||
@@ -2231,7 +2247,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006"
|
checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2241,7 +2257,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009"
|
checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2252,7 +2268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d"
|
checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-core-graphics",
|
"objc2-core-graphics",
|
||||||
]
|
]
|
||||||
@@ -2280,7 +2296,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"block2",
|
"block2",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2291,7 +2307,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
|
checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2302,7 +2318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
|
checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
@@ -2315,7 +2331,7 @@ checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"block2",
|
"block2",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-cloud-kit",
|
"objc2-cloud-kit",
|
||||||
"objc2-core-data",
|
"objc2-core-data",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
@@ -2334,7 +2350,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e"
|
checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2346,7 +2362,7 @@ checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"block2",
|
"block2",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
@@ -3211,7 +3227,7 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"ndk",
|
"ndk",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-core-graphics",
|
"objc2-core-graphics",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
@@ -3385,7 +3401,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk",
|
||||||
"ndk-sys",
|
"ndk-sys",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
@@ -3441,7 +3457,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
"muda",
|
"muda",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
@@ -3612,7 +3628,7 @@ dependencies = [
|
|||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
"jni",
|
"jni",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
"objc2-web-kit",
|
"objc2-web-kit",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
@@ -3636,7 +3652,7 @@ dependencies = [
|
|||||||
"http",
|
"http",
|
||||||
"jni",
|
"jni",
|
||||||
"log",
|
"log",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
@@ -4051,7 +4067,7 @@ dependencies = [
|
|||||||
"dirs",
|
"dirs",
|
||||||
"libappindicator",
|
"libappindicator",
|
||||||
"muda",
|
"muda",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-core-graphics",
|
"objc2-core-graphics",
|
||||||
@@ -4222,9 +4238,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vyla-home"
|
name = "vyla-home"
|
||||||
version = "1.1.25"
|
version = "1.1.33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
"objc2 0.5.2",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
@@ -4475,7 +4492,7 @@ version = "0.6.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c"
|
checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
@@ -4930,7 +4947,7 @@ dependencies = [
|
|||||||
"jni",
|
"jni",
|
||||||
"libc",
|
"libc",
|
||||||
"ndk",
|
"ndk",
|
||||||
"objc2",
|
"objc2 0.6.4",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vyla-home"
|
name = "vyla-home"
|
||||||
version = "1.1.25"
|
version = "1.1.33"
|
||||||
description = "Vyla Home Desktop App Launcher"
|
description = "Vyla Home Desktop App Launcher"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -16,6 +16,9 @@ serde = { version = "1", features = ["derive"] }
|
|||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
|
objc2 = "0.5"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
@@ -6,16 +6,8 @@
|
|||||||
<dict>
|
<dict>
|
||||||
<key>NSAllowsLocalNetworking</key>
|
<key>NSAllowsLocalNetworking</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSExceptionDomains</key>
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
<dict>
|
<true/>
|
||||||
<key>localhost</key>
|
|
||||||
<dict>
|
|
||||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
|
||||||
<true/>
|
|
||||||
<key>NSIncludesSubdomains</key>
|
|
||||||
<false/>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -16,5 +16,17 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
let node_path = std::path::Path::new("../bin/node");
|
||||||
|
if node_path.exists() {
|
||||||
|
let _ = std::fs::set_permissions(
|
||||||
|
node_path,
|
||||||
|
std::fs::Permissions::from_mode(0o755),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tauri_build::build();
|
tauri_build::build();
|
||||||
}
|
}
|
||||||
@@ -7,11 +7,19 @@ use tauri::{Emitter, Manager, State, WebviewUrl, WebviewWindowBuilder};
|
|||||||
|
|
||||||
fn debug_log(msg: &str) {
|
fn debug_log(msg: &str) {
|
||||||
let log_dir = if let Ok(app_data) = std::env::var("APPDATA") {
|
let log_dir = if let Ok(app_data) = std::env::var("APPDATA") {
|
||||||
std::path::PathBuf::from(app_data).join("vyla-home").join("vyla-home-files").join("logs")
|
std::path::PathBuf::from(app_data)
|
||||||
|
.join("vyla-home")
|
||||||
|
.join("vyla-home-files")
|
||||||
|
.join("logs")
|
||||||
} else if let Ok(home) = std::env::var("HOME") {
|
} else if let Ok(home) = std::env::var("HOME") {
|
||||||
std::path::PathBuf::from(home).join("Library").join("Logs").join("VylaHome")
|
std::path::PathBuf::from(home)
|
||||||
|
.join("Library")
|
||||||
|
.join("Logs")
|
||||||
|
.join("VylaHome")
|
||||||
} else if let Ok(user_profile) = std::env::var("USERPROFILE") {
|
} else if let Ok(user_profile) = std::env::var("USERPROFILE") {
|
||||||
std::path::PathBuf::from(user_profile).join(".vyla-home").join("logs")
|
std::path::PathBuf::from(user_profile)
|
||||||
|
.join(".vyla-home")
|
||||||
|
.join("logs")
|
||||||
} else {
|
} else {
|
||||||
std::env::temp_dir().join("vyla-home-logs")
|
std::env::temp_dir().join("vyla-home-logs")
|
||||||
};
|
};
|
||||||
@@ -19,7 +27,11 @@ fn debug_log(msg: &str) {
|
|||||||
let _ = std::fs::create_dir_all(&log_dir);
|
let _ = std::fs::create_dir_all(&log_dir);
|
||||||
let log_path = log_dir.join("rust-debug.log");
|
let log_path = log_dir.join("rust-debug.log");
|
||||||
|
|
||||||
if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open(&log_path) {
|
if let Ok(mut file) = std::fs::OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.append(true)
|
||||||
|
.open(&log_path)
|
||||||
|
{
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
let _ = writeln!(file, "[RUST] {}", msg);
|
let _ = writeln!(file, "[RUST] {}", msg);
|
||||||
}
|
}
|
||||||
@@ -109,6 +121,7 @@ fn find_node_binary(app: &tauri::App) -> Option<String> {
|
|||||||
if node_exe.exists() {
|
if node_exe.exists() {
|
||||||
return Some(clean_path(&node_exe));
|
return Some(clean_path(&node_exe));
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = p.join("node");
|
let node = p.join("node");
|
||||||
if node.exists() {
|
if node.exists() {
|
||||||
return Some(clean_path(&node));
|
return Some(clean_path(&node));
|
||||||
@@ -166,7 +179,6 @@ fn resolve_script_and_root(app: &tauri::App) -> (String, String) {
|
|||||||
resource_dir.join("_up_").join("main.js"),
|
resource_dir.join("_up_").join("main.js"),
|
||||||
resource_dir.join("up").join("main.js"),
|
resource_dir.join("up").join("main.js"),
|
||||||
];
|
];
|
||||||
|
|
||||||
for candidate in candidates {
|
for candidate in candidates {
|
||||||
if candidate.exists() {
|
if candidate.exists() {
|
||||||
let root_dir = candidate.parent().unwrap();
|
let root_dir = candidate.parent().unwrap();
|
||||||
@@ -325,10 +337,7 @@ const LINK_HANDLER_SCRIPT: &str = r##"
|
|||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vyla-nav-btn:hover {
|
.vyla-nav-btn:hover { opacity: 1 !important; }
|
||||||
opacity: 1 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vyla-nav-btn svg {
|
.vyla-nav-btn svg {
|
||||||
width: 20px !important;
|
width: 20px !important;
|
||||||
height: 20px !important;
|
height: 20px !important;
|
||||||
@@ -455,11 +464,12 @@ const LINK_HANDLER_SCRIPT: &str = r##"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', injectLiquidNavBar);
|
document.addEventListener('DOMContentLoaded', injectLiquidNavBar);
|
||||||
} else {
|
} else {
|
||||||
injectLiquidNavBar();
|
injectLiquidNavBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
const navObserver = new MutationObserver(() => {
|
const navObserver = new MutationObserver(() => {
|
||||||
if (!document.getElementById('vyla-floating-nav')) {
|
if (!document.getElementById('vyla-floating-nav')) {
|
||||||
injectLiquidNavBar();
|
injectLiquidNavBar();
|
||||||
@@ -503,9 +513,9 @@ fn open_new_window(app: tauri::AppHandle, url: String) -> Result<(), String> {
|
|||||||
let final_url = if url.starts_with("http") || url.starts_with("tauri://") {
|
let final_url = if url.starts_with("http") || url.starts_with("tauri://") {
|
||||||
url.clone()
|
url.clone()
|
||||||
} else if url.starts_with('/') {
|
} else if url.starts_with('/') {
|
||||||
format!("http://localhost:4890{}", url)
|
format!("http://127.0.0.1:4890{}", url)
|
||||||
} else {
|
} else {
|
||||||
format!("http://localhost:4890/{}", url)
|
format!("http://127.0.0.1:4890/{}", url)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(window) = app.get_webview_window("main") {
|
if let Some(window) = app.get_webview_window("main") {
|
||||||
@@ -578,6 +588,123 @@ fn get_logo_base64(app: tauri::AppHandle) -> Result<String, String> {
|
|||||||
Err("icon_white.png not found".to_string())
|
Err("icon_white.png not found".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_tauri_cmd(w: &tauri::WebviewWindow, msg: &BackendMessage) {
|
||||||
|
let window_label = msg
|
||||||
|
.data
|
||||||
|
.get("window")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.unwrap_or("main");
|
||||||
|
|
||||||
|
debug_log(&format!("[MAIN-DEBUG] Finding window by label: {}", window_label));
|
||||||
|
|
||||||
|
let cmd_window = match w.app_handle().get_webview_window(window_label) {
|
||||||
|
Some(win) => win,
|
||||||
|
None => {
|
||||||
|
debug_log(&format!("[TAURI-CMD] Window '{}' NOT FOUND!", window_label));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let cmd = match msg.data.get("cmd").and_then(|c| c.as_str()) {
|
||||||
|
Some(c) => c,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_log(&format!("[TAURI-CMD] Executing action: {}", cmd));
|
||||||
|
|
||||||
|
match cmd {
|
||||||
|
"win_minimize" => {
|
||||||
|
let res = cmd_window.minimize();
|
||||||
|
debug_log(&format!("[TAURI-CMD] Minimize result: {:?}", res));
|
||||||
|
}
|
||||||
|
"win_maximize" => {
|
||||||
|
let is_max = cmd_window.is_maximized().unwrap_or(false);
|
||||||
|
debug_log(&format!("[TAURI-CMD] Currently maximized: {}", is_max));
|
||||||
|
let res = if is_max {
|
||||||
|
cmd_window.unmaximize()
|
||||||
|
} else {
|
||||||
|
cmd_window.maximize()
|
||||||
|
};
|
||||||
|
debug_log(&format!("[TAURI-CMD] Maximize/Unmaximize result: {:?}", res));
|
||||||
|
}
|
||||||
|
"win_close" => {
|
||||||
|
let res = cmd_window.close();
|
||||||
|
debug_log(&format!("[TAURI-CMD] Close result: {:?}", res));
|
||||||
|
}
|
||||||
|
"win_drag" => {
|
||||||
|
let res = cmd_window.start_dragging();
|
||||||
|
debug_log(&format!("[TAURI-CMD] Drag result: {:?}", res));
|
||||||
|
}
|
||||||
|
"open_new_window" => {
|
||||||
|
debug_log("[TAURI-CMD-DEBUG] open_new_window command received");
|
||||||
|
debug_log(&format!(
|
||||||
|
"[TAURI-CMD-DEBUG] Full message data: {}",
|
||||||
|
serde_json::to_string(&msg.data).unwrap_or_default()
|
||||||
|
));
|
||||||
|
|
||||||
|
let url = match msg.data.get("url").and_then(|u| u.as_str()) {
|
||||||
|
Some(u) => u.to_string(),
|
||||||
|
None => {
|
||||||
|
debug_log("[TAURI-CMD-DEBUG] ERROR: No URL found in message data");
|
||||||
|
debug_log(&format!(
|
||||||
|
"[TAURI-CMD-DEBUG] Available keys: {:?}",
|
||||||
|
msg.data.as_object().map(|o| o.keys().collect::<Vec<_>>())
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_log(&format!("[TAURI-CMD-DEBUG] URL extracted: {}", url));
|
||||||
|
debug_log(&format!("[TAURI-CMD-DEBUG] URL length: {}", url.len()));
|
||||||
|
debug_log("[TAURI-CMD-DEBUG] Attempting to dispatch to main thread");
|
||||||
|
|
||||||
|
let app_handle = w.app_handle().clone();
|
||||||
|
let closure_handle = app_handle.clone();
|
||||||
|
|
||||||
|
match app_handle.run_on_main_thread(move || {
|
||||||
|
debug_log("[TAURI-CMD-DEBUG] Now on main thread, calling open_new_window");
|
||||||
|
match open_new_window(closure_handle, url) {
|
||||||
|
Ok(_) => debug_log("[TAURI-CMD-DEBUG] open_new_window succeeded"),
|
||||||
|
Err(e) => debug_log(&format!("[TAURI-CMD-DEBUG] open_new_window error: {}", e)),
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Ok(_) => debug_log("[TAURI-CMD-DEBUG] Main thread dispatch succeeded"),
|
||||||
|
Err(e) => debug_log(&format!("[TAURI-CMD-DEBUG] Main thread dispatch failed: {}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_ready(w: &tauri::WebviewWindow, msg: &BackendMessage) {
|
||||||
|
let url_str = match msg.data.get("url").and_then(|u| u.as_str()) {
|
||||||
|
Some(u) => u,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let url_parsed = match url_str.parse::<tauri::Url>() {
|
||||||
|
Ok(u) => u,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
use objc2::msg_send;
|
||||||
|
use objc2::runtime::AnyObject;
|
||||||
|
debug_log("Attempting with_webview on ready event");
|
||||||
|
let result = w.with_webview(|webview| unsafe {
|
||||||
|
debug_log("Inside with_webview closure");
|
||||||
|
let wk_webview = webview.inner() as *mut AnyObject;
|
||||||
|
let config: *mut AnyObject = msg_send![wk_webview, configuration];
|
||||||
|
let _: () = msg_send![config, setUpgradeKnownHostsToHTTPS: false];
|
||||||
|
debug_log("setUpgradeKnownHostsToHTTPS set to false");
|
||||||
|
});
|
||||||
|
debug_log(&format!("with_webview result: {:?}", result));
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = w.navigate(url_parsed);
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
debug_log("=== Vyla Home Executable Started ===");
|
debug_log("=== Vyla Home Executable Started ===");
|
||||||
|
|
||||||
@@ -603,7 +730,7 @@ fn main() {
|
|||||||
std::path::PathBuf::from(appdata_env)
|
std::path::PathBuf::from(appdata_env)
|
||||||
.join("vyla-home")
|
.join("vyla-home")
|
||||||
.join("vyla-home-files")
|
.join("vyla-home-files")
|
||||||
} else if let Ok(home) = std::env::var("HOME") {
|
} else if let Ok(home) = std::env::var("HOME") {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let base = std::path::PathBuf::from(&home)
|
let base = std::path::PathBuf::from(&home)
|
||||||
.join("Library")
|
.join("Library")
|
||||||
@@ -619,34 +746,7 @@ fn main() {
|
|||||||
app_data.join("vyla-home-files")
|
app_data.join("vyla-home-files")
|
||||||
};
|
};
|
||||||
|
|
||||||
let version_file = vyla_files.join("version.json");
|
let _ = std::fs::create_dir_all(&vyla_files);
|
||||||
let current_app_version = app.package_info().version.to_string();
|
|
||||||
let mut version_mismatch = false;
|
|
||||||
|
|
||||||
if version_file.exists() {
|
|
||||||
if let Ok(content) = std::fs::read_to_string(&version_file) {
|
|
||||||
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
|
|
||||||
if let Some(version) = json.get("version").and_then(|v| v.as_str()) {
|
|
||||||
if version != current_app_version {
|
|
||||||
version_mismatch = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
version_mismatch = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
version_mismatch = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if version_mismatch {
|
|
||||||
debug_log(&format!("App version updated to {}. Cleaning old files.", current_app_version));
|
|
||||||
let dirs_to_remove = ["frontend", "player", "stream-api", "auth-proxy", "config"];
|
|
||||||
for d in dirs_to_remove {
|
|
||||||
let _ = std::fs::remove_dir_all(vyla_files.join(d));
|
|
||||||
}
|
|
||||||
let _ = std::fs::remove_file(&version_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
let window = WebviewWindowBuilder::new(app, "main", WebviewUrl::App("index.html".into()))
|
let window = WebviewWindowBuilder::new(app, "main", WebviewUrl::App("index.html".into()))
|
||||||
.title("Vyla Home")
|
.title("Vyla Home")
|
||||||
@@ -660,6 +760,7 @@ fn main() {
|
|||||||
|
|
||||||
let (main_js, root_dir) = resolve_script_and_root(app);
|
let (main_js, root_dir) = resolve_script_and_root(app);
|
||||||
debug_log("Searching for node binary...");
|
debug_log("Searching for node binary...");
|
||||||
|
|
||||||
let node_bin = match find_node_binary(app) {
|
let node_bin = match find_node_binary(app) {
|
||||||
Some(bin) => {
|
Some(bin) => {
|
||||||
debug_log(&format!("Found node binary: {}", bin));
|
debug_log(&format!("Found node binary: {}", bin));
|
||||||
@@ -675,7 +776,6 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let vyla_files_str = clean_path(&vyla_files);
|
let vyla_files_str = clean_path(&vyla_files);
|
||||||
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(400));
|
std::thread::sleep(std::time::Duration::from_millis(400));
|
||||||
|
|
||||||
let mut cmd = Command::new(&node_bin);
|
let mut cmd = Command::new(&node_bin);
|
||||||
@@ -700,6 +800,7 @@ fn main() {
|
|||||||
"Node child process spawned successfully, PID: {}",
|
"Node child process spawned successfully, PID: {}",
|
||||||
child.id()
|
child.id()
|
||||||
));
|
));
|
||||||
|
|
||||||
if let Some(stderr) = child.stderr.take() {
|
if let Some(stderr) = child.stderr.take() {
|
||||||
let w = window.clone();
|
let w = window.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
@@ -707,8 +808,14 @@ fn main() {
|
|||||||
let reader = BufReader::new(stderr);
|
let reader = BufReader::new(stderr);
|
||||||
for line in reader.lines().flatten() {
|
for line in reader.lines().flatten() {
|
||||||
debug_log(&format!("[NODE STDERR] {}", line));
|
debug_log(&format!("[NODE STDERR] {}", line));
|
||||||
if line.contains("Error") || line.contains("Exception") || line.contains("MODULE_NOT_FOUND") {
|
if line.contains("Error")
|
||||||
let _ = w.emit("error", serde_json::json!({ "message": format!("Backend failed: {}", line) }));
|
|| line.contains("Exception")
|
||||||
|
|| line.contains("MODULE_NOT_FOUND")
|
||||||
|
{
|
||||||
|
let _ = w.emit(
|
||||||
|
"error",
|
||||||
|
serde_json::json!({ "message": format!("Backend failed: {}", line) }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -721,144 +828,22 @@ fn main() {
|
|||||||
let reader = BufReader::new(stdout);
|
let reader = BufReader::new(stdout);
|
||||||
for line in reader.lines().flatten() {
|
for line in reader.lines().flatten() {
|
||||||
debug_log(&format!("[NODE STDOUT] {}", line));
|
debug_log(&format!("[NODE STDOUT] {}", line));
|
||||||
if let Ok(msg) = serde_json::from_str::<BackendMessage>(&line) {
|
|
||||||
debug_log(&format!("[MAIN-DEBUG] Received event: {}", msg.event));
|
|
||||||
debug_log(&format!(
|
|
||||||
"[MAIN-DEBUG] Event data: {}",
|
|
||||||
serde_json::to_string(&msg.data).unwrap_or_default()
|
|
||||||
));
|
|
||||||
if msg.event == "tauri-cmd" {
|
|
||||||
let window_label = msg
|
|
||||||
.data
|
|
||||||
.get("window")
|
|
||||||
.and_then(|val| val.as_str())
|
|
||||||
.unwrap_or("main");
|
|
||||||
debug_log(&format!(
|
|
||||||
"[MAIN-DEBUG] Finding window by label: {}",
|
|
||||||
window_label
|
|
||||||
));
|
|
||||||
|
|
||||||
if let Some(cmd_window) =
|
let msg = match serde_json::from_str::<BackendMessage>(&line) {
|
||||||
w.app_handle().get_webview_window(window_label)
|
Ok(m) => m,
|
||||||
{
|
Err(_) => continue,
|
||||||
if let Some(cmd) =
|
};
|
||||||
msg.data.get("cmd").and_then(|c| c.as_str())
|
|
||||||
{
|
debug_log(&format!("[MAIN-DEBUG] Received event: {}", msg.event));
|
||||||
debug_log(&format!(
|
debug_log(&format!(
|
||||||
"[TAURI-CMD] Executing action: {}",
|
"[MAIN-DEBUG] Event data: {}",
|
||||||
cmd
|
serde_json::to_string(&msg.data).unwrap_or_default()
|
||||||
));
|
));
|
||||||
match cmd {
|
|
||||||
"win_minimize" => {
|
match msg.event.as_str() {
|
||||||
let res = cmd_window.minimize();
|
"tauri-cmd" => handle_tauri_cmd(&w, &msg),
|
||||||
debug_log(&format!(
|
"ready" => handle_ready(&w, &msg),
|
||||||
"[TAURI-CMD] Minimize result: {:?}",
|
_ => {
|
||||||
res
|
|
||||||
));
|
|
||||||
}
|
|
||||||
"win_maximize" => {
|
|
||||||
let is_max = cmd_window
|
|
||||||
.is_maximized()
|
|
||||||
.unwrap_or(false);
|
|
||||||
debug_log(&format!(
|
|
||||||
"[TAURI-CMD] Currently maximized: {}",
|
|
||||||
is_max
|
|
||||||
));
|
|
||||||
let res = if is_max {
|
|
||||||
cmd_window.unmaximize()
|
|
||||||
} else {
|
|
||||||
cmd_window.maximize()
|
|
||||||
};
|
|
||||||
debug_log(&format!(
|
|
||||||
"[TAURI-CMD] Maximize/Unmaximize result: {:?}",
|
|
||||||
res
|
|
||||||
));
|
|
||||||
}
|
|
||||||
"win_close" => {
|
|
||||||
let res = cmd_window.close();
|
|
||||||
debug_log(&format!(
|
|
||||||
"[TAURI-CMD] Close result: {:?}",
|
|
||||||
res
|
|
||||||
));
|
|
||||||
}
|
|
||||||
"win_drag" => {
|
|
||||||
let res = cmd_window.start_dragging();
|
|
||||||
debug_log(&format!(
|
|
||||||
"[TAURI-CMD] Drag result: {:?}",
|
|
||||||
res
|
|
||||||
));
|
|
||||||
}
|
|
||||||
"open_new_window" => {
|
|
||||||
debug_log("[TAURI-CMD-DEBUG] open_new_window command received");
|
|
||||||
debug_log(&format!(
|
|
||||||
"[TAURI-CMD-DEBUG] Full message data: {}",
|
|
||||||
serde_json::to_string(&msg.data)
|
|
||||||
.unwrap_or_default()
|
|
||||||
));
|
|
||||||
if let Some(url) = msg
|
|
||||||
.data
|
|
||||||
.get("url")
|
|
||||||
.and_then(|u| u.as_str())
|
|
||||||
{
|
|
||||||
debug_log(&format!(
|
|
||||||
"[TAURI-CMD-DEBUG] URL extracted: {}",
|
|
||||||
url
|
|
||||||
));
|
|
||||||
debug_log(&format!(
|
|
||||||
"[TAURI-CMD-DEBUG] URL length: {}",
|
|
||||||
url.len()
|
|
||||||
));
|
|
||||||
debug_log("[TAURI-CMD-DEBUG] Attempting to dispatch to main thread");
|
|
||||||
let app_handle = w.app_handle().clone();
|
|
||||||
let closure_handle = app_handle.clone();
|
|
||||||
let url_owned = url.to_string();
|
|
||||||
let dispatch_result = app_handle
|
|
||||||
.run_on_main_thread(move || {
|
|
||||||
debug_log("[TAURI-CMD-DEBUG] Now on main thread, calling open_new_window");
|
|
||||||
match open_new_window(
|
|
||||||
closure_handle,
|
|
||||||
url_owned,
|
|
||||||
) {
|
|
||||||
Ok(_) => {
|
|
||||||
debug_log("[TAURI-CMD-DEBUG] open_new_window succeeded");
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
debug_log(&format!(
|
|
||||||
"[TAURI-CMD-DEBUG] open_new_window error: {}",
|
|
||||||
e
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
match dispatch_result {
|
|
||||||
Ok(_) => debug_log(
|
|
||||||
"[TAURI-CMD-DEBUG] Main thread dispatch succeeded",
|
|
||||||
),
|
|
||||||
Err(e) => debug_log(&format!(
|
|
||||||
"[TAURI-CMD-DEBUG] Main thread dispatch failed: {}",
|
|
||||||
e
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debug_log("[TAURI-CMD-DEBUG] ERROR: No URL found in message data");
|
|
||||||
debug_log(&format!(
|
|
||||||
"[TAURI-CMD-DEBUG] Available keys: {:?}",
|
|
||||||
msg.data
|
|
||||||
.as_object()
|
|
||||||
.map(|o| o.keys().collect::<Vec<_>>())
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debug_log(&format!(
|
|
||||||
"[TAURI-CMD] Window '{}' NOT FOUND!",
|
|
||||||
window_label
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let _ = w.emit(&msg.event, msg.data.clone());
|
let _ = w.emit(&msg.event, msg.data.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -884,7 +869,7 @@ fn main() {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.on_window_event(|window, event| {
|
.on_window_event(|window, event| {
|
||||||
if let tauri::WindowEvent::Destroyed = event {
|
if let tauri::WindowEvent::Destroyed = event {
|
||||||
if window.label() == "main" {
|
if window.label() == "main" {
|
||||||
let state: State<NodeServices> = window.state();
|
let state: State<NodeServices> = window.state();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "Vyla Home",
|
"productName": "Vyla Home",
|
||||||
"version": "1.1.25",
|
"version": "1.1.33",
|
||||||
"identifier": "com.vyla.home",
|
"identifier": "com.vyla.home",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../ui"
|
"frontendDist": "../ui"
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
],
|
],
|
||||||
"macOS": {
|
"macOS": {
|
||||||
"exceptionDomain": "localhost",
|
"exceptionDomain": "localhost",
|
||||||
"infoPlist": "../Info.plist"
|
"infoPlist": "Info.plist"
|
||||||
},
|
},
|
||||||
"windows": {
|
"windows": {
|
||||||
"webviewInstallMode": {
|
"webviewInstallMode": {
|
||||||
|
|||||||
@@ -569,15 +569,14 @@ void main() {
|
|||||||
if (progressTrack) progressTrack.style.display = "block";
|
if (progressTrack) progressTrack.style.display = "block";
|
||||||
const percent = data.percent || 0;
|
const percent = data.percent || 0;
|
||||||
if (progressFill) progressFill.style.width = percent + "%";
|
if (progressFill) progressFill.style.width = percent + "%";
|
||||||
if (!currentStatusText.startsWith("Downloading update...")) {
|
setStatus(`Downloading update (${percent}%)...`);
|
||||||
setStatus("Downloading update...");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
eventApi.listen("update-available", (e) => {
|
eventApi.listen("update-available", (e) => {
|
||||||
const data = e.payload || e;
|
const data = e.payload || e;
|
||||||
if (data) {
|
if (data) {
|
||||||
|
if (progressTrack) progressTrack.style.display = "none";
|
||||||
setStatus(`Update Available: ${data.latest} (Current: ${data.current})`);
|
setStatus(`Update Available: ${data.latest} (Current: ${data.current})`);
|
||||||
if (actionsEl) actionsEl.style.display = "flex";
|
if (actionsEl) actionsEl.style.display = "flex";
|
||||||
}
|
}
|
||||||
@@ -586,8 +585,9 @@ void main() {
|
|||||||
eventApi.listen("ready", (e) => {
|
eventApi.listen("ready", (e) => {
|
||||||
const data = e.payload || e;
|
const data = e.payload || e;
|
||||||
if (data && data.url) {
|
if (data && data.url) {
|
||||||
|
if (progressTrack) progressTrack.style.display = "none";
|
||||||
|
if (actionsEl) actionsEl.style.display = "none";
|
||||||
setStatus("Launching...");
|
setStatus("Launching...");
|
||||||
window.location.replace(data.url);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user