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"