improved compatibility with latest version of Yfitops

This commit is contained in:
Martchus 2015-10-10 21:35:16 +02:00
parent a6199d0fdd
commit a5936281d7
5 changed files with 243 additions and 130 deletions

View File

@ -4,6 +4,8 @@
#include <c++utilities/io/inifile.h>
#include <c++utilities/conversion/stringconversion.h>
#include <QStringBuilder>
#include <iostream>
#include <fstream>
@ -23,12 +25,14 @@ FfmpegLauncher::FfmpegLauncher(PlayerWatcher &watcher, QObject *parent) :
QObject(parent),
m_watcher(watcher),
m_sink(QStringLiteral("default")),
m_inputOptions(),
m_options(),
m_targetDir(QStringLiteral(".")),
m_targetExtension(QStringLiteral(".m4a")),
m_ffmpeg(new QProcess(this))
{
connect(&watcher, &PlayerWatcher::nextSong, this, &FfmpegLauncher::nextSong);
connect(&watcher, &PlayerWatcher::playbackStopped, this, &FfmpegLauncher::stopFfmpeg);
connect(m_ffmpeg, &QProcess::started, this, &FfmpegLauncher::ffmpegStarted);
connect(m_ffmpeg, static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error), this, &FfmpegLauncher::ffmpegError);
connect(m_ffmpeg, static_cast<void(QProcess::*)(int)>(&QProcess::finished), this, &FfmpegLauncher::ffmpegFinished);
@ -46,112 +50,145 @@ void addMetaData(QStringList &args, const QString &field, const QString &value)
void FfmpegLauncher::nextSong()
{
// skip ads
if(m_watcher.isAd()) {
return;
}
// pause player until ffmpeg has been started
m_watcher.setSilent(true);
if(m_watcher.isPlaying()) {
m_watcher.pause();
}
// terminate/kill the current process
stopFfmpeg();
// determine output file, create target directory
static const QString miscCategory(QStringLiteral("misc"));
static const QString unknownTitle(QStringLiteral("unknown track"));
const auto targetDirPath = QStringLiteral("%1/%2").arg(m_watcher.artist().isEmpty() ? miscCategory : m_watcher.artist(), m_watcher.artist().isEmpty() ? miscCategory : m_watcher.album());
if(!m_targetDir.mkpath(targetDirPath)) {
cerr << "Error: Can not create target directory: " << targetDirPath << endl;
return;
}
QDir targetDir(m_targetDir);
targetDir.cd(targetDirPath);
// determine track number
QString number, length, year, genre, totalTracks, totalDisks;
if(m_watcher.trackNumber()) {
if(m_watcher.diskNumber()) {
number = QStringLiteral("%2-%1").arg(m_watcher.trackNumber(), 2, 10, QLatin1Char('0')).arg(m_watcher.diskNumber());
} else {
number = QStringLiteral("%1").arg(m_watcher.trackNumber(), 2, 10, QLatin1Char('0'));
}
}
if(!number.isEmpty()) {
number.append(QStringLiteral(" - "));
}
// read additional meta info
// - from an INI file called info.ini in the album directory (must be created before recording)
// - track lengths might be specified for each track in the [length] section (useful to get rid of advertisements at the end)
// - year, genre, total_tracks and total_disks might be specified in the [general] section
if(targetDir.exists(QStringLiteral("info.ini"))) {
fstream infoFile;
infoFile.exceptions(ios_base::badbit | ios_base::failbit);
try {
infoFile.open((targetDir.path() + QStringLiteral("/info.ini")).toLocal8Bit().data(), ios_base::in);
IniFile infoIni;
infoIni.parse(infoFile);
for(auto &scope : infoIni.data()) {
if(scope.first == "length") {
if(m_watcher.trackNumber()) {
// reading length scope is only possible if track number known because the track number is used for mapping
for(const auto &entry : scope.second) {
try {
if(stringToNumber<unsigned int>(entry.first) == m_watcher.trackNumber()) {
// length entry for this track
length = QString::fromLocal8Bit(entry.second.data());
break;
}
} catch(const ConversionException &) {
cerr << "Warning: Ignoring non-numeric key \"" << entry.first << "\" in [length] section of info.ini." << endl;
}
}
}
} else if(scope.first == "general") {
for(const auto &entry : scope.second) {
if(entry.first == "year") {
year = QString::fromLocal8Bit(entry.second.data());
} else if(entry.first == "genre") {
genre = QString::fromLocal8Bit(entry.second.data());
} else if(entry.first == "total_tracks") {
totalTracks = QString::fromLocal8Bit(entry.second.data());
} else if(entry.first == "total_disks") {
totalDisks = QString::fromLocal8Bit(entry.second.data());
} else {
cerr << "Warning: Ignoring unknown property \"" << entry.first << "\" in [general] section of info.ini." << endl;
}
}
} else {
cerr << "Warning: Ignoring unknown section [" << scope.first << "] in info.ini." << endl;
}
}
} catch(const ios_base::failure &) {
cerr << "Warning: Can't parse info.ini because an IO error occured." << endl;
}
}
// determine target name/path
QString targetName(QStringLiteral("%3%1%2").arg(m_watcher.title().isEmpty() ? unknownTitle : m_watcher.title(), m_targetExtension, number));
unsigned int count = 1;
while(targetDir.exists(targetName)) {
++count;
targetName = QStringLiteral("%3%1 (%4)%2").arg(m_watcher.title().isEmpty() ? unknownTitle : m_watcher.title(), m_targetExtension, number).arg(count);
}
auto targetPath = targetDir.absoluteFilePath(targetName);
// set input device
QStringList args;
args << QStringLiteral("-f");
args << QStringLiteral("pulse");
args << m_inputOptions;
args << QStringLiteral("-i");
args << m_sink;
// set length if specified in info.ini
if(!length.isEmpty() || !m_watcher.length().isNull()) {
args << "-t";
args << (length.isEmpty() ? QString::number(m_watcher.length().totalSeconds()) : length);
}
// set additional options
args << m_options;
// set meta data
addMetaData(args, QStringLiteral("title"), m_watcher.title());
addMetaData(args, QStringLiteral("album"), m_watcher.album());
addMetaData(args, QStringLiteral("artist"), m_watcher.artist());
addMetaData(args, QStringLiteral("genre"), genre.isEmpty() ? m_watcher.genre() : genre);
addMetaData(args, QStringLiteral("year"), year.isEmpty() ? m_watcher.year() : year);
if(m_watcher.trackNumber()) {
addMetaData(args, QStringLiteral("track"), totalTracks.isEmpty() ? QString::number(m_watcher.trackNumber()) : QString::number(m_watcher.trackNumber()) % QChar('/') % totalTracks);
}
if(m_watcher.diskNumber()) {
addMetaData(args, QStringLiteral("disk"), totalDisks.isEmpty() ? QString::number(m_watcher.diskNumber()) : QString::number(m_watcher.diskNumber()) % QChar('/') % totalDisks);
}
// set output file
args << targetPath;
m_ffmpeg->setArguments(args);
// start process
m_ffmpeg->start();
// resume player
m_watcher.play();
m_watcher.setSilent(false);
}
void FfmpegLauncher::stopFfmpeg()
{
if(m_ffmpeg->state() != QProcess::NotRunning) {
m_ffmpeg->terminate();
m_ffmpeg->waitForFinished(250);
m_ffmpeg->waitForFinished(10000);
if(m_ffmpeg->state() != QProcess::NotRunning) {
m_ffmpeg->kill();
m_ffmpeg->waitForFinished(250);
m_ffmpeg->waitForFinished(5000);
if(m_ffmpeg->state() != QProcess::NotRunning) {
throw runtime_error("Unable to terminate/kill ffmpeg process.");
}
}
}
if(m_watcher.isPlaying()) {
// determine output file, create target directory
static const QString miscCategory(QStringLiteral("misc"));
static const QString unknownTitle(QStringLiteral("unknown track"));
const auto targetDirPath = QStringLiteral("%1/%2").arg(m_watcher.artist().isEmpty() ? miscCategory : m_watcher.artist(), m_watcher.artist().isEmpty() ? miscCategory : m_watcher.album());
if(!m_targetDir.mkpath(targetDirPath)) {
cerr << "Error: Can not create target directory: " << targetDirPath << endl;
return;
}
QDir targetDir(m_targetDir);
targetDir.cd(targetDirPath);
// determine track number
QString number, length;
if(m_watcher.trackNumber()) {
if(m_watcher.diskNumber()) {
number = QStringLiteral("%2-%1").arg(m_watcher.trackNumber(), 2, 10, QLatin1Char('0')).arg(m_watcher.diskNumber());
} else {
number = QStringLiteral("%1").arg(m_watcher.trackNumber(), 2, 10, QLatin1Char('0'));
}
}
if(!number.isEmpty()) {
number.append(QStringLiteral(" - "));
}
// determine additional info
// - from a file called info.ini in the album directory
// - currently only track length is supported (used to get rid of advertisements at the end)
if(targetDir.exists(QStringLiteral("info.ini"))) {
fstream infoFile;
infoFile.exceptions(ios_base::badbit | ios_base::failbit);
try {
infoFile.open((targetDir.path() + QStringLiteral("/info.ini")).toLocal8Bit().data(), ios_base::in);
IniFile infoIni;
infoIni.parse(infoFile);
// read length scope, only possible if track number known because the track number is used for mapping
if(m_watcher.trackNumber()) {
for(auto &scope : infoIni.data()) {
if(scope.first == "length") {
for(const auto &entry : scope.second) {
try {
if(stringToNumber<unsigned int>(entry.first) == m_watcher.trackNumber()) {
// length entry for this track
length = QString::fromLocal8Bit(entry.second.data());
break;
}
} catch( const ConversionException &) {
cerr << "Warning: Ignoring non-numeric key \"" << entry.first << "\" in info.ini." << endl;
}
}
}
}
}
} catch(const ios_base::failure &) {
cerr << "Warning: Can't parse info.ini because an IO error occured." << endl;
}
}
// determine target name/path
QString targetName(QStringLiteral("%3%1%2").arg(m_watcher.title().isEmpty() ? unknownTitle : m_watcher.title(), m_targetExtension, number));
unsigned int count = 1;
while(targetDir.exists(targetName)) {
++count;
targetName = QStringLiteral("%3%1 (%4)%2").arg(m_watcher.title().isEmpty() ? unknownTitle : m_watcher.title(), m_targetExtension, number).arg(count);
}
auto targetPath = targetDir.absoluteFilePath(targetName);
// set input device
QStringList args;
args << QStringLiteral("-f");
args << QStringLiteral("pulse");
args << QStringLiteral("-i");
args << m_sink;
// set length
if(!length.isEmpty()) {
args << "-t";
args << length;
}
// set additional options
args << m_options;
// set meta data
addMetaData(args, QStringLiteral("title"), m_watcher.title());
addMetaData(args, QStringLiteral("album"), m_watcher.album());
addMetaData(args, QStringLiteral("artist"), m_watcher.artist());
addMetaData(args, QStringLiteral("genre"), m_watcher.genre());
addMetaData(args, QStringLiteral("year"), m_watcher.year());
if(m_watcher.trackNumber()) {
addMetaData(args, QStringLiteral("track"), QString::number(m_watcher.trackNumber()));
}
if(m_watcher.diskNumber()) {
addMetaData(args, QStringLiteral("disk"), QString::number(m_watcher.diskNumber()));
}
// set output file
args << targetPath;
m_ffmpeg->setArguments(args);
// start process
m_ffmpeg->start();
}
}
void FfmpegLauncher::ffmpegStarted()

