mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 16:05:18 +00:00
133 lines
3.4 KiB
Dart
133 lines
3.4 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:media_kit/media_kit.dart' hide Track;
|
|
import 'package:spotube/models/metadata/metadata.dart';
|
|
import 'package:spotube/models/playback/track_sources.dart';
|
|
import 'package:spotube/services/logger/logger.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:spotube/services/audio_player/custom_player.dart';
|
|
import 'dart:async';
|
|
|
|
import 'package:media_kit/media_kit.dart' as mk;
|
|
|
|
import 'package:spotube/services/audio_player/playback_state.dart';
|
|
import 'package:spotube/utils/platform.dart';
|
|
|
|
part 'audio_players_streams_mixin.dart';
|
|
part 'audio_player_impl.dart';
|
|
|
|
class SpotubeMedia extends mk.Media {
|
|
static int serverPort = 0;
|
|
|
|
static String get _host =>
|
|
kIsWindows ? "localhost" : InternetAddress.anyIPv4.address;
|
|
|
|
static String _queries(SpotubeFullTrackObject track) {
|
|
final params = TrackSourceQuery.fromTrack(track).toJson();
|
|
|
|
return params.entries
|
|
.map((e) =>
|
|
"${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value is List<String> ? e.value.join(",") : e.value.toString())}")
|
|
.join("&");
|
|
}
|
|
|
|
final SpotubeTrackObject track;
|
|
SpotubeMedia(
|
|
this.track, {
|
|
Map<String, dynamic>? extras,
|
|
super.httpHeaders,
|
|
}) : assert(
|
|
track is SpotubeLocalTrackObject || track is SpotubeFullTrackObject,
|
|
"Track must be a either a local track or a full track object with ISRC",
|
|
),
|
|
// If the track is a local track, use its path, otherwise use the server URL
|
|
super(
|
|
track is SpotubeLocalTrackObject
|
|
? track.path
|
|
: "http://$_host:$serverPort/stream/${track.id}?${_queries(track as SpotubeFullTrackObject)}",
|
|
);
|
|
}
|
|
|
|
abstract class AudioPlayerInterface {
|
|
final CustomPlayer _mkPlayer;
|
|
|
|
AudioPlayerInterface()
|
|
: _mkPlayer = CustomPlayer(
|
|
configuration: const mk.PlayerConfiguration(
|
|
title: "Spotube",
|
|
logLevel: kDebugMode ? mk.MPVLogLevel.info : mk.MPVLogLevel.error,
|
|
),
|
|
) {
|
|
_mkPlayer.stream.error.listen((event) {
|
|
AppLogger.reportError(event, StackTrace.current);
|
|
});
|
|
}
|
|
|
|
/// Whether the current platform supports the audioplayers plugin
|
|
static const bool _mkSupportedPlatform = true;
|
|
|
|
bool get mkSupportedPlatform => _mkSupportedPlatform;
|
|
|
|
Duration get duration {
|
|
return _mkPlayer.state.duration;
|
|
}
|
|
|
|
Playlist get playlist {
|
|
return _mkPlayer.state.playlist;
|
|
}
|
|
|
|
Duration get position {
|
|
return _mkPlayer.state.position;
|
|
}
|
|
|
|
Duration get bufferedPosition {
|
|
return _mkPlayer.state.buffer;
|
|
}
|
|
|
|
Future<mk.AudioDevice> get selectedDevice async {
|
|
return _mkPlayer.state.audioDevice;
|
|
}
|
|
|
|
Future<List<mk.AudioDevice>> get devices async {
|
|
return _mkPlayer.state.audioDevices;
|
|
}
|
|
|
|
bool get hasSource {
|
|
return _mkPlayer.state.playlist.medias.isNotEmpty;
|
|
}
|
|
|
|
// states
|
|
bool get isPlaying {
|
|
return _mkPlayer.state.playing;
|
|
}
|
|
|
|
bool get isPaused {
|
|
return !_mkPlayer.state.playing;
|
|
}
|
|
|
|
bool get isStopped {
|
|
return !hasSource;
|
|
}
|
|
|
|
Future<bool> get isCompleted async {
|
|
return _mkPlayer.state.completed;
|
|
}
|
|
|
|
bool get isShuffled {
|
|
return _mkPlayer.shuffled;
|
|
}
|
|
|
|
PlaylistMode get loopMode {
|
|
return _mkPlayer.state.playlistMode;
|
|
}
|
|
|
|
/// Returns the current volume of the player, between 0 and 1
|
|
double get volume {
|
|
return _mkPlayer.state.volume / 100;
|
|
}
|
|
|
|
bool get isBuffering {
|
|
return _mkPlayer.state.buffering;
|
|
}
|
|
}
|