diff options
Diffstat (limited to 'transferengine-plugins/fediversetransferplugin/fediverseuploader.cpp')
| -rw-r--r-- | transferengine-plugins/fediversetransferplugin/fediverseuploader.cpp | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/transferengine-plugins/fediversetransferplugin/fediverseuploader.cpp b/transferengine-plugins/fediversetransferplugin/fediverseuploader.cpp new file mode 100644 index 0000000..7c8766b --- /dev/null +++ b/transferengine-plugins/fediversetransferplugin/fediverseuploader.cpp @@ -0,0 +1,252 @@ +/* + * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fediverseuploader.h" +#include "fediverseapi.h" + +#include <imageoperation.h> +#include <mediaitem.h> + +#include <QtCore/QFile> +#include <QtCore/QMimeDatabase> +#include <QtCore/QMimeType> + +#include <QtDebug> + +FediverseUploader::FediverseUploader(QNetworkAccessManager *qnam, QObject *parent) + : MediaTransferInterface(parent) + , m_api(0) + , m_fediverseShareServiceStatus(0) + , m_qnam(qnam) + , m_useTmpFile(false) +{ +} + +FediverseUploader::~FediverseUploader() +{ +} + +QString FediverseUploader::displayName() const +{ + return tr("Fediverse"); +} + +QUrl FediverseUploader::serviceIcon() const +{ + return QUrl(QStringLiteral("image://theme/icon-l-fediverse")); +} + +bool FediverseUploader::cancelEnabled() const +{ + return true; +} + +bool FediverseUploader::restartEnabled() const +{ + return true; +} + +void FediverseUploader::start() +{ + if (!mediaItem()) { + qWarning() << Q_FUNC_INFO << "NULL MediaItem. Can't continue"; + setStatus(MediaTransferInterface::TransferInterrupted); + return; + } + + if (!m_fediverseShareServiceStatus) { + m_fediverseShareServiceStatus = new FediverseShareServiceStatus(this); + connect(m_fediverseShareServiceStatus, &FediverseShareServiceStatus::serviceReady, + this, &FediverseUploader::startUploading); + connect(m_fediverseShareServiceStatus, &FediverseShareServiceStatus::serviceError, + this, [this] (const QString &) { + transferError(); + }); + } + + m_fediverseShareServiceStatus->queryStatus(); +} + +void FediverseUploader::cancel() +{ + if (m_api) { + m_api->cancelUpload(); + } else { + qWarning() << Q_FUNC_INFO << "Can't cancel. NULL FediverseApi object!"; + } +} + +void FediverseUploader::startUploading() +{ + if (!m_fediverseShareServiceStatus) { + qWarning() << Q_FUNC_INFO << "NULL FediverseShareServiceStatus object!"; + return; + } + + const quint32 accountId = mediaItem()->value(MediaItem::AccountId).toInt(); + m_accountDetails = m_fediverseShareServiceStatus->detailsByIdentifier(accountId); + if (m_accountDetails.accountId <= 0 || m_accountDetails.accessToken.isEmpty()) { + qWarning() << Q_FUNC_INFO << "Fediverse account details missing for id" << accountId; + transferError(); + return; + } + + const QString mimeType = mediaItem()->value(MediaItem::MimeType).toString(); + if (mimeType.startsWith(QLatin1String("image/")) + || mimeType.startsWith(QLatin1String("video/"))) { + postImage(); + } else if (mimeType.contains(QLatin1String("text/plain")) + || mimeType.contains(QLatin1String("text/x-url"))) { + postStatus(); + } else { + qWarning() << Q_FUNC_INFO << "Unsupported mime type:" << mimeType; + setStatus(MediaTransferInterface::TransferInterrupted); + } +} + +void FediverseUploader::transferFinished() +{ + setStatus(MediaTransferInterface::TransferFinished); +} + +void FediverseUploader::transferProgress(qreal progress) +{ + setProgress(progress); +} + +void FediverseUploader::transferError() +{ + setStatus(MediaTransferInterface::TransferInterrupted); + qWarning() << Q_FUNC_INFO << "Transfer interrupted"; +} + +void FediverseUploader::transferCanceled() +{ + setStatus(MediaTransferInterface::TransferCanceled); +} + +void FediverseUploader::credentialsExpired() +{ + const quint32 accountId = mediaItem()->value(MediaItem::AccountId).toInt(); + m_fediverseShareServiceStatus->setCredentialsNeedUpdate(accountId, QStringLiteral("fediverse-sharing")); +} + +void FediverseUploader::setStatus(MediaTransferInterface::TransferStatus status) +{ + const bool finished = (status == TransferCanceled + || status == TransferInterrupted + || status == TransferFinished); + if (m_useTmpFile && finished) { + QFile::remove(m_filePath); + m_useTmpFile = false; + m_filePath.clear(); + } + + MediaTransferInterface::setStatus(status); +} + +void FediverseUploader::postImage() +{ + m_useTmpFile = false; + m_filePath.clear(); + const QString sourceFile = mediaItem()->value(MediaItem::Url).toUrl().toLocalFile(); + if (sourceFile.isEmpty()) { + qWarning() << Q_FUNC_INFO << "Empty source file"; + setStatus(MediaTransferInterface::TransferInterrupted); + return; + } + + QMimeDatabase db; + const QMimeType mime = db.mimeTypeForFile(sourceFile); + const bool isImage = mediaItem()->value(MediaItem::MimeType).toString().startsWith(QLatin1String("image/")); + const bool isJpeg = isImage && mime.name() == QLatin1String("image/jpeg"); + + if (isJpeg && mediaItem()->value(MediaItem::MetadataStripped).toBool()) { + m_useTmpFile = true; + m_filePath = ImageOperation::removeImageMetadata(sourceFile); + if (m_filePath.isEmpty()) { + qWarning() << Q_FUNC_INFO << "Failed to remove metadata"; + MediaTransferInterface::setStatus(MediaTransferInterface::TransferInterrupted); + return; + } + } + + const qreal scale = mediaItem()->value(MediaItem::ScalePercent).toReal(); + if (isImage && 0 < scale && scale < 1) { + m_useTmpFile = true; + m_filePath = ImageOperation::scaleImage(sourceFile, scale, m_filePath); + if (m_filePath.isEmpty()) { + qWarning() << Q_FUNC_INFO << "Failed to scale image"; + MediaTransferInterface::setStatus(MediaTransferInterface::TransferInterrupted); + return; + } + } + + if (!m_useTmpFile) { + m_filePath = sourceFile; + } + + ensureApi(); + + const bool ok = m_api->uploadImage(m_filePath, + mediaItem()->value(MediaItem::Description).toString(), + mediaItem()->value(MediaItem::MimeType).toString(), + m_accountDetails.apiHost, + m_accountDetails.accessToken); + if (ok) { + setStatus(MediaTransferInterface::TransferStarted); + } else { + setStatus(MediaTransferInterface::TransferInterrupted); + qWarning() << Q_FUNC_INFO << "Failed to upload media"; + } +} + +void FediverseUploader::postStatus() +{ + ensureApi(); + + const QVariantMap userData = mediaItem()->value(MediaItem::UserData).toMap(); + QString statusText = userData.value(QStringLiteral("status")).toString().trimmed(); + if (statusText.isEmpty()) { + statusText = mediaItem()->value(MediaItem::Description).toString().trimmed(); + } + if (statusText.isEmpty()) { + statusText = mediaItem()->value(MediaItem::ContentData).toString().trimmed(); + } + + if (statusText.isEmpty()) { + qWarning() << Q_FUNC_INFO << "Failed to resolve status text"; + setStatus(MediaTransferInterface::TransferInterrupted); + return; + } + + const bool ok = m_api->postStatus(statusText, + m_accountDetails.apiHost, + m_accountDetails.accessToken); + if (ok) { + setStatus(MediaTransferInterface::TransferStarted); + } else { + setStatus(MediaTransferInterface::TransferInterrupted); + qWarning() << Q_FUNC_INFO << "Failed to post status"; + } +} + +void FediverseUploader::ensureApi() +{ + if (!m_api) { + m_api = new FediverseApi(m_qnam, this); + connect(m_api, &FediverseApi::transferProgressUpdated, + this, &FediverseUploader::transferProgress); + connect(m_api, &FediverseApi::transferFinished, + this, &FediverseUploader::transferFinished); + connect(m_api, &FediverseApi::transferError, + this, &FediverseUploader::transferError); + connect(m_api, &FediverseApi::transferCanceled, + this, &FediverseUploader::transferCanceled); + connect(m_api, &FediverseApi::credentialsExpired, + this, &FediverseUploader::credentialsExpired); + } +} |