View File

@ -16,13 +16,15 @@ public:
explicit FfmpegLauncher(PlayerWatcher &watcher, QObject *parent = nullptr);
void setSink(const QString &sinkName);
void setFfmpegBinary(const QString &path);
void setFfmpegOptions(const QString &options);
void setFFmpegInputOptions(const QString &options);
void setFFmpegBinary(const QString &path);
void setFFmpegOptions(const QString &options);
void setTargetDir(const QString &path);
void setTargetExtension(const QString &extension);
private slots:
void nextSong();
void stopFfmpeg();
void ffmpegStarted();
void ffmpegError();
void ffmpegFinished(int exitCode);
@ -30,6 +32,7 @@ private slots:
private:
PlayerWatcher &m_watcher;
QString m_sink;
QStringList m_inputOptions;
QStringList m_options;
QDir m_targetDir;
QString m_targetExtension;
@ -41,12 +44,17 @@ inline void FfmpegLauncher::setSink(const QString &sinkName)
m_sink = sinkName;
}
inline void FfmpegLauncher::setFfmpegBinary(const QString &path)
inline void FfmpegLauncher::setFFmpegInputOptions(const QString &options)
{
m_inputOptions = options.split(QChar(' '), QString::SkipEmptyParts);
}
inline void FfmpegLauncher::setFFmpegBinary(const QString &path)
{
m_ffmpeg->setProgram(path);
}
inline void FfmpegLauncher::setFfmpegOptions(const QString &options)
inline void FfmpegLauncher::setFFmpegOptions(const QString &options)
{
m_options = options.split(QChar(' '), QString::SkipEmptyParts);
}

