Skip to content

Commit 6dbbb3f

Browse files
✨ feat: 模拟播放接口下载
1 parent 2ec2b3c commit 6dbbb3f

4 files changed

Lines changed: 52 additions & 7 deletions

File tree

electron/main/ipc/ipc-file.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { basename, dirname, extname, isAbsolute, join, relative, resolve } from
33
import { access, readdir, readFile, stat, unlink, writeFile } from "fs/promises";
44
import { parseFile } from "music-metadata";
55
import { getFileID, getFileMD5, metaDataLyricsArrayToLrc } from "../utils/helper";
6-
import { File, Picture, Id3v2Settings } from "node-taglib-sharp";
6+
import { File, Picture, Id3v2Settings, TagTypes } from "node-taglib-sharp";
77
import { ipcLog } from "../logger";
88
import { download } from "electron-dl";
99
import { Options as GlobOptions } from "fast-glob/out/settings";
@@ -437,12 +437,21 @@ const initFileIpc = (): void => {
437437
filename: `${fileName}.jpg`,
438438
});
439439
// 读取歌曲文件
440-
const songFile = File.createFromPath(songDownload.getSavePath());
440+
let songFile = File.createFromPath(songDownload.getSavePath());
441+
// 清除原有标签,防止脏数据(如模拟播放下载时的乱码歌词)
442+
songFile.removeTags(TagTypes.AllTags);
443+
songFile.save();
444+
songFile.dispose();
445+
446+
// 重新读取文件以写入新标签
447+
songFile = File.createFromPath(songDownload.getSavePath());
441448
// 生成图片信息
442449
const songCover = Picture.fromPath(coverDownload.getSavePath());
450+
443451
// 保存修改后的元数据
444452
Id3v2Settings.forceDefaultVersion = true;
445453
Id3v2Settings.defaultVersion = 3;
454+
446455
songFile.tag.title = songData?.name || "未知曲目";
447456
songFile.tag.album = songData?.album?.name || "未知专辑";
448457
songFile.tag.performers = songData?.artists?.map((ar: any) => ar.name) || ["未知艺术家"];

src/components/Setting/LocalSetting.vue

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@
142142
class="set"
143143
/>
144144
</n-card>
145+
<n-card class="set-item">
146+
<div class="label">
147+
<n-text class="name">模拟播放下载</n-text>
148+
<n-text class="tip" :depth="3">使用播放接口进行下载,可能解决部分下载失败问题</n-text>
149+
</div>
150+
<n-switch
151+
v-model:value="settingStore.usePlaybackForDownload"
152+
:round="false"
153+
class="set"
154+
/>
155+
</n-card>
145156
<n-card class="set-item">
146157
<div class="label">
147158
<n-text class="name">保留元信息文件</n-text>

src/stores/setting.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ export interface SettingState {
7272
downloadCover: boolean;
7373
/** 下载歌词 */
7474
downloadLyric: boolean;
75+
/** 下载歌词翻译 */
76+
downloadLyricTranslation: boolean;
77+
/** 下载歌词音译 */
78+
downloadLyricRomaji: boolean;
79+
/** 模拟播放下载 */
80+
usePlaybackForDownload: boolean;
7581
/** 保存元信息文件 */
7682
saveMetaFile: boolean;
7783
/** 代理协议 */
@@ -293,6 +299,9 @@ export const useSettingStore = defineStore("setting", {
293299
downloadMeta: true,
294300
downloadCover: true,
295301
downloadLyric: true,
302+
downloadLyricTranslation: true,
303+
downloadLyricRomaji: true,
304+
usePlaybackForDownload: false,
296305
saveMetaFile: false,
297306
proxyProtocol: "off",
298307
proxyServe: "127.0.0.1",

src/utils/download.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import type { SongType, SongLevelType } from "@/types/main";
2-
import { songDownloadUrl, songLyric } from "@/api/song";
2+
import { songDownloadUrl, songLyric, songUrl } from "@/api/song";
33
import { isElectron } from "@/utils/env";
44
import { saveAs } from "file-saver";
55
import { useSettingStore } from "@/stores";
66
import { cloneDeep } from "lodash-es";
77
import songManager from "@/utils/songManager";
8+
import { songLevelData } from "@/utils/meta";
89

910
interface DownloadOptions {
1011
song: SongType;
@@ -21,13 +22,28 @@ export const downloadSong = async ({
2122
}: DownloadOptions): Promise<{ success: boolean; skipped?: boolean; message?: string }> => {
2223
try {
2324
const settingStore = useSettingStore();
25+
let url = "";
26+
let type = "mp3";
27+
2428
// 获取下载链接
25-
const result = await songDownloadUrl(song.id, quality);
26-
if (result.code !== 200 || !result?.data?.url) {
27-
return { success: false, message: result.message || "获取下载链接失败" };
29+
if (settingStore.usePlaybackForDownload) {
30+
const levelName = songLevelData[quality].level;
31+
// @ts-ignore
32+
const result = await songUrl(song.id, levelName);
33+
if (result.code !== 200 || !result?.data?.[0]?.url) {
34+
return { success: false, message: result.message || "获取播放链接失败" };
35+
}
36+
url = result.data[0].url;
37+
type = (result.data[0].type || result.data[0].encodeType || "mp3").toLowerCase();
38+
} else {
39+
const result = await songDownloadUrl(song.id, quality);
40+
if (result.code !== 200 || !result?.data?.url) {
41+
return { success: false, message: result.message || "获取下载链接失败" };
42+
}
43+
url = result.data.url;
44+
type = result.data.type?.toLowerCase() || "mp3";
2845
}
2946

30-
const { url, type = "mp3" } = result.data;
3147
const songName = songManager.getPlayerInfo(song) || "未知曲目";
3248
const finalPath = downloadPath || settingStore.downloadPath;
3349

0 commit comments

Comments
 (0)