part of 'audio_player.dart'; 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); } } } Future preload(String url) async { throw UnimplementedError(); // final urlType = _resolveUrlType(url); // if (mkSupportedPlatform && urlType is ap.Source) { // // audioplayers doesn't have the capability to preload // return; // } else { // return; // } } 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(); } } } Future pause() async { await _mkPlayer?.pause(); await _justAudio?.pause(); } Future resume() async { await _mkPlayer?.play(); await _justAudio?.play(); } Future stop() async { await _mkPlayer?.stop(); await _justAudio?.stop(); } Future seek(Duration position) async { 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); } Future setSpeed(double speed) async { await _mkPlayer?.setRate(speed); await _justAudio?.setSpeed(speed); } Future dispose() async { await _mkPlayer?.dispose(); await _justAudio?.dispose(); } // Playlist related Future openPlaylist( List tracks, { bool autoPlay = true, int initialIndex = 0, }) 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(); } } } List resolveTracksForSource(List tracks) { return tracks.where((e) => sources.contains(e.ytUri)).toList(); } bool tracksExistsInPlaylist(List tracks) { return resolveTracksForSource(tracks).length == tracks.length; } 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() ?? []; } } int get currentIndex { if (mkSupportedPlatform) { return _mkPlayer!.playlist.index; } else { return _justAudio!.sequenceState?.currentIndex ?? -1; } } Future skipToNext() async { if (mkSupportedPlatform) { await _mkPlayer!.next(); } else { await _justAudio!.seekToNext(); } } Future skipToPrevious() async { 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); } } 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); } } Future removeTrack(int index) async { 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); } } Future replaceSource( String oldSource, String newSource, { bool exclusive = false, }) async { final oldSourceIndex = sources.indexOf(oldSource); if (oldSourceIndex == -1) return; if (mkSupportedPlatform) { _mkPlayer!.replace(oldSource, newSource); } 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); } 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 clearPlaylist() async { 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); } } Future setLoopMode(PlaybackLoopMode loop) async { if (mkSupportedPlatform) { await _mkPlayer!.setPlaylistMode(loop.toPlaylistMode()); } else { await _justAudio!.setLoopMode(loop.toLoopMode()); } } }