From 67e605c341accc393051c984cb5ff0ecedd5a2dd Mon Sep 17 00:00:00 2001 From: Isilsolme Date: Sun, 25 Oct 2026 13:39:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=B8=8B=E8=BD=BD=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E5=90=8D=E4=BC=98=E5=85=88=E9=87=87=E7=94=A8=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- electron/main/services/downloadManager.ts | 13 +++++++++---- electron/main/utils/filename.ts | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/electron/main/services/downloadManager.ts b/electron/main/services/downloadManager.ts index 913efb1aa..fa8e9bb12 100644 --- a/electron/main/services/downloadManager.ts +++ b/electron/main/services/downloadManager.ts @@ -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"; @@ -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(); diff --git a/electron/main/utils/filename.ts b/electron/main/utils/filename.ts index f0c2e1fd0..0d0bf22ce 100644 --- a/electron/main/utils/filename.ts +++ b/electron/main/utils/filename.ts @@ -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