2023-11-23 18:28:53 +08:00
|
|
|
|
import { join } from "path";
|
2023-12-16 16:07:51 +08:00
|
|
|
|
import { app, protocol, shell, BrowserWindow, globalShortcut, nativeImage } from "electron";
|
2023-12-04 13:35:06 +08:00
|
|
|
|
import { platform, optimizer, is } from "@electron-toolkit/utils";
|
2023-11-23 18:28:53 +08:00
|
|
|
|
import { startNcmServer } from "@main/startNcmServer";
|
|
|
|
|
|
import { startMainServer } from "@main/startMainServer";
|
2023-12-16 16:07:51 +08:00
|
|
|
|
import createSystemTray from "@main/utils/createSystemTray";
|
2023-11-27 18:23:01 +08:00
|
|
|
|
import createGlobalShortcut from "@main/utils/createGlobalShortcut";
|
2023-11-23 18:28:53 +08:00
|
|
|
|
import mainIpcMain from "@main/mainIpcMain";
|
2023-12-01 15:29:14 +08:00
|
|
|
|
import Store from "electron-store";
|
2023-11-27 18:23:01 +08:00
|
|
|
|
import log from "electron-log";
|
2023-11-23 18:28:53 +08:00
|
|
|
|
|
|
|
|
|
|
// 屏蔽报错
|
|
|
|
|
|
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = "true";
|
|
|
|
|
|
|
2023-11-27 18:23:01 +08:00
|
|
|
|
// 配置 log
|
|
|
|
|
|
log.transports.file.resolvePathFn = () =>
|
2023-12-16 16:07:51 +08:00
|
|
|
|
join(app.getPath("documents"), "/SPlayer/SPlayer-log.txt");
|
2023-11-30 15:02:51 +08:00
|
|
|
|
// 设置日志文件的最大大小为 2 MB
|
|
|
|
|
|
log.transports.file.maxSize = 2 * 1024 * 1024;
|
2023-12-01 15:29:14 +08:00
|
|
|
|
// 绑定 console 事件
|
|
|
|
|
|
console.error = log.error.bind(log);
|
|
|
|
|
|
console.warn = log.warn.bind(log);
|
|
|
|
|
|
console.info = log.info.bind(log);
|
|
|
|
|
|
console.debug = log.debug.bind(log);
|
2023-11-27 18:23:01 +08:00
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 主进程
|
|
|
|
|
|
class MainProcess {
|
|
|
|
|
|
constructor() {
|
|
|
|
|
|
// 主窗口
|
|
|
|
|
|
this.mainWindow = null;
|
|
|
|
|
|
// 主代理
|
|
|
|
|
|
this.mainServer = null;
|
|
|
|
|
|
// 网易云 API
|
|
|
|
|
|
this.ncmServer = null;
|
2023-12-01 15:29:14 +08:00
|
|
|
|
// Store
|
|
|
|
|
|
this.store = new Store({
|
|
|
|
|
|
// 窗口大小
|
|
|
|
|
|
windowSize: {
|
|
|
|
|
|
width: { type: "number", default: 1280 },
|
|
|
|
|
|
height: { type: "number", default: 740 },
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
2023-12-12 18:11:28 +08:00
|
|
|
|
// 设置应用程序名称
|
|
|
|
|
|
if (process.platform === "win32") app.setAppUserModelId(app.getName());
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 初始化
|
2023-12-12 18:11:28 +08:00
|
|
|
|
this.checkApp().then(async (lockObtained) => {
|
2023-12-02 17:25:23 +08:00
|
|
|
|
if (lockObtained) {
|
2023-12-12 18:11:28 +08:00
|
|
|
|
await this.init();
|
2023-12-02 17:25:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
2023-11-23 18:28:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-12-04 13:35:06 +08:00
|
|
|
|
// 单例锁
|
2023-12-02 17:25:23 +08:00
|
|
|
|
async checkApp() {
|
2023-11-30 15:43:05 +08:00
|
|
|
|
if (!app.requestSingleInstanceLock()) {
|
|
|
|
|
|
log.error("已有一个程序正在运行,本次启动阻止");
|
2023-12-02 17:25:23 +08:00
|
|
|
|
app.quit();
|
|
|
|
|
|
// 未获得锁
|
|
|
|
|
|
return false;
|
2023-11-30 15:43:05 +08:00
|
|
|
|
}
|
2023-12-02 17:25:23 +08:00
|
|
|
|
// 聚焦到当前程序
|
|
|
|
|
|
else {
|
|
|
|
|
|
app.on("second-instance", () => {
|
|
|
|
|
|
if (this.mainWindow) {
|
|
|
|
|
|
this.mainWindow.show();
|
|
|
|
|
|
if (this.mainWindow.isMinimized()) this.mainWindow.restore();
|
|
|
|
|
|
this.mainWindow.focus();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
// 获得锁
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化程序
|
|
|
|
|
|
async init() {
|
|
|
|
|
|
log.info("主进程初始化");
|
2023-11-29 17:03:51 +08:00
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 启动网易云 API
|
2023-12-12 11:03:20 +08:00
|
|
|
|
try {
|
|
|
|
|
|
this.ncmServer = await startNcmServer({
|
|
|
|
|
|
port: import.meta.env.MAIN_VITE_SERVER_PORT,
|
|
|
|
|
|
host: import.meta.env.MAIN_VITE_SERVER_HOST,
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error("启动网易云 API 失败:", error);
|
|
|
|
|
|
}
|
2023-11-23 18:28:53 +08:00
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 非开发环境启动代理
|
2023-12-13 10:14:54 +08:00
|
|
|
|
if (!is.dev) {
|
|
|
|
|
|
this.mainServer = await startMainServer();
|
|
|
|
|
|
}
|
2023-11-23 18:28:53 +08:00
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 注册应用协议
|
2023-12-16 16:07:51 +08:00
|
|
|
|
app.setAsDefaultProtocolClient("SPlayer");
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 应用程序准备好之前注册
|
|
|
|
|
|
protocol.registerSchemesAsPrivileged([
|
|
|
|
|
|
{ scheme: "app", privileges: { secure: true, standard: true } },
|
|
|
|
|
|
]);
|
2023-11-30 15:02:51 +08:00
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 主应用程序事件
|
|
|
|
|
|
this.mainAppEvents();
|
|
|
|
|
|
}
|
2023-11-30 15:02:51 +08:00
|
|
|
|
|
2023-11-23 18:28:53 +08:00
|
|
|
|
// 创建主窗口
|
2023-11-30 15:43:05 +08:00
|
|
|
|
createWindow() {
|
|
|
|
|
|
// 创建浏览器窗口
|
|
|
|
|
|
this.mainWindow = new BrowserWindow({
|
2023-12-16 16:07:51 +08:00
|
|
|
|
title: app.getName() || "SPlayer",
|
2023-12-01 15:29:14 +08:00
|
|
|
|
width: this.store.get("windowSize.width") || 1280, // 窗口宽度
|
|
|
|
|
|
height: this.store.get("windowSize.height") || 740, // 窗口高度
|
2023-11-30 15:43:05 +08:00
|
|
|
|
minHeight: 700, // 最小高度
|
|
|
|
|
|
minWidth: 1200, // 最小宽度
|
|
|
|
|
|
center: true, // 是否出现在屏幕居中的位置
|
|
|
|
|
|
show: false, // 初始时不显示窗口
|
|
|
|
|
|
frame: false, // 无边框
|
2024-05-28 09:47:33 +08:00
|
|
|
|
// transparent: true, // 透明窗口
|
2023-11-30 15:43:05 +08:00
|
|
|
|
titleBarStyle: "customButtonsOnHover", // Macos 隐藏菜单栏
|
|
|
|
|
|
autoHideMenuBar: true, // 失去焦点后自动隐藏菜单栏
|
|
|
|
|
|
// 图标配置
|
2024-05-24 11:19:20 +08:00
|
|
|
|
icon: nativeImage.createFromPath(join(__dirname, "../../public/imgs/icons/favicon.png")),
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 预加载
|
|
|
|
|
|
webPreferences: {
|
2024-01-12 11:08:35 +08:00
|
|
|
|
// devTools: is.dev,
|
|
|
|
|
|
preload: join(__dirname, "../preload/index.mjs"),
|
2023-11-30 15:43:05 +08:00
|
|
|
|
sandbox: false,
|
|
|
|
|
|
webSecurity: false,
|
|
|
|
|
|
hardwareAcceleration: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 窗口准备就绪时显示窗口
|
2023-12-01 15:29:14 +08:00
|
|
|
|
this.mainWindow.once("ready-to-show", () => {
|
2023-11-30 15:43:05 +08:00
|
|
|
|
this.mainWindow.show();
|
|
|
|
|
|
// mainWindow.maximize();
|
2023-12-01 15:29:14 +08:00
|
|
|
|
this.store.set("windowSize", this.mainWindow.getBounds());
|
2023-11-30 15:43:05 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2023-11-30 17:59:13 +08:00
|
|
|
|
// 主窗口事件
|
|
|
|
|
|
this.mainWindowEvents();
|
|
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 设置窗口打开处理程序
|
|
|
|
|
|
this.mainWindow.webContents.setWindowOpenHandler((details) => {
|
|
|
|
|
|
shell.openExternal(details.url);
|
|
|
|
|
|
return { action: "deny" };
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染路径
|
|
|
|
|
|
// 在开发模式
|
|
|
|
|
|
if (is.dev && process.env.ELECTRON_RENDERER_URL) {
|
|
|
|
|
|
this.mainWindow.loadURL(process.env.ELECTRON_RENDERER_URL);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 生产模式
|
2023-12-13 10:14:54 +08:00
|
|
|
|
else {
|
2024-06-21 00:11:47 +08:00
|
|
|
|
console.log("生产模式渲染端口: " + process.env.MAIN_VITE_MAIN_PORT ?? 7899);
|
|
|
|
|
|
this.mainWindow.loadURL(`http://127.0.0.1:${process.env.MAIN_VITE_MAIN_PORT ?? 7899}`);
|
2023-12-13 10:14:54 +08:00
|
|
|
|
}
|
2024-04-25 18:17:50 +08:00
|
|
|
|
|
|
|
|
|
|
// 配置网络代理
|
|
|
|
|
|
const proxyRules = this.store.get("proxy");
|
|
|
|
|
|
if (proxyRules) {
|
|
|
|
|
|
this.mainWindow.webContents.session.setProxy({ proxyRules }, (result) => {
|
|
|
|
|
|
console.info("网络代理配置:", result);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2023-11-30 15:43:05 +08:00
|
|
|
|
}
|
2023-11-23 18:28:53 +08:00
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 主应用程序事件
|
|
|
|
|
|
mainAppEvents() {
|
2023-12-12 18:11:28 +08:00
|
|
|
|
app.whenReady().then(async () => {
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 创建主窗口
|
|
|
|
|
|
this.createWindow();
|
|
|
|
|
|
// 引入主 Ipc
|
2024-04-25 18:17:50 +08:00
|
|
|
|
mainIpcMain(this.mainWindow, this.store);
|
2023-12-16 16:07:51 +08:00
|
|
|
|
// 系统托盘
|
|
|
|
|
|
createSystemTray(this.mainWindow);
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 注册快捷键
|
|
|
|
|
|
createGlobalShortcut(this.mainWindow);
|
|
|
|
|
|
});
|
2023-12-01 15:29:14 +08:00
|
|
|
|
|
2023-12-04 13:35:06 +08:00
|
|
|
|
// 开发环境下 F12 打开控制台
|
2023-11-30 15:43:05 +08:00
|
|
|
|
app.on("browser-window-created", (_, window) => {
|
|
|
|
|
|
optimizer.watchWindowShortcuts(window);
|
|
|
|
|
|
});
|
2023-12-01 15:29:14 +08:00
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 在 macOS 上,当单击 Dock 图标且没有其他窗口时,通常会重新创建窗口
|
|
|
|
|
|
app.on("activate", () => {
|
|
|
|
|
|
if (BrowserWindow.getAllWindows().length === 0) this.createWindow();
|
|
|
|
|
|
});
|
2023-12-01 15:29:14 +08:00
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 自定义协议
|
|
|
|
|
|
app.on("open-url", (_, url) => {
|
|
|
|
|
|
console.log("Received custom protocol URL:", url);
|
|
|
|
|
|
});
|
2023-12-01 15:29:14 +08:00
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 将要退出
|
|
|
|
|
|
app.on("will-quit", () => {
|
|
|
|
|
|
// 注销全部快捷键
|
|
|
|
|
|
globalShortcut.unregisterAll();
|
|
|
|
|
|
});
|
2023-12-01 15:29:14 +08:00
|
|
|
|
|
2023-11-30 15:43:05 +08:00
|
|
|
|
// 当所有窗口都关闭时退出应用,macOS 除外
|
|
|
|
|
|
app.on("window-all-closed", () => {
|
2023-12-04 13:35:06 +08:00
|
|
|
|
if (!platform.isMacOS) {
|
2023-11-30 15:43:05 +08:00
|
|
|
|
app.quit();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2023-11-23 18:28:53 +08:00
|
|
|
|
}
|
2023-11-30 17:59:13 +08:00
|
|
|
|
|
|
|
|
|
|
// 主窗口事件
|
|
|
|
|
|
mainWindowEvents() {
|
|
|
|
|
|
this.mainWindow.on("show", () => {
|
|
|
|
|
|
this.mainWindow.webContents.send("lyricsScroll");
|
|
|
|
|
|
});
|
2023-12-01 15:29:14 +08:00
|
|
|
|
|
2023-11-30 17:59:13 +08:00
|
|
|
|
// this.mainWindow.on("hide", () => {
|
|
|
|
|
|
// console.info("窗口隐藏");
|
|
|
|
|
|
// });
|
2023-12-01 15:29:14 +08:00
|
|
|
|
|
2023-11-30 17:59:13 +08:00
|
|
|
|
this.mainWindow.on("focus", () => {
|
|
|
|
|
|
this.mainWindow.webContents.send("lyricsScroll");
|
|
|
|
|
|
});
|
2023-12-01 15:29:14 +08:00
|
|
|
|
|
2023-11-30 17:59:13 +08:00
|
|
|
|
// this.mainWindow.on("blur", () => {
|
|
|
|
|
|
// console.info("窗口失去焦点");
|
|
|
|
|
|
// });
|
2023-12-01 15:29:14 +08:00
|
|
|
|
|
|
|
|
|
|
this.mainWindow.on("maximize", () => {
|
|
|
|
|
|
this.mainWindow.webContents.send("windowState", true);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
this.mainWindow.on("unmaximize", () => {
|
|
|
|
|
|
this.mainWindow.webContents.send("windowState", false);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2024-06-21 00:11:47 +08:00
|
|
|
|
this.mainWindow.on("resize", () => {
|
2023-12-01 15:29:14 +08:00
|
|
|
|
this.store.set("windowSize", this.mainWindow.getBounds());
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2024-06-21 00:11:47 +08:00
|
|
|
|
this.mainWindow.on("move", () => {
|
2023-12-01 15:29:14 +08:00
|
|
|
|
this.store.set("windowSize", this.mainWindow.getBounds());
|
|
|
|
|
|
});
|
2023-12-13 17:23:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 窗口关闭
|
|
|
|
|
|
this.mainWindow.on("close", (event) => {
|
2024-06-21 00:11:47 +08:00
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
if (!app.isQuiting) {
|
|
|
|
|
|
this.mainWindow.hide();
|
2023-12-13 17:23:18 +08:00
|
|
|
|
} else {
|
2024-06-21 00:11:47 +08:00
|
|
|
|
app.exit();
|
2023-12-13 17:23:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
2023-11-30 17:59:13 +08:00
|
|
|
|
}
|
2023-11-30 15:43:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
new MainProcess();
|