From bf59570251720a80efe0aa6be481899864da5079 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 27 May 2023 13:34:25 +0600 Subject: [PATCH] feat: show loading when track metadata is being fetched, android, ios, macos enable shuffling --- lib/main.dart | 4 +- lib/pages/player/player.dart | 4 +- .../proxy_playlist_provider.dart | 60 +-- lib/services/audio_player/audio_player.dart | 145 +++---- .../audio_player/audio_player_impl.dart | 358 +++++++++--------- .../audio_players_streams_mixin.dart | 186 ++++----- lib/services/audio_player/loop_mode.dart | 42 +- lib/services/audio_player/playback_state.dart | 34 +- macos/Flutter/GeneratedPluginRegistrant.swift | 4 +- pubspec.lock | 48 +-- pubspec.yaml | 8 +- 11 files changed, 454 insertions(+), 439 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 32f42ec3b..e90328245 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -82,9 +82,7 @@ Future main(List rawArgs) async { FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); - if (DesktopTools.platform.isWindows || DesktopTools.platform.isLinux) { - MediaKit.ensureInitialized(); - } + MediaKit.ensureInitialized(); await DesktopTools.ensureInitialized( DesktopWindowOptions( diff --git a/lib/pages/player/player.dart b/lib/pages/player/player.dart index 6663ddfd8..6f96a99aa 100644 --- a/lib/pages/player/player.dart +++ b/lib/pages/player/player.dart @@ -31,10 +31,10 @@ class PlayerView extends HookConsumerWidget { final theme = Theme.of(context); final auth = ref.watch(AuthenticationNotifier.provider); final currentTrack = ref.watch(ProxyPlaylistNotifier.provider.select( - (value) => value?.activeTrack, + (value) => value.activeTrack, )); final isLocalTrack = ref.watch(ProxyPlaylistNotifier.provider.select( - (value) => value?.activeTrack is LocalTrack, + (value) => value.activeTrack is LocalTrack, )); final breakpoint = useBreakpoints(); diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index f620b9a95..e0a13d3aa 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -20,12 +20,12 @@ import 'package:spotube/utils/type_conversion_utils.dart'; /// * [x] Prefetch next track as [SpotubeTrack] on 80% of current track /// * [ ] Mixed Queue containing both [SpotubeTrack] and [LocalTrack] /// * [ ] Modification of the Queue -/// * [ ] Add track at the end +/// * [x] Add track at the end /// * [ ] Add track at the beginning -/// * [ ] Remove track +/// * [x] Remove track /// * [ ] Reorder track /// * [ ] Caching and loading of cache of tracks -/// * [ ] Shuffling +/// * [x] Shuffling /// * [x] loop => playlist, track, none /// * [ ] Alternative Track Source /// * [x] Blacklisting of tracks and artist @@ -65,30 +65,19 @@ class ProxyPlaylistNotifier extends StateNotifier return; } - print('=============== Active Track Changed ==============='); - - print('Current tracks: ${state.tracks.map((e) => e.name).toList()}'); - print('newIndexedTrack: ${newActiveTrack.name}'); - notificationService.addTrack(newActiveTrack); state = state.copyWith( active: state.tracks .toList() .indexWhere((element) => element.id == newActiveTrack.id), ); - print('New active: ${state.active}'); - print('=============== ----- ==============='); if (preferences.albumColorSync) { updatePalette(); } }); audioPlayer.shuffledStream.listen((event) { - print('=============== Shuffled ==============='); - - print('oldTracks: ${state.tracks.map((e) => e.name).toList()}'); - final newlyOrderedTracks = mapSourcesToTracks(audioPlayer.sources); print( @@ -98,10 +87,6 @@ class ProxyPlaylistNotifier extends StateNotifier (element) => element.id == state.activeTrack?.id, ); - print('newActiveIndex $newActiveIndex'); - - print('=============== ----- ==============='); - if (newActiveIndex == -1) return; state = state.copyWith( @@ -157,14 +142,10 @@ class ProxyPlaylistNotifier extends StateNotifier } Future ensureSourcePlayable(String source) async { - print("======== Ensure Source Playable ========="); - print("source: $source"); - if (isPlayable(source)) return null; final track = mapSourcesToTracks([source]).firstOrNull; - print("nthTrack: ${track?.name}"); if (track == null || track is LocalTrack) { return null; } @@ -174,8 +155,6 @@ class ProxyPlaylistNotifier extends StateNotifier _ => await SpotubeTrack.fetchFromTrack(track, preferences), }; - print("======== ----- ========="); - await audioPlayer.replaceSource( source, nthFetchedTrack.ytUri, @@ -256,9 +235,14 @@ class ProxyPlaylistNotifier extends StateNotifier Future jumpTo(int index) async { final oldTrack = mapSourcesToTracks([audioPlayer.currentSource!]).firstOrNull; + state = state.copyWith(active: index); + await audioPlayer.pause(); final track = await ensureSourcePlayable(audioPlayer.sources[index]); if (track != null) { - state = state.copyWith(tracks: mergeTracks([track], state.tracks)); + state = state.copyWith( + tracks: mergeTracks([track], state.tracks), + active: index, + ); } await audioPlayer.jumpTo(index); @@ -300,9 +284,20 @@ class ProxyPlaylistNotifier extends StateNotifier Future next() async { if (audioPlayer.nextSource == null) return; final oldTrack = mapSourcesToTracks([audioPlayer.nextSource!]).firstOrNull; + state = state.copyWith( + active: state.tracks + .toList() + .indexWhere((element) => element.id == oldTrack?.id), + ); + await audioPlayer.pause(); final track = await ensureSourcePlayable(audioPlayer.nextSource!); if (track != null) { - state = state.copyWith(tracks: mergeTracks([track], state.tracks)); + state = state.copyWith( + tracks: mergeTracks([track], state.tracks), + active: state.tracks + .toList() + .indexWhere((element) => element.id == track.id), + ); } await audioPlayer.skipToNext(); @@ -318,9 +313,20 @@ class ProxyPlaylistNotifier extends StateNotifier if (audioPlayer.previousSource == null) return; final oldTrack = mapSourcesToTracks([audioPlayer.previousSource!]).firstOrNull; + state = state.copyWith( + active: state.tracks + .toList() + .indexWhere((element) => element.id == oldTrack?.id), + ); + await audioPlayer.pause(); final track = await ensureSourcePlayable(audioPlayer.previousSource!); if (track != null) { - state = state.copyWith(tracks: mergeTracks([track], state.tracks)); + state = state.copyWith( + tracks: mergeTracks([track], state.tracks), + active: state.tracks + .toList() + .indexWhere((element) => element.id == track.id), + ); } await audioPlayer.skipToPrevious(); if (oldTrack != null && track != null) { diff --git a/lib/services/audio_player/audio_player.dart b/lib/services/audio_player/audio_player.dart index e2e7a06d6..fd0e5a5a2 100644 --- a/lib/services/audio_player/audio_player.dart +++ b/lib/services/audio_player/audio_player.dart @@ -1,7 +1,6 @@ import 'package:catcher/catcher.dart'; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:spotube/services/audio_player/mk_state_player.dart'; -import 'package:just_audio/just_audio.dart' as ja; +// import 'package:just_audio/just_audio.dart' as ja; import 'dart:async'; import 'package:media_kit/media_kit.dart' as mk; @@ -14,37 +13,38 @@ part 'audio_players_streams_mixin.dart'; part 'audio_player_impl.dart'; abstract class AudioPlayerInterface { - final MkPlayerWithState? _mkPlayer; - final ja.AudioPlayer? _justAudio; - - AudioPlayerInterface() - : _mkPlayer = _mkSupportedPlatform ? MkPlayerWithState() : null, - _justAudio = !_mkSupportedPlatform ? ja.AudioPlayer() : null { - _mkPlayer?.streams.error.listen((event) { + final MkPlayerWithState _mkPlayer; + // final ja.AudioPlayer? _justAudio; + + AudioPlayerInterface() : _mkPlayer = MkPlayerWithState() + // _mkPlayer = _mkSupportedPlatform ? MkPlayerWithState() : null, + // _justAudio = !_mkSupportedPlatform ? ja.AudioPlayer() : null + { + _mkPlayer.streams.error.listen((event) { Catcher.reportCheckedError(event, StackTrace.current); }); } /// Whether the current platform supports the audioplayers plugin - static final bool _mkSupportedPlatform = - DesktopTools.platform.isWindows || DesktopTools.platform.isLinux; + static const bool _mkSupportedPlatform = true; + // DesktopTools.platform.isWindows || DesktopTools.platform.isLinux; bool get mkSupportedPlatform => _mkSupportedPlatform; Future get duration async { - if (mkSupportedPlatform) { - return _mkPlayer!.state.duration; - } else { - return _justAudio!.duration; - } + return _mkPlayer.state.duration; + // if (mkSupportedPlatform) { + // } else { + // return _justAudio!.duration; + // } } Future get position async { - if (mkSupportedPlatform) { - return _mkPlayer!.state.position; - } else { - return _justAudio!.position; - } + return _mkPlayer.state.position; + // if (mkSupportedPlatform) { + // } else { + // return _justAudio!.position; + // } } Future get bufferedPosition async { @@ -57,78 +57,87 @@ abstract class AudioPlayerInterface { } bool get hasSource { - if (mkSupportedPlatform) { - return _mkPlayer!.playlist.medias.isNotEmpty; - } else { - return _justAudio!.audioSource != null; - } + return _mkPlayer.playlist.medias.isNotEmpty; + // if (mkSupportedPlatform) { + // return _mkPlayer.playlist.medias.isNotEmpty; + // } else { + // return _justAudio!.audioSource != null; + // } } // states bool get isPlaying { - if (mkSupportedPlatform) { - return _mkPlayer!.state.playing; - } else { - return _justAudio!.playing; - } + return _mkPlayer.state.playing; + // if (mkSupportedPlatform) { + // return _mkPlayer.state.playing; + // } else { + // return _justAudio!.playing; + // } } bool get isPaused { - if (mkSupportedPlatform) { - return !_mkPlayer!.state.playing; - } else { - return !isPlaying; - } + return !_mkPlayer.state.playing; + // if (mkSupportedPlatform) { + // return !_mkPlayer.state.playing; + // } else { + // return !isPlaying; + // } } bool get isStopped { - if (mkSupportedPlatform) { - return !hasSource; - } else { - return _justAudio!.processingState == ja.ProcessingState.idle; - } + return !hasSource; + // if (mkSupportedPlatform) { + // return !hasSource; + // } else { + // return _justAudio!.processingState == ja.ProcessingState.idle; + // } } Future get isCompleted async { - if (mkSupportedPlatform) { - return _mkPlayer!.state.completed; - } else { - return _justAudio!.processingState == ja.ProcessingState.completed; - } + return _mkPlayer.state.completed; + // if (mkSupportedPlatform) { + // return _mkPlayer.state.completed; + // } else { + // return _justAudio!.processingState == ja.ProcessingState.completed; + // } } Future get isShuffled async { - if (mkSupportedPlatform) { - return _mkPlayer!.shuffled; - } else { - return _justAudio!.shuffleModeEnabled; - } + return _mkPlayer.shuffled; + // if (mkSupportedPlatform) { + // return _mkPlayer.shuffled; + // } else { + // return _justAudio!.shuffleModeEnabled; + // } } Future get loopMode async { - if (mkSupportedPlatform) { - return PlaybackLoopMode.fromPlaylistMode(_mkPlayer!.loopMode); - } else { - return PlaybackLoopMode.fromLoopMode(_justAudio!.loopMode); - } + return PlaybackLoopMode.fromPlaylistMode(_mkPlayer.loopMode); + // if (mkSupportedPlatform) { + // return PlaybackLoopMode.fromPlaylistMode(_mkPlayer.loopMode); + // } else { + // return PlaybackLoopMode.fromLoopMode(_justAudio!.loopMode); + // } } /// Returns the current volume of the player, between 0 and 1 double get volume { - if (mkSupportedPlatform) { - return _mkPlayer!.state.volume / 100; - } else { - return _justAudio!.volume; - } + return _mkPlayer.state.volume / 100; + // if (mkSupportedPlatform) { + // return _mkPlayer.state.volume / 100; + // } else { + // return _justAudio!.volume; + // } } bool get isBuffering { - if (mkSupportedPlatform) { - // audioplayers doesn't have the capability to get buffering state - return false; - } else { - return _justAudio!.processingState == ja.ProcessingState.buffering || - _justAudio!.processingState == ja.ProcessingState.loading; - } + return false; + // if (mkSupportedPlatform) { + // // audioplayers doesn't have the capability to get buffering state + // return false; + // } else { + // return _justAudio!.processingState == ja.ProcessingState.buffering || + // _justAudio!.processingState == ja.ProcessingState.loading; + // } } } diff --git a/lib/services/audio_player/audio_player_impl.dart b/lib/services/audio_player/audio_player_impl.dart index 40f4e09b5..770f00958 100644 --- a/lib/services/audio_player/audio_player_impl.dart +++ b/lib/services/audio_player/audio_player_impl.dart @@ -5,15 +5,15 @@ final audioPlayer = SpotubeAudioPlayer(); class SpotubeAudioPlayer extends AudioPlayerInterface with SpotubeAudioPlayersStreams { Object _resolveUrlType(String url) { - if (mkSupportedPlatform) { - return mk.Media(url); - } else { - if (url.startsWith("https")) { - return ja.AudioSource.uri(Uri.parse(url)); - } else { - return ja.AudioSource.file(url); - } - } + // if (mkSupportedPlatform) { + return mk.Media(url); + // } else { + // if (url.startsWith("https")) { + // return ja.AudioSource.uri(Uri.parse(url)); + // } else { + // return ja.AudioSource.file(url); + // } + // } } Future preload(String url) async { @@ -29,63 +29,63 @@ class SpotubeAudioPlayer extends AudioPlayerInterface Future play(String url) async { final urlType = _resolveUrlType(url); - if (mkSupportedPlatform && urlType is mk.Media) { - await _mkPlayer?.open(urlType, play: true); - } else { - if (_justAudio?.audioSource is ja.ProgressiveAudioSource && - (_justAudio?.audioSource as ja.ProgressiveAudioSource) - .uri - .toString() == - url) { - await _justAudio?.play(); - } else { - await _justAudio?.stop(); - await _justAudio?.setAudioSource( - urlType as ja.AudioSource, - preload: true, - ); - await _justAudio?.play(); - } - } + // if (mkSupportedPlatform && urlType is mk.Media) { + await _mkPlayer.open(urlType as mk.Media, play: true); + // } else { + // if (_justAudio?.audioSource is ja.ProgressiveAudioSource && + // (_justAudio?.audioSource as ja.ProgressiveAudioSource) + // .uri + // .toString() == + // url) { + // await _justAudio?.play(); + // } else { + // await _justAudio?.stop(); + // await _justAudio?.setAudioSource( + // urlType as ja.AudioSource, + // preload: true, + // ); + // await _justAudio?.play(); + // } + // } } Future pause() async { - await _mkPlayer?.pause(); - await _justAudio?.pause(); + await _mkPlayer.pause(); + // await _justAudio?.pause(); } Future resume() async { - await _mkPlayer?.play(); - await _justAudio?.play(); + await _mkPlayer.play(); + // await _justAudio?.play(); } Future stop() async { - await _mkPlayer?.stop(); - await _justAudio?.stop(); - await _justAudio?.setShuffleModeEnabled(false); - await _justAudio?.setLoopMode(ja.LoopMode.off); + await _mkPlayer.stop(); + // await _justAudio?.stop(); + // await _justAudio?.setShuffleModeEnabled(false); + // await _justAudio?.setLoopMode(ja.LoopMode.off); } Future seek(Duration position) async { - await _mkPlayer?.seek(position); - await _justAudio?.seek(position); + await _mkPlayer.seek(position); + // await _justAudio?.seek(position); } /// Volume is between 0 and 1 Future setVolume(double volume) async { assert(volume >= 0 && volume <= 1); - await _mkPlayer?.setVolume(volume * 100); - await _justAudio?.setVolume(volume); + await _mkPlayer.setVolume(volume * 100); + // await _justAudio?.setVolume(volume); } Future setSpeed(double speed) async { - await _mkPlayer?.setRate(speed); - await _justAudio?.setSpeed(speed); + await _mkPlayer.setRate(speed); + // await _justAudio?.setSpeed(speed); } Future dispose() async { - await _mkPlayer?.dispose(); - await _justAudio?.dispose(); + await _mkPlayer.dispose(); + // await _justAudio?.dispose(); } // Playlist related @@ -97,28 +97,28 @@ class SpotubeAudioPlayer extends AudioPlayerInterface }) async { assert(tracks.isNotEmpty); assert(initialIndex <= tracks.length - 1); - if (mkSupportedPlatform) { - await _mkPlayer!.open( - mk.Playlist( - tracks.map(mk.Media.new).toList(), - index: initialIndex, - ), - play: autoPlay, - ); - } else { - await _justAudio!.setAudioSource( - ja.ConcatenatingAudioSource( - useLazyPreparation: true, - children: - tracks.map((e) => ja.AudioSource.uri(Uri.parse(e))).toList(), - ), - preload: true, - initialIndex: initialIndex, - ); - if (autoPlay) { - await _justAudio!.play(); - } - } + // if (mkSupportedPlatform) { + await _mkPlayer.open( + mk.Playlist( + tracks.map(mk.Media.new).toList(), + index: initialIndex, + ), + play: autoPlay, + ); + // } else { + // await _justAudio!.setAudioSource( + // ja.ConcatenatingAudioSource( + // useLazyPreparation: true, + // children: + // tracks.map((e) => ja.AudioSource.uri(Uri.parse(e))).toList(), + // ), + // preload: true, + // initialIndex: initialIndex, + // ); + // if (autoPlay) { + // await _justAudio!.play(); + // } + // } } List resolveTracksForSource(List tracks) { @@ -130,108 +130,108 @@ class SpotubeAudioPlayer extends AudioPlayerInterface } List get sources { - if (mkSupportedPlatform) { - return _mkPlayer!.playlist.medias.map((e) => e.uri).toList(); - } else { - return _justAudio!.sequenceState?.effectiveSequence - .map((e) => (e as ja.UriAudioSource).uri.toString()) - .toList() ?? - []; - } + // if (mkSupportedPlatform) { + return _mkPlayer.playlist.medias.map((e) => e.uri).toList(); + // } else { + // return _justAudio!.sequenceState?.effectiveSequence + // .map((e) => (e as ja.UriAudioSource).uri.toString()) + // .toList() ?? + // []; + // } } String? get currentSource { - if (mkSupportedPlatform) { - return _mkPlayer!.playlist.medias - .elementAtOrNull(_mkPlayer!.playlist.index) - ?.uri; - } else { - return (_justAudio?.sequenceState?.effectiveSequence - .elementAtOrNull(_justAudio!.sequenceState!.currentIndex) - as ja.UriAudioSource?) - ?.uri - .toString(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.playlist.medias + .elementAtOrNull(_mkPlayer.playlist.index) + ?.uri; + // } else { + // return (_justAudio?.sequenceState?.effectiveSequence + // .elementAtOrNull(_justAudio!.sequenceState!.currentIndex) + // as ja.UriAudioSource?) + // ?.uri + // .toString(); + // } } String? get nextSource { - if (mkSupportedPlatform) { - return _mkPlayer!.playlist.medias - .elementAtOrNull(_mkPlayer!.playlist.index + 1) - ?.uri; - } else { - return (_justAudio?.sequenceState?.effectiveSequence - .elementAtOrNull(_justAudio!.sequenceState!.currentIndex + 1) - as ja.UriAudioSource?) - ?.uri - .toString(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.playlist.medias + .elementAtOrNull(_mkPlayer.playlist.index + 1) + ?.uri; + // } else { + // return (_justAudio?.sequenceState?.effectiveSequence + // .elementAtOrNull(_justAudio!.sequenceState!.currentIndex + 1) + // as ja.UriAudioSource?) + // ?.uri + // .toString(); + // } } String? get previousSource { - if (mkSupportedPlatform) { - return _mkPlayer!.playlist.medias - .elementAtOrNull(_mkPlayer!.playlist.index - 1) - ?.uri; - } else { - return (_justAudio?.sequenceState?.effectiveSequence - .elementAtOrNull(_justAudio!.sequenceState!.currentIndex - 1) - as ja.UriAudioSource?) - ?.uri - .toString(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.playlist.medias + .elementAtOrNull(_mkPlayer.playlist.index - 1) + ?.uri; + // } else { + // return (_justAudio?.sequenceState?.effectiveSequence + // .elementAtOrNull(_justAudio!.sequenceState!.currentIndex - 1) + // as ja.UriAudioSource?) + // ?.uri + // .toString(); + // } } Future skipToNext() async { - if (mkSupportedPlatform) { - await _mkPlayer!.next(); - } else { - await _justAudio!.seekToNext(); - } + // if (mkSupportedPlatform) { + await _mkPlayer.next(); + // } else { + // await _justAudio!.seekToNext(); + // } } Future skipToPrevious() async { - if (mkSupportedPlatform) { - await _mkPlayer!.previous(); - } else { - await _justAudio!.seekToPrevious(); - } + // if (mkSupportedPlatform) { + await _mkPlayer.previous(); + // } else { + // await _justAudio!.seekToPrevious(); + // } } Future jumpTo(int index) async { - if (mkSupportedPlatform) { - await _mkPlayer!.jump(index); - } else { - await _justAudio!.seek(Duration.zero, index: index); - } + // if (mkSupportedPlatform) { + await _mkPlayer.jump(index); + // } else { + // await _justAudio!.seek(Duration.zero, index: index); + // } } Future addTrack(String url) async { final urlType = _resolveUrlType(url); - if (mkSupportedPlatform && urlType is mk.Media) { - await _mkPlayer!.add(urlType); - } else { - await (_justAudio!.audioSource as ja.ConcatenatingAudioSource) - .add(urlType as ja.AudioSource); - } + // if (mkSupportedPlatform && urlType is mk.Media) { + await _mkPlayer.add(urlType as mk.Media); + // } else { + // await (_justAudio!.audioSource as ja.ConcatenatingAudioSource) + // .add(urlType as ja.AudioSource); + // } } Future removeTrack(int index) async { - if (mkSupportedPlatform) { - await _mkPlayer!.remove(index); - } else { - await (_justAudio!.audioSource as ja.ConcatenatingAudioSource) - .removeAt(index); - } + // if (mkSupportedPlatform) { + await _mkPlayer.remove(index); + // } else { + // await (_justAudio!.audioSource as ja.ConcatenatingAudioSource) + // .removeAt(index); + // } } Future moveTrack(int from, int to) async { - if (mkSupportedPlatform) { - await _mkPlayer!.move(from, to); - } else { - await (_justAudio!.audioSource as ja.ConcatenatingAudioSource) - .move(from, to); - } + // if (mkSupportedPlatform) { + await _mkPlayer.move(from, to); + // } else { + // await (_justAudio!.audioSource as ja.ConcatenatingAudioSource) + // .move(from, to); + // } } Future replaceSource( @@ -242,54 +242,54 @@ class SpotubeAudioPlayer extends AudioPlayerInterface final oldSourceIndex = sources.indexOf(oldSource); if (oldSourceIndex == -1) return; - if (mkSupportedPlatform) { - _mkPlayer!.replace(oldSource, newSource); - } else { - final playlist = _justAudio!.audioSource as ja.ConcatenatingAudioSource; - - print('oldSource: $oldSource'); - print('newSource: $newSource'); - final oldSourceIndexInPlaylist = - _justAudio?.sequenceState?.effectiveSequence.indexWhere( - (e) => (e as ja.UriAudioSource).uri.toString() == oldSource, - ); - - print('oldSourceIndexInPlaylist: $oldSourceIndexInPlaylist'); - - // ignores non existing source - if (oldSourceIndexInPlaylist == null || oldSourceIndexInPlaylist == -1) { - return; - } - - await playlist.removeAt(oldSourceIndexInPlaylist); - await playlist.insert( - oldSourceIndexInPlaylist, - ja.AudioSource.uri(Uri.parse(newSource)), - ); - } + // if (mkSupportedPlatform) { + _mkPlayer.replace(oldSource, newSource); + // } else { + // final playlist = _justAudio!.audioSource as ja.ConcatenatingAudioSource; + + // print('oldSource: $oldSource'); + // print('newSource: $newSource'); + // final oldSourceIndexInPlaylist = + // _justAudio?.sequenceState?.effectiveSequence.indexWhere( + // (e) => (e as ja.UriAudioSource).uri.toString() == oldSource, + // ); + + // print('oldSourceIndexInPlaylist: $oldSourceIndexInPlaylist'); + + // // ignores non existing source + // if (oldSourceIndexInPlaylist == null || oldSourceIndexInPlaylist == -1) { + // return; + // } + + // await playlist.removeAt(oldSourceIndexInPlaylist); + // await playlist.insert( + // oldSourceIndexInPlaylist, + // ja.AudioSource.uri(Uri.parse(newSource)), + // ); + // } } Future clearPlaylist() async { - if (mkSupportedPlatform) { - _mkPlayer!.stop(); - } else { - await (_justAudio!.audioSource as ja.ConcatenatingAudioSource).clear(); - } + // if (mkSupportedPlatform) { + _mkPlayer.stop(); + // } else { + // await (_justAudio!.audioSource as ja.ConcatenatingAudioSource).clear(); + // } } Future setShuffle(bool shuffle) async { - if (mkSupportedPlatform) { - await _mkPlayer!.setShuffle(shuffle); - } else { - await _justAudio!.setShuffleModeEnabled(shuffle); - } + // if (mkSupportedPlatform) { + await _mkPlayer.setShuffle(shuffle); + // } else { + // await _justAudio!.setShuffleModeEnabled(shuffle); + // } } Future setLoopMode(PlaybackLoopMode loop) async { - if (mkSupportedPlatform) { - await _mkPlayer!.setPlaylistMode(loop.toPlaylistMode()); - } else { - await _justAudio!.setLoopMode(loop.toLoopMode()); - } + // if (mkSupportedPlatform) { + await _mkPlayer.setPlaylistMode(loop.toPlaylistMode()); + // } else { + // await _justAudio!.setLoopMode(loop.toLoopMode()); + // } } } diff --git a/lib/services/audio_player/audio_players_streams_mixin.dart b/lib/services/audio_player/audio_players_streams_mixin.dart index 90644d336..3c583aa4f 100644 --- a/lib/services/audio_player/audio_players_streams_mixin.dart +++ b/lib/services/audio_player/audio_players_streams_mixin.dart @@ -3,42 +3,42 @@ part of 'audio_player.dart'; mixin SpotubeAudioPlayersStreams on AudioPlayerInterface { // stream getters Stream get durationStream { - if (mkSupportedPlatform) { - return _mkPlayer!.streams.duration.asBroadcastStream(); - } else { - return _justAudio!.durationStream - .where((event) => event != null) - .map((event) => event!) - .asBroadcastStream(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.streams.duration.asBroadcastStream(); + // } else { + // return _justAudio!.durationStream + // .where((event) => event != null) + // .map((event) => event!) + // .asBroadcastStream(); + // } } Stream get positionStream { - if (mkSupportedPlatform) { - return _mkPlayer!.streams.position.asBroadcastStream(); - } else { - return _justAudio!.positionStream.asBroadcastStream(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.streams.position.asBroadcastStream(); + // } else { + // return _justAudio!.positionStream.asBroadcastStream(); + // } } Stream get bufferedPositionStream { - if (mkSupportedPlatform) { - // audioplayers doesn't have the capability to get buffered position - return _mkPlayer!.streams.buffer.asBroadcastStream(); - } else { - return _justAudio!.bufferedPositionStream.asBroadcastStream(); - } + // if (mkSupportedPlatform) { + // audioplayers doesn't have the capability to get buffered position + return _mkPlayer.streams.buffer.asBroadcastStream(); + // } else { + // return _justAudio!.bufferedPositionStream.asBroadcastStream(); + // } } Stream get completedStream { - if (mkSupportedPlatform) { - return _mkPlayer!.streams.completed.asBroadcastStream(); - } else { - return _justAudio!.playerStateStream - .where( - (event) => event.processingState == ja.ProcessingState.completed) - .asBroadcastStream(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.streams.completed.asBroadcastStream(); + // } else { + // return _justAudio!.playerStateStream + // .where( + // (event) => event.processingState == ja.ProcessingState.completed) + // .asBroadcastStream(); + // } } /// Stream that emits when the player is almost (%) complete @@ -57,92 +57,92 @@ mixin SpotubeAudioPlayersStreams on AudioPlayerInterface { } Stream get playingStream { - if (mkSupportedPlatform) { - return _mkPlayer!.streams.playing.asBroadcastStream(); - } else { - return _justAudio!.playingStream.asBroadcastStream(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.streams.playing.asBroadcastStream(); + // } else { + // return _justAudio!.playingStream.asBroadcastStream(); + // } } Stream get shuffledStream { - if (mkSupportedPlatform) { - return _mkPlayer!.shuffleStream.asBroadcastStream(); - } else { - return _justAudio!.shuffleModeEnabledStream.asBroadcastStream(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.shuffleStream.asBroadcastStream(); + // } else { + // return _justAudio!.shuffleModeEnabledStream.asBroadcastStream(); + // } } Stream get loopModeStream { - if (mkSupportedPlatform) { - return _mkPlayer!.loopModeStream - .map(PlaybackLoopMode.fromPlaylistMode) - .asBroadcastStream(); - } else { - return _justAudio!.loopModeStream - .map(PlaybackLoopMode.fromLoopMode) - .asBroadcastStream(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.loopModeStream + .map(PlaybackLoopMode.fromPlaylistMode) + .asBroadcastStream(); + // } else { + // return _justAudio!.loopModeStream + // .map(PlaybackLoopMode.fromLoopMode) + // .asBroadcastStream(); + // } } Stream get volumeStream { - if (mkSupportedPlatform) { - return _mkPlayer!.streams.volume - .map((event) => event / 100) - .asBroadcastStream(); - } else { - return _justAudio!.volumeStream.asBroadcastStream(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.streams.volume + .map((event) => event / 100) + .asBroadcastStream(); + // } else { + // return _justAudio!.volumeStream.asBroadcastStream(); + // } } Stream get bufferingStream { - if (mkSupportedPlatform) { - return Stream.value(false).asBroadcastStream(); - } else { - return _justAudio!.playerStateStream - .map( - (event) => - event.processingState == ja.ProcessingState.buffering || - event.processingState == ja.ProcessingState.loading, - ) - .asBroadcastStream(); - } + // if (mkSupportedPlatform) { + return Stream.value(false).asBroadcastStream(); + // } else { + // return _justAudio!.playerStateStream + // .map( + // (event) => + // event.processingState == ja.ProcessingState.buffering || + // event.processingState == ja.ProcessingState.loading, + // ) + // .asBroadcastStream(); + // } } Stream get playerStateStream { - if (mkSupportedPlatform) { - return _mkPlayer!.playerStateStream.asBroadcastStream(); - } else { - return _justAudio!.playerStateStream - .map(AudioPlaybackState.fromJaPlayerState) - .asBroadcastStream(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.playerStateStream.asBroadcastStream(); + // } else { + // return _justAudio!.playerStateStream + // .map(AudioPlaybackState.fromJaPlayerState) + // .asBroadcastStream(); + // } } Stream get currentIndexChangedStream { - if (mkSupportedPlatform) { - return _mkPlayer!.indexChangeStream; - } else { - return _justAudio!.sequenceStateStream - .map((event) => event?.currentIndex ?? -1) - .asBroadcastStream(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.indexChangeStream; + // } else { + // return _justAudio!.sequenceStateStream + // .map((event) => event?.currentIndex ?? -1) + // .asBroadcastStream(); + // } } Stream get activeSourceChangedStream { - if (mkSupportedPlatform) { - return _mkPlayer!.indexChangeStream - .map((event) { - return _mkPlayer!.playlist.medias.elementAtOrNull(event)?.uri; - }) - .where((event) => event != null) - .cast(); - } else { - return _justAudio!.sequenceStateStream - .map((event) { - return (event?.currentSource as ja.UriAudioSource?)?.uri.toString(); - }) - .where((event) => event != null) - .cast(); - } + // if (mkSupportedPlatform) { + return _mkPlayer.indexChangeStream + .map((event) { + return _mkPlayer.playlist.medias.elementAtOrNull(event)?.uri; + }) + .where((event) => event != null) + .cast(); + // } else { + // return _justAudio!.sequenceStateStream + // .map((event) { + // return (event?.currentSource as ja.UriAudioSource?)?.uri.toString(); + // }) + // .where((event) => event != null) + // .cast(); + // } } } diff --git a/lib/services/audio_player/loop_mode.dart b/lib/services/audio_player/loop_mode.dart index a55b2298c..252d68105 100644 --- a/lib/services/audio_player/loop_mode.dart +++ b/lib/services/audio_player/loop_mode.dart @@ -1,6 +1,6 @@ import 'package:audio_service/audio_service.dart'; import 'package:media_kit/media_kit.dart'; -import 'package:just_audio/just_audio.dart'; +// import 'package:just_audio/just_audio.dart'; import 'package:mpris_service/mpris_service.dart'; /// An unified loop mode for both [LoopMode] and [PlaylistMode] @@ -9,27 +9,27 @@ enum PlaybackLoopMode { one, none; - static PlaybackLoopMode fromLoopMode(LoopMode loopMode) { - switch (loopMode) { - case LoopMode.all: - return PlaybackLoopMode.all; - case LoopMode.one: - return PlaybackLoopMode.one; - case LoopMode.off: - return PlaybackLoopMode.none; - } - } + // static PlaybackLoopMode fromLoopMode(LoopMode loopMode) { + // switch (loopMode) { + // case LoopMode.all: + // return PlaybackLoopMode.all; + // case LoopMode.one: + // return PlaybackLoopMode.one; + // case LoopMode.off: + // return PlaybackLoopMode.none; + // } + // } - LoopMode toLoopMode() { - switch (this) { - case PlaybackLoopMode.all: - return LoopMode.all; - case PlaybackLoopMode.one: - return LoopMode.one; - case PlaybackLoopMode.none: - return LoopMode.off; - } - } + // LoopMode toLoopMode() { + // switch (this) { + // case PlaybackLoopMode.all: + // return LoopMode.all; + // case PlaybackLoopMode.one: + // return LoopMode.one; + // case PlaybackLoopMode.none: + // return LoopMode.off; + // } + // } static PlaybackLoopMode fromPlaylistMode(PlaylistMode mode) { switch (mode) { diff --git a/lib/services/audio_player/playback_state.dart b/lib/services/audio_player/playback_state.dart index 0bdae439b..a4743a48c 100644 --- a/lib/services/audio_player/playback_state.dart +++ b/lib/services/audio_player/playback_state.dart @@ -1,4 +1,4 @@ -import 'package:just_audio/just_audio.dart'; +// import 'package:just_audio/just_audio.dart'; /// An unified playback state enum enum AudioPlaybackState { @@ -8,21 +8,21 @@ enum AudioPlaybackState { buffering, stopped; - static AudioPlaybackState fromJaPlayerState(PlayerState state) { - if (state.playing) { - return AudioPlaybackState.playing; - } + // static AudioPlaybackState fromJaPlayerState(PlayerState state) { + // if (state.playing) { + // return AudioPlaybackState.playing; + // } - switch (state.processingState) { - case ProcessingState.idle: - return AudioPlaybackState.stopped; - case ProcessingState.ready: - return AudioPlaybackState.paused; - case ProcessingState.completed: - return AudioPlaybackState.completed; - case ProcessingState.loading: - case ProcessingState.buffering: - return AudioPlaybackState.buffering; - } - } + // switch (state.processingState) { + // case ProcessingState.idle: + // return AudioPlaybackState.stopped; + // case ProcessingState.ready: + // return AudioPlaybackState.paused; + // case ProcessingState.completed: + // return AudioPlaybackState.completed; + // case ProcessingState.loading: + // case ProcessingState.buffering: + // return AudioPlaybackState.buffering; + // } + // } } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index af840e219..cbd42bdce 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,8 +11,8 @@ import audio_session import catcher import device_info_plus import flutter_secure_storage_macos -import just_audio import local_notifier +import media_kit_libs_macos_audio import package_info_plus import path_provider_foundation import screen_retriever @@ -32,8 +32,8 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { CatcherPlugin.register(with: registry.registrar(forPlugin: "CatcherPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) - JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) LocalNotifierPlugin.register(with: registry.registrar(forPlugin: "LocalNotifierPlugin")) + MediaKitLibsMacosAudioPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosAudioPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 969e5a80b..79c438870 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -966,30 +966,6 @@ packages: url: "https://pub.dev" source: hosted version: "6.6.2" - just_audio: - dependency: "direct main" - description: - name: just_audio - sha256: "7e6d31508dacd01a066e3889caf6282e5f1eb60707c230203b21a83af5c55586" - url: "https://pub.dev" - source: hosted - version: "0.9.32" - just_audio_platform_interface: - dependency: transitive - description: - name: just_audio_platform_interface - sha256: eff112d5138bea3ba544b6338b1e0537a32b5e1425e4d0dc38f732771cda7c84 - url: "https://pub.dev" - source: hosted - version: "4.2.0" - just_audio_web: - dependency: transitive - description: - name: just_audio_web - sha256: "89d8db6f19f3821bb6bf908c4bfb846079afb2ab575b783d781a6bf119e3abaf" - url: "https://pub.dev" - source: hosted - version: "0.4.7" jwt_decode: dependency: transitive description: @@ -1062,6 +1038,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.7+1" + media_kit_libs_android_audio: + dependency: "direct main" + description: + name: media_kit_libs_android_audio + sha256: e16292bbb1d737ce026fa68154b2fcf5c6f88d6fa752bdb4c0d079c98a82b523 + url: "https://pub.dev" + source: hosted + version: "1.0.4" + media_kit_libs_ios_audio: + dependency: "direct main" + description: + name: media_kit_libs_ios_audio + sha256: bb18ed87e8a155fc1d2ee4bf59462ca04d02a0eeb38d0b454facee6d32441ce7 + url: "https://pub.dev" + source: hosted + version: "1.0.4" media_kit_libs_linux: dependency: "direct main" description: @@ -1070,6 +1062,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + media_kit_libs_macos_audio: + dependency: "direct main" + description: + name: media_kit_libs_macos_audio + sha256: b9f4a2995396fd5cc243901e618c0586d4f1781eecf2302999b77d6faee8b250 + url: "https://pub.dev" + source: hosted + version: "1.0.5" media_kit_libs_windows_audio: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index b7ee0408f..76e3a1132 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,12 +55,14 @@ dependencies: intl: ^0.18.0 introduction_screen: ^3.0.2 json_annotation: ^4.8.1 - just_audio: ^0.9.32 logger: ^1.1.0 media_kit: ^0.0.7+1 - media_kit_libs_windows_audio: ^1.0.3 - media_kit_libs_linux: ^1.0.2 media_kit_native_event_loop: ^1.0.3 + media_kit_libs_android_audio: ^1.0.4 + media_kit_libs_ios_audio: ^1.0.4 + media_kit_libs_linux: ^1.0.2 + media_kit_libs_macos_audio: ^1.0.5 + media_kit_libs_windows_audio: ^1.0.3 metadata_god: ^0.4.1 mime: ^1.0.2 mpris_service: