Skip to content

Commit ccfc7ad

Browse files
committed
🔧 refactor: 优化缓存服务
1 parent 1b9575b commit ccfc7ad

8 files changed

Lines changed: 107 additions & 335 deletions

File tree

components.d.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ declare module 'vue' {
8282
NGi: typeof import('naive-ui')['NGi']
8383
NGlobalStyle: typeof import('naive-ui')['NGlobalStyle']
8484
NGrid: typeof import('naive-ui')['NGrid']
85-
NGridItem: typeof import('naive-ui')['NGridItem']
8685
NH1: typeof import('naive-ui')['NH1']
8786
NH2: typeof import('naive-ui')['NH2']
8887
NH3: typeof import('naive-ui')['NH3']
@@ -125,7 +124,6 @@ declare module 'vue' {
125124
NTag: typeof import('naive-ui')['NTag']
126125
NText: typeof import('naive-ui')['NText']
127126
NThing: typeof import('naive-ui')['NThing']
128-
NUpload: typeof import('naive-ui')['NUpload']
129127
NVirtualList: typeof import('naive-ui')['NVirtualList']
130128
OtherSetting: typeof import('./src/components/Setting/OtherSetting.vue')['default']
131129
PersonalFM: typeof import('./src/components/Player/PersonalFM.vue')['default']
@@ -159,7 +157,6 @@ declare module 'vue' {
159157
SongUnlockManager: typeof import('./src/components/Modal/Setting/SongUnlockManager.vue')['default']
160158
SvgIcon: typeof import('./src/components/Global/SvgIcon.vue')['default']
161159
TextContainer: typeof import('./src/components/Global/TextContainer.vue')['default']
162-
ThemeConfig: typeof import('./src/components/Modal/Setting/ThemeConfig.vue')['default']
163160
ThirdSetting: typeof import('./src/components/Setting/ThirdSetting.vue')['default']
164161
UpdateApp: typeof import('./src/components/Modal/UpdateApp.vue')['default']
165162
UpdatePlaylist: typeof import('./src/components/Modal/UpdatePlaylist.vue')['default']

electron/main/services/CacheService.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,21 @@ export class CacheService {
130130

131131
for (const type of Object.keys(this.CACHE_SUB_DIR) as CacheResourceType[]) {
132132
const dir = join(basePath, this.CACHE_SUB_DIR[type]);
133-
if (!existsSync(dir)) await mkdir(dir, { recursive: true });
133+
if (!existsSync(dir)) {
134+
await mkdir(dir, { recursive: true });
135+
} else {
136+
// 清理可能残留的临时文件 (.tmp)
137+
try {
138+
const files = await readdir(dir);
139+
for (const file of files) {
140+
if (file.endsWith(".tmp")) {
141+
await rm(join(dir, file), { force: true });
142+
}
143+
}
144+
} catch (e) {
145+
cacheLog.warn(`⚠️ 无法清理目录中的临时文件: ${dir}`, e);
146+
}
147+
}
134148
// 计算初始大小
135149
this.sizes[type] = await this.calculateDirSize(dir);
136150
}

electron/main/services/LocalMusicService.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { nativeImage } from "electron";
12
import { join, basename } from "path";
23
import { readFile, mkdir } from "fs/promises";
34
import { CacheService } from "./CacheService";
@@ -7,7 +8,6 @@ import { useStore } from "../store";
78
import { type IAudioMetadata, parseFile } from "music-metadata";
89
import FastGlob, { type Entry } from "fast-glob";
910
import pLimit from "p-limit";
10-
import sharp from "sharp";
1111

1212
/** 当前本地音乐库 DB 版本,用于控制缓存结构升级 */
1313
const CURRENT_DB_VERSION = 2;
@@ -138,18 +138,34 @@ export class LocalMusicService {
138138
const { coverDir } = this.paths;
139139
const picture = metadata.common.picture?.[0];
140140
if (!picture) return undefined;
141-
const fileName = `${fileId}.webp`;
141+
142+
// 使用 jpg 格式,兼容性更好且无需外部依赖
143+
const fileName = `${fileId}.jpg`;
142144
const savePath = join(coverDir, fileName);
145+
143146
// 已存在
144147
if (existsSync(savePath)) return fileName;
145-
// 压缩封面处理
146-
const cacheService = CacheService.getInstance();
147-
const buffer = await sharp(picture.data)
148-
.resize(256, 256, { fit: "cover", position: "centre" })
149-
.webp({ quality: 80 })
150-
.toBuffer();
151-
await cacheService.put("local-data", `covers/${fileName}`, buffer);
152-
return fileName;
148+
149+
try {
150+
const img = nativeImage.createFromBuffer(Buffer.from(picture.data));
151+
if (img.isEmpty()) return undefined;
152+
153+
// 调整大小并压缩
154+
const buffer = img
155+
.resize({
156+
width: 256,
157+
height: 256,
158+
quality: "better",
159+
})
160+
.toJPEG(80);
161+
162+
const cacheService = CacheService.getInstance();
163+
await cacheService.put("local-data", `covers/${fileName}`, buffer);
164+
return fileName;
165+
} catch (e) {
166+
console.error("Failed to extract cover using nativeImage:", e);
167+
return undefined;
168+
}
153169
}
154170

155171
/**

electron/main/services/MusicCacheService.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { existsSync, createWriteStream } from "fs";
2-
import { unlink } from "fs/promises";
2+
import { unlink, rename } from "fs/promises";
33
import { pipeline } from "stream/promises";
44
import { CacheService } from "./CacheService";
55
import { useStore } from "../store";
@@ -52,9 +52,11 @@ export class MusicCacheService {
5252
// 模糊查找 (API请求失败时,只要有缓存就用)
5353
try {
5454
const items = await this.cacheService.list("music");
55-
// 查找以 id_ 开头的文件
55+
// 查找以 id_ 开头且以 .sc 结尾的文件(排除 .tmp 文件)
5656
const prefix = `${id}_`;
57-
const match = items.find((item) => item.key.startsWith(prefix));
57+
const match = items.find(
58+
(item) => item.key.startsWith(prefix) && item.key.endsWith(".sc"),
59+
);
5860
if (match) {
5961
return this.cacheService.getFilePath("music", match.key);
6062
}
@@ -91,25 +93,29 @@ export class MusicCacheService {
9193

9294
const key = this.getCacheKey(id, quality);
9395
const filePath = this.cacheService.getFilePath("music", key);
96+
const tempPath = `${filePath}.tmp`;
9497

9598
// 确保目录存在
9699
await this.cacheService.init();
97100

98101
// 下载并写入
99102
try {
100103
const downloadStream = got.stream(url);
101-
const fileStream = createWriteStream(filePath);
104+
const fileStream = createWriteStream(tempPath);
102105

103106
await pipeline(downloadStream, fileStream);
104107

108+
// 下载成功后,将临时文件重命名为正式缓存文件
109+
await rename(tempPath, filePath);
110+
105111
// 更新 CacheService 的大小记录
106112
await this.cacheService.notifyFileChange("music", key);
107113

108114
return filePath;
109115
} catch (error) {
110-
// 下载失败,清理残余
111-
if (existsSync(filePath)) {
112-
await unlink(filePath);
116+
// 下载失败,清理残余的临时文件
117+
if (existsSync(tempPath)) {
118+
await unlink(tempPath).catch(() => {});
113119
}
114120
cacheLog.error("Music download failed:", error);
115121
throw error;

package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@
7575
"pinia": "^3.0.4",
7676
"pinia-plugin-persistedstate": "^4.7.1",
7777
"plyr": "^3.8.3",
78-
"sharp": "^0.34.5",
7978
"sortablejs": "^1.15.6",
8079
"vue-virtual-scroller": "2.0.0-beta.8"
8180
},
@@ -134,7 +133,6 @@
134133
"electron",
135134
"electron-winstaller",
136135
"esbuild",
137-
"sharp",
138136
"vue-demi"
139137
]
140138
}

0 commit comments

Comments
 (0)