File indexing completed on 2024-05-12 16:59:41

0001 /*
0002  *   SPDX-FileCopyrightText: 2007 Tobias Koenig <tokoe@kde.org>
0003  *
0004  *   SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "cachedprovider.h"
0008 
0009 #include <QDateTime>
0010 #include <QDir>
0011 #include <QFile>
0012 #include <QFileInfo>
0013 #include <QJsonDocument>
0014 #include <QJsonObject>
0015 #include <QRegularExpression>
0016 #include <QStandardPaths>
0017 #include <QThreadPool>
0018 #include <QTimer>
0019 
0020 #include <QDebug>
0021 #include "debug.h"
0022 
0023 LoadImageThread::LoadImageThread(const QString &filePath)
0024     : m_filePath(filePath)
0025 {
0026 }
0027 
0028 void LoadImageThread::run()
0029 {
0030     PotdProviderData data;
0031     data.wallpaperImage = QImage(m_filePath);
0032 
0033     const QString infoPath = m_filePath + QStringLiteral(".json");
0034     QFile infoFile(infoPath);
0035 
0036     if (infoFile.exists()) {
0037         if (infoFile.open(QIODevice::ReadOnly)) {
0038             QJsonParseError jsonParseError;
0039             const QJsonDocument jsonDoc = QJsonDocument::fromJson(infoFile.readAll(), &jsonParseError);
0040             infoFile.close();
0041 
0042             if (jsonParseError.error == QJsonParseError::NoError && jsonDoc.isObject()) {
0043                 const QJsonObject jsonObject = jsonDoc.object();
0044                 data.wallpaperInfoUrl = QUrl(jsonObject.value(QStringLiteral("InfoUrl")).toString());
0045                 data.wallpaperRemoteUrl = QUrl(jsonObject.value(QStringLiteral("RemoteUrl")).toString());
0046                 data.wallpaperTitle = jsonObject.value(QStringLiteral("Title")).toString();
0047                 data.wallpaperAuthor = jsonObject.value(QStringLiteral("Author")).toString();
0048             } else {
0049                 qCWarning(WALLPAPERPOTD) << "Failed to read the wallpaper information!";
0050             }
0051         } else {
0052             qCWarning(WALLPAPERPOTD) << "Failed to open the wallpaper information file!";
0053         }
0054     }
0055 
0056     Q_EMIT done(data);
0057 }
0058 
0059 SaveImageThread::SaveImageThread(const QString &identifier, const QVariantList &args, const PotdProviderData &data)
0060     : m_identifier(identifier)
0061     , m_args(args)
0062     , m_data(data)
0063 {
0064 }
0065 
0066 void SaveImageThread::run()
0067 {
0068     m_data.wallpaperLocalUrl = CachedProvider::identifierToPath(m_identifier, m_args);
0069     m_data.wallpaperImage.save(m_data.wallpaperLocalUrl, "JPEG");
0070 
0071     const QString infoPath = m_data.wallpaperLocalUrl + ".json";
0072     QFile infoFile(infoPath);
0073     if (infoFile.open(QIODevice::WriteOnly)) {
0074         QJsonObject jsonObject;
0075 
0076         jsonObject.insert(QStringLiteral("InfoUrl"), m_data.wallpaperInfoUrl.url());
0077         jsonObject.insert(QStringLiteral("RemoteUrl"), m_data.wallpaperRemoteUrl.url());
0078         jsonObject.insert(QStringLiteral("Title"), m_data.wallpaperTitle);
0079         jsonObject.insert(QStringLiteral("Author"), m_data.wallpaperAuthor);
0080 
0081         infoFile.write(QJsonDocument(jsonObject).toJson(QJsonDocument::Compact));
0082         infoFile.close();
0083     } else {
0084         qWarning(WALLPAPERPOTD) << "Failed to save the wallpaper information!";
0085     }
0086 
0087     Q_EMIT done(m_identifier, m_data);
0088 }
0089 
0090 QString CachedProvider::identifierToPath(const QString &identifier, const QVariantList &args)
0091 {
0092     const QString argString = std::accumulate(args.cbegin(), args.cend(), QString(), [](const QString &s, const QVariant &arg) {
0093         if (arg.canConvert(QMetaType::QString)) {
0094             return s + QStringLiteral(":%1").arg(arg.toString());
0095         }
0096 
0097         return s;
0098     });
0099 
0100     const QString dataDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/plasma_engine_potd/");
0101     QDir d;
0102     d.mkpath(dataDir);
0103     return QStringLiteral("%1%2%3").arg(dataDir, identifier, argString);
0104 }
0105 
0106 CachedProvider::CachedProvider(const QString &identifier, const QVariantList &args, QObject *parent)
0107     : PotdProvider(parent, KPluginMetaData(), QVariantList())
0108     , mIdentifier(identifier)
0109     , m_args(args)
0110 {
0111     LoadImageThread *thread = new LoadImageThread(identifierToPath(mIdentifier, m_args));
0112     connect(thread, &LoadImageThread::done, this, &CachedProvider::triggerFinished);
0113     QThreadPool::globalInstance()->start(thread);
0114 }
0115 
0116 QString CachedProvider::identifier() const
0117 {
0118     return mIdentifier;
0119 }
0120 
0121 void CachedProvider::triggerFinished(const PotdProviderData &data)
0122 {
0123     potdProviderData()->wallpaperImage = data.wallpaperImage;
0124     potdProviderData()->wallpaperLocalUrl = data.wallpaperLocalUrl;
0125     potdProviderData()->wallpaperInfoUrl = data.wallpaperInfoUrl;
0126     potdProviderData()->wallpaperRemoteUrl = data.wallpaperRemoteUrl;
0127     potdProviderData()->wallpaperTitle = data.wallpaperTitle;
0128     potdProviderData()->wallpaperAuthor = data.wallpaperAuthor;
0129 
0130     Q_EMIT finished(this);
0131 }
0132 
0133 bool CachedProvider::isCached(const QString &identifier, const QVariantList &args, bool ignoreAge)
0134 {
0135     const QString path = identifierToPath(identifier, args);
0136     if (!QFile::exists(path)) {
0137         return false;
0138     }
0139 
0140     QRegularExpression re(QLatin1String(":\\d{4}-\\d{2}-\\d{2}"));
0141 
0142     if (!ignoreAge && !re.match(identifier).hasMatch()) {
0143         // no date in the identifier, so it's a daily; check to see ifthe modification time is today
0144         QFileInfo info(path);
0145         if (info.lastModified().daysTo(QDateTime::currentDateTime()) >= 1) {
0146             return false;
0147         }
0148     }
0149 
0150     return true;
0151 }