MetaTagger

A pure Dart library for reading and writing metadata to MP3, MP4/M4A, and FLAC files with custom tag support.

Features

  • Read & Write Support: Both read and write metadata tags
  • MP3 Support: Read and write ID3v2 tags to MP3 files
  • MP4/M4A Support: Read and write iTunes-style metadata to MP4/M4A files
  • FLAC Support: Read and write Vorbis Comments to FLAC files
  • Custom Tags: Support for custom metadata fields
  • Album Art: Support for reading and embedding album artwork
  • Pure Dart: No native dependencies required
  • Simple API: Easy-to-use interface for metadata operations

Supported Formats

Format Metadata Standard File Extensions Read Write
MP3 ID3v2.3/2.4 .mp3
MP4/M4A iTunes Metadata .mp4, .m4a, .m4v, .m4b
FLAC Vorbis Comments .flac

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  metatagger: ^1.0.0

Usage

Reading Metadata

Basic Reading

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // Read all metadata as a map
  final tags = await tagger.readCommonTags('song.mp3');
  
  print('Title: ${tags[CommonTags.title]}');
  print('Artist: ${tags[CommonTags.artist]}');
  print('Album: ${tags[CommonTags.album]}');
  print('Year: ${tags[CommonTags.year]}');
}

Reading Specific Tags

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // Read a specific tag
  final titleTag = await tagger.readTag('song.mp3', CommonTags.title);
  if (titleTag != null) {
    print('Title: ${titleTag.value}');
  }
  
  // Read all tags as MetadataTag objects
  final allTags = await tagger.readTags('song.mp3');
  for (final tag in allTags) {
    print('${tag.key}: ${tag.value}');
  }
}

Reading Album Art

import 'package:metatagger/metatagger.dart';
import 'dart:io';

void main() async {
  final tagger = MetaTagger();
  
  // Read album art
  final artTag = await tagger.readTag('song.mp3', CommonTags.albumArt);
  if (artTag != null && artTag.type == TagType.binary) {
    // Save album art to file
    await File('cover.jpg').writeAsBytes(artTag.value);
    print('Album art extracted!');
  }
}

Writing Metadata

Basic Writing

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // Write metadata using the convenient map interface
  await tagger.writeCommonTags('song.mp3', {
    CommonTags.title: 'My Song',
    CommonTags.artist: 'My Artist',
    CommonTags.album: 'My Album',
    CommonTags.year: '2024',
    CommonTags.genre: 'Rock',
    CommonTags.track: '1',
  });
}

Writing Individual Tags

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // Write individual tags
  await tagger.writeTag('song.mp3', 
    MetadataTag.text(CommonTags.composer, 'John Doe'));
  
  await tagger.writeTag('song.mp3', 
    MetadataTag.number(CommonTags.bpm, 120));
}

Custom Tags

All formats support custom tags for storing application-specific metadata.

MP3 Custom Tags

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // MP3 stores custom tags as TXXX frames
  await tagger.writeTag('song.mp3', 
    MetadataTag.text('CUSTOM_FIELD', 'Custom Value'));
}

MP4/M4A Custom Tags

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // MP4 stores custom tags as freeform (----) atoms
  // with namespace com.apple.iTunes
  await tagger.writeTag('song.m4a', 
    MetadataTag.text('MOOD', 'Energetic'));
  
  await tagger.writeTag('song.m4a', 
    MetadataTag.text('PRODUCER', 'John Producer'));
  
  await tagger.writeTag('song.m4a', 
    MetadataTag.text('ISRC', 'USIR12345678'));
}

FLAC Custom Tags

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // FLAC stores custom tags as Vorbis comments
  await tagger.writeTag('song.flac', 
    MetadataTag.text('MY_CUSTOM_TAG', 'Some custom data'));
}

Album Art

import 'package:metatagger/metatagger.dart';
import 'dart:io';

void main() async {
  final tagger = MetaTagger();
  final imageBytes = await File('album_art.jpg').readAsBytes();
  
  // Add album art
  await tagger.writeTag('song.mp3', 
    MetadataTag.binary(CommonTags.albumArt, imageBytes));
}

