haudiotagger 1.2.3
haudiotagger: ^1.2.3 copied to clipboard
Read and write audio metadata in Flutter. Supports MP3, FLAC, OGG, MP4, WAV, AIFF, and more. Powered by Rust for fast, reliable performance.
[hAudiotagger]
hAudiotagger
Rust-powered audio metadata for Flutter
Read, write, and edit audio metadata across Android, iOS, Linux, macOS, Windows, and Web. Built on lofty via flutter_rust_bridge.
[hAudiotagger]
Features #
| Feature | Platforms |
|---|---|
| Read / write metadata (title, artist, album, art, lyrics...) | All |
| Partial updates — change one field without touching others | All |
| Batch operations with progress callbacks | All |
| Custom tags (TXXX, Vorbis) | All |
| ID3v2 version control (v2.3 / v2.4) | All |
| Strip ID3v1 tags | All |
| Audio properties (duration, bitrate, codec...) | All |
| Tag format detection | All |
Install #
dependencies:
haudiotagger: ^1.2.3
Quick Start #
import 'package:haudiotagger/haudiotagger.dart';
// Read
final tag = await Haudiotagger.read('/path/to/song.mp3');
print(tag?.title);
// Write
await Haudiotagger.write('/path/to/song.mp3', Tag(
title: 'My Song',
artist: 'Artist',
album: 'Album',
));
// Update (preserves other fields)
await Haudiotagger.update('/path/to/song.mp3', TagChanges(
album: 'New Album',
));
// Batch
final result = await Haudiotagger.batchWrite(paths, tag);
Supported Formats #
| Format | Tags |
|---|---|
| MP3 | ID3v2, ID3v1, APE |
| FLAC | Vorbis Comments, ID3v2* |
| MP4 / M4A | iTunes ilst |
| Ogg Vorbis | Vorbis Comments |
| Opus | Vorbis Comments |
| AAC | ID3v2, ID3v1 |
| WAV | ID3v2, RIFF INFO |
| AIFF | ID3v2, Text Chunks |
| APE | APE, ID3v2*, ID3v1 |
| WavPack | APE, ID3v1 |
* The tag will be read only, due to lack of official support
Usage #
Read Metadata #
// From file path (native)
final tag = await Haudiotagger.read('/path/to/song.mp3');
// From bytes (web + native)
final tag = await Haudiotagger.readFromBytes(fileBytes);
Write Metadata #
// To file path (native)
await Haudiotagger.write('/path/to/song.mp3', Tag(
title: 'Song Title',
trackArtist: 'Artist',
album: 'Album',
year: 2024,
));
// To bytes (web + native)
final modified = await Haudiotagger.writeToBytes(fileBytes, tag);
Update Metadata #
Only the fields you pass are changed — everything else stays intact.
await Haudiotagger.update('/path/to/song.mp3', TagChanges(
title: 'New Title',
genre: 'Jazz',
));
// Bytes variant
final modified = await Haudiotagger.updateFromBytes(fileBytes, changes);
Batch Operations #
// Write same tag to multiple files
final result = await Haudiotagger.batchWrite(paths, tag);
// Apply same changes to multiple files
await Haudiotagger.batchUpdateChanges(paths, TagChanges(album: 'New Album'));
// Per-file callback with progress
await Haudiotagger.batchUpdate(
paths,
onProgress: (p) => print('${(p.percent * 100).round()}%'),
(path, current) => current.copyWith(trackNumber: paths.indexOf(path) + 1),
);
// Web/bytes variants available
await Haudiotagger.batchWriteFromBytes(byteArrays, tag);
Custom Tags #
Read, write, and remove format-specific custom tags (ID3v2 TXXX frames, Vorbis non-standard keys).
// Read
final custom = await Haudiotagger.getCustomTags('/path/to/song.mp3');
// {'MY_FIELD': 'some value'}
// Write
await Haudiotagger.setCustomTag('/path/to/song.mp3', 'MY_FIELD', 'some value');
// Remove
await Haudiotagger.removeCustomTag('/path/to/song.mp3', 'MY_FIELD');
// Bytes variants: getCustomTagsFromBytes, setCustomTagFromBytes, removeCustomTagFromBytes
ID3v2 Version Control #
// Detect version
final version = await Haudiotagger.getId3v2Version('/path/to/song.mp3');
// Id3v2Version.v3 or Id3v2Version.v4
// Convert to ID3v2.3 (widely compatible)
await Haudiotagger.convertId3v2('/path/to/song.mp3', Id3v2Version.v3);
// Convert to ID3v2.4 (latest spec)
await Haudiotagger.convertId3v2('/path/to/song.mp3', Id3v2Version.v4);
// Bytes variants: getId3v2VersionFromBytes, convertId3v2FromBytes
Remove ID3v1 #
await Haudiotagger.removeId3v1('/path/to/song.mp3');
final cleaned = await Haudiotagger.removeId3v1FromBytes(bytes);
Audio Properties #
final props = await Haudiotagger.readProperties('/path/to/song.mp3');
// props.duration, props.bitrate, props.sampleRate, props.codec, ...
// Bytes variant
await Haudiotagger.readPropertiesFromBytes(bytes);
Diff Tags #
Compare two tags to see exactly what changed — useful for confirmation dialogs and undo previews.
final oldTag = await Haudiotagger.read('/path/to/song.mp3');
final newTag = oldTag?.copyWith(title: 'New Title', year: 2025);
final diff = Haudiotagger.diff(oldTag!, newTag!);
print(diff.length); // 2
print(diff.changes[0]); // title: Old Title → New Title
for (final change in diff.changes) {
switch (change.type) {
case ChangeType.added:
print('Added ${change.field.name}');
case ChangeType.updated:
print('Updated ${change.field.name}');
case ChangeType.removed:
print('Removed ${change.field.name}');
}
}
Detect Tag Formats #
final formats = await Haudiotagger.getTagFormats('/path/to/song.mp3');
// ['ID3v2', 'ID3v1']
Inspect File #
One call to get everything: format, tag format, properties, metadata, pictures, and file size.
final info = await Haudiotagger.inspect('/path/to/song.mp3');
print(info.format); // 'MP3'
print(info.tagFormat); // 'ID3v2'
print(info.size); // 4812345
print(info.metadata?.title);
print(info.properties.duration);
print(info.pictures.length);
// Bytes variant
final info = await Haudiotagger.inspectFromBytes(bytes);
Web Setup #
The host page must be cross-origin isolated for WASM shared memory. Add these headers when serving:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
For local development:
flutter run -d chrome \
--web-header=Cross-Origin-Opener-Policy=same-origin \
--web-header=Cross-Origin-Embedder-Policy=require-corp
API Reference #
All methods
| Method | Returns | Platform |
|---|---|---|
read(path) |
Tag? |
native |
readFromBytes(bytes) |
Tag? |
all |
write(path, tag) |
void |
native |
writeToBytes(bytes, tag) |
Uint8List |
all |
update(path, changes) |
void |
native |
updateFromBytes(bytes, changes) |
Uint8List |
all |
remove(path, fields) |
void |
native |
removeFromBytes(bytes, fields) |
Uint8List |
all |
clear(path) |
void |
native |
clearFromBytes(bytes) |
Uint8List |
all |
readProperties(path) |
AudioProperties |
native |
readPropertiesFromBytes(bytes) |
AudioProperties |
all |
getTagFormats(path) |
List<String> |
native |
getTagFormatsFromBytes(bytes) |
List<String> |
all |
inspect(path) |
AudioFileInfo |
native |
inspectFromBytes(bytes) |
AudioFileInfo |
all |
getCustomTags(path) |
Map<String, String> |
native |
getCustomTagsFromBytes(bytes) |
Map<String, String> |
all |
setCustomTag(path, key, value) |
void |
native |
setCustomTagFromBytes(bytes, key, value) |
Uint8List |
all |
removeCustomTag(path, key) |
void |
native |
removeCustomTagFromBytes(bytes, key) |
Uint8List |
all |
getId3v2Version(path) |
Id3v2Version? |
all |
getId3v2VersionFromBytes(bytes) |
Id3v2Version? |
all |
convertId3v2(path, version) |
void |
all |
convertId3v2FromBytes(bytes, version) |
Uint8List |
all |
removeId3v1(path) |
void |
all |
removeId3v1FromBytes(bytes) |
Uint8List |
all |
batchWrite(paths, tag) |
BatchResult |
native |
batchUpdateChanges(paths, changes) |
BatchResult |
native |
batchUpdate(paths, updater, {onProgress}) |
BatchResult |
native |
batchWriteFromBytes(bytes, tag) |
BatchBytesResult |
all |
batchUpdateChangesFromBytes(bytes, changes) |
BatchBytesResult |
all |
batchUpdateFromBytes(bytes, updater, {onProgress}) |
BatchBytesResult |
all |
Data types
Tag #
| Field | Type | Notes |
|---|---|---|
title |
String? |
|
trackArtist |
String? |
|
album |
String? |
|
albumArtist |
String? |
|
year |
int? |
|
genre |
String? |
|
trackNumber |
int? |
|
trackTotal |
int? |
|
discNumber |
int? |
|
discTotal |
int? |
|
lyrics |
String? |
|
comment |
String? |
|
bpm |
double? |
|
duration |
int? |
Read-only |
pictures |
List<Picture> |
TagChanges #
Same fields as Tag, all optional. Only set fields are applied.
Picture #
| Field | Type |
|---|---|
pictureType |
PictureType |
mimeType |
MimeType? |
bytes |
Uint8List |
AudioFileInfo #
| Field | Type | Notes |
|---|---|---|
format |
String |
e.g. MP3, FLAC |
tagFormat |
String |
e.g. ID3v2, VorbisComments |
properties |
AudioProperties |
Technical details |
metadata |
Tag? |
All metadata fields |
pictures |
List<Picture> |
Embedded artwork |
size |
BigInt |
File size in bytes |
AudioProperties #
| Field | Type |
|---|---|
duration |
Duration? |
durationMicros |
int? |
bitrate |
int? |
sampleRate |
int? |
channels |
int? |
bitsPerSample |
int? |
codec |
String |
containerFormat |
String |
lossless |
bool |
bitrateMode |
BitrateMode |
fileSize |
BigInt? |
Id3v2Version #
v2 (not supported for writing), v3, v4
BatchResult #
| Field | Type |
|---|---|
successes |
int |
failures |
int |
errors |
List<(String, String)> |
BatchBytesResult #
| Field | Type |
|---|---|
results |
List<Uint8List> |
failures |
int |
errors |
List<(int, String)> |
BatchProgress #
| Field | Type |
|---|---|
completed |
int |
total |
int |
percent |
double |
MetadataDiff #
| Field | Type |
|---|---|
changes |
List<MetadataChange> |
length |
int |
isEmpty |
bool |
MetadataChange<T> #
| Field | Type |
|---|---|
field |
TagField |
oldValue |
T? |
newValue |
T? |
type |
ChangeType |
ChangeType #
added, updated, removed
Requirements #
- Flutter >= 3.0.0
- Dart SDK >= 3.6.0
License #
hAudiotagger is open-source software licensed under the MIT License.
See the LICENSE file for more information.
❤️ Support #
If hAudiotagger helps you build something cool, consider:
- ⭐ Starring the repository
- 🐛 Reporting bugs
- 💡 Suggesting improvements
- 🤝 Contributing code
- 📦 Sharing the package with other Flutter developers
Every bit of support helps keep the project moving forward.
Made with ❤️ and 🦀.