diff --git a/.env b/.env
index ce099b82..14bb6124 100644
--- a/.env
+++ b/.env
@@ -27,3 +27,14 @@ RENDERER_VITE_SITE_APPLE_LOGO = "/images/logo/favicon-apple.png"
# Cookie
## 咪咕音乐 Cookie
MAIN_VITE_MIGU_COOKIE = ""
+
+# 公告配置
+## 若无需公告,请将标题或内容任意一项设为空即可
+## 公告类型
+RENDERER_VITE_ANN_TYPE = "info"
+## 公告标题
+RENDERER_VITE_ANN_TITLE = ""
+## 公告内容
+RENDERER_VITE_ANN_CONTENT = ""
+## 公告时长(毫秒)不可超过 999999
+RENDERER_VITE_ANN_DURATION = 8000
diff --git a/electron/main/index.js b/electron/main/index.js
index f1237d66..2bef9f0c 100644
--- a/electron/main/index.js
+++ b/electron/main/index.js
@@ -42,18 +42,38 @@ class MainProcess {
},
});
// 初始化
- this.init();
+ this.checkApp().then((lockObtained) => {
+ if (lockObtained) {
+ this.init();
+ }
+ });
}
- // 初始化程序
- async init() {
- log.info("主进程初始化");
-
- // 单例锁
+ // 检查上次程序
+ async checkApp() {
if (!app.requestSingleInstanceLock()) {
- app.quit();
log.error("已有一个程序正在运行,本次启动阻止");
+ app.quit();
+ // 未获得锁
+ return false;
+ }
+ // 聚焦到当前程序
+ 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("主进程初始化");
// 启动网易云 API
this.ncmServer = await startNcmServer({
diff --git a/electron/main/utils/createGlobalShortcut.js b/electron/main/utils/createGlobalShortcut.js
index 4d13167c..917fd9ce 100644
--- a/electron/main/utils/createGlobalShortcut.js
+++ b/electron/main/utils/createGlobalShortcut.js
@@ -7,7 +7,7 @@ import { globalShortcut } from "electron";
const createGlobalShortcut = (win) => {
// 刷新程序
globalShortcut.register("CommandOrControl+R", () => {
- win?.reload();
+ if (win && win.isFocused()) win?.reload();
});
};
diff --git a/electron/main/utils/createSystemInfo.js b/electron/main/utils/createSystemInfo.js
index 12ba76ba..7ac32ac3 100644
--- a/electron/main/utils/createSystemInfo.js
+++ b/electron/main/utils/createSystemInfo.js
@@ -14,6 +14,8 @@ const createSystemInfo = (win) => {
app.setUserTasks([]);
// 系统托盘
const mainTray = new Tray(join(__dirname, "../../public/images/logo/favicon.png"));
+ // 默认托盘菜单
+ Menu.setApplicationMenu(Menu.buildFromTemplate(createTrayMenu(win)));
// 给托盘图标设置气球提示
mainTray.setToolTip(app.getName());
// 歌曲数据改变时
@@ -36,6 +38,10 @@ const createSystemInfo = (win) => {
mainTray.on("right-click", () => {
mainTray.popUpContextMenu(Menu.buildFromTemplate(createTrayMenu(win)));
});
+ // linux 右键菜单
+ if (process.platform === "linux") {
+ mainTray.setContextMenu(Menu.buildFromTemplate(createTrayMenu(win)));
+ }
};
// 生成右键菜单
@@ -69,6 +75,7 @@ const createTrayMenu = (win) => {
{
label: "上一曲",
icon: createIcon("prev"),
+ accelerator: "CommandOrControl+Left",
click: () => {
win.webContents.send("playNextOrPrev", "prev");
},
@@ -76,6 +83,7 @@ const createTrayMenu = (win) => {
{
label: playSongState ? "暂停" : "播放",
icon: createIcon(playSongState ? "pause" : "play"),
+ accelerator: "Space",
click: () => {
win.webContents.send("playOrPause");
},
@@ -83,6 +91,7 @@ const createTrayMenu = (win) => {
{
label: "下一曲",
icon: createIcon("next"),
+ accelerator: "CommandOrControl+Right",
click: () => {
win.webContents.send("playNextOrPrev", "next");
},
diff --git a/package.json b/package.json
index 1b6789cf..7ece3d0d 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
"@rushstack/eslint-patch": "^1.3.3",
"@vitejs/plugin-vue": "^4.3.1",
"@vue/eslint-config-prettier": "^8.0.0",
+ "ajv": "^8.12.0",
"electron": "^25.6.0",
"electron-builder": "^24.6.4",
"electron-log": "^5.0.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 46b5dc3c..317172cc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -88,6 +88,9 @@ devDependencies:
'@vue/eslint-config-prettier':
specifier: ^8.0.0
version: 8.0.0(eslint@8.47.0)(prettier@3.0.2)
+ ajv:
+ specifier: ^8.12.0
+ version: 8.12.0
electron:
specifier: ^25.6.0
version: 25.6.0
@@ -1168,7 +1171,6 @@ packages:
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
uri-js: 4.4.1
- dev: false
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
@@ -3274,7 +3276,6 @@ packages:
/json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
- dev: false
/json-schema-typed@7.0.3:
resolution: {integrity: sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==}
@@ -4209,7 +4210,6 @@ packages:
/require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
- dev: false
/require-main-filename@2.0.0:
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
diff --git a/src/App.vue b/src/App.vue
index 6f45b6e6..74d424fd 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -94,6 +94,27 @@ const music = musicData();
const status = siteStatus();
const settings = siteSettings();
+// 公告数据
+const annShow =
+ import.meta.env.RENDERER_VITE_ANN_TITLE && import.meta.env.RENDERER_VITE_ANN_CONTENT
+ ? true
+ : false;
+const annType = import.meta.env.RENDERER_VITE_ANN_TYPE;
+const annTitle = import.meta.env.RENDERER_VITE_ANN_TITLE;
+const annContene = import.meta.env.RENDERER_VITE_ANN_CONTENT;
+const annDuration = Number(import.meta.env.RENDERER_VITE_ANN_DURATION);
+
+// 显示公告
+const showAnnouncements = () => {
+ if (annShow) {
+ $notification[annType]({
+ content: annTitle,
+ meta: annContene,
+ duration: annDuration,
+ });
+ }
+};
+
// 网络无法连接
const canNotConnect = (error) => {
console.error("网络连接错误:", error.message);
@@ -120,11 +141,13 @@ onMounted(() => {
// 全局事件
globalEvents(router);
// 键盘监听
- window.addEventListener("keyup", globalShortcut);
+ if (!checkPlatform.electron()) window.addEventListener("keyup", globalShortcut);
+ // 显示公告
+ showAnnouncements();
});
onUnmounted(() => {
- window.removeEventListener("keyup", globalShortcut);
+ if (!checkPlatform.electron()) window.removeEventListener("keyup", globalShortcut);
});
diff --git a/src/assets/icon.json b/src/assets/icon.json
index 6b886df6..e29f0550 100644
--- a/src/assets/icon.json
+++ b/src/assets/icon.json
@@ -80,5 +80,6 @@
"download": "M16.59 9H15V4c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v5H7.41c-.89 0-1.34 1.08-.71 1.71l4.59 4.59c.39.39 1.02.39 1.41 0l4.59-4.59c.63-.63.19-1.71-.7-1.71zM5 19c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H6c-.55 0-1 .45-1 1z",
"radio": "M3.24 6.15C2.51 6.43 2 7.17 2 8v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8c0-1.11-.89-2-2-2H8.3l8.26-3.34L15.88 1L3.24 6.15zM7 20c-1.66 0-3-1.34-3-3s1.34-3 3-3s3 1.34 3 3s-1.34 3-3 3zm13-8h-2v-2h-2v2H4V8h16v4z",
"person-add": "M15.39 14.56C13.71 13.7 11.53 13 9 13s-4.71.7-6.39 1.56A2.97 2.97 0 0 0 1 17.22V20h16v-2.78c0-1.12-.61-2.15-1.61-2.66zM9 12c2.21 0 4-1.79 4-4s-1.79-4-4-4s-4 1.79-4 4s1.79 4 4 4zm11-3V7c0-.55-.45-1-1-1s-1 .45-1 1v2h-2c-.55 0-1 .45-1 1s.45 1 1 1h2v2c0 .55.45 1 1 1s1-.45 1-1v-2h2c.55 0 1-.45 1-1s-.45-1-1-1h-2z",
- "person-remove": "M14 8c0-2.21-1.79-4-4-4S6 5.79 6 8s1.79 4 4 4s4-1.79 4-4zM2 18v1c0 .55.45 1 1 1h14c.55 0 1-.45 1-1v-1c0-2.66-5.33-4-8-4s-8 1.34-8 4zm16-8h4c.55 0 1 .45 1 1s-.45 1-1 1h-4c-.55 0-1-.45-1-1s.45-1 1-1z"
+ "person-remove": "M14 8c0-2.21-1.79-4-4-4S6 5.79 6 8s1.79 4 4 4s4-1.79 4-4zM2 18v1c0 .55.45 1 1 1h14c.55 0 1-.45 1-1v-1c0-2.66-5.33-4-8-4s-8 1.34-8 4zm16-8h4c.55 0 1 .45 1 1s-.45 1-1 1h-4c-.55 0-1-.45-1-1s.45-1 1-1z",
+ "github": "M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5c.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34c-.46-1.16-1.11-1.47-1.11-1.47c-.91-.62.07-.6.07-.6c1 .07 1.53 1.03 1.53 1.03c.87 1.52 2.34 1.07 2.91.83c.09-.65.35-1.09.63-1.34c-2.22-.25-4.55-1.11-4.55-4.92c0-1.11.38-2 1.03-2.71c-.1-.25-.45-1.29.1-2.64c0 0 .84-.27 2.75 1.02c.79-.22 1.65-.33 2.5-.33c.85 0 1.71.11 2.5.33c1.91-1.29 2.75-1.02 2.75-1.02c.55 1.35.2 2.39.1 2.64c.65.71 1.03 1.6 1.03 2.71c0 3.82-2.34 4.66-4.57 4.91c.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2Z"
}
diff --git a/src/components/Nav/MainNav.vue b/src/components/Nav/MainNav.vue
index 2768e4ec..0f5c10d3 100644
--- a/src/components/Nav/MainNav.vue
+++ b/src/components/Nav/MainNav.vue
@@ -28,6 +28,14 @@
+
+
+
+
+
+
+
+
@@ -36,12 +44,19 @@
diff --git a/src/components/Player/MainControl.vue b/src/components/Player/MainControl.vue
index 7f11b4a8..ce6a49b4 100644
--- a/src/components/Player/MainControl.vue
+++ b/src/components/Player/MainControl.vue
@@ -171,6 +171,7 @@
{
e.stopPropagation();
// 播放或暂停
- if (e.ctrlKey && e.code === "Space") playOrPause();
+ if (e.code === "Space") playOrPause();
// 调整音量
- if (e.ctrlKey && (e.code === "ArrowUp" || e.code === "ArrowDown")) {
+ if (e.code === "ArrowUp" || e.code === "ArrowDown") {
const music = musicData();
const volume = music.playVolume;
const delta = e.code === "ArrowUp" ? 0.1 : -0.1;