File indexing completed on 2024-04-21 04:55:26

0001 /*
0002     This file is part of Choqok, the KDE micro-blogging client
0003 
0004     SPDX-FileCopyrightText: 2008-2012 Mehrdad Momeny <mehrdad.momeny@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 */
0008 
0009 #include "mediamanager.h"
0010 
0011 #include <QApplication>
0012 #include <QHash>
0013 #include <QIcon>
0014 #include <QMimeDatabase>
0015 
0016 #include <KEmoticons>
0017 #include <KEmoticonsTheme>
0018 #include <KImageCache>
0019 #include <KIO/StoredTransferJob>
0020 #include <KLocalizedString>
0021 #include <KMessageBox>
0022 
0023 #include "choqokbehaviorsettings.h"
0024 #include "choqokuiglobal.h"
0025 #include "libchoqokdebug.h"
0026 #include "pluginmanager.h"
0027 #include "uploader.h"
0028 
0029 namespace Choqok
0030 {
0031 
0032 class MediaManager::Private
0033 {
0034 public:
0035     Private()
0036         : emoticons(KEmoticons().theme()), cache(QLatin1String("choqok-userimages"), 30000000), uploader(nullptr)
0037     {}
0038     KEmoticonsTheme emoticons;
0039     KImageCache cache;
0040     QHash<KJob *, QUrl> queue;
0041     QPixmap defaultImage;
0042     Uploader *uploader;
0043 };
0044 
0045 MediaManager::MediaManager()
0046     : QObject(qApp), d(new Private)
0047 {
0048     d->defaultImage = QIcon::fromTheme(QLatin1String("image-loading")).pixmap(48);
0049 }
0050 
0051 MediaManager::~MediaManager()
0052 {
0053     delete d;
0054     mSelf = nullptr;
0055 }
0056 
0057 MediaManager *MediaManager::mSelf = nullptr;
0058 
0059 MediaManager *MediaManager::self()
0060 {
0061     if (!mSelf) {
0062         mSelf = new MediaManager;
0063     }
0064     return mSelf;
0065 }
0066 
0067 QPixmap &MediaManager::defaultImage()
0068 {
0069     return d->defaultImage;
0070 }
0071 
0072 QString MediaManager::parseEmoticons(const QString &text)
0073 {
0074     return d->emoticons.parseEmoticons(text, KEmoticonsTheme::DefaultParse, QStringList() << QLatin1String("(e)"));
0075 }
0076 
0077 QPixmap MediaManager::fetchImage(const QUrl &remoteUrl, ReturnMode mode /*= Sync*/)
0078 {
0079     QPixmap p;
0080     if (d->cache.findPixmap(remoteUrl.toDisplayString(), &p)) {
0081         Q_EMIT imageFetched(remoteUrl, p);
0082     } else if (mode == Async) {
0083         if (d->queue.values().contains(remoteUrl)) {
0084             ///The file is on the way, wait to download complete.
0085             return p;
0086         }
0087         KIO::StoredTransferJob *job = KIO::storedGet(remoteUrl, KIO::NoReload, KIO::HideProgressInfo) ;
0088         if (!job) {
0089             qCCritical(CHOQOK) << "Cannot create a FileCopyJob!";
0090             QString errMsg = i18n("Cannot create a KDE Job. Please check your installation.");
0091             Q_EMIT fetchError(remoteUrl, errMsg);
0092             return p;
0093         }
0094         d->queue.insert(job, remoteUrl);
0095         connect(job, &KIO::StoredTransferJob::result, this, &MediaManager::slotImageFetched);
0096         job->start();
0097     }
0098     return p;
0099 }
0100 
0101 void MediaManager::slotImageFetched(KJob *job)
0102 {
0103     KIO::StoredTransferJob *baseJob = qobject_cast<KIO::StoredTransferJob *>(job);
0104     QUrl remote = d->queue.value(job);
0105     d->queue.remove(job);
0106 
0107     int responseCode = 0;
0108     if (baseJob->metaData().contains(QStringLiteral("responsecode"))) {
0109         responseCode = baseJob->queryMetaData(QStringLiteral("responsecode")).toInt();
0110     }
0111 
0112     if (job->error() || (responseCode > 399 && responseCode < 600)) {
0113         qCCritical(CHOQOK) << "Job error:" << job->error() << "\t" << job->errorString();
0114         qCCritical(CHOQOK) << "HTTP response code" << responseCode;
0115         QString errMsg = i18n("Cannot download image from %1.", job->errorString());
0116         Q_EMIT fetchError(remote, errMsg);
0117     } else {
0118         QPixmap p;
0119         if (p.loadFromData(baseJob->data())) {
0120             d->cache.insertPixmap(remote.toDisplayString(), p);
0121             Q_EMIT imageFetched(remote, p);
0122         } else {
0123             qCCritical(CHOQOK) << "Cannot parse reply from " << baseJob->url().toDisplayString();
0124             Q_EMIT fetchError(remote, i18n("The request failed. Cannot get image file."));
0125         }
0126     }
0127 }
0128 
0129 void MediaManager::clearImageCache()
0130 {
0131     d->cache.clear();
0132 }
0133 
0134 QPixmap MediaManager::convertToGrayScale(const QPixmap &pic)
0135 {
0136     QImage result = pic.toImage();
0137     for (int y = 0; y < result.height(); ++y) {
0138         for (int x = 0; x < result.width(); ++x) {
0139             int pixel = result.pixel(x, y);
0140             int gray = qGray(pixel);
0141             int alpha = qAlpha(pixel);
0142             result.setPixel(x, y, qRgba(gray, gray, gray, alpha));
0143         }
0144     }
0145     return QPixmap::fromImage(result);
0146 }
0147 
0148 void MediaManager::uploadMedium(const QUrl &localUrl, const QString &pluginId)
0149 {
0150     QString pId = pluginId;
0151     if (pId.isEmpty()) {
0152         pId = Choqok::BehaviorSettings::lastUsedUploaderPlugin();
0153     }
0154     if (pId.isEmpty()) {
0155         Q_EMIT mediumUploadFailed(localUrl, i18n("No pluginId specified, And last used plugin is null."));
0156         return;
0157     }
0158     if (!d->uploader) {
0159         Plugin *plugin = PluginManager::self()->loadPlugin(pId);
0160         d->uploader = qobject_cast<Uploader *>(plugin);
0161     } else if (d->uploader->pluginId() != pId) {
0162 //         qCDebug(CHOQOK)<<"CREATING A NEW UPLOADER OBJECT";
0163         PluginManager::self()->unloadPlugin(d->uploader->pluginId());
0164         Plugin *plugin = PluginManager::self()->loadPlugin(pId);
0165         d->uploader = qobject_cast<Uploader *>(plugin);
0166     }
0167     if (!d->uploader) {
0168         return;
0169     }
0170     KIO::StoredTransferJob *picJob = KIO::storedGet(localUrl, KIO::Reload, KIO::HideProgressInfo);
0171     picJob->exec();
0172     if (picJob->error()) {
0173         qCritical() << "Job error:" << picJob->errorString();
0174         KMessageBox::detailedError(UI::Global::mainWindow(), i18n("Uploading medium failed: cannot read the medium file."),
0175                                    picJob->errorString());
0176         return;
0177     }
0178     const QByteArray picData = picJob->data();
0179     if (picData.count() == 0) {
0180         qCritical() << "Cannot read the media file, please check if it exists.";
0181         KMessageBox::error(UI::Global::mainWindow(), i18n("Uploading medium failed: cannot read the medium file."));
0182         return;
0183     }
0184     connect(d->uploader, &Uploader::mediumUploaded, this, &MediaManager::mediumUploaded);
0185     connect(d->uploader, &Uploader::uploadingFailed, this, &MediaManager::mediumUploadFailed);
0186     const QMimeDatabase db;
0187     d->uploader->upload(localUrl, picData, db.mimeTypeForUrl(localUrl).name().toLocal8Bit());
0188 }
0189 
0190 QByteArray MediaManager::createMultipartFormData(const QMap< QString, QByteArray > &formdata,
0191         const QList< QMap< QString, QByteArray > > &mediaFiles)
0192 {
0193     QByteArray newLine("\r\n");
0194     QString formHeader(QLatin1String(newLine) + QLatin1String("Content-Disposition: form-data; name=\"%1\""));
0195     QByteArray header("--AaB03x");
0196     QByteArray footer("--AaB03x--");
0197     QString fileHeader(QLatin1String(newLine) + QLatin1String("Content-Disposition: file; name=\"%1\"; filename=\"%2\""));
0198     QByteArray data;
0199 
0200     data.append(header);
0201 
0202     if (!mediaFiles.isEmpty()) {
0203         QList< QMap< QString, QByteArray > >::const_iterator it1 = mediaFiles.constBegin();
0204         QList< QMap< QString, QByteArray > >::const_iterator endIt1 = mediaFiles.constEnd();
0205         for (; it1 != endIt1; ++it1) {
0206             data.append(fileHeader.arg(QLatin1String(it1->value(QLatin1String("name")).data())).arg(QLatin1String(it1->value(QLatin1String("filename")).data())).toUtf8());
0207             data.append(newLine + "Content-Type: " + it1->value(QLatin1String("mediumType")));
0208             data.append(newLine);
0209             data.append(newLine + it1->value(QLatin1String("medium")));
0210         }
0211     }
0212 
0213     for (const QString &key: formdata.keys()) {
0214         data.append(newLine);
0215         data.append(header);
0216         data.append(formHeader.arg(key).toLatin1());
0217         data.append(newLine);
0218         data.append(newLine + formdata.value(key));
0219     }
0220     data.append(newLine);
0221     data.append(footer);
0222 
0223     return data;
0224 }
0225 
0226 }
0227 
0228 #include "moc_mediamanager.cpp"