Skip to content

Commit 69ae338

Browse files
committed
🐞 fix: 修复本地歌曲文件读取 #593
1 parent 9601fa0 commit 69ae338

8 files changed

Lines changed: 115 additions & 64 deletions

File tree

.github/workflows/issue-helper.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
actions: "create-comment, close-issue"
3636
token: ${{ secrets.GITHUB_TOKEN }}
3737
body: |
38-
抱歉,由于该 Issue 被标记为 **${{ github.event.label.name }}**,系统将自动将其关闭
38+
抱歉,由于被标记为 **${{ github.event.label.name }}**,该 Issue 将自动关闭
3939
如果您认为该 Issue 仍然有效,请重新开启或者创建新的 Issue,我们会尽快确认并修复
4040
# 有问题回复
4141
- name: Auto Reply
@@ -45,7 +45,7 @@ jobs:
4545
actions: "create-comment"
4646
token: ${{ secrets.GITHUB_TOKEN }}
4747
body: |
48-
🤝 您好 @${{ github.event.issue.user.login }},感谢您的反馈!我们注意到该问题被添加了 **${{ github.event.label.name }}**
48+
🤝 您好 @${{ github.event.issue.user.login }},感谢您的反馈!
4949
由于缺少复现步骤,我们无法重现问题,因此无法修复
5050
请确保您已经详细描述了问题的复现步骤,维护团队会尽快查看
5151
# 已确认 BUG

