diff --git a/lib/provider/local_tracks/local_tracks_provider.dart b/lib/provider/local_tracks/local_tracks_provider.dart index 3245ff2d..db8c3401 100644 --- a/lib/provider/local_tracks/local_tracks_provider.dart +++ b/lib/provider/local_tracks/local_tracks_provider.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:io'; -import 'package:collection/collection.dart'; import 'package:spotube/services/logger/logger.dart'; import 'package:flutter/foundation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -110,7 +109,7 @@ final localTracksProvider = return null; } }), - ).then((value) => value.whereNotNull().toList()); + ).then((value) => value.nonNulls.toList()); final tracksFromMetadata = filesWithMetadata .map( diff --git a/lib/provider/server/routes/playback.dart b/lib/provider/server/routes/playback.dart index 3a480248..9ee00896 100644 --- a/lib/provider/server/routes/playback.dart +++ b/lib/provider/server/routes/playback.dart @@ -11,7 +11,6 @@ import 'package:shelf/shelf.dart'; import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/track.dart'; -import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/parser/range_headers.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/state.dart'; @@ -125,14 +124,9 @@ class ServerPlaybackRoutes { ) .catchError((e, stack) async { AppLogger.reportError(e, stack); - final sourcedTrack = userPreferences.audioSource == AudioSource.youtube && - e is DioException - ? await ref - .read(sourcedTrackProvider(SpotubeMedia(track)).notifier) - .refreshStreamingUrl() - : await ref - .read(sourcedTrackProvider(SpotubeMedia(track)).notifier) - .switchToAlternativeSources(); + final sourcedTrack = await ref + .read(sourcedTrackProvider(SpotubeMedia(track)).notifier) + .refreshStreamingUrl(); ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack); diff --git a/lib/provider/server/sourced_track.dart b/lib/provider/server/sourced_track.dart index 2081ac0a..f733f9d6 100644 --- a/lib/provider/server/sourced_track.dart +++ b/lib/provider/server/sourced_track.dart @@ -41,18 +41,6 @@ class SourcedTrackNotifier ); }); } - - Future switchToAlternativeSources() async { - if (arg == null) { - return null; - } - return await update((prev) async { - return await SourcedTrack.fetchFromTrackAltSource( - track: arg!.track, - ref: ref, - ); - }); - } } final sourcedTrackProvider = AsyncNotifierProviderFamily PlaylistsFeatured.fromJson(json), ).getPage(limit, offset); - final items = playlists.items?.whereNotNull().toList() ?? []; + final items = playlists.items?.nonNulls.toList() ?? []; return ( items: items, diff --git a/lib/services/sourced_track/sourced_track.dart b/lib/services/sourced_track/sourced_track.dart index 38f01498..272295e4 100644 --- a/lib/services/sourced_track/sourced_track.dart +++ b/lib/services/sourced_track/sourced_track.dart @@ -1,15 +1,9 @@ -import 'dart:io'; - -import 'package:http/http.dart'; -import 'package:collection/collection.dart'; -import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/sourced_track/enums.dart'; -import 'package:spotube/services/sourced_track/exceptions.dart'; import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/models/source_map.dart'; import 'package:spotube/services/sourced_track/sources/invidious.dart'; @@ -17,7 +11,6 @@ import 'package:spotube/services/sourced_track/sources/jiosaavn.dart'; import 'package:spotube/services/sourced_track/sources/piped.dart'; import 'package:spotube/services/sourced_track/sources/youtube.dart'; import 'package:spotube/utils/service_utils.dart'; -import 'package:youtube_explode_dart/youtube_explode_dart.dart'; abstract class SourcedTrack extends Track { final SourceMap source; @@ -97,11 +90,8 @@ abstract class SourcedTrack extends Track { } static String getSearchTerm(Track track) { - final artists = (track.artists ?? []) - .map((ar) => ar.name) - .toList() - .whereNotNull() - .toList(); + final artists = + (track.artists ?? []).map((ar) => ar.name).toList().nonNulls.toList(); final title = ServiceUtils.getTitle( track.name!, @@ -112,100 +102,21 @@ abstract class SourcedTrack extends Track { return "$title - ${artists.join(", ")}"; } - static fetchFromTrackAltSource({ - required Track track, - required Ref ref, - }) async { - final preferences = ref.read(userPreferencesProvider); - try { - return switch (preferences.audioSource) { - AudioSource.piped || - AudioSource.invidious || - AudioSource.jiosaavn => - await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), - AudioSource.youtube => - await JioSaavnSourcedTrack.fetchFromTrack(track: track, ref: ref), - }; - } on TrackNotFoundError catch (_) { - return switch (preferences.audioSource) { - AudioSource.piped || - AudioSource.youtube || - AudioSource.invidious => - await JioSaavnSourcedTrack.fetchFromTrack( - track: track, - ref: ref, - weakMatch: true, - ), - AudioSource.jiosaavn => - await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), - }; - } on HttpClientClosedException catch (_) { - return await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref); - } on VideoUnplayableException catch (_) { - return await InvidiousSourcedTrack.fetchFromTrack(track: track, ref: ref); - } catch (e) { - if (e is DioException || e is ClientException || e is SocketException) { - return await JioSaavnSourcedTrack.fetchFromTrack( - track: track, - ref: ref, - weakMatch: preferences.audioSource == AudioSource.jiosaavn, - ); - } - rethrow; - } - } - static Future fetchFromTrack({ required Track track, required Ref ref, }) async { final preferences = ref.read(userPreferencesProvider); - try { - return switch (preferences.audioSource) { - AudioSource.piped => - await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref), - AudioSource.youtube => - await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), - AudioSource.jiosaavn => - await JioSaavnSourcedTrack.fetchFromTrack(track: track, ref: ref), - AudioSource.invidious => - await InvidiousSourcedTrack.fetchFromTrack(track: track, ref: ref), - }; - } on TrackNotFoundError catch (_) { - return switch (preferences.audioSource) { - AudioSource.piped || - AudioSource.youtube || - AudioSource.invidious => - await JioSaavnSourcedTrack.fetchFromTrack( - track: track, - ref: ref, - weakMatch: true, - ), - AudioSource.jiosaavn => - await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), - }; - } on HttpClientClosedException catch (_) { - return await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref); - } on VideoUnplayableException catch (_) { - return await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref); - } catch (e) { - if (e is DioException || e is ClientException || e is SocketException) { - return switch (preferences.audioSource) { - AudioSource.piped || - AudioSource.invidious => - await YoutubeSourcedTrack.fetchFromTrack( - track: track, - ref: ref, - ), - _ => await JioSaavnSourcedTrack.fetchFromTrack( - track: track, - ref: ref, - weakMatch: preferences.audioSource == AudioSource.jiosaavn, - ) - }; - } - rethrow; - } + return switch (preferences.audioSource) { + AudioSource.youtube => + await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), + AudioSource.piped => + await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref), + AudioSource.invidious => + await InvidiousSourcedTrack.fetchFromTrack(track: track, ref: ref), + AudioSource.jiosaavn => + await JioSaavnSourcedTrack.fetchFromTrack(track: track, ref: ref), + }; } static Future> fetchSiblings({ diff --git a/lib/services/sourced_track/sources/invidious.dart b/lib/services/sourced_track/sources/invidious.dart index 2ec5068e..4a32ad41 100644 --- a/lib/services/sourced_track/sources/invidious.dart +++ b/lib/services/sourced_track/sources/invidious.dart @@ -50,6 +50,22 @@ class InvidiousSourcedTrack extends SourcedTrack { required Track track, required Ref ref, }) async { + // Indicates a stream url refresh + if (track is InvidiousSourcedTrack) { + final manifest = await ref + .read(invidiousProvider) + .videos + .get(track.sourceInfo.id, local: true); + + return InvidiousSourcedTrack( + ref: ref, + siblings: track.siblings, + source: toSourceMap(manifest), + sourceInfo: track.sourceInfo, + track: track, + ); + } + final database = ref.read(databaseProvider); final cachedSource = await (database.select(database.sourceMatchTable) ..where((s) => s.trackId.equals(track.id!)) diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart index d24f110f..1728753a 100644 --- a/lib/services/sourced_track/sources/piped.dart +++ b/lib/services/sourced_track/sources/piped.dart @@ -50,6 +50,19 @@ class PipedSourcedTrack extends SourcedTrack { required Track track, required Ref ref, }) async { + // Means it wants a refresh of the stream + if (track is PipedSourcedTrack) { + final manifest = + await ref.read(pipedProvider).streams(track.sourceInfo.id); + return PipedSourcedTrack( + ref: ref, + siblings: track.siblings, + sourceInfo: track.sourceInfo, + source: toSourceMap(manifest), + track: track, + ); + } + final database = ref.read(databaseProvider); final cachedSource = await (database.select(database.sourceMatchTable) ..where((s) => s.trackId.equals(track.id!)) @@ -183,11 +196,8 @@ class PipedSourcedTrack extends SourcedTrack { : preference.searchMode == SearchMode.youtubeMusic; if (isYouTubeMusic) { - final artists = (track.artists ?? []) - .map((ar) => ar.name) - .toList() - .whereNotNull() - .toList(); + final artists = + (track.artists ?? []).map((ar) => ar.name).toList().nonNulls.toList(); return await Future.wait( searchResults diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index 0b29a684..c4881051 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -268,7 +268,7 @@ class YoutubeSourcedTrack extends SourcedTrack { final query = SourcedTrack.getSearchTerm(track); final searchResults = - await ref.read(youtubeEngineProvider).searchVideos("$query - Topic"); + await ref.read(youtubeEngineProvider).searchVideos(query); if (ServiceUtils.onlyContainsEnglish(query)) { return await Future.wait(searchResults diff --git a/lib/services/youtube_engine/newpipe_engine.dart b/lib/services/youtube_engine/newpipe_engine.dart index 6e6204f0..f58fc333 100644 --- a/lib/services/youtube_engine/newpipe_engine.dart +++ b/lib/services/youtube_engine/newpipe_engine.dart @@ -96,7 +96,7 @@ class NewPipeEngine implements YouTubeEngine { Future> searchVideos(String query) async { final results = await NewPipeExtractor.search( query, - contentFilters: [SearchContentFilters.musicSongs], + contentFilters: [SearchContentFilters.videos], ); final resultsWithVideos = results