Dart技术实现:从MP3文件ID3标签提取多份专辑封面
问题:如何读取MP3文件中所有的专辑封面?
我用iTunes/Apple Music给MP3文件添加了多份专辑封面,第一份会显示在「Album Artwork」列,剩余封面会放在「Other Artwork」列。但用Dart的id3库读取ID3标签时,只能获取到第一份封面——虽然文件大小明显增加,能确定其他封面确实存在。
我的代码如下:
import 'dart:convert'; import 'dart:io' as io; import 'package:id3/id3.dart'; void main(List<String> args) { var mp3 = io.File("./lib/song2.mp3"); MP3Instance mp3instance = MP3Instance(mp3.readAsBytesSync()); mp3instance.parseTagsSync(); Map<String, dynamic>? id3Tags = mp3instance.getMetaTags(); print(id3Tags!['APIC'].keys); print(id3Tags!['APIC']['mime']); io.File outputFile = io.File("lib/id3TagsOutput.txt"); outputFile.writeAsString(jsonEncode(id3Tags)); }
输出的ID3标签数据里,APIC仅包含第一份封面的信息:
{ "Version": "v2.3.0", "Album": "God of War (PlayStation Soundtrack)", "Accompaniment": "Bear McCreary", "Artist": "Bear McCreary", "AdditionalInfo": "WWW", "Composer": "Bear McCreary", "Year": "2018", "TPOS": "1", "Genre": "Game Soundtrack", "Conductor": "London Session Orchestra, Schola Cantorum Choir, London Voices", "Title": "God of War", "Track": "1", "Settings": "Lavf57.56.100", "APIC": { "mime": "image/png", "textEncoding": "0", "picType": "FrontCover", "description": "", "base64": "//VERY LONG BASE 64 DATA" } }
请问怎么才能获取到MP3文件里的所有封面?
解决方法
1. 问题根源
你使用的id3库默认只解析并返回第一个APIC帧(ID3标签中存储封面的帧类型),而iTunes添加的多份封面是通过多个APIC帧存储的,因此后续的封面被直接忽略了。
2. 方案一:换用支持多封面的Dart库
推荐使用audio_metadata包,它可以直接提取所有专辑封面,无需手动处理解析逻辑。
示例代码:
import 'dart:io'; import 'package:audio_metadata/audio_metadata.dart'; void main() async { // 读取目标MP3文件 final mp3File = File('./lib/song2.mp3'); // 解析文件元数据 final metadata = await MetadataRetriever.fromFile(mp3File); // 获取所有封面数据 final allArtworks = metadata.artworks; // 遍历处理每一份封面 for (var artwork in allArtworks) { print('封面MIME类型: ${artwork.mimeType}'); print('封面类型: ${artwork.type}'); // 例如FrontCover、BackCover等 // artwork.data为图片原始字节数据,可转成Base64或直接保存为图片文件 File('cover_${allArtworks.indexOf(artwork)}.png').writeAsBytesSync(artwork.data!); } }
3. 方案二:修改现有id3库的源码
如果不想更换库,可以修改id3包的解析逻辑,让它收集所有APIC帧而非仅保留第一个:
- 找到
id3包源码中MP3Instance类的parseTagsSync方法(通常在mp3instance.dart文件内); - 定位处理APIC帧的代码块,将原来的“覆盖赋值”逻辑改为“列表收集”逻辑:
// 原代码(仅保留第一个APIC): metaTags['APIC'] = apicData; // 修改为(收集所有APIC): if (metaTags.containsKey('APIC')) { // 若已有APIC,判断是否为列表,非列表则转为列表后添加新数据 if (metaTags['APIC'] is List) { (metaTags['APIC'] as List).add(apicData); } else { metaTags['APIC'] = [metaTags['APIC'], apicData]; } } else { // 无APIC时直接赋值 metaTags['APIC'] = apicData; }
修改完成后,你的代码中id3Tags['APIC']会变成包含所有封面的列表,遍历该列表即可获取每一份封面的数据。
内容的提问来源于stack exchange,提问作者Jeremi
相关产品推荐
相关产品推荐

