|
|
@@ -1074,6 +1074,9 @@ export class Utility {
|
|
|
imagePath = fileUri.getUriFromPath(imagePath)
|
|
|
}else{
|
|
|
imagePath = ''
|
|
|
+ // 使用华为接口提取封面(备用方案)
|
|
|
+ // console.warn('onecold 提取封面图片失败,使用华为接口提取封面');
|
|
|
+ // imagePath = await extractCoverWithHwInterface(inputPath, context, name);
|
|
|
}
|
|
|
videoItem.pixelMapPath = imagePath;
|
|
|
}else if(Utility.isVideoByExtension(inputPath)){
|
|
|
@@ -1901,6 +1904,40 @@ function getFileNameWithoutExtension(filePath: string): string {
|
|
|
// return ;
|
|
|
// }
|
|
|
|
|
|
+/**
|
|
|
+ * 使用华为接口提取音乐文件封面(备用方案)
|
|
|
+ * @param inputPath 音乐文件路径
|
|
|
+ * @param context 应用上下文
|
|
|
+ * @param name 文件名称(用于保存)
|
|
|
+ * @returns Promise<string> 返回封面图片的URI路径,失败返回空字符串
|
|
|
+ */
|
|
|
+async function extractCoverWithHwInterface(inputPath: string, context: Context, name: string): Promise<string> {
|
|
|
+ try {
|
|
|
+ // 创建AVMetadataExtractor对象
|
|
|
+ const avMetadataExtractor: media.AVMetadataExtractor = await media.createAVMetadataExtractor();
|
|
|
+ // 设置fdSrc
|
|
|
+ const fd = await fs.openSync(inputPath, fs.OpenMode.READ_ONLY);
|
|
|
+ avMetadataExtractor.fdSrc = fd;
|
|
|
+
|
|
|
+ // 获取专辑封面
|
|
|
+ const pixelMap = await fetchAlbumCover(avMetadataExtractor);
|
|
|
+
|
|
|
+ // 释放资源(promise模式)
|
|
|
+ await avMetadataExtractor.release();
|
|
|
+ console.info('onecold release success. name= ' + name);
|
|
|
+
|
|
|
+ if (pixelMap !== undefined && pixelMap !== null) {
|
|
|
+ const imagePath = await ImageUtil.savePixelMap(pixelMap, context.filesDir, name);
|
|
|
+ return fileUri.getUriFromPath(imagePath);
|
|
|
+ } else {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('华为接口提取封面失败:', error instanceof Error ? error.message : String(error));
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* 从音乐文件中提取封面
|
|
|
* @param inputPath 音乐文件路径
|
|
|
@@ -1923,7 +1960,28 @@ async function getFFmpegCover(inputPath: string, outputPath: string): Promise<bo
|
|
|
return true;
|
|
|
} catch (error) {
|
|
|
console.error(`FFmpeg execution failed with error: ${error instanceof Error ? error.message : String(error)}`);
|
|
|
- return false;
|
|
|
+ try {
|
|
|
+ let primaryCommands = [
|
|
|
+ "ffmpeg", "-y",
|
|
|
+ "-i", inputPath,
|
|
|
+ "-map", "0:2", // 直接提取第三个流(Stream #0:2),这是附加图片流
|
|
|
+ "-c:v", "copy", // 直接复制流数据
|
|
|
+ outputPath
|
|
|
+ ];
|
|
|
+ await FFmpeg.execute(primaryCommands, {
|
|
|
+ logCallback: (logLevel: number, logMessage: string) => {
|
|
|
+ console.info(`[FFmpeg LOG] [${logLevel}] ${logMessage}`);
|
|
|
+ },
|
|
|
+ progressCallback: (message: string) => {
|
|
|
+ console.info(`[FFmpeg progress] ${JSON.stringify(FFProgressMessageParser.parse(message))}`);
|
|
|
+ },
|
|
|
+ });
|
|
|
+ console.info("FFmpeg 2 execution succeeded.");
|
|
|
+ return true;
|
|
|
+ }catch (error) {
|
|
|
+ console.error(`FFmpeg execution 2 failed with error: ${error instanceof Error ? error.message : String(error)}`);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
/**
|
|
|
@@ -2180,11 +2238,7 @@ function hasGarbledText(tags: FFMpegTags): boolean {
|
|
|
/[\uD800-\uDFFF]/.test(text) // 无效的UTF-16代理对
|
|
|
);
|
|
|
}
|
|
|
-// function hasGarbledText(tags: FFMpegTags): boolean {
|
|
|
-// if (!tags) return false;
|
|
|
-// const text = [tags.title, tags.artist, tags.album].join("");
|
|
|
-// return /[À-ÿµØÇò]/.test(text); // 匹配常见乱码字符
|
|
|
-// }
|
|
|
+
|
|
|
|
|
|
|
|
|
/**
|