pake-cli 3.3.1 → 3.3.2

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
@@ -3,7 +3,7 @@
3
3
  <img src=https://gw.alipayobjects.com/zos/k/fa/logo-modified.png width=138/>
4
4
  </p>
5
5
  <h1 align="center">Pake</h1>
6
- <p align="center"><strong>Turn any webpage into a desktop app with Rust <em>with ease</em>.</strong></p>
6
+ <p align="center"><strong>Turn any webpage into a desktop app with one command, supports macOS, Windows, and Linux</strong></p>
7
7
  <div align="center">
8
8
  <a href="https://twitter.com/HiTw93" target="_blank">
9
9
  <img alt="twitter" src="https://img.shields.io/badge/follow-Tw93-red?style=flat-square&logo=Twitter"></a>
@@ -15,19 +15,20 @@
15
15
  <img alt="GitHub commit" src="https://img.shields.io/github/commit-activity/m/tw93/Pake?style=flat-square"></a>
16
16
  <a href="https://github.com/tw93/Pake/issues?q=is%3Aissue+is%3Aclosed" target="_blank">
17
17
  <img alt="GitHub closed issues" src="https://img.shields.io/github/issues-closed/tw93/Pake.svg?style=flat-square"></a>
18
- <a href="https://colab.research.google.com/drive/1bX345znvDZ30848xjRtpgtU8eypWwXrp?usp=sharing" target="_blank">
19
- <img alt="Open in Colab" src="https://colab.research.google.com/assets/colab-badge.svg"></a>
20
18
  </div>
21
19
 
22
- <div align="left">Pake supports Mac, Windows, and Linux. Check out README for <a href="#popular-packages">Popular Packages</a>, <a href="#command-line-packaging">Command-Line Packaging</a>, and <a href="#development">Customized Development</a> information. Feel free to share your suggestions in <a href=https://github.com/tw93/Pake/discussions>Discussions</a>.</div>
23
-
24
20
  ## Features
25
21
 
