|
|
@@ -823,8 +823,17 @@ export class Utility {
|
|
|
item.playCount = 0;
|
|
|
item.pyStr = pinyin4js.getShortPinyin(musicName)
|
|
|
|
|
|
- item.lyricContent = await extractLyricsContent(uri)
|
|
|
- console.info('onecold pyStr = '+pinyin4js.getShortPinyin(musicName));
|
|
|
+ // item.lyricContent = await extractLyricsContent(uri)
|
|
|
+ let metaItem = await parseAudioMetadata(uri)
|
|
|
+ if(metaItem){
|
|
|
+ item.lyricContent = metaItem.lyricContent
|
|
|
+ item.bit_rate = metaItem.bit_rate
|
|
|
+ item.year = metaItem.year
|
|
|
+ item.probe_score = metaItem.probe_score
|
|
|
+ item.nb_streams = metaItem.nb_streams
|
|
|
+ item.nb_programs = metaItem.nb_programs
|
|
|
+ }
|
|
|
+
|
|
|
})
|
|
|
} catch (error) {
|
|
|
console.error('uriGetAssetsFromFile failed with err: ' + JSON.stringify(error));
|
|
|
@@ -895,6 +904,7 @@ export class Utility {
|
|
|
videoItem.album = album;
|
|
|
videoItem.mimeType = format.format_name
|
|
|
videoItem.sampleRate = sampleRate
|
|
|
+ videoItem.pyStr = pinyin4js.getShortPinyin(name)
|
|
|
videoItem.fileName = FileUtil.getFileName(inputPath);
|
|
|
if(format.duration)
|
|
|
videoItem.duration = convertSecondsToTime(format.duration.toString())
|
|
|
@@ -1628,4 +1638,68 @@ async function extractLyricsContent(inputPath: string): Promise<string> {
|
|
|
reject(`解析失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
|
}
|
|
|
});
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 解析音乐文件元数据(包含歌词和其他关键字段)
|
|
|
+ * @param inputPath 文件路径
|
|
|
+ * @returns Promise<VideoItem> 包含完整元数据的对象
|
|
|
+ */
|
|
|
+async function parseAudioMetadata(inputPath: string): Promise<VideoItem> {
|
|
|
+ return new Promise(async (resolve, reject) => {
|
|
|
+ try {
|
|
|
+ // 1. 执行FFprobe命令
|
|
|
+ const commands: string[] = [
|
|
|
+ 'ffprobe',
|
|
|
+ '-v', 'quiet',
|
|
|
+ '-print_format', 'json',
|
|
|
+ '-show_format',
|
|
|
+ '-show_streams',
|
|
|
+ inputPath
|
|
|
+ ];
|
|
|
+
|
|
|
+ let outputJson = '';
|
|
|
+ await FFmpeg.execute(commands, {
|
|
|
+ outputCallback: (message: string) => outputJson += message,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 2. 解析元数据
|
|
|
+ const metadata = JSON.parse(outputJson) as FFprobeMetadata;
|
|
|
+ const format:FFprobeFormat = metadata.format ;
|
|
|
+ const tags = format.tags||{} ;
|
|
|
+ // 3. 构建VideoItem基础信息
|
|
|
+ const videoItem = new VideoItem(
|
|
|
+ tags.title || getFileNameWithoutExtension(inputPath),
|
|
|
+ inputPath, // id
|
|
|
+ inputPath,
|
|
|
+ CommonConstants.TYPE_LOCAL,
|
|
|
+ 0,
|
|
|
+ new Date().toISOString() // 使用当前时间作为默认创建时间
|
|
|
+ );
|
|
|
+
|
|
|
+ // 4. 设置关键字段
|
|
|
+ videoItem.bit_rate = format.bit_rate || '';
|
|
|
+ videoItem.probe_score = format.probe_score || 0;
|
|
|
+ videoItem.year = tags.TYER || tags.date || '';
|
|
|
+ videoItem.lyricContent =
|
|
|
+ tags.LYRICS ??
|
|
|
+ tags.lyrics ??
|
|
|
+ tags.USLT ??
|
|
|
+ tags.UNSYNCEDLYRICS ??
|
|
|
+ '';
|
|
|
+
|
|
|
+ // 5. 设置其他可选字段
|
|
|
+ videoItem.artist = tags.artist || '';
|
|
|
+ videoItem.album = tags.album || '';
|
|
|
+ videoItem.duration = format.duration || '';
|
|
|
+ videoItem.nb_streams = format.nb_streams;
|
|
|
+ videoItem.nb_programs = format.nb_programs;
|
|
|
+
|
|
|
+ resolve(videoItem);
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ reject(new Error(`元数据解析失败: ${error instanceof Error ? error.message : String(error)}`));
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|