Skip to content
71 changes: 15 additions & 56 deletions example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,19 @@ import 'dart:io';
import 'dart:typed_data';

import 'package:audio_metadata_reader/audio_metadata_reader.dart';

void main() {
final track = File("Pieces.mp3");

// Returns a condensate
// Getting the image of a track can be heavy and slow the reading
final metadata = readMetadata(track, getImage: false);

print(metadata.title);
print(metadata.album);
print(metadata.duration);
// etc...

// If you need ALL the metadata of a file (eg. MP3 has bpm)
// Later you need to check the type of the metadata with a switch
// ignore: unused_local_variable
final allMetadata = readAllMetadata(track, getImage: true);

print("Now we are going to rewrite the metadata");

// Use the switch if you want to update metadata for a specific format
updateMetadata(
track,
(metadata) {
switch (metadata) {
case Mp3Metadata m:
m.songName = "New title";
break;
case Mp4Metadata m:
m.title = "New title";
break;
case VorbisMetadata m:
m.title = ["New title"];
break;
case RiffMetadata m:
m.title = "New title";
}
},
);

// Or use the extension methods to update common properties
updateMetadata(
track,
(metadata) {
metadata.setTitle("New title");
metadata.setArtist("New artist");
metadata.setAlbum("New album");
metadata.setTrackNumber(1);
metadata.setYear(DateTime(2014));
metadata.setLyrics("I'm singing");
metadata.setGenres(["Rock", "Metal", "Salsa"]);
metadata.setPictures([
Picture(Uint8List.fromList([]), "image/png", PictureType.coverFront)
]);
},
);
import 'package:audio_metadata_reader/src/parser.dart';
import 'package:webdav_client/webdav_client.dart' as webdav;

final client = webdav.newClient(
"https://xxx.xxx.xx/dav",
user: 'xxx',
password: 'xxxxxx',
);

void main() async {
File file = File('/Users/lyp/Music/LZF-Music/After Hours - The Weeknd.flac');
Uint8List data = await file.readAsBytes();
print(data.length);
final metadata = await readMetadataUint8List(Stream.value(data), getImage: true);
print(metadata);
}
3 changes: 1 addition & 2 deletions lib/audio_metadata_reader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ export "src/parsers/tag_parser.dart" show AudioMetadata, Picture;
export 'src/metadata/base.dart' show PictureType;
export 'src/utils/metadata_parser_exception.dart'
show MetadataParserException, NoMetadataParserException;
export 'src/parser.dart' show readMetadata;
export 'src/utils/metadata_parser_exception.dart' show MetadataParserException;
export 'src/parser.dart' show readMetadata, readAllMetadata;
export 'src/parser.dart' show readMetadata, readAllMetadata,readMetadataFile,readMetadataUint8List,readMetadataWebDav;
export 'src/writer.dart' show updateMetadata, writeMetadata;

export 'src/parsers/id3v1.dart' show ID3v1Parser;
Expand Down
3 changes: 2 additions & 1 deletion lib/src/metadata/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ extension CommonMetadataSetters on ParserTag {
case VorbisMetadata m:
m.lyric = lyric;
break;
case RiffMetadata():
case RiffMetadata m:
m.lyric = lyric;
break;
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/src/metadata/riff_metadata.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class RiffMetadata extends ParserTag {
String? album;
DateTime? year;
String? comment;
String? lyric;
String? genre;
int? trackNumber;
String? encoder;
Expand All @@ -22,6 +23,7 @@ class RiffMetadata extends ParserTag {
this.album,
this.year,
this.comment,
this.lyric,
this.genre,
this.trackNumber,
this.encoder,
Expand All @@ -40,6 +42,7 @@ class RiffMetadata extends ParserTag {
' album: $album,\n'
' year: $year,\n'
' comment: $comment,\n'
' lyrics: $lyric,\n'
' genre: $genre,\n'
' trackNumber: $trackNumber,\n'
' encoder: $encoder,\n'
Expand Down
126 changes: 64 additions & 62 deletions lib/src/parser.dart
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
import 'dart:io';
import 'dart:typed_data';

import 'package:audio_metadata_reader/audio_metadata_reader.dart';
import 'package:audio_metadata_reader/src/parsers/riff.dart';
import 'package:audio_metadata_reader/src/metadata/base.dart';
import 'package:audio_metadata_reader/src/utils/buffer.dart';
import 'package:webdav_client/webdav_client.dart' as webdav;

/// Parse the metadata of a file.
///
/// It automatically detects the type of the file (`.mp3`, `.ogg`, `.flac` etc)
/// and select the matching file parser.
///
/// If there's no parser or an error, a `MetadataParserException` exception is raised.
///
/// By default, it does not fetch the images of the file. Because some
/// images/covers are sometimes huge (~5MB), it can drastically make the
/// parsing slower.
AudioMetadata readMetadata(File track, {bool getImage = false}) {
final reader = track.openSync();

Future<AudioMetadata> readMetadataFile(File track, {bool getImage = false}) async {
MyRandomAccessFile reader = FileRandomAccessFile(randomAccessFile: track.openSync());
return readMetadata(reader, getImage: getImage);
}


Future<AudioMetadata> readMetadataWebDav(webdav.Client client, String path,
{bool getImage = false}) async {
final reader = WebDavRandomAccessFile(client: client, path: path);
return readMetadata(reader, getImage: getImage);
}

Future<AudioMetadata> readMetadataUint8List(Stream<Uint8List> data,{bool getImage = false}) async {
final reader = StreamRandomAccessFile(stream: data);
return readMetadata(reader, getImage: getImage);
}



Future<AudioMetadata> readMetadata(MyRandomAccessFile reader,
{bool getImage = false}) async {
try {
if (ID3v2Parser.canUserParser(reader)) {
final mp3Metadata =
ID3v2Parser(fetchImage: getImage).parse(reader) as Mp3Metadata;
if (await ID3v2Parser.canUserParser(reader)) {
final mp3Metadata = (await ID3v2Parser(fetchImage: getImage)
.parse(reader)) as Mp3Metadata;

final a = AudioMetadata(
file: track,
file: File(''),
album: mp3Metadata.album,
artist: mp3Metadata.bandOrOrchestra ??
mp3Metadata.leadPerformer ??
Expand Down Expand Up @@ -52,12 +64,12 @@ AudioMetadata readMetadata(File track, {bool getImage = false}) {
}

return a;
} else if (FlacParser.canUserParser(reader)) {
final vorbisMetadata =
FlacParser(fetchImage: getImage).parse(reader) as VorbisMetadata;
} else if (await FlacParser.canUserParser(reader)) {
final vorbisMetadata = (await FlacParser(fetchImage: getImage)
.parse(reader)) as VorbisMetadata;

final newMetadata = AudioMetadata(
file: track,
file: File(''),
album: vorbisMetadata.album.firstOrNull,
artist: vorbisMetadata.artist.firstOrNull,
bitrate: vorbisMetadata.bitrate,
Expand All @@ -78,12 +90,12 @@ AudioMetadata readMetadata(File track, {bool getImage = false}) {
newMetadata.performers.addAll(vorbisMetadata.performer);

return newMetadata;
} else if (MP4Parser.canUserParser(reader)) {
} else if (await MP4Parser.canUserParser(reader)) {
final mp4Metadata =
MP4Parser(fetchImage: getImage).parse(reader) as Mp4Metadata;
(await MP4Parser(fetchImage: getImage).parse(reader)) as Mp4Metadata;

final newMetadata = AudioMetadata(
file: track,
file: File(''),
album: mp4Metadata.album,
artist: mp4Metadata.artist,
bitrate: mp4Metadata.bitrate,
Expand All @@ -108,12 +120,12 @@ AudioMetadata readMetadata(File track, {bool getImage = false}) {
}

return newMetadata;
} else if (OGGParser.canUserParser(reader)) {
final oggMetadata =
OGGParser(fetchImage: getImage).parse(reader) as VorbisMetadata;
} else if (await OGGParser.canUserParser(reader)) {
final oggMetadata = (await OGGParser(fetchImage: getImage).parse(reader))
as VorbisMetadata;

final newMetadata = AudioMetadata(
file: track,
file: File(''),
album: oggMetadata.album.firstOrNull,
artist: oggMetadata.artist.firstOrNull,
bitrate: oggMetadata.bitrate,
Expand All @@ -133,17 +145,17 @@ AudioMetadata readMetadata(File track, {bool getImage = false}) {
newMetadata.performers.addAll(oggMetadata.performer);

return newMetadata;
} else if (RiffParser.canUserParser(reader)) {
final riffMetadata = RiffParser().parse(reader) as RiffMetadata;
} else if (await RiffParser.canUserParser(reader)) {
final riffMetadata = (await RiffParser().parse(reader)) as RiffMetadata;

final newMetadata = AudioMetadata(
file: track,
file: File(''),
album: riffMetadata.album,
artist: riffMetadata.artist,
bitrate: riffMetadata.bitrate,
duration: riffMetadata.duration,
language: null,
lyrics: null,
lyrics: riffMetadata.comment,
sampleRate: riffMetadata.samplerate,
title: riffMetadata.title,
totalDisc: null,
Expand All @@ -158,11 +170,11 @@ AudioMetadata readMetadata(File track, {bool getImage = false}) {
(riffMetadata.genre != null) ? [riffMetadata.genre!] : [];

return newMetadata;
} else if (ID3v1Parser.canUserParser(reader)) {
final mp3Metadata = ID3v1Parser().parse(reader) as Mp3Metadata;
} else if (await ID3v1Parser.canUserParser(reader)) {
final mp3Metadata = (await ID3v1Parser().parse(reader)) as Mp3Metadata;

final newMetadata = AudioMetadata(
file: track,
file: File(''),
album: mp3Metadata.album,
artist: mp3Metadata.bandOrOrchestra ??
mp3Metadata.originalArtist ??
Expand All @@ -188,50 +200,40 @@ AudioMetadata readMetadata(File track, {bool getImage = false}) {
}
} on MetadataParserException catch (e, s) {
Error.throwWithStackTrace(
MetadataParserException(track: track, message: e.message), s);
MetadataParserException(track: reader, message: e.message), s);
} catch (e, s) {
Error.throwWithStackTrace(
MetadataParserException(track: track, message: e.toString()), s);
MetadataParserException(track: reader, message: e.toString()), s);
}

throw NoMetadataParserException(
track: track,
track: reader,
);
}

/// Parse the metadata of a file and return ALL the metadata. It contains more information
/// than `readMetadata(...)` but you need more knowledges about the metadata specifications.
///
/// Use this one if you want to rewrite the metadata later.
///
/// It automatically detects the type of the file (`.mp3`, `.ogg`, `.flac` etc)
/// and select the matching file parser.
///
/// If there's no parser or an error, a `MetadataParserException` exception is raised.
///
/// By default, it fetches the cover images
ParserTag readAllMetadata(File track, {bool getImage = true}) {
final reader = track.openSync();

Future<ParserTag> readAllMetadata(MyRandomAccessFile reader, {bool getImage = true}) async {
try {
if (ID3v2Parser.canUserParser(reader)) {
return ID3v2Parser(fetchImage: getImage).parse(reader);
} else if (FlacParser.canUserParser(reader)) {
return FlacParser(fetchImage: getImage).parse(reader);
} else if (MP4Parser.canUserParser(reader)) {
return MP4Parser(fetchImage: getImage).parse(reader);
} else if (OGGParser.canUserParser(reader)) {
return OGGParser(fetchImage: getImage).parse(reader);
} else if (ID3v2Parser.isID3v1(reader)) {
return ID3v1Parser().parse(reader);
if (await ID3v2Parser.canUserParser(reader)) {
return await ID3v2Parser(fetchImage: getImage).parse(reader);
} else if (await FlacParser.canUserParser(reader)) {
return await FlacParser(fetchImage: getImage).parse(reader);
} else if (await MP4Parser.canUserParser(reader)) {
return await MP4Parser(fetchImage: getImage).parse(reader);
} else if (await OGGParser.canUserParser(reader)) {
return await OGGParser(fetchImage: getImage).parse(reader);
} else if (await ID3v2Parser.isID3v1(reader)) {
return await ID3v1Parser().parse(reader);
} else if (await RiffParser.canUserParser(reader)) {
return await RiffParser().parse(reader);
}
} catch (e, trace) {
print(trace);
throw MetadataParserException(track: track, message: e.toString());
throw MetadataParserException(track: reader, message: e.toString());
}

throw MetadataParserException(
track: track,
track: reader,
message:
"No available parser for this file. Please raise an issue in Github",
);
Expand Down
Loading