File indexing completed on 2024-05-19 04:03:04

0001 /*
0002     SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include "youtubejob.h"
0008 #include <KPasswordDialog>
0009 
0010 #include <KIO/StoredTransferJob>
0011 #include <QDebug>
0012 #include <QJsonDocument>
0013 #include <QJsonObject>
0014 #include <QNetworkReply>
0015 
0016 static const QUrl apiUrl(QStringLiteral("https://www.googleapis.com/upload/youtube/v3/videos?part=snippet%2Cstatus&uploadType=resumable"));
0017 static const QString watchUrl = QStringLiteral("https://www.youtube.com/watch?v=");
0018 
0019 YoutubeJob::YoutubeJob(const QUrl &url,
0020                        const QByteArray &accessToken,
0021                        const QString &title,
0022                        const QStringList &tags,
0023                        const QString &description,
0024                        QObject *parent)
0025     : KJob(parent)
0026     , m_url(url)
0027     , m_token(accessToken)
0028 {
0029     m_metadata = QByteArray("{ "
0030         "\"snippet\": {"
0031             "\"title\": \"" + title.toUtf8() + "\", "
0032             "\"categoryId\": \"22\", "
0033             "\"description\": \"" + description.toUtf8() + "\", "
0034             "\"tags\": [ \"" + tags.join(QStringLiteral("\", \"")).toUtf8() + "\" ] "
0035         "}, "
0036         "\"status\": { "
0037             "\"privacyStatus\": \"public\" "
0038         "} "
0039     "}");
0040 }
0041 
0042 void YoutubeJob::start()
0043 {
0044     createLocation();
0045 }
0046 
0047 void YoutubeJob::fileFetched(KJob *j)
0048 {
0049     if (j->error()) {
0050         setError(j->error());
0051         setErrorText(j->errorText());
0052         emitResult();
0053     }
0054     KIO::StoredTransferJob *job = qobject_cast<KIO::StoredTransferJob *>(j);
0055 
0056     uploadVideo(job->data());
0057 }
0058 
0059 void YoutubeJob::createLocation()
0060 {
0061     QNetworkRequest req(apiUrl);
0062     req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json; charset=UTF-8"));
0063     req.setRawHeader("Authorization", "Bearer " + m_token);
0064     req.setRawHeader("X-Upload-Content-Type", "video/*");
0065 
0066     auto reply = m_manager.post(req, m_metadata);
0067     connect(reply, &QNetworkReply::finished, this, &YoutubeJob::locationCreated);
0068     connect(reply, &QNetworkReply::errorOccurred, this, [](QNetworkReply::NetworkError e) {
0069         qDebug() << "creation error" << e;
0070     });
0071 }
0072 
0073 void YoutubeJob::locationCreated()
0074 {
0075     QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
0076     if (reply->error()) {
0077         setError(reply->error());
0078         setErrorText(reply->errorString());
0079         qWarning() << "couldn't upload file" << reply->readAll();
0080         emitResult();
0081         return;
0082     }
0083     Q_ASSERT(reply->atEnd());
0084     Q_ASSERT(reply->hasRawHeader("Location"));
0085 
0086     m_uploadUrl = QUrl::fromEncoded(reply->rawHeader("Location"));
0087 
0088     KIO::StoredTransferJob *job = KIO::storedGet(m_url);
0089     connect(job, &KJob::finished, this, &YoutubeJob::fileFetched);
0090 }
0091 
0092 void YoutubeJob::uploadVideo(const QByteArray &data)
0093 {
0094     QNetworkRequest req(m_uploadUrl);
0095     req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("video/*"));
0096     req.setRawHeader("X-Upload-Content-Length", QByteArray::number(data.size()));
0097     req.setRawHeader("Authorization", "Bearer " + m_token);
0098 
0099     setTotalAmount(Bytes, data.size());
0100     auto reply = m_manager.post(req, data);
0101     connect(reply, &QNetworkReply::finished, this, &YoutubeJob::videoUploaded);
0102     connect(reply, &QNetworkReply::uploadProgress, this, [this](quint64 bytesSent, quint64 bytesTotal) {
0103         setProcessedAmount(Bytes, bytesSent);
0104         setPercent(bytesTotal == 0 ? 0 : (bytesSent * 100) / bytesTotal);
0105     });
0106     connect(reply, &QNetworkReply::errorOccurred, this, [](QNetworkReply::NetworkError e) {
0107         qDebug() << "upload error" << e;
0108     });
0109 }
0110 
0111 void YoutubeJob::videoUploaded()
0112 {
0113     QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
0114     if (reply->error()) {
0115         setError(reply->error());
0116         setErrorText(reply->errorString());
0117         qWarning() << "couldn't finish upload" << reply->readAll();
0118         emitResult();
0119         return;
0120     }
0121 
0122     auto doc = QJsonDocument::fromJson(reply->readAll()).object();
0123     m_output = watchUrl + doc.value(QLatin1String("id")).toString();
0124     emitResult();
0125 }
0126 
0127 #include "moc_youtubejob.cpp"