diff --git a/assets/plugins/spotube-plugin-youtube-audio/plugin.smplug b/assets/plugins/spotube-plugin-youtube-audio/plugin.smplug index f8dedd0c..55aa2895 100644 Binary files a/assets/plugins/spotube-plugin-youtube-audio/plugin.smplug and b/assets/plugins/spotube-plugin-youtube-audio/plugin.smplug differ diff --git a/lib/modules/home/sections/new_releases.dart b/lib/modules/home/sections/new_releases.dart index 2a1f2f91..be6d335d 100644 --- a/lib/modules/home/sections/new_releases.dart +++ b/lib/modules/home/sections/new_releases.dart @@ -28,7 +28,7 @@ class HomeNewReleasesSection extends HookConsumerWidget { if (newReleases.error case MetadataPluginException( - errorCode: MetadataPluginErrorCode.noDefaultPlugin, + errorCode: MetadataPluginErrorCode.noDefaultMetadataPlugin, message: _, )) { return const SizedBox.shrink(); diff --git a/lib/modules/home/sections/sections.dart b/lib/modules/home/sections/sections.dart index b04e7a9e..93055b74 100644 --- a/lib/modules/home/sections/sections.dart +++ b/lib/modules/home/sections/sections.dart @@ -48,7 +48,7 @@ class HomePageBrowseSection extends HookConsumerWidget { if (browseSections.error case MetadataPluginException( - errorCode: MetadataPluginErrorCode.noDefaultPlugin, + errorCode: MetadataPluginErrorCode.noDefaultMetadataPlugin, message: _, )) { return const SliverFillRemaining( diff --git a/lib/pages/library/user_albums.dart b/lib/pages/library/user_albums.dart index 4f183346..2d989138 100644 --- a/lib/pages/library/user_albums.dart +++ b/lib/pages/library/user_albums.dart @@ -55,7 +55,7 @@ class UserAlbumsPage extends HookConsumerWidget { if (albumsQuery.error case MetadataPluginException( - errorCode: MetadataPluginErrorCode.noDefaultPlugin, + errorCode: MetadataPluginErrorCode.noDefaultMetadataPlugin, message: _, )) { return const Center(child: NoDefaultMetadataPlugin()); diff --git a/lib/pages/library/user_artists.dart b/lib/pages/library/user_artists.dart index d5df13e5..750cb50b 100644 --- a/lib/pages/library/user_artists.dart +++ b/lib/pages/library/user_artists.dart @@ -60,7 +60,7 @@ class UserArtistsPage extends HookConsumerWidget { if (artistQuery.error case MetadataPluginException( - errorCode: MetadataPluginErrorCode.noDefaultPlugin, + errorCode: MetadataPluginErrorCode.noDefaultMetadataPlugin, message: _, )) { return const Center(child: NoDefaultMetadataPlugin()); diff --git a/lib/pages/library/user_playlists.dart b/lib/pages/library/user_playlists.dart index 9020d463..740bc947 100644 --- a/lib/pages/library/user_playlists.dart +++ b/lib/pages/library/user_playlists.dart @@ -83,7 +83,7 @@ class UserPlaylistsPage extends HookConsumerWidget { if (playlistsQuery.error case MetadataPluginException( - errorCode: MetadataPluginErrorCode.noDefaultPlugin, + errorCode: MetadataPluginErrorCode.noDefaultMetadataPlugin, message: _, )) { return const Center(child: NoDefaultMetadataPlugin()); diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index c6118a97..cb4f4a0b 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -85,7 +85,7 @@ class SearchPage extends HookConsumerWidget { child: Builder(builder: (context) { if (searchChipSnapshot.error case MetadataPluginException( - errorCode: MetadataPluginErrorCode.noDefaultPlugin, + errorCode: MetadataPluginErrorCode.noDefaultMetadataPlugin, message: _ )) { return const NoDefaultMetadataPlugin(); diff --git a/lib/provider/audio_player/audio_player.dart b/lib/provider/audio_player/audio_player.dart index 1bfd8f2d..66878714 100644 --- a/lib/provider/audio_player/audio_player.dart +++ b/lib/provider/audio_player/audio_player.dart @@ -144,40 +144,8 @@ class AudioPlayerNotifier extends Notifier { }), audioPlayer.playlistStream.listen((playlist) async { try { - // Playlist and state has to be in sync. This is only meant for - // the shuffle/re-ordering indices to be in sync - if (playlist.medias.length != state.tracks.length) { - AppLogger.log.w( - "Playlist length does not match state tracks length. Ignoring... " - "Playlist length: ${playlist.medias.length}, " - "State tracks length: ${state.tracks.length}", - ); - return; - } - - final trackGroupedById = groupBy( - state.tracks, - (query) => query.id, - ); - - final tracks = []; - - for (final media in playlist.medias) { - final track = trackGroupedById[SpotubeMedia.media(media).track.id] - ?.firstOrNull; - if (track != null) { - tracks.add(track); - } - } - - if (tracks.length != state.tracks.length) { - AppLogger.log.w("Mismatch in tracks after reordering/shuffling."); - final missingTracks = - state.tracks.where((track) => !tracks.contains(track)).toList(); - AppLogger.log.w( - "Missing tracks: ${missingTracks.map((e) => e.id).join(", ")}", - ); - } + final tracks = + playlist.medias.map((e) => SpotubeMedia.media(e).track).toList(); state = state.copyWith( tracks: tracks, @@ -434,13 +402,31 @@ class AudioPlayerNotifier extends Notifier { return; } - final currentIndex = state.currentIndex; - final currentTrack = state.activeTrack as SpotubeFullTrackObject; - final swappedMedia = SpotubeMedia(currentTrack); + final oldState = state; + await audioPlayer.stop(); - await audioPlayer.addTrackAt(swappedMedia, currentIndex + 1); - await audioPlayer.skipToNext(); - await audioPlayer.removeTrack(currentIndex); + await load( + oldState.tracks, + initialIndex: oldState.currentIndex, + autoPlay: true, + ); + state = state.copyWith( + collections: oldState.collections, + loopMode: oldState.loopMode, + playing: oldState.playing, + shuffled: false, + ); + await audioPlayer.setLoopMode(oldState.loopMode); + await _updatePlayerState( + AudioPlayerStateTableCompanion( + tracks: Value(state.tracks), + currentIndex: Value(state.currentIndex), + collections: Value(state.collections), + loopMode: Value(state.loopMode), + playing: Value(state.playing), + shuffled: Value(state.shuffled), + ), + ); } Future jumpToTrack(SpotubeTrackObject track) async { diff --git a/lib/provider/metadata_plugin/album/album.dart b/lib/provider/metadata_plugin/album/album.dart index 3a386236..394f6eb0 100644 --- a/lib/provider/metadata_plugin/album/album.dart +++ b/lib/provider/metadata_plugin/album/album.dart @@ -12,7 +12,7 @@ final metadataPluginAlbumProvider = final metadataPlugin = await ref.watch(metadataPluginProvider.future); if (metadataPlugin == null) { - throw MetadataPluginException.noDefaultPlugin(); + throw MetadataPluginException.noDefaultMetadataPlugin(); } return metadataPlugin.album.getAlbum(id); diff --git a/lib/provider/metadata_plugin/artist/artist.dart b/lib/provider/metadata_plugin/artist/artist.dart index f1691657..e66309d4 100644 --- a/lib/provider/metadata_plugin/artist/artist.dart +++ b/lib/provider/metadata_plugin/artist/artist.dart @@ -12,7 +12,7 @@ final metadataPluginArtistProvider = final metadataPlugin = await ref.watch(metadataPluginProvider.future); if (metadataPlugin == null) { - throw MetadataPluginException.noDefaultPlugin(); + throw MetadataPluginException.noDefaultMetadataPlugin(); } return metadataPlugin.artist.getArtist(artistId); diff --git a/lib/provider/metadata_plugin/audio_source/quality_presets.dart b/lib/provider/metadata_plugin/audio_source/quality_presets.dart index 0a8b00fe..ba88fed6 100644 --- a/lib/provider/metadata_plugin/audio_source/quality_presets.dart +++ b/lib/provider/metadata_plugin/audio_source/quality_presets.dart @@ -6,6 +6,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:spotube/models/metadata/metadata.dart'; import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; +import 'package:spotube/services/metadata/errors/exceptions.dart'; import 'package:spotube/services/metadata/metadata.dart'; part 'quality_presets.g.dart'; @@ -61,7 +62,7 @@ class AudioSourceAvailableQualityPresetsNotifier audioSourceConfigSnapshot.whenData((audioSourceConfig) { audioSourceSnapshot.whenData((audioSource) async { if (audioSource == null || audioSourceConfig == null) { - throw Exception("Dude wat?"); + throw MetadataPluginException.noDefaultAudioSourcePlugin(); } final preferences = await SharedPreferences.getInstance(); final persistedStateStr = @@ -114,7 +115,7 @@ class AudioSourceAvailableQualityPresetsNotifier final audioSourceConfig = await ref.read(metadataPluginsProvider .selectAsync((data) => data.defaultAudioSourcePluginConfig)); if (audioSourceConfig == null) { - throw Exception("Dude wat?"); + throw MetadataPluginException.noDefaultAudioSourcePlugin(); } final preferences = await SharedPreferences.getInstance(); diff --git a/lib/provider/metadata_plugin/library/playlists.dart b/lib/provider/metadata_plugin/library/playlists.dart index 6350d610..5793eb57 100644 --- a/lib/provider/metadata_plugin/library/playlists.dart +++ b/lib/provider/metadata_plugin/library/playlists.dart @@ -131,7 +131,7 @@ final metadataPluginIsSavedPlaylistProvider = final plugin = await ref.watch(metadataPluginProvider.future); if (plugin == null) { - throw MetadataPluginException.noDefaultPlugin(); + throw MetadataPluginException.noDefaultMetadataPlugin(); } final savedPlaylists = diff --git a/lib/provider/metadata_plugin/playlist/playlist.dart b/lib/provider/metadata_plugin/playlist/playlist.dart index 71062b95..9a41340d 100644 --- a/lib/provider/metadata_plugin/playlist/playlist.dart +++ b/lib/provider/metadata_plugin/playlist/playlist.dart @@ -13,7 +13,7 @@ class MetadataPluginPlaylistNotifier final metadataPlugin = await ref.read(metadataPluginProvider.future); if (metadataPlugin == null) { - throw MetadataPluginException.noDefaultPlugin(); + throw MetadataPluginException.noDefaultMetadataPlugin(); } return metadataPlugin; diff --git a/lib/provider/metadata_plugin/search/all.dart b/lib/provider/metadata_plugin/search/all.dart index b40ee78a..4b051e58 100644 --- a/lib/provider/metadata_plugin/search/all.dart +++ b/lib/provider/metadata_plugin/search/all.dart @@ -9,7 +9,7 @@ final metadataPluginSearchAllProvider = final metadataPlugin = await ref.watch(metadataPluginProvider.future); if (metadataPlugin == null) { - throw MetadataPluginException.noDefaultPlugin(); + throw MetadataPluginException.noDefaultMetadataPlugin(); } return metadataPlugin.search.all(query); @@ -20,7 +20,7 @@ final metadataPluginSearchChipsProvider = FutureProvider((ref) async { final metadataPlugin = await ref.watch(metadataPluginProvider.future); if (metadataPlugin == null) { - throw MetadataPluginException.noDefaultPlugin(); + throw MetadataPluginException.noDefaultMetadataPlugin(); } return metadataPlugin.search.chips; }); diff --git a/lib/provider/metadata_plugin/tracks/track.dart b/lib/provider/metadata_plugin/tracks/track.dart index 502780e1..1beac43a 100644 --- a/lib/provider/metadata_plugin/tracks/track.dart +++ b/lib/provider/metadata_plugin/tracks/track.dart @@ -8,7 +8,7 @@ final metadataPluginTrackProvider = final metadataPlugin = await ref.watch(metadataPluginProvider.future); if (metadataPlugin == null) { - throw MetadataPluginException.noDefaultPlugin(); + throw MetadataPluginException.noDefaultMetadataPlugin(); } return metadataPlugin.track.getTrack(trackId); diff --git a/lib/provider/metadata_plugin/utils/common.dart b/lib/provider/metadata_plugin/utils/common.dart index 087b8a1b..dc56e494 100644 --- a/lib/provider/metadata_plugin/utils/common.dart +++ b/lib/provider/metadata_plugin/utils/common.dart @@ -20,7 +20,7 @@ mixin MetadataPluginMixin final plugin = await ref.read(metadataPluginProvider.future); if (plugin == null) { - throw MetadataPluginException.noDefaultPlugin(); + throw MetadataPluginException.noDefaultMetadataPlugin(); } return plugin; diff --git a/lib/provider/track_options/track_options_provider.dart b/lib/provider/track_options/track_options_provider.dart index d31aba73..5aebf39c 100644 --- a/lib/provider/track_options/track_options_provider.dart +++ b/lib/provider/track_options/track_options_provider.dart @@ -95,7 +95,7 @@ class TrackOptionsActions { final metadataPlugin = await ref.read(metadataPluginProvider.future); if (metadataPlugin == null) { - throw MetadataPluginException.noDefaultPlugin(); + throw MetadataPluginException.noDefaultMetadataPlugin(); } final tracks = await metadataPlugin.track.radio(track.id); diff --git a/lib/services/metadata/errors/exceptions.dart b/lib/services/metadata/errors/exceptions.dart index 62cc3779..5bb5ac57 100644 --- a/lib/services/metadata/errors/exceptions.dart +++ b/lib/services/metadata/errors/exceptions.dart @@ -9,7 +9,8 @@ enum MetadataPluginErrorCode { pluginDownloadFailed, duplicatePlugin, pluginByteCodeFileNotFound, - noDefaultPlugin, + noDefaultMetadataPlugin, + noDefaultAudiSourcePlugin, } class MetadataPluginException implements Exception { @@ -68,10 +69,15 @@ class MetadataPluginException implements Exception { 'Plugin byte code file, plugin.out not found. Please ensure the plugin is correctly packaged.', errorCode: MetadataPluginErrorCode.pluginByteCodeFileNotFound, ); - MetadataPluginException.noDefaultPlugin() + MetadataPluginException.noDefaultMetadataPlugin() : this._( 'No default metadata plugin is set. Please set a default plugin in the settings.', - errorCode: MetadataPluginErrorCode.noDefaultPlugin, + errorCode: MetadataPluginErrorCode.noDefaultMetadataPlugin, + ); + MetadataPluginException.noDefaultAudioSourcePlugin() + : this._( + 'No default audio source plugin is set. Please set a default plugin in the settings.', + errorCode: MetadataPluginErrorCode.noDefaultAudiSourcePlugin, ); @override diff --git a/lib/services/sourced_track/sourced_track.dart b/lib/services/sourced_track/sourced_track.dart index 5da54fc8..385e5be6 100644 --- a/lib/services/sourced_track/sourced_track.dart +++ b/lib/services/sourced_track/sourced_track.dart @@ -12,6 +12,7 @@ import 'package:spotube/provider/metadata_plugin/audio_source/quality_presets.da import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart'; import 'package:spotube/services/dio/dio.dart'; import 'package:spotube/services/logger/logger.dart'; +import 'package:spotube/services/metadata/errors/exceptions.dart'; import 'package:spotube/services/sourced_track/exceptions.dart'; import 'package:spotube/utils/service_utils.dart'; @@ -41,7 +42,7 @@ class SourcedTrack extends BasicSourcedTrack { final audioSourceConfig = await ref.read(metadataPluginsProvider .selectAsync((data) => data.defaultAudioSourcePluginConfig)); if (audioSource == null || audioSourceConfig == null) { - throw Exception("Dude wat?"); + throw MetadataPluginException.noDefaultAudioSourcePlugin(); } final database = ref.read(databaseProvider); @@ -157,7 +158,7 @@ class SourcedTrack extends BasicSourcedTrack { final audioSource = await ref.read(audioSourcePluginProvider.future); if (audioSource == null) { - throw Exception("Dude wat?"); + throw MetadataPluginException.noDefaultAudioSourcePlugin(); } final videoResults = []; @@ -190,7 +191,8 @@ class SourcedTrack extends BasicSourcedTrack { } Future swapWithSibling( - SpotubeAudioSourceMatchObject sibling) async { + SpotubeAudioSourceMatchObject sibling, + ) async { if (sibling.id == info.id) { return null; } @@ -199,7 +201,7 @@ class SourcedTrack extends BasicSourcedTrack { final audioSourceConfig = await ref.read(metadataPluginsProvider .selectAsync((data) => data.defaultAudioSourcePluginConfig)); if (audioSource == null || audioSourceConfig == null) { - throw Exception("Dude wat?"); + throw MetadataPluginException.noDefaultAudioSourcePlugin(); } // a sibling source that was fetched from the search results @@ -216,10 +218,19 @@ class SourcedTrack extends BasicSourcedTrack { final database = ref.read(databaseProvider); + // Delete the old Entry + await (database.sourceMatchTable.delete() + ..where( + (table) => + table.trackId.equals(query.id) & + table.sourceType.equals(audioSourceConfig.slug), + )) + .go(); + await database.into(database.sourceMatchTable).insert( SourceMatchTableCompanion.insert( trackId: query.id, - sourceInfo: Value(jsonEncode(siblings.first)), + sourceInfo: Value(jsonEncode(sibling)), sourceType: audioSourceConfig.slug, createdAt: Value(DateTime.now()), ), @@ -245,7 +256,7 @@ class SourcedTrack extends BasicSourcedTrack { final audioSourceConfig = await ref.read(metadataPluginsProvider .selectAsync((data) => data.defaultAudioSourcePluginConfig)); if (audioSource == null || audioSourceConfig == null) { - throw Exception("Dude wat?"); + throw MetadataPluginException.noDefaultAudioSourcePlugin(); } List validStreams = [];