View File

@ -28,6 +28,9 @@ int main(int argc, char *argv[])
sinkArg.setValueNames({"sink"});
sinkArg.setRequiredValueCount(1);
sinkArg.setCombinable(true);
Argument ffmpegInputOptions("ffmpeg-input-options", "i", "specifies options for the ffmpeg input device");
ffmpegInputOptions.setRequiredValueCount(1);
ffmpegInputOptions.setCombinable(true);
Argument targetDirArg("target-dir", "t", "specifies the target directory");
targetDirArg.setValueNames({"path"});
targetDirArg.setRequiredValueCount(1);
@ -36,6 +39,8 @@ int main(int argc, char *argv[])
targetExtArg.setValueNames({"extension"});
targetExtArg.setRequiredValueCount(1);
targetExtArg.setCombinable(true);
Argument ignorePlaybackStatusArg("ignore-playback-status", string(), "ignores the playback status (does not call PlaybackStatus())");
ignorePlaybackStatusArg.setCombinable(true);
Argument ffmpegBinArg("ffmpeg-bin", "f", "specifies the path to the ffmpeg binary");
ffmpegBinArg.setValueNames({"path"});
ffmpegBinArg.setRequiredValueCount(1);
@ -44,7 +49,7 @@ int main(int argc, char *argv[])
ffmpegOptions.setValueNames({"options"});
ffmpegOptions.setRequiredValueCount(1);
ffmpegOptions.setCombinable(true);
recordArg.setSecondaryArguments({&applicationArg, &sinkArg, &targetDirArg, &targetExtArg, &ffmpegBinArg, &ffmpegOptions});
recordArg.setSecondaryArguments({&applicationArg, &sinkArg, &ffmpegInputOptions, &targetDirArg, &targetExtArg, &ignorePlaybackStatusArg, &ffmpegBinArg, &ffmpegOptions});
parser.setMainArguments({&recordArg, &helpArg});
parser.setIgnoreUnknownArguments(false);
// parse command line arguments
@ -60,17 +65,20 @@ int main(int argc, char *argv[])
cerr << "Watching MPRIS service of the specified application \"" << applicationArg.values().front() << "\" ..." << endl;
// create app loop, player watcher and ffmpeg launcher
QCoreApplication app(argc, argv);
PlayerWatcher watcher(QString::fromLocal8Bit(applicationArg.values().front().data()));
PlayerWatcher watcher(QString::fromLocal8Bit(applicationArg.values().front().data()), ignorePlaybackStatusArg.isPresent());
FfmpegLauncher ffmpeg(watcher);
// pass specified args to ffmpeg launcher
if(sinkArg.isPresent()) {
ffmpeg.setSink(QString::fromLocal8Bit(sinkArg.values().front().data()));
}
if(ffmpegInputOptions.isPresent()) {
ffmpeg.setFFmpegInputOptions(QString::fromLocal8Bit(ffmpegInputOptions.values().front().data()));
}
if(ffmpegBinArg.isPresent()) {
ffmpeg.setFfmpegBinary(QString::fromLocal8Bit(ffmpegBinArg.values().front().data()));
ffmpeg.setFFmpegBinary(QString::fromLocal8Bit(ffmpegBinArg.values().front().data()));
}
if(ffmpegOptions.isPresent()) {
ffmpeg.setFfmpegOptions(QString::fromLocal8Bit(ffmpegOptions.values().front().data()));
ffmpeg.setFFmpegOptions(QString::fromLocal8Bit(ffmpegOptions.values().front().data()));
}
if(targetDirArg.isPresent()) {
ffmpeg.setTargetDir(QString::fromLocal8Bit(targetDirArg.values().front().data()));
@ -80,7 +88,7 @@ int main(int argc, char *argv[])
}
// enter app loop
return app.exec();
} else {
} else if(!helpArg.isPresent()) {
cerr << "No operation specified." << endl;
return 2;
}

