From e206f16723ac989ad58006c1b3c90c6691d8cab3 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 3 Sep 2022 09:42:41 +0600 Subject: [PATCH 1/2] feat(local-tracks): complete support for local tracks Downloaded tracks are saved with metadata. Only MP3 file metadata support is available in local track player for now --- assets/album-placeholder.png | Bin 0 -> 95911 bytes lib/components/Home/Sidebar.dart | 12 + lib/components/Library/UserDownloads.dart | 4 +- lib/components/Library/UserLibrary.dart | 8 +- lib/components/Library/UserLocalTracks.dart | 230 ++++++++++++--- lib/components/Lyrics/SyncedLyrics.dart | 6 +- lib/components/Player/Player.dart | 10 +- lib/components/Player/PlayerTrackDetails.dart | 15 +- lib/components/Player/PlayerView.dart | 12 +- .../Shared/DownloadTrackButton.dart | 8 +- lib/components/Shared/TrackTile.dart | 116 ++++---- lib/components/Shared/TracksTableView.dart | 275 +++++++++--------- lib/components/Shared/UniversalImage.dart | 98 +++++++ lib/hooks/usePaletteColor.dart | 15 +- lib/models/CurrentPlaylist.dart | 4 + lib/models/Id3Tags.dart | 143 +++++++++ lib/provider/Downloader.dart | 56 +++- lib/provider/Playback.dart | 11 +- lib/utils/type_conversion_utils.dart | 69 +++-- linux/flutter/generated_plugin_registrant.cc | 4 - linux/flutter/generated_plugins.cmake | 1 - macos/Flutter/GeneratedPluginRegistrant.swift | 2 - pubspec.lock | 73 +++-- pubspec.yaml | 5 +- .../flutter/generated_plugin_registrant.cc | 3 - windows/flutter/generated_plugins.cmake | 1 - 26 files changed, 856 insertions(+), 325 deletions(-) create mode 100644 assets/album-placeholder.png create mode 100644 lib/components/Shared/UniversalImage.dart create mode 100644 lib/models/Id3Tags.dart diff --git a/assets/album-placeholder.png b/assets/album-placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..bcb25969b641d9157b78be510af39555966941b0 GIT binary patch literal 95911 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

