Skip to content

Commit 9b5192e

Browse files
committed
🐞 fix: 神秘的小修复
1 parent a414c23 commit 9b5192e

33 files changed

Lines changed: 186 additions & 265 deletions

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Set `SKIP_NATIVE_BUILD=true` to skip Rust native module compilation during dev.
4646
### Native Modules (`native/`)
4747

4848
Rust-based, built via `scripts/build-native.ts`:
49+
4950
- `taskbar-lyric` — Windows taskbar lyrics display
5051
- `external-media-integration` — OS media integration
5152
- `smtc-for-splayer` — Windows System Media Transport Controls

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
> [!CAUTION]
2-
> # 本项目停止维护
3-
> 后续版本请使用 [SPlayer-Next](https://github.com/SPlayer-Dev/SPlayer-Next)
4-
2+
>
3+
> # 本项目进入维护模式
4+
>
5+
> 项目已进入维护模式,后续仅进行必要的维护与重大问题修复,不再主动开发新功能
6+
>
7+
> 新功能及后续版本请移步 [SPlayer-Next](https://github.com/SPlayer-Dev/SPlayer-Next)
58
69
<div align="center">
710
<img alt="logo" height="100" width="100" src="public/icons/favicon.png" />

docs/api.md

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -296,29 +296,6 @@
296296

297297
---
298298

299-
### 歌曲宝解锁
300-
301-
**接口**: `GET /api/unblock/gequbao?keyword={keyword}`
302-
303-
**描述**: 获取歌曲宝解锁后的播放链接
304-
305-
**请求参数**:
306-
307-
- `keyword` (必需): 搜索关键词(歌曲名-歌手名)
308-
- `songName` (可选): 歌曲名称,用于匹配校验
309-
- `artist` (可选): 歌手名称,用于匹配校验
310-
311-
**响应示例**:
312-
313-
```json
314-
{
315-
"code": 200,
316-
"url": "https://..."
317-
}
318-
```
319-
320-
---
321-
322299
## 全部 API 列表
323300

324301
**接口**: `GET /api`

electron/main/services/MusicCacheService.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ export class MusicCacheService {
1515
private downloadingTasks: Map<string, Promise<string>> = new Map();
1616
/** 音质优先级 */
1717
private readonly qualityPriority: Record<string, number> = {
18-
"master": 100,
19-
"dolby": 95,
20-
"spatial": 90,
21-
"surround": 85,
18+
master: 100,
19+
dolby: 95,
20+
spatial: 90,
21+
surround: 85,
2222
"hi-res": 80,
23-
"sq": 70,
24-
"hq": 60,
25-
"mq": 50,
26-
"lq": 40,
27-
"standard": 40,
23+
sq: 70,
24+
hq: 60,
25+
mq: 50,
26+
lq: 40,
27+
standard: 40,
2828
};
2929

3030
private constructor() {

electron/main/store/index.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ export interface StoreType {
7272
enabled: boolean;
7373
};
7474
};
75-
/** 更新通道 */
76-
updateChannel?: "stable" | "nightly";
7775
}
7876

7977
/**
@@ -118,7 +116,6 @@ export const useStore = () => {
118116
},
119117
downloadThreadCount: 8,
120118
enableDownloadHttp2: true,
121-
updateChannel: "stable",
122119
},
123120
});
124121
};

electron/main/update/index.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { type BrowserWindow } from "electron";
22
import { updateLog } from "../logger";
33
import electronUpdater from "electron-updater";
44
import { isDev } from "../utils/config";
5-
import { useStore } from "../store";
65

76
// import
87
const { autoUpdater } = electronUpdater;
@@ -70,15 +69,6 @@ export const checkUpdate = (win: BrowserWindow, showTip: boolean = false) => {
7069
// 更改提示
7170
isShowTip = showTip;
7271

73-
// 获取更新通道
74-
const store = useStore();
75-
const updateChannel = store.get("updateChannel") || "stable";
76-
const allowPrerelease = updateChannel === "nightly";
77-
78-
// 设置更新通道
79-
autoUpdater.channel = updateChannel === "nightly" ? "nightly" : "latest";
80-
// 设置是否允许 Pre-release
81-
autoUpdater.allowPrerelease = allowPrerelease;
8272
// 检查更新
8373
autoUpdater
8474
.checkForUpdates()

electron/main/windows/taskbar-lyric-window.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,10 @@ class TaskbarLyricWindow {
249249
const scaleFactor = primaryDisplay.scaleFactor;
250250
const store = useStore();
251251
const GAP = store.get("taskbar.margin", 10) * scaleFactor;
252-
const positionSetting = store.get("taskbar.position", "automatic") as TaskbarConfig["position"];
252+
const positionSetting = store.get(
253+
"taskbar.position",
254+
"automatic",
255+
) as TaskbarConfig["position"];
253256
// autoMaxWidth 开启时无上限(撑满可用空间),关闭时按设置的像素值(逻辑像素)限制
254257
const autoMaxWidth = store.get("taskbar.autoMaxWidth", true);
255258
const maxWidthLogical = store.get("taskbar.maxWidth", 400);

electron/server/netease/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ import { pathCase } from "change-case";
33
import { serverLog } from "../../main/logger";
44
import { useStore } from "../../main/store";
55
import { defaultAMLLDbServer } from "../../main/utils/config";
6+
import { ensureNcmConfig, NON_API_EXPORTS } from "./ncm-config";
67
import NeteaseCloudMusicApi from "@neteasecloudmusicapienhanced/api";
78

89
// 初始化 NcmAPI
910
export const initNcmAPI = async (fastify: FastifyInstance) => {
11+
// 预热配置
12+
void ensureNcmConfig();
13+
1014
// 主信息
1115
fastify.get("/netease", (_, reply) => {
1216
reply.send({
@@ -24,6 +28,8 @@ export const initNcmAPI = async (fastify: FastifyInstance) => {
2428

2529
// 将 path-case 转回 camelCase 或直接匹配下划线路由
2630
const routerName = Object.keys(NeteaseCloudMusicApi).find((key) => {
31+
// 排除包的服务层导出
32+
if (NON_API_EXPORTS.has(key)) return false;
2733
// 跳过非函数属性
2834
if (typeof (NeteaseCloudMusicApi as Record<string, unknown>)[key] !== "function")
2935
return false;
@@ -40,6 +46,9 @@ export const initNcmAPI = async (fastify: FastifyInstance) => {
4046
)[routerName];
4147
serverLog.log("🌐 Request NcmAPI:", requestPath);
4248

49+
// 等待 xeapi 公钥等配置就绪
50+
await ensureNcmConfig();
51+
4352
try {
4453
const result = await neteaseApi({
4554
...(req.query as Record<string, unknown>),
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @neteasecloudmusicapienhanced/api 部分内部模块未导出类型声明,此处补充
2+
3+
// generateConfig:注册匿名 token 并获取 xeapi 公钥
4+
declare module "@neteasecloudmusicapienhanced/api/generateConfig.js" {
5+
const generateConfig: () => Promise<void>;
6+
export default generateConfig;
7+
}
8+
9+
// server.js:服务层导出
10+
declare module "@neteasecloudmusicapienhanced/api/server.js" {
11+
const serverModule: Record<string, unknown>;
12+
export default serverModule;
13+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// 封装对 @neteasecloudmusicapienhanced/api 内部模块的依赖
2+
// 该包未对外导出 generateConfig / server 的稳定接口,此处集中处理「伸进内部文件」的耦合
3+
import { existsSync } from "fs";
4+
import { join } from "path";
5+
import { tmpdir } from "os";
6+
import { serverLog } from "../../main/logger";
7+
import generateConfig from "@neteasecloudmusicapienhanced/api/generateConfig.js";
8+
import ncmServerExports from "@neteasecloudmusicapienhanced/api/server.js";
9+
10+
// 包 server.js 的导出(serveNcmApi、getModulesDefinitions 等)会被合并到主入口对象上,
11+
// 它们不是网易云接口模块,必须从动态路由中排除,避免被当作 HTTP 接口调用(如 /netease/serve-ncm-api)。
12+
export const NON_API_EXPORTS = new Set<string>([
13+
...Object.keys(ncmServerExports ?? {}),
14+
"server", // 主入口对象上的 server getter
15+
]);
16+
17+
// xeapi 公钥缓存文件路径(由 generateConfig 写入系统临时目录)
18+
const xeapiPublicKeyPath = join(tmpdir(), "xeapi_public_key");
19+
20+
let ncmConfigReady = false;
21+
let ncmConfigPromise: Promise<void> | null = null;
22+
23+
/**
24+
* 确保 NcmAPI 配置就绪
25+
*
26+
* 新版本 @neteasecloudmusicapienhanced/api 的 song/url/v1 等接口改用 xeapi 加密,
27+
* 必须先调用 generateConfig 注册匿名 token 并获取 xeapi 公钥,
28+
* 否则请求会抛出 "xeapi public key is missing"。
29+
*
30+
* 不阻塞服务启动;失败时不锁死状态,下次调用会自动重试。
31+
*/
32+
export const ensureNcmConfig = (): Promise<void> => {
33+
if (ncmConfigReady) return Promise.resolve();
34+
if (!ncmConfigPromise) {
35+
ncmConfigPromise = generateConfig()
36+
.then(() => {
37+
if (existsSync(xeapiPublicKeyPath)) {
38+
ncmConfigReady = true;
39+
serverLog.info("🔑 NcmAPI xeapi 公钥初始化完成");
40+
} else {
41+
serverLog.error("❌ NcmAPI xeapi 公钥生成失败,下次请求将重试");
42+
}
43+
})
44+
.catch((error: unknown) => {
45+
serverLog.error("❌ NcmAPI 配置初始化失败:", error);
46+
})
47+
.finally(() => {
48+
// 释放,未成功时允许后续请求重新尝试
49+
ncmConfigPromise = null;
50+
});
51+
}
52+
return ncmConfigPromise;
53+
};

0 commit comments

Comments
 (0)