mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
refactor(audi_service): unify all platform audio services
This commit is contained in:
parent
58473f0ff9
commit
d7135db5ad
@ -1,4 +1,3 @@
|
||||
import 'package:audio_service/audio_service.dart';
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
@ -12,11 +11,8 @@ import 'package:spotube/provider/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/palette_provider.dart';
|
||||
import 'package:spotube/provider/user_preferences_provider.dart';
|
||||
import 'package:spotube/services/audio_player.dart';
|
||||
import 'package:spotube/services/linux_audio_service.dart';
|
||||
import 'package:spotube/services/mobile_audio_service.dart';
|
||||
import 'package:spotube/services/windows_audio_service.dart';
|
||||
import 'package:spotube/services/audio_services/audio_services.dart';
|
||||
import 'package:spotube/utils/persisted_state_notifier.dart';
|
||||
import 'package:spotube/utils/platform.dart';
|
||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||
import 'package:youtube_explode_dart/youtube_explode_dart.dart' hide Playlist;
|
||||
import 'package:collection/collection.dart';
|
||||
@ -139,9 +135,8 @@ class PlaylistQueue {
|
||||
|
||||
class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
|
||||
final Ref ref;
|
||||
MobileAudioService? mobileService;
|
||||
LinuxAudioService? linuxService;
|
||||
WindowsAudioService? windowsService;
|
||||
|
||||
AudioServices? audioServices;
|
||||
|
||||
static final provider =
|
||||
StateNotifierProvider<PlaylistQueueNotifier, PlaylistQueue?>(
|
||||
@ -155,32 +150,7 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
|
||||
}
|
||||
|
||||
void configure() async {
|
||||
if (kIsMobile || kIsMacOS) {
|
||||
mobileService = await AudioService.init(
|
||||
builder: () => MobileAudioService(
|
||||
this,
|
||||
ref.read(VolumeProvider.provider.notifier),
|
||||
),
|
||||
config: const AudioServiceConfig(
|
||||
androidNotificationChannelId: 'com.krtirtho.Spotube',
|
||||
androidNotificationChannelName: 'Spotube',
|
||||
androidNotificationOngoing: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (kIsLinux) {
|
||||
linuxService = LinuxAudioService(ref, this);
|
||||
}
|
||||
if (kIsWindows) {
|
||||
windowsService = WindowsAudioService(ref, this);
|
||||
}
|
||||
addListener((state) {
|
||||
linuxService?.player.updateProperties();
|
||||
});
|
||||
|
||||
audioPlayer.onPlayerStateChanged.listen((event) {
|
||||
linuxService?.player.updateProperties();
|
||||
});
|
||||
audioServices = await AudioServices.create(ref, this);
|
||||
|
||||
audioPlayer.onPlayerComplete.listen((event) async {
|
||||
if (!isLoaded) return;
|
||||
@ -196,7 +166,6 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
|
||||
|
||||
audioPlayer.onPositionChanged.listen((pos) async {
|
||||
if (!isLoaded) return;
|
||||
await linuxService?.player.updateProperties();
|
||||
final currentDuration = await audioPlayer.getDuration() ?? Duration.zero;
|
||||
|
||||
// skip all the activeTrack.skipSegments
|
||||
@ -368,23 +337,8 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
|
||||
Future<void> play() async {
|
||||
if (!isLoaded) return;
|
||||
await pause();
|
||||
await mobileService?.session?.setActive(true);
|
||||
final mediaItem = MediaItem(
|
||||
id: state!.activeTrack.id!,
|
||||
title: state!.activeTrack.name!,
|
||||
album: state!.activeTrack.album?.name,
|
||||
artist: TypeConversionUtils.artists_X_String(
|
||||
state!.activeTrack.artists ?? <ArtistSimple>[]),
|
||||
artUri: Uri.parse(
|
||||
TypeConversionUtils.image_X_UrlString(
|
||||
state!.activeTrack.album?.images,
|
||||
placeholder: ImagePlaceholder.online,
|
||||
),
|
||||
),
|
||||
duration: state!.activeTrack.duration,
|
||||
);
|
||||
mobileService?.addItem(mediaItem);
|
||||
windowsService?.addTrack(state!.activeTrack);
|
||||
audioServices?.activateSession();
|
||||
await audioServices?.addTrack(state!.activeTrack);
|
||||
if (state!.activeTrack is LocalTrack) {
|
||||
await audioPlayer.play(
|
||||
DeviceFileSource((state!.activeTrack as LocalTrack).path),
|
||||
@ -409,9 +363,7 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
|
||||
);
|
||||
}
|
||||
|
||||
mobileService?.addItem(mediaItem.copyWith(
|
||||
duration: (state!.activeTrack as SpotubeTrack).ytTrack.duration,
|
||||
));
|
||||
audioServices?.addTrack(state!.activeTrack);
|
||||
|
||||
final cached =
|
||||
await DefaultCacheManager().getFileFromCache(state!.activeTrack.id!);
|
||||
@ -463,7 +415,7 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
(mobileService)?.session?.setActive(false);
|
||||
audioServices?.deactivateSession();
|
||||
state = null;
|
||||
|
||||
return audioPlayer.stop();
|
||||
@ -576,7 +528,7 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
windowsService?.dispose();
|
||||
audioServices?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
69
lib/services/audio_services/audio_services.dart
Normal file
69
lib/services/audio_services/audio_services.dart
Normal file
@ -0,0 +1,69 @@
|
||||
import 'package:audio_service/audio_service.dart';
|
||||
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.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_services/linux_audio_service.dart';
|
||||
import 'package:spotube/services/audio_services/mobile_audio_service.dart';
|
||||
import 'package:spotube/services/audio_services/windows_audio_service.dart';
|
||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||
|
||||
class AudioServices {
|
||||
final MobileAudioService? mobile;
|
||||
final WindowsAudioService? smtc;
|
||||
final LinuxAudioService? mpris;
|
||||
|
||||
AudioServices(this.mobile, this.smtc, this.mpris);
|
||||
|
||||
static Future<AudioServices> create(
|
||||
Ref ref, PlaylistQueueNotifier playlistQueueNotifier) async {
|
||||
final mobile =
|
||||
!DesktopTools.platform.isMobile && !!DesktopTools.platform.isMacOS
|
||||
? null
|
||||
: MobileAudioService(
|
||||
playlistQueueNotifier,
|
||||
ref.read(VolumeProvider.provider.notifier),
|
||||
);
|
||||
final smtc = !DesktopTools.platform.isWindows
|
||||
? null
|
||||
: WindowsAudioService(ref, playlistQueueNotifier);
|
||||
final mpris = !DesktopTools.platform.isLinux
|
||||
? null
|
||||
: LinuxAudioService(ref, playlistQueueNotifier);
|
||||
|
||||
return AudioServices(mobile, smtc, mpris);
|
||||
}
|
||||
|
||||
Future<void> addTrack(Track track) async {
|
||||
await smtc?.addTrack(track);
|
||||
await mpris?.addTrack(track);
|
||||
mobile?.addItem(MediaItem(
|
||||
id: track.id!,
|
||||
album: track.album?.name ?? "",
|
||||
title: track.name!,
|
||||
artist: TypeConversionUtils.artists_X_String(track.artists ?? <Artist>[]),
|
||||
duration: track is SpotubeTrack
|
||||
? track.ytTrack.duration!
|
||||
: Duration(milliseconds: track.durationMs ?? 0),
|
||||
artUri: Uri.parse(TypeConversionUtils.image_X_UrlString(
|
||||
track.album?.images ?? <Image>[],
|
||||
placeholder: ImagePlaceholder.albumArt,
|
||||
)),
|
||||
playable: true,
|
||||
));
|
||||
}
|
||||
|
||||
void activateSession() {
|
||||
mobile?.session?.setActive(true);
|
||||
}
|
||||
|
||||
void deactivateSession() {
|
||||
mobile?.session?.setActive(false);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
smtc?.dispose();
|
||||
mpris?.dispose();
|
||||
}
|
||||
}
|
124
lib/services/audio_services/linux_audio_service.dart
Normal file
124
lib/services/audio_services/linux_audio_service.dart
Normal file
@ -0,0 +1,124 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
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.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 {
|
||||
if (value == MPRISLoopStatus.none) {
|
||||
playlistNotifier.unloop();
|
||||
} else if (value == MPRISLoopStatus.track) {
|
||||
playlistNotifier.loop();
|
||||
}
|
||||
},
|
||||
next: playlistNotifier.next,
|
||||
pause: playlistNotifier.pause,
|
||||
play: playlistNotifier.resume,
|
||||
playPause: () async {
|
||||
if (PlaylistQueueNotifier.isPlaying) {
|
||||
await playlistNotifier.pause();
|
||||
} else {
|
||||
await playlistNotifier.resume();
|
||||
}
|
||||
},
|
||||
seek: playlistNotifier.seek,
|
||||
shuffle: (value) async {
|
||||
if (value) {
|
||||
playlistNotifier.shuffle();
|
||||
} else {
|
||||
playlistNotifier.unshuffle();
|
||||
}
|
||||
},
|
||||
stop: playlistNotifier.stop,
|
||||
volume: (value) async {
|
||||
await ref.read(VolumeProvider.provider.notifier).setVolume(value);
|
||||
},
|
||||
previous: playlistNotifier.previous,
|
||||
));
|
||||
|
||||
final playerStateStream =
|
||||
audioPlayer.onPlayerStateChanged.listen((state) async {
|
||||
switch (state) {
|
||||
case PlayerState.playing:
|
||||
mpris.playbackStatus = MPRISPlaybackStatus.playing;
|
||||
break;
|
||||
case PlayerState.paused:
|
||||
mpris.playbackStatus = MPRISPlaybackStatus.paused;
|
||||
break;
|
||||
case PlayerState.stopped:
|
||||
case PlayerState.completed:
|
||||
mpris.playbackStatus = MPRISPlaybackStatus.stopped;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
final positionStream = audioPlayer.onPositionChanged.listen((pos) async {
|
||||
mpris.position = pos;
|
||||
});
|
||||
|
||||
final durationStream =
|
||||
audioPlayer.onDurationChanged.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();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,738 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dbus/dbus.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:spotube/provider/dbus_provider.dart';
|
||||
import 'package:spotube/models/spotube_track.dart';
|
||||
import 'package:spotube/provider/playlist_queue_provider.dart';
|
||||
import 'package:spotube/services/audio_player.dart';
|
||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
class _MprisMediaPlayer2 extends DBusObject {
|
||||
/// Creates a new object to expose on [path].
|
||||
_MprisMediaPlayer2() : super(DBusObjectPath('/org/mpris/MediaPlayer2')) {
|
||||
dbus.registerObject(this);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
dbus.unregisterObject(this);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.CanQuit
|
||||
Future<DBusMethodResponse> getCanQuit() async {
|
||||
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Fullscreen
|
||||
Future<DBusMethodResponse> getFullscreen() async {
|
||||
return DBusMethodSuccessResponse([const DBusBoolean(false)]);
|
||||
}
|
||||
|
||||
/// Sets property org.mpris.MediaPlayer2.Fullscreen
|
||||
Future<DBusMethodResponse> setFullscreen(bool value) async {
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.CanSetFullscreen
|
||||
Future<DBusMethodResponse> getCanSetFullscreen() async {
|
||||
return DBusMethodSuccessResponse([const DBusBoolean(false)]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.CanRaise
|
||||
Future<DBusMethodResponse> getCanRaise() async {
|
||||
return DBusMethodSuccessResponse([const DBusBoolean(false)]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.HasTrackList
|
||||
Future<DBusMethodResponse> getHasTrackList() async {
|
||||
return DBusMethodSuccessResponse([const DBusBoolean(false)]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Identity
|
||||
Future<DBusMethodResponse> getIdentity() async {
|
||||
return DBusMethodSuccessResponse([const DBusString("Spotube")]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.DesktopEntry
|
||||
Future<DBusMethodResponse> getDesktopEntry() async {
|
||||
return DBusMethodSuccessResponse([const DBusString("spotube")]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.SupportedUriSchemes
|
||||
Future<DBusMethodResponse> getSupportedUriSchemes() async {
|
||||
return DBusMethodSuccessResponse([
|
||||
DBusArray.string(["http"])
|
||||
]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.SupportedMimeTypes
|
||||
Future<DBusMethodResponse> getSupportedMimeTypes() async {
|
||||
return DBusMethodSuccessResponse([
|
||||
DBusArray.string(["audio/mpeg"])
|
||||
]);
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Raise()
|
||||
Future<DBusMethodResponse> doRaise() async {
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Quit()
|
||||
Future<DBusMethodResponse> doQuit() async {
|
||||
await windowManager.close();
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
@override
|
||||
List<DBusIntrospectInterface> introspect() {
|
||||
return [
|
||||
DBusIntrospectInterface('org.mpris.MediaPlayer2', methods: [
|
||||
DBusIntrospectMethod('Raise'),
|
||||
DBusIntrospectMethod('Quit')
|
||||
], properties: [
|
||||
DBusIntrospectProperty('CanQuit', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('Fullscreen', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.readwrite),
|
||||
DBusIntrospectProperty('CanSetFullscreen', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('CanRaise', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('HasTrackList', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('Identity', DBusSignature('s'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('DesktopEntry', DBusSignature('s'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('SupportedUriSchemes', DBusSignature('as'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('SupportedMimeTypes', DBusSignature('as'),
|
||||
access: DBusPropertyAccess.read)
|
||||
])
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DBusMethodResponse> handleMethodCall(DBusMethodCall methodCall) async {
|
||||
if (methodCall.interface == 'org.mpris.MediaPlayer2') {
|
||||
if (methodCall.name == 'Raise') {
|
||||
if (methodCall.values.isNotEmpty) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doRaise();
|
||||
} else if (methodCall.name == 'Quit') {
|
||||
if (methodCall.values.isNotEmpty) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doQuit();
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownMethod();
|
||||
}
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownInterface();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DBusMethodResponse> getProperty(String interface, String name) async {
|
||||
if (interface == 'org.mpris.MediaPlayer2') {
|
||||
if (name == 'CanQuit') {
|
||||
return getCanQuit();
|
||||
} else if (name == 'Fullscreen') {
|
||||
return getFullscreen();
|
||||
} else if (name == 'CanSetFullscreen') {
|
||||
return getCanSetFullscreen();
|
||||
} else if (name == 'CanRaise') {
|
||||
return getCanRaise();
|
||||
} else if (name == 'HasTrackList') {
|
||||
return getHasTrackList();
|
||||
} else if (name == 'Identity') {
|
||||
return getIdentity();
|
||||
} else if (name == 'DesktopEntry') {
|
||||
return getDesktopEntry();
|
||||
} else if (name == 'SupportedUriSchemes') {
|
||||
return getSupportedUriSchemes();
|
||||
} else if (name == 'SupportedMimeTypes') {
|
||||
return getSupportedMimeTypes();
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownProperty();
|
||||
}
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownProperty();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DBusMethodResponse> setProperty(
|
||||
String interface, String name, DBusValue value) async {
|
||||
if (interface == 'org.mpris.MediaPlayer2') {
|
||||
if (name == 'CanQuit') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'Fullscreen') {
|
||||
if (value.signature != DBusSignature('b')) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return setFullscreen((value as DBusBoolean).value);
|
||||
} else if (name == 'CanSetFullscreen') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'CanRaise') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'HasTrackList') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'Identity') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'DesktopEntry') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'SupportedUriSchemes') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'SupportedMimeTypes') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownProperty();
|
||||
}
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownProperty();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DBusMethodResponse> getAllProperties(String interface) async {
|
||||
var properties = <String, DBusValue>{};
|
||||
if (interface == 'org.mpris.MediaPlayer2') {
|
||||
properties['CanQuit'] = (await getCanQuit()).returnValues[0];
|
||||
properties['Fullscreen'] = (await getFullscreen()).returnValues[0];
|
||||
properties['CanSetFullscreen'] =
|
||||
(await getCanSetFullscreen()).returnValues[0];
|
||||
properties['CanRaise'] = (await getCanRaise()).returnValues[0];
|
||||
properties['HasTrackList'] = (await getHasTrackList()).returnValues[0];
|
||||
properties['Identity'] = (await getIdentity()).returnValues[0];
|
||||
properties['DesktopEntry'] = (await getDesktopEntry()).returnValues[0];
|
||||
properties['SupportedUriSchemes'] =
|
||||
(await getSupportedUriSchemes()).returnValues[0];
|
||||
properties['SupportedMimeTypes'] =
|
||||
(await getSupportedMimeTypes()).returnValues[0];
|
||||
}
|
||||
return DBusMethodSuccessResponse([DBusDict.stringVariant(properties)]);
|
||||
}
|
||||
}
|
||||
|
||||
class _MprisMediaPlayer2Player extends DBusObject {
|
||||
final Ref ref;
|
||||
final PlaylistQueueNotifier playlistNotifier;
|
||||
|
||||
/// Creates a new object to expose on [path].
|
||||
_MprisMediaPlayer2Player(this.ref, this.playlistNotifier)
|
||||
: super(DBusObjectPath("/org/mpris/MediaPlayer2")) {
|
||||
(() async {
|
||||
final nameStatus =
|
||||
await dbus.requestName("org.mpris.MediaPlayer2.spotube");
|
||||
if (nameStatus == DBusRequestNameReply.exists) {
|
||||
await dbus.requestName("org.mpris.MediaPlayer2.spotube.instance$pid");
|
||||
}
|
||||
await dbus.registerObject(this);
|
||||
}());
|
||||
}
|
||||
|
||||
PlaylistQueue? get playlist => playlistNotifier.state;
|
||||
double get volume => ref.read(VolumeProvider.provider);
|
||||
VolumeProvider get volumeNotifier =>
|
||||
ref.read(VolumeProvider.provider.notifier);
|
||||
|
||||
void dispose() {
|
||||
dbus.unregisterObject(this);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.PlaybackStatus
|
||||
Future<DBusMethodResponse> getPlaybackStatus() async {
|
||||
final status = PlaylistQueueNotifier.isPlaying
|
||||
? "Playing"
|
||||
: playlist == null
|
||||
? "Stopped"
|
||||
: "Paused";
|
||||
return DBusMethodSuccessResponse([DBusString(status)]);
|
||||
}
|
||||
|
||||
// TODO: Implement Track Loop
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.LoopStatus
|
||||
Future<DBusMethodResponse> getLoopStatus() async {
|
||||
return DBusMethodSuccessResponse([
|
||||
/* playlistNotifier.isLoop */ false
|
||||
? const DBusString("Track")
|
||||
: const DBusString("None"),
|
||||
]);
|
||||
}
|
||||
|
||||
/// Sets property org.mpris.MediaPlayer2.Player.LoopStatus
|
||||
Future<DBusMethodResponse> setLoopStatus(String value) async {
|
||||
// playlistNotifier.setIsLoop(value == "Track");
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.Rate
|
||||
Future<DBusMethodResponse> getRate() async {
|
||||
return DBusMethodSuccessResponse([const DBusDouble(1)]);
|
||||
}
|
||||
|
||||
/// Sets property org.mpris.MediaPlayer2.Player.Rate
|
||||
Future<DBusMethodResponse> setRate(double value) async {
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.Shuffle
|
||||
Future<DBusMethodResponse> getShuffle() async {
|
||||
return DBusMethodSuccessResponse(
|
||||
[DBusBoolean(playlist?.isShuffled ?? false)]);
|
||||
}
|
||||
|
||||
/// Sets property org.mpris.MediaPlayer2.Player.Shuffle
|
||||
Future<DBusMethodResponse> setShuffle(bool value) async {
|
||||
if (value) {
|
||||
playlistNotifier.shuffle();
|
||||
} else {
|
||||
playlistNotifier.unshuffle();
|
||||
}
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.Metadata
|
||||
Future<DBusMethodResponse> getMetadata() async {
|
||||
if (playlist == null || playlist!.isLoading) {
|
||||
return DBusMethodSuccessResponse([DBusDict.stringVariant({})]);
|
||||
}
|
||||
final id = playlist!.active;
|
||||
|
||||
return DBusMethodSuccessResponse([
|
||||
DBusDict.stringVariant({
|
||||
"mpris:trackid": DBusString("${path.value}/Track/$id"),
|
||||
"mpris:length":
|
||||
DBusInt32((await audioPlayer.getDuration())?.inMicroseconds ?? 0),
|
||||
"mpris:artUrl": DBusString(
|
||||
TypeConversionUtils.image_X_UrlString(
|
||||
playlist?.activeTrack.album?.images,
|
||||
placeholder: ImagePlaceholder.albumArt,
|
||||
),
|
||||
),
|
||||
"xesam:album": DBusString(playlist!.activeTrack.album!.name!),
|
||||
"xesam:artist": DBusArray.string(
|
||||
playlist!.activeTrack.artists!.map((artist) => artist.name!),
|
||||
),
|
||||
"xesam:title": DBusString(playlist!.activeTrack.name!),
|
||||
"xesam:url": DBusString(
|
||||
playlist!.activeTrack is SpotubeTrack
|
||||
? (playlist!.activeTrack as SpotubeTrack).ytUri
|
||||
: playlist!.activeTrack.previewUrl!,
|
||||
),
|
||||
"xesam:genre": const DBusString("Unknown"),
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.Volume
|
||||
Future<DBusMethodResponse> getVolume() async {
|
||||
return DBusMethodSuccessResponse([DBusDouble(volume)]);
|
||||
}
|
||||
|
||||
/// Sets property org.mpris.MediaPlayer2.Player.Volume
|
||||
Future<DBusMethodResponse> setVolume(double value) async {
|
||||
await volumeNotifier.setVolume(value);
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.Position
|
||||
Future<DBusMethodResponse> getPosition() async {
|
||||
return DBusMethodSuccessResponse([
|
||||
DBusInt64((await audioPlayer.getDuration())?.inMicroseconds ?? 0),
|
||||
]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.MinimumRate
|
||||
Future<DBusMethodResponse> getMinimumRate() async {
|
||||
return DBusMethodSuccessResponse([const DBusDouble(1)]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.MaximumRate
|
||||
Future<DBusMethodResponse> getMaximumRate() async {
|
||||
return DBusMethodSuccessResponse([const DBusDouble(1)]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.CanGoNext
|
||||
Future<DBusMethodResponse> getCanGoNext() async {
|
||||
return DBusMethodSuccessResponse([
|
||||
DBusBoolean(
|
||||
(playlist?.tracks.length ?? 0) > 1,
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.CanGoPrevious
|
||||
Future<DBusMethodResponse> getCanGoPrevious() async {
|
||||
return DBusMethodSuccessResponse([
|
||||
DBusBoolean(
|
||||
(playlist?.tracks.length ?? 0) > 1,
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.CanPlay
|
||||
Future<DBusMethodResponse> getCanPlay() async {
|
||||
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.CanPause
|
||||
Future<DBusMethodResponse> getCanPause() async {
|
||||
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.CanSeek
|
||||
Future<DBusMethodResponse> getCanSeek() async {
|
||||
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
|
||||
}
|
||||
|
||||
/// Gets value of property org.mpris.MediaPlayer2.Player.CanControl
|
||||
Future<DBusMethodResponse> getCanControl() async {
|
||||
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Player.Next()
|
||||
Future<DBusMethodResponse> doNext() async {
|
||||
await playlistNotifier.next();
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Player.Previous()
|
||||
Future<DBusMethodResponse> doPrevious() async {
|
||||
await playlistNotifier.previous();
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Player.Pause()
|
||||
Future<DBusMethodResponse> doPause() async {
|
||||
playlistNotifier.pause();
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Player.PlayPause()
|
||||
Future<DBusMethodResponse> doPlayPause() async {
|
||||
PlaylistQueueNotifier.isPlaying
|
||||
? await playlistNotifier.pause()
|
||||
: await playlistNotifier.resume();
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Player.Stop()
|
||||
Future<DBusMethodResponse> doStop() async {
|
||||
playlistNotifier.stop();
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Player.Play()
|
||||
Future<DBusMethodResponse> doPlay() async {
|
||||
playlistNotifier.resume();
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Player.Seek()
|
||||
Future<DBusMethodResponse> doSeek(int offset) async {
|
||||
await playlistNotifier.seek(Duration(microseconds: offset));
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Player.SetPosition()
|
||||
Future<DBusMethodResponse> doSetPosition(String TrackId, int Position) async {
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Implementation of org.mpris.MediaPlayer2.Player.OpenUri()
|
||||
Future<DBusMethodResponse> doOpenUri(String Uri) async {
|
||||
return DBusMethodSuccessResponse();
|
||||
}
|
||||
|
||||
/// Emits signal org.mpris.MediaPlayer2.Player.Seeked
|
||||
Future<void> emitSeeked(int position) async {
|
||||
await emitSignal(
|
||||
'org.mpris.MediaPlayer2.Player',
|
||||
'Seeked',
|
||||
[DBusInt64(position)],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> updateProperties() async {
|
||||
return emitPropertiesChanged(
|
||||
"org.mpris.MediaPlayer2.Player",
|
||||
changedProperties: {
|
||||
"PlaybackStatus": (await getPlaybackStatus()).returnValues.first,
|
||||
"LoopStatus": (await getLoopStatus()).returnValues.first,
|
||||
"Rate": (await getRate()).returnValues.first,
|
||||
"Shuffle": (await getShuffle()).returnValues.first,
|
||||
"Metadata": (await getMetadata()).returnValues.first,
|
||||
"Volume": (await getVolume()).returnValues.first,
|
||||
"Position": (await getPosition()).returnValues.first,
|
||||
"MinimumRate": (await getMinimumRate()).returnValues.first,
|
||||
"MaximumRate": (await getMaximumRate()).returnValues.first,
|
||||
"CanGoNext": (await getCanGoNext()).returnValues.first,
|
||||
"CanGoPrevious": (await getCanGoPrevious()).returnValues.first,
|
||||
"CanPlay": (await getCanPlay()).returnValues.first,
|
||||
"CanPause": (await getCanPause()).returnValues.first,
|
||||
"CanSeek": (await getCanSeek()).returnValues.first,
|
||||
"CanControl": (await getCanControl()).returnValues.first,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<DBusIntrospectInterface> introspect() {
|
||||
return [
|
||||
DBusIntrospectInterface('org.mpris.MediaPlayer2.Player', methods: [
|
||||
DBusIntrospectMethod('Next'),
|
||||
DBusIntrospectMethod('Previous'),
|
||||
DBusIntrospectMethod('Pause'),
|
||||
DBusIntrospectMethod('PlayPause'),
|
||||
DBusIntrospectMethod('Stop'),
|
||||
DBusIntrospectMethod('Play'),
|
||||
DBusIntrospectMethod('Seek', args: [
|
||||
DBusIntrospectArgument(DBusSignature('x'), DBusArgumentDirection.in_,
|
||||
name: 'Offset')
|
||||
]),
|
||||
DBusIntrospectMethod('SetPosition', args: [
|
||||
DBusIntrospectArgument(DBusSignature('o'), DBusArgumentDirection.in_,
|
||||
name: 'TrackId'),
|
||||
DBusIntrospectArgument(DBusSignature('x'), DBusArgumentDirection.in_,
|
||||
name: 'Position')
|
||||
]),
|
||||
DBusIntrospectMethod('OpenUri', args: [
|
||||
DBusIntrospectArgument(DBusSignature('s'), DBusArgumentDirection.in_,
|
||||
name: 'Uri')
|
||||
])
|
||||
], signals: [
|
||||
DBusIntrospectSignal('Seeked', args: [
|
||||
DBusIntrospectArgument(DBusSignature('x'), DBusArgumentDirection.out,
|
||||
name: 'Position')
|
||||
])
|
||||
], properties: [
|
||||
DBusIntrospectProperty('PlaybackStatus', DBusSignature('s'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('LoopStatus', DBusSignature('s'),
|
||||
access: DBusPropertyAccess.readwrite),
|
||||
DBusIntrospectProperty('Rate', DBusSignature('d'),
|
||||
access: DBusPropertyAccess.readwrite),
|
||||
DBusIntrospectProperty('Shuffle', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.readwrite),
|
||||
DBusIntrospectProperty('Metadata', DBusSignature('a{sv}'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('Volume', DBusSignature('d'),
|
||||
access: DBusPropertyAccess.readwrite),
|
||||
DBusIntrospectProperty('Position', DBusSignature('x'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('MinimumRate', DBusSignature('d'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('MaximumRate', DBusSignature('d'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('CanGoNext', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('CanGoPrevious', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('CanPlay', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('CanPause', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('CanSeek', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.read),
|
||||
DBusIntrospectProperty('CanControl', DBusSignature('b'),
|
||||
access: DBusPropertyAccess.read)
|
||||
])
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DBusMethodResponse> handleMethodCall(DBusMethodCall methodCall) async {
|
||||
if (methodCall.interface == 'org.mpris.MediaPlayer2.Player') {
|
||||
if (methodCall.name == 'Next') {
|
||||
if (methodCall.values.isNotEmpty) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doNext();
|
||||
} else if (methodCall.name == 'Previous') {
|
||||
if (methodCall.values.isNotEmpty) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doPrevious();
|
||||
} else if (methodCall.name == 'Pause') {
|
||||
if (methodCall.values.isNotEmpty) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doPause();
|
||||
} else if (methodCall.name == 'PlayPause') {
|
||||
if (methodCall.values.isNotEmpty) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doPlayPause();
|
||||
} else if (methodCall.name == 'Stop') {
|
||||
if (methodCall.values.isNotEmpty) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doStop();
|
||||
} else if (methodCall.name == 'Play') {
|
||||
if (methodCall.values.isNotEmpty) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doPlay();
|
||||
} else if (methodCall.name == 'Seek') {
|
||||
if (methodCall.signature != DBusSignature('x')) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doSeek((methodCall.values[0] as DBusInt64).value);
|
||||
} else if (methodCall.name == 'SetPosition') {
|
||||
if (methodCall.signature != DBusSignature('ox')) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doSetPosition((methodCall.values[0] as DBusObjectPath).value,
|
||||
(methodCall.values[1] as DBusInt64).value);
|
||||
} else if (methodCall.name == 'OpenUri') {
|
||||
if (methodCall.signature != DBusSignature('s')) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return doOpenUri((methodCall.values[0] as DBusString).value);
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownMethod();
|
||||
}
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownInterface();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DBusMethodResponse> getProperty(String interface, String name) async {
|
||||
if (interface == 'org.mpris.MediaPlayer2.Player') {
|
||||
if (name == 'PlaybackStatus') {
|
||||
return getPlaybackStatus();
|
||||
} else if (name == 'LoopStatus') {
|
||||
return getLoopStatus();
|
||||
} else if (name == 'Rate') {
|
||||
return getRate();
|
||||
} else if (name == 'Shuffle') {
|
||||
return getShuffle();
|
||||
} else if (name == 'Metadata') {
|
||||
return getMetadata();
|
||||
} else if (name == 'Volume') {
|
||||
return getVolume();
|
||||
} else if (name == 'Position') {
|
||||
return getPosition();
|
||||
} else if (name == 'MinimumRate') {
|
||||
return getMinimumRate();
|
||||
} else if (name == 'MaximumRate') {
|
||||
return getMaximumRate();
|
||||
} else if (name == 'CanGoNext') {
|
||||
return getCanGoNext();
|
||||
} else if (name == 'CanGoPrevious') {
|
||||
return getCanGoPrevious();
|
||||
} else if (name == 'CanPlay') {
|
||||
return getCanPlay();
|
||||
} else if (name == 'CanPause') {
|
||||
return getCanPause();
|
||||
} else if (name == 'CanSeek') {
|
||||
return getCanSeek();
|
||||
} else if (name == 'CanControl') {
|
||||
return getCanControl();
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownProperty();
|
||||
}
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownProperty();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DBusMethodResponse> setProperty(
|
||||
String interface, String name, DBusValue value) async {
|
||||
if (interface == 'org.mpris.MediaPlayer2.Player') {
|
||||
if (name == 'PlaybackStatus') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'LoopStatus') {
|
||||
if (value.signature != DBusSignature('s')) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return setLoopStatus((value as DBusString).value);
|
||||
} else if (name == 'Rate') {
|
||||
if (value.signature != DBusSignature('d')) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return setRate((value as DBusDouble).value);
|
||||
} else if (name == 'Shuffle') {
|
||||
if (value.signature != DBusSignature('b')) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return setShuffle((value as DBusBoolean).value);
|
||||
} else if (name == 'Metadata') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'Volume') {
|
||||
if (value.signature != DBusSignature('d')) {
|
||||
return DBusMethodErrorResponse.invalidArgs();
|
||||
}
|
||||
return setVolume((value as DBusDouble).value);
|
||||
} else if (name == 'Position') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'MinimumRate') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'MaximumRate') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'CanGoNext') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'CanGoPrevious') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'CanPlay') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'CanPause') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'CanSeek') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else if (name == 'CanControl') {
|
||||
return DBusMethodErrorResponse.propertyReadOnly();
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownProperty();
|
||||
}
|
||||
} else {
|
||||
return DBusMethodErrorResponse.unknownProperty();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DBusMethodResponse> getAllProperties(String interface) async {
|
||||
var properties = <String, DBusValue>{};
|
||||
if (interface == 'org.mpris.MediaPlayer2.Player') {
|
||||
properties['PlaybackStatus'] =
|
||||
(await getPlaybackStatus()).returnValues[0];
|
||||
properties['LoopStatus'] = (await getLoopStatus()).returnValues[0];
|
||||
properties['Rate'] = (await getRate()).returnValues[0];
|
||||
properties['Shuffle'] = (await getShuffle()).returnValues[0];
|
||||
properties['Metadata'] = (await getMetadata()).returnValues[0];
|
||||
properties['Volume'] = (await getVolume()).returnValues[0];
|
||||
properties['Position'] = (await getPosition()).returnValues[0];
|
||||
properties['MinimumRate'] = (await getMinimumRate()).returnValues[0];
|
||||
properties['MaximumRate'] = (await getMaximumRate()).returnValues[0];
|
||||
properties['CanGoNext'] = (await getCanGoNext()).returnValues[0];
|
||||
properties['CanGoPrevious'] = (await getCanGoPrevious()).returnValues[0];
|
||||
properties['CanPlay'] = (await getCanPlay()).returnValues[0];
|
||||
properties['CanPause'] = (await getCanPause()).returnValues[0];
|
||||
properties['CanSeek'] = (await getCanSeek()).returnValues[0];
|
||||
properties['CanControl'] = (await getCanControl()).returnValues[0];
|
||||
}
|
||||
return DBusMethodSuccessResponse([DBusDict.stringVariant(properties)]);
|
||||
}
|
||||
}
|
||||
|
||||
class LinuxAudioService {
|
||||
_MprisMediaPlayer2 mp2;
|
||||
_MprisMediaPlayer2Player player;
|
||||
|
||||
LinuxAudioService(Ref ref, PlaylistQueueNotifier playlistNotifier)
|
||||
: mp2 = _MprisMediaPlayer2(),
|
||||
player = _MprisMediaPlayer2Player(ref, playlistNotifier);
|
||||
|
||||
void dispose() {
|
||||
mp2.dispose();
|
||||
player.dispose();
|
||||
}
|
||||
}
|
17
pubspec.lock
17
pubspec.lock
@ -209,6 +209,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
base_x:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: base_x
|
||||
sha256: "3f1043679659f1759c651f900da6f24f0a8062c28daa6f9625e8d580002e187b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1065,6 +1073,15 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
mpris_service:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: HEAD
|
||||
resolved-ref: "3a4a72140087d3df130271c9213e61fa413d5740"
|
||||
url: "https://github.com/alexmercerind/mpris_service"
|
||||
source: git
|
||||
version: "1.0.0"
|
||||
mutex:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -24,7 +24,6 @@ dependencies:
|
||||
collection: ^1.15.0
|
||||
cupertino_icons: ^1.0.5
|
||||
curved_navigation_bar: ^1.0.3
|
||||
dbus: ^0.7.8
|
||||
envied: ^0.3.0
|
||||
file_picker: ^5.2.2
|
||||
fl_query: ^1.0.0-alpha.2
|
||||
@ -89,6 +88,9 @@ dependencies:
|
||||
url: https://github.com/KRTirtho/smtc_windows.git
|
||||
ref: 6cc93624b8fab8d7727c8693e91577a7413ccd13
|
||||
path: packages/smtc_windows
|
||||
mpris_service:
|
||||
git:
|
||||
url: https://github.com/alexmercerind/mpris_service
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.3.2
|
||||
|
Loading…
Reference in New Issue
Block a user