🐛 Bug fixes on playback

This commit is contained in:
LittleSheep 2024-08-27 02:22:47 +08:00
parent 031cab75e0
commit 41e248f8cc
6 changed files with 101 additions and 13 deletions

View File

@ -50,10 +50,11 @@ class MyApp extends StatelessWidget {
void _initializeProviders(BuildContext context) async { void _initializeProviders(BuildContext context) async {
Get.lazyPut(() => SpotifyProvider()); Get.lazyPut(() => SpotifyProvider());
Get.lazyPut(() => AudioPlayerProvider());
Get.lazyPut(() => ActiveSourcedTrackProvider()); Get.lazyPut(() => ActiveSourcedTrackProvider());
Get.lazyPut(() => SourcedTrackProvider()); Get.lazyPut(() => SourcedTrackProvider());
Get.lazyPut(() => ServerPlaybackRoutesProvider());
Get.lazyPut(() => PlaybackServerProvider()); Get.put(AudioPlayerProvider());
Get.put(ServerPlaybackRoutesProvider());
Get.put(PlaybackServerProvider());
} }
} }

View File

@ -1,10 +1,11 @@
import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:media_kit/media_kit.dart' hide Track; import 'package:media_kit/media_kit.dart' hide Track;
import 'package:rhythm_box/services/audio_player/state.dart'; import 'package:rhythm_box/services/audio_player/state.dart';
import 'package:rhythm_box/services/local_track.dart'; import 'package:rhythm_box/services/local_track.dart';
import 'package:rhythm_box/services/sourced_track/sourced_track.dart'; import 'package:rhythm_box/services/server/sourced_track.dart';
import 'package:spotify/spotify.dart' hide Playlist; import 'package:spotify/spotify.dart' hide Playlist;
import 'package:rhythm_box/services/audio_player/audio_player.dart'; import 'package:rhythm_box/services/audio_player/audio_player.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -20,10 +21,49 @@ class AudioPlayerProvider extends GetxController {
collections: [], collections: [],
)); ));
AudioPlayerProvider() { List<StreamSubscription<Object>>? _subscriptions;
@override
void onInit() {
SharedPreferences.getInstance().then((ins) { SharedPreferences.getInstance().then((ins) {
_prefs = ins; _prefs = ins;
_syncSavedState();
}); });
_subscriptions = [
audioPlayer.playingStream.listen((playing) async {
state.value = state.value.copyWith(playing: playing);
}),
audioPlayer.loopModeStream.listen((loopMode) async {
state.value = state.value.copyWith(loopMode: loopMode);
}),
audioPlayer.shuffledStream.listen((shuffled) async {
state.value = state.value.copyWith(shuffled: shuffled);
}),
audioPlayer.playlistStream.listen((playlist) async {
state.value = state.value.copyWith(playlist: playlist);
}),
];
state.value = AudioPlayerState(
loopMode: audioPlayer.loopMode,
playing: audioPlayer.isPlaying,
playlist: audioPlayer.playlist,
shuffled: audioPlayer.isShuffled,
collections: [],
);
super.onInit();
}
@override
void dispose() {
if (_subscriptions != null) {
for (final subscription in _subscriptions!) {
subscription.cancel();
}
}
super.dispose();
} }
Future<void> _syncSavedState() async { Future<void> _syncSavedState() async {
@ -35,6 +75,29 @@ class AudioPlayerProvider extends GetxController {
// TODO Sync saved playlist // TODO Sync saved playlist
} }
Future<void> addCollections(List<String> collectionIds) async {
state.value = state.value.copyWith(collections: [
...state.value.collections,
...collectionIds,
]);
}
Future<void> addCollection(String collectionId) async {
await addCollections([collectionId]);
}
Future<void> removeCollections(List<String> collectionIds) async {
state.value = state.value.copyWith(
collections: state.value.collections
.where((element) => !collectionIds.contains(element))
.toList(),
);
}
Future<void> removeCollection(String collectionId) async {
await removeCollections([collectionId]);
}
Future<void> load( Future<void> load(
List<Track> tracks, { List<Track> tracks, {
int initialIndex = 0, int initialIndex = 0,
@ -46,11 +109,14 @@ class AudioPlayerProvider extends GetxController {
// because of timeout // because of timeout
final intendedActiveTrack = medias.elementAt(initialIndex); final intendedActiveTrack = medias.elementAt(initialIndex);
if (intendedActiveTrack.track is! LocalTrack) { if (intendedActiveTrack.track is! LocalTrack) {
await SourcedTrack.fetchFromTrack(track: intendedActiveTrack.track); await Get.find<SourcedTrackProvider>()
.fetch(RhythmMedia(intendedActiveTrack.track));
} }
if (medias.isEmpty) return; if (medias.isEmpty) return;
await removeCollections(state.value.collections);
await audioPlayer.openPlaylist( await audioPlayer.openPlaylist(
medias.map((s) => s as Media).toList(), medias.map((s) => s as Media).toList(),
initialIndex: initialIndex, initialIndex: initialIndex,

View File

@ -1,10 +1,12 @@
import 'dart:developer'; import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:get/get.dart';
import 'package:media_kit/media_kit.dart' hide Track; import 'package:media_kit/media_kit.dart' hide Track;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:rhythm_box/platform.dart'; import 'package:rhythm_box/platform.dart';
import 'package:rhythm_box/services/local_track.dart'; import 'package:rhythm_box/services/local_track.dart';
import 'package:rhythm_box/services/server/server.dart';
import 'package:spotify/spotify.dart' hide Playlist; import 'package:spotify/spotify.dart' hide Playlist;
import 'package:rhythm_box/services/audio_player/custom_player.dart'; import 'package:rhythm_box/services/audio_player/custom_player.dart';
import 'dart:async'; import 'dart:async';
@ -20,7 +22,7 @@ part 'audio_player_impl.dart';
class RhythmMedia extends mk.Media { class RhythmMedia extends mk.Media {
final Track track; final Track track;
static int serverPort = 0; static int get serverPort => Get.find<PlaybackServerProvider>().port;
RhythmMedia( RhythmMedia(
this.track, { this.track, {

View File

@ -58,8 +58,8 @@ class ServerPlaybackRoutesProvider {
}, },
headers: res.headers.map, headers: res.headers.map,
); );
} catch (e) { } catch (e, stackTrace) {
log('[PlaybackSever] Error: $e'); log('[PlaybackSever] Error: $e; Trace:\n $stackTrace');
return Response.internalServerError(); return Response.internalServerError();
} }
} }

View File

@ -11,6 +11,8 @@ import 'package:shelf/shelf_io.dart';
import 'package:shelf_router/shelf_router.dart'; import 'package:shelf_router/shelf_router.dart';
class PlaybackServerProvider extends GetxController { class PlaybackServerProvider extends GetxController {
final int port = Random().nextInt(17500) + 5000;
HttpServer? _server; HttpServer? _server;
Router? _router; Router? _router;
@ -26,8 +28,6 @@ class PlaybackServerProvider extends GetxController {
pipeline.addMiddleware(logRequests()); pipeline.addMiddleware(logRequests());
} }
final port = Random().nextInt(17500) + 5000;
RhythmMedia.serverPort = port; RhythmMedia.serverPort = port;
_router = Router(); _router = Router();

View File

@ -1,17 +1,36 @@
import 'package:collection/collection.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:rhythm_box/providers/audio_player.dart';
import 'package:rhythm_box/services/audio_player/audio_player.dart'; import 'package:rhythm_box/services/audio_player/audio_player.dart';
import 'package:rhythm_box/services/local_track.dart'; import 'package:rhythm_box/services/local_track.dart';
import 'package:rhythm_box/services/sourced_track/sourced_track.dart'; import 'package:rhythm_box/services/sourced_track/sourced_track.dart';
import 'package:spotify/spotify.dart';
class SourcedTrackProvider extends GetxController { class SourcedTrackProvider extends GetxController {
Rx<SourcedTrack?> sourcedTrack = Rx(null);
Future<SourcedTrack?> fetch(RhythmMedia? media) async { Future<SourcedTrack?> fetch(RhythmMedia? media) async {
final track = media?.track; final track = media?.track;
if (track == null || track is LocalTrack) { if (track == null || track is LocalTrack) {
sourcedTrack.value = null;
return null; return null;
} }
final sourcedTrack = await SourcedTrack.fetchFromTrack(track: track); final AudioPlayerProvider playback = Get.find();
return sourcedTrack; ever(playback.state.value.tracks.obs, (List<Track> tracks) {
if (tracks.isEmpty || tracks.none((element) => element.id == track.id)) {
invalidate();
}
});
sourcedTrack.value = await SourcedTrack.fetchFromTrack(track: track);
return sourcedTrack.value;
}
void invalidate() {
sourcedTrack.value = null;
fetch(null);
} }
} }