fix:优化主进程代码优化

This commit is contained in:
sqj
2025-08-19 21:33:43 +08:00
parent 262848d2e9
commit c4d7681453
18 changed files with 2857 additions and 550 deletions

View File

@@ -1,6 +1,6 @@
{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"

View File

@@ -2,7 +2,7 @@ version: '1.0'
name: pr-pipeline
displayName: PRPipeline
stages:
- stage:
- stage:
name: compile
displayName: 编译
steps:
@@ -16,7 +16,7 @@ stages:
- npm install && rm -rf ./dist && npm run build
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:

View File

@@ -23,7 +23,7 @@ npm install node-fetch
### 基本使用
```javascript
const CeruMusicPluginHost = require('./CeruMusicPluginHost');
const CeruMusicPluginHost = require('./CeruMusicPluginHost')
// 方式1: 从代码字符串创建
const pluginCode = `
@@ -48,26 +48,26 @@ async function musicUrl(source, musicInfo, quality) {
}
module.exports = { pluginInfo, sources, musicUrl };
`;
`
const host = new CeruMusicPluginHost(pluginCode);
const host = new CeruMusicPluginHost(pluginCode)
// 方式2: 从文件加载
const host2 = new CeruMusicPluginHost();
await host2.loadPlugin('./my-plugin.js');
const host2 = new CeruMusicPluginHost()
await host2.loadPlugin('./my-plugin.js')
```
### 获取插件信息
```javascript
// 获取插件基本信息
const info = host.getPluginInfo();
console.log(info);
const info = host.getPluginInfo()
console.log(info)
// 输出: { name: "示例插件", version: "1.0.0", ... }
// 获取支持的音源
const sources = host.getSupportedSources();
console.log(sources);
const sources = host.getSupportedSources()
console.log(sources)
// 输出: { demo: { name: "示例音源", type: "music", ... } }
```
@@ -77,31 +77,31 @@ console.log(sources);
// 获取音乐URL
try {
const musicInfo = {
songmid: "123456",
hash: "abcdef",
title: "歌曲名"
};
const url = await host.getMusicUrl("demo", musicInfo, "320k");
console.log("音乐URL:", url);
songmid: '123456',
hash: 'abcdef',
title: '歌曲名'
}
const url = await host.getMusicUrl('demo', musicInfo, '320k')
console.log('音乐URL:', url)
} catch (error) {
console.error("获取失败:", error.message);
console.error('获取失败:', error.message)
}
// 获取歌曲封面(如果插件支持)
try {
const picUrl = await host.getPic("demo", musicInfo);
console.log("封面URL:", picUrl);
const picUrl = await host.getPic('demo', musicInfo)
console.log('封面URL:', picUrl)
} catch (error) {
console.error("获取封面失败:", error.message);
console.error('获取封面失败:', error.message)
}
// 获取歌词(如果插件支持)
try {
const lyric = await host.getLyric("demo", musicInfo);
console.log("歌词:", lyric);
const lyric = await host.getLyric('demo', musicInfo)
console.log('歌词:', lyric)
} catch (error) {
console.error("获取歌词失败:", error.message);
console.error('获取歌词失败:', error.message)
}
```
@@ -114,6 +114,7 @@ new CeruMusicPluginHost(pluginCode?)
```
**参数:**
- `pluginCode` (string, 可选): 插件的 JavaScript 代码字符串
### 方法
@@ -123,6 +124,7 @@ new CeruMusicPluginHost(pluginCode?)
从文件加载插件。
**参数:**
- `pluginPath` (string): 插件文件路径
**返回:** Promise<Object> - 插件导出的对象
@@ -144,6 +146,7 @@ new CeruMusicPluginHost(pluginCode?)
获取音乐播放链接。
**参数:**
- `source` (string): 音源标识
- `musicInfo` (Object): 歌曲信息对象
- `quality` (string): 音质标识
@@ -155,6 +158,7 @@ new CeruMusicPluginHost(pluginCode?)
获取歌曲封面链接。
**参数:**
- `source` (string): 音源标识
- `musicInfo` (Object): 歌曲信息对象
@@ -165,6 +169,7 @@ new CeruMusicPluginHost(pluginCode?)
获取歌曲歌词。
**参数:**
- `source` (string): 音源标识
- `musicInfo` (Object): 歌曲信息对象
@@ -178,19 +183,19 @@ new CeruMusicPluginHost(pluginCode?)
```javascript
// CeruMusic API
cerumusic.env // 运行环境标识
cerumusic.version // 版本号
cerumusic.request // HTTP 请求函数
cerumusic.utils // 工具函数集合
cerumusic.env // 运行环境标识
cerumusic.version // 版本号
cerumusic.request // HTTP 请求函数
cerumusic.utils // 工具函数集合
// 标准 JavaScript 对象
console // 控制台输出
setTimeout // 定时器
console // 控制台输出
setTimeout // 定时器
clearTimeout
setInterval
clearInterval
Buffer // Node.js Buffer
JSON // JSON 处理
Buffer // Node.js Buffer
JSON // JSON 处理
```
### HTTP 请求
@@ -201,16 +206,16 @@ JSON // JSON 处理
// 支持 callback 模式
cerumusic.request(url, options, (error, response) => {
if (error) {
console.error('请求失败:', error);
return;
console.error('请求失败:', error)
return
}
console.log('响应状态:', response.statusCode);
console.log('响应内容:', response.body);
});
console.log('响应状态:', response.statusCode)
console.log('响应内容:', response.body)
})
// 也支持 Promise 模式
const response = await cerumusic.request(url, options);
const response = await cerumusic.request(url, options)
```
## 错误处理
@@ -218,20 +223,22 @@ const response = await cerumusic.request(url, options);
### 常见错误类型
1. **插件加载错误**
```javascript
try {
const host = new CeruMusicPluginHost(invalidCode);
const host = new CeruMusicPluginHost(invalidCode)
} catch (error) {
console.error('插件加载失败:', error.message);
console.error('插件加载失败:', error.message)
}
```
2. **方法调用错误**
```javascript
try {
const url = await host.getMusicUrl("invalid_source", {}, "320k");
const url = await host.getMusicUrl('invalid_source', {}, '320k')
} catch (error) {
console.error('方法调用失败:', error.message);
console.error('方法调用失败:', error.message)
}
```
@@ -249,6 +256,7 @@ const response = await cerumusic.request(url, options);
## 示例项目
查看项目中的示例文件:
- `example-plugin.js` - 标准插件示例
- `test-converted-plugin.js` - 插件测试示例
@@ -270,4 +278,4 @@ A: 检查插件内部是否有死循环或长时间阻塞的操作
## 版本历史
- v1.0.0: 初始版本,支持基本的插件加载和执行功能
- v1.0.0: 初始版本,支持基本的插件加载和执行功能

View File

@@ -12,10 +12,10 @@
```javascript
module.exports = {
pluginInfo, // 插件信息
sources, // 支持的音源
musicUrl // 获取音乐链接的函数
};
pluginInfo, // 插件信息
sources, // 支持的音源
musicUrl // 获取音乐链接的函数
}
```
# 完整示例
@@ -32,70 +32,70 @@ const pluginInfo = {
name: '示例音源插件',
version: '1.0.0',
author: '开发者名称',
description: '这是一个示例音乐源插件',
};
description: '这是一个示例音乐源插件'
}
// 2. 支持的音源配置
const sources = {
demo: {
name: '示例音源',
type: 'music',
qualitys: ['128k', '320k', 'flac'],
qualitys: ['128k', '320k', 'flac']
},
demo2: {
name: '示例音源2',
type: 'music',
qualitys: ['128k', '320k'],
type: 'music',
qualitys: ['128k', '320k']
}
};
}
// 3. 获取音乐URL的核心函数
async function musicUrl(source, musicInfo, quality) {
// 从 cerumusic 对象获取 API
const { request, env, version } = cerumusic;
const { request, env, version } = cerumusic
// 构建请求参数
const songId = musicInfo.hash ?? musicInfo.songmid;
const apiUrl = `https://api.example.com/music/${source}/${songId}/${quality}`;
console.log(`[${pluginInfo.name}] 请求音乐链接: ${apiUrl}`);
const songId = musicInfo.hash ?? musicInfo.songmid
const apiUrl = `https://api.example.com/music/${source}/${songId}/${quality}`
console.log(`[${pluginInfo.name}] 请求音乐链接: ${apiUrl}`)
// 发起网络请求
const { body, statusCode } = await request(apiUrl, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'User-Agent': `cerumusic-${env}/${version}`,
},
});
'User-Agent': `cerumusic-${env}/${version}`
}
})
// 处理响应
if (statusCode !== 200 || body.code !== 200) {
const errorMessage = body.msg || `接口错误 (HTTP: ${statusCode})`;
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`);
throw new Error(errorMessage);
const errorMessage = body.msg || `接口错误 (HTTP: ${statusCode})`
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`)
throw new Error(errorMessage)
}
console.log(`[${pluginInfo.name}] 获取成功: ${body.url}`);
return body.url;
console.log(`[${pluginInfo.name}] 获取成功: ${body.url}`)
return body.url
}
// 4. 可选:获取封面图片
async function getPic(source, musicInfo) {
const { request } = cerumusic;
const songId = musicInfo.hash ?? musicInfo.songmid;
const { body } = await request(`https://api.example.com/pic/${source}/${songId}`);
return body.picUrl;
const { request } = cerumusic
const songId = musicInfo.hash ?? musicInfo.songmid
const { body } = await request(`https://api.example.com/pic/${source}/${songId}`)
return body.picUrl
}
// 5. 可选:获取歌词
async function getLyric(source, musicInfo) {
const { request } = cerumusic;
const songId = musicInfo.hash ?? musicInfo.songmid;
const { body } = await request(`https://api.example.com/lyric/${source}/${songId}`);
return body.lyric;
const { request } = cerumusic
const songId = musicInfo.hash ?? musicInfo.songmid
const { body } = await request(`https://api.example.com/lyric/${source}/${songId}`)
return body.lyric
}
// 导出插件
@@ -103,9 +103,9 @@ module.exports = {
pluginInfo,
sources,
musicUrl,
getPic, // 可选
getLyric, // 可选
};
getPic, // 可选
getLyric // 可选
}
```
## 详细说明
@@ -116,11 +116,11 @@ module.exports = {
```javascript
const pluginInfo = {
name: '插件名称', // 必需:插件显示名称
version: '1.0.0', // 必需:版本号
author: '作者名', // 必需:作者信息
description: '插件描述', // 必需:功能描述
};
name: '插件名称', // 必需:插件显示名称
version: '1.0.0', // 必需:版本号
author: '作者名', // 必需:作者信息
description: '插件描述' // 必需:功能描述
}
```
### 2. sources 对象
@@ -130,18 +130,19 @@ const pluginInfo = {
```javascript
const sources = {
// 音源标识用于API调用
'source_id': {
name: '音源显示名称', // 必需:用户看到的名称
type: 'music', // 必需:固定为 'music'
qualitys: [ // 必需:支持的音质列表
'128k', // 标准音质
'320k', // 音质
'flac', // 无损音质
'flac24bit', // 24位无损
'hires' // 高解析度
],
source_id: {
name: '音源显示名称', // 必需:用户看到的名称
type: 'music', // 必需:固定为 'music'
qualitys: [
// 必需:支持的音质列表
'128k', // 标准音质
'320k', // 音质
'flac', // 无损音质
'flac24bit', // 24位无损
'hires' // 高解析度
]
}
};
}
```
### 3. musicUrl 函数
@@ -153,7 +154,6 @@ async function musicUrl(source, musicInfo, quality) {
// source: 音源标识sources 对象的键)
// musicInfo: 歌曲信息对象
// quality: 请求的音质
// 返回: Promise<string> - 音乐播放链接
}
```
@@ -162,13 +162,13 @@ async function musicUrl(source, musicInfo, quality) {
```javascript
const musicInfo = {
songmid: '歌曲ID', // 歌曲标识符
hash: '歌曲哈希', // 备用标识符
title: '歌曲标题', // 歌曲名称
artist: '艺术家', // 演唱者
album: '专辑名', // 专辑信息
songmid: '歌曲ID', // 歌曲标识符
hash: '歌曲哈希', // 备用标识符
title: '歌曲标题', // 歌曲名称
artist: '艺术家', // 演唱者
album: '专辑名' // 专辑信息
// ... 其他可能的字段
};
}
```
## 可用 API
@@ -178,7 +178,7 @@ const musicInfo = {
插件运行时可以访问 `cerumusic` 全局对象:
```javascript
const { request, env, version, utils } = cerumusic;
const { request, env, version, utils } = cerumusic
```
#### request 函数
@@ -187,19 +187,20 @@ const { request, env, version, utils } = cerumusic;
```javascript
// Promise 模式
const response = await request(url, options);
const response = await request(url, options)
// Callback 模式
// Callback 模式
request(url, options, (error, response) => {
if (error) {
console.error('请求失败:', error);
return;
console.error('请求失败:', error)
return
}
console.log('响应:', response);
});
console.log('响应:', response)
})
```
**参数说明:**
- `url` (string): 请求地址
- `options` (Object): 请求选项
- `method`: HTTP 方法 ('GET', 'POST', 等)
@@ -207,6 +208,7 @@ request(url, options, (error, response) => {
- `body`: 请求体POST 请求时)
**响应格式:**
```javascript
{
body: {}, // 解析后的响应体
@@ -220,11 +222,11 @@ request(url, options, (error, response) => {
提供实用工具函数:
```javascript
const { utils } = cerumusic;
const { utils } = cerumusic
// Buffer 操作
const buffer = utils.buffer.from('hello', 'utf8');
const string = utils.buffer.bufToString(buffer, 'utf8');
const buffer = utils.buffer.from('hello', 'utf8')
const string = utils.buffer.bufToString(buffer, 'utf8')
```
## 错误处理
@@ -232,26 +234,28 @@ const string = utils.buffer.bufToString(buffer, 'utf8');
### 最佳实践
1. **总是检查 API 响应状态**
```javascript
if (statusCode !== 200 || body.code !== 200) {
throw new Error(`请求失败: ${body.msg || '未知错误'}`);
throw new Error(`请求失败: ${body.msg || '未知错误'}`)
}
```
2. **提供有意义的错误信息**
```javascript
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`);
throw new Error(errorMessage);
console.error(`[${pluginInfo.name}] Error: ${errorMessage}`)
throw new Error(errorMessage)
```
3. **处理网络异常**
```javascript
try {
const response = await request(url, options);
const response = await request(url, options)
// 处理响应
} catch (error) {
console.error(`[${pluginInfo.name}] 网络请求失败:`, error.message);
throw new Error(`网络错误: ${error.message}`);
console.error(`[${pluginInfo.name}] 网络请求失败:`, error.message)
throw new Error(`网络错误: ${error.message}`)
}
```
@@ -279,17 +283,17 @@ node converter-event-driven.js input-plugin.js output-plugin.js
### 1. 使用 console.log
```javascript
console.log(`[${pluginInfo.name}] 调试信息:`, data);
console.error(`[${pluginInfo.name}] 错误:`, error);
console.log(`[${pluginInfo.name}] 调试信息:`, data)
console.error(`[${pluginInfo.name}] 错误:`, error)
```
### 2. 检查请求和响应
```javascript
console.log('请求URL:', url);
console.log('请求选项:', options);
console.log('响应状态:', statusCode);
console.log('响应内容:', body);
console.log('请求URL:', url)
console.log('请求选项:', options)
console.log('响应状态:', statusCode)
console.log('响应内容:', body)
```
### 3. 测试插件
@@ -297,26 +301,26 @@ console.log('响应内容:', body);
创建测试文件:
```javascript
const CeruMusicPluginHost = require('./CeruMusicPluginHost');
const CeruMusicPluginHost = require('./CeruMusicPluginHost')
async function testPlugin() {
const host = new CeruMusicPluginHost();
await host.loadPlugin('./my-plugin.js');
const host = new CeruMusicPluginHost()
await host.loadPlugin('./my-plugin.js')
const musicInfo = {
songmid: 'test123',
title: '测试歌曲'
};
}
try {
const url = await host.getMusicUrl('demo', musicInfo, '320k');
console.log('成功获取URL:', url);
const url = await host.getMusicUrl('demo', musicInfo, '320k')
console.log('成功获取URL:', url)
} catch (error) {
console.error('测试失败:', error.message);
console.error('测试失败:', error.message)
}
}
testPlugin();
testPlugin()
```
## 发布和分发
@@ -334,6 +338,7 @@ my-plugin/
### 版本管理
遵循语义化版本规范:
- `1.0.0` - 主版本.次版本.修订版本
- 主版本:不兼容的 API 修改
- 次版本:向下兼容的功能性新增
@@ -342,6 +347,7 @@ my-plugin/
## 示例插件
查看项目中的示例:
- `example-plugin.js` - 基础插件示例
- `plugin.js` - 事件驱动插件示例
- `fm.js` - 复杂插件示例
@@ -372,4 +378,4 @@ A: 减少不必要的网络请求,使用适当的缓存策略,避免阻塞
4. 提交 Pull Request
5. 等待代码审查
欢迎贡献新的音源插件!
欢迎贡献新的音源插件!

8
package-lock.json generated
View File

@@ -50,7 +50,7 @@
"@types/crypto-js": "^4.2.2",
"@types/node": "^22.16.5",
"@vitejs/plugin-vue": "^6.0.0",
"electron": "^37.2.3",
"electron": "^37.3.1",
"electron-builder": "^25.1.8",
"electron-icon-builder": "^2.0.1",
"electron-vite": "^4.0.0",
@@ -7497,9 +7497,9 @@
}
},
"node_modules/electron": {
"version": "37.3.0",
"resolved": "https://registry.npmmirror.com/electron/-/electron-37.3.0.tgz",
"integrity": "sha512-cPOPUD26DwCh+PZ9q+gMyVBvdBN75SnekI6u5zcOeoLVIXQpzrCm1ewz9BcrkWkVW7oOtfQAEo1G1SffvXrSSw==",
"version": "37.3.1",
"resolved": "https://registry.npmmirror.com/electron/-/electron-37.3.1.tgz",
"integrity": "sha512-7DhktRLqhe6OJh/Bo75bTI0puUYEmIwSzMinocgO63mx3MVjtIn2tYMzLmAleNIlud2htkjpsMG2zT4PiTCloA==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {

View File

@@ -65,7 +65,7 @@
"@types/crypto-js": "^4.2.2",
"@types/node": "^22.16.5",
"@vitejs/plugin-vue": "^6.0.0",
"electron": "^37.2.3",
"electron": "^37.3.1",
"electron-builder": "^25.1.8",
"electron-icon-builder": "^2.0.1",
"electron-vite": "^4.0.0",

1641
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

71
src/main/events/ai.ts Normal file
View File

@@ -0,0 +1,71 @@
import { AIService } from '../services/ai-service'
import { ipcMain } from 'electron'
// 创建AI服务实例
export default function aiEvents(mainWindow) {
const aiService = new AIService()
// 注册AI服务的IPC处理器
ipcMain.handle('ai-ask', async (_, prompt) => {
try {
return await aiService.askChat(prompt)
} catch (error: any) {
console.error('AI对话失败:', error)
// 返回错误信息给渲染进程
throw {
message: (error as Error).message || 'AI服务暂时不可用',
code: 'AI_SERVICE_ERROR'
}
}
})
// 注册AI流式服务的IPC处理器
ipcMain.handle('ai-ask-stream', async (event, prompt, streamId) => {
try {
const stream = aiService.askChatStream(prompt)
for await (const chunk of stream) {
// 发送流式数据块到渲染进程
event.sender.send('ai-stream-chunk', { streamId, chunk })
}
// 发送流结束信号
event.sender.send('ai-stream-end', { streamId })
return { success: true }
} catch (error: any) {
console.error('AI流式对话失败:', error)
// 发送错误信号,包含更详细的错误信息
const errorMessage = (error as Error).message || 'AI服务暂时不可用'
event.sender.send('ai-stream-error', {
streamId,
error: errorMessage,
code: 'AI_SERVICE_ERROR'
})
throw {
message: errorMessage,
code: 'AI_SERVICE_ERROR'
}
}
})
// 注册获取用户配置的IPC处理器
ipcMain.handle('get-user-config', async () => {
try {
// 从渲染进程的localStorage获取用户配置
const result = await mainWindow?.webContents.executeJavaScript(`
(() => {
try {
const userInfo = localStorage.getItem('userInfo');
return userInfo ? JSON.parse(userInfo) : null;
} catch (error) {
console.error('获取用户配置失败:', error);
return null;
}
})()
`)
return result
} catch (error) {
console.error('获取用户配置失败:', error)
return null
}
})
}

View File

@@ -1,64 +1,19 @@
import { app, shell, BrowserWindow, ipcMain, Tray, Menu } from 'electron'
import { app, shell, BrowserWindow, ipcMain, Tray } from 'electron'
import { is } from '@electron-toolkit/utils'
import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/logo.png?asset'
import path from 'node:path'
import musicService from './services/music'
import pluginService from './services/plugin'
import { AIService } from './services/ai-service'
import useWindow from './window/index'
import aiEvents from './events/ai'
let tray: Tray | null = null
let mainWindow: BrowserWindow | null = null
let isQuitting = false
function createTray(): void {
// 创建系统托盘
const trayIconPath = path.join(__dirname, '../../resources/logo.png')
tray = new Tray(trayIconPath)
// 创建托盘菜单
const contextMenu = Menu.buildFromTemplate([
{
label: '显示窗口',
click: () => {
if (mainWindow) {
mainWindow.show()
mainWindow.focus()
}
}
},
{
label: '播放/暂停',
click: () => {
// 这里可以添加播放控制逻辑
mainWindow?.webContents.send('music-control')
}
},
{ type: 'separator' },
{
label: '退出',
click: () => {
isQuitting = true
app.quit()
}
}
])
tray.setContextMenu(contextMenu)
tray.setToolTip('Ceru Music')
// 双击托盘图标显示窗口
tray.on('click', () => {
if (mainWindow) {
if (mainWindow.isVisible()) {
mainWindow.hide()
} else {
mainWindow.show()
mainWindow.focus()
}
}
})
}
// 使用对象包装布尔值,以便通过引用传递
const isQuittingState = { value: false }
const tray: { value: Tray | null } = { value: null }
function createWindow(): void {
// Create the browser window.
@@ -92,13 +47,13 @@ function createWindow(): void {
// 阻止窗口关闭,改为隐藏到系统托盘
mainWindow.on('close', (event) => {
if (!isQuitting) {
if (!isQuittingState.value) {
event.preventDefault()
mainWindow?.hide()
// 显示托盘通知
if (tray) {
tray.displayBalloon({
if (tray.value) {
tray.value.displayBalloon({
iconType: 'info',
title: 'Ceru Music',
content: '已最小化到系统托盘啦,点击托盘图标可重新打开~'
@@ -138,166 +93,17 @@ ipcMain.handle('service-music-request', async (_, api, args) => {
return await musicService.request(api, args)
})
// 创建AI服务实例
const aiService = new AIService()
// 注册AI服务的IPC处理器
ipcMain.handle('ai-ask', async (_, prompt) => {
try {
return await aiService.askChat(prompt)
} catch (error: any) {
console.error('AI对话失败:', error)
// 返回错误信息给渲染进程
throw {
message: (error as Error).message || 'AI服务暂时不可用',
code: 'AI_SERVICE_ERROR'
}
}
})
// 注册AI流式服务的IPC处理器
ipcMain.handle('ai-ask-stream', async (event, prompt, streamId) => {
try {
const stream = aiService.askChatStream(prompt)
for await (const chunk of stream) {
// 发送流式数据块到渲染进程
event.sender.send('ai-stream-chunk', { streamId, chunk })
}
// 发送流结束信号
event.sender.send('ai-stream-end', { streamId })
return { success: true }
} catch (error: any) {
console.error('AI流式对话失败:', error)
// 发送错误信号,包含更详细的错误信息
const errorMessage = (error as Error).message || 'AI服务暂时不可用'
event.sender.send('ai-stream-error', {
streamId,
error: errorMessage,
code: 'AI_SERVICE_ERROR'
})
throw {
message: errorMessage,
code: 'AI_SERVICE_ERROR'
}
}
})
// 注册获取用户配置的IPC处理器
ipcMain.handle('get-user-config', async () => {
try {
// 从渲染进程的localStorage获取用户配置
const result = await mainWindow?.webContents.executeJavaScript(`
(() => {
try {
const userInfo = localStorage.getItem('userInfo');
return userInfo ? JSON.parse(userInfo) : null;
} catch (error) {
console.error('获取用户配置失败:', error);
return null;
}
})()
`)
return result
} catch (error) {
console.error('获取用户配置失败:', error)
return null
}
})
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
// Set app user model id for windows
electronApp.setAppUserModelId('com.cerulean.music')
// Default open or close DevTools by F12 in development
// and ignore CommandOrControl + R in production.
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
app.on('browser-window-created', (_, window) => {
optimizer.watchWindowShortcuts(window)
})
// IPC test
ipcMain.on('ping', () => console.log('pong'))
// 窗口控制 IPC 处理
ipcMain.on('window-minimize', () => {
const window = BrowserWindow.getFocusedWindow()
if (window) {
window.minimize()
}
})
ipcMain.on('window-maximize', () => {
const window = BrowserWindow.getFocusedWindow()
if (window) {
if (window.isMaximized()) {
window.unmaximize()
} else {
window.maximize()
}
}
})
ipcMain.on('window-close', () => {
const window = BrowserWindow.getFocusedWindow()
if (window) {
window.close()
}
})
// Mini 模式 IPC 处理 - 最小化到系统托盘
ipcMain.on('window-mini-mode', (_, isMini) => {
if (mainWindow) {
if (isMini) {
// 进入 Mini 模式:隐藏窗口到系统托盘
mainWindow.hide()
// 显示托盘通知(可选)
if (tray) {
tray.displayBalloon({
title: '澜音 Music',
content: '已最小化到系统托盘啦,点击托盘图标可重新打开~'
})
}
} else {
// 退出 Mini 模式:显示窗口
mainWindow.show()
mainWindow.focus()
}
}
})
// 全屏模式 IPC 处理
ipcMain.on('window-toggle-fullscreen', () => {
if (mainWindow) {
const isFullScreen = mainWindow.isFullScreen()
mainWindow.setFullScreen(!isFullScreen)
}
})
createWindow()
createTray()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// 当所有窗口关闭时不退出应用,因为我们有系统托盘
app.on('window-all-closed', () => {
// 在 macOS 上,应用通常会保持活跃状态
// 在其他平台上,我们也保持应用运行,因为有系统托盘
})
aiEvents(mainWindow)
// 应用退出前的清理
app.on('before-quit', () => {
isQuitting = true
isQuittingState.value = true
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
// 创建窗口并注册window服务
app.whenReady().then(() => {
// 先创建窗口
createWindow()
// 然后注册window服务确保mainWindow已经创建
useWindow(() => {}, ipcMain, app, mainWindow, isQuittingState, tray)
})

View File

@@ -1,6 +1,6 @@
/* eslint-disable */
const vm = require('vm');
const fetch = require('node-fetch');
const vm = require('vm')
const fetch = require('node-fetch')
/**
* CeruMusic 插件引擎
@@ -11,11 +11,11 @@ class CeruMusicPluginHost {
* @param {string | null} pluginCode 插件的 JavaScript 代码字符串(可选)
* @param {any} logger
*/
constructor(pluginCode = null, logger=console) {
this.pluginCode = pluginCode;
this.plugin = null; // 存储插件导出的对象
constructor(pluginCode = null, logger = console) {
this.pluginCode = pluginCode
this.plugin = null // 存储插件导出的对象
if (pluginCode) {
this._initialize(logger);
this._initialize(logger)
}
}
@@ -24,11 +24,11 @@ class CeruMusicPluginHost {
* @param {string} pluginPath 插件文件路径
* @param {any} logger
*/
async loadPlugin(pluginPath, logger=console) {
const fs = require('fs');
this.pluginCode = fs.readFileSync(pluginPath, 'utf-8');
this._initialize(logger);
return this.plugin;
async loadPlugin(pluginPath, logger = console) {
const fs = require('fs')
this.pluginCode = fs.readFileSync(pluginPath, 'utf-8')
this._initialize(logger)
return this.plugin
}
/**
@@ -43,93 +43,92 @@ class CeruMusicPluginHost {
utils: {
buffer: {
from: (data, encoding) => Buffer.from(data, encoding),
bufToString: (buffer, encoding) => buffer.toString(encoding),
},
bufToString: (buffer, encoding) => buffer.toString(encoding)
}
},
request: (url, options, callback) => {
// 支持 Promise 和 callback 两种调用方式
if (typeof options === 'function') {
callback = options;
options = { method: 'GET' };
callback = options
options = { method: 'GET' }
}
const makeRequest = async () => {
try {
console.log(`[CeruMusic] 发起请求: ${url}`);
console.log(`[CeruMusic] 发起请求: ${url}`)
// 添加超时设置
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 10000) // 10秒超时
const requestOptions = {
method: 'GET',
...options,
signal: controller.signal
};
}
const response = await fetch(url, requestOptions);
clearTimeout(timeoutId);
const response = await fetch(url, requestOptions)
clearTimeout(timeoutId)
console.log(`[CeruMusic] 请求响应状态: ${response.status}`);
console.log(`[CeruMusic] 请求响应状态: ${response.status}`)
// 尝试解析JSON如果失败则返回文本
let body;
const contentType = response.headers.get('content-type');
let body
const contentType = response.headers.get('content-type')
try {
if (contentType && contentType.includes('application/json')) {
body = await response.json();
body = await response.json()
} else {
const text = await response.text();
console.log(`[CeruMusic] 响应不是JSON格式内容: ${text.substring(0, 200)}...`);
const text = await response.text()
console.log(`[CeruMusic] 响应不是JSON格式内容: ${text.substring(0, 200)}...`)
// 对于非JSON响应创建一个错误状态的body
body = {
code: response.status,
msg: `Expected JSON response but got: ${contentType || 'unknown content type'}`,
data: text
};
}
}
} catch (parseError) {
console.error(`[CeruMusic] 解析响应失败: ${parseError.message}`);
console.error(`[CeruMusic] 解析响应失败: ${parseError.message}`)
// 解析失败时创建错误body
body = {
code: response.status,
msg: `Failed to parse response: ${parseError.message}`
};
}
}
console.log(`[CeruMusic] 请求响应内容:`, body);
console.log(`[CeruMusic] 请求响应内容:`, body)
const result = {
body,
statusCode: response.status,
headers: response.headers.raw(),
};
headers: response.headers.raw()
}
if (callback) {
callback(null, result);
callback(null, result)
}
return result;
return result
} catch (error) {
console.error(`[CeruMusic] Request failed: ${error.message}`);
console.error(`[CeruMusic] Request failed: ${error.message}`)
if (callback) {
// 网络错误时,调用 callback(error, null)
callback(error, null);
callback(error, null)
} else {
throw error;
throw error
}
}
};
}
if (callback) {
makeRequest().catch(() => {}); // 错误已在makeRequest中处理
makeRequest().catch(() => {}) // 错误已在makeRequest中处理
} else {
return makeRequest();
return makeRequest()
}
},
};
}
}
const sandbox = {
module: { exports: {} },
@@ -144,21 +143,21 @@ class CeruMusicPluginHost {
require: () => ({}),
global: {},
process: { env: {} }
};
}
try {
// 在沙箱中执行插件代码
vm.runInNewContext(this.pluginCode, sandbox);
this.plugin = sandbox.module.exports;
console.log(`[CeruMusic] Plugin "${this.plugin.pluginInfo.name}" loaded successfully.`);
vm.runInNewContext(this.pluginCode, sandbox)
this.plugin = sandbox.module.exports
console.log(`[CeruMusic] Plugin "${this.plugin.pluginInfo.name}" loaded successfully.`)
} catch (e) {
console.error('[CeruMusic] Error executing plugin code:', e);
throw new Error('Failed to initialize plugin.');
console.error('[CeruMusic] Error executing plugin code:', e)
throw new Error('Failed to initialize plugin.')
}
// 验证插件结构
if (!this.plugin.pluginInfo || !this.plugin.sources || !this.plugin.musicUrl) {
throw new Error('Invalid plugin structure. Required fields: pluginInfo, sources, musicUrl.');
throw new Error('Invalid plugin structure. Required fields: pluginInfo, sources, musicUrl.')
}
}
@@ -166,14 +165,14 @@ class CeruMusicPluginHost {
* 获取插件信息
*/
getPluginInfo() {
return this.plugin.pluginInfo;
return this.plugin.pluginInfo
}
/**
* 获取支持的音源和音质信息
*/
getSupportedSources() {
return this.plugin.sources;
return this.plugin.sources
}
/**
@@ -185,10 +184,10 @@ class CeruMusicPluginHost {
async getMusicUrl(source, musicInfo, quality) {
try {
if (typeof this.plugin.musicUrl !== 'function') {
throw new Error(`Action "musicUrl" is not implemented in plugin.`);
throw new Error(`Action "musicUrl" is not implemented in plugin.`)
}
console.log(`[CeruMusic] 开始调用插件的 musicUrl 方法...`);
console.log(`[CeruMusic] 开始调用插件的 musicUrl 方法...`)
// 将 cerumusic API 绑定到函数调用的 this 上下文
const result = await this.plugin.musicUrl.call(
@@ -196,17 +195,16 @@ class CeruMusicPluginHost {
source,
musicInfo,
quality
);
console.log(`[CeruMusic] 插件 musicUrl 方法调用成功`);
return result;
)
console.log(`[CeruMusic] 插件 musicUrl 方法调用成功`)
return result
} catch (error) {
console.error(`[CeruMusic] getMusicUrl 方法执行失败:`, error.message);
console.error(`[CeruMusic] 错误堆栈:`, error.stack);
console.error(`[CeruMusic] getMusicUrl 方法执行失败:`, error.message)
console.error(`[CeruMusic] 错误堆栈:`, error.stack)
// 重新抛出错误,确保外部可以捕获
throw new Error(`Plugin getMusicUrl failed: ${error.message}`);
throw new Error(`Plugin getMusicUrl failed: ${error.message}`)
}
}
@@ -221,93 +219,92 @@ class CeruMusicPluginHost {
utils: {
buffer: {
from: (data, encoding) => Buffer.from(data, encoding),
bufToString: (buffer, encoding) => buffer.toString(encoding),
},
bufToString: (buffer, encoding) => buffer.toString(encoding)
}
},
request: (url, options, callback) => {
// 支持 Promise 和 callback 两种调用方式
if (typeof options === 'function') {
callback = options;
options = { method: 'GET' };
callback = options
options = { method: 'GET' }
}
const makeRequest = async () => {
try {
console.log(`[CeruMusic] 发起请求: ${url}`);
console.log(`[CeruMusic] 发起请求: ${url}`)
// 添加超时设置
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 10000) // 10秒超时
const requestOptions = {
method: 'GET',
...options,
signal: controller.signal
};
}
const response = await fetch(url, requestOptions);
clearTimeout(timeoutId);
const response = await fetch(url, requestOptions)
clearTimeout(timeoutId)
console.log(`[CeruMusic] 请求响应状态: ${response.status}`);
console.log(`[CeruMusic] 请求响应状态: ${response.status}`)
// 尝试解析JSON如果失败则返回文本
let body;
const contentType = response.headers.get('content-type');
let body
const contentType = response.headers.get('content-type')
try {
if (contentType && contentType.includes('application/json')) {
body = await response.json();
body = await response.json()
} else {
const text = await response.text();
console.log(`[CeruMusic] 响应不是JSON格式内容: ${text.substring(0, 200)}...`);
const text = await response.text()
console.log(`[CeruMusic] 响应不是JSON格式内容: ${text.substring(0, 200)}...`)
// 对于非JSON响应创建一个错误状态的body
body = {
code: response.status,
msg: `Expected JSON response but got: ${contentType || 'unknown content type'}`,
data: text
};
}
}
} catch (parseError) {
console.error(`[CeruMusic] 解析响应失败: ${parseError.message}`);
console.error(`[CeruMusic] 解析响应失败: ${parseError.message}`)
// 解析失败时创建错误body
body = {
code: response.status,
msg: `Failed to parse response: ${parseError.message}`
};
}
}
console.log(`[CeruMusic] 请求响应内容:`, body);
console.log(`[CeruMusic] 请求响应内容:`, body)
const result = {
body,
statusCode: response.status,
headers: response.headers.raw(),
};
headers: response.headers.raw()
}
if (callback) {
callback(null, result);
callback(null, result)
}
return result;
return result
} catch (error) {
console.error(`[CeruMusic] Request failed: ${error.message}`);
console.error(`[CeruMusic] Request failed: ${error.message}`)
if (callback) {
// 网络错误时,调用 callback(error, null)
callback(error, null);
callback(error, null)
} else {
throw error;
throw error
}
}
};
}
if (callback) {
makeRequest().catch(() => {}); // 错误已在makeRequest中处理
makeRequest().catch(() => {}) // 错误已在makeRequest中处理
} else {
return makeRequest();
return makeRequest()
}
},
};
}
}
}
/**
@@ -318,23 +315,22 @@ class CeruMusicPluginHost {
async getPic(source, musicInfo) {
try {
if (typeof this.plugin.getPic !== 'function') {
throw new Error(`Action "getPic" is not implemented in plugin.`);
throw new Error(`Action "getPic" is not implemented in plugin.`)
}
console.log(`[CeruMusic] 开始调用插件的 getPic 方法...`);
console.log(`[CeruMusic] 开始调用插件的 getPic 方法...`)
const result = await this.plugin.getPic.call(
{ cerumusic: this._getCerumusicApi() },
source,
musicInfo
);
console.log(`[CeruMusic] 插件 getPic 方法调用成功`);
return result;
)
console.log(`[CeruMusic] 插件 getPic 方法调用成功`)
return result
} catch (error) {
console.error(`[CeruMusic] getPic 方法执行失败:`, error.message);
throw new Error(`Plugin getPic failed: ${error.message}`);
console.error(`[CeruMusic] getPic 方法执行失败:`, error.message)
throw new Error(`Plugin getPic failed: ${error.message}`)
}
}
@@ -346,23 +342,22 @@ class CeruMusicPluginHost {
async getLyric(source, musicInfo) {
try {
if (typeof this.plugin.getLyric !== 'function') {
throw new Error(`Action "getLyric" is not implemented in plugin.`);
throw new Error(`Action "getLyric" is not implemented in plugin.`)
}
console.log(`[CeruMusic] 开始调用插件的 getLyric 方法...`);
console.log(`[CeruMusic] 开始调用插件的 getLyric 方法...`)
const result = await this.plugin.getLyric.call(
{ cerumusic: this._getCerumusicApi() },
source,
musicInfo
);
console.log(`[CeruMusic] 插件 getLyric 方法调用成功`);
return result;
)
console.log(`[CeruMusic] 插件 getLyric 方法调用成功`)
return result
} catch (error) {
console.error(`[CeruMusic] getLyric 方法执行失败:`, error.message);
throw new Error(`Plugin getLyric failed: ${error.message}`);
console.error(`[CeruMusic] getLyric 方法执行失败:`, error.message)
throw new Error(`Plugin getLyric failed: ${error.message}`)
}
}
}

View File

@@ -1,20 +1,20 @@
const fs = require('fs');
const fs = require('fs')
function convertEventDrivenPlugin(inputFile) {
console.log('检测到事件驱动插件,使用事件包装器转换...');
const originalCode = fs.readFileSync(inputFile, 'utf-8');
// 提取插件信息
const nameMatch = originalCode.match(/@name\s+(.+)/);
const versionMatch = originalCode.match(/@version\s+(.+)/);
const descMatch = originalCode.match(/@description\s+(.+)/);
const pluginName = nameMatch ? nameMatch[1].trim() : "未知插件";
const pluginVersion = versionMatch ? versionMatch[1].trim() : "1.0.0";
const pluginDesc = descMatch ? descMatch[1].trim() : "从事件驱动插件转换而来";
return `/**
console.log('检测到事件驱动插件,使用事件包装器转换...')
const originalCode = fs.readFileSync(inputFile, 'utf-8')
// 提取插件信息
const nameMatch = originalCode.match(/@name\s+(.+)/)
const versionMatch = originalCode.match(/@version\s+(.+)/)
const descMatch = originalCode.match(/@description\s+(.+)/)
const pluginName = nameMatch ? nameMatch[1].trim() : '未知插件'
const pluginVersion = versionMatch ? versionMatch[1].trim() : '1.0.0'
const pluginDesc = descMatch ? descMatch[1].trim() : '从事件驱动插件转换而来'
return `/**
* 由 CeruMusic 插件转换器转换 - @author sqj
* @name ${pluginName}
* @version ${pluginVersion}
@@ -49,16 +49,16 @@ function initializePlugin() {
updateAlert: 'updateAlert'
},
on: (event, handler) => {
console.log(\`[${ pluginName + ' by Ceru插件' || 'ceru插件' }] 注册事件监听器: \${event}\`);
console.log(\`[${pluginName + ' by Ceru插件' || 'ceru插件'}] 注册事件监听器: \${event}\`);
if (event === 'request') {
requestHandler = handler;
}
},
send: (event, data) => {
console.log(\`[${ pluginName + ' by Ceru插件' || 'ceru插件' }] 发送事件: \${event}\`, data);
console.log(\`[${pluginName + ' by Ceru插件' || 'ceru插件'}] 发送事件: \${event}\`, data);
if (event === 'inited' && data.sources) {
pluginSources = data.sources;
console.log('[${ pluginName + ' by Ceru插件' || 'ceru插件' }] 音源注册完成:', Object.keys(pluginSources));
console.log('[${pluginName + ' by Ceru插件' || 'ceru插件'}] 音源注册完成:', Object.keys(pluginSources));
}
},
request: request,
@@ -233,31 +233,31 @@ module.exports = {
pluginInfo,
sources,
musicUrl
};`;
};`
}
// 主函数
function main() {
const inputFile = process.argv[2];
const outputFile = process.argv[3] || 'event-driven-plugin.js';
const inputFile = process.argv[2]
const outputFile = process.argv[3] || 'event-driven-plugin.js'
if (!inputFile) {
console.error('使用方法: node converter-event-driven.js <输入文件> [输出文件]');
process.exit(1);
}
if (!inputFile) {
console.error('使用方法: node converter-event-driven.js <输入文件> [输出文件]')
process.exit(1)
}
try {
const result = convertEventDrivenPlugin(inputFile);
fs.writeFileSync(outputFile, result);
console.log('\\n🎉 事件驱动插件转换成功!');
console.log(` 新插件已保存至: ${outputFile}`);
} catch (error) {
console.error('❌ 转换失败:', error.message);
process.exit(1);
}
try {
const result = convertEventDrivenPlugin(inputFile)
fs.writeFileSync(outputFile, result)
console.log('\\n🎉 事件驱动插件转换成功!')
console.log(` 新插件已保存至: ${outputFile}`)
} catch (error) {
console.error('❌ 转换失败:', error.message)
process.exit(1)
}
}
if (require.main === module) {
main();
}
main()
}

View File

@@ -9,6 +9,4 @@ function getAppDirPath() {
return dirPath
}
export {
getAppDirPath
}
export { getAppDirPath }

178
src/main/window/index.ts Normal file
View File

@@ -0,0 +1,178 @@
import { Tray, Menu, BrowserWindow } from 'electron'
import { electronApp, optimizer } from '@electron-toolkit/utils'
import path from 'node:path'
// 使用传入的 tray 对象
export default function useWindow(
createWindow,
ipcMain,
app,
mainWindow: BrowserWindow | null,
isQuitting: { value: boolean },
trayObj: { value: Tray | null }
) {
function createTray(): void {
// 创建系统托盘
const trayIconPath = path.join(__dirname, '../../resources/logo.png')
trayObj.value = new Tray(trayIconPath)
// 创建托盘菜单
const contextMenu = Menu.buildFromTemplate([
{
label: '显示窗口',
click: () => {
if (mainWindow) {
mainWindow.show()
mainWindow.focus()
}
}
},
{
label: '播放/暂停',
click: () => {
// 这里可以添加播放控制逻辑
mainWindow?.webContents.send('music-control')
}
},
{ type: 'separator' },
{
label: '退出',
click: () => {
isQuitting.value = true
app.quit()
}
}
])
trayObj.value.setContextMenu(contextMenu)
trayObj.value.setToolTip('Ceru Music')
// 双击托盘图标显示窗口
trayObj.value.on('click', () => {
if (mainWindow) {
if (mainWindow.isVisible()) {
mainWindow.hide()
} else {
mainWindow.show()
mainWindow.focus()
}
}
})
}
app.whenReady().then(() => {
// Set app user model id for windows
electronApp.setAppUserModelId('com.cerulean.music')
// Default open or close DevTools by F12 in development
// and ignore CommandOrControl + R in production.
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
app.on('browser-window-created', (_, window) => {
optimizer.watchWindowShortcuts(window)
})
// 窗口控制 IPC 处理
ipcMain.on('window-minimize', () => {
console.log('收到 window-minimize 事件')
if (mainWindow) {
console.log('正在最小化窗口...')
mainWindow.minimize()
} else {
console.log('mainWindow 不存在')
const window = BrowserWindow.getFocusedWindow()
if (window) {
console.log('使用 getFocusedWindow 最小化窗口...')
window.minimize()
} else {
console.log('没有找到可用的窗口')
}
}
})
ipcMain.on('window-maximize', () => {
console.log('收到 window-maximize 事件')
if (mainWindow) {
console.log('正在最大化/还原窗口...')
if (mainWindow.isMaximized()) {
mainWindow.unmaximize()
} else {
mainWindow.maximize()
}
} else {
console.log('mainWindow 不存在')
const window = BrowserWindow.getFocusedWindow()
if (window) {
console.log('使用 getFocusedWindow 最大化/还原窗口...')
if (window.isMaximized()) {
window.unmaximize()
} else {
window.maximize()
}
} else {
console.log('没有找到可用的窗口')
}
}
})
ipcMain.on('window-close', () => {
console.log('收到 window-close 事件')
if (mainWindow) {
console.log('正在关闭窗口...')
mainWindow.close()
} else {
console.log('mainWindow 不存在')
const window = BrowserWindow.getFocusedWindow()
if (window) {
console.log('使用 getFocusedWindow 关闭窗口...')
window.close()
} else {
console.log('没有找到可用的窗口')
}
}
})
// Mini 模式 IPC 处理 - 最小化到系统托盘
ipcMain.on('window-mini-mode', (_, isMini) => {
console.log('收到 window-mini-mode 事件isMini:', isMini)
if (mainWindow) {
if (isMini) {
// 进入 Mini 模式:隐藏窗口到系统托盘
console.log('正在隐藏窗口...')
mainWindow.hide()
// 显示托盘通知(可选)
if (trayObj.value) {
console.log('显示托盘通知...')
trayObj.value.displayBalloon({
title: '澜音 Music',
content: '已最小化到系统托盘啦,点击托盘图标可重新打开~'
})
} else {
console.log('托盘对象不存在trayObj.value:', trayObj.value)
}
} else {
// 退出 Mini 模式:显示窗口
mainWindow.show()
mainWindow.focus()
}
}
})
// 全屏模式 IPC 处理
ipcMain.on('window-toggle-fullscreen', () => {
if (mainWindow) {
const isFullScreen = mainWindow.isFullScreen()
mainWindow.setFullScreen(!isFullScreen)
}
})
createWindow()
createTray()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// 不需要返回 tray因为我们已经通过引用修改了外部传入的 trayObj
return {}
}

View File

@@ -4,10 +4,22 @@ import { electronAPI } from '@electron-toolkit/preload'
// Custom APIs for renderer
const api = {
// 窗口控制方法
minimize: () => ipcRenderer.send('window-minimize'),
maximize: () => ipcRenderer.send('window-maximize'),
close: () => ipcRenderer.send('window-close'),
setMiniMode: (isMini: boolean) => ipcRenderer.send('window-mini-mode', isMini),
minimize: () => {
console.log('preload: 发送 window-minimize 事件')
ipcRenderer.send('window-minimize')
},
maximize: () => {
console.log('preload: 发送 window-maximize 事件')
ipcRenderer.send('window-maximize')
},
close: () => {
console.log('preload: 发送 window-close 事件')
ipcRenderer.send('window-close')
},
setMiniMode: (isMini: boolean) => {
console.log('preload: 发送 window-mini-mode 事件isMini:', isMini)
ipcRenderer.send('window-mini-mode', isMini)
},
toggleFullscreen: () => ipcRenderer.send('window-toggle-fullscreen'),
onMusicCtrl: (callback) => ipcRenderer.on('music-control', callback),

View File

@@ -5,6 +5,4 @@
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
}
declare global {}

View File

@@ -20,7 +20,6 @@ import { parseYrc, parseLrc, parseTTML } from '@applemusic-like-lyrics/lyric/pkg
import { storeToRefs } from 'pinia'
interface Props {
show?: boolean
coverImage?: string
@@ -120,7 +119,7 @@ watch(
const translatedline = parseLrc(lyricData.tlyric.lyric)
console.log(translatedline)
for (let i = 0; i < parsedLyrics.length; i++) {
parsedLyrics[i].translatedLyric = translatedline[i].words[0].word
parsedLyrics[i].translatedLyric = translatedline[i].words[0].word
}
console.log('使用翻译歌词', translatedline)
}
@@ -274,7 +273,7 @@ watch(
<div v-show="state.lyricLines.length > 0" class="right">
<LyricPlayer
ref="lyricPlayerRef"
:lyric-lines="props.show? state.lyricLines : []"
:lyric-lines="props.show ? state.lyricLines : []"
:current-time="state.currentTime"
:align-position="0.38"
style="mix-blend-mode: plus-lighter"

View File

@@ -52,7 +52,13 @@ const handleClose = (): void => {
const handleMiniMode = (): void => {
// 直接最小化到系统托盘
window.api?.setMiniMode(true)
console.log('TitleBarControls: 点击了最小化到系统托盘按钮')
if (window.api) {
console.log('TitleBarControls: window.api 存在,调用 setMiniMode(true)')
window.api.setMiniMode(true)
} else {
console.error('TitleBarControls: window.api 不存在!')
}
console.log('最小化到系统托盘')
}

641
yarn.lock
View File

@@ -432,6 +432,138 @@
minimatch "^9.0.3"
plist "^3.1.0"
"@emnapi/runtime@^1.2.0":
version "1.4.5"
resolved "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.4.5.tgz"
integrity sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==
dependencies:
tslib "^2.4.0"
"@esbuild/aix-ppc64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz"
integrity sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==
"@esbuild/android-arm@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.25.9.tgz"
integrity sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==
"@esbuild/android-arm64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz"
integrity sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==
"@esbuild/android-x64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.25.9.tgz"
integrity sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==
"@esbuild/darwin-arm64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz"
integrity sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==
"@esbuild/darwin-x64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz"
integrity sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==
"@esbuild/freebsd-arm64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz"
integrity sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==
"@esbuild/freebsd-x64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz"
integrity sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==
"@esbuild/linux-arm@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz"
integrity sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==
"@esbuild/linux-arm64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz"
integrity sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==
"@esbuild/linux-ia32@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz"
integrity sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==
"@esbuild/linux-loong64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz"
integrity sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==
"@esbuild/linux-mips64el@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz"
integrity sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==
"@esbuild/linux-ppc64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz"
integrity sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==
"@esbuild/linux-riscv64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz"
integrity sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==
"@esbuild/linux-s390x@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz"
integrity sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==
"@esbuild/linux-x64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz"
integrity sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==
"@esbuild/netbsd-arm64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz"
integrity sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==
"@esbuild/netbsd-x64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz"
integrity sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==
"@esbuild/openbsd-arm64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz"
integrity sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==
"@esbuild/openbsd-x64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz"
integrity sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==
"@esbuild/openharmony-arm64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz"
integrity sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==
"@esbuild/sunos-x64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz"
integrity sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==
"@esbuild/win32-arm64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz"
integrity sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==
"@esbuild/win32-ia32@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz"
integrity sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==
"@esbuild/win32-x64@0.25.9":
version "0.25.9"
resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz"
@@ -536,6 +668,114 @@
resolved "https://registry.npmmirror.com/@humanwhocodes/retry/-/retry-0.4.3.tgz"
integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==
"@img/sharp-darwin-arm64@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz"
integrity sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==
optionalDependencies:
"@img/sharp-libvips-darwin-arm64" "1.0.4"
"@img/sharp-darwin-x64@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz"
integrity sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==
optionalDependencies:
"@img/sharp-libvips-darwin-x64" "1.0.4"
"@img/sharp-libvips-darwin-arm64@1.0.4":
version "1.0.4"
resolved "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz"
integrity sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==
"@img/sharp-libvips-darwin-x64@1.0.4":
version "1.0.4"
resolved "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz"
integrity sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==
"@img/sharp-libvips-linux-arm@1.0.5":
version "1.0.5"
resolved "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz"
integrity sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==
"@img/sharp-libvips-linux-arm64@1.0.4":
version "1.0.4"
resolved "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz"
integrity sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==
"@img/sharp-libvips-linux-s390x@1.0.4":
version "1.0.4"
resolved "https://registry.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz"
integrity sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==
"@img/sharp-libvips-linux-x64@1.0.4":
version "1.0.4"
resolved "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz"
integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==
"@img/sharp-libvips-linuxmusl-arm64@1.0.4":
version "1.0.4"
resolved "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz"
integrity sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==
"@img/sharp-libvips-linuxmusl-x64@1.0.4":
version "1.0.4"
resolved "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz"
integrity sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==
"@img/sharp-linux-arm@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz"
integrity sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==
optionalDependencies:
"@img/sharp-libvips-linux-arm" "1.0.5"
"@img/sharp-linux-arm64@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz"
integrity sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==
optionalDependencies:
"@img/sharp-libvips-linux-arm64" "1.0.4"
"@img/sharp-linux-s390x@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz"
integrity sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==
optionalDependencies:
"@img/sharp-libvips-linux-s390x" "1.0.4"
"@img/sharp-linux-x64@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz"
integrity sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==
optionalDependencies:
"@img/sharp-libvips-linux-x64" "1.0.4"
"@img/sharp-linuxmusl-arm64@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz"
integrity sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==
optionalDependencies:
"@img/sharp-libvips-linuxmusl-arm64" "1.0.4"
"@img/sharp-linuxmusl-x64@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz"
integrity sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==
optionalDependencies:
"@img/sharp-libvips-linuxmusl-x64" "1.0.4"
"@img/sharp-wasm32@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz"
integrity sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==
dependencies:
"@emnapi/runtime" "^1.2.0"
"@img/sharp-win32-ia32@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz"
integrity sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==
"@img/sharp-win32-x64@0.33.5":
version "0.33.5"
resolved "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz"
@@ -992,6 +1232,66 @@
mkdirp "^1.0.4"
rimraf "^3.0.2"
"@parcel/watcher-android-arm64@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz"
integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==
"@parcel/watcher-darwin-arm64@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz"
integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==
"@parcel/watcher-darwin-x64@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz"
integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==
"@parcel/watcher-freebsd-x64@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz"
integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==
"@parcel/watcher-linux-arm-glibc@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz"
integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==
"@parcel/watcher-linux-arm-musl@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz"
integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==
"@parcel/watcher-linux-arm64-glibc@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz"
integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==
"@parcel/watcher-linux-arm64-musl@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz"
integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==
"@parcel/watcher-linux-x64-glibc@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz"
integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==
"@parcel/watcher-linux-x64-musl@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz"
integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==
"@parcel/watcher-win32-arm64@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz"
integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==
"@parcel/watcher-win32-ia32@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz"
integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==
"@parcel/watcher-win32-x64@2.5.1":
version "2.5.1"
resolved "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz"
@@ -1158,6 +1458,101 @@
resolved "https://registry.npmmirror.com/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz"
integrity sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A==
"@rollup/rollup-android-arm-eabi@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz"
integrity sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==
"@rollup/rollup-android-arm64@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz"
integrity sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==
"@rollup/rollup-darwin-arm64@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz"
integrity sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==
"@rollup/rollup-darwin-x64@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz"
integrity sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==
"@rollup/rollup-freebsd-arm64@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz"
integrity sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==
"@rollup/rollup-freebsd-x64@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz"
integrity sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==
"@rollup/rollup-linux-arm-gnueabihf@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz"
integrity sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==
"@rollup/rollup-linux-arm-musleabihf@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz"
integrity sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==
"@rollup/rollup-linux-arm64-gnu@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz"
integrity sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==
"@rollup/rollup-linux-arm64-musl@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz"
integrity sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==
"@rollup/rollup-linux-loongarch64-gnu@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz"
integrity sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==
"@rollup/rollup-linux-ppc64-gnu@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz"
integrity sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==
"@rollup/rollup-linux-riscv64-gnu@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz"
integrity sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==
"@rollup/rollup-linux-riscv64-musl@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz"
integrity sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==
"@rollup/rollup-linux-s390x-gnu@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz"
integrity sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==
"@rollup/rollup-linux-x64-gnu@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz"
integrity sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==
"@rollup/rollup-linux-x64-musl@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz"
integrity sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==
"@rollup/rollup-win32-arm64-msvc@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz"
integrity sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==
"@rollup/rollup-win32-ia32-msvc@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz"
integrity sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==
"@rollup/rollup-win32-x64-msvc@4.46.2":
version "4.46.2"
resolved "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz"
@@ -1178,6 +1573,51 @@
resolved "https://registry.npmmirror.com/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz"
integrity sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==
"@swc/core-darwin-arm64@1.13.3":
version "1.13.3"
resolved "https://registry.npmmirror.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.13.3.tgz"
integrity sha512-ux0Ws4pSpBTqbDS9GlVP354MekB1DwYlbxXU3VhnDr4GBcCOimpocx62x7cFJkSpEBF8bmX8+/TTCGKh4PbyXw==
"@swc/core-darwin-x64@1.13.3":
version "1.13.3"
resolved "https://registry.npmmirror.com/@swc/core-darwin-x64/-/core-darwin-x64-1.13.3.tgz"
integrity sha512-p0X6yhxmNUOMZrbeZ3ZNsPige8lSlSe1llllXvpCLkKKxN/k5vZt1sULoq6Nj4eQ7KeHQVm81/+AwKZyf/e0TA==
"@swc/core-linux-arm-gnueabihf@1.13.3":
version "1.13.3"
resolved "https://registry.npmmirror.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.13.3.tgz"
integrity sha512-OmDoiexL2fVWvQTCtoh0xHMyEkZweQAlh4dRyvl8ugqIPEVARSYtaj55TBMUJIP44mSUOJ5tytjzhn2KFxFcBA==
"@swc/core-linux-arm64-gnu@1.13.3":
version "1.13.3"
resolved "https://registry.npmmirror.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.13.3.tgz"
integrity sha512-STfKku3QfnuUj6k3g9ld4vwhtgCGYIFQmsGPPgT9MK/dI3Lwnpe5Gs5t1inoUIoGNP8sIOLlBB4HV4MmBjQuhw==
"@swc/core-linux-arm64-musl@1.13.3":
version "1.13.3"
resolved "https://registry.npmmirror.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.13.3.tgz"
integrity sha512-bc+CXYlFc1t8pv9yZJGus372ldzOVscBl7encUBlU1m/Sig0+NDJLz6cXXRcFyl6ABNOApWeR4Yl7iUWx6C8og==
"@swc/core-linux-x64-gnu@1.13.3":
version "1.13.3"
resolved "https://registry.npmmirror.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.13.3.tgz"
integrity sha512-dFXoa0TEhohrKcxn/54YKs1iwNeW6tUkHJgXW33H381SvjKFUV53WR231jh1sWVJETjA3vsAwxKwR23s7UCmUA==
"@swc/core-linux-x64-musl@1.13.3":
version "1.13.3"
resolved "https://registry.npmmirror.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.13.3.tgz"
integrity sha512-ieyjisLB+ldexiE/yD8uomaZuZIbTc8tjquYln9Quh5ykOBY7LpJJYBWvWtm1g3pHv6AXlBI8Jay7Fffb6aLfA==
"@swc/core-win32-arm64-msvc@1.13.3":
version "1.13.3"
resolved "https://registry.npmmirror.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.13.3.tgz"
integrity sha512-elTQpnaX5vESSbhCEgcwXjpMsnUbqqHfEpB7ewpkAsLzKEXZaK67ihSRYAuAx6ewRQTo7DS5iTT6X5aQD3MzMw==
"@swc/core-win32-ia32-msvc@1.13.3":
version "1.13.3"
resolved "https://registry.npmmirror.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.13.3.tgz"
integrity sha512-nvehQVEOdI1BleJpuUgPLrclJ0TzbEMc+MarXDmmiRFwEUGqj+pnfkTSb7RZyS1puU74IXdK/YhTirHurtbI9w==
"@swc/core-win32-x64-msvc@1.13.3":
version "1.13.3"
resolved "https://registry.npmmirror.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.13.3.tgz"
@@ -1344,6 +1784,14 @@
resolved "https://registry.npmmirror.com/@types/node/-/node-16.9.1.tgz"
integrity sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==
"@types/plist@^3.0.1":
version "3.0.5"
resolved "https://registry.npmmirror.com/@types/plist/-/plist-3.0.5.tgz"
integrity sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==
dependencies:
"@types/node" "*"
xmlbuilder ">=11.0.1"
"@types/responselike@^1.0.0":
version "1.0.3"
resolved "https://registry.npmmirror.com/@types/responselike/-/responselike-1.0.3.tgz"
@@ -1381,6 +1829,11 @@
resolved "https://registry.npmmirror.com/@types/validator/-/validator-13.15.2.tgz"
integrity sha512-y7pa/oEJJ4iGYBxOpfAKn5b9+xuihvzDVnC/OSvlVnGxVg0pOqmjiMafiJ1KVNQEaPZf9HsEp5icEwGg8uIe5Q==
"@types/verror@^1.10.3":
version "1.10.11"
resolved "https://registry.npmmirror.com/@types/verror/-/verror-1.10.11.tgz"
integrity sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==
"@types/yauzl@^2.9.1":
version "2.10.3"
resolved "https://registry.npmmirror.com/@types/yauzl/-/yauzl-2.10.3.tgz"
@@ -1790,7 +2243,7 @@ ajv-keywords@^3.4.1:
resolved "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz"
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
ajv@^6.12.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.9.1:
ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.9.1:
version "6.12.6"
resolved "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@@ -2007,6 +2460,11 @@ ast-types@^0.13.4:
dependencies:
tslib "^2.0.1"
astral-regex@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
async-exit-hook@^2.0.1:
version "2.0.1"
resolved "https://registry.npmmirror.com/async-exit-hook/-/async-exit-hook-2.0.1.tgz"
@@ -2189,7 +2647,7 @@ buffer-from@^1.0.0:
resolved "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer@^5.2.0, buffer@^5.5.0:
buffer@^5.1.0, buffer@^5.2.0, buffer@^5.5.0:
version "5.7.1"
resolved "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz"
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
@@ -2443,6 +2901,14 @@ cli-spinners@^2.5.0:
resolved "https://registry.npmmirror.com/cli-spinners/-/cli-spinners-2.9.2.tgz"
integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==
cli-truncate@^2.1.0:
version "2.1.0"
resolved "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-2.1.0.tgz"
integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==
dependencies:
slice-ansi "^3.0.0"
string-width "^4.2.0"
cliui@^3.2.0:
version "3.2.0"
resolved "https://registry.npmmirror.com/cliui/-/cliui-3.2.0.tgz"
@@ -2677,6 +3143,13 @@ crc-32@^1.2.0:
resolved "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz"
integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==
crc@^3.8.0:
version "3.8.0"
resolved "https://registry.npmmirror.com/crc/-/crc-3.8.0.tgz"
integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==
dependencies:
buffer "^5.1.0"
crc32-stream@^4.0.2:
version "4.0.3"
resolved "https://registry.npmmirror.com/crc32-stream/-/crc32-stream-4.0.3.tgz"
@@ -2934,6 +3407,20 @@ dmg-builder@25.1.8:
optionalDependencies:
dmg-license "^1.0.11"
dmg-license@^1.0.11:
version "1.0.11"
resolved "https://registry.npmmirror.com/dmg-license/-/dmg-license-1.0.11.tgz"
integrity sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==
dependencies:
"@types/plist" "^3.0.1"
"@types/verror" "^1.10.3"
ajv "^6.10.0"
crc "^3.8.0"
iconv-corefoundation "^1.1.7"
plist "^3.0.4"
smart-buffer "^4.0.2"
verror "^1.10.0"
dom-walk@^0.1.0:
version "0.1.2"
resolved "https://registry.npmmirror.com/dom-walk/-/dom-walk-0.1.2.tgz"
@@ -3076,10 +3563,10 @@ electron-vite@^4.0.0:
magic-string "^0.30.17"
picocolors "^1.1.1"
electron@^37.2.3, electron@>=13.0.0:
version "37.3.0"
resolved "https://registry.npmmirror.com/electron/-/electron-37.3.0.tgz"
integrity sha512-cPOPUD26DwCh+PZ9q+gMyVBvdBN75SnekI6u5zcOeoLVIXQpzrCm1ewz9BcrkWkVW7oOtfQAEo1G1SffvXrSSw==
electron@^37.3.1, electron@>=13.0.0:
version "37.3.1"
resolved "https://registry.npmmirror.com/electron/-/electron-37.3.1.tgz"
integrity sha512-7DhktRLqhe6OJh/Bo75bTI0puUYEmIwSzMinocgO63mx3MVjtIn2tYMzLmAleNIlud2htkjpsMG2zT4PiTCloA==
dependencies:
"@electron/get" "^2.0.0"
"@types/node" "^22.7.7"
@@ -3508,7 +3995,12 @@ extract-zip@^2.0.1:
optionalDependencies:
"@types/yauzl" "^2.9.1"
extsprintf@^1.2.0, extsprintf@1.3.0:
extsprintf@^1.2.0:
version "1.4.1"
resolved "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.4.1.tgz"
integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.3.0.tgz"
integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==
@@ -3805,6 +4297,11 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
fsevents@~2.3.2, fsevents@~2.3.3:
version "2.3.3"
resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz"
@@ -4219,6 +4716,14 @@ icon-gen@^2.0.0:
svg2png "4.1.1"
uuid "^8.3.1"
iconv-corefoundation@^1.1.7:
version "1.1.7"
resolved "https://registry.npmmirror.com/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz"
integrity sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==
dependencies:
cli-truncate "^2.1.0"
node-addon-api "^1.6.3"
iconv-lite@^0.6.2:
version "0.6.3"
resolved "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz"
@@ -5401,6 +5906,11 @@ node-abi@^3.45.0:
dependencies:
semver "^7.3.5"
node-addon-api@^1.6.3:
version "1.7.2"
resolved "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-1.7.2.tgz"
integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==
node-addon-api@^7.0.0:
version "7.1.1"
resolved "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz"
@@ -5948,7 +6458,7 @@ pkg-types@^2.0.1, pkg-types@^2.2.0:
exsolve "^1.0.7"
pathe "^2.0.3"
plist@^3.0.5, plist@^3.1.0:
plist@^3.0.4, plist@^3.0.5, plist@^3.1.0:
version "3.1.0"
resolved "https://registry.npmmirror.com/plist/-/plist-3.1.0.tgz"
integrity sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==
@@ -6462,6 +6972,95 @@ sanitize-filename@^1.6.3:
dependencies:
truncate-utf8-bytes "^1.0.0"
sass-embedded-all-unknown@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.90.0.tgz"
integrity sha512-/n7jTQvI+hftDDrHzK19G4pxfDzOhtjuQO1K54ui1pT2S0sWfWDjCYUbQgtWQ6FO7g5qWS0hgmrWdc7fmS3rgA==
dependencies:
sass "1.90.0"
sass-embedded-android-arm@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-android-arm/-/sass-embedded-android-arm-1.90.0.tgz"
integrity sha512-usF6kVJQWa1CMgPH1nCT1y8KEmAT2fzB00dDIPBYHq8U5VZLCihi2bJRP5U9NlcwP1TlKGKCjwsbIdSjDKfecg==
sass-embedded-android-arm64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.90.0.tgz"
integrity sha512-bkTlewzWksa6Sj4Zs1CWiutnvUbsO3xuYh2QBRknXsOtuMlfTPoXnwhCnyE4lSvUxw2qxSbv+NdQev9qMfsBgA==
sass-embedded-android-riscv64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.90.0.tgz"
integrity sha512-bpqCIOaX+0Lou/BNJ4iJIKbWbVaYXFdg26C3gG6gxxKZRzp/6OYCxHrIQDwhKz6YC8Q5rwNPMpfDVYbWPcgroA==
sass-embedded-android-x64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-android-x64/-/sass-embedded-android-x64-1.90.0.tgz"
integrity sha512-GNxVKnCMd/p2icZ+Q4mhvNk19NrLXq1C4guiqjrycHYQLEnxRkjbW1QXYiL+XyDn4e+Bcq0knzG0I9pMuNZxkg==
sass-embedded-darwin-arm64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.90.0.tgz"
integrity sha512-qr4KBMJfBA+lzXiWnP00qzpLzHQzGd1OSK3VHcUFjZ8l7VOYf2R7Tc3fcTLhpaNPMJtTK0jrk8rFqBvsiZExnA==
sass-embedded-darwin-x64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.90.0.tgz"
integrity sha512-z2nr1nNqtWDLVRwTbHtL7zriK90U7O/Gb15UaCSMYeAz9Y+wog5s/sDEKm0+GsVdzzkaCaMZRWGN4jTilnUwmQ==
sass-embedded-linux-arm@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.90.0.tgz"
integrity sha512-FeBxI5Q2HvM3CCadcEcQgvWbDPVs2YEF0PZ87fbAVTCG8dV+iNnQreSz7GRJroknpvbRhm5t2gedvcgmTnPb2Q==
sass-embedded-linux-arm64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.90.0.tgz"
integrity sha512-SPMcGZuP71Fj8btCGtlBnv8h8DAbJn8EQfLzXs9oo6NGFFLVjNGiFpqGfgtUV6DLWCuaRyEFeViO7wZow/vKGQ==
sass-embedded-linux-musl-arm@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.90.0.tgz"
integrity sha512-EB2z0fUXdUdvSoddf4DzdZQkD/xyreD72gwAi8YScgUvR4HMXI7bLcK/n78Rft6OnqvV8090hjC8FsLDo3x5xQ==
sass-embedded-linux-musl-arm64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.90.0.tgz"
integrity sha512-xLH7+PFq763MoEm3vI7hQk5E+nStiLWbijHEYW/tEtCbcQIphgzSkDItEezxXew3dU4EJ1jqrBUySPdoXFLqWA==
sass-embedded-linux-musl-riscv64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.90.0.tgz"
integrity sha512-L21UkOgnSrD+ERF+jo1IWneGv40t0ap9+3cI+wZWYhQS5MkxponhT9QaNU57JEDJwB9mOl01LVw14opz4SN+VQ==
sass-embedded-linux-musl-x64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.90.0.tgz"
integrity sha512-NeAycQlsdhFdnIeSmRmScYUyCd+uE+x15NLFunbF8M0PgCKurrUhaxgGKSuBbaK56FpxarKOHCqcOrWbemIGzQ==
sass-embedded-linux-riscv64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.90.0.tgz"
integrity sha512-lJopaQhW8S+kaQ61vMqq3c+bOurcf9RdZf2EmzQYpc2y1vT5cWfRNrRkbAgO/23IQxsk/fq3UIUnsjnyQmi6MA==
sass-embedded-linux-x64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.90.0.tgz"
integrity sha512-Cc061gBfMPwH9rN7neQaH36cvOQC+dFMSGIeX5qUOhrEL4Ng51iqBV6aI4RIB1jCFGth6eDydVRN1VdV9qom8A==
sass-embedded-unknown-all@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.90.0.tgz"
integrity sha512-DBGzHVCJDqtjTHZFohush9YTxd4ZxhIygIRTNRXnA0359woF9Z8AS7/YxfzwkqrTX5durSJa6ZamGFYVLoRphQ==
dependencies:
sass "1.90.0"
sass-embedded-win32-arm64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.90.0.tgz"
integrity sha512-c3/vL/CATnaW3x/6kcNbCROEOUU7zvJpIURp7M9664GJj08/gLPRWKNruw0OkAPQ3C5TTQz7+/fQWEpRA6qmvA==
sass-embedded-win32-x64@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.90.0.tgz"
@@ -6500,7 +7099,7 @@ sass-embedded@^1.70.0, sass-embedded@^1.90.0:
sass-embedded-win32-arm64 "1.90.0"
sass-embedded-win32-x64 "1.90.0"
sass@^1.70.0:
sass@^1.70.0, sass@1.90.0:
version "1.90.0"
resolved "https://registry.npmmirror.com/sass/-/sass-1.90.0.tgz"
integrity sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==
@@ -6748,7 +7347,16 @@ slash@^3.0.0:
resolved "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
smart-buffer@^4.2.0:
slice-ansi@^3.0.0:
version "3.0.0"
resolved "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-3.0.0.tgz"
integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==
dependencies:
ansi-styles "^4.0.0"
astral-regex "^2.0.0"
is-fullwidth-code-point "^3.0.0"
smart-buffer@^4.0.2, smart-buffer@^4.2.0:
version "4.2.0"
resolved "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
@@ -7206,7 +7814,7 @@ ts-api-utils@^2.1.0:
resolved "https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz"
integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==
tslib@^2.0.1, tslib@^2.1.0:
tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0:
version "2.8.1"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
@@ -7478,6 +8086,15 @@ vary@~1.1.2:
resolved "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz"
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
verror@^1.10.0:
version "1.10.1"
resolved "https://registry.npmmirror.com/verror/-/verror-1.10.1.tgz"
integrity sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==
dependencies:
assert-plus "^1.0.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
verror@1.10.0:
version "1.10.0"
resolved "https://registry.npmmirror.com/verror/-/verror-1.10.0.tgz"
@@ -7765,7 +8382,7 @@ xml2js@^0.6.2:
sax ">=0.6.0"
xmlbuilder "~11.0.0"
xmlbuilder@^15.1.1:
xmlbuilder@^15.1.1, xmlbuilder@>=11.0.1:
version "15.1.1"
resolved "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz"
integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==