mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-05-09 08:44:36 +00:00
feat: add source change support and re-add prefetching tracks
This commit is contained in:
parent
11964e588d
commit
ed079e3e15
@ -161,7 +161,7 @@ class PlayerQueue extends HookConsumerWidget {
|
|||||||
snap: false,
|
snap: false,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
automaticallyImplyLeading: !isSearching.value,
|
automaticallyImplyLeading: false,
|
||||||
title: BackdropFilter(
|
title: BackdropFilter(
|
||||||
filter: ImageFilter.blur(
|
filter: ImageFilter.blur(
|
||||||
sigmaX: 10,
|
sigmaX: 10,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:catcher_2/catcher_2.dart';
|
|||||||
import 'package:spotube/models/local_track.dart';
|
import 'package:spotube/models/local_track.dart';
|
||||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||||
import 'package:spotube/provider/proxy_playlist/skip_segments.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';
|
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||||
|
|
||||||
extension ProxyPlaylistListeners on ProxyPlaylistNotifier {
|
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() {
|
StreamSubscription subscribeToPlayerError() {
|
||||||
return audioPlayer.errorStream.listen((event) {});
|
return audioPlayer.errorStream.listen((event) {});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier<ProxyPlaylist> {
|
|||||||
// These are subscription methods from player_listeners.dart
|
// These are subscription methods from player_listeners.dart
|
||||||
subscribeToPlaylist(),
|
subscribeToPlaylist(),
|
||||||
subscribeToSkipSponsor(),
|
subscribeToSkipSponsor(),
|
||||||
|
subscribeToPosition(),
|
||||||
subscribeToScrobbleChanged(),
|
subscribeToScrobbleChanged(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.dart';
|
||||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.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/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_provider.dart';
|
||||||
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
|
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
|
||||||
import 'package:spotube/services/sourced_track/sourced_track.dart';
|
|
||||||
|
|
||||||
class PlaybackServer {
|
class PlaybackServer {
|
||||||
final Ref ref;
|
final Ref ref;
|
||||||
@ -38,7 +38,6 @@ class PlaybackServer {
|
|||||||
|
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
pipeline.addMiddleware(logRequests());
|
pipeline.addMiddleware(logRequests());
|
||||||
dio.interceptors.add(LogInterceptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serve(pipeline.addHandler(router.call), InternetAddress.loopbackIPv4, port)
|
serve(pipeline.addHandler(router.call), InternetAddress.loopbackIPv4, port)
|
||||||
@ -58,13 +57,15 @@ class PlaybackServer {
|
|||||||
try {
|
try {
|
||||||
final track =
|
final track =
|
||||||
playlist.tracks.firstWhere((element) => element.id == trackId);
|
playlist.tracks.firstWhere((element) => element.id == trackId);
|
||||||
final sourcedTrack =
|
final activeSourcedTrack = ref.read(activeSourcedTrackProvider);
|
||||||
await SourcedTrack.fetchFromTrack(track: track, ref: ref);
|
final sourcedTrack = activeSourcedTrack?.id == track.id
|
||||||
|
? activeSourcedTrack
|
||||||
|
: await ref.read(sourcedTrackProvider(track).future);
|
||||||
|
|
||||||
ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack);
|
ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack);
|
||||||
|
|
||||||
final res = await dio.get(
|
final res = await dio.get(
|
||||||
sourcedTrack.url,
|
sourcedTrack!.url,
|
||||||
options: Options(
|
options: Options(
|
||||||
headers: {
|
headers: {
|
||||||
...request.headers,
|
...request.headers,
|
||||||
@ -75,13 +76,14 @@ class PlaybackServer {
|
|||||||
"Connection": "keep-alive",
|
"Connection": "keep-alive",
|
||||||
},
|
},
|
||||||
responseType: ResponseType.stream,
|
responseType: ResponseType.stream,
|
||||||
|
validateStatus: (status) => status! < 500,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final audioStream = res.data?.stream as Stream<Uint8List>?;
|
final audioStream = res.data?.stream as Stream<Uint8List>?;
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
200,
|
res.statusCode!,
|
||||||
body: audioStream,
|
body: audioStream,
|
||||||
context: {
|
context: {
|
||||||
"shelf.io.buffer_output": false,
|
"shelf.io.buffer_output": false,
|
||||||
|
|||||||
27
lib/provider/server/sourced_track.dart
Normal file
27
lib/provider/server/sourced_track.dart
Normal 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;
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user