mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
fix(downloader): downloaded track is corrupted for tagging
This commit is contained in:
parent
47ab4c588d
commit
2ab1fba3d6
@ -39,74 +39,96 @@ const imgMimeToExt = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
final localTracksProvider = FutureProvider<List<Track>>((ref) async {
|
final localTracksProvider = FutureProvider<List<Track>>((ref) async {
|
||||||
final downloadDir = Directory(
|
try {
|
||||||
ref.watch(userPreferencesProvider.select((s) => s.downloadLocation)),
|
final downloadDir = Directory(
|
||||||
);
|
ref.watch(userPreferencesProvider.select((s) => s.downloadLocation)),
|
||||||
if (!await downloadDir.exists()) {
|
);
|
||||||
await downloadDir.create(recursive: true);
|
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 [];
|
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 {
|
class UserLocalTracks extends HookConsumerWidget {
|
||||||
|
@ -64,6 +64,20 @@ class Id3Tags {
|
|||||||
"genre": genre,
|
"genre": genre,
|
||||||
"picture": picture,
|
"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 {
|
extension CommentJson on Comment {
|
||||||
|
@ -16,6 +16,7 @@ import 'package:spotube/models/SpotubeTrack.dart';
|
|||||||
import 'package:spotube/provider/Playback.dart';
|
import 'package:spotube/provider/Playback.dart';
|
||||||
import 'package:spotube/provider/UserPreferences.dart';
|
import 'package:spotube/provider/UserPreferences.dart';
|
||||||
import 'package:spotube/provider/YouTube.dart';
|
import 'package:spotube/provider/YouTube.dart';
|
||||||
|
import 'package:spotube/utils/platform.dart';
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
import 'package:youtube_explode_dart/youtube_explode_dart.dart' hide Comment;
|
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",
|
"[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(
|
final response = await get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
TypeConversionUtils.image_X_UrlString(
|
imageUri,
|
||||||
track.album?.images ?? [],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final picture = AttachedPicture.base64(
|
final picture = AttachedPicture.base64(
|
||||||
|
@ -463,13 +463,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
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:
|
fading_edge_scrollview:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1417,5 +1410,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.17.5 <3.0.0"
|
dart: ">=2.17.1 <3.0.0"
|
||||||
flutter: ">=3.0.0"
|
flutter: ">=3.0.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user