🐛 Bug fixes on playback
This commit is contained in:
		@@ -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());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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, {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user