u2a 2.1.1 → 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/commands/create.js +271 -13
package/README.md
CHANGED
|
@@ -130,4 +130,4 @@ Created by [Douxx](https://douxx.tech)
|
|
|
130
130
|
|
|
131
131
|
## Disclaimer
|
|
132
132
|
|
|
133
|
-
This tool is for personal use only. Always respect the terms of service of websites you convert to desktop apps.
|
|
133
|
+
This tool is for personal use only. Always respect the terms of service of websites you convert to desktop apps.
|
package/package.json
CHANGED
package/src/commands/create.js
CHANGED
|
@@ -51,7 +51,6 @@ function createWindowsShortcut(appInfo) {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
54
|
function createLinuxDesktopEntry(appInfo) {
|
|
56
55
|
try {
|
|
57
56
|
const { domain, url, appDir, iconPath } = appInfo;
|
|
@@ -179,9 +178,7 @@ function removeAppFromOS(domain) {
|
|
|
179
178
|
const desktopFilePath = path.join(os.homedir(), '.local', 'share', 'applications', `u2a-${domain}.desktop`);
|
|
180
179
|
if (fs.existsSync(desktopFilePath)) {
|
|
181
180
|
fs.unlinkSync(desktopFilePath);
|
|
182
|
-
logger.success(`Linux desktop entry removed: ${desktopFilePath}
|
|
183
|
-
|
|
184
|
-
`);
|
|
181
|
+
logger.success(`Linux desktop entry removed: ${desktopFilePath}`);
|
|
185
182
|
}
|
|
186
183
|
}
|
|
187
184
|
} catch (error) {
|
|
@@ -200,11 +197,13 @@ const APP_URL = "${url}";
|
|
|
200
197
|
const APP_ICON_PATH = "${iconPath.replace(/\\/g, '\\\\')}";
|
|
201
198
|
|
|
202
199
|
let mainWindow;
|
|
200
|
+
let splashWindow;
|
|
201
|
+
let loadErrors = [];
|
|
203
202
|
|
|
204
203
|
function logAppInfo() {
|
|
205
204
|
const packageJsonPath = path.join(__dirname, 'package.json');
|
|
206
205
|
let packageInfo = {};
|
|
207
|
-
|
|
206
|
+
|
|
208
207
|
try {
|
|
209
208
|
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
210
209
|
packageInfo = JSON.parse(packageJsonContent);
|
|
@@ -220,25 +219,210 @@ function logAppInfo() {
|
|
|
220
219
|
console.log(\`Started at: \${new Date().toLocaleString()}\`);
|
|
221
220
|
console.log(\`App directory: \${__dirname}\`);
|
|
222
221
|
console.log(\`Icon path: \${APP_ICON_PATH}\`);
|
|
223
|
-
|
|
222
|
+
|
|
224
223
|
console.log('\\n PACKAGE INFO:');
|
|
225
224
|
console.log(\` - Name: \${packageInfo.name || 'N/A'}\`);
|
|
226
225
|
console.log(\` - Version: \${packageInfo.version || 'N/A'}\`);
|
|
227
226
|
console.log(\` - Description: \${packageInfo.description || 'N/A'}\`);
|
|
228
227
|
console.log(\` - Electron version: \${packageInfo.dependencies?.electron || 'N/A'}\`);
|
|
229
|
-
|
|
228
|
+
|
|
230
229
|
if (packageInfo.build) {
|
|
231
230
|
console.log('\\n BUILD CONFIG:');
|
|
232
231
|
console.log(\` - App ID: \${packageInfo.build.appId || 'N/A'}\`);
|
|
233
232
|
console.log(\` - Product Name: \${packageInfo.build.productName || 'N/A'}\`);
|
|
234
233
|
}
|
|
235
|
-
|
|
234
|
+
|
|
236
235
|
console.log('--------------------------------\\n');
|
|
237
236
|
}
|
|
238
237
|
|
|
238
|
+
function updateSplashScreen(message, isError = false) {
|
|
239
|
+
if (splashWindow && !splashWindow.isDestroyed()) {
|
|
240
|
+
splashWindow.webContents.executeJavaScript(\`
|
|
241
|
+
try {
|
|
242
|
+
document.getElementById('loading-text').innerText = "\${message.replace(/"/g, '\\"')}";
|
|
243
|
+
} catch (e) {
|
|
244
|
+
console.error('Failed to update splash screen:', e);
|
|
245
|
+
}
|
|
246
|
+
\`).catch(err => console.error('Failed to update splash screen:', err));
|
|
247
|
+
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function createSplashScreen() {
|
|
252
|
+
splashWindow = new BrowserWindow({
|
|
253
|
+
width: 550,
|
|
254
|
+
height: 400,
|
|
255
|
+
transparent: true,
|
|
256
|
+
frame: false,
|
|
257
|
+
alwaysOnTop: true,
|
|
258
|
+
icon: APP_ICON_PATH,
|
|
259
|
+
webPreferences: {
|
|
260
|
+
nodeIntegration: false,
|
|
261
|
+
contextIsolation: true
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const splashHtml = \`
|
|
266
|
+
<!DOCTYPE html>
|
|
267
|
+
<html>
|
|
268
|
+
<head>
|
|
269
|
+
<meta charset="UTF-8">
|
|
270
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'; object-src 'none';">
|
|
271
|
+
<title>Loading...</title>
|
|
272
|
+
<style>
|
|
273
|
+
body {
|
|
274
|
+
margin: 0;
|
|
275
|
+
padding: 0;
|
|
276
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
277
|
+
background-color: var(--bg-primary, #0f172a);
|
|
278
|
+
color: var(--text-primary, #f8fafc);
|
|
279
|
+
height: 100vh;
|
|
280
|
+
display: flex;
|
|
281
|
+
flex-direction: column;
|
|
282
|
+
justify-content: center;
|
|
283
|
+
align-items: center;
|
|
284
|
+
overflow: hidden;
|
|
285
|
+
border-radius: 20px;
|
|
286
|
+
overflow: hidden;
|
|
287
|
+
box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.2);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.container {
|
|
291
|
+
text-align: center;
|
|
292
|
+
width: 90%;
|
|
293
|
+
max-width: 500px;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.domain {
|
|
297
|
+
font-size: 24px;
|
|
298
|
+
margin-bottom: 20px;
|
|
299
|
+
color: var(--primary, #2563eb);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.spinner {
|
|
303
|
+
width: 50px;
|
|
304
|
+
height: 50px;
|
|
305
|
+
border: 5px solid rgba(37, 99, 235, 0.2);
|
|
306
|
+
border-radius: 50%;
|
|
307
|
+
border-top-color: var(--primary, #2563eb);
|
|
308
|
+
animation: spin 1s ease-in-out infinite;
|
|
309
|
+
margin: 0 auto 20px;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
@keyframes spin {
|
|
313
|
+
to { transform: rotate(360deg); }
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.loading-text {
|
|
317
|
+
font-size: 16px;
|
|
318
|
+
color: var(--text-secondary, #cbd5e1);
|
|
319
|
+
margin-top: 15px;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.loading-text.error {
|
|
323
|
+
color: var(--danger, #ef4444);
|
|
324
|
+
font-weight: bold;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.progress-bar {
|
|
328
|
+
width: 100%;
|
|
329
|
+
height: 4px;
|
|
330
|
+
background-color: var(--bg-secondary, #1e293b);
|
|
331
|
+
border-radius: 2px;
|
|
332
|
+
overflow: hidden;
|
|
333
|
+
margin-top: 15px;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.progress {
|
|
337
|
+
height: 100%;
|
|
338
|
+
width: 0%;
|
|
339
|
+
background-color: var(--primary, #2563eb);
|
|
340
|
+
animation: progress 3s ease-in-out infinite;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
@keyframes progress {
|
|
344
|
+
0% { width: 0%; }
|
|
345
|
+
50% { width: 70%; }
|
|
346
|
+
100% { width: 100%; }
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
#errors-container {
|
|
350
|
+
display: none;
|
|
351
|
+
margin-top: 20px;
|
|
352
|
+
background-color: rgba(239, 68, 68, 0.1);
|
|
353
|
+
border-left: 3px solid var(--danger, #ef4444);
|
|
354
|
+
padding: 10px;
|
|
355
|
+
border-radius: 4px;
|
|
356
|
+
text-align: left;
|
|
357
|
+
max-height: 150px;
|
|
358
|
+
overflow-y: auto;
|
|
359
|
+
width: 100%;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
#errors-list {
|
|
363
|
+
margin: 0;
|
|
364
|
+
padding-left: 20px;
|
|
365
|
+
color: var(--danger, #ef4444);
|
|
366
|
+
font-size: 14px;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
#errors-list li {
|
|
370
|
+
margin-bottom: 5px;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.retry-button {
|
|
374
|
+
background-color: var(--primary, #2563eb);
|
|
375
|
+
color: white;
|
|
376
|
+
border: none;
|
|
377
|
+
padding: 8px 16px;
|
|
378
|
+
border-radius: 4px;
|
|
379
|
+
margin-top: 15px;
|
|
380
|
+
cursor: pointer;
|
|
381
|
+
font-weight: bold;
|
|
382
|
+
transition: background-color 0.2s;
|
|
383
|
+
display: none;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.retry-button:hover {
|
|
387
|
+
background-color: var(--primary-dark, #1d4ed8);
|
|
388
|
+
}
|
|
389
|
+
</style>
|
|
390
|
+
</head>
|
|
391
|
+
<body>
|
|
392
|
+
<div class="container">
|
|
393
|
+
<div class="domain">\${APP_DOMAIN}</div>
|
|
394
|
+
<div class="spinner"></div>
|
|
395
|
+
<div id="loading-text" class="loading-text">Loading...</div>
|
|
396
|
+
<div class="progress-bar">
|
|
397
|
+
<div class="progress"></div>
|
|
398
|
+
</div>
|
|
399
|
+
<div id="errors-container">
|
|
400
|
+
<h3 style="margin-top: 0; color: var(--danger, #ef4444);">Errors detected:</h3>
|
|
401
|
+
<ul id="errors-list"></ul>
|
|
402
|
+
</div>
|
|
403
|
+
<button id="retry-button" class="retry-button" onclick="window.location.reload()">Retry</button>
|
|
404
|
+
</div>
|
|
405
|
+
<script>
|
|
406
|
+
window.showRetryButton = function() {
|
|
407
|
+
document.getElementById('retry-button').style.display = 'inline-block';
|
|
408
|
+
document.querySelector('.spinner').style.animationPlayState = 'paused';
|
|
409
|
+
document.querySelector('.progress').style.animationPlayState = 'paused';
|
|
410
|
+
}
|
|
411
|
+
</script>
|
|
412
|
+
</body>
|
|
413
|
+
</html>
|
|
414
|
+
\`;
|
|
415
|
+
|
|
416
|
+
const splashPath = path.join(app.getPath('temp'), \`\${APP_DOMAIN}-splash.html\`);
|
|
417
|
+
fs.writeFileSync(splashPath, splashHtml);
|
|
418
|
+
|
|
419
|
+
splashWindow.loadFile(splashPath);
|
|
420
|
+
splashWindow.center();
|
|
421
|
+
}
|
|
422
|
+
|
|
239
423
|
function createWindow() {
|
|
240
424
|
logAppInfo();
|
|
241
|
-
|
|
425
|
+
|
|
242
426
|
app.setAppUserModelId(APP_DOMAIN);
|
|
243
427
|
|
|
244
428
|
mainWindow = new BrowserWindow({
|
|
@@ -246,12 +430,72 @@ function createWindow() {
|
|
|
246
430
|
height: 800,
|
|
247
431
|
title: APP_DOMAIN,
|
|
248
432
|
icon: APP_ICON_PATH,
|
|
433
|
+
show: false,
|
|
249
434
|
webPreferences: {
|
|
250
435
|
nodeIntegration: false,
|
|
251
436
|
contextIsolation: true
|
|
252
437
|
}
|
|
253
438
|
});
|
|
254
439
|
|
|
440
|
+
mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL, isMainFrame) => {
|
|
441
|
+
const errorMessage = \`Load error (\${errorCode}): \${errorDescription}\`;
|
|
442
|
+
loadErrors.push(errorMessage);
|
|
443
|
+
|
|
444
|
+
updateSplashScreen(errorMessage, true);
|
|
445
|
+
|
|
446
|
+
if (isMainFrame) {
|
|
447
|
+
splashWindow.webContents.executeJavaScript('window.showRetryButton()').catch(err => {
|
|
448
|
+
console.error('Failed to show retry button:', err);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
mainWindow.webContents.on('certificate-error', (event, url, error, certificate, callback) => {
|
|
454
|
+
event.preventDefault();
|
|
455
|
+
const errorMessage = \`Certificate error: \${error}\`;
|
|
456
|
+
console.error(errorMessage);
|
|
457
|
+
loadErrors.push(errorMessage);
|
|
458
|
+
|
|
459
|
+
updateSplashScreen(errorMessage, true);
|
|
460
|
+
callback(false);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
mainWindow.webContents.on('console-message', (event, level, message, line, sourceId) => {
|
|
464
|
+
if (level === 2) {
|
|
465
|
+
const errorMessage = \`Console: \${message} (line \${line})\`;
|
|
466
|
+
loadErrors.push(errorMessage);
|
|
467
|
+
|
|
468
|
+
updateSplashScreen('JavaScript error detected', true);
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
mainWindow.webContents.on('did-start-loading', () => {
|
|
473
|
+
updateSplashScreen('Connecting to ' + APP_DOMAIN + '...');
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
mainWindow.webContents.on('did-start-navigation', (event, url) => {
|
|
477
|
+
updateSplashScreen('Navigating to ' + new URL(url).host + '...');
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
mainWindow.webContents.on('dom-ready', () => {
|
|
481
|
+
updateSplashScreen('DOM ready, loading resources...');
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
mainWindow.webContents.on('did-finish-load', () => {
|
|
485
|
+
updateSplashScreen('Loading complete!');
|
|
486
|
+
|
|
487
|
+
setTimeout(() => {
|
|
488
|
+
if (splashWindow && !splashWindow.isDestroyed()) {
|
|
489
|
+
splashWindow.close();
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (!mainWindow.isVisible()) {
|
|
493
|
+
mainWindow.show();
|
|
494
|
+
mainWindow.focus();
|
|
495
|
+
}
|
|
496
|
+
}, 500);
|
|
497
|
+
});
|
|
498
|
+
|
|
255
499
|
mainWindow.loadURL(APP_URL);
|
|
256
500
|
|
|
257
501
|
mainWindow.webContents.on('context-menu', (e, params) => {
|
|
@@ -272,13 +516,28 @@ function createWindow() {
|
|
|
272
516
|
|
|
273
517
|
const menu = Menu.buildFromTemplate(template);
|
|
274
518
|
Menu.setApplicationMenu(menu);
|
|
519
|
+
|
|
520
|
+
setTimeout(() => {
|
|
521
|
+
if (splashWindow && !splashWindow.isDestroyed()) {
|
|
522
|
+
if (loadErrors.length === 0) {
|
|
523
|
+
splashWindow.close();
|
|
524
|
+
if (!mainWindow.isVisible()) {
|
|
525
|
+
mainWindow.show();
|
|
526
|
+
mainWindow.focus();
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}, 15000);
|
|
275
531
|
}
|
|
276
532
|
|
|
277
533
|
if (process.platform === 'win32') {
|
|
278
534
|
app.setAppUserModelId(app.name);
|
|
279
535
|
}
|
|
280
536
|
|
|
281
|
-
app.whenReady().then(
|
|
537
|
+
app.whenReady().then(() => {
|
|
538
|
+
createSplashScreen();
|
|
539
|
+
createWindow();
|
|
540
|
+
});
|
|
282
541
|
|
|
283
542
|
app.on('window-all-closed', () => {
|
|
284
543
|
if (process.platform !== 'darwin') {
|
|
@@ -294,10 +553,9 @@ app.on('activate', () => {
|
|
|
294
553
|
`;
|
|
295
554
|
}
|
|
296
555
|
|
|
297
|
-
|
|
298
556
|
function generatePackageJson(domain, iconPath) {
|
|
299
557
|
const u2aPackagePath = path.resolve(__dirname, '../../package.json');
|
|
300
|
-
|
|
558
|
+
|
|
301
559
|
let u2aVersion = '1.0.0';
|
|
302
560
|
try {
|
|
303
561
|
const u2aPackageContent = fs.readFileSync(u2aPackagePath, 'utf8');
|
|
@@ -306,7 +564,7 @@ function generatePackageJson(domain, iconPath) {
|
|
|
306
564
|
} catch (error) {
|
|
307
565
|
logger.error('Error while fetching u2a package.json', error)
|
|
308
566
|
}
|
|
309
|
-
|
|
567
|
+
|
|
310
568
|
return {
|
|
311
569
|
name: `u2a-${domain}`,
|
|
312
570
|
version: u2aVersion,
|