mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
refactor: drop fallback support to different sources
This commit is contained in:
parent
4ea0523692
commit
fb0d9620d0
@ -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(
|
||||
|
@ -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
|
||||
final sourcedTrack = await ref
|
||||
.read(sourcedTrackProvider(SpotubeMedia(track)).notifier)
|
||||
.refreshStreamingUrl()
|
||||
: await ref
|
||||
.read(sourcedTrackProvider(SpotubeMedia(track)).notifier)
|
||||
.switchToAlternativeSources();
|
||||
.refreshStreamingUrl();
|
||||
|
||||
ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack);
|
||||
|
||||
|
@ -41,18 +41,6 @@ class SourcedTrackNotifier
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<SourcedTrack?> switchToAlternativeSources() async {
|
||||
if (arg == null) {
|
||||
return null;
|
||||
}
|
||||
return await update((prev) async {
|
||||
return await SourcedTrack.fetchFromTrackAltSource(
|
||||
track: arg!.track,
|
||||
ref: ref,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
final sourcedTrackProvider = AsyncNotifierProviderFamily<SourcedTrackNotifier,
|
||||
|
@ -39,7 +39,7 @@ class CategoryPlaylistsNotifier extends AutoDisposeFamilyPaginatedAsyncNotifier<
|
||||
(json) => PlaylistsFeatured.fromJson(json),
|
||||
).getPage(limit, offset);
|
||||
|
||||
final items = playlists.items?.whereNotNull().toList() ?? [];
|
||||
final items = playlists.items?.nonNulls.toList() ?? [];
|
||||
|
||||
return (
|
||||
items: items,
|
||||
|
@ -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<SourcedTrack> 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.piped =>
|
||||
await PipedSourcedTrack.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),
|
||||
await JioSaavnSourcedTrack.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;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<List<SiblingType>> fetchSiblings({
|
||||
|
@ -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!))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -96,7 +96,7 @@ class NewPipeEngine implements YouTubeEngine {
|
||||
Future<List<Video>> searchVideos(String query) async {
|
||||
final results = await NewPipeExtractor.search(
|
||||
query,
|
||||
contentFilters: [SearchContentFilters.musicSongs],
|
||||
contentFilters: [SearchContentFilters.videos],
|
||||
);
|
||||
|
||||
final resultsWithVideos = results
|
||||
|
Loading…
Reference in New Issue
Block a user