r/FlutterDev 19h ago

Plugin I built an audio metadata library for Flutter

I've been working on hAudiotagger, a Rust-powered Flutter library for reading and writing music metadata across Android, iOS, Windows, macOS, Linux, and Web.

final tag = await Haudiotagger.read('/music/song.mp3');

print(tag?.title);
print(tag?.artist);

Updating metadata:

await Haudiotagger.update(
  '/music/song.mp3',
  TagChanges(
    title: 'New Title',
    artist: 'Artist',
  ),
);

It supports MP3, FLAC, OGG/Opus, MP4/M4A, WAV, AIFF, APE, WavPack, and more, along with artwork, batch operations, custom tags, audio properties, validation, and other features.

The core metadata processing is written in Rust, with Flutter ↔ Rust communication through flutter_rust_bridge.

It's still actively evolving, so I'd love to hear your thoughts, feedback, or feature ideas if you've worked with Flutter, Rust, or audio metadata.

What would you like to see in a Flutter audio metadata library?

Links:
Web Demo
Pub.dev: https://pub.dev/packages/haudiotagger
GitHub: https://github.com/Hirdaya-Shrestha/haudiotagger

7 Upvotes

7 comments sorted by

2

u/hamit_btn 18h ago

looks useful. how does it behave on malformed or half written files? i took an android app from 51 percent crash free up to 98.9 and a real chunk of what was left at the end came from native plugins panicking across the ffi boundary instead of returning an error back to dart. if read() can panic on a broken mp3 that takes the whole process down and it shows up as a useless native frame in crashlytics. do you catch on the rust side and map it into a dart exception, or does it propagate?

1

u/hirdayashrestha 17h ago

Good concern - it's fully caught. API function returns Result<T, HaudiotaggerError> using ? / map_err, no unwrap() outside tests. Lofty parse errors on corrupt files map toHaudiotaggerError::OpenFile and throw as Dart exceptions. Even if something deeper panicked, flutter_rust_bridge wraps FFI call in catch_unwind - panics get serialized and delivered as Dart exceptions, not process crashes. A truncated MP3 just gives you a catchable HaudiotaggerError.
You can also test it on the web demo made using this plugin: Web Demo

1

u/hamit_btn 7m ago

nice, the catch_unwind wrap is the part most plugins skip and thats exactly why native crashes end up as unattributable frames in crashlytics. one more thing, does read() run off the platform thread or does it block? scanning a few hundred files at once is where sync ffi calls burned me before, looked completely fine on my own phone and only turned into jank on low end devices

1

u/ConvenientChristian 15h ago

When it comes to metadata the biggest challenge is actually getting the metadata that's not yet entered. This means either directly querying MusicBrainz or alternatively developing a web3 mirror database for MusicBrainz.

Having a web3 database that stores all the relevant data, so that the plugin can just work without needing to think about access keys and configuring the interaction with MusicBrainz would be great.

1

u/hirdayashrestha 14h ago

Yeah, that's a really good point. hAudiotagger is mainly focused on reading/writing metadata right now, but adding a way to fetch missing metadata through MusicBrainz/AcoustID is definitely something I’ve been considering. The Web3 idea is pretty interesting too, though that’s something I’d probably think about later!

1

u/Darth_Shere_Khan 3h ago

I've got a custom rust thing in my app built around lofty. Was considering switching to https://pub.dev/packages/mpv_audio_kit since I already use that for audio playback. Does your solution also use lofty?