Skip to content

Commit

Permalink
feat(player): custom playlist implementation for media_kit to replace…
Browse files Browse the repository at this point in the history
… unpredictable playlist of mpv
  • Loading branch information
Kingkor Roy Tirtho committed May 14, 2023
1 parent 5a4e3ba commit eaf65b6
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 56 deletions.
23 changes: 6 additions & 17 deletions lib/provider/proxy_playlist/proxy_playlist_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,9 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
try {
isPreSearching = true;

final softReplace =
SpotubeAudioPlayer.mkSupportedPlatform && percent <= 98;

// TODO: Make repeat mode sensitive changes later
final track = await ensureNthSourcePlayable(
audioPlayer.currentIndex + 1,

/// [MediaKit] doesn't fully support replacing source, so we need
/// to check if the platform is supported or not and replace the
/// actual playlist with a playlist that contains the next track
/// at 98% >= progress
softReplace: softReplace,
exclusive: SpotubeAudioPlayer.mkSupportedPlatform,
);
final track =
await ensureNthSourcePlayable(audioPlayer.currentIndex + 1);

if (track != null) {
state = state.copyWith(tracks: mergeTracks([track], state.tracks));
Expand Down Expand Up @@ -190,17 +179,17 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>

// TODO: Safely Remove playing tracks

void removeTrack(String trackId) {
Future<void> removeTrack(String trackId) async {
final track =
state.tracks.firstWhereOrNull((element) => element.id == trackId);
if (track == null) return;
state = state.copyWith(tracks: {...state.tracks..remove(track)});
final index = audioPlayer.sources.indexOf(makeAppropriateSource(track));
if (index == -1) return;
audioPlayer.removeTrack(index);
await audioPlayer.removeTrack(index);
}

void removeTracks(Iterable<String> tracksIds) {
Future<void> removeTracks(Iterable<String> tracksIds) async {
final tracks =
state.tracks.where((element) => tracksIds.contains(element.id));

Expand All @@ -211,7 +200,7 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
for (final track in tracks) {
final index = audioPlayer.sources.indexOf(makeAppropriateSource(track));
if (index == -1) continue;
audioPlayer.removeTrack(index);
await audioPlayer.removeTrack(index);
}
}

Expand Down
73 changes: 36 additions & 37 deletions lib/services/audio_player/audio_player.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:async';

import 'package:catcher/catcher.dart';
import 'package:collection/collection.dart';
import 'package:media_kit/media_kit.dart' as mk;
import 'package:just_audio/just_audio.dart' as ja;
Expand All @@ -17,7 +18,11 @@ class SpotubeAudioPlayer {

SpotubeAudioPlayer()
: _mkPlayer = mkSupportedPlatform ? MkPlayerWithState() : null,
_justAudio = !mkSupportedPlatform ? ja.AudioPlayer() : 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 =
Expand Down Expand Up @@ -140,9 +145,7 @@ class SpotubeAudioPlayer {

Stream<int> get currentIndexChangedStream {
if (mkSupportedPlatform) {
return _mkPlayer!.streams.playlist
.map((event) => event.index)
.asBroadcastStream();
return _mkPlayer!.indexChangeStream;
} else {
return _justAudio!.sequenceStateStream
.map((event) => event?.currentIndex ?? -1)
Expand Down Expand Up @@ -179,7 +182,7 @@ class SpotubeAudioPlayer {

bool get hasSource {
if (mkSupportedPlatform) {
return _mkPlayer!.state.playlist.medias.isNotEmpty;
return _mkPlayer!.playlist.medias.isNotEmpty;
} else {
return _justAudio!.audioSource != null;
}
Expand Down Expand Up @@ -378,7 +381,7 @@ class SpotubeAudioPlayer {

List<String> get sources {
if (mkSupportedPlatform) {
return _mkPlayer!.state.playlist.medias.map((e) => e.uri).toList();
return _mkPlayer!.playlist.medias.map((e) => e.uri).toList();
} else {
return (_justAudio!.audioSource as ja.ConcatenatingAudioSource)
.children
Expand All @@ -389,7 +392,7 @@ class SpotubeAudioPlayer {

int get currentIndex {
if (mkSupportedPlatform) {
return _mkPlayer!.state.playlist.index;
return _mkPlayer!.playlist.index;
} else {
return _justAudio!.sequenceState?.currentIndex ?? -1;
}
Expand Down Expand Up @@ -455,44 +458,40 @@ class SpotubeAudioPlayer {
final oldSourceIndex = sources.indexOf(oldSource);
if (oldSourceIndex == -1) return;

if (mkSupportedPlatform) {
final sourcesCp = sources.toList();
sourcesCp[oldSourceIndex] = newSource;

await _mkPlayer!.open(
mk.Playlist(
sourcesCp.map(mk.Media.new).toList(),
index: currentIndex,
),
play: false,
);
if (exclusive) await jumpTo(oldSourceIndex);
} else {
await addTrack(newSource);
await removeTrack(oldSourceIndex);
// if (mkSupportedPlatform) {
// final sourcesCp = sources.toList();
// sourcesCp[oldSourceIndex] = newSource;

// await _mkPlayer!.open(
// mk.Playlist(
// sourcesCp.map(mk.Media.new).toList(),
// index: currentIndex,
// ),
// play: false,
// );
// if (exclusive) await jumpTo(oldSourceIndex);
// } else {
await addTrack(newSource);
await removeTrack(oldSourceIndex);

int newSourceIndex = sources.indexOf(newSource);
while (newSourceIndex == -1) {
await Future.delayed(const Duration(milliseconds: 100));
newSourceIndex = sources.indexOf(newSource);
}
int newSourceIndex = sources.indexOf(newSource);
while (newSourceIndex == -1) {
await Future.delayed(const Duration(milliseconds: 100));
newSourceIndex = sources.indexOf(newSource);
}
await moveTrack(newSourceIndex, oldSourceIndex);
newSourceIndex = sources.indexOf(newSource);
while (newSourceIndex != oldSourceIndex) {
await Future.delayed(const Duration(milliseconds: 100));
await moveTrack(newSourceIndex, oldSourceIndex);
newSourceIndex = sources.indexOf(newSource);
while (newSourceIndex != oldSourceIndex) {
await Future.delayed(const Duration(milliseconds: 100));
await moveTrack(newSourceIndex, oldSourceIndex);
newSourceIndex = sources.indexOf(newSource);
}
}
// }
}

Future<void> clearPlaylist() async {
if (mkSupportedPlatform) {
await Future.wait(
_mkPlayer!.state.playlist.medias.mapIndexed(
(i, e) async => await _mkPlayer!.remove(i),
),
);
_mkPlayer!.stop();
} else {
await (_justAudio!.audioSource as ja.ConcatenatingAudioSource).clear();
}
Expand Down
Loading

0 comments on commit eaf65b6

Please sign in to comment.