From a5936281d71713dd70e7d591818173ce766d94c5 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 10 Oct 2015 21:35:16 +0200 Subject: [PATCH] improved compatibility with latest version of Yfitops --- ffmpeglauncher.cpp | 229 ++++++++++++++++++++++++++------------------- ffmpeglauncher.h | 16 +++- main.cpp | 18 +++- playerwatcher.cpp | 72 ++++++++++---- playerwatcher.h | 38 ++++++-- 5 files changed, 243 insertions(+), 130 deletions(-) diff --git a/ffmpeglauncher.cpp b/ffmpeglauncher.cpp index 3d4ace0..2d1ba14 100644 --- a/ffmpeglauncher.cpp +++ b/ffmpeglauncher.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -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(&QProcess::error), this, &FfmpegLauncher::ffmpegError); connect(m_ffmpeg, static_cast(&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(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(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() diff --git a/ffmpeglauncher.h b/ffmpeglauncher.h index 0c4f656..f60fe11 100644 --- a/ffmpeglauncher.h +++ b/ffmpeglauncher.h @@ -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); } diff --git a/main.cpp b/main.cpp index 3fb3c9d..d59e4a6 100644 --- a/main.cpp +++ b/main.cpp @@ -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; } diff --git a/playerwatcher.cpp b/playerwatcher.cpp index aa31248..af6edf8 100644 --- a/playerwatcher.cpp +++ b/playerwatcher.cpp @@ -9,6 +9,7 @@ #include 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; diff --git a/playerwatcher.h b/playerwatcher.h index 3dbe3d8..2b7bedc 100644 --- a/playerwatcher.h +++ b/playerwatcher.h @@ -1,6 +1,8 @@ #ifndef PLAYERWATCHER_H #define PLAYERWATCHER_H +#include + #include 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