View File

@ -9,6 +9,7 @@
#include <iostream>
using namespace std;
using namespace ChronoUtilities;
namespace DBusSoundRecorder {
@ -18,18 +19,30 @@ inline ostream &operator <<(ostream &stream, const QString &str)
return stream;
}
PlayerWatcher::PlayerWatcher(const QString &appName, QObject *parent) :
PlayerWatcher::PlayerWatcher(const QString &appName, bool ignorePlaybackStatus, QObject *parent) :
QObject(parent),
m_service(QStringLiteral("org.mpris.MediaPlayer2.%1").arg(appName)),
m_serviceWatcher(new QDBusServiceWatcher(m_service, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this)),
m_propertiesInterface(new OrgFreedesktopDBusPropertiesInterface(m_service, QStringLiteral("/org/mpris/MediaPlayer2"), QDBusConnection::sessionBus(), this)),
m_playerInterface(new OrgMprisMediaPlayer2PlayerInterface(m_service, QStringLiteral("/org/mpris/MediaPlayer2"), QDBusConnection::sessionBus(), this)),
m_mediaPlayerInterfaceName(QStringLiteral("org.mpris.MediaPlayer2.%1").arg(appName)),
m_mediaPlayerServiceWatcher(new QDBusServiceWatcher(m_mediaPlayerInterfaceName, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this)),
m_propertiesInterface(new OrgFreedesktopDBusPropertiesInterface(m_mediaPlayerInterfaceName, QStringLiteral("/org/mpris/MediaPlayer2"), QDBusConnection::sessionBus(), this)),
m_playerInterface(new OrgMprisMediaPlayer2PlayerInterface(m_mediaPlayerInterfaceName, QStringLiteral("/org/mpris/MediaPlayer2"), QDBusConnection::sessionBus(), this)),
m_isPlaying(false),
m_isAd(false),
m_trackNumber(0),
m_diskNumber(0)
m_diskNumber(0),
m_silent(false),
m_ignorePlaybackStatus(ignorePlaybackStatus)
{
connect(m_serviceWatcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &PlayerWatcher::serviceOwnerChanged);
connect(m_propertiesInterface, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged, this, &PlayerWatcher::propertiesChanged);
if(!connect(m_mediaPlayerServiceWatcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &PlayerWatcher::serviceOwnerChanged)) {
cout << "Warning: Unable to connect \"serviceOwnerChanged\" signal of service watcher." << endl;
}
// The code below does not work anymore with the newest version of Spotify.
//if(!connect(m_propertiesInterface, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged, this, &PlayerWatcher::propertiesChanged)) {
// cout << "Warning: Unable to connect \"PropertiesChanged\" signal of properties interface." << endl;
//}
// However, the following works:
if(!QDBusConnection::sessionBus().connect(m_mediaPlayerInterfaceName, QStringLiteral("/org/mpris/MediaPlayer2"), QStringLiteral("org.freedesktop.DBus.Properties"), QStringLiteral("PropertiesChanged"), this, SLOT(propertiesChanged()))) {
cout << "Warning: Unable to connect \"PropertiesChanged\" signal of properties interface." << endl;
}
propertiesChanged();
}
@ -66,15 +79,22 @@ void PlayerWatcher::serviceOwnerChanged(const QString &service, const QString &o
void PlayerWatcher::propertiesChanged()
{
// get meta data
if(!m_playerInterface->playbackStatus().compare(QLatin1String("playing"), Qt::CaseInsensitive)) {
QVariantMap metadata = m_playerInterface->metadata();
m_isAd = metadata.value(QStringLiteral("mpris:trackid")).toString().startsWith(QLatin1String("spotify:ad"));
QString title = metadata.value(QStringLiteral("xesam:title")).toString();
QString album = metadata.value(QStringLiteral("xesam:album")).toString();
QString artist = metadata.value(QStringLiteral("xesam:artist")).toString();
bool isPlaying;
if(m_ignorePlaybackStatus) {
// determine playback status by checking whether there is a song title
isPlaying = !title.isEmpty();
} else {
isPlaying = !m_playerInterface->playbackStatus().compare(QLatin1String("playing"), Qt::CaseInsensitive);
}
if(isPlaying) {
if(!m_isPlaying) {
m_isPlaying = true;
cerr << "Playback started" << endl;
}
QVariantMap metadata = m_playerInterface->metadata();
QString title = metadata.value(QStringLiteral("xesam:title")).toString();
QString album = metadata.value(QStringLiteral("xesam:album")).toString();
QString artist = metadata.value(QStringLiteral("xesam:artist")).toString();
// use title, album and artist to identify song
if(m_title != title || m_album != album || m_artist != artist) {
// next song playing
@ -92,23 +112,37 @@ void PlayerWatcher::propertiesChanged()
if(!m_diskNumber) {
m_diskNumber = metadata.value(QStringLiteral("xesam:discNumber")).toUInt();
}
m_length = metadata.value(QStringLiteral("xesam:length")).toULongLong();
m_length = TimeSpan(metadata.value(QStringLiteral("mpris:length")).toULongLong() * 10);
// notify
cerr << "Next song: " << m_title << endl;
if(!m_isPlaying) {
if(!m_isPlaying && !m_silent) {
m_isPlaying = true;
emit playbackStarted();
}
emit nextSong();
if(!m_silent) {
m_isPlaying = true;
emit nextSong();
}
} else if(!m_isPlaying) {
emit playbackStarted();
if(!m_silent) {
m_isPlaying = true;
emit playbackStarted();
}
}
} else if(m_isPlaying) {
m_isPlaying = false;
cerr << "Playback stopped" << endl;
emit playbackStopped();
if(!m_silent) {
emit playbackStopped();
}
}
}
void PlayerWatcher::notificationReceived()
{
cout << "It works!" << endl;
}
void PlayerWatcher::seeked(qlonglong pos)
{
cerr << "Seeked: " << pos << endl;

View File

@ -1,6 +1,8 @@
#ifndef PLAYERWATCHER_H
#define PLAYERWATCHER_H
#include <c++utilities/chrono/timespan.h>
#include <QObject>
QT_FORWARD_DECLARE_CLASS(QDBusServiceWatcher)
@ -14,7 +16,7 @@ class PlayerWatcher : public QObject
{
Q_OBJECT
public:
explicit PlayerWatcher(const QString &appName, QObject *parent = nullptr);
explicit PlayerWatcher(const QString &appName, bool ignorePlaybackStatus = false, QObject *parent = nullptr);
void play();
void stop();
@ -22,6 +24,8 @@ public:
void playPause();
bool isPlaying() const;
bool isPlaybackStatusIgnored() const;
bool isAd() const;
const QString &title() const;
const QString &album() const;
const QString &artist() const;
@ -29,7 +33,8 @@ public:
const QString &genre() const;
unsigned int trackNumber() const;
unsigned int diskNumber() const;
unsigned long long length() const;
ChronoUtilities::TimeSpan length() const;
void setSilent(bool silent);
signals:
void nextSong();
@ -39,14 +44,18 @@ signals:
private slots:
void serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner);
void propertiesChanged();
void notificationReceived();
void seeked(qlonglong pos);
private:
QString m_service;
QDBusServiceWatcher *m_serviceWatcher;
QString m_mediaPlayerInterfaceName;
QDBusServiceWatcher *m_mediaPlayerServiceWatcher;
QString m_notifyInterfaceName;
QDBusServiceWatcher *m_notifyServiceWatcher;
OrgFreedesktopDBusPropertiesInterface *m_propertiesInterface;
OrgMprisMediaPlayer2PlayerInterface *m_playerInterface;
bool m_isPlaying;
bool m_isAd;
QString m_title;
QString m_album;
QString m_artist;
@ -54,7 +63,9 @@ private:
QString m_genre;
unsigned int m_trackNumber;
unsigned int m_diskNumber;
unsigned long long m_length;
ChronoUtilities::TimeSpan m_length;
bool m_silent;
bool m_ignorePlaybackStatus;
};
inline bool PlayerWatcher::isPlaying() const
@ -62,6 +73,16 @@ inline bool PlayerWatcher::isPlaying() const
return m_isPlaying;
}
inline bool PlayerWatcher::isPlaybackStatusIgnored() const
{
return m_ignorePlaybackStatus;
}
inline bool PlayerWatcher::isAd() const
{
return m_isAd;
}
inline const QString &PlayerWatcher::title() const
{
return m_title;
@ -97,11 +118,16 @@ inline unsigned int PlayerWatcher::diskNumber() const
return m_diskNumber;
}
inline unsigned long long PlayerWatcher::length() const
inline ChronoUtilities::TimeSpan PlayerWatcher::length() const
{
return m_length;
}
inline void PlayerWatcher::setSilent(bool silent)
{
m_silent = silent;
}
}
#endif // PLAYERWATCHER_H