u2a 2.1.1 → 2.1.5

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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u2a",
3
- "version": "2.1.1",
3
+ "version": "2.1.5",
4
4
  "description": "URL to App - Turn any URL into a desktop application",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -200,11 +200,13 @@ const APP_URL = "${url}";
200
200
  const APP_ICON_PATH = "${iconPath.replace(/\\/g, '\\\\')}";
201
201
 
202
202
  let mainWindow;
203
+ let splashWindow;
204
+ let loadErrors = [];
203
205
 
204
206
  function logAppInfo() {
205
207
  const packageJsonPath = path.join(__dirname, 'package.json');
206
208
  let packageInfo = {};
207
-
209
+
208
210
  try {
209
211
  const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');
210
212
  packageInfo = JSON.parse(packageJsonContent);
@@ -220,25 +222,212 @@ function logAppInfo() {
220
222
  console.log(\`Started at: \${new Date().toLocaleString()}\`);
221
223
  console.log(\`App directory: \${__dirname}\`);
222
224
  console.log(\`Icon path: \${APP_ICON_PATH}\`);
223
-
225
+
224
226
  console.log('\\n PACKAGE INFO:');
225
227
  console.log(\` - Name: \${packageInfo.name || 'N/A'}\`);
226
228
  console.log(\` - Version: \${packageInfo.version || 'N/A'}\`);
227
229
  console.log(\` - Description: \${packageInfo.description || 'N/A'}\`);
228
230
  console.log(\` - Electron version: \${packageInfo.dependencies?.electron || 'N/A'}\`);
229
-
231
+
230
232
  if (packageInfo.build) {
231
233
  console.log('\\n BUILD CONFIG:');
232
234
  console.log(\` - App ID: \${packageInfo.build.appId || 'N/A'}\`);
233
235
  console.log(\` - Product Name: \${packageInfo.build.productName || 'N/A'}\`);
234
236
  }
235
-
237
+
236
238
  console.log('--------------------------------\\n');
237
239
  }
238
240
 
241
+ function updateSplashScreen(message, isError = false) {
242
+ if (splashWindow && !splashWindow.isDestroyed()) {
243
+ const script = \`
244
+ document.getElementById('loading-text').innerText = "\${message.replace(/"/g, '\\"')}";
245
+ \${isError ?
246
+ \`document.getElementById('loading-text').classList.add('error');
247
+ document.getElementById('errors-container').style.display = 'block';
248
+ const errorItem = document.createElement('li');
249
+ errorItem.textContent = "\${message.replace(/"/g, '\\"')}";
250
+ document.getElementById('errors-list').appendChild(errorItem);\`
251
+ : ''}
252
+ \`;
253
+ splashWindow.webContents.executeJavaScript(script).catch(err => console.error('Failed to update splash screen:', err));
254
+ }
255
+ }
256
+
257
+ function createSplashScreen() {
258
+ splashWindow = new BrowserWindow({
259
+ width: 550,
260
+ height: 400,
261
+ transparent: true,
262
+ frame: false,
263
+ alwaysOnTop: true,
264
+ icon: APP_ICON_PATH,
265
+ webPreferences: {
266
+ nodeIntegration: false,
267
+ contextIsolation: true
268
+ }
269
+ });
270
+
271
+ const splashHtml = \`
272
+ <!DOCTYPE html>
273
+ <html>
274
+ <head>
275
+ <meta charset="UTF-8">
276
+ <title>Loading...</title>
277
+ <style>
278
+ body {
279
+ margin: 0;
280
+ padding: 0;
281
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
282
+ background-color: var(--bg-primary, #0f172a);
283
+ color: var(--text-primary, #f8fafc);
284
+ height: 100vh;
285
+ display: flex;
286
+ flex-direction: column;
287
+ justify-content: center;
288
+ align-items: center;
289
+ overflow: hidden;
290
+ border-radius: 20px;
291
+ overflow: hidden;
292
+ box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.2);
293
+ }
294
+
295
+ .container {
296
+ text-align: center;
297
+ width: 90%;
298
+ max-width: 500px;
299
+ }
300
+
301
+ .domain {
302
+ font-size: 24px;
303
+ margin-bottom: 20px;
304
+ color: var(--primary, #2563eb);
305
+ }
306
+
307
+ .spinner {
308
+ width: 50px;
309
+ height: 50px;
310
+ border: 5px solid rgba(37, 99, 235, 0.2);
311
+ border-radius: 50%;
312
+ border-top-color: var(--primary, #2563eb);
313
+ animation: spin 1s ease-in-out infinite;
314
+ margin: 0 auto 20px;
315
+ }
316
+
317
+ @keyframes spin {
318
+ to { transform: rotate(360deg); }
319
+ }
320
+
321
+ .loading-text {
322
+ font-size: 16px;
323
+ color: var(--text-secondary, #cbd5e1);
324
+ margin-top: 15px;
325
+ }
326
+
327
+ .loading-text.error {
328
+ color: var(--danger, #ef4444);
329
+ font-weight: bold;
330
+ }
331
+
332
+ .progress-bar {
333
+ width: 100%;
334
+ height: 4px;
335
+ background-color: var(--bg-secondary, #1e293b);
336
+ border-radius: 2px;
337
+ overflow: hidden;
338
+ margin-top: 15px;
339
+ }
340
+
341
+ .progress {
342
+ height: 100%;
343
+ width: 0%;
344
+ background-color: var(--primary, #2563eb);
345
+ animation: progress 3s ease-in-out infinite;
346
+ }
347
+
348
+ @keyframes progress {
349
+ 0% { width: 0%; }
350
+ 50% { width: 70%; }
351
+ 100% { width: 100%; }
352
+ }
353
+
354
+ #errors-container {
355
+ display: none;
356
+ margin-top: 20px;
357
+ background-color: rgba(239, 68, 68, 0.1);
358
+ border-left: 3px solid var(--danger, #ef4444);
359
+ padding: 10px;
360
+ border-radius: 4px;
361
+ text-align: left;
362
+ max-height: 150px;
363
+ overflow-y: auto;
364
+ width: 100%;
365
+ }
366
+
367
+ #errors-list {
368
+ margin: 0;
369
+ padding-left: 20px;
370
+ color: var(--danger, #ef4444);
371
+ font-size: 14px;
372
+ }
373
+
374
+ #errors-list li {
375
+ margin-bottom: 5px;
376
+ }
377
+
378
+ .retry-button {
379
+ background-color: var(--primary, #2563eb);
380
+ color: white;
381
+ border: none;
382
+ padding: 8px 16px;
383
+ border-radius: 4px;
384
+ margin-top: 15px;
385
+ cursor: pointer;
386
+ font-weight: bold;
387
+ transition: background-color 0.2s;
388
+ display: none;
389
+ }
390
+
391
+ .retry-button:hover {
392
+ background-color: var(--primary-dark, #1d4ed8);
393
+ }
394
+ </style>
395
+ </head>
396
+ <body>
397
+ <div class="container">
398
+ <div class="domain">\${APP_DOMAIN}</div>
399
+ <div class="spinner"></div>
400
+ <div id="loading-text" class="loading-text">Loading...</div>
401
+ <div class="progress-bar">
402
+ <div class="progress"></div>
403
+ </div>
404
+ <div id="errors-container">
405
+ <h3 style="margin-top: 0; color: var(--danger, #ef4444);">Errors detected:</h3>
406
+ <ul id="errors-list"></ul>
407
+ </div>
408
+ <button id="retry-button" class="retry-button" onclick="window.location.reload()">Retry</button>
409
+ </div>
410
+ <script>
411
+ window.showRetryButton = function() {
412
+ document.getElementById('retry-button').style.display = 'inline-block';
413
+ document.querySelector('.spinner').style.animationPlayState = 'paused';
414
+ document.querySelector('.progress').style.animationPlayState = 'paused';
415
+ }
416
+ </script>
417
+ </body>
418
+ </html>
419
+ \`;
420
+
421
+ const splashPath = path.join(app.getPath('temp'), \`\${APP_DOMAIN}-splash.html\`);
422
+ fs.writeFileSync(splashPath, splashHtml);
423
+
424
+ splashWindow.loadFile(splashPath);
425
+ splashWindow.center();
426
+ }
427
+
239
428
  function createWindow() {
240
429
  logAppInfo();
241
-
430
+
242
431
  app.setAppUserModelId(APP_DOMAIN);
243
432
 
244
433
  mainWindow = new BrowserWindow({
@@ -246,12 +435,74 @@ function createWindow() {
246
435
  height: 800,
247
436
  title: APP_DOMAIN,
248
437
  icon: APP_ICON_PATH,
438
+ show: false,
249
439
  webPreferences: {
250
440
  nodeIntegration: false,
251
441
  contextIsolation: true
252
442
  }
253
443
  });
254
444
 
445
+ mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL, isMainFrame) => {
446
+ const errorMessage = \`Load error (\${errorCode}): \${errorDescription}\`;
447
+ console.error(errorMessage);
448
+ loadErrors.push(errorMessage);
449
+
450
+ updateSplashScreen(errorMessage, true);
451
+
452
+ if (isMainFrame) {
453
+ splashWindow.webContents.executeJavaScript('window.showRetryButton()').catch(err => {
454
+ console.error('Failed to show retry button:', err);
455
+ });
456
+ }
457
+ });
458
+
459
+ mainWindow.webContents.on('certificate-error', (event, url, error, certificate, callback) => {
460
+ event.preventDefault();
461
+ const errorMessage = \`Certificate error: \${error}\`;
462
+ console.error(errorMessage);
463
+ loadErrors.push(errorMessage);
464
+
465
+ updateSplashScreen(errorMessage, true);
466
+ callback(false);
467
+ });
468
+
469
+ mainWindow.webContents.on('console-message', (event, level, message, line, sourceId) => {
470
+ if (level === 2) {
471
+ const errorMessage = \`Console: \${message} (line \${line})\`;
472
+ console.error(errorMessage);
473
+ loadErrors.push(errorMessage);
474
+
475
+ updateSplashScreen('JavaScript error detected', true);
476
+ }
477
+ });
478
+
479
+ mainWindow.webContents.on('did-start-loading', () => {
480
+ updateSplashScreen('Connecting to ' + APP_DOMAIN + '...');
481
+ });
482
+
483
+ mainWindow.webContents.on('did-start-navigation', (event, url) => {
484
+ updateSplashScreen('Navigating to ' + new URL(url).host + '...');
485
+ });
486
+
487
+ mainWindow.webContents.on('dom-ready', () => {
488
+ updateSplashScreen('DOM ready, loading resources...');
489
+ });
490
+
491
+ mainWindow.webContents.on('did-finish-load', () => {
492
+ updateSplashScreen('Loading complete!');
493
+
494
+ setTimeout(() => {
495
+ if (splashWindow && !splashWindow.isDestroyed()) {
496
+ splashWindow.close();
497
+ }
498
+
499
+ if (!mainWindow.isVisible()) {
500
+ mainWindow.show();
501
+ mainWindow.focus();
502
+ }
503
+ }, 500);
504
+ });
505
+
255
506
  mainWindow.loadURL(APP_URL);
256
507
 
257
508
  mainWindow.webContents.on('context-menu', (e, params) => {
@@ -272,13 +523,28 @@ function createWindow() {
272
523
 
273
524
  const menu = Menu.buildFromTemplate(template);
274
525
  Menu.setApplicationMenu(menu);
526
+
527
+ setTimeout(() => {
528
+ if (splashWindow && !splashWindow.isDestroyed()) {
529
+ if (loadErrors.length === 0) {
530
+ splashWindow.close();
531
+ if (!mainWindow.isVisible()) {
532
+ mainWindow.show();
533
+ mainWindow.focus();
534
+ }
535
+ }
536
+ }
537
+ }, 15000);
275
538
  }
276
539
 
277
540
  if (process.platform === 'win32') {
278
541
  app.setAppUserModelId(app.name);
279
542
  }
280
543
 
281
- app.whenReady().then(createWindow);
544
+ app.whenReady().then(() => {
545
+ createSplashScreen();
546
+ createWindow();
547
+ });
282
548
 
283
549
  app.on('window-all-closed', () => {
284
550
  if (process.platform !== 'darwin') {
@@ -295,6 +561,7 @@ app.on('activate', () => {
295
561
  }
296
562
 
297
563
 
564
+
298
565
  function generatePackageJson(domain, iconPath) {
299
566
  const u2aPackagePath = path.resolve(__dirname, '../../package.json');
300
567