Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions electron/main/services/downloadManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ import { getEngine } from "@main/services/engine";
import { fetchBytes } from "@main/utils/fetchBytes";
import { fetchStreamingDownload } from "@main/services/streaming/mediaSource";
import { StreamingRequestError } from "@main/services/streaming/errors";
import { renderDownloadPath, dedupePath, resolveExtension } from "@main/utils/filename";
import {
renderDownloadPath,
dedupePath,
resolveExtension,
extensionFromDisposition,
} from "@main/utils/filename";
import * as db from "@main/database/downloads";
import { ErrorCode } from "@shared/types/errors";
import type { JsTagWriteRequest } from "@splayer/audio-engine";
Expand Down Expand Up @@ -325,9 +330,9 @@ const runTask = async (
);
}
// 原文件格式以服务器文件名或 MIME 为准,不能套用界面选择的在线音质
const format = streamingDownload
? response.headers.get("content-disposition")?.match(/\.([a-z\d]{2,5})(?="|;|$)/i)?.[1]
: req.declaredFormat;
// 插件音源给的地址常常没有后缀(下载接口 302 到 CDN),文件名是唯一的格式信号
const disposition = response.headers.get("content-disposition");
const format = req.declaredFormat || extensionFromDisposition(disposition);
const ext = resolveExtension(format, mime, audioUrl);
if (policy === "skip" && fs.existsSync(`${finalNoExt}${ext}`)) {
await response.body.cancel();
Expand Down
18 changes: 18 additions & 0 deletions electron/main/utils/filename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,24 @@ const KNOWN_EXTS = new Set([
".aiff",
]);

/**
* 从 Content-Disposition 的文件名里取扩展名
*
* 插件音源给出的地址常常没有路径后缀(下载接口 302 到 CDN),
* 此时服务器给的文件名是唯一可靠的格式信号
* @param disposition - 响应头 content-disposition
* @returns 已知音频扩展名(不含点);无法识别时返回 undefined
*/
export const extensionFromDisposition = (
disposition: string | null | undefined,
): string | undefined => {
if (!disposition) return undefined;
const match = disposition.match(/\.([a-z\d]{2,5})(?=["';]|$)/i);
if (!match) return undefined;
const name = match[1].toLowerCase();
return KNOWN_EXTS.has(`.${name}`) ? name : undefined;
};

/**
* 推断下载文件扩展名(含点)
* 优先级:已声明格式 → Content-Type → URL 路径后缀 → 兜底 .mp3
Expand Down
Loading