Purpose

youtubejob.cpp
1/*
2 SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7#include "youtubejob.h"
8#include <KPasswordDialog>
9
10#include <KIO/StoredTransferJob>
11#include <QDebug>
12#include <QJsonDocument>
13#include <QJsonObject>
14#include <QNetworkReply>
15
16static const QUrl apiUrl(QStringLiteral("https://www.googleapis.com/upload/youtube/v3/videos?part=snippet%2Cstatus&uploadType=resumable"));
17static const QString watchUrl = QStringLiteral("https://www.youtube.com/watch?v=");
18
19YoutubeJob::YoutubeJob(const QUrl &url,
20 const QByteArray &accessToken,
21 const QString &title,
22 const QStringList &tags,
23 const QString &description,
24 QObject *parent)
25 : KJob(parent)
26 , m_url(url)
27 , m_token(accessToken)
28{
29 m_metadata = QByteArray("{ "
30 "\"snippet\": {"
31 "\"title\": \"" + title.toUtf8() + "\", "
32 "\"categoryId\": \"22\", "
33 "\"description\": \"" + description.toUtf8() + "\", "
34 "\"tags\": [ \"" + tags.join(QStringLiteral("\", \"")).toUtf8() + "\" ] "
35 "}, "
36 "\"status\": { "
37 "\"privacyStatus\": \"public\" "
38 "} "
39 "}");
40}
41
42void YoutubeJob::start()
43{
44 createLocation();
45}
46
47void YoutubeJob::fileFetched(KJob *j)
48{
49 if (j->error()) {
50 setError(j->error());
52 emitResult();
53 }
54 KIO::StoredTransferJob *job = qobject_cast<KIO::StoredTransferJob *>(j);
55
56 uploadVideo(job->data());
57}
58
59void YoutubeJob::createLocation()
60{
61 QNetworkRequest req(apiUrl);
62 req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json; charset=UTF-8"));
63 req.setRawHeader("Authorization", "Bearer " + m_token);
64 req.setRawHeader("X-Upload-Content-Type", "video/*");
65
66 auto reply = m_manager.post(req, m_metadata);
67 connect(reply, &QNetworkReply::finished, this, &YoutubeJob::locationCreated);
69 qDebug() << "creation error" << e;
70 });
71}
72
73void YoutubeJob::locationCreated()
74{
75 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
76 if (reply->error()) {
77 setError(reply->error());
78 setErrorText(reply->errorString());
79 qWarning() << "couldn't upload file" << reply->readAll();
80 emitResult();
81 return;
82 }
83 Q_ASSERT(reply->atEnd());
84 Q_ASSERT(reply->hasRawHeader("Location"));
85
86 m_uploadUrl = QUrl::fromEncoded(reply->rawHeader("Location"));
87
89 connect(job, &KJob::finished, this, &YoutubeJob::fileFetched);
90}
91
92void YoutubeJob::uploadVideo(const QByteArray &data)
93{
94 QNetworkRequest req(m_uploadUrl);
95 req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("video/*"));
96 req.setRawHeader("X-Upload-Content-Length", QByteArray::number(data.size()));
97 req.setRawHeader("Authorization", "Bearer " + m_token);
98
99 setTotalAmount(Bytes, data.size());
100 auto reply = m_manager.post(req, data);
101 connect(reply, &QNetworkReply::finished, this, &YoutubeJob::videoUploaded);
102 connect(reply, &QNetworkReply::uploadProgress, this, [this](quint64 bytesSent, quint64 bytesTotal) {
103 setProcessedAmount(Bytes, bytesSent);
104 setPercent(bytesTotal == 0 ? 0 : (bytesSent * 100) / bytesTotal);
105 });
107 qDebug() << "upload error" << e;
108 });
109}
110
111void YoutubeJob::videoUploaded()
112{
113 QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
114 if (reply->error()) {
115 setError(reply->error());
116 setErrorText(reply->errorString());
117 qWarning() << "couldn't finish upload" << reply->readAll();
118 emitResult();
119 return;
120 }
121
122 auto doc = QJsonDocument::fromJson(reply->readAll()).object();
123 m_output = watchUrl + doc.value(QLatin1String("id")).toString();
124 emitResult();
125}
126
127#include "moc_youtubejob.cpp"
QByteArray data() const
void setErrorText(const QString &errorText)
void setTotalAmount(Unit unit, qulonglong amount)
void emitResult()
int error() const
void finished(KJob *job)
void setPercent(unsigned long percentage)
void setError(int errorCode)
QString errorText() const
void setProcessedAmount(Unit unit, qulonglong amount)
KIOCORE_EXPORT StoredTransferJob * storedGet(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
QByteArray number(double n, char format, int precision)
qsizetype size() const const
virtual bool atEnd() const const
QString errorString() const const
QByteArray readAll()
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonObject object() const const
QNetworkReply * post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
NetworkError error() const const
void errorOccurred(QNetworkReply::NetworkError code)
bool hasRawHeader(const QByteArray &headerName) const const
QByteArray rawHeader(const QByteArray &headerName) const const
void uploadProgress(qint64 bytesSent, qint64 bytesTotal)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * sender() const const
QByteArray toUtf8() const const
QString join(QChar separator) const const
QUrl fromEncoded(const QByteArray &input, ParsingMode parsingMode)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:05 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.