fix(downloader): downloaded track is corrupted for tagging

This commit is contained in:
Kingkor Roy Tirtho 2022-09-03 13:50:33 +06:00
parent 47ab4c588d
commit 2ab1fba3d6
4 changed files with 111 additions and 77 deletions

View File

@ -39,74 +39,96 @@ const imgMimeToExt = {
};
final localTracksProvider = FutureProvider<List<Track>>((ref) async {
final downloadDir = Directory(
ref.watch(userPreferencesProvider.select((s) => s.downloadLocation)),
);
if (!await downloadDir.exists()) {
await downloadDir.create(recursive: true);
try {
final downloadDir = Directory(
ref.watch(userPreferencesProvider.select((s) => s.downloadLocation)),
);
if (!await downloadDir.exists()) {
await downloadDir.create(recursive: true);
return [];
}
final entities = downloadDir.listSync(recursive: true);
final filesWithMetadata = (await Future.wait(
entities.map((e) => File(e.path)).where((file) {
final mimetype = lookupMimeType(file.path);
return mimetype != null && supportedAudioTypes.contains(mimetype);
}).map(
(f) async {
try {
final bytes = f.readAsBytes();
final mp3Instance = MP3Instance(await bytes);
bool isParsed = false;
try {
isParsed = mp3Instance.parseTagsSync();
} catch (e, stack) {
getLogger(MP3Instance).e("[parseTagsSync]", e, stack);
}
final imageFile = isParsed
? File(join(
(await getTemporaryDirectory()).path,
"spotube",
basenameWithoutExtension(f.path) +
imgMimeToExt[mp3Instance.metaTags["APIC"]?["mime"] ??
"image/jpeg"]!,
))
: null;
if (imageFile != null &&
!await imageFile.exists() &&
mp3Instance.metaTags["APIC"]?["base64"] != null) {
await imageFile.create(recursive: true);
await imageFile.writeAsBytes(
base64Decode(
mp3Instance.metaTags["APIC"]["base64"],
),
mode: FileMode.writeOnly,
);
}
Duration duration;
try {
duration = MP3Processor.fromBytes(await bytes).duration;
} catch (e, stack) {
getLogger(MP3Processor).e("[Parsing Mp3]", e, stack);
duration = Duration.zero;
}
final metadata = await tagProcessor.getTagsFromByteArray(bytes);
return {
"metadata": metadata,
"file": f,
"art": imageFile?.path,
"duration": duration,
};
} catch (e, stack) {
getLogger(FutureProvider).e("[Fetching metadata]", e, stack);
return {
"metadata": <Tag>[],
"file": f,
"duration": Duration.zero,
};
}
},
),
));
final tracks = filesWithMetadata
.map(
(fileWithMetadata) => TypeConversionUtils.localTrack_X_Track(
fileWithMetadata["metadata"] as List<Tag>,
fileWithMetadata["file"] as File,
fileWithMetadata["duration"] as Duration,
fileWithMetadata["art"] as String?,
),
)
.toList();
return tracks;
} catch (e, stack) {
getLogger(FutureProvider).e("[LocalTracksProvider]", e, stack);
return [];
}
final entities = downloadDir.listSync(recursive: true);
final filesWithMetadata = (await Future.wait(
entities.map((e) => File(e.path)).where((file) {
final mimetype = lookupMimeType(file.path);
return mimetype != null && supportedAudioTypes.contains(mimetype);
}).map(
(f) async {
final bytes = f.readAsBytes();
final mp3Instance = MP3Instance(await bytes);
final imageFile = mp3Instance.parseTagsSync()
? File(join(
(await getTemporaryDirectory()).path,
"spotube",
basenameWithoutExtension(f.path) +
imgMimeToExt[
mp3Instance.metaTags["APIC"]?["mime"] ?? "image/jpeg"]!,
))
: null;
if (imageFile != null &&
!await imageFile.exists() &&
mp3Instance.metaTags["APIC"]?["base64"] != null) {
await imageFile.create(recursive: true);
await imageFile.writeAsBytes(
base64Decode(
mp3Instance.metaTags["APIC"]["base64"],
),
mode: FileMode.writeOnly,
);
}
Duration duration;
try {
duration = MP3Processor.fromBytes(await bytes).duration;
} catch (e, stack) {
getLogger(MP3Processor).e("[Parsing Mp3]", e, stack);
duration = Duration.zero;
}
final metadata = await tagProcessor.getTagsFromByteArray(bytes);
return {
"metadata": metadata,
"file": f,
"art": imageFile?.path,
"duration": duration,
};
},
),
));
final tracks = filesWithMetadata
.map(
(fileWithMetadata) => TypeConversionUtils.localTrack_X_Track(
fileWithMetadata["metadata"] as List<Tag>,
fileWithMetadata["file"] as File,
fileWithMetadata["duration"] as Duration,
fileWithMetadata["art"] as String?,
),
)
.toList();
return tracks;
});
class UserLocalTracks extends HookConsumerWidget {

View File

@ -64,6 +64,20 @@ class Id3Tags {
"genre": genre,
"picture": picture,
};
String? get artist => tpe2;
String? get year => tdrc;
Map<String, String> toAndroidJson(String artwork) {
return {
"title": title ?? "Unknown",
"artist": artist ?? "Unknown",
"album": album ?? "Unknown",
"genre": genre ?? "Unknown",
"artwork": artwork,
"year": year ?? "Unknown",
};
}
}
extension CommentJson on Comment {

View File

@ -16,6 +16,7 @@ import 'package:spotube/models/SpotubeTrack.dart';
import 'package:spotube/provider/Playback.dart';
import 'package:spotube/provider/UserPreferences.dart';
import 'package:spotube/provider/YouTube.dart';
import 'package:spotube/utils/platform.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart' hide Comment;
@ -96,11 +97,15 @@ class Downloader with ChangeNotifier {
"[addToQueue] Download of ${file.path} is done successfully",
);
// Tagging isn't supported in Android currently
if (kIsAndroid) return;
final imageUri = TypeConversionUtils.image_X_UrlString(
track.album?.images ?? [],
);
final response = await get(
Uri.parse(
TypeConversionUtils.image_X_UrlString(
track.album?.images ?? [],
),
imageUri,
),
);
final picture = AttachedPicture.base64(

View File

@ -463,13 +463,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
eztags:
dependency: "direct main"
description:
name: eztags
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
fading_edge_scrollview:
dependency: transitive
description:
@ -1417,5 +1410,5 @@ packages:
source: hosted
version: "1.11.0"
sdks:
dart: ">=2.17.5 <3.0.0"
dart: ">=2.17.1 <3.0.0"
flutter: ">=3.0.0"