diff --git a/yetanotherradio@io.github.buddysirjava/extension.js b/yetanotherradio@io.github.buddysirjava/extension.js
index 8bcee53..5abb2fe 100644
--- a/yetanotherradio@io.github.buddysirjava/extension.js
+++ b/yetanotherradio@io.github.buddysirjava/extension.js
@@ -12,16 +12,17 @@ import { createMetadataItem, updateMetadataDisplay, updatePlaybackStateIcon } fr
import { createVolumeItem, onVolumeChanged } from './modules/volumeControl.js';
import { createScrollableSection, createStationMenuItem, refreshStationsMenu } from './modules/stationMenu.js';
import PlaybackManager from './modules/playbackManager.js';
-import { setupMediaKeys, cleanupMediaKeys } from './modules/mediaKeys.js';
+import MprisInterface from './modules/mprisInterface.js';
const Indicator = GObject.registerClass(
class Indicator extends PanelMenu.Button {
- _init(stations, openPrefs, extensionPath, settings) {
+ _init(stations, openPrefs, extensionPath, settings, onStationsChanged) {
super._init(0.0, _('Yet Another Radio'));
this._stations = stations ?? [];
this._openPrefs = openPrefs;
this._settings = settings;
+ this._onStationsChanged = onStationsChanged;
this._refreshIdleId = 0;
const iconPath = `${extensionPath}/icons/yetanotherradio.svg`;
@@ -125,6 +126,7 @@ const Indicator = GObject.registerClass(
setStations(stations) {
this._stations = stations ?? [];
this._refreshStationsMenu();
+ this._onStationsChanged?.(this._stations.length);
}
_refreshStationsMenu() {
@@ -168,12 +170,24 @@ const Indicator = GObject.registerClass(
this._playbackManager.stop();
}
- handleMediaPlayPause() {
- this._togglePlayback();
+ _orderedStations() {
+ const favorites = this._stations
+ .filter(s => s.favorite)
+ .sort((a, b) => a.name.localeCompare(b.name));
+ const regulars = this._stations.filter(s => !s.favorite);
+ return [...favorites, ...regulars];
}
- handleMediaStop() {
- this._stopPlayback();
+ navigateStation(delta) {
+ if (!this._playbackManager.nowPlaying) return;
+ const ordered = this._orderedStations();
+ if (ordered.length <= 1) return;
+ const currentIdx = ordered.findIndex(
+ s => s.uuid === this._playbackManager.nowPlaying.uuid
+ );
+ if (currentIdx === -1) return;
+ const nextIdx = (currentIdx + delta + ordered.length) % ordered.length;
+ this._playStation(ordered[nextIdx]);
}
destroy() {
@@ -201,7 +215,54 @@ export default class YetAnotherRadioExtension extends Extension {
initTranslations(_);
ensureStorageFile();
this._settings = this.getSettings();
- this._indicator = new Indicator([], () => this.openPreferences(), this.path, this._settings);
+ this._indicator = new Indicator(
+ [],
+ () => this.openPreferences(),
+ this.path,
+ this._settings,
+ (count) => this._mpris?.setStationCount(count)
+ );
+
+ if (this._settings.get_boolean('enable-mpris')) {
+ try {
+ this._mpris = new MprisInterface(
+ this._indicator._playbackManager,
+ this._settings,
+ (delta) => this._indicator.navigateStation(delta),
+ () => this._indicator._stations.slice().sort((a, b) => (b.lastPlayed ?? 0) - (a.lastPlayed ?? 0))[0] ?? null,
+ () => this._indicator.menu.open(true)
+ );
+ this._mpris.setStationCount(this._indicator._stations.length);
+ } catch (error) {
+ console.warn('Failed to initialize MPRIS interface:', error);
+ }
+ }
+
+ this._mprisSettingId = 0;
+ this._mprisSettingId = this._settings.connect('changed::enable-mpris', () => {
+ if (this._settings.get_boolean('enable-mpris')) {
+ if (!this._mpris) {
+ try {
+ this._mpris = new MprisInterface(
+ this._indicator._playbackManager,
+ this._settings,
+ (delta) => this._indicator.navigateStation(delta),
+ () => this._indicator._stations.slice().sort((a, b) => (b.lastPlayed ?? 0) - (a.lastPlayed ?? 0))[0] ?? null,
+ () => this._indicator.menu.open(true)
+ );
+ this._mpris.setStationCount(this._indicator._stations.length);
+ } catch (error) {
+ console.warn('Failed to initialize MPRIS interface:', error);
+ }
+ }
+ } else {
+ if (this._mpris) {
+ this._mpris.destroy();
+ this._mpris = null;
+ }
+ }
+ });
+
Main.panel.addToStatusArea(this.uuid, this._indicator);
loadStations().then(stations => {
@@ -213,7 +274,6 @@ export default class YetAnotherRadioExtension extends Extension {
});
this._monitor = this._watchStationsFile();
- this._setupMediaKeys();
}
_watchStationsFile() {
@@ -229,24 +289,6 @@ export default class YetAnotherRadioExtension extends Extension {
return monitor;
}
- _setupMediaKeys() {
- const { mediaKeyAccelerators, acceleratorHandlerId, mediaKeysSettingsHandlerId } = setupMediaKeys(this._settings, this._indicator);
- this._mediaKeyAccelerators = mediaKeyAccelerators;
- this._acceleratorHandlerId = acceleratorHandlerId;
- this._mediaKeysSettingsHandlerId = mediaKeysSettingsHandlerId;
- this._mediaKeysSettingsHandlerId = this._settings?.connect('changed::enable-media-keys', () => {
- this._cleanupMediaKeys();
- this._setupMediaKeys();
- });
- }
-
- _cleanupMediaKeys() {
- const { mediaKeyAccelerators, acceleratorHandlerId, mediaKeysSettingsHandlerId } = cleanupMediaKeys(this._mediaKeyAccelerators, this._acceleratorHandlerId, this._mediaKeysSettingsHandlerId, this._settings);
- this._mediaKeyAccelerators = mediaKeyAccelerators;
- this._acceleratorHandlerId = acceleratorHandlerId;
- this._mediaKeysSettingsHandlerId = mediaKeysSettingsHandlerId;
- }
-
disable() {
if (this._monitor) {
if (this._monitorHandlerId) {
@@ -257,7 +299,15 @@ export default class YetAnotherRadioExtension extends Extension {
this._monitor = null;
}
- this._cleanupMediaKeys();
+ if (this._mprisSettingId) {
+ this._settings.disconnect(this._mprisSettingId);
+ this._mprisSettingId = 0;
+ }
+
+ if (this._mpris) {
+ this._mpris.destroy();
+ this._mpris = null;
+ }
this._indicator?.destroy();
this._indicator = null;
diff --git a/yetanotherradio@io.github.buddysirjava/modules/mediaKeys.js b/yetanotherradio@io.github.buddysirjava/modules/mediaKeys.js
deleted file mode 100644
index a022f51..0000000
--- a/yetanotherradio@io.github.buddysirjava/modules/mediaKeys.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import Meta from 'gi://Meta';
-
-export function setupMediaKeys(settings, indicator) {
- const enableMediaKeys = settings?.get_boolean('enable-media-keys') ?? true;
- if (!enableMediaKeys) {
- return { mediaKeyAccelerators: [], acceleratorHandlerId: null, mediaKeysSettingsHandlerId: null };
- }
-
- const display = global.display;
- const mediaKeyAccelerators = [];
-
- const playPauseId = display.grab_accelerator('XF86AudioPlay', Meta.KeyBindingFlags.NONE);
- if (playPauseId > 0) {
- mediaKeyAccelerators.push({
- id: playPauseId,
- action: 'play-pause'
- });
- }
-
- const stopId = display.grab_accelerator('XF86AudioStop', Meta.KeyBindingFlags.NONE);
- if (stopId > 0) {
- mediaKeyAccelerators.push({
- id: stopId,
- action: 'stop'
- });
- }
-
- const acceleratorHandlerId = global.display.connect('accelerator-activated', (display, action, deviceId, timestamp) => {
- const accelerator = mediaKeyAccelerators.find(acc => acc.id === action);
- if (!accelerator || !indicator) {
- return;
- }
-
- if (accelerator.action === 'play-pause') {
- indicator.handleMediaPlayPause();
- } else if (accelerator.action === 'stop') {
- indicator.handleMediaStop();
- }
- });
-
- return { mediaKeyAccelerators, acceleratorHandlerId, mediaKeysSettingsHandlerId: null };
-}
-
-export function cleanupMediaKeys(mediaKeyAccelerators, acceleratorHandlerId, mediaKeysSettingsHandlerId, settings) {
- if (acceleratorHandlerId) {
- global.display.disconnect(acceleratorHandlerId);
- acceleratorHandlerId = null;
- }
-
- if (mediaKeyAccelerators) {
- const display = global.display;
- mediaKeyAccelerators.forEach(acc => {
- try {
- display.ungrab_accelerator(acc.id);
- } catch (e) {
- console.debug(e);
- }
- });
- }
-
- if (mediaKeysSettingsHandlerId) {
- settings?.disconnect(mediaKeysSettingsHandlerId);
- mediaKeysSettingsHandlerId = null;
- }
-
- return { mediaKeyAccelerators: [], acceleratorHandlerId, mediaKeysSettingsHandlerId };
-}
diff --git a/yetanotherradio@io.github.buddysirjava/modules/mprisInterface.js b/yetanotherradio@io.github.buddysirjava/modules/mprisInterface.js
new file mode 100644
index 0000000..5641b02
--- /dev/null
+++ b/yetanotherradio@io.github.buddysirjava/modules/mprisInterface.js
@@ -0,0 +1,275 @@
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+
+const MPRIS_SERVICE_NAME = 'org.mpris.MediaPlayer2.yetanotherradio';
+const MPRIS_OBJECT_PATH = '/org/mpris/MediaPlayer2';
+
+const MPRIS_ROOT_XML = `
+
+
+
+
+
+
+
+`;
+
+const MPRIS_PLAYER_XML = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+export default class MprisInterface {
+ constructor(playbackManager, settings, navigateCallback, lastStationCallback, raiseCallback) {
+ this._playbackManager = playbackManager;
+ this._settings = settings;
+ this._navigateCallback = navigateCallback ?? null;
+ this._lastStationCallback = lastStationCallback ?? null;
+ this._raiseCallback = raiseCallback ?? null;
+ this._stationCount = 0;
+ this._dbusConnection = null;
+ this._rootExported = null;
+ this._playerExported = null;
+ this._ownerId = 0;
+ this._settingsChangedId = 0;
+
+ this._setupCallbacks();
+ this._setupSettingsMonitoring();
+ this._register();
+ }
+
+ _setupCallbacks() {
+ if (!this._playbackManager) return;
+
+ this._onState = () => this._emitPlayerPropertiesChanged(['PlaybackStatus', 'CanPlay', 'CanPause']);
+ this._onMeta = () => this._emitPlayerPropertiesChanged(['Metadata']);
+ this._onStation = () => this._emitPlayerPropertiesChanged(['Metadata', 'CanPlay', 'CanPause', 'CanGoNext', 'CanGoPrevious']);
+
+ this._playbackManager.addListener('onStateChanged', this._onState);
+ this._playbackManager.addListener('onMetadataUpdate', this._onMeta);
+ this._playbackManager.addListener('onStationChanged', this._onStation);
+ }
+
+ _setupSettingsMonitoring() {
+ if (this._settings) {
+ this._settingsChangedId = this._settings.connect('changed::volume', () => {
+ this._emitPlayerPropertiesChanged(['Volume']);
+ });
+ }
+ }
+
+ _register() {
+ try {
+ this._dbusConnection = Gio.bus_get_sync(Gio.BusType.SESSION, null);
+
+ const self = this;
+
+ this._rootExported = Gio.DBusExportedObject.wrapJSObject(
+ MPRIS_ROOT_XML,
+ {
+ Raise() { self._raiseCallback?.(); },
+ get Identity() { return 'Yet Another Radio'; },
+ get CanQuit() { return false; },
+ get CanRaise() { return true; },
+ get HasTrackList() { return false; },
+ }
+ );
+
+ this._playerExported = Gio.DBusExportedObject.wrapJSObject(
+ MPRIS_PLAYER_XML,
+ {
+ Play() {
+ const m = self._playbackManager;
+ if (!m) return;
+ const target = m.nowPlaying ?? self._lastStationCallback?.();
+ if (target) m.play(target);
+ },
+ Pause() { const m = self._playbackManager; if (m?.playbackState === 'playing') m.toggle(); },
+ PlayPause() {
+ const m = self._playbackManager;
+ if (!m) return;
+ if (m.playbackState === 'stopped') {
+ const target = m.nowPlaying ?? self._lastStationCallback?.();
+ if (target) m.play(target);
+ } else {
+ m.toggle();
+ }
+ },
+ Stop() { self._playbackManager?.stop(); },
+ Next() { self._navigateCallback?.(+1); },
+ Previous() { self._navigateCallback?.(-1); },
+ get PlaybackStatus() { return self._getPlaybackStatus(); },
+ get Metadata() { return self._getMetadata(); },
+ get Volume() { return self._getVolume(); },
+ set Volume(v) {
+ const vol = Math.max(0.0, Math.min(1.0, v));
+ self._playbackManager?.setVolume(vol);
+ self._settings?.set_int('volume', Math.round(vol * 100));
+ },
+ get CanPlay() { return !!self._playbackManager?.nowPlaying; },
+ get CanPause() { return !!self._playbackManager?.nowPlaying && self._getPlaybackStatus() !== 'Stopped'; },
+ get CanControl() { return true; },
+ get CanGoNext() { return self._canNavigate(); },
+ get CanGoPrevious() { return self._canNavigate(); },
+ }
+ );
+
+ this._rootExported.export(this._dbusConnection, MPRIS_OBJECT_PATH);
+ this._playerExported.export(this._dbusConnection, MPRIS_OBJECT_PATH);
+
+ this._ownerId = Gio.bus_own_name_on_connection(
+ this._dbusConnection,
+ MPRIS_SERVICE_NAME,
+ Gio.BusNameOwnerFlags.NONE,
+ null,
+ null
+ );
+
+ if (this._ownerId === 0) {
+ console.error('MPRIS: Failed to acquire bus name');
+ this._cleanup();
+ return;
+ }
+
+ console.log('MPRIS: Service registered successfully');
+ this._emitPlayerPropertiesChanged(['PlaybackStatus', 'Metadata', 'CanPlay', 'CanPause', 'Volume']);
+ } catch (error) {
+ console.error('MPRIS: Registration failed:', error);
+ this._cleanup();
+ }
+ }
+
+ _getPlaybackStatus() {
+ if (!this._playbackManager) return 'Stopped';
+ switch (this._playbackManager.playbackState) {
+ case 'playing': return 'Playing';
+ case 'paused': return 'Paused';
+ default: return 'Stopped';
+ }
+ }
+
+ _getMetadata() {
+ if (this._playbackManager) {
+ const metadata = this._playbackManager.getMPRISMetadata();
+ if (!metadata['mpris:trackid']) {
+ metadata['mpris:trackid'] = new GLib.Variant('o', '/org/mpris/MediaPlayer2/NoTrack');
+ }
+ return metadata;
+ }
+
+ return {
+ 'xesam:title': new GLib.Variant('s', 'Yet Another Radio'),
+ };
+ }
+
+ _getVolume() {
+ if (!this._settings) return 1.0;
+ return Math.max(0.0, Math.min(1.0, this._settings.get_int('volume') / 100.0));
+ }
+
+ _canNavigate() {
+ if (!this._playbackManager?.nowPlaying) return false;
+ return this._stationCount > 1;
+ }
+
+ setStationCount(count) {
+ this._stationCount = count;
+ this._emitPlayerPropertiesChanged(['CanGoNext', 'CanGoPrevious']);
+ }
+
+ _emitPropertiesChanged(interfaceName, changedProps) {
+ if (!this._dbusConnection) return;
+
+ try {
+ this._dbusConnection.emit_signal(
+ null,
+ MPRIS_OBJECT_PATH,
+ 'org.freedesktop.DBus.Properties',
+ 'PropertiesChanged',
+ GLib.Variant.new_tuple([
+ new GLib.Variant('s', interfaceName),
+ new GLib.Variant('a{sv}', changedProps),
+ new GLib.Variant('as', [])
+ ])
+ );
+ } catch (error) {
+ console.error('MPRIS: Failed to emit PropertiesChanged:', error);
+ }
+ }
+
+ _emitPlayerPropertiesChanged(propertyNames) {
+ const getters = {
+ PlaybackStatus: () => new GLib.Variant('s', this._getPlaybackStatus()),
+ Metadata: () => new GLib.Variant('a{sv}', this._getMetadata()),
+ Volume: () => new GLib.Variant('d', this._getVolume()),
+ CanPlay: () => new GLib.Variant('b', !!this._playbackManager?.nowPlaying),
+ CanPause: () => new GLib.Variant('b', !!this._playbackManager?.nowPlaying && this._getPlaybackStatus() !== 'Stopped'),
+ CanGoNext: () => new GLib.Variant('b', this._canNavigate()),
+ CanGoPrevious: () => new GLib.Variant('b', this._canNavigate()),
+ };
+
+ const changed = {};
+ for (const name of propertyNames) {
+ if (getters[name]) changed[name] = getters[name]();
+ }
+
+ if (Object.keys(changed).length > 0) {
+ this._emitPropertiesChanged('org.mpris.MediaPlayer2.Player', changed);
+ }
+ }
+
+ _cleanup() {
+ if (this._playbackManager) {
+ this._playbackManager.removeListener('onStateChanged', this._onState);
+ this._playbackManager.removeListener('onMetadataUpdate', this._onMeta);
+ this._playbackManager.removeListener('onStationChanged', this._onStation);
+ }
+ this._onState = null;
+ this._onMeta = null;
+ this._onStation = null;
+
+ if (this._settingsChangedId !== 0) {
+ if (this._settings) {
+ this._settings.disconnect(this._settingsChangedId);
+ }
+ this._settingsChangedId = 0;
+ }
+
+ if (this._ownerId !== 0) {
+ Gio.bus_unown_name(this._ownerId);
+ this._ownerId = 0;
+ }
+
+ if (this._rootExported) {
+ this._rootExported.unexport();
+ this._rootExported = null;
+ }
+
+ if (this._playerExported) {
+ this._playerExported.unexport();
+ this._playerExported = null;
+ }
+
+ this._dbusConnection = null;
+ }
+
+ destroy() {
+ this._cleanup();
+ this._playbackManager = null;
+ this._settings = null;
+ }
+}
diff --git a/yetanotherradio@io.github.buddysirjava/modules/playbackManager.js b/yetanotherradio@io.github.buddysirjava/modules/playbackManager.js
index 911da2d..d7931a8 100644
--- a/yetanotherradio@io.github.buddysirjava/modules/playbackManager.js
+++ b/yetanotherradio@io.github.buddysirjava/modules/playbackManager.js
@@ -16,6 +16,7 @@ export default class PlaybackManager {
constructor(settings, callbacks, osdIcon = null) {
this._settings = settings;
this._callbacks = callbacks || {};
+ this._listeners = {};
this._osdIcon = osdIcon;
this._player = null;
@@ -39,6 +40,23 @@ export default class PlaybackManager {
};
}
+ addListener(event, fn) {
+ (this._listeners[event] ||= []).push(fn);
+ }
+
+ removeListener(event, fn) {
+ const list = this._listeners[event];
+ if (list) {
+ const idx = list.indexOf(fn);
+ if (idx !== -1) list.splice(idx, 1);
+ }
+ }
+
+ _emit(event, ...args) {
+ this._callbacks[event]?.(...args);
+ (this._listeners[event] || []).forEach(fn => fn(...args));
+ }
+
_initGst() {
if (!Gst.is_initialized()) {
Gst.init(null);
@@ -57,6 +75,27 @@ export default class PlaybackManager {
return this._nowPlaying;
}
+ getMPRISMetadata() {
+ const metadata = {};
+
+ if (this._currentMetadata.title) {
+ metadata['xesam:title'] = new GLib.Variant('s', this._currentMetadata.title);
+ }
+ if (this._currentMetadata.artist) {
+ metadata['xesam:artist'] = new GLib.Variant('as', [this._currentMetadata.artist]);
+ }
+
+ let artUrl = this._currentMetadata.albumArt || this._nowPlaying?.favicon || null;
+ if (artUrl) {
+ if (artUrl.startsWith('/')) {
+ artUrl = 'file://' + artUrl;
+ }
+ metadata['mpris:artUrl'] = new GLib.Variant('s', artUrl);
+ }
+
+ return metadata;
+ }
+
_ensurePlayer() {
if (this._player) return;
@@ -88,9 +127,7 @@ export default class PlaybackManager {
if (metadata.albumArt) this._currentMetadata.albumArt = metadata.albumArt;
if (metadata.bitrate) this._currentMetadata.bitrate = metadata.bitrate;
- if (this._callbacks.onMetadataUpdate) {
- this._callbacks.onMetadataUpdate();
- }
+ this._emit('onMetadataUpdate');
}
} else if (message.type === Gst.MessageType.ERROR) {
const [error, debug] = message.parse_error();
@@ -159,9 +196,9 @@ export default class PlaybackManager {
this._currentMetadata.nowPlaying = station;
this._currentMetadata.playbackState = 'playing';
- if (this._callbacks.onStateChanged) this._callbacks.onStateChanged('playing');
- if (this._callbacks.onStationChanged) this._callbacks.onStationChanged(station);
- if (this._callbacks.onVisibilityChanged) this._callbacks.onVisibilityChanged(true);
+ this._emit('onStateChanged', 'playing');
+ this._emit('onStationChanged', station);
+ this._emit('onVisibilityChanged', true);
this._startMetadataUpdate();
@@ -209,7 +246,7 @@ export default class PlaybackManager {
this._pausedAt = Date.now();
this._currentMetadata.playbackState = 'paused';
- if (this._callbacks.onStateChanged) this._callbacks.onStateChanged('paused');
+ this._emit('onStateChanged', 'paused');
} else if (this._playbackState === 'paused') {
const pauseDuration = this._pausedAt ? Date.now() - this._pausedAt : 0;
@@ -222,7 +259,7 @@ export default class PlaybackManager {
this._playbackState = 'playing';
this._currentMetadata.playbackState = 'playing';
- if (this._callbacks.onStateChanged) this._callbacks.onStateChanged('playing');
+ this._emit('onStateChanged', 'playing');
}
this._pausedAt = null;
}
@@ -246,9 +283,9 @@ export default class PlaybackManager {
this._stopMetadataUpdate();
- if (this._callbacks.onStateChanged) this._callbacks.onStateChanged('stopped');
- if (this._callbacks.onStationChanged) this._callbacks.onStationChanged(null);
- if (this._callbacks.onVisibilityChanged) this._callbacks.onVisibilityChanged(false);
+ this._emit('onStateChanged', 'stopped');
+ this._emit('onStationChanged', null);
+ this._emit('onVisibilityChanged', false);
}
setVolume(volume) {
@@ -265,9 +302,7 @@ export default class PlaybackManager {
interval,
() => {
queryPlayerTags(this._player, this._currentMetadata);
- if (this._callbacks.onMetadataUpdate) {
- this._callbacks.onMetadataUpdate();
- }
+ this._emit('onMetadataUpdate');
return true;
}
);
diff --git a/yetanotherradio@io.github.buddysirjava/prefs.js b/yetanotherradio@io.github.buddysirjava/prefs.js
index aaf8cca..68df683 100644
--- a/yetanotherradio@io.github.buddysirjava/prefs.js
+++ b/yetanotherradio@io.github.buddysirjava/prefs.js
@@ -712,22 +712,6 @@ const GeneralSettingsPage = GObject.registerClass(
});
this.add(generalGroup);
- const mediaKeysRow = new Adw.ActionRow({
- title: _('Enable Media Keys'),
- subtitle: _('Use keyboard media keys (Play/Pause, Stop) to control playback'),
- });
- mediaKeysRow.set_activatable(false);
-
- const mediaKeysSwitch = new Gtk.Switch({
- active: this._settings.get_boolean('enable-media-keys'),
- valign: 3,
- });
- mediaKeysSwitch.connect('notify::active', (sw) => {
- this._settings.set_boolean('enable-media-keys', sw.active);
- });
- mediaKeysRow.add_suffix(mediaKeysSwitch);
- generalGroup.add(mediaKeysRow);
-
const playingNotificationRow = new Adw.ActionRow({
title: _('Show Playing Notification'),
subtitle: _('Show an on-screen notification when starting playback'),
@@ -760,6 +744,22 @@ const GeneralSettingsPage = GObject.registerClass(
autoPlayRow.add_suffix(autoPlaySwitch);
generalGroup.add(autoPlayRow);
+ const mprisRow = new Adw.ActionRow({
+ title: _('MPRIS Integration'),
+ subtitle: _('Expose the player over D-Bus so media keys and system controls work'),
+ });
+ mprisRow.set_activatable(false);
+
+ const mprisSwitch = new Gtk.Switch({
+ active: this._settings.get_boolean('enable-mpris'),
+ valign: 3,
+ });
+ mprisSwitch.connect('notify::active', (sw) => {
+ this._settings.set_boolean('enable-mpris', sw.active);
+ });
+ mprisRow.add_suffix(mprisSwitch);
+ generalGroup.add(mprisRow);
+
const importExportGroup = new Adw.PreferencesGroup({
title: _('Import / Export'),
description: _('Backup or restore your station list.'),
diff --git a/yetanotherradio@io.github.buddysirjava/schemas/gschemas.compiled b/yetanotherradio@io.github.buddysirjava/schemas/gschemas.compiled
index 5ca108d..0036f5d 100644
Binary files a/yetanotherradio@io.github.buddysirjava/schemas/gschemas.compiled and b/yetanotherradio@io.github.buddysirjava/schemas/gschemas.compiled differ
diff --git a/yetanotherradio@io.github.buddysirjava/schemas/org.gnome.shell.extensions.yetanotherradio.gschema.xml b/yetanotherradio@io.github.buddysirjava/schemas/org.gnome.shell.extensions.yetanotherradio.gschema.xml
index de5fce7..a6ba3e3 100644
--- a/yetanotherradio@io.github.buddysirjava/schemas/org.gnome.shell.extensions.yetanotherradio.gschema.xml
+++ b/yetanotherradio@io.github.buddysirjava/schemas/org.gnome.shell.extensions.yetanotherradio.gschema.xml
@@ -27,18 +27,17 @@
Auto-play last station
Automatically play the last played station when the extension is enabled
-
-
- true
- Enable media keys
- Enable global keyboard media keys (Play/Pause, Stop) to control playback
-
-
true
Show playing notification
Show an on-screen notification when starting radio playback
+
+
+ true
+ Enable MPRIS integration
+ Expose the player over D-Bus via the MPRIS2 protocol
+
100