/* * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fediverseuploader.h" #include "fediverseapi.h" #include #include #include #include #include #include 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); } }