diff --git a/lib/components/Library/UserLocalTracks.dart b/lib/components/Library/UserLocalTracks.dart index 8648467ea..152b1a71c 100644 --- a/lib/components/Library/UserLocalTracks.dart +++ b/lib/components/Library/UserLocalTracks.dart @@ -39,74 +39,96 @@ const imgMimeToExt = { }; final localTracksProvider = FutureProvider>((ref) async { - 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 { - final bytes = f.readAsBytes(); - final mp3Instance = MP3Instance(await bytes); + 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 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 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); - final metadata = await tagProcessor.getTagsFromByteArray(bytes); - return { - "metadata": metadata, - "file": f, - "art": imageFile?.path, - "duration": duration, - }; - }, - ), - )); + bool isParsed = false; + try { + isParsed = mp3Instance.parseTagsSync(); + } catch (e, stack) { + getLogger(MP3Instance).e("[parseTagsSync]", e, stack); + } - final tracks = filesWithMetadata - .map( - (fileWithMetadata) => TypeConversionUtils.localTrack_X_Track( - fileWithMetadata["metadata"] as List, - fileWithMetadata["file"] as File, - fileWithMetadata["duration"] as Duration, - fileWithMetadata["art"] as String?, - ), - ) - .toList(); + 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; + } - return tracks; + 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": [], + "file": f, + "duration": Duration.zero, + }; + } + }, + ), + )); + + final tracks = filesWithMetadata + .map( + (fileWithMetadata) => TypeConversionUtils.localTrack_X_Track( + fileWithMetadata["metadata"] as List, + 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 []; + } }); class UserLocalTracks extends HookConsumerWidget { diff --git a/lib/models/Id3Tags.dart b/lib/models/Id3Tags.dart index 746773ab0..c2d0f885c 100644 --- a/lib/models/Id3Tags.dart +++ b/lib/models/Id3Tags.dart @@ -64,6 +64,20 @@ class Id3Tags { "genre": genre, "picture": picture, }; + + String? get artist => tpe2; + String? get year => tdrc; + + Map 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 { diff --git a/lib/provider/Downloader.dart b/lib/provider/Downloader.dart index 68634e31a..c8f4f2385 100644 --- a/lib/provider/Downloader.dart +++ b/lib/provider/Downloader.dart @@ -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( diff --git a/pubspec.lock b/pubspec.lock index 9922b11bb..a0dcd9c88 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -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"