26
- - 🎐 Nearly 20 times smaller than an Electron package (around 5M!)
27
- - 🚀 With Rust Tauri, Pake is much more lightweight and faster than JS-based frameworks.
28
- - 📦 Battery-included package shortcut pass-through, immersive windows, and minimalist customization.
29
- - 🖱️ Smart right-click context menus with download support for images, videos, and files.
30
- - 👻 Pake is just a simple tool — replaces the old bundle approach with Tauri (though PWA is also a good alternative).
22
+ - 🎐 **Lightweight**: Nearly 20 times smaller than Electron packages, typically around 5M
23
+ - 🚀 **Fast**: Built with Rust Tauri, much faster than traditional JS frameworks with lower memory usage
24
+ - **Easy to use**: One-command packaging via CLI or online building, no complex configuration needed
25
+ - 📦 **Feature-rich**: Supports shortcut pass-through, immersive windows, drag & drop, style customization, ad removal
26
+
27
+ ## Getting Started
28
+
29
+ - **Beginners**: Download ready-made [Popular Packages](#popular-packages) or use [Online Building](docs/github-actions-usage.md) with no environment setup required
30
+ - **Developers**: Install [CLI Tool](docs/cli-usage.md) for one-command packaging of any website with customizable icons, window settings, and more
31
+ - **Advanced Users**: Clone the project locally for [Custom Development](#development), or check [Advanced Usage](docs/advanced-usage.md) for style customization and feature enhancement
31
32
 
32
33
  ## Popular Packages
33
34
 
@@ -152,58 +153,39 @@ In addition, double-click the title bar to switch to full-screen mode. For Mac u
152
153
 
153
154
  </details>
154
155
 
155
- ## Before starting
156
-
157
- 1. **For beginners**: Play with Popular Packages to find out Pake's capabilities, or try to pack your application with [GitHub Actions](docs/github-actions-usage.md). Don't hesitate to reach for assistance at [Discussion](https://github.com/tw93/Pake/discussions)!
158
- 2. **For developers**: “Command-Line Packaging” supports macOS fully. For Windows/Linux users, it requires some tinkering. [Configure your environment](https://tauri.app/start/prerequisites/) before getting started.
159
- 3. **For hackers**: For people who are good at both front-end development and Rust, how about customizing your apps' function more with the following [Customized Development](#development)?
160
-
161
156
  ## Command-Line Packaging
162
157
 
163
158
  ![Pake](https://raw.githubusercontent.com/tw93/static/main/pake/pake.gif)
164
159
 
165
- **Pake provides a command line tool, making the flow of package customization quicker and easier. See the [CLI usage guide](docs/cli-usage.md) for more information.**
166
-
167
160
  ```bash
168
- # Recommended (pnpm)
161
+ # Install
169
162
  pnpm install -g pake-cli
170
163
 
171
- # Alternative (npm)
172
- npm install -g pake-cli
173
-
174
- # Command usage
175
- pake url [OPTIONS]...
164
+ # Basic usage (auto-fetch website icon)
165
+ pake https://weekly.tw93.fun --name Weekly
176
166
 
177
- # Feel free to play with Pake! It might take a while to prepare the environment the first time you launch Pake.
178
- pake https://weekly.tw93.fun --name Weekly --hide-title-bar
167
+ # Common options: --name app name, --icon custom icon, --width/--height window size, --hide-title-bar macOS immersive
168
+ pake https://weekly.tw93.fun --name Weekly --icon https://cdn.tw93.fun/pake/weekly.icns --hide-title-bar
179
169
  ```
180
170
 
181
- If you are new to the command line, you can compile packages online with _GitHub Actions_. See our [documentation](#documentation) for detailed guides.
171
+ First-time packaging requires environment setup and may be slower, subsequent builds are fast. For complete parameter documentation, see [CLI Usage Guide](docs/cli-usage.md). Don't want to use CLI? Try [GitHub Actions Online Building](docs/github-actions-usage.md).
182
172
 
183
173
  ## Development
184
174
 
185
- Prepare your environment before starting. Make sure you have Rust `>=1.89` and Node `>=18` (e.g., `22.11.0`) installed on your computer. _Note: Latest stable versions are recommended._ For installation guidance, see [Tauri documentation](https://tauri.app/start/prerequisites/).
186
-
187
- If you are unfamiliar with these, it is better to try out the above tool to pack with one click.
175
+ Requires Rust `>=1.89` and Node `>=22`. For detailed installation guide, see [Tauri documentation](https://tauri.app/start/prerequisites/). If unfamiliar with development environment, use the CLI tool instead.
188
176
 
189
- ```sh
177
+ ```bash
190
178
  # Install dependencies
191
179
  pnpm i
192
180
 
193
- # Local development (right-click to open debug mode)
181
+ # Local development [right-click to open debug mode]
194
182
  pnpm run dev
195
183
 
196
184
  # Build application
197
185
  pnpm run build
198
186
  ```
199
187
 
200
- ## Documentation
201
-
202
- - **[CLI Usage](docs/cli-usage.md)** | [中文](docs/cli-usage_CN.md) - Command-line interface reference
203
- - **[Advanced Usage](docs/advanced-usage.md)** | [中文](docs/advanced-usage_CN.md) - Customization and advanced features
204
- - **[GitHub Actions](docs/github-actions-usage.md)** | [中文](docs/github-actions-usage_CN.md) - Build apps online
205
- - **[Pake Action](docs/pake-action.md)** - Use Pake as GitHub Action in your projects
206
- - **[Contributing](CONTRIBUTING.md)** - How to contribute to development
188
+ For style customization, feature enhancement, container communication and other advanced features, see [Advanced Usage Documentation](docs/advanced-usage.md).
207
189
 
208
190
  ## Developers
209
191
 
@@ -548,6 +530,6 @@ Pake's development can not be without these Hackers. They contributed a lot of c
548
530
  ## Support
549
531
 
550
532
  1. I have two cats, TangYuan and Coke. If you think Pake delights your life, you can feed them <a href="https://miaoyan.app/cats.html?name=Pake" target="_blank">some canned food 🥩</a>.
551
- 2. If you like Pake, you can star it on GitHub. Also, welcome to [recommend Pake](https://twitter.com/intent/tweet?url=https://github.com/tw93/Pake&text=%23Pake%20-%20A%20simple%20Rust%20packaged%20web%20pages%20to%20generate%20Mac%20App%20tool,%20compared%20to%20traditional%20Electron%20package,%20the%20size%20of%20nearly%2040%20times%20smaller,%20generally%20about%202M,%20the%20underlying%20use%20of%20Tauri,%20performance%20experience%20than%20the%20JS%20framework%20is%20much%20lighter~) to your friends.
533
+ 2. If you like Pake, you can star it on GitHub. Also, welcome to [recommend Pake](https://twitter.com/intent/tweet?url=https://github.com/tw93/Pake&text=Pake%20-%20Turn%20any%20webpage%20into%20a%20desktop%20app%20with%20one%20command.%20Nearly%2020x%20smaller%20than%20Electron%20packages,%20supports%20macOS%20Windows%20Linux) to your friends.
552
534
  3. You can follow my [Twitter](https://twitter.com/HiTw93) to get the latest news of Pake or join our [Telegram](https://t.me/+GclQS9ZnxyI2ODQ1) chat group.
553
535
  4. I hope that you enjoy playing with it. Let us know if you find a website that would be great for a Mac App!
package/dist/cli.js CHANGED
@@ -22,8 +22,8 @@ import sharp from 'sharp';
22
22
  import * as psl from 'psl';
23
23
 
24
24
  var name = "pake-cli";
25
- var version = "3.3.1";
26
- var description = "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 利用 Rust 轻松构建轻量级多端桌面应用。";
25
+ var version = "3.3.2";
26
+ var description = "🤱🏻 Turn any webpage into a desktop app with one command. 🤱🏻 一键打包网页生成轻量桌面应用。";
27
27
  var engines = {
28
28
  node: ">=18.0.0"
29
29
  };
@@ -73,7 +73,7 @@ var exports = "./dist/cli.js";
73
73
  var license = "MIT";
74
74
  var dependencies = {
75
75
  "@tauri-apps/api": "^2.8.0",
76
- "@tauri-apps/cli": "^2.8.3",
76
+ "@tauri-apps/cli": "^2.8.4",
77
77
  axios: "^1.11.0",
78
78
  chalk: "^5.6.0",
79
79
  commander: "^12.1.0",
@@ -85,7 +85,7 @@ var dependencies = {
85
85
  ora: "^8.2.0",
86
86
  prompts: "^2.4.2",
87
87
  psl: "^1.15.0",
88
- sharp: "^0.33.4",
88
+ sharp: "^0.33.5",
89
89
  "tmp-promise": "^3.0.3",
90
90
  "update-notifier": "^7.3.1"
91
91
  };
@@ -96,7 +96,7 @@ var devDependencies = {
96
96
  "@rollup/plugin-replace": "^6.0.2",
97
97
  "@rollup/plugin-terser": "^0.4.4",
98
98
  "@types/fs-extra": "^11.0.4",
99
- "@types/node": "^20.19.11",
99
+ "@types/node": "^20.19.13",
100
100
  "@types/page-icon": "^0.3.6",
101
101
  "@types/prompts": "^2.4.9",
102
102
  "@types/tmp": "^0.2.6",
@@ -104,7 +104,7 @@ var devDependencies = {
104
104
  "app-root-path": "^3.1.0",
105
105
  "cross-env": "^7.0.3",
106
106
  prettier: "^3.6.2",
107
- rollup: "^4.49.0",
107
+ rollup: "^4.50.0",
108
108
  "rollup-plugin-typescript2": "^0.36.0",
109
109
  tslib: "^2.8.1",
110
110
  typescript: "^5.9.2"
@@ -1150,20 +1150,54 @@ async function checkUpdateTips() {
1150
1150
  });
1151
1151
  }
1152
1152
 
1153
- // Constants
1154
1153
  const ICON_CONFIG = {
1155
1154
  minFileSize: 100,
1156
- downloadTimeout: 10000,
1157
1155
  supportedFormats: ['png', 'ico', 'jpeg', 'jpg', 'webp', 'icns'],
1158
1156
  whiteBackground: { r: 255, g: 255, b: 255 },
1157
+ transparentBackground: { r: 255, g: 255, b: 255, alpha: 0 },
1158
+ downloadTimeout: {
1159
+ ci: 5000,
1160
+ default: 15000,
1161
+ },
1162
+ };
1163
+ const PLATFORM_CONFIG = {
1164
+ win: { format: '.ico', sizes: [16, 32, 48, 64, 128, 256] },
1165
+ linux: { format: '.png', size: 512 },
1166
+ macos: { format: '.icns', sizes: [16, 32, 64, 128, 256, 512, 1024] },
1159
1167
  };
1160
- // API Configuration
1161
- const API_TOKENS = {
1162
- // cspell:disable-next-line
1168
+ const API_KEYS = {
1163
1169
  logoDev: ['pk_JLLMUKGZRpaG5YclhXaTkg', 'pk_Ph745P8mQSeYFfW2Wk039A'],
1164
- // cspell:disable-next-line
1165
1170
  brandfetch: ['1idqvJC0CeFSeyp3Yf7', '1idej-yhU_ThggIHFyG'],
1166
1171
  };
1172
+ /**
1173
+ * Generates platform-specific icon paths and handles copying for Windows
1174
+ */
1175
+ function generateIconPath(appName, isDefault = false) {
1176
+ const safeName = appName.toLowerCase().replace(/[^a-z0-9-_]/g, '_');
1177
+ const baseName = isDefault ? 'icon' : safeName;
1178
+ if (IS_WIN) {
1179
+ return path.join(npmDirectory, 'src-tauri', 'png', `${baseName}_256.ico`);
1180
+ }
1181
+ if (IS_LINUX) {
1182
+ return path.join(npmDirectory, 'src-tauri', 'png', `${baseName}_512.png`);
1183
+ }
1184
+ return path.join(npmDirectory, 'src-tauri', 'icons', `${baseName}.icns`);
1185
+ }
1186
+ async function copyWindowsIconIfNeeded(convertedPath, appName) {
1187
+ if (!IS_WIN || !convertedPath.endsWith('.ico')) {
1188
+ return convertedPath;
1189
+ }
1190
+ try {
1191
+ const finalIconPath = generateIconPath(appName);
1192
+ await fsExtra.ensureDir(path.dirname(finalIconPath));
1193
+ await fsExtra.copy(convertedPath, finalIconPath);
1194
+ return finalIconPath;
1195
+ }
1196
+ catch (error) {
1197
+ logger.warn(`Failed to copy Windows icon: ${error instanceof Error ? error.message : 'Unknown error'}`);
1198
+ return convertedPath;
1199
+ }
1200
+ }
1167
1201
  /**
1168
1202
  * Adds white background to transparent icons only
1169
1203
  */
@@ -1206,23 +1240,34 @@ async function convertIconFormat(inputPath, appName) {
1206
1240
  const iconName = appName.toLowerCase();
1207
1241
  // Generate platform-specific format
1208
1242
  if (IS_WIN) {
1243
+ // Support multiple sizes for better Windows compatibility
1209
1244
  await icongen(processedInputPath, platformOutputDir, {
1210
1245
  report: false,
1211
- ico: { name: `${iconName}_256`, sizes: [256] },
1246
+ ico: {
1247
+ name: `${iconName}_256`,
1248
+ sizes: PLATFORM_CONFIG.win.sizes,
1249
+ },
1212
1250
  });
1213
- return path.join(platformOutputDir, `${iconName}_256.ico`);
1251
+ return path.join(platformOutputDir, `${iconName}_256${PLATFORM_CONFIG.win.format}`);
1214
1252
  }
1215
1253
  if (IS_LINUX) {
1216
- const outputPath = path.join(platformOutputDir, `${iconName}_512.png`);
1217
- await fsExtra.copy(processedInputPath, outputPath);
1254
+ const outputPath = path.join(platformOutputDir, `${iconName}_${PLATFORM_CONFIG.linux.size}${PLATFORM_CONFIG.linux.format}`);
1255
+ // Ensure we convert to proper PNG format with correct size
1256
+ await sharp(processedInputPath)
1257
+ .resize(PLATFORM_CONFIG.linux.size, PLATFORM_CONFIG.linux.size, {
1258
+ fit: 'contain',
1259
+ background: ICON_CONFIG.transparentBackground,
1260
+ })
1261
+ .png()
1262
+ .toFile(outputPath);
1218
1263
  return outputPath;
1219
1264
  }
1220
1265
  // macOS
1221
1266
  await icongen(processedInputPath, platformOutputDir, {
1222
1267
  report: false,
1223
- icns: { name: iconName, sizes: [16, 32, 64, 128, 256, 512, 1024] },
1268
+ icns: { name: iconName, sizes: PLATFORM_CONFIG.macos.sizes },
1224
1269
  });
1225
- const outputPath = path.join(platformOutputDir, `${iconName}.icns`);
1270
+ const outputPath = path.join(platformOutputDir, `${iconName}${PLATFORM_CONFIG.macos.format}`);
1226
1271
  return (await fsExtra.pathExists(outputPath)) ? outputPath : null;
1227
1272
  }
1228
1273
  catch (error) {
@@ -1230,105 +1275,113 @@ async function convertIconFormat(inputPath, appName) {
1230
1275
  return null;
1231
1276
  }
1232
1277
  }
1233
- async function handleIcon(options, url) {
1234
- if (options.icon) {
1235
- if (options.icon.startsWith('http')) {
1236
- const downloadedPath = await downloadIcon(options.icon);
1237
- if (downloadedPath && options.name) {
1238
- // Check if the downloaded file is already in the correct format for the platform
1239
- const downloadedExt = path.extname(downloadedPath).toLowerCase();
1240
- const isCorrectFormat = (IS_WIN && downloadedExt === '.ico') ||
1241
- (IS_LINUX && downloadedExt === '.png') ||
1242
- (!IS_WIN && !IS_LINUX && downloadedExt === '.icns'); // macOS
1243
- if (isCorrectFormat) {
1244
- return downloadedPath;
1245
- }
1246
- // Convert downloaded icon to platform-specific format
1247
- const convertedPath = await convertIconFormat(downloadedPath, options.name);
1248
- if (convertedPath) {
1249
- // For Windows, copy the converted ico to the expected location
1250
- if (IS_WIN && convertedPath.endsWith('.ico')) {
1251
- const finalIconPath = path.join(npmDirectory, `src-tauri/png/${options.name.toLowerCase()}_256.ico`);
1252
- await fsExtra.ensureDir(path.dirname(finalIconPath));
1253
- await fsExtra.copy(convertedPath, finalIconPath);
1254
- return finalIconPath;
1255
- }
1256
- return convertedPath;
1257
- }
1258
- }
1259
- return downloadedPath;
1260
- }
1261
- return path.resolve(options.icon);
1262
- }
1263
- // Try to get favicon from website if URL is provided
1264
- if (url && url.startsWith('http') && options.name) {
1265
- const faviconPath = await tryGetFavicon(url, options.name);
1266
- if (faviconPath)
1267
- return faviconPath;
1278
+ /**
1279
+ * Processes downloaded or local icon for platform-specific format
1280
+ */
1281
+ async function processIcon(iconPath, appName) {
1282
+ if (!iconPath || !appName)
1283
+ return iconPath;
1284
+ // Check if already in correct platform format
1285
+ const ext = path.extname(iconPath).toLowerCase();
1286
+ const isCorrectFormat = (IS_WIN && ext === '.ico') ||
1287
+ (IS_LINUX && ext === '.png') ||
1288
+ (!IS_WIN && !IS_LINUX && ext === '.icns');
1289
+ if (isCorrectFormat) {
1290
+ return await copyWindowsIconIfNeeded(iconPath, appName);
1291
+ }
1292
+ // Convert to platform format
1293
+ const convertedPath = await convertIconFormat(iconPath, appName);
1294
+ if (convertedPath) {
1295
+ return await copyWindowsIconIfNeeded(convertedPath, appName);
1268
1296
  }
1297
+ return iconPath;
1298
+ }
1299
+ /**
1300
+ * Gets default icon with platform-specific fallback logic
1301
+ */
1302
+ async function getDefaultIcon() {
1269
1303
  logger.info('✼ No icon provided, using default icon.');
1270
- // For Windows, ensure we have proper fallback handling
1271
1304
  if (IS_WIN) {
1272
- const defaultIcoPath = path.join(npmDirectory, 'src-tauri/png/icon_256.ico');
1305
+ const defaultIcoPath = generateIconPath('icon', true);
1273
1306
  const defaultPngPath = path.join(npmDirectory, 'src-tauri/png/icon_512.png');
1274
- // First try default ico
1307
+ // Try default ico first
1275
1308
  if (await fsExtra.pathExists(defaultIcoPath)) {
1276
1309
  return defaultIcoPath;
1277
1310
  }
1278
- // If ico doesn't exist, try to convert from png
1311
+ // Convert from png if ico doesn't exist
1279
1312
  if (await fsExtra.pathExists(defaultPngPath)) {
1280
1313
  logger.info('✼ Default ico not found, converting from png...');
1281
1314
  try {
1282
1315
  const convertedPath = await convertIconFormat(defaultPngPath, 'icon');
1283
1316
  if (convertedPath && (await fsExtra.pathExists(convertedPath))) {
1284
- // Copy converted icon to the expected location for Windows
1285
- const finalIconPath = path.join(npmDirectory, 'src-tauri/png/icon_256.ico');
1286
- await fsExtra.ensureDir(path.dirname(finalIconPath));
1287
- await fsExtra.copy(convertedPath, finalIconPath);
1288
- return finalIconPath;
1317
+ return await copyWindowsIconIfNeeded(convertedPath, 'icon');
1289
1318
  }
1290
1319
  }
1291
1320
  catch (error) {
1292
- logger.warn(`Failed to convert default png to ico: ${error.message}`);
1321
+ logger.warn(`Failed to convert default png to ico: ${error instanceof Error ? error.message : 'Unknown error'}`);
1293
1322
  }
1294
1323
  }
1295
- // Last resort: return png path if it exists (Windows can handle png in some cases)
1324
+ // Fallback to png or empty
1296
1325
  if (await fsExtra.pathExists(defaultPngPath)) {
1297
1326
  logger.warn('✼ Using png as fallback for Windows (may cause issues).');
1298
1327
  return defaultPngPath;
1299
1328
  }
1300
- // If nothing exists, return empty string to let merge.ts handle default icon
1301
1329
  logger.warn('✼ No default icon found, will use pake default.');
1302
1330
  return '';
1303
1331
  }
1332
+ // Linux and macOS defaults
1304
1333
  const iconPath = IS_LINUX
1305
1334
  ? 'src-tauri/png/icon_512.png'
1306
1335
  : 'src-tauri/icons/icon.icns';
1307
1336
  return path.join(npmDirectory, iconPath);
1308
1337
  }
1338
+ /**
1339
+ * Main icon handling function with simplified logic flow
1340
+ */
1341
+ async function handleIcon(options, url) {
1342
+ // Handle custom icon (local file or remote URL)
1343
+ if (options.icon) {
1344
+ if (options.icon.startsWith('http')) {
1345
+ const downloadedPath = await downloadIcon(options.icon);
1346
+ if (downloadedPath) {
1347
+ const result = await processIcon(downloadedPath, options.name || '');
1348
+ if (result)
1349
+ return result;
1350
+ }
1351
+ return '';
1352
+ }
1353
+ // Local file path
1354
+ const resolvedPath = path.resolve(options.icon);
1355
+ const result = await processIcon(resolvedPath, options.name || '');
1356
+ return result || resolvedPath;
1357
+ }
1358
+ // Try favicon from website
1359
+ if (url && options.name) {
1360
+ const faviconPath = await tryGetFavicon(url, options.name);
1361
+ if (faviconPath)
1362
+ return faviconPath;
1363
+ }
1364
+ // Use default icon
1365
+ return await getDefaultIcon();
1366
+ }
1309
1367
  /**
1310
1368
  * Generates icon service URLs for a domain
1311
1369
  */
1312
1370
  function generateIconServiceUrls(domain) {
1313
- const logoDevUrls = API_TOKENS.logoDev
1371
+ const logoDevUrls = API_KEYS.logoDev
1314
1372
  .sort(() => Math.random() - 0.5)
1315
1373
  .map((token) => `https://img.logo.dev/${domain}?token=${token}&format=png&size=256`);
1316
- const brandfetchUrls = API_TOKENS.brandfetch
1374
+ const brandfetchUrls = API_KEYS.brandfetch
1317
1375
  .sort(() => Math.random() - 0.5)
1318
1376
  .map((key) => `https://cdn.brandfetch.io/${domain}/w/400/h/400?c=${key}`);
1319
1377
  return [
1320
1378
  ...logoDevUrls,
1321
1379
  ...brandfetchUrls,
1322
1380
  `https://logo.clearbit.com/${domain}?size=256`,
1323
- `https://logo.uplead.com/${domain}`,
1324
1381
  `https://www.google.com/s2/favicons?domain=${domain}&sz=256`,
1325
1382
  `https://favicon.is/${domain}`,
1326
- `https://icons.duckduckgo.com/ip3/${domain}.ico`,
1327
- `https://icon.horse/icon/${domain}`,
1328
1383
  `https://${domain}/favicon.ico`,
1329
1384
  `https://www.${domain}/favicon.ico`,
1330
- `https://${domain}/apple-touch-icon.png`,
1331
- `https://${domain}/apple-touch-icon-precomposed.png`,
1332
1385
  ];
1333
1386
  }
1334
1387
  /**
@@ -1339,9 +1392,10 @@ async function tryGetFavicon(url, appName) {
1339
1392
  const domain = new URL(url).hostname;
1340
1393
  const spinner = getSpinner(`Fetching icon from ${domain}...`);
1341
1394
  const serviceUrls = generateIconServiceUrls(domain);
1342
- // Use shorter timeout for CI environments
1343
1395
  const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
1344
- const downloadTimeout = isCI ? 5000 : ICON_CONFIG.downloadTimeout;
1396
+ const downloadTimeout = isCI
1397
+ ? ICON_CONFIG.downloadTimeout.ci
1398
+ : ICON_CONFIG.downloadTimeout.default;
1345
1399
  for (const serviceUrl of serviceUrls) {
1346
1400
  try {
1347
1401
  const faviconPath = await downloadIcon(serviceUrl, false, downloadTimeout);
@@ -1349,22 +1403,20 @@ async function tryGetFavicon(url, appName) {
1349
1403
  continue;
1350
1404
  const convertedPath = await convertIconFormat(faviconPath, appName);
1351
1405
  if (convertedPath) {
1352
- // For Windows, copy the converted ico to the expected location
1353
- if (IS_WIN && convertedPath.endsWith('.ico')) {
1354
- const finalIconPath = path.join(npmDirectory, `src-tauri/png/${appName.toLowerCase()}_256.ico`);
1355
- await fsExtra.ensureDir(path.dirname(finalIconPath));
1356
- await fsExtra.copy(convertedPath, finalIconPath);
1357
- spinner.succeed(chalk.green('Icon fetched and converted successfully!'));
1358
- return finalIconPath;
1359
- }
1406
+ const finalPath = await copyWindowsIconIfNeeded(convertedPath, appName);
1360
1407
  spinner.succeed(chalk.green('Icon fetched and converted successfully!'));
1361
- return convertedPath;
1408
+ return finalPath;
1362
1409
  }
1363
1410
  }
1364
1411
  catch (error) {
1365
- // Log specific errors in CI for debugging
1366
- if (isCI) {
1367
- logger.debug(`Icon service ${serviceUrl} failed: ${error.message}`);
1412
+ logger.debug(`Icon service ${serviceUrl} failed: ${error.message}`);
1413
+ // Platform-specific error handling
1414
+ if ((IS_LINUX || IS_WIN) && error.code === 'ENOTFOUND') {
1415
+ logger.debug(`DNS resolution failed for ${serviceUrl}, trying next service...`);
1416
+ }
1417
+ // Windows-specific icon conversion errors
1418
+ if (IS_WIN && error.message.includes('icongen')) {
1419
+ logger.debug(`Windows icon conversion failed for ${serviceUrl}, trying next service...`);
1368
1420
  }
1369
1421
  continue;
1370
1422
  }
@@ -1384,7 +1436,7 @@ async function downloadIcon(iconUrl, showSpinner = true, customTimeout) {
1384
1436
  try {
1385
1437
  const response = await axios.get(iconUrl, {
1386
1438
  responseType: 'arraybuffer',
1387
- timeout: customTimeout || ICON_CONFIG.downloadTimeout,
1439
+ timeout: customTimeout || 10000,
1388
1440
  });
1389
1441
  const iconData = response.data;
1390
1442
  if (!iconData || iconData.byteLength < ICON_CONFIG.minFileSize)
@@ -1408,15 +1460,11 @@ async function downloadIcon(iconUrl, showSpinner = true, customTimeout) {
1408
1460
  */
1409
1461
  async function saveIconFile(iconData, extension) {
1410
1462
  const buffer = Buffer.from(iconData);
1411
- if (IS_LINUX) {
1412
- const iconPath = 'png/linux_temp.png';
1413
- await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, buffer);
1414
- return iconPath;
1415
- }
1416
1463
  const { path: tempPath } = await dir();
1417
- const iconPath = `${tempPath}/icon.${extension}`;
1418
- await fsExtra.outputFile(iconPath, buffer);
1419
- return iconPath;
1464
+ // Always save with the original extension first
1465
+ const originalIconPath = path.join(tempPath, `icon.${extension}`);
1466
+ await fsExtra.outputFile(originalIconPath, buffer);
1467
+ return originalIconPath;
1420
1468
  }
1421
1469
 
1422
1470
  // Extracts the domain from a given URL.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pake-cli",
3
- "version": "3.3.1",
4
- "description": "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 利用 Rust 轻松构建轻量级多端桌面应用。",
3
+ "version": "3.3.2",
4
+ "description": "🤱🏻 Turn any webpage into a desktop app with one command. 🤱🏻 一键打包网页生成轻量桌面应用。",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
7
7
  },
@@ -51,7 +51,7 @@
51
51
  "license": "MIT",
52
52
  "dependencies": {
53
53
  "@tauri-apps/api": "^2.8.0",
54
- "@tauri-apps/cli": "^2.8.3",
54
+ "@tauri-apps/cli": "^2.8.4",
55
55
  "axios": "^1.11.0",
56
56
  "chalk": "^5.6.0",
57
57
  "commander": "^12.1.0",
@@ -63,7 +63,7 @@
63
63
  "ora": "^8.2.0",
64
64
  "prompts": "^2.4.2",
65
65
  "psl": "^1.15.0",
66
- "sharp": "^0.33.4",
66
+ "sharp": "^0.33.5",
67
67
  "tmp-promise": "^3.0.3",
68
68
  "update-notifier": "^7.3.1"
69
69
  },
@@ -74,7 +74,7 @@
74
74
  "@rollup/plugin-replace": "^6.0.2",
75
75
  "@rollup/plugin-terser": "^0.4.4",
76
76
  "@types/fs-extra": "^11.0.4",
77
- "@types/node": "^20.19.11",
77
+ "@types/node": "^20.19.13",
78
78
  "@types/page-icon": "^0.3.6",
79
79
  "@types/prompts": "^2.4.9",
80
80
  "@types/tmp": "^0.2.6",
@@ -82,7 +82,7 @@
82
82
  "app-root-path": "^3.1.0",
83
83
  "cross-env": "^7.0.3",
84
84
  "prettier": "^3.6.2",
85
- "rollup": "^4.49.0",
85
+ "rollup": "^4.50.0",
86
86
  "rollup-plugin-typescript2": "^0.36.0",
87
87
  "tslib": "^2.8.1",
88
88
  "typescript": "^5.9.2"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "windows": [
3
3
  {
4
- "url": "https://weekly.tw93.fun",
4
+ "url": "https://github.com",
5
5
  "url_type": "web",
6
6
  "hide_title_bar": false,
7
7
  "fullscreen": false,
@@ -1,6 +1,6 @@
1
1
  {
2
- "productName": "WeeklyIconFixed",
3
- "identifier": "com.pake.33f03a",
2
+ "productName": "GitHubAutoIconTest",
3
+ "identifier": "com.pake.3097fc",
4
4
  "version": "1.0.0",
5
5
  "app": {
6
6
  "withGlobalTauri": true,
@@ -13,14 +13,14 @@
13
13
  },
14
14
  "bundle": {
15
15
  "icon": [
16
- "icons/weeklyiconfixed.icns"
16
+ "icons/githubautoicontest.icns"
17
17
  ],
18
18
  "active": true,
19
19
  "targets": [
20
20
  "app"
21
21
  ],
22
22
  "resources": [
23
- "icons/weeklyiconfixed.icns"
23
+ "icons/githubautoicontest.icns"
24
24
  ]
25
25
  }
26
26
  }
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "bundle": {
3
3
  "icon": [
4
- "icons/weeklyiconfixed.icns"
4
+ "icons/githubautoicontest.icns"
5
5
  ],
6
6
  "active": true,
7
7
  "targets": [
8
8
  "app"
9
9
  ],
10
10
  "resources": [
11
- "icons/weeklyiconfixed.icns"
11
+ "icons/githubautoicontest.icns"
12
12
  ]
13
13
  }
14
14
  }