Multiple Tags at Once

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  final tags = [
    MetadataTag.text(CommonTags.title, 'Song Title'),
    MetadataTag.text(CommonTags.artist, 'Artist Name'),
    MetadataTag.text(CommonTags.album, 'Album Name'),
    MetadataTag.number(CommonTags.track, 1),
    MetadataTag.text('CUSTOM_TAG', 'Custom Value'),
  ];
  
  await tagger.writeTags('song.flac', tags);
}

Clearing Metadata

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // Remove all metadata from a file
  await tagger.clearTags('song.mp3');
}

Advanced Examples

Copy Metadata Between Files

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // Read metadata from one file
  final tags = await tagger.readTags('source.mp3');
  
  // Write to another file
  await tagger.writeTags('destination.mp3', tags);
}

Update Specific Tags

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // Read existing tags
  final existingTags = await tagger.readTags('song.mp3');
  
  // Filter out the tag you want to update
  final updatedTags = existingTags.where((t) => t.key != CommonTags.year).toList();
  
  // Add the new value
  updatedTags.add(MetadataTag.text(CommonTags.year, '2025'));
  
  // Write back
  await tagger.writeTags('song.mp3', updatedTags);
}

Migrate Metadata Between Formats

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  // Read from MP3
  final tags = await tagger.readTags('song.mp3');
  
  // Write to FLAC or MP4
  await tagger.writeTags('song.flac', tags);
  await tagger.writeTags('song.m4a', tags);
  
  print('Metadata migrated across formats!');
}

Checking File Support

import 'package:metatagger/metatagger.dart';

void main() {
  final tagger = MetaTagger();
  
  // Check if a file format is supported
  print('MP3 supported: ${tagger.isSupported('test.mp3')}'); // true
  print('MP4 supported: ${tagger.isSupported('test.m4a')}'); // true
  print('WAV supported: ${tagger.isSupported('test.wav')}'); // false
  
  // Get all supported extensions
  print('Supported formats: ${tagger.supportedExtensions}'); // [.mp3, .flac]
}

Common Tags

The library provides constants for common metadata tags:

CommonTags.title          // Song title
CommonTags.artist         // Artist name
CommonTags.album          // Album name
CommonTags.albumArtist    // Album artist
CommonTags.date           // Release date
CommonTags.year           // Release year
CommonTags.genre          // Music genre
CommonTags.track          // Track number
CommonTags.trackTotal     // Total tracks
CommonTags.disc           // Disc number
CommonTags.discTotal      // Total discs
CommonTags.comment        // Comment
CommonTags.composer       // Composer
CommonTags.performer      // Performer
CommonTags.conductor      // Conductor
CommonTags.lyricist       // Lyricist
CommonTags.copyright      // Copyright
CommonTags.encodedBy      // Encoded by
CommonTags.bpm            // Beats per minute
CommonTags.mood           // Mood
CommonTags.isrc           // ISRC code
CommonTags.barcode        // Barcode
CommonTags.catalogNumber  // Catalog number
CommonTags.label          // Record label
CommonTags.lyrics         // Song lyrics
CommonTags.albumArt       // Album artwork

Tag Types

The library supports different types of metadata:

  • Text Tags: MetadataTag.text(key, value)
  • Number Tags: MetadataTag.number(key, value)
  • Binary Tags: MetadataTag.binary(key, bytes) (for album art)

Error Handling

The library throws MetadataException for various error conditions:

import 'package:metatagger/metatagger.dart';

void main() async {
  final tagger = MetaTagger();
  
  try {
    await tagger.writeTag('nonexistent.mp3', 
      MetadataTag.text(CommonTags.title, 'Test'));
  } catch (e) {
    if (e is MetadataException) {
      print('Metadata error: ${e.message}');
      if (e.filePath != null) {
        print('File: ${e.filePath}');
      }
    }
  }
}

Format-Specific Notes

MP3 (ID3v2.4)

  • Uses ID3v2.4 format for maximum compatibility
  • Supports UTF-8 encoding for international characters
  • Album art stored as APIC frames
  • Custom tags use TXXX frames

FLAC (Vorbis Comments)

  • Uses standard Vorbis Comment format
  • All text is UTF-8 encoded
  • Album art stored as METADATA_BLOCK_PICTURE
  • Custom tags supported natively

License

This project is licensed under the GPLv3 License - see the LICENSE file for details.

Libraries

metatagger
A pure Dart library for reading and writing metadata to MP3, MP4/M4A, and FLAC files with custom tag support.