feat: add source change support and re-add prefetching tracks

This commit is contained in:
Kingkor Roy Tirtho 2024-04-09 21:18:42 +06:00
parent 11964e588d
commit ed079e3e15
5 changed files with 53 additions and 7 deletions

View File

@ -161,7 +161,7 @@ class PlayerQueue extends HookConsumerWidget {
snap: false,
backgroundColor: Colors.transparent,
elevation: 0,
automaticallyImplyLeading: !isSearching.value,
automaticallyImplyLeading: false,
title: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10,

View File

@ -6,6 +6,7 @@ import 'package:catcher_2/catcher_2.dart';
import 'package:spotube/models/local_track.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/proxy_playlist/skip_segments.dart';
import 'package:spotube/provider/server/sourced_track.dart';
import 'package:spotube/services/audio_player/audio_player.dart';
extension ProxyPlaylistListeners on ProxyPlaylistNotifier {
@ -63,6 +64,21 @@ extension ProxyPlaylistListeners on ProxyPlaylistNotifier {
});
}
StreamSubscription subscribeToPosition() {
String lastTrack = ""; // used to prevent multiple calls to the same track
return audioPlayer.positionStream.listen((event) async {
if (event < const Duration(seconds: 3) ||
state.active == null ||
state.active == state.tracks.length - 1) return;
final nextTrack = state.tracks.elementAt(state.active! + 1);
if (lastTrack == nextTrack.id) return;
await ref.read(sourcedTrackProvider(nextTrack).future);
lastTrack = nextTrack.id!;
});
}
StreamSubscription subscribeToPlayerError() {
return audioPlayer.errorStream.listen((event) {});
}

View File

@ -51,6 +51,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier<ProxyPlaylist> {
// These are subscription methods from player_listeners.dart
subscribeToPlaylist(),
subscribeToSkipSponsor(),
subscribeToPosition(),
subscribeToScrobbleChanged(),
];
}

View File

@ -13,9 +13,9 @@ import 'package:spotube/models/logger.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/provider/server/active_sourced_track.dart';
import 'package:spotube/provider/server/sourced_track.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/services/sourced_track/sourced_track.dart';
class PlaybackServer {
final Ref ref;
@ -38,7 +38,6 @@ class PlaybackServer {
if (kDebugMode) {
pipeline.addMiddleware(logRequests());
dio.interceptors.add(LogInterceptor());
}
serve(pipeline.addHandler(router.call), InternetAddress.loopbackIPv4, port)
@ -58,13 +57,15 @@ class PlaybackServer {
try {
final track =
playlist.tracks.firstWhere((element) => element.id == trackId);
final sourcedTrack =
await SourcedTrack.fetchFromTrack(track: track, ref: ref);
final activeSourcedTrack = ref.read(activeSourcedTrackProvider);
final sourcedTrack = activeSourcedTrack?.id == track.id
? activeSourcedTrack
: await ref.read(sourcedTrackProvider(track).future);
ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack);
final res = await dio.get(
sourcedTrack.url,
sourcedTrack!.url,
options: Options(
headers: {
...request.headers,
@ -75,13 +76,14 @@ class PlaybackServer {
"Connection": "keep-alive",
},
responseType: ResponseType.stream,
validateStatus: (status) => status! < 500,
),
);
final audioStream = res.data?.stream as Stream<Uint8List>?;
return Response(
200,
res.statusCode!,
body: audioStream,
context: {
"shelf.io.buffer_output": false,

View File

@ -0,0 +1,27 @@
import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
import 'package:spotube/services/sourced_track/sourced_track.dart';
final sourcedTrackProvider =
FutureProvider.family<SourcedTrack?, Track?>((ref, track) async {
if (track == null) {
return null;
}
ref.listen(
ProxyPlaylistNotifier.provider,
(old, next) {
if (next.tracks.isEmpty ||
next.tracks.none((element) => element.id == track.id)) {
ref.invalidateSelf();
}
},
);
final sourcedTrack =
await SourcedTrack.fetchFromTrack(track: track, ref: ref);
return sourcedTrack;
});