187 lines
5.8 KiB
QML
187 lines
5.8 KiB
QML
/**
|
|
Credits: https://github.com/ccatterina/plasmusic-toolbar
|
|
|
|
looked handy, ty
|
|
*/
|
|
|
|
import QtQml.Models
|
|
import QtQuick
|
|
import org.kde.plasma.private.mpris as Mpris
|
|
|
|
QtObject {
|
|
id: root
|
|
|
|
readonly property int containerRole: Qt.UserRole + 1
|
|
property string sourceName: "any"
|
|
property string sourcePriority: ""
|
|
property bool sourceWhitelist: false
|
|
property var mpris2Model
|
|
property int modelRevision: 0
|
|
readonly property var normalizedSourcePriority: parseSourcePriority(sourcePriority)
|
|
readonly property var resolvedPlayer: resolvePlayer()
|
|
readonly property bool ready: {
|
|
if (!resolvedPlayer)
|
|
return false;
|
|
|
|
return sourceName === "any" || entriesMatch(resolvedPlayer.desktopEntry, sourceName);
|
|
}
|
|
readonly property string artists: ready ? resolvedPlayer.artist : ""
|
|
readonly property string title: ready ? resolvedPlayer.track : ""
|
|
readonly property int playbackStatus: ready ? resolvedPlayer.playbackStatus : Mpris.PlaybackStatus.Unknown
|
|
readonly property int shuffle: ready ? resolvedPlayer.shuffle : Mpris.ShuffleStatus.Unknown
|
|
readonly property string artUrl: ready ? resolvedPlayer.artUrl : ""
|
|
readonly property int loopStatus: ready ? resolvedPlayer.loopStatus : Mpris.LoopStatus.Unknown
|
|
readonly property double songPosition: ready ? resolvedPlayer.position : 0
|
|
readonly property double songLength: ready ? resolvedPlayer.length : 0
|
|
readonly property real volume: ready ? resolvedPlayer.volume : 0
|
|
readonly property string identity: ready ? resolvedPlayer.identity : ""
|
|
readonly property bool canGoNext: ready ? resolvedPlayer.canGoNext : false
|
|
readonly property bool canGoPrevious: ready ? resolvedPlayer.canGoPrevious : false
|
|
readonly property bool canPlay: ready ? resolvedPlayer.canPlay : false
|
|
readonly property bool canPause: ready ? resolvedPlayer.canPause : false
|
|
readonly property bool canSeek: ready ? resolvedPlayer.canSeek : false
|
|
readonly property bool canRaise: ready ? resolvedPlayer.canRaise : false
|
|
// To know whether Shuffle and Loop can be changed we have to check if the property is defined,
|
|
// unlike the other commands, LoopStatus and Shuffle do not have specific properties such as
|
|
// CanPause, CanSeek, etc.
|
|
readonly property bool canChangeShuffle: ready ? resolvedPlayer.shuffle !== undefined : false
|
|
readonly property bool canChangeLoopStatus: ready ? resolvedPlayer.loopStatus !== undefined : false
|
|
|
|
function normalizedEntry(value) {
|
|
return (value || "").toString().trim().toLowerCase();
|
|
}
|
|
|
|
function entriesMatch(left, right) {
|
|
const normalizedLeft = normalizedEntry(left);
|
|
const normalizedRight = normalizedEntry(right);
|
|
if (!normalizedLeft || !normalizedRight)
|
|
return false;
|
|
|
|
return normalizedLeft === normalizedRight;
|
|
}
|
|
|
|
function parseSourcePriority(value) {
|
|
return (value || "").split(",").map((entry) => {
|
|
return normalizedEntry(entry);
|
|
}).filter((entry) => {
|
|
return entry.length > 0;
|
|
});
|
|
}
|
|
|
|
function playerAt(row) {
|
|
if (!mpris2Model || row < 0 || row >= mpris2Model.rowCount())
|
|
return null;
|
|
|
|
return mpris2Model.data(mpris2Model.index(row, 0), containerRole);
|
|
}
|
|
|
|
function findPlayerByEntry(targetEntry) {
|
|
if (!targetEntry || !mpris2Model)
|
|
return null;
|
|
|
|
const playerCount = mpris2Model.rowCount();
|
|
for (let row = 0; row < playerCount; ++row) {
|
|
const player = playerAt(row);
|
|
if (player && entriesMatch(player.desktopEntry, targetEntry))
|
|
return player;
|
|
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function resolvePlayer() {
|
|
modelRevision;
|
|
if (!mpris2Model)
|
|
return null;
|
|
|
|
for (const targetEntry of normalizedSourcePriority) {
|
|
const matchedPlayer = findPlayerByEntry(targetEntry);
|
|
if (matchedPlayer)
|
|
return matchedPlayer;
|
|
|
|
}
|
|
if (sourceWhitelist && normalizedSourcePriority.length > 0)
|
|
return null;
|
|
|
|
return mpris2Model.currentPlayer || null;
|
|
}
|
|
|
|
function togglePlayPause() {
|
|
if (resolvedPlayer)
|
|
resolvedPlayer.PlayPause();
|
|
|
|
}
|
|
|
|
function setPosition(position) {
|
|
if (resolvedPlayer)
|
|
resolvedPlayer.position = position;
|
|
|
|
}
|
|
|
|
function next() {
|
|
if (resolvedPlayer)
|
|
resolvedPlayer.Next();
|
|
|
|
}
|
|
|
|
function previous() {
|
|
if (resolvedPlayer)
|
|
resolvedPlayer.Previous();
|
|
|
|
}
|
|
|
|
function updatePosition() {
|
|
if (resolvedPlayer)
|
|
resolvedPlayer.updatePosition();
|
|
|
|
}
|
|
|
|
function setVolume(volume) {
|
|
if (resolvedPlayer)
|
|
resolvedPlayer.volume = volume;
|
|
|
|
}
|
|
|
|
function changeVolume(delta, showOSD) {
|
|
if (resolvedPlayer)
|
|
resolvedPlayer.changeVolume(delta, showOSD);
|
|
|
|
}
|
|
|
|
function setShuffle(shuffle) {
|
|
if (resolvedPlayer)
|
|
resolvedPlayer.shuffle = shuffle;
|
|
|
|
}
|
|
|
|
function setLoopStatus(loopStatus) {
|
|
if (resolvedPlayer)
|
|
resolvedPlayer.loopStatus = loopStatus;
|
|
|
|
}
|
|
|
|
function raise() {
|
|
if (resolvedPlayer)
|
|
resolvedPlayer.Raise();
|
|
|
|
}
|
|
|
|
function formatTrackTime(s) {
|
|
const hours = Math.floor(s / 3600);
|
|
let minutes = Math.floor((s - hours * 3600) / 60);
|
|
let seconds = Math.ceil(s - hours * 3600 - minutes * 60);
|
|
minutes = minutes < 10 ? "0" + minutes : minutes;
|
|
seconds = seconds < 10 ? "0" + seconds : seconds;
|
|
return minutes + ":" + seconds;
|
|
}
|
|
|
|
mpris2Model: Mpris.Mpris2Model {
|
|
onRowsInserted: root.modelRevision += 1
|
|
onRowsRemoved: root.modelRevision += 1
|
|
onModelReset: root.modelRevision += 1
|
|
onDataChanged: root.modelRevision += 1
|
|
onCurrentPlayerChanged: root.modelRevision += 1
|
|
}
|
|
|
|
}
|