Skip to content

Commit 895843a

Browse files
committed
🐞 fix: 完善自定义协议处理逻辑
1 parent e50bef7 commit 895843a

9 files changed

Lines changed: 318 additions & 12 deletions

File tree

electron/main/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class MainProcess {
8181
// 自定义协议
8282
app.on("open-url", (_, url) => {
8383
processLog.log("🔗 Received custom protocol URL:", url);
84-
trySendCustomProtocol(url)
84+
trySendCustomProtocol(url);
8585
});
8686

8787
// 将要退出

electron/main/ipc/ipc-window.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ import { app, ipcMain } from "electron";
22
import { useStore } from "../store";
33
import { isDev } from "../utils/config";
44
import { initThumbar } from "../thumbar";
5+
import { processProtocolFromCommand } from "../utils/protocol";
56
import mainWindow from "../windows/main-window";
67
import loadWindow from "../windows/load-window";
78
import loginWindow from "../windows/login-window";
89

10+
// 记录是否已处理启动协议
11+
let isProtocolProcessed = false;
12+
913
/**
1014
* 窗口 IPC 通信
1115
* @returns void
@@ -42,7 +46,14 @@ const initWindowsIpc = (): void => {
4246
}
4347
}, 100);
4448
// 初始化缩略图工具栏
45-
if (mainWin) initThumbar(mainWin);
49+
if (mainWin) {
50+
initThumbar(mainWin);
51+
// 检查是否有自定义协议启动(仅执行一次)
52+
if (!isProtocolProcessed) {
53+
processProtocolFromCommand(process.argv);
54+
isProtocolProcessed = true;
55+
}
56+
}
4657
});
4758

4859
// 最小化

electron/main/utils/protocol.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,20 @@ import { app } from "electron";
22
import { processLog } from "../logger";
33
import mainWindow from "../windows/main-window";
44

5+
/**
6+
* 注册自定义协议
7+
* 用于在外部打开应用时传递 URL 参数
8+
*/
59
export const registerCustomProtocol = () => {
610
app.setAsDefaultProtocolClient("orpheus");
711
processLog.info("🔗 Registered custom protocol");
812
};
913

14+
/**
15+
* 尝试发送自定义协议 URL 到主窗口
16+
* @param str 自定义协议字符串
17+
* @returns 是否成功发送
18+
*/
1019
export const trySendCustomProtocol = (str: string): boolean => {
1120
try {
1221
if (str.startsWith("orpheus://")) {
@@ -18,13 +27,18 @@ export const trySendCustomProtocol = (str: string): boolean => {
1827
processLog.error("❌ Failed to send protocol url", e);
1928
return false;
2029
}
21-
}
30+
};
2231

32+
/**
33+
* 从命令行参数中处理自定义协议
34+
* @param command 命令行参数数组
35+
* @returns 是否成功处理协议
36+
*/
2337
export const processProtocolFromCommand = (command: string[]): boolean => {
2438
// 这里第一个参数是程序名称 忽略此 仅遍历参数
2539
for (let i = 1; i < command.length; i++) {
2640
const arg = command[i];
2741
if (trySendCustomProtocol(arg)) return true;
2842
}
2943
return false;
30-
}
44+
};

src/components/Layout/Menu.vue

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ const menuOptions = computed<MenuOption[] | MenuGroupOption[]>(() => {
132132
show: isLogin() === 1 && !settingStore.hideCloud,
133133
icon: renderIcon("Cloud"),
134134
},
135+
// {
136+
// key: "download",
137+
// link: "download",
138+
// label: "下载管理",
139+
// show: isElectron,
140+
// icon: renderIcon("Download"),
141+
// },
135142
{
136143
key: "local",
137144
link: "local",
@@ -283,8 +290,8 @@ const menuUpdate = (key: string, item: MenuOption) => {
283290
284291
// 选中菜单项
285292
const checkMenuItem = () => {
286-
// 当前路由名称
287-
let routerName =
293+
// 当前路由名称
294+
let routerName =
288295
(router.currentRoute.value.matched?.[0]?.name as string) ||
289296
(router.currentRoute.value?.name as string);
290297
if (!routerName) return;
@@ -296,6 +303,10 @@ const checkMenuItem = () => {
296303
if (routerName.startsWith("like-") && routerName !== "like-songs") {
297304
routerName = "like";
298305
}
306+
// 处理下载子路由
307+
if (routerName.startsWith("download-")) {
308+
routerName = "download";
309+
}
299310
// 显示菜单
300311
menuRef.value?.showOption(routerName);
301312
// 高亮菜单

src/router/routes.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,26 @@ const appRoutes: Array<RouteRecordRaw> = [
225225
},
226226
],
227227
},
228+
// 下载管理
229+
{
230+
path: "/download",
231+
name: "download",
232+
meta: { needApp: true },
233+
component: () => import("@/views/Download/layout.vue"),
234+
redirect: "/download/downloaded",
235+
children: [
236+
{
237+
path: "downloaded",
238+
name: "download-downloaded",
239+
component: () => import("@/views/Download/downloaded.vue"),
240+
},
241+
{
242+
path: "downloading",
243+
name: "download-downloading",
244+
component: () => import("@/views/Download/downloading.vue"),
245+
},
246+
],
247+
},
228248
// 本地歌曲
229249
{
230250
path: "/local",

src/utils/protocal.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ export const handleProtocolUrl = (url: string) => {
2222
default:
2323
break;
2424
}
25-
}
26-
27-
25+
};
2826

2927
export const handleOpenOrpheus = async (url: string) => {
3028
const data = parseOrpheus(url);
@@ -48,8 +46,31 @@ const parseOrpheus = (url: string): OrpheusData | undefined => {
4846
// 形如 `{"type":"song","id":"1826361712","cmd":"play"}`
4947

5048
if (!url.startsWith("orpheus://")) return;
51-
const path = url.replace("orpheus://", "");
52-
const jsonString = atob(path);
49+
let path = url.replace("orpheus://", "");
50+
// 移除末尾可能存在的斜杠
51+
if (path.endsWith("/")) {
52+
path = path.slice(0, -1);
53+
}
54+
// 尝试 URL 解码
55+
try {
56+
path = decodeURIComponent(path);
57+
} catch (e) {
58+
console.warn("URL Decode failed, using original path:", e);
59+
}
60+
// 处理 URL-safe Base64
61+
path = path.replace(/-/g, "+").replace(/_/g, "/");
62+
// 补全 Base64 填充
63+
const padding = path.length % 4;
64+
if (padding > 0) {
65+
path += "=".repeat(4 - padding);
66+
}
67+
let jsonString: string;
68+
try {
69+
jsonString = atob(path);
70+
} catch (e) {
71+
console.error("❌ Failed to decode base64:", path, e);
72+
return;
73+
}
5374
let data: OrpheusData;
5475
try {
5576
const json = JSON.parse(jsonString);
@@ -59,4 +80,4 @@ const parseOrpheus = (url: string): OrpheusData | undefined => {
5980
return;
6081
}
6182
return data;
62-
}
83+
};

src/views/Download/downloaded.vue

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<template>
2+
<div class="download-downloaded">
3+
<SongList
4+
:data="data"
5+
:loading="loading"
6+
/>
7+
</div>
8+
</template>
9+
10+
<script setup lang="ts">
11+
import type { SongType } from "@/types/main";
12+
import SongList from "@/components/List/SongList.vue";
13+
14+
defineProps<{
15+
data: SongType[];
16+
loading: boolean;
17+
}>();
18+
</script>
19+
20+
<style lang="scss" scoped>
21+
.download-downloaded {
22+
height: 100%;
23+
}
24+
</style>

src/views/Download/downloading.vue

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<template>
2+
<div class="download-downloading">
3+
<n-empty description="暂无正在下载的任务" class="empty" />
4+
</div>
5+
</template>
6+
7+
<style lang="scss" scoped>
8+
.download-downloading {
9+
height: 100%;
10+
display: flex;
11+
align-items: center;
12+
justify-content: center;
13+
}
14+
</style>

0 commit comments

Comments
 (0)