teBTI@5-@zOML&EE?o+jfAS* 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 Container( + height: 16, + width: 16, + color: Theme.of(context).cardColor, + ), ), const SizedBox(width: 10), Text( @@ -176,6 +182,12 @@ class Sidebar extends HookConsumerWidget { child: CircleAvatar( backgroundImage: CachedNetworkImageProvider(avatarImg), + onBackgroundImageError: (exception, stackTrace) => + Container( + height: 16, + width: 16, + color: Theme.of(context).cardColor, + ), ), ), ); diff --git a/lib/components/Library/UserDownloads.dart b/lib/components/Library/UserDownloads.dart index ac7d3fd2..916c0c95 100644 --- a/lib/components/Library/UserDownloads.dart +++ b/lib/components/Library/UserDownloads.dart @@ -69,8 +69,8 @@ class UserDownloads extends HookConsumerWidget { ), horizontalTitleGap: 5, subtitle: Text( - TypeConversionUtils.artists_X_String( - track.artists ?? [], + TypeConversionUtils.artists_X_String( + track.artists ?? [], ), ), ); diff --git a/lib/components/Library/UserLibrary.dart b/lib/components/Library/UserLibrary.dart index 760d34fc..1dd350cc 100644 --- a/lib/components/Library/UserLibrary.dart +++ b/lib/components/Library/UserLibrary.dart @@ -20,18 +20,18 @@ class UserLibrary extends ConsumerWidget { isScrollable: true, tabs: [ Tab(text: "Playlist"), - Tab(text: "Artists"), - Tab(text: "Album"), Tab(text: "Downloads"), Tab(text: "Local"), + Tab(text: "Artists"), + Tab(text: "Album"), ], ), body: TabBarView(children: [ const AnonymousFallback(child: UserPlaylists()), - AnonymousFallback(child: UserArtists()), - const AnonymousFallback(child: UserAlbums()), const UserDownloads(), const UserLocalTracks(), + AnonymousFallback(child: UserArtists()), + const AnonymousFallback(child: UserAlbums()), ]), ), ), diff --git a/lib/components/Library/UserLocalTracks.dart b/lib/components/Library/UserLocalTracks.dart index 2aa56cc9..8648467e 100644 --- a/lib/components/Library/UserLocalTracks.dart +++ b/lib/components/Library/UserLocalTracks.dart @@ -1,13 +1,26 @@ +import 'dart:convert'; import 'dart:io'; +import 'package:dart_tags/dart_tags.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:flutter_media_metadata/flutter_media_metadata.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:mime/mime.dart'; +import 'package:mp3_info/mp3_info.dart'; +import 'package:path/path.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/components/LoaderShimmers/ShimmerTrackTile.dart'; +import 'package:spotube/components/Shared/TrackTile.dart'; +import 'package:spotube/models/CurrentPlaylist.dart'; +import 'package:spotube/models/Logger.dart'; +import 'package:spotube/provider/Playback.dart'; import 'package:spotube/provider/UserPreferences.dart'; +import 'package:spotube/utils/primitive_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; +import 'package:id3/id3.dart'; + +final tagProcessor = TagProcessor(); const supportedAudioTypes = [ "audio/webm", @@ -18,54 +31,193 @@ const supportedAudioTypes = [ "audio/aac", ]; -List usePullLocalTracks(WidgetRef ref) { +const imgMimeToExt = { + "image/png": ".png", + "image/jpeg": ".jpg", + "image/webp": ".webp", + "image/gif": ".gif", +}; + +final localTracksProvider = FutureProvider>((ref) async { final downloadDir = Directory( ref.watch(userPreferencesProvider.select((s) => s.downloadLocation)), ); - final localTracks = useState>([]); + 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); - useEffect(() { - (() async { - 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 => { - "metadata": await MetadataRetriever.fromFile(f), - "file": f, - }, + 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, + fileWithMetadata["file"] as File, + fileWithMetadata["duration"] as Duration, + fileWithMetadata["art"] as String?, ), - )); + ) + .toList(); - final tracks = filesWithMetadata - .map( - (fileWithMetadata) => TypeConversionUtils.localTrack_X_Track( - fileWithMetadata["metadata"] as Metadata, - fileWithMetadata["file"] as File), - ) - .toList(); - - localTracks.value = tracks; - })(); - - return; - }, [downloadDir]); - - return localTracks.value; -} + return tracks; +}); class UserLocalTracks extends HookConsumerWidget { const UserLocalTracks({Key? key}) : super(key: key); + void playLocalTracks(Playback playback, List tracks, + {Track? currentTrack}) async { + currentTrack ??= tracks.first; + final isPlaylistPlaying = playback.playlist?.id == "local"; + if (!isPlaylistPlaying) { + await playback.playPlaylist( + CurrentPlaylist( + tracks: tracks, + id: "local", + name: "Local Tracks", + thumbnail: TypeConversionUtils.image_X_UrlString(null), + isLocal: true, + ), + tracks.indexWhere((s) => s.id == currentTrack?.id), + ); + } else if (isPlaylistPlaying && + currentTrack.id != null && + currentTrack.id != playback.track?.id) { + await playback.play(currentTrack); + } + } + @override Widget build(BuildContext context, ref) { - final tracks = usePullLocalTracks(ref); - return Column(); + final playback = ref.watch(playbackProvider); + final isPlaylistPlaying = playback.playlist?.id == "local"; + final trackSnapshot = ref.watch(localTracksProvider); + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + const SizedBox(width: 10), + ElevatedButton.icon( + label: const Text("Play"), + icon: Icon( + isPlaylistPlaying + ? Icons.stop_rounded + : Icons.play_arrow_rounded, + ), + onPressed: trackSnapshot.value != null + ? () { + if (trackSnapshot.value?.isNotEmpty == true) { + if (!isPlaylistPlaying) { + playLocalTracks(playback, trackSnapshot.value!); + } else { + playback.stop(); + } + } + } + : null, + ), + const Spacer(), + ElevatedButton( + child: const Icon(Icons.refresh_rounded), + onPressed: () { + ref.refresh(localTracksProvider); + }, + ) + ], + ), + ), + trackSnapshot.when( + data: (tracks) { + return Expanded( + child: ListView.builder( + itemCount: tracks.length, + itemBuilder: (context, index) { + final track = tracks[index]; + return TrackTile( + playback, + duration: + "${track.duration?.inMinutes.remainder(60)}:${PrimitiveUtils.zeroPadNumStr(track.duration?.inSeconds.remainder(60) ?? 0)}", + track: MapEntry(index, track), + isActive: playback.track?.id == track.id, + isChecked: false, + showCheck: false, + thumbnailUrl: track.album?.images?.isNotEmpty == true + ? track.album?.images?.single.url + : "assets/album-placeholder.png", + isLocal: true, + onTrackPlayButtonPressed: (currentTrack) { + if (tracks.isNotEmpty) { + if (!isPlaylistPlaying) { + playLocalTracks( + playback, + tracks, + currentTrack: track, + ); + } else { + playback.stop(); + } + } + }, + ); + }, + ), + ); + }, + loading: () => const ShimmerTrackTile(noSliver: true), + error: (error, stackTrace) => + Text(error.toString() + stackTrace.toString()), + ) + ], + ); + ; } } diff --git a/lib/components/Lyrics/SyncedLyrics.dart b/lib/components/Lyrics/SyncedLyrics.dart index b825c276..1610460e 100644 --- a/lib/components/Lyrics/SyncedLyrics.dart +++ b/lib/components/Lyrics/SyncedLyrics.dart @@ -11,6 +11,7 @@ import 'package:spotube/components/Lyrics/LyricDelayAdjustDialog.dart'; import 'package:spotube/components/Lyrics/Lyrics.dart'; import 'package:spotube/components/Shared/PageWindowTitleBar.dart'; import 'package:spotube/components/Shared/SpotubeMarqueeText.dart'; +import 'package:spotube/components/Shared/UniversalImage.dart'; import 'package:spotube/hooks/useAutoScrollController.dart'; import 'package:spotube/hooks/useBreakpoints.dart'; import 'package:spotube/hooks/useCustomStatusBarColor.dart'; @@ -132,10 +133,7 @@ class SyncedLyrics extends HookConsumerWidget { clipBehavior: Clip.hardEdge, decoration: BoxDecoration( image: DecorationImage( - image: CachedNetworkImageProvider( - albumArt, - cacheKey: albumArt, - ), + image: UniversalImage.imageProvider(albumArt), fit: BoxFit.cover, ), ), diff --git a/lib/components/Player/Player.dart b/lib/components/Player/Player.dart index 505ebd2d..3a0e0832 100644 --- a/lib/components/Player/Player.dart +++ b/lib/components/Player/Player.dart @@ -21,10 +21,12 @@ class Player extends HookConsumerWidget { final breakpoint = useBreakpoints(); String albumArt = useMemoized( - () => TypeConversionUtils.image_X_UrlString( - playback.track?.album?.images, - index: (playback.track?.album?.images?.length ?? 1) - 1, - ), + () => playback.track?.album?.images?.isNotEmpty == true + ? TypeConversionUtils.image_X_UrlString( + playback.track?.album?.images, + index: (playback.track?.album?.images?.length ?? 1) - 1, + ) + : "assets/album-placeholder.png", [playback.track?.album?.images], ); diff --git a/lib/components/Player/PlayerTrackDetails.dart b/lib/components/Player/PlayerTrackDetails.dart index b66f6816..4a8a0342 100644 --- a/lib/components/Player/PlayerTrackDetails.dart +++ b/lib/components/Player/PlayerTrackDetails.dart @@ -1,6 +1,6 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/components/Shared/UniversalImage.dart'; import 'package:spotube/hooks/useBreakpoints.dart'; import 'package:spotube/provider/Playback.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; @@ -21,16 +21,15 @@ class PlayerTrackDetails extends HookConsumerWidget { if (albumArt != null) Padding( padding: const EdgeInsets.all(5.0), - child: CachedNetworkImage( - imageUrl: albumArt!, - maxHeightDiskCache: 50, - maxWidthDiskCache: 50, - cacheKey: albumArt, + child: UniversalImage( + path: albumArt!, + height: 50, + width: 50, placeholder: (context, url) { - return Container( + return Image.asset( + "assets/album-placeholder.png", height: 50, width: 50, - color: Theme.of(context).primaryColor, ); }, ), diff --git a/lib/components/Player/PlayerView.dart b/lib/components/Player/PlayerView.dart index 0d90ae74..4a33c16d 100644 --- a/lib/components/Player/PlayerView.dart +++ b/lib/components/Player/PlayerView.dart @@ -10,6 +10,7 @@ import 'package:spotube/components/Player/PlayerActions.dart'; import 'package:spotube/components/Player/PlayerControls.dart'; import 'package:spotube/components/Shared/PageWindowTitleBar.dart'; import 'package:spotube/components/Shared/SpotubeMarqueeText.dart'; +import 'package:spotube/components/Shared/UniversalImage.dart'; import 'package:spotube/hooks/useBreakpoints.dart'; import 'package:spotube/hooks/useCustomStatusBarColor.dart'; import 'package:spotube/hooks/usePaletteColor.dart'; @@ -57,10 +58,7 @@ class PlayerView extends HookConsumerWidget { body: Container( decoration: BoxDecoration( image: DecorationImage( - image: CachedNetworkImageProvider( - albumArt, - cacheKey: albumArt, - ), + image: UniversalImage.imageProvider(albumArt), fit: BoxFit.cover, ), ), @@ -121,10 +119,8 @@ class PlayerView extends HookConsumerWidget { shape: BoxShape.circle, ), child: CircleAvatar( - backgroundImage: CachedNetworkImageProvider( - albumArt, - cacheKey: albumArt, - ), + backgroundImage: + UniversalImage.imageProvider(albumArt), radius: MediaQuery.of(context).size.width * (breakpoint.isSm ? 0.4 : 0.3), ), diff --git a/lib/components/Shared/DownloadTrackButton.dart b/lib/components/Shared/DownloadTrackButton.dart index e768d840..64b395f4 100644 --- a/lib/components/Shared/DownloadTrackButton.dart +++ b/lib/components/Shared/DownloadTrackButton.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/components/Library/UserLocalTracks.dart'; import 'package:spotube/models/SpotubeTrack.dart'; import 'package:spotube/provider/Playback.dart'; import 'package:spotube/provider/UserPreferences.dart'; @@ -89,6 +90,7 @@ class DownloadTrackButton extends HookConsumerWidget { }, onDone: () async { status.value = TrackStatus.done; + ref.refresh(localTracksProvider); await Future.delayed( const Duration(seconds: 3), () { @@ -187,7 +189,11 @@ class DownloadTrackButton extends HookConsumerWidget { icon: Icon( outputFileExists ? Icons.download_done_rounded : Icons.download_rounded, ), - onPressed: track != null && track is SpotubeTrack ? _downloadTrack : null, + onPressed: track != null && + track is SpotubeTrack && + playback.playlist?.isLocal != true + ? _downloadTrack + : null, ); } } diff --git a/lib/components/Shared/TrackTile.dart b/lib/components/Shared/TrackTile.dart index e0988905..c09c1d39 100644 --- a/lib/components/Shared/TrackTile.dart +++ b/lib/components/Shared/TrackTile.dart @@ -1,11 +1,11 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart' hide Action; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotify/spotify.dart'; +import 'package:spotify/spotify.dart' hide Image; import 'package:spotube/components/Shared/AdaptivePopupMenuButton.dart'; import 'package:spotube/components/Shared/LinkText.dart'; +import 'package:spotube/components/Shared/UniversalImage.dart'; import 'package:spotube/hooks/useBreakpoints.dart'; import 'package:spotube/hooks/useForceUpdate.dart'; import 'package:spotube/models/Logger.dart'; @@ -32,6 +32,8 @@ class TrackTile extends HookConsumerWidget { final bool isChecked; final bool showCheck; + + final bool isLocal; final void Function(bool?)? onCheckChange; TrackTile( @@ -46,12 +48,17 @@ class TrackTile extends HookConsumerWidget { this.showAlbum = true, this.isChecked = false, this.showCheck = false, + this.isLocal = false, this.onCheckChange, Key? key, }) : super(key: key); @override Widget build(BuildContext context, ref) { + final isReallyLocal = isLocal || + ref.watch( + playbackProvider.select((s) => s.playlist?.isLocal == true), + ); final breakpoint = useBreakpoints(); final auth = ref.watch(authProvider); final spotify = ref.watch(spotifyProvider); @@ -60,7 +67,7 @@ class TrackTile extends HookConsumerWidget { final savedTracksSnapshot = ref.watch(currentUserSavedTracksQuery); final isSaved = savedTracksSnapshot.asData?.value.any( - (e) => track.value.id! == e.id, + (e) => track.value.id == e.id, ) ?? false; @@ -210,17 +217,17 @@ class TrackTile extends HookConsumerWidget { ), child: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(5)), - child: CachedNetworkImage( + child: UniversalImage( + path: thumbnailUrl!, + height: 40, + width: 40, placeholder: (context, url) { - return Container( + return Image.asset( + "assets/album-placeholder.png", height: 40, width: 40, - color: Theme.of(context).primaryColor, ); }, - imageUrl: thumbnailUrl!, - maxHeightDiskCache: 40, - maxWidthDiskCache: 40, ), ), ), @@ -248,61 +255,70 @@ class TrackTile extends HookConsumerWidget { ), overflow: TextOverflow.ellipsis, ), - TypeConversionUtils.artists_X_ClickableArtists( - track.value.artists ?? [], - textStyle: TextStyle( - fontSize: - breakpoint.isLessThan(Breakpoints.lg) ? 12 : 14)), + isReallyLocal + ? Text( + TypeConversionUtils.artists_X_String( + track.value.artists ?? []), + ) + : TypeConversionUtils.artists_X_ClickableArtists( + track.value.artists ?? [], + textStyle: TextStyle( + fontSize: breakpoint.isLessThan(Breakpoints.lg) + ? 12 + : 14)), ], ), ), if (breakpoint.isMoreThan(Breakpoints.md) && showAlbum) Expanded( - child: LinkText( - track.value.album!.name!, - "/album/${track.value.album?.id}", - extra: track.value.album, - overflow: TextOverflow.ellipsis, - ), + child: isReallyLocal + ? Text(track.value.album?.name ?? "") + : LinkText( + track.value.album!.name!, + "/album/${track.value.album?.id}", + extra: track.value.album, + overflow: TextOverflow.ellipsis, + ), ), if (!breakpoint.isSm) ...[ const SizedBox(width: 10), Text(duration), ], const SizedBox(width: 10), - AdaptiveActions( - actions: [ - if (auth.isLoggedIn) + if (!isReallyLocal) + AdaptiveActions( + actions: [ + if (auth.isLoggedIn) + Action( + icon: Icon(isSaved + ? Icons.favorite_rounded + : Icons.favorite_border_rounded), + text: const Text("Save as favorite"), + onPressed: () { + actionFavorite(isSaved); + }, + ), + if (auth.isLoggedIn) + Action( + icon: const Icon(Icons.add_box_rounded), + text: const Text("Add To playlist"), + onPressed: actionAddToPlaylist, + ), + if (userPlaylist && auth.isLoggedIn) + Action( + icon: const Icon(Icons.remove_circle_outline_rounded), + text: const Text("Remove from playlist"), + onPressed: actionRemoveFromPlaylist, + ), Action( - icon: Icon(isSaved - ? Icons.favorite_rounded - : Icons.favorite_border_rounded), - text: const Text("Save as favorite"), + icon: const Icon(Icons.share_rounded), + text: const Text("Share"), onPressed: () { - actionFavorite(isSaved); + actionShare(track.value); }, - ), - if (auth.isLoggedIn) - Action( - icon: const Icon(Icons.add_box_rounded), - text: const Text("Add To playlist"), - onPressed: actionAddToPlaylist, - ), - if (userPlaylist && auth.isLoggedIn) - Action( - icon: const Icon(Icons.remove_circle_outline_rounded), - text: const Text("Remove from playlist"), - onPressed: actionRemoveFromPlaylist, - ), - Action( - icon: const Icon(Icons.share_rounded), - text: const Text("Share"), - onPressed: () { - actionShare(track.value); - }, - ) - ], - ), + ) + ], + ), ], ), ), diff --git a/lib/components/Shared/TracksTableView.dart b/lib/components/Shared/TracksTableView.dart index d38f6981..4edcbd88 100644 --- a/lib/components/Shared/TracksTableView.dart +++ b/lib/components/Shared/TracksTableView.dart @@ -17,6 +17,7 @@ class TracksTableView extends HookConsumerWidget { final bool userPlaylist; final String? playlistId; final bool bottomSpace; + final bool isSliver; final Widget? heading; const TracksTableView( @@ -27,6 +28,7 @@ class TracksTableView extends HookConsumerWidget { this.playlistId, this.heading, this.bottomSpace = false, + this.isSliver = true, }) : super(key: key); @override @@ -48,156 +50,153 @@ class TracksTableView extends HookConsumerWidget { [tracks], ); - return SliverList( - delegate: SliverChildListDelegate( - [ - if (heading != null) heading!, - Row( - children: [ - Checkbox( - value: selected.value.length == tracks.length, - onChanged: (checked) { - if (!showCheck.value) showCheck.value = true; - if (checked == true) { - selected.value = tracks.map((s) => s.id!).toList(); - } else { - selected.value = []; - showCheck.value = false; - } - }, - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - "#", - textAlign: TextAlign.center, + final children = [ + if (heading != null) heading!, + Row( + children: [ + Checkbox( + value: selected.value.length == tracks.length, + onChanged: (checked) { + if (!showCheck.value) showCheck.value = true; + if (checked == true) { + selected.value = tracks.map((s) => s.id!).toList(); + } else { + selected.value = []; + showCheck.value = false; + } + }, + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "#", + textAlign: TextAlign.center, + style: tableHeadStyle, + ), + ), + Expanded( + child: Row( + children: [ + Text( + "Title", style: tableHeadStyle, + overflow: TextOverflow.ellipsis, ), + ], + ), + ), + // used alignment of this table-head + if (breakpoint.isMoreThan(Breakpoints.md)) ...[ + const SizedBox(width: 100), + Expanded( + child: Row( + children: [ + Text( + "Album", + overflow: TextOverflow.ellipsis, + style: tableHeadStyle, + ), + ], ), - Expanded( - child: Row( - children: [ - Text( - "Title", - style: tableHeadStyle, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - // used alignment of this table-head - if (breakpoint.isMoreThan(Breakpoints.md)) ...[ - const SizedBox(width: 100), - Expanded( + ) + ], + if (!breakpoint.isSm) ...[ + const SizedBox(width: 10), + Text("Time", style: tableHeadStyle), + const SizedBox(width: 10), + ], + PopupMenuButton( + itemBuilder: (context) { + return [ + PopupMenuItem( + enabled: selected.value.isNotEmpty, child: Row( children: [ + const Icon(Icons.file_download_outlined), Text( - "Album", - overflow: TextOverflow.ellipsis, - style: tableHeadStyle, + "Download ${selectedTracks.isNotEmpty ? "(${selectedTracks.length})" : ""}", ), ], ), - ) - ], - if (!breakpoint.isSm) ...[ - const SizedBox(width: 10), - Text("Time", style: tableHeadStyle), - const SizedBox(width: 10), - ], - PopupMenuButton( - itemBuilder: (context) { - return [ - PopupMenuItem( - enabled: selected.value.isNotEmpty, - child: Row( - children: [ - const Icon(Icons.file_download_outlined), - Text( - "Download ${selectedTracks.isNotEmpty ? "(${selectedTracks.length})" : ""}", - ), - ], - ), - value: "download", - ), - ]; - }, - onSelected: (action) async { - switch (action) { - case "download": - { - final isConfirmed = await showDialog( - context: context, - builder: (context) { - return const DownloadConfirmationDialog(); - }); - if (isConfirmed != true) return; - for (final selectedTrack in selectedTracks) { - downloader.addToQueue(selectedTrack); - } - selected.value = []; - showCheck.value = false; - break; - } - default: + value: "download", + ), + ]; + }, + onSelected: (action) async { + switch (action) { + case "download": + { + final isConfirmed = await showDialog( + context: context, + builder: (context) { + return const DownloadConfirmationDialog(); + }); + if (isConfirmed != true) return; + for (final selectedTrack in selectedTracks) { + downloader.addToQueue(selectedTrack); + } + selected.value = []; + showCheck.value = false; + break; } - }, - ), - ], + default: + } + }, ), - ...tracks.asMap().entries.map((track) { - String? thumbnailUrl = TypeConversionUtils.image_X_UrlString( - track.value.album?.images, - index: (track.value.album?.images?.length ?? 1) - 1, - ); - String duration = - "${track.value.duration?.inMinutes.remainder(60)}:${PrimitiveUtils.zeroPadNumStr(track.value.duration?.inSeconds.remainder(60) ?? 0)}"; - return InkWell( - onLongPress: () { - showCheck.value = true; - selected.value = [...selected.value, track.value.id!]; - }, - onTap: () { - if (showCheck.value) { - final alreadyChecked = - selected.value.contains(track.value.id); - if (alreadyChecked) { - selected.value = selected.value - .where((id) => id != track.value.id) - .toList(); - } else { - selected.value = [...selected.value, track.value.id!]; - } - } else { - onTrackPlayButtonPressed?.call(track.value); - } - }, - child: TrackTile( - playback, - playlistId: playlistId, - track: track, - duration: duration, - thumbnailUrl: thumbnailUrl, - userPlaylist: userPlaylist, - isActive: playback.track?.id == track.value.id, - onTrackPlayButtonPressed: onTrackPlayButtonPressed, - isChecked: selected.value.contains(track.value.id), - showCheck: showCheck.value, - onCheckChange: (checked) { - if (checked == true) { - selected.value = [...selected.value, track.value.id!]; - } else { - selected.value = selected.value - .where((id) => id != track.value.id) - .toList(); - } - }, - ), - ); - }).toList(), - if (bottomSpace) const SizedBox(height: 70), ], ), - ); + ...tracks.asMap().entries.map((track) { + String? thumbnailUrl = TypeConversionUtils.image_X_UrlString( + track.value.album?.images, + index: (track.value.album?.images?.length ?? 1) - 1, + ); + String duration = + "${track.value.duration?.inMinutes.remainder(60)}:${PrimitiveUtils.zeroPadNumStr(track.value.duration?.inSeconds.remainder(60) ?? 0)}"; + return InkWell( + onLongPress: () { + showCheck.value = true; + selected.value = [...selected.value, track.value.id!]; + }, + onTap: () { + if (showCheck.value) { + final alreadyChecked = selected.value.contains(track.value.id); + if (alreadyChecked) { + selected.value = + selected.value.where((id) => id != track.value.id).toList(); + } else { + selected.value = [...selected.value, track.value.id!]; + } + } else { + onTrackPlayButtonPressed?.call(track.value); + } + }, + child: TrackTile( + playback, + playlistId: playlistId, + track: track, + duration: duration, + thumbnailUrl: thumbnailUrl, + userPlaylist: userPlaylist, + isActive: playback.track?.id == track.value.id, + onTrackPlayButtonPressed: onTrackPlayButtonPressed, + isChecked: selected.value.contains(track.value.id), + showCheck: showCheck.value, + onCheckChange: (checked) { + if (checked == true) { + selected.value = [...selected.value, track.value.id!]; + } else { + selected.value = + selected.value.where((id) => id != track.value.id).toList(); + } + }, + ), + ); + }).toList(), + if (bottomSpace) const SizedBox(height: 70), + ]; + if (isSliver) { + return SliverList(delegate: SliverChildListDelegate(children)); + } + return ListView(children: children); } } diff --git a/lib/components/Shared/UniversalImage.dart b/lib/components/Shared/UniversalImage.dart new file mode 100644 index 00000000..6a4aa373 --- /dev/null +++ b/lib/components/Shared/UniversalImage.dart @@ -0,0 +1,98 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; + +class UniversalImage extends HookWidget { + final String path; + final double? height; + final double? width; + final double scale; + final PlaceholderWidgetBuilder? placeholder; + const UniversalImage({ + required this.path, + this.height, + this.width, + this.placeholder, + this.scale = 1, + Key? key, + }) : super(key: key); + + static ImageProvider imageProvider( + String path, { + final double? height, + final double? width, + final double scale = 1, + }) { + if (path.startsWith("http")) { + return CachedNetworkImageProvider( + path, + maxHeight: height?.toInt(), + maxWidth: width?.toInt(), + cacheKey: path, + scale: scale, + ); + } else if (Uri.tryParse(path) != null) { + return FileImage(File(path), scale: scale); + } + return MemoryImage(base64Decode(path), scale: scale); + } + + @override + Widget build(BuildContext context) { + if (path.startsWith("http")) { + return CachedNetworkImage( + imageUrl: path, + height: height, + width: width, + maxWidthDiskCache: width?.toInt(), + maxHeightDiskCache: height?.toInt(), + memCacheHeight: height?.toInt(), + memCacheWidth: width?.toInt(), + placeholder: placeholder, + cacheKey: path, + ); + } else if (Uri.tryParse(path) != null) { + return Image.file( + File(path), + width: width, + height: height, + cacheHeight: height?.toInt(), + cacheWidth: width?.toInt(), + scale: scale, + errorBuilder: (context, error, stackTrace) { + return placeholder?.call(context, error.toString()) ?? + Image.asset( + "assets/placeholder.png", + width: width, + height: height, + cacheHeight: height?.toInt(), + cacheWidth: width?.toInt(), + scale: scale, + ); + }, + ); + } + return Image.memory( + base64Decode(path), + width: width, + height: height, + cacheHeight: height?.toInt(), + cacheWidth: width?.toInt(), + scale: scale, + errorBuilder: (context, error, stackTrace) { + return placeholder?.call(context, error.toString()) ?? + Image.asset( + "assets/placeholder.png", + width: width, + height: height, + cacheHeight: height?.toInt(), + cacheWidth: width?.toInt(), + scale: scale, + ); + }, + ); + } +} diff --git a/lib/hooks/usePaletteColor.dart b/lib/hooks/usePaletteColor.dart index e5a472f5..9809fb26 100644 --- a/lib/hooks/usePaletteColor.dart +++ b/lib/hooks/usePaletteColor.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; +import 'package:spotube/components/Shared/UniversalImage.dart'; final _paletteColorState = StateProvider( (ref) { @@ -18,11 +19,10 @@ PaletteColor usePaletteColor(String imageUrl, WidgetRef ref) { useEffect(() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { final palette = await PaletteGenerator.fromImageProvider( - CachedNetworkImageProvider( + UniversalImage.imageProvider( imageUrl, - cacheKey: imageUrl, - maxHeight: 50, - maxWidth: 50, + height: 50, + width: 50, ), ); if (!mounted()) return; @@ -49,11 +49,10 @@ PaletteGenerator usePaletteGenerator( useEffect(() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { final newPalette = await PaletteGenerator.fromImageProvider( - CachedNetworkImageProvider( + UniversalImage.imageProvider( imageUrl, - cacheKey: imageUrl, - maxHeight: 50, - maxWidth: 50, + height: 50, + width: 50, ), ); if (!mounted()) return; diff --git a/lib/models/CurrentPlaylist.dart b/lib/models/CurrentPlaylist.dart index 75322941..cacb42ff 100644 --- a/lib/models/CurrentPlaylist.dart +++ b/lib/models/CurrentPlaylist.dart @@ -61,12 +61,14 @@ class CurrentPlaylist { String id; String name; String thumbnail; + bool isLocal; CurrentPlaylist({ required this.tracks, required this.id, required this.name, required this.thumbnail, + this.isLocal = false, }); static CurrentPlaylist fromJson(Map map) { @@ -76,6 +78,7 @@ class CurrentPlaylist { map["tracks"].map((track) => Track.fromJson(track)).toList()), name: map["name"], thumbnail: map["thumbnail"], + isLocal: map["isLocal"], ); } @@ -107,6 +110,7 @@ class CurrentPlaylist { "name": name, "tracks": tracks.map((track) => track.toJson()).toList(), "thumbnail": thumbnail, + "isLocal": isLocal, }; } } diff --git a/lib/models/Id3Tags.dart b/lib/models/Id3Tags.dart new file mode 100644 index 00000000..746773ab --- /dev/null +++ b/lib/models/Id3Tags.dart @@ -0,0 +1,143 @@ +import 'package:dart_tags/dart_tags.dart'; + +class Id3Tags { + Id3Tags({ + this.tsse, + this.title, + this.album, + this.tpe2, + this.comment, + this.tcop, + this.tdrc, + this.genre, + this.picture, + }); + + String? tsse; + String? title; + String? album; + String? tpe2; + Comment? comment; + String? tcop; + String? tdrc; + String? genre; + AttachedPicture? picture; + + factory Id3Tags.fromJson(Map json) => Id3Tags( + tsse: json["TSSE"], + title: json["title"], + album: json["album"], + tpe2: json["TPE2"], + comment: json["comment"]?["eng:"] is Comment + ? json["comment"]["eng:"] + : CommentJson.fromJson(Map.from( + json["comment"]?["eng:"] ?? {}, + )), + tcop: json["TCOP"], + tdrc: json["TDRC"], + genre: json["genre"], + picture: json["picture"]?["Cover (front)"] is AttachedPicture + ? json["picture"]["Cover (front)"] + : AttachedPictureJson.fromJson(Map.from( + json["picture"]?["Cover (front)"] ?? {}, + )), + ); + + factory Id3Tags.fromId3v1Tags(Id3v1Tags v1tags) => Id3Tags( + album: v1tags.album, + comment: Comment("", "", v1tags.comment ?? ""), + genre: v1tags.genre, + title: v1tags.title, + tcop: v1tags.year, + tdrc: v1tags.year, + tpe2: v1tags.artist, + ); + + Map toJson() => { + "TSSE": tsse, + "title": title, + "album": album, + "TPE2": tpe2, + "comment": comment, + "TCOP": tcop, + "TDRC": tdrc, + "genre": genre, + "picture": picture, + }; +} + +extension CommentJson on Comment { + static fromJson(Map json) => Comment( + json["lang"] ?? "", + json["description"] ?? "", + json["comment"] ?? "", + ); + + Map toJson() => { + "comment": comment, + "description": description, + "key": key, + "lang": lang, + }; +} + +extension AttachedPictureJson on AttachedPicture { + static fromJson(Map json) => AttachedPicture( + json["mime"] ?? "", + json["imageTypeCode"] ?? 0, + json["description"] ?? "", + List.from(json["imageData"] ?? []), + ); + + Map toJson() => { + "description": description, + "imageData": imageData, + "imageData64": imageData64, + "imageType": imageType, + "imageTypeCode": imageTypeCode, + "key": key, + "mime": mime, + }; +} + +class Id3v1Tags { + String? title; + String? artist; + String? album; + String? year; + String? comment; + String? track; + String? genre; + + Id3v1Tags({ + this.title, + this.artist, + this.album, + this.year, + this.comment, + this.track, + this.genre, + }); + + Id3v1Tags.fromJson(Map json) { + title = json['title']; + artist = json['artist']; + album = json['album']; + year = json['year']; + comment = json['comment']; + track = json['track']; + genre = json['genre']; + } + + Map toJson() { + return { + 'title': title, + 'artist': artist, + 'album': album, + 'year': year, + 'comment': comment, + 'track': track, + 'genre': genre, + }; + } +} diff --git a/lib/provider/Downloader.dart b/lib/provider/Downloader.dart index 75c5f4cc..68634e31 100644 --- a/lib/provider/Downloader.dart +++ b/lib/provider/Downloader.dart @@ -1,17 +1,23 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:io'; +import 'package:dart_tags/dart_tags.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:http/http.dart'; import 'package:queue/queue.dart'; import 'package:path/path.dart' as path; import 'package:spotify/spotify.dart'; +import 'package:spotube/components/Library/UserLocalTracks.dart'; +import 'package:spotube/models/Id3Tags.dart'; import 'package:spotube/models/Logger.dart'; 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:youtube_explode_dart/youtube_explode_dart.dart'; +import 'package:spotube/utils/type_conversion_utils.dart'; +import 'package:youtube_explode_dart/youtube_explode_dart.dart' hide Comment; Queue queueInstance = Queue(delay: const Duration(seconds: 5)); Queue grabberQueue = Queue(delay: const Duration(seconds: 5)); @@ -89,6 +95,54 @@ class Downloader with ChangeNotifier { logger.v( "[addToQueue] Download of ${file.path} is done successfully", ); + + final response = await get( + Uri.parse( + TypeConversionUtils.image_X_UrlString( + track.album?.images ?? [], + ), + ), + ); + final picture = AttachedPicture.base64( + response.headers["Content-Type"] ?? "image/jpeg", + 3, + track.name!, + base64Encode(response.bodyBytes), + ); + // write id3 metadata + final tag = Id3Tags( + album: track.album?.name, + picture: picture, + title: track.name, + genre: "Spotube", + tcop: track.ytTrack.uploadDate?.year.toString(), + tdrc: track.ytTrack.uploadDate?.year.toString(), + tpe2: TypeConversionUtils.artists_X_String( + track.artists ?? [], + ), + tsse: "", + comment: Comment( + "eng", + track.ytTrack.description, + track.ytTrack.title, + ), + ); + + logger.v("[addToQueue] Writing metadata to ${file.path}"); + + final taggedMp3 = await tagProcessor.putTagsToByteArray( + file.readAsBytes(), + [ + Tag() + ..type = "ID3" + ..version = "2.4.0" + ..tags = tag.toJson() + ], + ); + await file.writeAsBytes(taggedMp3); + logger.v( + "[addToQueue] Writing metadata to ${file.path} is successful", + ); } catch (e, stack) { logger.e( "[addToQueue] Failed download of ${file.path}", diff --git a/lib/provider/Playback.dart b/lib/provider/Playback.dart index 9a2573ff..4bbd48a3 100644 --- a/lib/provider/Playback.dart +++ b/lib/provider/Playback.dart @@ -208,7 +208,10 @@ class Playback extends PersistedChangeNotifier { artist: TypeConversionUtils.artists_X_String( track.artists ?? []), artUri: Uri.parse( - TypeConversionUtils.image_X_UrlString(track.album?.images)), + TypeConversionUtils.image_X_UrlString( + track.album?.images, + ), + ), duration: track.ytTrack.duration, ); mobileAudioService?.addItem(tag); @@ -216,7 +219,11 @@ class Playback extends PersistedChangeNotifier { this.track = track; notifyListeners(); updatePersistence(); - await player.play(UrlSource(track.ytUri)); + await player.play( + track.ytUri.startsWith("http") + ? UrlSource(track.ytUri) + : DeviceFileSource(track.ytUri), + ); status = PlaybackStatus.playing; notifyListeners(); } catch (e, stack) { diff --git a/lib/utils/type_conversion_utils.dart b/lib/utils/type_conversion_utils.dart index 7d617da9..d887637a 100644 --- a/lib/utils/type_conversion_utils.dart +++ b/lib/utils/type_conversion_utils.dart @@ -2,11 +2,16 @@ import 'dart:io'; +import 'package:dart_tags/dart_tags.dart'; import 'package:flutter/widgets.dart' hide Image; -import 'package:flutter_media_metadata/flutter_media_metadata.dart'; +import 'package:path/path.dart'; import 'package:spotube/components/Shared/LinkText.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/models/Id3Tags.dart'; +import 'package:spotube/models/SpotubeTrack.dart'; import 'package:spotube/utils/primitive_utils.dart'; +import 'package:collection/collection.dart'; +import 'package:youtube_explode_dart/youtube_explode_dart.dart'; abstract class TypeConversionUtils { static String image_X_UrlString(List? images, {int index = 0}) { @@ -85,31 +90,61 @@ abstract class TypeConversionUtils { return track; } - static Track localTrack_X_Track(Metadata metadata, File file) { - final track = Track(); + static SpotubeTrack localTrack_X_Track( + List metadatas, + File file, + Duration duration, + String? art, + ) { + final v2Tags = + metadatas.firstWhereOrNull((s) => s.version == "2.4.0")?.tags; + final v1Tags = + metadatas.firstWhereOrNull((s) => s.version != "2.4.0")?.tags; + final metadata = v2Tags != null + ? Id3Tags.fromJson(v2Tags) + : Id3Tags.fromId3v1Tags(Id3v1Tags.fromJson(v1Tags ?? {})); + final track = SpotubeTrack( + Video( + VideoId("dQw4w9WgXcQ"), + basenameWithoutExtension(file.path), + metadata.tpe2 ?? "", + ChannelId( + "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw", + ), + DateTime.now(), + DateTime.now(), + "", + duration, + ThumbnailSet(metadata.title ?? ""), + [], + const Engagement(0, 0, 0), + false, + ), + file.path, + [], + ); track.album = Album() - ..name = metadata.albumName + ..name = metadata.album ?? "Spotube" + ..images = [if (art != null) Image()..url = art] ..genres = [if (metadata.genre != null) metadata.genre!] ..artists = [ Artist() - ..name = metadata.albumArtistName - ..id = metadata.albumArtistName + ..name = metadata.tpe2 ?? "Spotube" + ..id = metadata.tpe2 ?? "Spotube" ..type = "artist", ] - ..id = "${metadata.albumName}${metadata.albumLength}"; - track.artists = metadata.trackArtistNames - ?.map((name) => Artist() - ..name = name - ..id = name) - .toList(); + ..id = metadata.album; + track.artists = [ + Artist() + ..name = metadata.tpe2 ?? "Spotube" + ..id = metadata.tpe2 ?? "Spotube" + ]; - track.discNumber = metadata.discNumber; - track.durationMs = metadata.trackDuration; - track.id = "${metadata.trackName}${metadata.trackDuration}"; - track.name = metadata.trackName; - track.trackNumber = metadata.trackNumber; + track.id = metadata.title ?? basenameWithoutExtension(file.path); + track.name = metadata.title ?? basenameWithoutExtension(file.path); track.type = "track"; track.uri = file.path; + track.durationMs = duration.inMilliseconds; return track; } diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index cce5b687..01b8e0f7 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -8,7 +8,6 @@ #include #include -#include #include void fl_register_plugins(FlPluginRegistry* registry) { @@ -18,9 +17,6 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin"); bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar); - g_autoptr(FlPluginRegistrar) flutter_media_metadata_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterMediaMetadataPlugin"); - flutter_media_metadata_plugin_register_with_registrar(flutter_media_metadata_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 4e314d80..9aebc645 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -5,7 +5,6 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux bitsdojo_window_linux - flutter_media_metadata url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 594b241f..3e375fb3 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,7 +9,6 @@ import audio_service import audio_session import audioplayers_darwin import bitsdojo_window_macos -import flutter_media_metadata import package_info_plus_macos import path_provider_macos import shared_preferences_macos @@ -21,7 +20,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin")) - FlutterMediaMetadataPlugin.register(with: registry.registrar(forPlugin: "FlutterMediaMetadataPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/pubspec.lock b/pubspec.lock index ce4760d1..9922b11b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -140,7 +140,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.2" + version: "2.9.0" audio_service: dependency: "direct main" description: @@ -357,14 +357,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" + version: "1.2.1" checked_yaml: dependency: transitive description: @@ -378,7 +371,7 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" code_builder: dependency: transitive description: @@ -442,6 +435,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.3" + dart_tags: + dependency: "direct main" + description: + name: dart_tags + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.0" dbus: dependency: "direct main" description: @@ -463,6 +463,13 @@ 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: @@ -476,7 +483,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" ffi: dependency: transitive description: @@ -573,13 +580,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.4" - flutter_media_metadata: - dependency: "direct main" - description: - path: "../flutter_media_metadata" - relative: true - source: path - version: "1.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -702,6 +702,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.1" + id3: + dependency: "direct main" + description: + name: id3 + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" image: dependency: transitive description: @@ -778,21 +785,21 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.12.12" material_color_utilities: dependency: transitive description: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.5" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" mime: dependency: "direct main" description: @@ -800,6 +807,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.2" + mp3_info: + dependency: "direct main" + description: + name: mp3_info + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" msix: dependency: "direct dev" description: @@ -890,7 +904,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" path_provider: dependency: "direct main" description: @@ -1175,7 +1189,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.2" + version: "1.9.0" spotify: dependency: "direct main" description: @@ -1233,7 +1247,7 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" synchronized: dependency: transitive description: @@ -1247,14 +1261,14 @@ packages: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.12" timing: dependency: transitive description: @@ -1325,6 +1339,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" + utf_convert: + dependency: transitive + description: + name: utf_convert + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.0+1" uuid: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3d6b2bc1..9ea0fc31 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -71,8 +71,9 @@ dependencies: auto_size_text: ^3.0.0 badges: ^2.0.3 mime: ^1.0.2 - flutter_media_metadata: - path: ../flutter_media_metadata + dart_tags: ^0.4.0 + id3: ^1.0.2 + mp3_info: ^0.2.0 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index c8153a66..3e689c38 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,7 +8,6 @@ #include #include -#include #include #include @@ -17,8 +16,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); BitsdojoWindowPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("BitsdojoWindowPlugin")); - FlutterMediaMetadataPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FlutterMediaMetadataPlugin")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index d8bb9c42..c8e970a8 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,7 +5,6 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows bitsdojo_window_windows - flutter_media_metadata permission_handler_windows url_launcher_windows ) From 747efc6ee66bc6c7c917cc02bd134968a0781701 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 3 Sep 2022 09:53:44 +0600 Subject: [PATCH 2/2] fix(sidebar): user image url --- lib/components/Home/Sidebar.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/Home/Sidebar.dart b/lib/components/Home/Sidebar.dart index 5d85bd68..6b2459c4 100644 --- a/lib/components/Home/Sidebar.dart +++ b/lib/components/Home/Sidebar.dart @@ -155,7 +155,7 @@ class Sidebar extends HookConsumerWidget { children: [ CircleAvatar( backgroundImage: - CachedNetworkImageProvider("asdasd"), + CachedNetworkImageProvider(avatarImg), onBackgroundImageError: (exception, stackTrace) => Image.asset(