You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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帧而非仅保留第一个:

  1. 找到id3包源码中MP3Instance类的parseTagsSync方法(通常在mp3instance.dart文件内);
  2. 定位处理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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 16:55:18