File indexing completed on 2024-05-05 04:50:49

0001 /*
0002  * SPDX-FileCopyrightText: 2021 George Florea Bănuș <georgefb899@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #include "mediaplayer2player.h"
0008 
0009 #include <KFileMetaData/ExtractorCollection>
0010 #include <KFileMetaData/SimpleExtractionResult>
0011 
0012 #include <QBuffer>
0013 #include <QDBusConnection>
0014 #include <QDBusMessage>
0015 #include <QDBusObjectPath>
0016 #include <QImage>
0017 
0018 #include "application.h"
0019 #include "mpvitem.h"
0020 #include "mpvproperties.h"
0021 #include "videosettings.h"
0022 #include "worker.h"
0023 
0024 MediaPlayer2Player::MediaPlayer2Player(QObject *parent)
0025     : QDBusAbstractAdaptor(parent)
0026     , m_mpv{static_cast<MpvItem *>(parent)}
0027 {
0028     connect(m_mpv, &MpvItem::fileLoaded, this, [=]() {
0029         if (m_mpv->currentUrl().isLocalFile()) {
0030             Q_EMIT requestMprisThumbnail(m_mpv->currentUrl().toLocalFile(), 250);
0031         }
0032     });
0033 
0034     connect(this, &MediaPlayer2Player::requestMprisThumbnail, Worker::instance(), &Worker::mprisThumbnail);
0035 
0036     connect(Worker::instance(), &Worker::mprisThumbnailSuccess, this, [=](const QImage &image) {
0037         m_image = image;
0038         propertiesChanged(QStringLiteral("Metadata"), Metadata());
0039         Q_EMIT metadataChanged();
0040     });
0041 
0042     connect(m_mpv, &MpvItem::mediaTitleChanged, this, [=]() {
0043         auto title = m_mpv->mediaTitle();
0044         if (title.isEmpty() || title.startsWith(QStringLiteral("watch"))) {
0045             return;
0046         }
0047         m_image = QImage();
0048         propertiesChanged(QStringLiteral("Metadata"), Metadata());
0049         Q_EMIT metadataChanged();
0050     });
0051 
0052     connect(m_mpv, &MpvItem::durationChanged, this, [=]() {
0053         m_metadata.insert(QStringLiteral("mpris:length"), m_mpv->duration() * 1000 * 1000);
0054         propertiesChanged(QStringLiteral("Metadata"), m_metadata);
0055     });
0056 
0057     connect(m_mpv, &MpvItem::pauseChanged, this, [=]() {
0058         propertiesChanged(QStringLiteral("PlaybackStatus"), PlaybackStatus());
0059         Q_EMIT playbackStatusChanged();
0060     });
0061 
0062     connect(m_mpv, &MpvItem::volumeChanged, this, [=]() {
0063         propertiesChanged(QStringLiteral("Volume"), Volume());
0064         Q_EMIT volumeChanged();
0065     });
0066 }
0067 
0068 void MediaPlayer2Player::propertiesChanged(const QString &property, const QVariant &value)
0069 {
0070     QVariantMap properties;
0071     properties[property] = value;
0072 
0073     QDBusMessage msg = QDBusMessage::createSignal(QStringLiteral("/org/mpris/MediaPlayer2"),
0074                                                   QStringLiteral("org.freedesktop.DBus.Properties"),
0075                                                   QStringLiteral("PropertiesChanged"));
0076     msg << QStringLiteral("org.mpris.MediaPlayer2.Player") << properties << QStringList();
0077 
0078     QDBusConnection::sessionBus().send(msg);
0079 }
0080 
0081 QVariantMap MediaPlayer2Player::Metadata()
0082 {
0083     auto url = m_mpv->currentUrl();
0084 
0085     m_metadata.insert(QStringLiteral("xesam:title"), m_mpv->mediaTitle());
0086     m_metadata.insert(QStringLiteral("mpris:trackid"), QVariant::fromValue<QDBusObjectPath>(QDBusObjectPath(QStringLiteral("/org/kde/haruna"))));
0087     m_metadata.insert(QStringLiteral("mpris:artUrl"), getThumbnail(url.toLocalFile()));
0088     m_metadata.insert(QStringLiteral("xesam:url"), url.toString());
0089 
0090     return m_metadata;
0091 }
0092 
0093 QString MediaPlayer2Player::getThumbnail(const QString &path)
0094 {
0095     auto url = QUrl::fromUserInput(path);
0096     if (!url.isLocalFile()) {
0097         return QString();
0098     }
0099 
0100     QString mimeType = Application::mimeType(url);
0101     KFileMetaData::ExtractorCollection exCol;
0102     QList<KFileMetaData::Extractor *> extractors = exCol.fetchExtractors(mimeType);
0103     KFileMetaData::SimpleExtractionResult result(path, mimeType, KFileMetaData::ExtractionResult::ExtractImageData);
0104 
0105     if (extractors.size() > 0) {
0106         KFileMetaData::Extractor *ex = extractors.first();
0107         ex->extract(&result);
0108         QString base64 = QStringLiteral("data:image/png;base64,");
0109         auto imageData = result.imageData();
0110         if (!imageData.isEmpty()) {
0111             // look for image inside the file
0112             using namespace KFileMetaData;
0113             if (imageData.contains(EmbeddedImageData::MovieScreenCapture)) {
0114                 return base64.append(QString::fromUtf8(imageData[EmbeddedImageData::MovieScreenCapture].toBase64()));
0115             } else if (imageData.contains(EmbeddedImageData::FrontCover)) {
0116                 return base64.append(QString::fromUtf8(imageData[EmbeddedImageData::FrontCover].toBase64()));
0117             } else if (imageData.contains(EmbeddedImageData::BackCover)) {
0118                 return base64.append(QString::fromUtf8(imageData[EmbeddedImageData::BackCover].toBase64()));
0119             } else if (imageData.contains(EmbeddedImageData::Other)) {
0120                 return base64.append(QString::fromUtf8(imageData[EmbeddedImageData::Other].toBase64()));
0121             } else {
0122                 return base64.append(QString::fromUtf8(imageData[EmbeddedImageData::Unknown].toBase64()));
0123             }
0124         } else {
0125             QImage image = m_image;
0126             if (image.isNull()) {
0127                 return VideoSettings::defaultCover();
0128             } else {
0129                 QByteArray byteArray;
0130                 QBuffer buffer(&byteArray);
0131                 image.save(&buffer, "JPEG");
0132                 return base64.append(QString::fromUtf8(byteArray.toBase64().data()));
0133             }
0134         }
0135     }
0136     return QString();
0137 }
0138 
0139 void MediaPlayer2Player::Next()
0140 {
0141     Q_EMIT next();
0142 }
0143 
0144 void MediaPlayer2Player::Previous()
0145 {
0146     Q_EMIT previous();
0147 }
0148 
0149 void MediaPlayer2Player::Pause()
0150 {
0151     Q_EMIT pause();
0152 }
0153 
0154 void MediaPlayer2Player::PlayPause()
0155 {
0156     Q_EMIT playpause();
0157 }
0158 
0159 void MediaPlayer2Player::Stop()
0160 {
0161     Q_EMIT stop();
0162 }
0163 
0164 void MediaPlayer2Player::Play()
0165 {
0166     Q_EMIT play();
0167 }
0168 
0169 void MediaPlayer2Player::Seek(qlonglong offset)
0170 {
0171     Q_EMIT seek(offset / 1000 / 1000);
0172 }
0173 
0174 void MediaPlayer2Player::SetPosition(const QDBusObjectPath &trackId, qlonglong pos)
0175 {
0176     Q_UNUSED(trackId)
0177     m_mpv->setProperty(MpvProperties::self()->Position, pos / 1000 / 1000);
0178 }
0179 
0180 void MediaPlayer2Player::OpenUri(const QString &uri)
0181 {
0182     Q_EMIT openUri(uri);
0183 }
0184 
0185 QString MediaPlayer2Player::PlaybackStatus()
0186 {
0187     bool isPaused = m_mpv->pause();
0188     double position = m_mpv->position();
0189 
0190     return isPaused && position == 0 ? QStringLiteral("Stopped") : (isPaused ? QStringLiteral("Paused") : QStringLiteral("Playing"));
0191 }
0192 
0193 double MediaPlayer2Player::Volume()
0194 {
0195     return m_mpv->volume() / 100;
0196 }
0197 
0198 void MediaPlayer2Player::setVolume(double vol)
0199 {
0200     m_mpv->setProperty(MpvProperties::self()->Volume, vol * 100);
0201 }
0202 
0203 qlonglong MediaPlayer2Player::Position()
0204 {
0205     return m_mpv->position() * 1000 * 1000;
0206 }
0207 
0208 void MediaPlayer2Player::setPosition(int pos)
0209 {
0210     m_mpv->setProperty(MpvProperties::self()->Position, pos);
0211 }
0212 
0213 bool MediaPlayer2Player::CanGoNext()
0214 {
0215     return true;
0216 }
0217 
0218 bool MediaPlayer2Player::CanGoPrevious()
0219 {
0220     return true;
0221 }
0222 
0223 bool MediaPlayer2Player::CanPlay()
0224 {
0225     return true;
0226 }
0227 
0228 bool MediaPlayer2Player::CanPause()
0229 {
0230     return true;
0231 }
0232 
0233 bool MediaPlayer2Player::CanSeek()
0234 {
0235     return true;
0236 }
0237 
0238 bool MediaPlayer2Player::CanControl()
0239 {
0240     return true;
0241 }
0242 
0243 #include "moc_mediaplayer2player.cpp"