#include "player.h" // HOLY GRAIL // https://doc.qt.io/qt-6/qaudiobufferoutput.htmli t Player::Player(QObject *parent) : QObject(parent), player(this), output(this), manager(this) { QObject::connect(&this->player, &QMediaPlayer::mediaStatusChanged, this, [this] () { const QMediaPlayer::MediaStatus status = this->player.mediaStatus(); if (status == QMediaPlayer::NoMedia) { qDebug("Player::Player(): NoMedia"); this->stop(); } else if (status == QMediaPlayer::BufferingMedia || status == QMediaPlayer::LoadingMedia) { qDebug("Player::Player() loadingChanged"); this->m_loading = true; emit this->loadingChanged(); } else if (status == QMediaPlayer::EndOfMedia) { qDebug("Player::Player() playingChanged"); emit this->playingChanged(); } else { this->m_loading = false; emit this->loadingChanged(); if (!this->m_initialLoadFinished) { this->m_initialLoadFinished = true; this->play(); } } }); QObject::connect(&this->player, &QMediaPlayer::positionChanged, this, [this] () { this->m_position = this->player.position(); emit this->positionChanged(); }); QObject::connect(&this->player, &QMediaPlayer::bufferProgressChanged, this, [this] () { this->m_buffered = this->player.bufferedTimeRange().latestTime() / this->m_duration; emit this->bufferedChanged(); }); QObject::connect(&this->player, &QMediaPlayer::errorOccurred, this, [this] () { this->m_failed = true; qDebug("Player::Player() failedChanged"); emit this->failedChanged(); }); QObject::connect(&this->player, &QMediaPlayer::playbackStateChanged, this, [this] () { qDebug("Player::Player() playingChanged"); emit this->playingChanged(); }); QObject::connect(&this->output, &QAudioOutput::volumeChanged, this, [this] () { emit this->volumeChanged(); }); this->output.setVolume(0.2); this->player.setAudioOutput(&this->output); qDebug("Player::Player(): Constructed"); } Player::~Player() { qDebug("Player::~Player(): Destructed"); } // ******** // Read // ******** bool Player::playing() const { return this->player.playbackState() == QMediaPlayer::PlayingState; } float Player::volume() const { return this->output.volume(); } // ********* // Write // ********* void Player::setVolume(float newVolume) { this->output.setVolume(newVolume); } void Player::setPosition(float newPosition) { this->player.setPosition(newPosition); } // *********** // Methods // *********** void Player::loadVideo(QString id) { if (this->m_active) { this->unloadVideo(); } QNetworkReply* reply = this->manager.get(QNetworkRequest(QUrl("https://youvideo.nonamesoft.xyz/youvideo/video/" + id))); QEventLoop loop(this); QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); loop.exec(); if (reply->error() != QNetworkReply::NoError) { qDebug() << "Player::loadVideo(): Video " << id << " doesn't exist!\n"; delete reply; return; } const QJsonDocument data = QJsonDocument::fromJson(reply->readAll()); this->player.setSource(QUrl("https://youvideo.nonamesoft.xyz/youvideo/api/videofile/with_extension/" + id + data ["extension"].toString())); this->m_title = data["name"].toString(); emit this->titleChanged(); this->m_description = data["description"].toString(); emit this->descriptionChanged(); this->m_id = id; emit this->idChanged(); this->m_initialLoadFinished = false; this->m_active = true; emit this->activeChanged(); this->m_duration = data["metadata"]["duration"].toDouble() * 1000; emit this->durationChanged(); this->m_position = 0; emit this->positionChanged(); this->m_buffered = 0; emit this->bufferedChanged(); this->m_loading = true; emit this->loadingChanged(); this->m_failed = false; emit this->failedChanged(); qDebug() << "Player::loadVideo(): Loaded video https://youvideo.nonamesoft.xyz/youvideo/api/videofile/with_extension/" + id + data ["extension"].toString(); delete reply; } void Player::unloadVideo() { qDebug("Player::unloadVideo(): Video unloaded"); this->player.setSource(QUrl("")); this->player.stop(); this->m_failed = false; emit this->activeChanged(); this->m_active = false; emit this->activeChanged(); } void Player::play() { if (!this->m_active || this->m_loading) { return; } this->player.play(); } void Player::pause() { if (!this->m_active || this->m_loading) { return; } this->player.pause(); } void Player::stop() { if (!this->m_active || this->m_loading) { return; } this->player.stop(); this->unloadVideo(); }