@lynker-desktop/electron-sdk 0.0.9-alpha.7 → 0.0.9-alpha.72
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 +160 -1
- package/common/index.d.ts +96 -0
- package/common/index.d.ts.map +1 -1
- package/common/index.js.map +1 -1
- package/esm/common/index.d.ts +96 -0
- package/esm/common/index.d.ts.map +1 -1
- package/esm/common/index.js.map +1 -1
- package/esm/main/clipboard.d.ts +32 -0
- package/esm/main/clipboard.d.ts.map +1 -0
- package/esm/main/clipboard.js +1208 -0
- package/esm/main/clipboard.js.map +1 -0
- package/esm/main/downloader.d.ts +212 -0
- package/esm/main/downloader.d.ts.map +1 -0
- package/esm/main/downloader.js +674 -0
- package/esm/main/downloader.js.map +1 -0
- package/esm/main/index.d.ts +20 -67
- package/esm/main/index.d.ts.map +1 -1
- package/esm/main/index.js +51 -202
- package/esm/main/index.js.map +1 -1
- package/esm/main/resource-cache.d.ts +245 -0
- package/esm/main/resource-cache.d.ts.map +1 -0
- package/esm/main/resource-cache.js +857 -0
- package/esm/main/resource-cache.js.map +1 -0
- package/esm/main/shortcut.d.ts +14 -0
- package/esm/main/shortcut.d.ts.map +1 -0
- package/esm/main/shortcut.js +173 -0
- package/esm/main/shortcut.js.map +1 -0
- package/esm/main/store.d.ts +10 -0
- package/esm/main/store.d.ts.map +1 -0
- package/esm/main/store.js +62 -0
- package/esm/main/store.js.map +1 -0
- package/esm/main/video-downloader.d.ts +39 -0
- package/esm/main/video-downloader.d.ts.map +1 -0
- package/esm/main/video-downloader.js +505 -0
- package/esm/main/video-downloader.js.map +1 -0
- package/esm/preload/index.js +19 -1
- package/esm/preload/index.js.map +1 -1
- package/esm/renderer/index.d.ts +8 -0
- package/esm/renderer/index.d.ts.map +1 -1
- package/esm/renderer/index.js +25 -0
- package/esm/renderer/index.js.map +1 -1
- package/main/clipboard.d.ts +32 -0
- package/main/clipboard.d.ts.map +1 -0
- package/main/clipboard.js +1208 -0
- package/main/clipboard.js.map +1 -0
- package/main/downloader.d.ts +212 -0
- package/main/downloader.d.ts.map +1 -0
- package/main/downloader.js +674 -0
- package/main/downloader.js.map +1 -0
- package/main/index.d.ts +20 -67
- package/main/index.d.ts.map +1 -1
- package/main/index.js +54 -205
- package/main/index.js.map +1 -1
- package/main/resource-cache.d.ts +245 -0
- package/main/resource-cache.d.ts.map +1 -0
- package/main/resource-cache.js +857 -0
- package/main/resource-cache.js.map +1 -0
- package/main/shortcut.d.ts +14 -0
- package/main/shortcut.d.ts.map +1 -0
- package/main/shortcut.js +173 -0
- package/main/shortcut.js.map +1 -0
- package/main/store.d.ts +10 -0
- package/main/store.d.ts.map +1 -0
- package/main/store.js +64 -0
- package/main/store.js.map +1 -0
- package/main/video-downloader.d.ts +39 -0
- package/main/video-downloader.d.ts.map +1 -0
- package/main/video-downloader.js +510 -0
- package/main/video-downloader.js.map +1 -0
- package/package.json +9 -5
- package/preload/index.js +19 -1
- package/preload/index.js.map +1 -1
- package/renderer/index.d.ts +8 -0
- package/renderer/index.d.ts.map +1 -1
- package/renderer/index.js +25 -0
- package/renderer/index.js.map +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-cache.js","sources":["../src/src/main/resource-cache.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport md5 from 'md5';\nimport mime from 'mime-types';\nimport { ipcMain, webContents } from 'electron';\nimport { DownloaderHelper } from 'node-downloader-helper';\n\n/**\n * 默认文件扩展名\n */\nconst DEFAULT_EXT = '.res';\n\n/**\n * 默认 MIME 类型\n */\nconst DEFAULT_MIME_TYPE = 'application/octet-stream';\n\n/**\n * 最大重定向次数\n */\nconst MAX_REDIRECTS = 5;\n\n/**\n * 资源缓存配置项\n */\nexport interface ResourceCacheOptions {\n /** 缓存目录,必填 */\n cacheDir: string;\n /** 缓存有效期(毫秒),默认24小时 */\n cacheTTL?: number;\n /** 匹配需要缓存的资源,支持正则或函数 */\n match?: RegExp | ((url: string) => boolean);\n /** 允许缓存的资源来源,支持null/数组/函数 */\n allowedOrigins?: null | string[] | ((url: string) => boolean);\n}\n\n/**\n * 下载进度回调函数类型\n */\nexport type DownloadProgressCallback = (progress: {\n url: string; // 正在下载的 URL\n downloaded: number; // 已下载字节数\n total: number; // 总字节数(如果服务器提供 Content-Length)\n percentage: number; // 下载进度百分比 (0-100),如果 total 未知则为 -1\n speed: number; // 下载速度(字节/秒)\n}) => void;\n\n/**\n * 缓存进度回调函数类型\n */\nexport type CacheProgressCallback = (progress: {\n current: number; // 当前完成的 URL 数量\n total: number; // 总 URL 数量\n url: string; // 当前处理的 URL\n success: boolean; // 当前 URL 是否成功\n result?: { // 当前 URL 的处理结果\n filePath?: string;\n hostPath?: string;\n mimeType?: string;\n size?: number;\n error?: string;\n };\n percentage: number; // 进度百分比 (0-100)\n downloadProgress?: { // 下载进度(如果正在下载)\n downloaded: number;\n total: number;\n percentage: number;\n speed: number;\n };\n}) => void;\n\n/**\n * 默认配置\n */\nconst DEFAULT_OPTIONS: Required<Omit<ResourceCacheOptions, 'cacheDir'>> & { cacheDir: string } = {\n cacheDir: '',\n cacheTTL: 24 * 60 * 60 * 1000,\n // 图片格式:png, jpg/jpeg, webp, gif, svg, ico, bmp, avif, heic, heif, tiff, tif\n // 字体格式:woff, woff2, ttf, eot, otf\n // 视频格式:mp4, webm, ogg, mov, avi, mkv, flv, m4v, 3gp\n // 音频格式:mp3, wav, aac, m4a, flac, opus, wma\n // 样式和脚本:css, js, json, xml, txt\n // Web资源:wasm, map (source map)\n // 文档格式:pdf\n // 压缩文件:zip, 7z, rar, tar, gz, bz2\n match: /\\.(png|jpe?g|webp|gif|svg|ico|bmp|avif|heic|heif|tiff?|woff2?|ttf|eot|otf|mp4|webm|ogg|mov|avi|mkv|flv|m4v|3gp|mp3|wav|aac|m4a|flac|opus|wma|css|js|json|xml|txt|wasm|map|pdf|zip|7z|rar|tar|gz|bz2)(\\?.*)?$/i,\n allowedOrigins: null,\n};\n\n/**\n * 资源缓存类:拦截并缓存静态资源,提升加载性能\n */\nexport class ResourceCache {\n static scheme = 'cachefile';\n private cacheHost: string = `${ResourceCache.scheme}://-`;\n /** Electron session 实例 */\n private session: Electron.Session;\n /** 缓存配置 */\n private options: Required<ResourceCacheOptions>;\n /** 缓存的匹配函数(避免重复创建) */\n private _cachedMatchFunction?: (url: string) => boolean;\n /** 缓存的来源校验函数(避免重复创建) */\n private _cachedOriginFunction?: (url: string) => boolean;\n /** 正在下载的 URL 和对应的下载信息(避免重复下载,允许多个请求等待同一个下载任务) */\n private _downloadingUrls = new Map<string, {\n promise: Promise<void>;\n downloader: DownloaderHelper;\n progressCallbacks: Set<DownloadProgressCallback>;\n }>();\n\n /**\n * 构造函数\n * @param session Electron session\n * @param options 缓存配置\n */\n constructor(session: Electron.Session, options: ResourceCacheOptions) {\n if (!session) throw new Error('ResourceCache: session is required');\n this.session = session;\n // 合并配置,保证类型安全\n this.options = {\n ...DEFAULT_OPTIONS,\n ...options,\n cacheDir: options.cacheDir,\n cacheTTL: options.cacheTTL ?? DEFAULT_OPTIONS.cacheTTL,\n match: options.match ?? DEFAULT_OPTIONS.match,\n allowedOrigins: options.allowedOrigins ?? DEFAULT_OPTIONS.allowedOrigins,\n };\n\n if (!this.options.cacheDir) {\n throw new Error('ResourceCache: cacheDir is required');\n }\n\n // 确保缓存目录存在\n if (!fs.existsSync(this.options.cacheDir)) {\n fs.mkdirSync(this.options.cacheDir, { recursive: true });\n }\n\n this._registerInterceptor();\n // 异步清理过期缓存,不阻塞初始化\n this._cleanOldCache().catch(err => {\n console.log('初始化时清理过期缓存失败:', err);\n });\n\n ipcMain.handle('core:cache', async (event: Electron.IpcMainInvokeEvent, options: { id: string, method: 'add' | 'delete' | 'clear' | 'stats' | 'get', urls?: string | string[], force?: boolean }) => {\n try {\n switch (options.method) {\n case 'clear':\n return await this.clearCache();\n case 'add': {\n const { id } = options;\n const sender = event.sender as Electron.WebContents;\n const urls = Array.isArray(options.urls) ? options.urls : options.urls ? [options.urls] : [];\n const data = await this.addCacheUrls(urls, options.force ?? false, true, (data: any) => {\n try {\n if (sender) {\n if (typeof sender?.send === 'function') {\n sender?.send?.(`core:cache:progress`, {\n id,\n data\n });\n }\n }\n } catch (error) {\n console.log('发送缓存进度回调失败:', error);\n }\n });\n return Array.isArray(options.urls) ? data : data[0];\n }\n case 'delete': {\n const urls = Array.isArray(options.urls) ? options.urls : options.urls ? [options.urls] : [];\n const data = await this.deleteCacheUrls(urls);\n return Array.isArray(options.urls) ? data : data[0];\n }\n case 'get': {\n const urls = Array.isArray(options.urls) ? options.urls : options.urls ? [options.urls] : [];\n const data = await this.getCacheUrls(urls);\n return Array.isArray(options.urls) ? data : data[0];\n }\n case 'stats':\n return await this.getCacheStats();\n default:\n return undefined;\n }\n } catch (error) {\n return { success: false, error: error instanceof Error ? error.message : '未知错误' };\n }\n });\n }\n\n /**\n * 获取缓存统计信息(异步版本,性能更好)\n */\n public async getCacheStats(): Promise<{ size: number, totalSize: number }> {\n try {\n const files = await fs.promises.readdir(this.options.cacheDir);\n if (files.length === 0) {\n return { size: 0, totalSize: 0 };\n }\n\n // 并行获取文件信息,提升性能\n const fileInfos = await Promise.allSettled(\n files.map(async (file) => {\n const filePath = path.join(this.options.cacheDir, file);\n try {\n const stats = await fs.promises.stat(filePath);\n return { file, filePath, size: stats.size };\n } catch (error) {\n return { file, filePath, size: 0, error };\n }\n })\n );\n\n const validInfos = fileInfos\n .filter((r): r is PromiseFulfilledResult<{ file: string; filePath: string; size: number; error?: any }> => r.status === 'fulfilled')\n .map(r => r.value);\n\n return {\n size: validInfos.length,\n totalSize: validInfos.reduce((sum, info) => sum + info.size, 0)\n };\n } catch (error) {\n console.log('获取缓存统计信息失败:', error);\n return { size: 0, totalSize: 0 };\n }\n }\n\n /**\n * 获取资源匹配函数(带缓存,避免重复创建)\n */\n private _getMatchFunction(): (url: string) => boolean {\n if (this._cachedMatchFunction) {\n return this._cachedMatchFunction;\n }\n\n const matcher = this.options.match;\n if (typeof matcher === 'function') {\n this._cachedMatchFunction = matcher;\n } else if (matcher instanceof RegExp) {\n this._cachedMatchFunction = (url: string) => matcher.test(url);\n } else {\n this._cachedMatchFunction = () => false;\n }\n\n return this._cachedMatchFunction;\n }\n\n /**\n * 获取来源校验函数(带缓存,避免重复创建)\n */\n private _getOriginAllowFunction(): (url: string) => boolean {\n if (this._cachedOriginFunction) {\n return this._cachedOriginFunction;\n }\n\n const origins = this.options.allowedOrigins;\n if (!origins) {\n this._cachedOriginFunction = () => true;\n } else if (typeof origins === 'function') {\n this._cachedOriginFunction = origins;\n } else {\n const prefixList = origins.map(o => o.toLowerCase());\n this._cachedOriginFunction = (url: string) => {\n try {\n const origin = new URL(url).origin.toLowerCase();\n return prefixList.some(prefix => origin.startsWith(prefix));\n } catch {\n return false;\n }\n };\n }\n\n return this._cachedOriginFunction;\n }\n\n /**\n * 获取缓存文件路径\n * @param url 资源URL\n * @param customExt 自定义文件扩展名(可选,用于 base64 URL)\n */\n public getCachedPath(url: string, customExt?: string): { filePath: string, hostPath: string } {\n const md5Str = md5(url);\n let ext = '.res';\n\n if (customExt) {\n // 如果提供了自定义扩展名,使用它\n ext = customExt.startsWith('.') ? customExt : `.${customExt}`;\n } else {\n // 尝试从 URL 中提取扩展名\n try {\n const urlObj = new URL(url);\n ext = path.extname(urlObj.pathname) || DEFAULT_EXT;\n } catch {\n // 如果 URL 解析失败(可能是 base64 data URL),使用默认扩展名\n ext = DEFAULT_EXT;\n }\n }\n\n return {\n filePath: path.join(this.options.cacheDir, `${md5Str}${ext}`),\n hostPath: `${this.cacheHost}/${md5Str}${ext}`,\n }\n }\n\n /**\n * 判断缓存是否有效(同步版本,用于拦截器)\n * @param filePath 缓存文件路径\n */\n public isCacheValid(filePath: string): boolean {\n try {\n if (!fs.existsSync(filePath)) return false;\n const stat = fs.statSync(filePath);\n return Date.now() - stat.mtimeMs < this.options.cacheTTL;\n } catch {\n return false;\n }\n }\n\n /**\n * 判断缓存是否有效(异步版本,性能更好)\n * @param filePath 缓存文件路径\n */\n public async isCacheValidAsync(filePath: string): Promise<boolean> {\n try {\n const stat = await fs.promises.stat(filePath);\n return Date.now() - stat.mtimeMs < this.options.cacheTTL;\n } catch {\n return false;\n }\n }\n\n /**\n * 下载资源到本地缓存(异步版本,返回 Promise)\n * @param url 资源URL\n * @param filePath 本地缓存路径\n * @param redirectCount 当前重定向次数(内部使用)\n * @param onProgress 下载进度回调函数(可选)\n * @returns Promise<void> 下载完成或失败\n */\n public downloadResourceAsync(\n url: string,\n filePath: string,\n redirectCount: number = 0,\n onProgress?: DownloadProgressCallback\n ): Promise<void> {\n // 检查是否正在下载,如果正在下载则返回已存在的 Promise(允许多个请求等待同一个下载任务)\n const existingDownload = this._downloadingUrls.get(url);\n if (existingDownload) {\n // 如果提供了新的进度回调,添加到回调列表中\n if (onProgress) {\n existingDownload.progressCallbacks.add(onProgress);\n }\n return existingDownload.promise;\n }\n\n // 检查重定向次数限制\n if (redirectCount >= MAX_REDIRECTS) {\n return Promise.reject(new Error(`重定向次数超过限制 (${MAX_REDIRECTS}): ${url}`));\n }\n\n // 创建新的下载 Promise\n let downloader: DownloaderHelper;\n // 创建进度回调集合(在 Promise 外部,以便后续可以访问)\n const progressCallbacks = new Set<DownloadProgressCallback>();\n if (onProgress) {\n progressCallbacks.add(onProgress);\n }\n\n const downloadPromise = new Promise<void>((resolve, reject) => {\n const tempFilePath = `${filePath}.cache`;\n const downloadDir = path.dirname(tempFilePath);\n const downloadFileName = path.basename(tempFilePath);\n\n // 确保目录存在\n if (!fs.existsSync(downloadDir)) {\n fs.mkdirSync(downloadDir, { recursive: true });\n }\n\n // 创建下载器实例\n const dl = new DownloaderHelper(url, downloadDir, {\n fileName: downloadFileName,\n retry: { maxRetries: 3, delay: 1000 },\n // 超时设置:10 分钟(600000 毫秒)\n // 对于视频等大文件,需要更长的超时时间\n // 如果 10 分钟内没有任何数据传输,才会超时\n timeout: 600000,\n override: true, // 覆盖已存在的文件\n httpRequestOptions: {\n // 允许重定向\n followRedirect: true,\n maxRedirects: MAX_REDIRECTS\n }\n });\n\n // 将下载器实例赋值给外部变量(Promise 构造函数是同步执行的)\n downloader = dl;\n\n // 监听下载进度 - 必须在 start() 之前设置\n // 注意:我们需要在 start() 之前设置事件监听器,这样后续的请求可以正确绑定进度回调\n dl.on('progress', (stats) => {\n // 调用所有注册的进度回调\n const progressData = {\n url,\n downloaded: stats.downloaded || 0,\n total: stats.total || 0,\n percentage: stats.progress !== undefined ? Math.round(stats.progress) : -1,\n speed: stats.speed || 0\n };\n\n progressCallbacks.forEach((callback) => {\n try {\n callback(progressData);\n } catch (error) {\n // 忽略回调中的错误,避免影响下载\n console.error('进度回调执行失败:', error);\n }\n });\n });\n\n // 监听下载完成\n dl.on('end', () => {\n // 将临时文件重命名为最终文件\n fs.rename(tempFilePath, filePath, (renameErr) => {\n // 无论成功还是失败,都要从下载列表中删除\n this._downloadingUrls.delete(url);\n if (renameErr) {\n reject(new Error(`缓存文件重命名失败 from ${tempFilePath} to ${filePath}: ${renameErr.message}`));\n } else {\n resolve();\n }\n });\n });\n\n // 监听下载错误\n dl.on('error', (err) => {\n // 从下载列表中删除\n this._downloadingUrls.delete(url);\n // 清理临时文件\n fs.promises.unlink(tempFilePath).catch(() => {\n // 忽略删除失败\n });\n reject(err instanceof Error ? err : new Error(`下载失败: ${url}`));\n });\n\n // 监听下载停止(取消)\n dl.on('stop', () => {\n // 从下载列表中删除\n this._downloadingUrls.delete(url);\n // 清理临时文件\n fs.promises.unlink(tempFilePath).catch(() => {\n // 忽略删除失败\n });\n reject(new Error(`下载已停止: ${url}`));\n });\n\n // 开始下载 - 必须在所有事件监听器设置完成后调用\n dl.start().catch((err) => {\n // 从下载列表中删除\n this._downloadingUrls.delete(url);\n reject(err instanceof Error ? err : new Error(`启动下载失败: ${url}`));\n });\n });\n\n // 立即将 Promise、下载器实例和进度回调集合存储到 Map 中,供后续相同 URL 的请求复用\n // 注意:必须在 start() 调用之前存储,以便后续请求可以绑定进度回调\n // 由于 Promise 构造函数是同步执行的,此时 downloader 已经被赋值,事件监听器也已设置完成\n this._downloadingUrls.set(url, {\n promise: downloadPromise,\n downloader: downloader!,\n progressCallbacks\n });\n\n return downloadPromise;\n }\n\n /**\n * 下载资源到本地缓存(同步版本,不返回 Promise,用于拦截器)\n * @param url 资源URL\n * @param filePath 本地缓存路径\n */\n public downloadResource(url: string, filePath: string): void {\n // 异步执行,不等待完成\n // 如果正在下载,跳过(避免重复下载)\n if (this._downloadingUrls.has(url)) {\n return;\n }\n // 调用 downloadResourceAsync,它会自动处理重复下载的情况\n this.downloadResourceAsync(url, filePath).catch(() => {\n // 静默处理错误,避免日志过多\n });\n }\n\n /**\n * 从文件扩展名获取 MIME 类型\n * @param ext 文件扩展名(带或不带点)\n * @returns MIME 类型\n */\n private _getMimeTypeFromExt(ext: string): string {\n const cleanExt = ext.replace(/^\\./, '').toLowerCase();\n const mimeType = mime.lookup(cleanExt);\n return mimeType || DEFAULT_MIME_TYPE;\n }\n\n /**\n * 检测并处理 base64 data URL\n * @param url 资源URL\n * @returns 如果是 base64 URL,返回 true、文件扩展名、MIME 类型和数据;否则返回 false\n */\n private _isBase64DataUrl(url: string): { isBase64: boolean, ext?: string, mimeType?: string, data?: string } {\n if (!url.startsWith('data:')) {\n return { isBase64: false };\n }\n\n try {\n // 解析 data URL 格式:data:[<mediatype>][;base64],<data>\n const commaIndex = url.indexOf(',');\n if (commaIndex === -1) {\n return { isBase64: false };\n }\n\n const header = url.substring(0, commaIndex);\n const data = url.substring(commaIndex + 1);\n\n // 检查是否包含 base64 标识\n if (!header.includes('base64')) {\n return { isBase64: false };\n }\n\n // 从 mediatype 中提取文件扩展名和 MIME 类型\n // 例如:data:image/png;base64 -> png, image/png\n // 例如:data:image/jpeg;base64 -> jpeg, image/jpeg\n let ext = DEFAULT_EXT.replace(/^\\./, '');\n let mimeType = DEFAULT_MIME_TYPE;\n const mimeMatch = header.match(/data:([^;]+)/);\n if (mimeMatch && mimeMatch[1]) {\n mimeType = mimeMatch[1];\n // 使用 mime-types 包从 MIME 类型获取扩展名\n const extension = mime.extension(mimeType);\n if (extension) {\n ext = extension;\n }\n }\n\n return { isBase64: true, ext, mimeType, data };\n } catch (error) {\n return { isBase64: false };\n }\n }\n\n /**\n * 保存 base64 数据到文件\n * @param base64Data base64 编码的数据\n * @param filePath 目标文件路径\n */\n private async _saveBase64ToFile(base64Data: string, filePath: string): Promise<void> {\n try {\n // 解码 base64 数据\n const buffer = Buffer.from(base64Data, 'base64');\n\n // 使用 Promise 版本的 writeFile\n // Buffer 继承自 Uint8Array,可以直接使用\n await fs.promises.writeFile(filePath, buffer as Uint8Array);\n } catch (error) {\n throw new Error(`保存 base64 文件失败: ${error instanceof Error ? error.message : '未知错误'}`);\n }\n }\n\n /**\n * 手动缓存指定 URL 的资源\n * @param url 要缓存的资源 URL(支持普通 URL 和 base64 data URL)\n * @param force 是否强制重新下载,即使缓存有效(默认 false)\n * @param ignoreOrigin 是否忽略来源检查(默认 false)\n * @param onDownloadProgress 下载进度回调函数(可选)\n * @returns Promise<{ filePath: string, hostPath: string, mimeType: string, size: number }> 返回缓存文件路径、主机路径、MIME 类型和文件大小\n * @throws 如果 URL 不匹配缓存规则或来源不允许,会抛出错误\n */\n public async cacheUrl(\n url: string,\n force: boolean = false,\n ignoreOrigin: boolean = false,\n onDownloadProgress?: DownloadProgressCallback\n ): Promise<{ filePath: string, hostPath: string, mimeType: string, size: number }> {\n // 检查是否是 base64 data URL\n const base64Info = this._isBase64DataUrl(url);\n\n if (base64Info.isBase64) {\n // 处理 base64 data URL\n if (!base64Info.data || !base64Info.ext) {\n throw new Error(`无效的 base64 data URL: ${url}`);\n }\n\n // 获取缓存路径(使用检测到的扩展名)\n const cachePath = this.getCachedPath(url, base64Info.ext);\n const mimeType = base64Info.mimeType || this._getMimeTypeFromExt(base64Info.ext);\n\n // 如果缓存有效且不强制重新下载,直接返回\n if (!force && await this.isCacheValidAsync(cachePath.filePath)) {\n const stats = await fs.promises.stat(cachePath.filePath);\n return {\n ...cachePath,\n mimeType,\n size: stats.size\n };\n }\n\n // 保存 base64 数据到文件\n await this._saveBase64ToFile(base64Info.data, cachePath.filePath);\n\n // 获取文件大小\n const stats = await fs.promises.stat(cachePath.filePath);\n return {\n ...cachePath,\n mimeType,\n size: stats.size\n };\n }\n\n // 处理普通 URL\n const shouldCache = ignoreOrigin ? () => true : this._getMatchFunction();\n const isAllowedOrigin = ignoreOrigin ? () => true : this._getOriginAllowFunction();\n\n // 检查是否匹配缓存规则\n if (!shouldCache(url)) {\n throw new Error(`URL 不匹配缓存规则: ${url}`);\n }\n\n // 检查来源是否允许\n if (!isAllowedOrigin(url)) {\n throw new Error(`URL 来源不允许缓存: ${url}`);\n }\n\n // 获取缓存路径\n const cachePath = this.getCachedPath(url);\n\n // 从文件扩展名获取 MIME 类型\n const ext = path.extname(cachePath.filePath).replace(/^\\./, '') || DEFAULT_EXT.replace(/^\\./, '');\n const mimeType = this._getMimeTypeFromExt(ext);\n\n // 如果缓存有效且不强制重新下载,直接返回\n if (!force && await this.isCacheValidAsync(cachePath.filePath)) {\n const stats = await fs.promises.stat(cachePath.filePath);\n return {\n ...cachePath,\n mimeType,\n size: stats.size\n };\n }\n\n // 下载资源\n await this.downloadResourceAsync(url, cachePath.filePath, 0, onDownloadProgress);\n\n // 获取文件大小\n const stats = await fs.promises.stat(cachePath.filePath);\n return {\n ...cachePath,\n mimeType,\n size: stats.size\n };\n }\n\n /**\n * 批量缓存多个 URL 的资源\n * @param urls 要缓存的资源 URL 数组\n * @param force 是否强制重新下载,即使缓存有效(默认 false)\n * @param ignoreOrigin 是否忽略来源检查(默认 false)\n * @param onProgress 进度回调函数(可选)\n * @returns Promise<Array<{ url: string, success: boolean, filePath?: string, hostPath?: string, mimeType?: string, size?: number, error?: string }>> 返回每个 URL 的缓存结果\n */\n public async addCacheUrls(\n urls: string[],\n force: boolean = false,\n ignoreOrigin: boolean = false,\n onProgress?: CacheProgressCallback\n ): Promise<Array<{ url: string, success: boolean, filePath?: string, hostPath?: string, mimeType?: string, size?: number, error?: string }>> {\n const total = urls.length;\n const results: Array<{ url: string, success: boolean, filePath?: string, hostPath?: string, mimeType?: string, size?: number, error?: string }> = [];\n let completed = 0;\n\n // 存储每个 URL 的下载进度\n const downloadProgressMap = new Map<string, { downloaded: number; total: number; percentage: number; speed: number }>();\n\n // 进度回调的包装函数,确保线程安全\n const reportProgress = (url: string, success: boolean, result?: { filePath?: string; hostPath?: string; mimeType?: string; size?: number; error?: string }) => {\n if (onProgress) {\n completed++;\n const downloadProgress = downloadProgressMap.get(url);\n onProgress({\n current: completed,\n total,\n url,\n success,\n result,\n percentage: Math.round((completed / total) * 100),\n downloadProgress: downloadProgress ? {\n downloaded: downloadProgress.downloaded,\n total: downloadProgress.total,\n percentage: downloadProgress.percentage,\n speed: downloadProgress.speed\n } : undefined\n });\n }\n };\n\n // 并行处理所有 URL,但跟踪每个的完成状态\n const promises = urls.map(async (url, index) => {\n // 为每个 URL 创建下载进度回调\n const onDownloadProgress: DownloadProgressCallback | undefined = onProgress\n ? (progress) => {\n // 更新下载进度\n downloadProgressMap.set(url, {\n downloaded: progress.downloaded,\n total: progress.total,\n percentage: progress.percentage,\n speed: progress.speed\n });\n // 实时报告下载进度(不增加 completed 计数)\n if (onProgress) {\n onProgress({\n current: completed,\n total,\n url,\n success: true, // 下载中视为进行中\n result: undefined,\n percentage: Math.round((completed / total) * 100),\n downloadProgress: {\n downloaded: progress.downloaded,\n total: progress.total,\n percentage: progress.percentage,\n speed: progress.speed\n }\n });\n }\n }\n : undefined;\n\n try {\n const result = await this.cacheUrl(url, force, ignoreOrigin, onDownloadProgress);\n const item = {\n url,\n success: true,\n filePath: result.filePath,\n hostPath: result.hostPath,\n mimeType: result.mimeType,\n size: result.size\n };\n results[index] = item;\n\n // 清除下载进度(已完成)\n downloadProgressMap.delete(url);\n\n // 调用进度回调\n reportProgress(url, true, {\n filePath: result.filePath,\n hostPath: result.hostPath,\n mimeType: result.mimeType,\n size: result.size\n });\n\n return item;\n } catch (error) {\n const item = {\n url,\n success: false,\n error: error instanceof Error ? error.message : '未知错误'\n };\n results[index] = item;\n\n // 清除下载进度(失败)\n downloadProgressMap.delete(url);\n\n // 调用进度回调\n reportProgress(url, false, {\n error: item.error\n });\n\n return item;\n }\n });\n\n // 等待所有请求完成\n await Promise.allSettled(promises);\n\n return results;\n }\n\n /**\n * 删除多个 URL 的资源\n * @param urls 要删除的资源 URL 数组\n * @returns Promise<Array<{ url: string, success: boolean, error?: string }>> 返回每个 URL 的删除结果\n */\n public async deleteCacheUrls(urls: string[]): Promise<Array<{ url: string, success: boolean, error?: string }>> {\n const results = await Promise.allSettled(\n urls.map(url => this.deleteUrl(url))\n );\n return results.map((result, index) => {\n const url = urls[index] || '';\n if (result.status === 'fulfilled') {\n return { url, success: true };\n } else {\n return { url, success: false, error: result.reason?.message || '未知错误' };\n }\n });\n }\n\n /**\n * 获取单个 URL 的缓存信息\n * @param url 资源 URL\n * @returns Promise<{ url: string, exists: boolean, valid?: boolean, filePath?: string, hostPath?: string, mimeType?: string, size?: number, error?: string }> 返回缓存信息\n */\n public async getCacheUrl(url: string): Promise<{\n url: string;\n exists: boolean;\n valid?: boolean;\n filePath?: string;\n hostPath?: string;\n mimeType?: string;\n size?: number;\n error?: string;\n }> {\n try {\n const cachePath = this.getCachedPath(url);\n const exists = fs.existsSync(cachePath.filePath);\n\n if (!exists) {\n return { url, exists: false };\n }\n\n // 检查缓存是否有效\n const valid = await this.isCacheValidAsync(cachePath.filePath);\n\n // 获取文件信息\n const stats = await fs.promises.stat(cachePath.filePath);\n\n // 从文件扩展名获取 MIME 类型\n const ext = path.extname(cachePath.filePath).replace(/^\\./, '') || DEFAULT_EXT.replace(/^\\./, '');\n const mimeType = this._getMimeTypeFromExt(ext);\n\n return {\n url,\n exists: true,\n valid,\n filePath: cachePath.filePath,\n hostPath: cachePath.hostPath,\n mimeType,\n size: stats.size\n };\n } catch (error) {\n return {\n url,\n exists: false,\n error: error instanceof Error ? error.message : '未知错误'\n };\n }\n }\n\n /**\n * 获取多个 URL 的缓存信息\n * @param urls 资源 URL 数组\n * @returns Promise<Array<{ url: string, exists: boolean, valid?: boolean, filePath?: string, hostPath?: string, mimeType?: string, size?: number, error?: string }>> 返回每个 URL 的缓存信息\n */\n public async getCacheUrls(urls: string[]): Promise<Array<{\n url: string;\n exists: boolean;\n valid?: boolean;\n filePath?: string;\n hostPath?: string;\n mimeType?: string;\n size?: number;\n error?: string;\n }>> {\n const results = await Promise.allSettled(\n urls.map(url => this.getCacheUrl(url))\n );\n return results.map((result, index) => {\n const url = urls[index] || '';\n if (result.status === 'fulfilled') {\n return result.value;\n } else {\n return {\n url,\n exists: false,\n error: result.reason?.message || '未知错误'\n };\n }\n });\n }\n\n /**\n * 删除单个 URL 的资源(异步版本,性能更好)\n * @param url 要删除的资源 URL\n * @returns Promise<{ url: string, success: boolean, error?: string }> 返回删除结果\n */\n public async deleteUrl(url: string): Promise<{ url: string, success: boolean, error?: string }> {\n try {\n const cachePath = this.getCachedPath(url);\n try {\n await fs.promises.unlink(cachePath.filePath);\n return { url, success: true };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return { url, success: false, error: '文件不存在' };\n }\n throw error;\n }\n } catch (error) {\n return {\n url,\n success: false,\n error: error instanceof Error ? error.message : '未知错误'\n };\n }\n }\n\n /**\n * 删除单个 URL 的资源(别名,保持向后兼容)\n * @deprecated 使用 deleteUrl 代替\n */\n public async deleteCache(url: string): Promise<{ url: string, success: boolean, error?: string }> {\n return this.deleteUrl(url);\n }\n\n /**\n * 清理过期缓存文件(异步并行处理,性能更好)\n */\n private async _cleanOldCache(): Promise<void> {\n try {\n const files = await fs.promises.readdir(this.options.cacheDir);\n if (files.length === 0) return;\n\n const now = Date.now();\n // 并行处理,提升性能\n await Promise.allSettled(\n files.map(async (file) => {\n const fullPath = path.join(this.options.cacheDir, file);\n try {\n const stat = await fs.promises.stat(fullPath);\n if (now - stat.mtimeMs > this.options.cacheTTL) {\n await fs.promises.unlink(fullPath);\n }\n } catch {\n // 忽略单个文件异常\n }\n })\n );\n } catch (error) {\n // 忽略目录读取错误\n console.log('清理过期缓存时发生错误:', error);\n }\n }\n\n /**\n * 清理所有缓存文件(完全异步版本,性能更好)\n * @returns Promise<{ success: number, failed: number, totalSize: number }> 返回清理统计信息\n */\n public async clearCache(): Promise<{ success: number, failed: number, totalSize: number }> {\n try {\n const files = await fs.promises.readdir(this.options.cacheDir);\n if (files.length === 0) {\n return { success: 0, failed: 0, totalSize: 0 };\n }\n\n // 并行获取所有文件信息(避免并行时的竞态条件)\n const fileInfos = await Promise.allSettled(\n files.map(async (file) => {\n const filePath = path.join(this.options.cacheDir, file);\n try {\n const stats = await fs.promises.stat(filePath);\n return { file, filePath, size: stats.size };\n } catch (error) {\n return { file, filePath, size: 0, error };\n }\n })\n );\n\n const validInfos = fileInfos\n .filter((r): r is PromiseFulfilledResult<{ file: string; filePath: string; size: number; error?: any }> => r.status === 'fulfilled')\n .map(r => r.value);\n\n // 计算总大小\n const totalSize = validInfos.reduce((sum, info) => sum + info.size, 0);\n\n // 并行删除文件,提升性能\n const deleteResults = await Promise.allSettled(\n validInfos.map(async (info) => {\n try {\n await fs.promises.unlink(info.filePath);\n return { success: true, file: info.file };\n } catch (error) {\n throw error;\n }\n })\n );\n\n // 统计成功和失败数量\n const success = deleteResults.filter(r => r.status === 'fulfilled').length;\n const failed = deleteResults.filter(r => r.status === 'rejected').length;\n\n return { success, failed, totalSize };\n } catch (error) {\n console.log('清理缓存时发生错误:', error);\n throw error;\n }\n }\n\n /**\n * 注册 Electron 请求拦截器,实现资源缓存\n */\n private _registerInterceptor(): void {\n const shouldCache = this._getMatchFunction();\n const isAllowedOrigin = this._getOriginAllowFunction();\n\n this.session.webRequest.onBeforeRequest(\n { urls: ['http://*/*', 'https://*/*'] },\n (details: Electron.OnBeforeRequestListenerDetails, callback: (response: Electron.CallbackResponse) => void) => {\n const url = details.url;\n // 不匹配或来源不允许,直接放行\n if (details.method !== 'GET' || !shouldCache(url) || !isAllowedOrigin(url)) return callback({});\n\n const cachePath = this.getCachedPath(url);\n\n // 命中缓存,直接重定向到本地文件\n if (this.isCacheValid(cachePath.filePath)) {\n return callback({ redirectURL: cachePath.hostPath});\n }\n // 未命中则异步下载,当前请求正常放行\n this.downloadResource(url, cachePath.filePath);\n return callback({});\n }\n );\n }\n}\n\n"],"names":["ipcMain","DownloaderHelper"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ShortcutData {
|
|
2
|
+
accelerator: string;
|
|
3
|
+
registered: boolean;
|
|
4
|
+
}
|
|
5
|
+
export interface ShortcutQuery {
|
|
6
|
+
method: 'register' | 'unregister' | 'unregisterAll' | 'isRegistered' | 'getAll';
|
|
7
|
+
accelerator?: string;
|
|
8
|
+
callback?: () => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 初始化快捷键 IPC 处理器
|
|
12
|
+
*/
|
|
13
|
+
export declare const initializeShortcut: () => void;
|
|
14
|
+
//# sourceMappingURL=shortcut.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shortcut.d.ts","sourceRoot":"","sources":["../src/main/shortcut.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,eAAe,GAAG,cAAc,GAAG,QAAQ,CAAC;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAiKD;;GAEG;AACH,eAAO,MAAM,kBAAkB,YA0C9B,CAAC"}
|
package/main/shortcut.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
const electron = require('electron');
|
|
2
|
+
const ipc = require('@lynker-desktop/electron-ipc/main');
|
|
3
|
+
|
|
4
|
+
// 存储已注册的快捷键及其回调函数
|
|
5
|
+
const registeredShortcuts = new Map();
|
|
6
|
+
/**
|
|
7
|
+
* 安全执行快捷键操作(统一错误处理)
|
|
8
|
+
*/
|
|
9
|
+
function safeShortcutOperation(operation, defaultValue, errorMessage) {
|
|
10
|
+
try {
|
|
11
|
+
return operation();
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
console.error(errorMessage, error);
|
|
15
|
+
return defaultValue;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 验证快捷键格式
|
|
20
|
+
*/
|
|
21
|
+
function isValidAccelerator(accelerator) {
|
|
22
|
+
if (!accelerator || typeof accelerator !== 'string') {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const trimmed = accelerator.trim();
|
|
26
|
+
if (trimmed.length === 0) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
// Electron 的 accelerator 格式验证
|
|
30
|
+
// 基本格式:CommandOrControl+X, Alt+Shift+X 等
|
|
31
|
+
// 这里只做基本检查,实际验证由 Electron 的 globalShortcut 处理
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 注册全局快捷键
|
|
36
|
+
*/
|
|
37
|
+
function handleRegister(accelerator, callback) {
|
|
38
|
+
if (!isValidAccelerator(accelerator)) {
|
|
39
|
+
console.error('无效的快捷键格式:', accelerator);
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
// 如果已经注册,先注销
|
|
43
|
+
if (registeredShortcuts.has(accelerator)) {
|
|
44
|
+
handleUnregister(accelerator);
|
|
45
|
+
}
|
|
46
|
+
return safeShortcutOperation(() => {
|
|
47
|
+
const success = electron.globalShortcut.register(accelerator, () => {
|
|
48
|
+
// 如果提供了回调函数,执行它
|
|
49
|
+
if (callback) {
|
|
50
|
+
try {
|
|
51
|
+
callback();
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error('快捷键回调执行失败:', error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// 通知所有渲染进程快捷键被触发
|
|
58
|
+
ipc.mainIPC.invokeAllRenderer('core:shortcut:triggered', { accelerator });
|
|
59
|
+
});
|
|
60
|
+
if (success) {
|
|
61
|
+
// 存储回调函数(如果有)
|
|
62
|
+
if (callback) {
|
|
63
|
+
registeredShortcuts.set(accelerator, callback);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
registeredShortcuts.set(accelerator, () => { });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.error('注册快捷键失败,可能已被其他应用占用:', accelerator);
|
|
71
|
+
}
|
|
72
|
+
return success;
|
|
73
|
+
}, false, '注册快捷键失败:');
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 注销单个全局快捷键
|
|
77
|
+
*/
|
|
78
|
+
function handleUnregister(accelerator) {
|
|
79
|
+
if (!isValidAccelerator(accelerator)) {
|
|
80
|
+
console.error('无效的快捷键格式:', accelerator);
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return safeShortcutOperation(() => {
|
|
84
|
+
// 检查是否已注册
|
|
85
|
+
const wasRegistered = registeredShortcuts.has(accelerator);
|
|
86
|
+
if (wasRegistered) {
|
|
87
|
+
electron.globalShortcut.unregister(accelerator);
|
|
88
|
+
registeredShortcuts.delete(accelerator);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
}, false, '注销快捷键失败:');
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 注销所有全局快捷键
|
|
96
|
+
*/
|
|
97
|
+
function handleUnregisterAll() {
|
|
98
|
+
return safeShortcutOperation(() => {
|
|
99
|
+
electron.globalShortcut.unregisterAll();
|
|
100
|
+
registeredShortcuts.clear();
|
|
101
|
+
return true;
|
|
102
|
+
}, false, '注销所有快捷键失败:');
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 检查快捷键是否已注册
|
|
106
|
+
*/
|
|
107
|
+
function handleIsRegistered(accelerator) {
|
|
108
|
+
if (!isValidAccelerator(accelerator)) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
return safeShortcutOperation(() => {
|
|
112
|
+
return electron.globalShortcut.isRegistered(accelerator);
|
|
113
|
+
}, false, '检查快捷键注册状态失败:');
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 获取所有已注册的快捷键
|
|
117
|
+
*/
|
|
118
|
+
function handleGetAll() {
|
|
119
|
+
return safeShortcutOperation(() => {
|
|
120
|
+
const shortcuts = [];
|
|
121
|
+
registeredShortcuts.forEach((_, accelerator) => {
|
|
122
|
+
shortcuts.push({
|
|
123
|
+
accelerator,
|
|
124
|
+
registered: electron.globalShortcut.isRegistered(accelerator),
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
return shortcuts;
|
|
128
|
+
}, [], '获取所有快捷键失败:');
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* 初始化快捷键 IPC 处理器
|
|
132
|
+
*/
|
|
133
|
+
const initializeShortcut = () => {
|
|
134
|
+
ipc.mainIPC.handleRenderer('core:shortcut', async (options) => {
|
|
135
|
+
const { method, accelerator, callback } = options;
|
|
136
|
+
try {
|
|
137
|
+
switch (method) {
|
|
138
|
+
case 'register':
|
|
139
|
+
if (!accelerator) {
|
|
140
|
+
console.error('注册快捷键需要提供 accelerator');
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
return handleRegister(accelerator, callback);
|
|
144
|
+
case 'unregister':
|
|
145
|
+
if (!accelerator) {
|
|
146
|
+
console.error('注销快捷键需要提供 accelerator');
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
return handleUnregister(accelerator);
|
|
150
|
+
case 'unregisterAll':
|
|
151
|
+
return handleUnregisterAll();
|
|
152
|
+
case 'isRegistered':
|
|
153
|
+
if (!accelerator) {
|
|
154
|
+
console.error('检查快捷键需要提供 accelerator');
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return handleIsRegistered(accelerator);
|
|
158
|
+
case 'getAll':
|
|
159
|
+
return handleGetAll();
|
|
160
|
+
default:
|
|
161
|
+
console.error('未知的快捷键操作方法:', method);
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
console.error('快捷键操作失败:', error);
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
exports.initializeShortcut = initializeShortcut;
|
|
173
|
+
//# sourceMappingURL=shortcut.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shortcut.js","sources":["../src/src/main/shortcut.ts"],"sourcesContent":["import { globalShortcut } from 'electron';\nimport ipc from '@lynker-desktop/electron-ipc/main';\n\n// 存储已注册的快捷键及其回调函数\nconst registeredShortcuts = new Map<string, () => void>();\n\nexport interface ShortcutData {\n accelerator: string;\n registered: boolean;\n}\n\nexport interface ShortcutQuery {\n method: 'register' | 'unregister' | 'unregisterAll' | 'isRegistered' | 'getAll';\n accelerator?: string;\n callback?: () => void;\n}\n\n/**\n * 安全执行快捷键操作(统一错误处理)\n */\nfunction safeShortcutOperation<T>(\n operation: () => T,\n defaultValue: T,\n errorMessage: string\n): T {\n try {\n return operation();\n } catch (error) {\n console.error(errorMessage, error);\n return defaultValue;\n }\n}\n\n/**\n * 验证快捷键格式\n */\nfunction isValidAccelerator(accelerator: string): boolean {\n if (!accelerator || typeof accelerator !== 'string') {\n return false;\n }\n\n const trimmed = accelerator.trim();\n if (trimmed.length === 0) {\n return false;\n }\n\n // Electron 的 accelerator 格式验证\n // 基本格式:CommandOrControl+X, Alt+Shift+X 等\n // 这里只做基本检查,实际验证由 Electron 的 globalShortcut 处理\n return true;\n}\n\n/**\n * 注册全局快捷键\n */\nfunction handleRegister(accelerator: string, callback?: () => void): boolean {\n if (!isValidAccelerator(accelerator)) {\n console.error('无效的快捷键格式:', accelerator);\n return false;\n }\n\n // 如果已经注册,先注销\n if (registeredShortcuts.has(accelerator)) {\n handleUnregister(accelerator);\n }\n\n return safeShortcutOperation(\n () => {\n const success = globalShortcut.register(accelerator, () => {\n // 如果提供了回调函数,执行它\n if (callback) {\n try {\n callback();\n } catch (error) {\n console.error('快捷键回调执行失败:', error);\n }\n }\n // 通知所有渲染进程快捷键被触发\n ipc.mainIPC.invokeAllRenderer('core:shortcut:triggered', { accelerator });\n });\n\n if (success) {\n // 存储回调函数(如果有)\n if (callback) {\n registeredShortcuts.set(accelerator, callback);\n } else {\n registeredShortcuts.set(accelerator, () => {});\n }\n } else {\n console.error('注册快捷键失败,可能已被其他应用占用:', accelerator);\n }\n\n return success;\n },\n false,\n '注册快捷键失败:'\n );\n}\n\n/**\n * 注销单个全局快捷键\n */\nfunction handleUnregister(accelerator: string): boolean {\n if (!isValidAccelerator(accelerator)) {\n console.error('无效的快捷键格式:', accelerator);\n return false;\n }\n\n return safeShortcutOperation(\n () => {\n // 检查是否已注册\n const wasRegistered = registeredShortcuts.has(accelerator);\n if (wasRegistered) {\n globalShortcut.unregister(accelerator);\n registeredShortcuts.delete(accelerator);\n return true;\n }\n return false;\n },\n false,\n '注销快捷键失败:'\n );\n}\n\n/**\n * 注销所有全局快捷键\n */\nfunction handleUnregisterAll(): boolean {\n return safeShortcutOperation(\n () => {\n globalShortcut.unregisterAll();\n registeredShortcuts.clear();\n return true;\n },\n false,\n '注销所有快捷键失败:'\n );\n}\n\n/**\n * 检查快捷键是否已注册\n */\nfunction handleIsRegistered(accelerator: string): boolean {\n if (!isValidAccelerator(accelerator)) {\n return false;\n }\n\n return safeShortcutOperation(\n () => {\n return globalShortcut.isRegistered(accelerator);\n },\n false,\n '检查快捷键注册状态失败:'\n );\n}\n\n/**\n * 获取所有已注册的快捷键\n */\nfunction handleGetAll(): ShortcutData[] {\n return safeShortcutOperation(\n () => {\n const shortcuts: ShortcutData[] = [];\n registeredShortcuts.forEach((_, accelerator) => {\n shortcuts.push({\n accelerator,\n registered: globalShortcut.isRegistered(accelerator),\n });\n });\n return shortcuts;\n },\n [],\n '获取所有快捷键失败:'\n );\n}\n\n/**\n * 初始化快捷键 IPC 处理器\n */\nexport const initializeShortcut = () => {\n ipc.mainIPC.handleRenderer('core:shortcut', async (options: ShortcutQuery): Promise<ShortcutData[] | boolean> => {\n const { method, accelerator, callback } = options;\n\n try {\n switch (method) {\n case 'register':\n if (!accelerator) {\n console.error('注册快捷键需要提供 accelerator');\n return false;\n }\n return handleRegister(accelerator, callback);\n\n case 'unregister':\n if (!accelerator) {\n console.error('注销快捷键需要提供 accelerator');\n return false;\n }\n return handleUnregister(accelerator);\n\n case 'unregisterAll':\n return handleUnregisterAll();\n\n case 'isRegistered':\n if (!accelerator) {\n console.error('检查快捷键需要提供 accelerator');\n return false;\n }\n return handleIsRegistered(accelerator);\n\n case 'getAll':\n return handleGetAll();\n\n default:\n console.error('未知的快捷键操作方法:', method);\n return false;\n }\n } catch (error) {\n console.error('快捷键操作失败:', error);\n return false;\n }\n });\n};\n\n"],"names":["globalShortcut"],"mappings":"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"}
|
package/main/store.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const _appStore: Map<string, any>;
|
|
2
|
+
export interface EStoreQuery {
|
|
3
|
+
name?: string;
|
|
4
|
+
method: 'get' | 'set' | 'delete' | 'clear' | 'has' | 'store';
|
|
5
|
+
key?: string;
|
|
6
|
+
value?: any;
|
|
7
|
+
}
|
|
8
|
+
export declare const initializeStore: () => void;
|
|
9
|
+
export declare const getAppStore: (name: string) => any;
|
|
10
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/main/store.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAa,CAAC;AAErD,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;IAC7D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AA2BD,eAAO,MAAM,eAAe,YAsB3B,CAAA;AAED,eAAO,MAAM,WAAW,SAAU,MAAM,QAEvC,CAAA"}
|
package/main/store.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const ElectronStore = require('electron-store');
|
|
2
|
+
const ipc = require('@lynker-desktop/electron-ipc/main');
|
|
3
|
+
|
|
4
|
+
const _appStore = new Map();
|
|
5
|
+
/**
|
|
6
|
+
* 确保 store 存在并已初始化,如果不存在则创建
|
|
7
|
+
*/
|
|
8
|
+
function ensureStore(name) {
|
|
9
|
+
if (!_appStore.has(name) || typeof _appStore.get(name)?.set !== 'function') {
|
|
10
|
+
const Store = ElectronStore;
|
|
11
|
+
_appStore.set(name, new Store({
|
|
12
|
+
name,
|
|
13
|
+
accessPropertiesByDotNotation: true,
|
|
14
|
+
}));
|
|
15
|
+
_appStore.get(name).onDidAnyChange((newValue, oldValue) => {
|
|
16
|
+
try {
|
|
17
|
+
ipc.mainIPC.invokeAllRenderer('core:estore:didAnyChange', {
|
|
18
|
+
name,
|
|
19
|
+
newValue: newValue ? JSON.stringify(newValue) : undefined,
|
|
20
|
+
oldValue: oldValue ? JSON.stringify(oldValue) : undefined,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.error('core:estore:didAnyChange', error);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return _appStore.get(name);
|
|
29
|
+
}
|
|
30
|
+
const initializeStore = () => {
|
|
31
|
+
ipc.mainIPC.handleRenderer('core:estore', async (options) => {
|
|
32
|
+
const { name = 'appStore', method, key, value } = options;
|
|
33
|
+
const appStore = ensureStore(name);
|
|
34
|
+
if (method === 'get') {
|
|
35
|
+
return appStore.get(key);
|
|
36
|
+
}
|
|
37
|
+
else if (method === 'set') {
|
|
38
|
+
appStore.set(key, value);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
else if (method === 'delete') {
|
|
42
|
+
appStore.delete(key);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
else if (method === 'clear') {
|
|
46
|
+
appStore.clear();
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
else if (method === 'has') {
|
|
50
|
+
return appStore.has(key);
|
|
51
|
+
}
|
|
52
|
+
else if (method === 'store') {
|
|
53
|
+
return appStore.store;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const getAppStore = (name) => {
|
|
58
|
+
return ensureStore(name);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
exports._appStore = _appStore;
|
|
62
|
+
exports.getAppStore = getAppStore;
|
|
63
|
+
exports.initializeStore = initializeStore;
|
|
64
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sources":["../src/src/main/store.ts"],"sourcesContent":["import ElectronStore from 'electron-store';\nimport ipc from '@lynker-desktop/electron-ipc/main';\n\nexport const _appStore: Map<string, any> = new Map();\n\nexport interface EStoreQuery {\n name?: string;\n method: 'get' | 'set' | 'delete' | 'clear' | 'has' | 'store';\n key?: string;\n value?: any;\n};\n\n/**\n * 确保 store 存在并已初始化,如果不存在则创建\n */\nfunction ensureStore(name: string) {\n if (!_appStore.has(name) || typeof _appStore.get(name)?.set !== 'function') {\n const Store = ElectronStore;\n _appStore.set(name, new Store({\n name,\n accessPropertiesByDotNotation: true,\n }));\n _appStore.get(name).onDidAnyChange((newValue: any, oldValue: any) => {\n try {\n ipc.mainIPC.invokeAllRenderer('core:estore:didAnyChange', {\n name,\n newValue: newValue ? JSON.stringify(newValue) : undefined,\n oldValue: oldValue ? JSON.stringify(oldValue) : undefined,\n });\n } catch (error) {\n console.error('core:estore:didAnyChange', error);\n }\n });\n }\n return _appStore.get(name);\n}\n\nexport const initializeStore = () => {\n ipc.mainIPC.handleRenderer('core:estore', async (options: EStoreQuery) => {\n const { name = 'appStore', method, key, value } = options;\n const appStore = ensureStore(name);\n\n if (method === 'get') {\n return appStore.get(key);\n } else if (method === 'set') {\n appStore.set(key, value);\n return true;\n } else if (method === 'delete') {\n appStore.delete(key);\n return true;\n } else if (method === 'clear') {\n appStore.clear();\n return true;\n } else if (method === 'has') {\n return appStore.has(key);\n } else if (method === 'store') {\n return appStore.store;\n }\n })\n}\n\nexport const getAppStore = (name: string) => {\n return ensureStore(name);\n}\n"],"names":[],"mappings":";;;AAGa,MAAA,SAAS,GAAqB,IAAI,GAAG,GAAG;AASrD;;AAEG;AACH,SAAS,WAAW,CAAC,IAAY,EAAA;IAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,UAAU,EAAE;QAC1E,MAAM,KAAK,GAAG,aAAa,CAAC;AAC5B,QAAA,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC;YAC5B,IAAI;AACJ,YAAA,6BAA6B,EAAE,IAAI;AACpC,SAAA,CAAC,CAAC,CAAC;AACJ,QAAA,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,CAAC,QAAa,EAAE,QAAa,KAAI;AAClE,YAAA,IAAI;AACF,gBAAA,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,0BAA0B,EAAE;oBACxD,IAAI;AACJ,oBAAA,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,SAAS;AACzD,oBAAA,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,SAAS;AAC1D,iBAAA,CAAC,CAAC;aACJ;YAAC,OAAO,KAAK,EAAE;AACd,gBAAA,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;aAClD;AACH,SAAC,CAAC,CAAC;KACJ;AACD,IAAA,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAEM,MAAM,eAAe,GAAG,MAAK;IAClC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,aAAa,EAAE,OAAO,OAAoB,KAAI;AACvE,QAAA,MAAM,EAAE,IAAI,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;AAC1D,QAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;AAEnC,QAAA,IAAI,MAAM,KAAK,KAAK,EAAE;AACpB,YAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SAC1B;AAAM,aAAA,IAAI,MAAM,KAAK,KAAK,EAAE;AAC3B,YAAA,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACzB,YAAA,OAAO,IAAI,CAAC;SACb;AAAM,aAAA,IAAI,MAAM,KAAK,QAAQ,EAAE;AAC9B,YAAA,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,YAAA,OAAO,IAAI,CAAC;SACb;AAAM,aAAA,IAAI,MAAM,KAAK,OAAO,EAAE;YAC7B,QAAQ,CAAC,KAAK,EAAE,CAAC;AACjB,YAAA,OAAO,IAAI,CAAC;SACb;AAAM,aAAA,IAAI,MAAM,KAAK,KAAK,EAAE;AAC3B,YAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SAC1B;AAAM,aAAA,IAAI,MAAM,KAAK,OAAO,EAAE;YAC7B,OAAO,QAAQ,CAAC,KAAK,CAAC;SACvB;AACH,KAAC,CAAC,CAAA;AACJ,EAAC;AAEY,MAAA,WAAW,GAAG,CAAC,IAAY,KAAI;AAC1C,IAAA,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAC3B;;;;;;"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { VideoDownloadOptions, VideoProgressCallback, VideoDownloadResult } from '../common';
|
|
2
|
+
/**
|
|
3
|
+
* 生成跨平台的文件URL
|
|
4
|
+
* @param filePath 文件路径
|
|
5
|
+
* @returns file:// URL
|
|
6
|
+
*/
|
|
7
|
+
export declare function getFileUrl(filePath: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* 下载视频并转码
|
|
10
|
+
* @param options 下载和转码选项
|
|
11
|
+
* @param callbacks 进度回调
|
|
12
|
+
* @returns 转码结果
|
|
13
|
+
*/
|
|
14
|
+
export declare const downloadVideo: (options: VideoDownloadOptions, callbacks?: VideoProgressCallback) => Promise<VideoDownloadResult>;
|
|
15
|
+
/**
|
|
16
|
+
* 清除指定目录的所有缓存文件
|
|
17
|
+
*/
|
|
18
|
+
export declare const clearVideoCache: (outputDir: string) => void;
|
|
19
|
+
/**
|
|
20
|
+
* 获取缓存统计信息
|
|
21
|
+
*/
|
|
22
|
+
export declare const getVideoCacheStats: (outputDir: string) => {
|
|
23
|
+
size: number;
|
|
24
|
+
entries: Array<{
|
|
25
|
+
fileName: string;
|
|
26
|
+
filePath: string;
|
|
27
|
+
fileSize: number;
|
|
28
|
+
mtime: number;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* 删除指定URL的缓存文件
|
|
33
|
+
*/
|
|
34
|
+
export declare const removeVideoCache: (options: VideoDownloadOptions) => boolean;
|
|
35
|
+
/**
|
|
36
|
+
* 设置FFmpeg路径
|
|
37
|
+
*/
|
|
38
|
+
export declare const setFFmpegPath: (ffmpegPath: string) => void;
|
|
39
|
+
//# sourceMappingURL=video-downloader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-downloader.d.ts","sourceRoot":"","sources":["../src/main/video-downloader.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAElG;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAmBnD;AA4fD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,YACf,oBAAoB,cACjB,qBAAqB,KAChC,OAAO,CAAC,mBAAmB,CAG7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,cAAe,MAAM,KAAG,IAGnD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,cAAe,MAAM,KAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAG7J,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,YAAa,oBAAoB,KAAG,OAGhE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,eAAgB,MAAM,KAAG,IAGlD,CAAC"}
|