-
Notifications
You must be signed in to change notification settings - Fork 2
TagPipeline
Hirdaya Shrestha edited this page Oct 3, 2026
·
1 revision
The TagPipeline is a 56-rule transformation engine for batch processing metadata. Apply consistent changes across multiple files with a reusable pipeline.
TagPipeline lets you define a set of transformations and apply them to one or many files. This is useful for:
- Library cleanup — Normalize whitespace, remove empty fields
- Consistency — Set default album artist across all files
- Batch editing — Apply the same changes to hundreds of files
- Preview — See what would change before writing
import 'package:haudiotagger/haudiotagger.dart';
// Create a pipeline
final pipeline = TagPipeline()
..trimWhitespace()
..normalizeUnicode()
..setAlbumArtist('Various Artists')
..removeLyrics()
..setGenre('Rock');
// Apply to a single file
await pipeline.processFile('/path/to/song.mp3');
// Apply to multiple files
await pipeline.process([
'/path/to/song1.mp3',
'/path/to/song2.mp3',
'/path/to/song3.mp3',
]);See what would change without writing:
final result = await pipeline.preview('/path/to/song.mp3');
print('Changes: ${result.changes.length}');
for (final change in result.changes) {
print('${change.field}: ${change.oldValue} → ${change.newValue}');
}| Rule | Description |
|---|---|
setTitle(value) |
Set title |
setArtist(value) |
Set artist |
setAlbum(value) |
Set album |
setAlbumArtist(value) |
Set album artist |
setGenre(value) |
Set genre |
setYear(value) |
Set year |
setTrackNumber(value) |
Set track number |
setDiscNumber(value) |
Set disc number |
setTrackTotal(value) |
Set track total |
setDiscTotal(value) |
Set disc total |
setBpm(value) |
Set BPM |
setComment(value) |
Set comment |
| Rule | Description |
|---|---|
removeTitle() |
Remove title |
removeArtist() |
Remove artist |
removeAlbum() |
Remove album |
removeAlbumArtist() |
Remove album artist |
removeGenre() |
Remove genre |
removeYear() |
Remove year |
removeTrackNumber() |
Remove track number |
removeDiscNumber() |
Remove disc number |
removeLyrics() |
Remove lyrics |
removeComment() |
Remove comment |
removePictures() |
Remove all pictures |
removeBpm() |
Remove BPM |
removeReplayGain() |
Remove ReplayGain tags |
| Rule | Description |
|---|---|
trimWhitespace() |
Trim leading/trailing whitespace |
normalizeWhitespace() |
Collapse multiple spaces to one |
normalizeUnicode() |
Normalize Unicode to NFC |
normalizeTrackNumbers() |
Fix track number formatting |
normalizeDiscNumbers() |
Fix disc number formatting |
normalizeYear() |
Fix year formatting |
| Rule | Description |
|---|---|
copyArtistToAlbumArtist() |
Copy artist to album artist |
copyAlbumArtistToArtist() |
Copy album artist to artist |
copyTitleToComment() |
Copy title to comment |
| Rule | Description |
|---|---|
prefixTitle(value) |
Add prefix to title |
suffixTitle(value) |
Add suffix to title |
prefixAlbum(value) |
Add prefix to album |
suffixAlbum(value) |
Add suffix to album |
prefixArtist(value) |
Add prefix to artist |
suffixArtist(value) |
Add suffix to artist |
| Rule | Description |
|---|---|
titleCaseTitle() |
Title case for title |
titleCaseArtist() |
Title case for artist |
titleCaseAlbum() |
Title case for album |
lowerCaseAll() |
Lowercase all fields |
upperCaseAll() |
Uppercase all fields |
| Rule | Description |
|---|---|
replaceInTitle(search, replace) |
Replace in title |
replaceInArtist(search, replace) |
Replace in artist |
replaceInAlbum(search, replace) |
Replace in album |
replaceInAll(search, replace) |
Replace in all fields |
| Rule | Description |
|---|---|
setTitleIfEmpty(value) |
Set title only if empty |
setArtistIfEmpty(value) |
Set artist only if empty |
setAlbumIfEmpty(value) |
Set album only if empty |
setGenreIfEmpty(value) |
Set genre only if empty |
setAlbumArtistIfEmpty(value) |
Set album artist only if empty |
| Rule | Description |
|---|---|
removeEmptyFields() |
Remove fields with empty values |
removeNonCoverPictures() |
Remove non-cover artwork |
// Preview from bytes
final result = await pipeline.previewFromBytes(fileBytes);
// Process from bytes
final modifiedBytes = await pipeline.processFromBytes(fileBytes);
// Process batch from bytes
final modifiedList = await pipeline.processBatchFromBytes([bytes1, bytes2]);final cleanup = TagPipeline()
..trimWhitespace()
..normalizeWhitespace()
..normalizeUnicode()
..removeEmptyFields()
..normalizeTrackNumbers()
..normalizeDiscNumbers();
await cleanup.process(allFiles);final compilation = TagPipeline()
..setAlbumArtist('Various Artists')
..setGenre('Compilation')
..setYear(2024);
await compilation.process(compilationFiles);final noArt = TagPipeline()
..removePictures();
await noArt.process(files);final branding = TagPipeline()
..prefixTitle('[My Podcast] ')
..setAlbumArtist('My Podcast')
..setGenre('Podcast')
..setComment('© 2024 My Podcast');
await branding.process(episodeFiles);Made with ❤️ and 🦀 by Hirdaya Shrestha