mirror of
https://github.com/arcan1s/awesome-widgets.git
synced 2025-07-09 20:05:51 +00:00
Add test for hddsource, move sources to own library
This commit is contained in:
386
sources/extsysmonsources/playersource.cpp
Normal file
386
sources/extsysmonsources/playersource.cpp
Normal file
@ -0,0 +1,386 @@
|
||||
/***************************************************************************
|
||||
* This file is part of awesome-widgets *
|
||||
* *
|
||||
* awesome-widgets is free software: you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* awesome-widgets is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with awesome-widgets. If not, see http://www.gnu.org/licenses/ *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "playersource.h"
|
||||
|
||||
#include <QDBusArgument>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusConnectionInterface>
|
||||
#include <QDBusMessage>
|
||||
#include <QProcess>
|
||||
#include <QTextCodec>
|
||||
|
||||
#include "awdebug.h"
|
||||
|
||||
|
||||
PlayerSource::PlayerSource(QObject *parent, const QStringList args)
|
||||
: AbstractExtSysMonSource(parent, args)
|
||||
{
|
||||
Q_ASSERT(args.count() == 5);
|
||||
qCDebug(LOG_ESS) << __PRETTY_FUNCTION__;
|
||||
|
||||
m_player = args.at(0);
|
||||
m_mpdAddress = QString("%1:%2").arg(args.at(1)).arg(args.at(2));
|
||||
m_mpris = args.at(3);
|
||||
m_symbols = args.at(4).toInt();
|
||||
|
||||
m_mpdProcess = new QProcess(nullptr);
|
||||
// fucking magic from http://doc.qt.io/qt-5/qprocess.html#finished
|
||||
connect(m_mpdProcess,
|
||||
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(
|
||||
&QProcess::finished),
|
||||
[this](int, QProcess::ExitStatus) { return updateValue(); });
|
||||
m_mpdProcess->waitForFinished(0);
|
||||
m_mpdCached = defaultInfo();
|
||||
}
|
||||
|
||||
|
||||
PlayerSource::~PlayerSource()
|
||||
{
|
||||
qCDebug(LOG_ESS) << __PRETTY_FUNCTION__;
|
||||
|
||||
m_mpdProcess->kill();
|
||||
m_mpdProcess->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
QVariant PlayerSource::data(QString source)
|
||||
{
|
||||
qCDebug(LOG_ESS) << "Source" << source;
|
||||
|
||||
if (!m_values.contains(source))
|
||||
run();
|
||||
QVariant value = m_values.take(source);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
QVariantMap PlayerSource::initialData(QString source) const
|
||||
{
|
||||
qCDebug(LOG_ESS) << "Source" << source;
|
||||
|
||||
QVariantMap data;
|
||||
if (source == QString("player/album")) {
|
||||
data[QString("min")] = QString("");
|
||||
data[QString("max")] = QString("");
|
||||
data[QString("name")] = QString("Current song album");
|
||||
data[QString("type")] = QString("QString");
|
||||
data[QString("units")] = QString("");
|
||||
} else if (source == QString("player/salbum")) {
|
||||
data[QString("min")] = QString("");
|
||||
data[QString("max")] = QString("");
|
||||
data[QString("name")]
|
||||
= QString("Current song album (%1 symbols)").arg(m_symbols);
|
||||
data[QString("type")] = QString("QString");
|
||||
data[QString("units")] = QString("");
|
||||
} else if (source == QString("player/dalbum")) {
|
||||
data[QString("min")] = QString("");
|
||||
data[QString("max")] = QString("");
|
||||
data[QString("name")]
|
||||
= QString("Current song album (%1 symbols, dynamic)")
|
||||
.arg(m_symbols);
|
||||
data[QString("type")] = QString("QString");
|
||||
data[QString("units")] = QString("");
|
||||
} else if (source == QString("player/artist")) {
|
||||
data[QString("min")] = QString("");
|
||||
data[QString("max")] = QString("");
|
||||
data[QString("name")] = QString("Current song artist");
|
||||
data[QString("type")] = QString("QString");
|
||||
data[QString("units")] = QString("");
|
||||
} else if (source == QString("player/sartist")) {
|
||||
data[QString("min")] = QString("");
|
||||
data[QString("max")] = QString("");
|
||||
data[QString("name")]
|
||||
= QString("Current song artist (%1 symbols)").arg(m_symbols);
|
||||
data[QString("type")] = QString("QString");
|
||||
data[QString("units")] = QString("");
|
||||
} else if (source == QString("player/dartist")) {
|
||||
data[QString("min")] = QString("");
|
||||
data[QString("max")] = QString("");
|
||||
data[QString("name")]
|
||||
= QString("Current song artist (%1 symbols, dynamic)")
|
||||
.arg(m_symbols);
|
||||
data[QString("type")] = QString("QString");
|
||||
data[QString("units")] = QString("");
|
||||
} else if (source == QString("player/duration")) {
|
||||
data[QString("min")] = 0;
|
||||
data[QString("max")] = 0;
|
||||
data[QString("name")] = QString("Current song duration");
|
||||
data[QString("type")] = QString("integer");
|
||||
data[QString("units")] = QString("s");
|
||||
} else if (source == QString("player/progress")) {
|
||||
data[QString("min")] = 0;
|
||||
data[QString("max")] = 0;
|
||||
data[QString("name")] = QString("Current song progress");
|
||||
data[QString("type")] = QString("integer");
|
||||
data[QString("units")] = QString("s");
|
||||
} else if (source == QString("player/title")) {
|
||||
data[QString("min")] = QString("");
|
||||
data[QString("max")] = QString("");
|
||||
data[QString("name")] = QString("Current song title");
|
||||
data[QString("type")] = QString("QString");
|
||||
data[QString("units")] = QString("");
|
||||
} else if (source == QString("player/stitle")) {
|
||||
data[QString("min")] = QString("");
|
||||
data[QString("max")] = QString("");
|
||||
data[QString("name")]
|
||||
= QString("Current song title (%1 symbols)").arg(m_symbols);
|
||||
data[QString("type")] = QString("QString");
|
||||
data[QString("units")] = QString("");
|
||||
} else if (source == QString("player/dtitle")) {
|
||||
data[QString("min")] = QString("");
|
||||
data[QString("max")] = QString("");
|
||||
data[QString("name")]
|
||||
= QString("Current song title (%1 symbols, dynamic)")
|
||||
.arg(m_symbols);
|
||||
data[QString("type")] = QString("QString");
|
||||
data[QString("units")] = QString("");
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void PlayerSource::run()
|
||||
{
|
||||
// initial data
|
||||
if (m_player == QString("mpd")) {
|
||||
// mpd
|
||||
QHash<QString, QVariant> data = getPlayerMpdInfo(m_mpdAddress);
|
||||
for (auto key : data.keys())
|
||||
m_values[key] = data[key];
|
||||
} else if (m_player == QString("mpris")) {
|
||||
// players which supports mpris
|
||||
QString mpris = m_mpris == QString("auto") ? getAutoMpris() : m_mpris;
|
||||
QHash<QString, QVariant> data = getPlayerMprisInfo(mpris);
|
||||
for (auto key : data.keys())
|
||||
m_values[key] = data[key];
|
||||
}
|
||||
|
||||
// dymanic properties
|
||||
// solid
|
||||
m_values[QString("player/salbum")]
|
||||
= stripString(m_values[QString("player/album")].toString(), m_symbols);
|
||||
m_values[QString("player/sartist")]
|
||||
= stripString(m_values[QString("player/artist")].toString(), m_symbols);
|
||||
m_values[QString("player/stitle")]
|
||||
= stripString(m_values[QString("player/title")].toString(), m_symbols);
|
||||
// dynamic
|
||||
m_values[QString("player/dalbum")]
|
||||
= buildString(m_values[QString("player/dalbum")].toString(),
|
||||
m_values[QString("player/album")].toString(), m_symbols);
|
||||
m_values[QString("player/dartist")]
|
||||
= buildString(m_values[QString("player/dartist")].toString(),
|
||||
m_values[QString("player/artist")].toString(), m_symbols);
|
||||
m_values[QString("player/dtitle")]
|
||||
= buildString(m_values[QString("player/dtitle")].toString(),
|
||||
m_values[QString("player/title")].toString(), m_symbols);
|
||||
}
|
||||
|
||||
|
||||
QStringList PlayerSource::sources() const
|
||||
{
|
||||
QStringList sources;
|
||||
sources.append(QString("player/album"));
|
||||
sources.append(QString("player/dalbum"));
|
||||
sources.append(QString("player/salbum"));
|
||||
sources.append(QString("player/artist"));
|
||||
sources.append(QString("player/dartist"));
|
||||
sources.append(QString("player/sartist"));
|
||||
sources.append(QString("player/duration"));
|
||||
sources.append(QString("player/progress"));
|
||||
sources.append(QString("player/title"));
|
||||
sources.append(QString("player/dtitle"));
|
||||
sources.append(QString("player/stitle"));
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
|
||||
void PlayerSource::updateValue()
|
||||
{
|
||||
qCInfo(LOG_ESS) << "Cmd returns" << m_mpdProcess->exitCode();
|
||||
QString qdebug = QTextCodec::codecForMib(106)
|
||||
->toUnicode(m_mpdProcess->readAllStandardError())
|
||||
.trimmed();
|
||||
qCInfo(LOG_ESS) << "Error" << qdebug;
|
||||
QString qoutput = QTextCodec::codecForMib(106)
|
||||
->toUnicode(m_mpdProcess->readAllStandardOutput())
|
||||
.trimmed();
|
||||
qCInfo(LOG_ESS) << "Output" << qoutput;
|
||||
|
||||
for (auto str : qoutput.split(QChar('\n'), QString::SkipEmptyParts)) {
|
||||
if (str.split(QString(": "), QString::SkipEmptyParts).count() == 2) {
|
||||
// "Metadata: data"
|
||||
QString metadata = str.split(QString(": "), QString::SkipEmptyParts)
|
||||
.first()
|
||||
.toLower();
|
||||
QString data = str.split(QString(": "), QString::SkipEmptyParts)
|
||||
.last()
|
||||
.trimmed();
|
||||
// there are one more time...
|
||||
if ((metadata == QString("time")) && (data.contains(QChar(':')))) {
|
||||
QStringList times = data.split(QString(":"));
|
||||
m_mpdCached[QString("player/duration")] = times.at(0).toInt();
|
||||
m_mpdCached[QString("player/progress")] = times.at(1).toInt();
|
||||
} else if (m_metadata.contains(metadata)) {
|
||||
m_mpdCached[QString("player/%1").arg(metadata)] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QVariantHash PlayerSource::defaultInfo() const
|
||||
{
|
||||
QVariantHash info;
|
||||
info[QString("player/album")] = QString("unknown");
|
||||
info[QString("player/artist")] = QString("unknown");
|
||||
info[QString("player/duration")] = 0;
|
||||
info[QString("player/progress")] = 0;
|
||||
info[QString("player/title")] = QString("unknown");
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
QString PlayerSource::getAutoMpris() const
|
||||
{
|
||||
QDBusMessage listServices = QDBusConnection::sessionBus().interface()->call(
|
||||
QDBus::BlockWithGui, QString("ListNames"));
|
||||
if (listServices.arguments().isEmpty())
|
||||
return QString();
|
||||
QStringList arguments = listServices.arguments().first().toStringList();
|
||||
|
||||
for (auto arg : arguments) {
|
||||
if (!arg.startsWith(QString("org.mpris.MediaPlayer2.")))
|
||||
continue;
|
||||
qCInfo(LOG_ESS) << "Service found" << arg;
|
||||
QString service = arg;
|
||||
service.remove(QString("org.mpris.MediaPlayer2."));
|
||||
return service;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
QVariantHash PlayerSource::getPlayerMpdInfo(const QString mpdAddress) const
|
||||
{
|
||||
qCDebug(LOG_ESS) << "MPD" << mpdAddress;
|
||||
|
||||
// build cmd
|
||||
QString cmd = QString("bash -c \"echo 'currentsong\nstatus\nclose' | curl "
|
||||
"--connect-timeout 1 -fsm 3 telnet://%1\"")
|
||||
.arg(mpdAddress);
|
||||
qCInfo(LOG_ESS) << "cmd" << cmd;
|
||||
m_mpdProcess->start(cmd);
|
||||
|
||||
return m_mpdCached;
|
||||
}
|
||||
|
||||
|
||||
QVariantHash PlayerSource::getPlayerMprisInfo(const QString mpris) const
|
||||
{
|
||||
qCDebug(LOG_ESS) << "MPRIS" << mpris;
|
||||
|
||||
QVariantHash info = defaultInfo();
|
||||
if (mpris.isEmpty())
|
||||
return info;
|
||||
|
||||
QDBusConnection bus = QDBusConnection::sessionBus();
|
||||
// comes from the following request:
|
||||
// qdbus org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2
|
||||
// org.freedesktop.DBus.Properties.Get org.mpris.MediaPlayer2.Player
|
||||
// Metadata
|
||||
// or the same but using dbus-send:
|
||||
// dbus-send --print-reply --session --dest=org.mpris.MediaPlayer2.vlc
|
||||
// /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get
|
||||
// string:'org.mpris.MediaPlayer2.Player' string:'Metadata'
|
||||
QVariantList args = QVariantList()
|
||||
<< QString("org.mpris.MediaPlayer2.Player")
|
||||
<< QString("Metadata");
|
||||
QDBusMessage request = QDBusMessage::createMethodCall(
|
||||
QString("org.mpris.MediaPlayer2.%1").arg(mpris),
|
||||
QString("/org/mpris/MediaPlayer2"), QString(""), QString("Get"));
|
||||
request.setArguments(args);
|
||||
QDBusMessage response = bus.call(request, QDBus::BlockWithGui);
|
||||
if ((response.type() != QDBusMessage::ReplyMessage)
|
||||
|| (response.arguments().isEmpty())) {
|
||||
qCWarning(LOG_ESS) << "Error message" << response.errorMessage();
|
||||
} else {
|
||||
// another portion of dirty magic
|
||||
QVariantHash map
|
||||
= qdbus_cast<QVariantHash>(response.arguments()
|
||||
.first()
|
||||
.value<QDBusVariant>()
|
||||
.variant()
|
||||
.value<QDBusArgument>());
|
||||
info[QString("player/album")]
|
||||
= map.value(QString("xesam:album"), QString("unknown"));
|
||||
// artist is array
|
||||
info[QString("player/artist")]
|
||||
= map.value(QString("xesam:artist"), QString("unknown")).toString();
|
||||
info[QString("player/duration")]
|
||||
= map.value(QString("mpris:length"), 0).toInt() / (1000 * 1000);
|
||||
info[QString("player/title")]
|
||||
= map.value(QString("xesam:title"), QString("unknown"));
|
||||
}
|
||||
|
||||
// position
|
||||
args[1] = QString("Position");
|
||||
request.setArguments(args);
|
||||
response = bus.call(request, QDBus::BlockWithGui);
|
||||
if ((response.type() != QDBusMessage::ReplyMessage)
|
||||
|| (response.arguments().isEmpty())) {
|
||||
qCWarning(LOG_ESS) << "Error message" << response.errorMessage();
|
||||
} else {
|
||||
// this cast is simpler than the previous one ;)
|
||||
info[QString("player/progress")] = response.arguments()
|
||||
.first()
|
||||
.value<QDBusVariant>()
|
||||
.variant()
|
||||
.toLongLong()
|
||||
/ (1000 * 1000);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
QString PlayerSource::buildString(const QString current, const QString value,
|
||||
const int s) const
|
||||
{
|
||||
qCDebug(LOG_ESS) << "Current value" << current << "received" << value
|
||||
<< "will be stripped after" << s;
|
||||
|
||||
int index = value.indexOf(current);
|
||||
if ((current.isEmpty()) || ((index + s + 1) > value.count()))
|
||||
return QString("%1").arg(value.left(s), s, QLatin1Char(' '));
|
||||
else
|
||||
return QString("%1").arg(value.mid(index + 1, s), s, QLatin1Char(' '));
|
||||
}
|
||||
|
||||
|
||||
QString PlayerSource::stripString(const QString value, const int s) const
|
||||
{
|
||||
qCDebug(LOG_ESS) << "New value" << value << "will be stripped after" << s;
|
||||
|
||||
return value.count() > s ? QString("%1\u2026").arg(value.left(s - 1))
|
||||
: value.leftJustified(s, QLatin1Char(' '));
|
||||
}
|
Reference in New Issue
Block a user