File indexing completed on 2025-02-23 04:35:15
0001 // SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com> 0002 // SPDX-License-Identifier: GPL-3.0-or-later 0003 0004 #include "videocontroller.h" 0005 0006 #include "config.h" 0007 #include "plasmatube.h" 0008 0009 #ifdef HAS_DBUS 0010 #include <KLocalizedString> 0011 #include <QDBusConnection> 0012 #include <QDBusMessage> 0013 #include <QDBusReply> 0014 #include <QGuiApplication> 0015 #endif 0016 0017 VideoController::VideoController(QObject *parent) 0018 : QObject(parent) 0019 , m_videoModel(new VideoModel(this)) 0020 , m_videoQueue(new VideoQueue(this)) 0021 , m_mpris(new Mpris2(this)) 0022 { 0023 connect(m_videoModel, &VideoModel::videoChanged, this, [this] { 0024 Q_EMIT currentVideoChanged(); 0025 }); 0026 connect(m_videoQueue, &VideoQueue::currentVideoChanged, this, [this] { 0027 // If the user is attempting to "play" the same video, they probably meant to open the player 0028 if (currentVideo() && currentVideo()->videoId() == m_videoQueue->getCurrentVideoId()) { 0029 openPlayer(); 0030 return; 0031 } 0032 0033 m_videoModel->fetch(m_videoQueue->getCurrentVideoId()); 0034 0035 openPlayer(); 0036 }); 0037 connect(this, &VideoController::playbackStateChanged, this, [this] { 0038 const bool paused = m_currentPlayer->paused(); 0039 const bool durationMatchesPosition = abs(m_currentPlayer->duration() - m_currentPlayer->position()) < 0.1; 0040 const bool notAtBeginning = m_currentPlayer->position() > 1; 0041 0042 if (paused && durationMatchesPosition && notAtBeginning) { 0043 m_videoQueue->next(); 0044 } 0045 0046 const bool shouldInhibit = currentPlayer() && !currentPlayer()->paused(); 0047 0048 #ifdef HAS_DBUS 0049 if (shouldInhibit) { 0050 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.ScreenSaver"), 0051 QStringLiteral("/ScreenSaver"), 0052 QStringLiteral("org.freedesktop.ScreenSaver"), 0053 QStringLiteral("Inhibit")); 0054 message << QGuiApplication::desktopFileName(); 0055 message << i18n("Playing video"); 0056 0057 QDBusReply<uint> reply = QDBusConnection::sessionBus().call(message); 0058 if (reply.isValid()) { 0059 screenSaverDbusCookie = reply.value(); 0060 } 0061 } else { 0062 if (screenSaverDbusCookie != 0) { 0063 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.ScreenSaver"), 0064 QStringLiteral("/ScreenSaver"), 0065 QStringLiteral("org.freedesktop.ScreenSaver"), 0066 QStringLiteral("UnInhibit")); 0067 message << static_cast<uint>(screenSaverDbusCookie); 0068 screenSaverDbusCookie = 0; 0069 QDBusConnection::sessionBus().send(message); 0070 } 0071 } 0072 #endif 0073 }); 0074 } 0075 0076 void VideoController::play(const QString &videoId) 0077 { 0078 if (videoId.isEmpty()) { 0079 qWarning() << "Not trying to play an empty video id."; 0080 return; 0081 } 0082 0083 m_videoQueue->replace({videoId}); 0084 } 0085 0086 void VideoController::queueNext(const QString &videoId) 0087 { 0088 if (videoId.isEmpty()) { 0089 qWarning() << "Not trying to queue an empty video id."; 0090 return; 0091 } 0092 0093 m_videoQueue->queueNext(videoId); 0094 } 0095 0096 void VideoController::togglePlaying() 0097 { 0098 if (m_currentPlayer != nullptr) { 0099 const bool paused = m_currentPlayer->paused(); 0100 const bool durationMatchesPosition = abs(m_currentPlayer->duration() - m_currentPlayer->position()) < 0.1; 0101 const bool notAtBeginning = m_currentPlayer->position() > 1; 0102 0103 if (paused && durationMatchesPosition && notAtBeginning) { 0104 m_currentPlayer->setPosition(0); 0105 } 0106 0107 if (m_currentPlayer->paused()) { 0108 m_currentPlayer->play(); 0109 } else { 0110 m_currentPlayer->pause(); 0111 } 0112 } 0113 } 0114 0115 void VideoController::stop() 0116 { 0117 if (m_currentPlayer != nullptr) { 0118 Q_EMIT m_currentPlayer->command(QStringList() << QStringLiteral("stop")); 0119 videoModel()->clearVideo(); 0120 } 0121 } 0122 0123 void VideoController::previous() 0124 { 0125 m_videoQueue->previous(); 0126 } 0127 0128 void VideoController::next() 0129 { 0130 m_videoQueue->next(); 0131 } 0132 0133 VideoController::VideoMode VideoController::videoMode() const 0134 { 0135 return m_videoMode; 0136 } 0137 0138 void VideoController::setVideoMode(VideoController::VideoMode mode) 0139 { 0140 if (mode != m_videoMode) { 0141 m_videoMode = mode; 0142 Q_EMIT videoModeChanged(); 0143 0144 openPlayer(); 0145 } 0146 } 0147 0148 MpvObject *VideoController::currentPlayer() const 0149 { 0150 return m_currentPlayer; 0151 } 0152 0153 void VideoController::setCurrentPlayer(MpvObject *mpvObject) 0154 { 0155 std::optional<qreal> oldPosition; 0156 if (mpvObject != m_currentPlayer) { 0157 // stop existing player 0158 if (m_currentPlayer != nullptr) { 0159 Q_EMIT m_currentPlayer->command(QStringList() << QStringLiteral("stop")); 0160 oldPosition = m_currentPlayer->position(); 0161 } 0162 0163 m_currentPlayer->disconnect(this); 0164 0165 m_currentPlayer = mpvObject; 0166 Q_EMIT currentPlayerChanged(); 0167 } 0168 0169 m_currentPlayer->setProperty(QStringLiteral("pause"), !PlasmaTube::instance().selectedSource()->preferences().autoPlay()); 0170 0171 Q_EMIT m_currentPlayer->command(QStringList() << QStringLiteral("stop")); 0172 // See https://github.com/mpv-player/mpv/issues/10029 why this is needed 0173 if (PlasmaTube::instance().selectedSource()->type() == VideoSource::Type::PeerTube) { 0174 m_currentPlayer->setProperty(QStringLiteral("stream-lavf-o"), QStringLiteral("seekable=0")); 0175 } else { 0176 m_currentPlayer->setProperty(QStringLiteral("stream-lavf-o"), QStringLiteral("")); 0177 } 0178 0179 PlasmaTubeSettings settings(KSharedConfig::openConfig(QStringLiteral("plasmatuberc"), KConfig::SimpleConfig, QStandardPaths::AppConfigLocation)); 0180 if (settings.proxyType() == 1) { 0181 QString proxyString = QStringLiteral("http://%1:%2@%3:%4") 0182 .arg(settings.proxyUser(), settings.proxyPassword(), settings.proxyHost(), QString::number(settings.proxyPort())); 0183 m_currentPlayer->setProperty(QStringLiteral("http-proxy"), proxyString); 0184 m_currentPlayer->setProperty(QStringLiteral("ytdl-raw-options"), proxyString); 0185 } 0186 0187 Q_EMIT m_currentPlayer->command(QStringList() << QStringLiteral("loadfile") 0188 << PlasmaTube::instance().selectedSource()->api()->resolveVideoUrl(m_videoModel->videoId())); 0189 m_currentPlayer->setProperty(QStringLiteral("ytdl-format"), QStringLiteral("best")); 0190 0191 connect(m_currentPlayer, &MpvObject::positionChanged, this, &VideoController::positionChanged); 0192 connect(m_currentPlayer, &MpvObject::durationChanged, this, &VideoController::durationChanged); 0193 connect(m_currentPlayer, &MpvObject::pausedChanged, this, &VideoController::playbackStateChanged); 0194 connect(m_currentPlayer, &MpvObject::stoppedChanged, this, &VideoController::playbackStateChanged); 0195 0196 // Restore old position if we had an existing player 0197 if (oldPosition != std::nullopt) { 0198 qDebug() << "Attempting to restore position to" << *oldPosition; 0199 connect(m_currentPlayer, &MpvObject::stoppedChanged, this, [this, oldPosition] { 0200 m_currentPlayer->seek(*oldPosition); 0201 qDebug() << "Set old position..."; 0202 0203 disconnect(m_currentPlayer); 0204 }); 0205 } 0206 } 0207 0208 VideoItem *VideoController::currentVideo() const 0209 { 0210 return m_videoModel->video(); 0211 } 0212 0213 VideoModel *VideoController::videoModel() const 0214 { 0215 return m_videoModel; 0216 } 0217 0218 VideoQueue *VideoController::videoQueue() const 0219 { 0220 return m_videoQueue; 0221 } 0222 0223 void VideoController::openPlayer() 0224 { 0225 if (m_videoMode == VideoMode::Normal) { 0226 Q_EMIT openNormalPlayer(); 0227 } else { 0228 Q_EMIT openPiPPlayer(); 0229 } 0230 } 0231 0232 qreal VideoController::position() const 0233 { 0234 return m_currentPlayer->position(); 0235 } 0236 0237 void VideoController::setPosition(qreal position) 0238 { 0239 return m_currentPlayer->setPosition(position); 0240 } 0241 0242 qreal VideoController::duration() const 0243 { 0244 return m_currentPlayer->duration(); 0245 } 0246 0247 bool VideoController::paused() const 0248 { 0249 return m_currentPlayer->paused(); 0250 } 0251 0252 void VideoController::pause() 0253 { 0254 return m_currentPlayer->pause(); 0255 } 0256 0257 void VideoController::play() 0258 { 0259 return m_currentPlayer->play(); 0260 } 0261 0262 bool VideoController::stopped() const 0263 { 0264 return m_currentPlayer->stopped(); 0265 } 0266 0267 bool VideoController::hasVideo() const 0268 { 0269 return m_currentPlayer != nullptr && currentVideo() != nullptr && currentVideo()->isLoaded(); 0270 } 0271 0272 #include "moc_videocontroller.cpp"