bouncy/mpris.js

124 lines
3.0 KiB
JavaScript

const dbus = require('dbus-next');
const { info } = require('./render');
const playerName = process.env.BOUNCY_MUSICPLAYER || 'org.mpris.MediaPlayer2.rhythmbox';
const MPRIS_IFACE = 'org.mpris.MediaPlayer2.Player';
const MPRIS_PATH = '/org/mpris/MediaPlayer2';
const PROPERTIES_IFACE = 'org.freedesktop.DBus.Properties';
let artist = '';
let title = '';
let album = '';
let songStart; // timestamps
let songEnd;
let songPauseSpot;
let songPaused;
let infoFunc;
let warningFunc;
let errorFunc;
let lastStatus = '';
async function updateMetadata(metadata, props) {
try {
let artistVariant = metadata.value['xesam:artist'];
let titleVariant = metadata.value['xesam:title'];
artist = artistVariant ? artistVariant.value[0] : 'unknown';
title = titleVariant ? titleVariant.value : 'unknown';
let durationVariant = metadata.value['mpris:length'];
let duration = durationVariant ? durationVariant.value : 0n;
let position = (await props.Get(MPRIS_IFACE, 'Position')).value;
songStart = Date.now() - Number(position / 1000n);
songEnd = songStart + Number(duration / 1000n);
if (metadata.value['xesam:album'] && metadata.value['xesam:album'] !== 'Unknown') {
album = metadata.value['xesam:album'].value;
} else {
album = null;
}
songPaused = (await props.Get(MPRIS_IFACE, 'PlaybackStatus')).value === 'Paused';
if (songPaused) songPauseSpot = Date.now();
} catch(err) {
errorFunc(err.message);
}
}
async function setupProps(props) {
let metadata = await props.Get(MPRIS_IFACE, 'Metadata');
updateMetadata(metadata, props);
props.on('PropertiesChanged', (iface, changed) => {
if (changed.hasOwnProperty('PlaybackStatus')) {
let status = changed['PlaybackStatus'];
if (lastStatus !== status.value) {
lastStatus = status.value;
info(status.value);
updateMetadata(metadata, props);
}
}
if (changed.hasOwnProperty('Metadata')) {
metadata = changed['Metadata'];
updateMetadata(metadata, props);
}
});
}
async function setup() {
try {
let bus = dbus.sessionBus();
let obj = await bus.getProxyObject(playerName, MPRIS_PATH);
let props = obj.getInterface(PROPERTIES_IFACE);
setupProps(props);
infoFunc('connected to mpris')
} catch(err) {
errorFunc(err.message);
setTimeout(setup, 5000);
}
}
function init(e, w, i) {
errorFunc = e;
warningFunc = w;
infoFunc = i;
setup();
}
function getArtist() {
return artist;
}
function getTitle() {
return title;
}
function getAlbum() {
return album;
}
function getSongStart() {
return songStart;
}
function getSongEnd() {
return songEnd;
}
function getSongPauseSpot() {
return songPauseSpot;
}
function getSongPaused() {
return songPaused;
}
module.exports.init = init;
module.exports.getArtist = getArtist;
module.exports.getTitle = getTitle;
module.exports.getAlbum = getAlbum;
module.exports.getSongStart = getSongStart;
module.exports.getSongEnd = getSongEnd;
module.exports.getSongPauseSpot = getSongPauseSpot;
module.exports.getSongPaused = getSongPaused;