Warning, file /plasma/kdeplasma-addons/applets/comic/engine/comic.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * SPDX-FileCopyrightText: 2007 Tobias Koenig <tokoe@kde.org> 0003 * SPDX-FileCopyrightText: 2022 Alexander Lohnau <alexander.lohnau@gmx.de> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "comic.h" 0009 0010 #include <QDate> 0011 #include <QDebug> 0012 #include <QFileInfo> 0013 #include <QImage> 0014 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0015 #include <QNetworkInformation> 0016 #endif 0017 #include <QSettings> 0018 #include <QStandardPaths> 0019 0020 #include <KPackage/PackageLoader> 0021 #include <qloggingcategory.h> 0022 0023 #include "cachedprovider.h" 0024 #include "comic_debug.h" 0025 #include "comicprovider.h" 0026 #include "comicproviderkross.h" 0027 0028 ComicEngine::ComicEngine(QObject *parent) 0029 : QObject(parent) 0030 , mEmptySuffix(false) 0031 { 0032 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0033 QNetworkInformation::instance()->load(QNetworkInformation::Feature::Reachability); 0034 #endif 0035 loadProviders(); 0036 } 0037 0038 QList<ComicProviderInfo> ComicEngine::loadProviders() 0039 { 0040 mProviders.clear(); 0041 auto comics = KPackage::PackageLoader::self()->listPackages(QStringLiteral("Plasma/Comic")); 0042 QList<ComicProviderInfo> providers; 0043 for (auto comic : comics) { 0044 0045 qCDebug(PLASMA_COMIC) << "ComicEngine::loadProviders() service name=" << comic.name(); 0046 ComicProviderInfo data; 0047 data.pluginId = comic.pluginId(); 0048 data.name = comic.name(); 0049 QFileInfo file(comic.iconName()); 0050 if (file.isRelative()) { 0051 data.icon = 0052 QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString::fromLatin1("plasma/comics/%1/%2").arg(comic.pluginId(), comic.iconName())); 0053 } else { 0054 data.icon = comic.iconName(); 0055 } 0056 mProviders << comic.pluginId(); 0057 providers << data; 0058 } 0059 return providers; 0060 } 0061 0062 void ComicEngine::setMaxComicLimit(int maxComicLimit) 0063 { 0064 CachedProvider::setMaxComicLimit(maxComicLimit); 0065 } 0066 0067 bool ComicEngine::requestSource(const QString &identifier) 0068 { 0069 if (m_jobs.contains(identifier)) { 0070 return true; 0071 } 0072 0073 const QStringList parts = identifier.split(QLatin1Char(':'), Qt::KeepEmptyParts); 0074 0075 // check whether it is cached, make sure second part present 0076 if (parts.count() > 1 && (CachedProvider::isCached(identifier) || !isOnline())) { 0077 ComicProvider *provider = new CachedProvider(this, KPluginMetaData{}, IdentifierType::StringIdentifier, identifier); 0078 m_jobs[identifier] = provider; 0079 connect(provider, &ComicProvider::finished, this, &ComicEngine::finished); 0080 connect(provider, &ComicProvider::error, this, &ComicEngine::error); 0081 return true; 0082 } 0083 0084 // ... start a new query otherwise 0085 if (parts.count() < 2) { 0086 Q_EMIT requestFinished(ComicMetaData{.error = true}); 0087 qWarning() << "Less than two arguments specified."; 0088 return false; 0089 } 0090 if (!mProviders.contains(parts[0])) { 0091 // User might have installed more from GHNS 0092 loadProviders(); 0093 if (!mProviders.contains(parts[0])) { 0094 Q_EMIT requestFinished(ComicMetaData{.error = true}); 0095 qWarning() << identifier << "comic plugin does not seem to be installed."; 0096 return false; 0097 } 0098 } 0099 0100 // check if there is a connection 0101 if (!isOnline()) { 0102 qCDebug(PLASMA_COMIC) << "Currently offline, requested identifier was" << mIdentifierError; 0103 mIdentifierError = identifier; 0104 ComicMetaData data; 0105 data.error = true; 0106 data.errorAutomaticallyFixable = true; 0107 data.identifier = identifier; 0108 data.previousIdentifier = lastCachedIdentifier(identifier); 0109 Q_EMIT requestFinished(data); 0110 qCDebug(PLASMA_COMIC) << "No internet connection, using cached data"; 0111 return true; 0112 } 0113 0114 KPackage::Package pkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Comic"), parts[0]); 0115 0116 bool isCurrentComic = parts[1].isEmpty(); 0117 0118 ComicProvider *provider = nullptr; 0119 0120 QVariant data; 0121 const IdentifierType identifierType = stringToIdentifierType(pkg.metadata().value(QStringLiteral("X-KDE-PlasmaComicProvider-SuffixType"))); 0122 if (identifierType == IdentifierType::DateIdentifier) { 0123 QDate date = QDate::fromString(parts[1], Qt::ISODate); 0124 if (!date.isValid()) { 0125 date = QDate::currentDate(); 0126 } 0127 0128 data = date; 0129 } else if (identifierType == IdentifierType::NumberIdentifier) { 0130 data = parts[1].toInt(); 0131 } else if (identifierType == IdentifierType::StringIdentifier) { 0132 data = parts[1]; 0133 } 0134 provider = new ComicProviderKross(this, pkg.metadata(), identifierType, data); 0135 provider->setIsCurrent(isCurrentComic); 0136 0137 m_jobs[identifier] = provider; 0138 0139 connect(provider, &ComicProvider::finished, this, &ComicEngine::finished); 0140 connect(provider, &ComicProvider::error, this, &ComicEngine::error); 0141 return true; 0142 } 0143 0144 void ComicEngine::finished(ComicProvider *provider) 0145 { 0146 // sets the data 0147 if (provider->image().isNull()) { 0148 qCWarning(PLASMA_COMIC) << "Provider returned null image" << provider->name(); 0149 error(provider); 0150 return; 0151 } 0152 0153 ComicMetaData data = metaDataFromProvider(provider); 0154 0155 // different comic -- with no error yet -- has been chosen, old error is invalidated 0156 QString temp = mIdentifierError.left(mIdentifierError.indexOf(QLatin1Char(':')) + 1); 0157 if (!mIdentifierError.isEmpty() && provider->identifier().indexOf(temp) == -1) { 0158 mIdentifierError.clear(); 0159 } 0160 // comic strip with error worked now 0161 if (!mIdentifierError.isEmpty() && (mIdentifierError == provider->identifier())) { 0162 mIdentifierError.clear(); 0163 } 0164 0165 // store in cache if it's not the response of a CachedProvider, 0166 if (!provider->inherits("CachedProvider") && !provider->image().isNull()) { 0167 CachedProvider::storeInCache(provider->identifier(), provider->image(), data); 0168 } 0169 provider->deleteLater(); 0170 0171 const QString key = m_jobs.key(provider); 0172 if (!key.isEmpty()) { 0173 m_jobs.remove(key); 0174 } 0175 Q_EMIT requestFinished(data); 0176 } 0177 0178 void ComicEngine::error(ComicProvider *provider) 0179 { 0180 QString identifier(provider->identifier()); 0181 mIdentifierError = identifier; 0182 0183 qWarning() << identifier << "plugging reported an error."; 0184 0185 ComicMetaData data = metaDataFromProvider(provider); 0186 data.error = true; 0187 0188 // if there was an error loading the last cached comic strip, do not return its id anymore 0189 const QString lastCachedId = lastCachedIdentifier(identifier); 0190 if (lastCachedId != provider->identifier().mid(provider->identifier().indexOf(QLatin1Char(':')) + 1)) { 0191 // sets the previousIdentifier to the identifier of a strip that has been cached before 0192 data.previousIdentifier = lastCachedId; 0193 } 0194 data.nextIdentifier = QString(); 0195 0196 const QString key = m_jobs.key(provider); 0197 if (!key.isEmpty()) { 0198 m_jobs.remove(key); 0199 } 0200 0201 provider->deleteLater(); 0202 Q_EMIT requestFinished(data); 0203 } 0204 0205 ComicMetaData ComicEngine::metaDataFromProvider(ComicProvider *provider) 0206 { 0207 QString identifier(provider->identifier()); 0208 0209 /** 0210 * Requests for the current day have no suffix (date or id) 0211 * set initially, so we have to remove the 'faked' suffix 0212 * here again to not confuse the applet. 0213 */ 0214 if (provider->isCurrent()) { 0215 identifier = identifier.left(identifier.indexOf(QLatin1Char(':')) + 1); 0216 } 0217 0218 ComicMetaData data; 0219 data.imageUrl = provider->imageUrl(); 0220 data.image = provider->image(); 0221 data.websiteUrl = provider->websiteUrl(); 0222 data.shopUrl = provider->shopUrl(); 0223 data.nextIdentifier = provider->nextIdentifier(); 0224 data.previousIdentifier = provider->previousIdentifier(); 0225 data.comicAuthor = provider->comicAuthor(); 0226 data.additionalText = provider->additionalText(); 0227 data.stripTitle = provider->stripTitle(); 0228 data.firstStripIdentifier = provider->firstStripIdentifier(); 0229 data.identifier = identifier; 0230 data.providerName = provider->name(); 0231 data.identifierType = provider->identifierType(); 0232 data.isLeftToRight = provider->isLeftToRight(); 0233 data.isTopToBottom = provider->isTopToBottom(); 0234 0235 return data; 0236 } 0237 0238 QString ComicEngine::lastCachedIdentifier(const QString &identifier) const 0239 { 0240 const QString id = identifier.left(identifier.indexOf(QLatin1Char(':'))); 0241 QString data = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/plasma_engine_comic/"); 0242 data += QString::fromLatin1(QUrl::toPercentEncoding(id)); 0243 QSettings settings(data + QLatin1String(".conf"), QSettings::IniFormat); 0244 QString previousIdentifier = settings.value(QLatin1String("lastCachedStripIdentifier"), QString()).toString(); 0245 0246 return previousIdentifier; 0247 } 0248 0249 bool ComicEngine::isOnline() const 0250 { 0251 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0252 return m_networkConfigurationManager.isOnline(); 0253 #else 0254 return QNetworkInformation::instance()->reachability() == QNetworkInformation::Reachability::Online; 0255 #endif 0256 }