From 985103793dcf304464c37271cd6606943e4ec073 Mon Sep 17 00:00:00 2001 From: Sakith Banmitha Date: Fri, 27 Aug 2021 21:15:14 +0530 Subject: [PATCH 1/2] Updated README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index a8113e6..5fd4e65 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,15 @@ Show controls and information of the currently playing media in the panel - Shows the media player icon if possible - Show controls for the media +--- + +## Notes + +- Currently font awesome needs to be installed in the system for the icons to show up. +- There will be small performance issues, a fix for this will be put up soon + +--- + ## Screenshots ![Screenshot](screenshot.png) From c9054b0f0e19af78f20e2982c861be6815fcc23b Mon Sep 17 00:00:00 2001 From: Sakith Banmitha Date: Fri, 27 Aug 2021 23:54:02 +0530 Subject: [PATCH 2/2] "Fixed lagging issue - Used GLib.DBus instead of dbus-send" --- dbus.js | 141 +++++++++++++++++++++++++++++++++++++ extension.js | 191 ++++++++++++++++++++++----------------------------- 2 files changed, 225 insertions(+), 107 deletions(-) create mode 100644 dbus.js diff --git a/dbus.js b/dbus.js new file mode 100644 index 0000000..697fdac --- /dev/null +++ b/dbus.js @@ -0,0 +1,141 @@ +const { Gio, GLib } = imports.gi; + +// Toggle pause +// dbus-send --print-reply --dest=${currentPlayer} /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause + +// Next +// dbus-send --print-reply --dest=${currentPlayer} /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Next + +// Previous +// dbus-send --print-reply --dest=${currentPlayer} /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Previous + +// List names +// dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames + +// Player state +// dbus-send --print-reply --dest=${player} /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' string:'PlaybackStatus' + +// Metadata +// dbus-send --print-reply --dest=${player} /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' string:'Metadata' + +let connection = Gio.DBus.session; + +const playbackAction = (action, player) => { + return new Promise((resolve, reject) => { + connection.call( + player, + "/org/mpris/MediaPlayer2", + "org.mpris.MediaPlayer2.Player", + action, + null, + null, + Gio.DBusCallFlags.NONE, + -1, + null, + (connection, res) => { + try { + connection.call_finish(res); + resolve(); + } catch (e) { + reject(e); + } + } + ); + }); +}; + +const getPlayers = () => { + return new Promise((resolve, reject) => { + connection.call( + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "ListNames", + null, + null, + Gio.DBusCallFlags.NONE, + -1, + null, + (connection, res) => { + try { + let rawReply = connection + .call_finish(res) + .get_child_value(0); + let services = rawReply.deepUnpack(); + players = services.filter((service) => { + if (service.includes("org.mpris.MediaPlayer2")) { + return true; + } + }); + resolve(players); + } catch (e) { + reject(e); + } + } + ); + }); +}; + +const getMetadata = (player) => { + log("Getting metadata"); + return new Promise((resolve, reject) => { + connection.call( + player, + "/org/mpris/MediaPlayer2", + "org.freedesktop.DBus.Properties", + "Get", + new GLib.Variant("(ss)", [ + "org.mpris.MediaPlayer2.Player", + "Metadata", + ]), + null, + Gio.DBusCallFlags.NONE, + -1, + null, + (connection, res) => { + try { + let metaData = connection + .call_finish(res) + .recursiveUnpack()[0]; + let title = metaData["xesam:title"]; + let artist = metaData["xesam:artist"]; + log("Got metadata"); + resolve([title, artist]); + } catch (e) { + reject(e); + } + } + ); + }); +}; + +const getPlaybackStatus = (player) => { + log("Getting playback status"); + return new Promise((resolve, reject) => { + connection.call( + player, + "/org/mpris/MediaPlayer2", + "org.freedesktop.DBus.Properties", + "Get", + new GLib.Variant("(ss)", [ + "org.mpris.MediaPlayer2.Player", + "PlaybackStatus", + ]), + null, + Gio.DBusCallFlags.NONE, + -1, + null, + (connection, res) => { + try { + let playbackStatus = connection + .call_finish(res) + .recursiveUnpack()[0]; + log("Getting metadata"); + resolve(playbackStatus); + } catch (e) { + reject(e); + } + } + ); + }); +}; diff --git a/extension.js b/extension.js index 7eae90f..0495ddf 100644 --- a/extension.js +++ b/extension.js @@ -5,6 +5,8 @@ const Main = imports.ui.main; const Mainloop = imports.mainloop; const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); +const { getMetadata, getPlayers, getPlaybackStatus, playbackAction } = + Me.imports.dbus; // User-defined settings @@ -12,7 +14,7 @@ let maxDisplayLength, updateDelay; // Global variables -let currentPlayer, playerIcon, playersList, playerState, displayText; +let currentPlayer, playerIcon, playerState, displayText; let onUpdateDelayChanged, onMaxLengthChanged; let mainLoop; let settings; @@ -30,7 +32,7 @@ let lastPlayer, const playerIcons = { default: "", - chrome: "", + chrom: "", firefox: "", spotify: "", }; @@ -56,21 +58,15 @@ const _playerToggle = () => { buttonToggle.set_child(iconPlay); playerState = "Playing"; } - execCmd( - `dbus-send --print-reply --dest=${currentPlayer} /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause` - ); + playbackAction("PlayPause", currentPlayer); }; const _playerNext = () => { - execCmd( - `dbus-send --print-reply --dest=${currentPlayer} /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Next` - ); + playbackAction("Next", currentPlayer); }; const _playerPrev = () => { - execCmd( - `dbus-send --print-reply --dest=${currentPlayer} /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Previous` - ); + playbackAction("Previous", currentPlayer); }; // Housekeeping methods @@ -91,40 +87,16 @@ const removeContent = () => { // Utility methods -const execCmd = (cmd) => { - const [ok, out, err, code] = GLib.spawn_command_line_sync( - `/bin/bash -c "${cmd}"` - ); - if (ok) { - return out.toString().trim(); - } else { - throw new Error("Error while executing command.", err); - } -}; - -// Main utility methods - -const updatePlayers = () => { - // log("Updating players..."); - const rawPlayersList = execCmd( - "dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames" - ); - playersList = rawPlayersList.match(/\"org\.mpris\.MediaPlayer2.*\"/g); - - if (playersList !== null) { - playersList = playersList.map((player) => player.replaceAll('"', "")); - } else { - playersList = []; - } - // log(`${playersList.length} players found!`); -}; - const updateData = (player, _playerState, _title, _artist) => { if (lastPlayer !== player) { currentPlayer = player; - playerIcon = - playerIcons[player.replace("org.mpris.MediaPlayer2.", "")] || - playerIcons["default"]; + playerIcon = playerIcons["default"]; + for ([key, value] of Object.entries(playerIcons)) { + if (player.includes(key)) { + playerIcon = playerIcons[key]; + break; + } + } } if (lastState !== _playerState) { playerState = _playerState; @@ -140,74 +112,79 @@ const updateData = (player, _playerState, _title, _artist) => { } }; -const updatePlayer = () => { - // log("Determining current player"); - if (playersList.length > 0) { - let playerStateMap = []; - let playerDataMap = {}; - for (let i = 0; i <= playersList.length; i++) { - player = playersList[i]; - - _playerState = execCmd( - `dbus-send --print-reply --dest=${player} /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' string:'PlaybackStatus'|egrep -A 1 \\"string\\"|cut -b 26-|cut -d '\\"' -f 1|egrep -v ^$` - ); - - _title = execCmd( - `dbus-send --print-reply --dest=${player} /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' string:'Metadata'|egrep -A 1 \\"title\\"|egrep -v \\"title\\"|cut -b 44-|cut -d '\\"' -f 1|egrep -v ^$` - ); - - _artist = execCmd( - `dbus-send --print-reply --dest=${player} /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' string:'Metadata'|egrep -A 2 \\"artist\\"|egrep -v \\"artist\\"|egrep -v \\"array\\"|cut -b 27-|cut -d '\\"' -f 1|egrep -v ^$` - ); - - if (_title && _artist) { - playerStateMap.push([player, _playerState]); - playerDataMap[player] = { - _title, - _artist, - _playerState, - }; - } - } - // log(`${playerStateMap.length} eligible players found!`); - let playingPlayers = playerStateMap.filter(([player, state]) => { - if (state === "Playing") { - return true; +const updatePlayer = async () => { + try { + // log("Determining current player"); + playersList = await getPlayers(); + if (playersList.length > 0) { + let playerStateMap = []; + let playerDataMap = {}; + // log("Starting for loop"); + // log(`Player list - ${playersList}`); + for (let i = 0; i <= playersList.length; i++) { + player = playersList[i]; + if (player) { + _playerStatePromise = getPlaybackStatus(player); + _metadataPromise = getMetadata(player); + // log("Resolving promises"); + [_playerState, [_title, _artist]] = await Promise.all([ + _playerStatePromise, + _metadataPromise, + ]); + // log("Promises resolved"); + if (_title && _artist) { + playerStateMap.push([player, _playerState]); + playerDataMap[player] = { + _title, + _artist, + _playerState, + }; + } + } } - return false; - }); - // log(`${playingPlayers.length} playing players found!`); - if (playingPlayers.length > 0) { - if (contentRemoved) { - addContent(); - contentRemoved = false; - } - player = playingPlayers[0][0]; - updateData( - player, - playerDataMap[player]._playerState, - playerDataMap[player]._title, - playerDataMap[player]._artist - ); - } else if (playerStateMap.length > 0) { - if (contentRemoved) { - addContent(); - contentRemoved = false; + + // log(`${playerStateMap.length} eligible players found!`); + let playingPlayers = playerStateMap.filter(([player, state]) => { + if (state === "Playing") { + return true; + } + return false; + }); + // log(`${playingPlayers.length} playing players found!`); + if (playingPlayers.length > 0) { + if (contentRemoved) { + addContent(); + contentRemoved = false; + } + player = playingPlayers[0][0]; + updateData( + player, + playerDataMap[player]._playerState, + playerDataMap[player]._title, + playerDataMap[player]._artist + ); + } else if (playerStateMap.length > 0) { + if (contentRemoved) { + addContent(); + contentRemoved = false; + } + player = playerStateMap[0][0]; + updateData( + player, + playerDataMap[player]._playerState, + playerDataMap[player]._title, + playerDataMap[player]._artist + ); + } else { + removeContent(); + contentRemoved = true; } - player = playerStateMap[0][0]; - updateData( - player, - playerDataMap[player]._playerState, - playerDataMap[player]._title, - playerDataMap[player]._artist - ); } else { removeContent(); contentRemoved = true; } - } else { - removeContent(); - contentRemoved = true; + } catch (e) { + // logError(e); } }; @@ -309,9 +286,9 @@ const enable = () => { // Start the main loop mainLoop = Mainloop.timeout_add(updateDelay, () => { - updatePlayers(); - updatePlayer(); - updateContent(); + updatePlayer().then(() => { + updateContent(); + }); return true; }); };