mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
119 lines
3.8 KiB
Dart
119 lines
3.8 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:mpris_service/mpris_service.dart';
|
|
import 'package:spotify/spotify.dart';
|
|
import 'package:spotube/models/spotube_track.dart';
|
|
import 'package:spotube/provider/playlist_queue_provider.dart';
|
|
import 'package:spotube/services/audio_player/audio_player.dart';
|
|
import 'package:spotube/services/audio_player/loop_mode.dart';
|
|
import 'package:spotube/services/audio_player/playback_state.dart';
|
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
|
|
|
class LinuxAudioService {
|
|
late final MPRIS mpris;
|
|
final Ref ref;
|
|
final PlaylistQueueNotifier playlistNotifier;
|
|
|
|
final subscriptions = <StreamSubscription>[];
|
|
|
|
LinuxAudioService(this.ref, this.playlistNotifier) {
|
|
MPRIS
|
|
.create(
|
|
busName: 'org.mpris.MediaPlayer2.spotube',
|
|
identity: 'Spotube',
|
|
desktopEntry: Platform.resolvedExecutable,
|
|
)
|
|
.then((value) => mpris = value)
|
|
.then((_) {
|
|
mpris.playbackStatus = MPRISPlaybackStatus.stopped;
|
|
mpris.setEventHandler(MPRISEventHandler(
|
|
loopStatus: (value) async {
|
|
playlistNotifier.setLoopMode(
|
|
PlaybackLoopMode.fromMPRISLoopStatus(value),
|
|
);
|
|
},
|
|
next: playlistNotifier.next,
|
|
pause: playlistNotifier.pause,
|
|
play: playlistNotifier.resume,
|
|
playPause: () async {
|
|
if (audioPlayer.isPlaying) {
|
|
await playlistNotifier.pause();
|
|
} else {
|
|
await playlistNotifier.resume();
|
|
}
|
|
},
|
|
seek: playlistNotifier.seek,
|
|
shuffle: playlistNotifier.setShuffle,
|
|
stop: playlistNotifier.stop,
|
|
volume: (value) async {
|
|
await ref.read(VolumeProvider.provider.notifier).setVolume(value);
|
|
},
|
|
previous: playlistNotifier.previous,
|
|
));
|
|
|
|
final playerStateStream =
|
|
audioPlayer.playerStateStream.listen((state) async {
|
|
switch (state) {
|
|
case AudioPlaybackState.buffering:
|
|
case AudioPlaybackState.playing:
|
|
mpris.playbackStatus = MPRISPlaybackStatus.playing;
|
|
break;
|
|
case AudioPlaybackState.paused:
|
|
mpris.playbackStatus = MPRISPlaybackStatus.paused;
|
|
break;
|
|
case AudioPlaybackState.stopped:
|
|
case AudioPlaybackState.completed:
|
|
mpris.playbackStatus = MPRISPlaybackStatus.stopped;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
});
|
|
|
|
final positionStream = audioPlayer.positionStream.listen((pos) async {
|
|
mpris.position = pos;
|
|
});
|
|
|
|
final durationStream =
|
|
audioPlayer.durationStream.listen((duration) async {
|
|
mpris.metadata = mpris.metadata.copyWith(length: duration);
|
|
});
|
|
|
|
subscriptions.addAll([
|
|
playerStateStream,
|
|
positionStream,
|
|
durationStream,
|
|
]);
|
|
});
|
|
}
|
|
|
|
Future<void> addTrack(Track track) async {
|
|
mpris.metadata = MPRISMetadata(
|
|
track is SpotubeTrack ? Uri.parse(track.ytUri) : Uri.parse(track.uri!),
|
|
album: track.album?.name ?? "",
|
|
albumArtist: [track.album?.artists?.first.name ?? ""],
|
|
artUrl: Uri.parse(TypeConversionUtils.image_X_UrlString(
|
|
track.album?.images ?? <Image>[],
|
|
placeholder: ImagePlaceholder.albumArt,
|
|
)),
|
|
artist: track.artists?.map((e) => e.name!).toList(),
|
|
contentCreated: DateTime.tryParse(track.album?.releaseDate ?? ""),
|
|
discNumber: track.discNumber,
|
|
length: track is SpotubeTrack
|
|
? track.ytTrack.duration!
|
|
: Duration(milliseconds: track.durationMs!),
|
|
title: track.name!,
|
|
trackNumber: track.trackNumber,
|
|
);
|
|
}
|
|
|
|
void dispose() {
|
|
mpris.dispose();
|
|
for (var element in subscriptions) {
|
|
element.cancel();
|
|
}
|
|
}
|
|
}
|