auto-eslint.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export default {
5959
"isRef": true,
6060
"isShallow": true,
6161
"makeDestructurable": true,
62+
"manualResetRef": true,
6263
"markRaw": true,
6364
"nextTick": true,
6465
"onActivated": true,
@@ -96,11 +97,11 @@ export default {
9697
"refAutoReset": true,
9798
"refDebounced": true,
9899
"refDefault": true,
100+
"refManualReset": true,
99101
"refThrottled": true,
100102
"refWithControl": true,
101103
"resolveComponent": true,
102104
"resolveRef": true,
103-
"resolveUnref": true,
104105
"shallowReactive": true,
105106
"shallowReadonly": true,
106107
"shallowRef": true,

electron/main/ipc/ipc-file.ts

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,35 +33,53 @@ const initFileIpc = (): void => {
3333
// 遍历音乐文件
3434
ipcMain.handle("get-music-files", async (_, dirPath: string) => {
3535
try {
36+
// 校验路径有效性
37+
if (!dirPath || dirPath.trim() === "") {
38+
ipcLog.warn("⚠️ Empty directory path provided, skipping");
39+
return [];
40+
}
3641
// 规范化路径
3742
const filePath = resolve(dirPath).replace(/\\/g, "/");
43+
// 检查目录是否存在
44+
try {
45+
await access(filePath);
46+
} catch {
47+
ipcLog.warn(`⚠️ Directory not accessible: ${filePath}`);
48+
return [];
49+
}
3850
console.info(`📂 Fetching music files from: ${filePath}`);
3951
// 查找指定目录下的所有音乐文件
4052
const musicFiles = await FastGlob("**/*.{mp3,wav,flac,aac,webm}", globOpt(filePath));
41-
// 解析元信息
53+
// 解析元信息(使用 allSettled 防止单个文件失败影响整体)
4254
const metadataPromises = musicFiles.map(async (file) => {
43-
const filePath = join(dirPath, file);
44-
// 处理元信息
45-
const { common, format } = await parseFile(filePath);
46-
// 获取文件大小
47-
const { size } = await stat(filePath);
48-
return {
49-
id: getFileID(filePath),
50-
name: common.title || basename(filePath),
51-
artists: common.artists?.[0] || common.artist,
52-
album: common.album || "",
53-
alia: common.comment?.[0]?.text || "",
54-
duration: (format?.duration ?? 0) * 1000,
55-
size: (size / (1024 * 1024)).toFixed(2),
56-
path: filePath,
57-
quality: format.bitrate ?? 0,
58-
};
55+
const fullPath = join(dirPath, file);
56+
try {
57+
// 处理元信息
58+
const { common, format } = await parseFile(fullPath);
59+
// 获取文件大小
60+
const { size } = await stat(fullPath);
61+
return {
62+
id: getFileID(fullPath),
63+
name: common.title || basename(fullPath),
64+
artists: common.artists?.[0] || common.artist,
65+
album: common.album || "",
66+
alia: common.comment?.[0]?.text || "",
67+
duration: (format?.duration ?? 0) * 1000,
68+
size: (size / (1024 * 1024)).toFixed(2),
69+
path: fullPath,
70+
quality: format.bitrate ?? 0,
71+
};
72+
} catch (err) {
73+
ipcLog.warn(`⚠️ Failed to parse file: ${fullPath}`, err);
74+
return null;
75+
}
5976
});
60-
const metadataArray = await Promise.all(metadataPromises);
61-
return metadataArray;
77+
const metadataResults = await Promise.all(metadataPromises);
78+
// 过滤掉解析失败的文件
79+
return metadataResults.filter((item) => item !== null);
6280
} catch (error) {
6381
ipcLog.error("❌ Error fetching music metadata:", error);
64-
throw error;
82+
return [];
6583
}
6684
});
6785

src/components/Player/FullPlayer.vue

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@
8282
<script setup lang="ts">
8383
import { useStatusStore, useMusicStore, useSettingStore } from "@/stores";
8484
import { isElectron } from "@/utils/env";
85-
import { throttle } from "lodash-es";
8685
8786
const musicStore = useMusicStore();
8887
const statusStore = useStatusStore();
@@ -139,13 +138,13 @@ const {
139138
}, 3000);
140139
141140
// 鼠标移动
142-
const playerMove = throttle(
141+
const playerMove = useThrottleFn(
143142
() => {
144143
statusStore.playerMetaShow = true;
145144
if (!isPending.value) startShow();
146145
},
147146
300,
148-
{ trailing: false },
147+
false,
149148
);
150149
151150
// 停用隐藏
@@ -168,7 +167,7 @@ onMounted(() => {
168167
});
169168
170169
onBeforeUnmount(() => {
171-
console.log("离开播放器");
170+
stopShow();
172171
if (isElectron) window.electron.ipcRenderer.send("prevent-sleep", false);
173172
});
174173
</script>

src/components/Player/MainLyric.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,9 @@ onMounted(() => {
312312
onBeforeUnmount(() => {
313313
console.log("离开歌词");
314314
pauseSeek();
315+
if (isElectron) {
316+
window.electron.ipcRenderer.removeAllListeners("lyricsScroll");
317+
}
315318
});
316319
</script>
317320

src/components/Player/PlayerCover.vue

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,17 @@ const dynamicCoverLoaded = ref<boolean>(false);
4747
// 视频元素
4848
const videoRef = ref<HTMLVideoElement | null>(null);
4949
50+
// 清理动态封面资源
51+
const cleanupDynamicCover = () => {
52+
if (videoRef.value) {
53+
videoRef.value.pause();
54+
videoRef.value.src = "";
55+
videoRef.value.load();
56+
}
57+
dynamicCover.value = "";
58+
dynamicCoverLoaded.value = false;
59+
};
60+
5061
// 封面再放送
5162
const { start: dynamicCoverStart, stop: dynamicCoverStop } = useTimeoutFn(
5263
() => {
@@ -89,6 +100,13 @@ watch(
89100
);
90101
91102
onMounted(getDynamicCover);
103+
104+
onBeforeUnmount(() => {
105+
// 停止定时器
106+
dynamicCoverStop();
107+
// 清理动态封面资源
108+
cleanupDynamicCover();
109+
});
92110
</script>
93111

94112
<style lang="scss" scoped>

src/components/Player/PlayerSpectrum.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ onMounted(() => {
107107
});
108108
109109
onBeforeUnmount(() => {
110+
// 停止绘制循环
111+
isKeepDrawing.value = false;
110112
pauseDraw();
111113
});
112114
</script>

src/views/Local/layout.vue

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ const player = usePlayer();
158158
const localStore = useLocalStore();
159159
const settingStore = useSettingStore();
160160
161-
const loading = ref<boolean>(true);
161+
const loading = ref<boolean>(false);
162162
const loadingMsg = ref<MessageReactive | null>(null);
163163
164164
// 本地歌曲总线
@@ -184,10 +184,12 @@ const listData = computed<SongType[]>(() => {
184184
// 获取音乐文件夹
185185
const getMusicFolder = async (): Promise<string[]> => {
186186
defaultMusicPath.value = await window.electron.ipcRenderer.invoke("get-default-dir", "music");
187-
return [
187+
const paths = [
188188
settingStore.showDefaultLocalPath ? defaultMusicPath.value : "",
189189
...settingStore.localFilesPath,
190190
];
191+
// 过滤空路径
192+
return paths.filter((p) => p && p.trim() !== "");
191193
};
192194
193195
// 全部音乐大小
@@ -219,42 +221,50 @@ const moreOptions = computed<DropdownOption[]>(() => [
219221
// 获取全部路径歌曲
220222
const getAllLocalMusic = debounce(
221223
async (showTip: boolean = false) => {
222-
// 获取路径
223-
const allPath = await getMusicFolder();
224-
if (!allPath || !allPath.length) return;
225-
// 加载提示
226-
if (showTip) {
227-
loadingMsg.value = window.$message.loading("正在获取本地歌曲", {
228-
duration: 0,
229-
});
230-
}
231-
// 获取全部歌曲
232-
loading.value = true;
233-
const dirContentsPromises = allPath.map((path) =>
234-
window.electron.ipcRenderer.invoke("get-music-files", path),
235-
);
236-
const results = await Promise.allSettled(dirContentsPromises);
237-
const allSongData = results
238-
.filter((result) => result.status === "fulfilled")
239-
.map((result) => (result as PromiseFulfilledResult<any>).value);
240-
// 展平去重
241-
const songData = uniqBy(flattenDeep(allSongData), "id");
242-
// 处理数据
243-
const listData = formatSongsList(songData);
244-
// 数据是否变化
245-
const oldLength = localStore.localSongs.length;
246-
if (oldLength === 0 && listData.length > 0) {
247-
window.$message.success(`发现 ${listData.length} 首歌曲`);
248-
} else if (listData.length > oldLength) {
249-
window.$message.success(`新增 ${listData.length - oldLength} 首歌曲`);
224+
try {
225+
// 获取路径
226+
const allPath = await getMusicFolder();
227+
if (!allPath || !allPath.length) {
228+
loading.value = false;
229+
return;
230+
}
231+
// 加载提示
232+
if (showTip) {
233+
loadingMsg.value = window.$message.loading("正在获取本地歌曲", {
234+
duration: 0,
235+
});
236+
}
237+
// 获取全部歌曲
238+
loading.value = true;
239+
const dirContentsPromises = allPath.map((path) =>
240+
window.electron.ipcRenderer.invoke("get-music-files", path),
241+
);
242+
const results = await Promise.allSettled(dirContentsPromises);
243+
const allSongData = results
244+
.filter((result) => result.status === "fulfilled")
245+
.map((result) => (result as PromiseFulfilledResult<any>).value);
246+
// 展平去重
247+
const songData = uniqBy(flattenDeep(allSongData), "id");
248+
// 处理数据
249+
const listData = formatSongsList(songData);
250+
// 数据是否变化
251+
const oldLength = localStore.localSongs.length;
252+
if (oldLength === 0 && listData.length > 0) {
253+
window.$message.success(`发现 ${listData.length} 首歌曲`);
254+
} else if (listData.length > oldLength) {
255+
window.$message.success(`新增 ${listData.length - oldLength} 首歌曲`);
256+
}
257+
if (showTip) window.$message.success(`已发现 ${listData.length} 首`);
258+
// 保存并更新
259+
localStore.updateLocalSong(listData);
260+
} catch (error) {
261+
console.error("获取本地音乐失败:", error);
262+
window.$message.error("获取本地音乐失败,请重试");
263+
} finally {
264+
loading.value = false;
265+
loadingMsg.value?.destroy();
266+
loadingMsg.value = null;
250267
}
251-
if (showTip) window.$message.success(`已发现 ${listData.length} 首`);
252-
// 保存并更新
253-
localStore.updateLocalSong(listData);
254-
// 关闭加载
255-
loading.value = false;
256-
loadingMsg.value?.destroy();
257-
loadingMsg.value = null;
258268
},
259269
300,
260270
{ leading: true, trailing: false },

0 commit comments

Comments
 (0)