File indexing completed on 2024-05-12 05:09:31
0001 /*************************************************************************** 0002 Copyright (C) 2005-2022 Robby Stephenson <robby@periapsis.org> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or * 0008 * modify it under the terms of the GNU General Public License as * 0009 * published by the Free Software Foundation; either version 2 of * 0010 * the License or (at your option) version 3 or any later version * 0011 * accepted by the membership of KDE e.V. (or its successor approved * 0012 * by the membership of KDE e.V.), which shall act as a proxy * 0013 * defined in Section 14 of version 3 of the license. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0022 * * 0023 ***************************************************************************/ 0024 0025 #include "fetcher.h" 0026 #include "fetchmanager.h" // for calling static optional fields 0027 #include "../collection.h" 0028 #include "../entry.h" 0029 #include "../tellico_debug.h" 0030 0031 #include <KLocalizedString> 0032 #include <KSharedConfig> 0033 #include <KConfigGroup> 0034 #include <KIO/Global> 0035 #include <kio_version.h> 0036 #if KIO_VERSION >= QT_VERSION_CHECK(5,19,0) 0037 #include <KIO/FavIconRequestJob> 0038 #endif 0039 0040 #include <QUrl> 0041 #include <QUuid> 0042 #include <QPointer> 0043 0044 using namespace Tellico::Fetch; 0045 using Tellico::Fetch::Fetcher; 0046 0047 Fetcher::Fetcher(QObject* parent) : QObject(parent) 0048 , m_updateOverwrite(false) 0049 , m_hasMoreResults(false) 0050 , m_messager(nullptr) { 0051 Q_ASSERT(parent); 0052 } 0053 0054 Fetcher::~Fetcher() { 0055 saveConfig(); 0056 } 0057 0058 int Fetcher::collectionType() const { 0059 return m_request.collectionType(); 0060 } 0061 0062 /// virtual, overridden by subclasses 0063 bool Fetcher::canUpdate() const { 0064 return true; 0065 } 0066 0067 bool Fetcher::updateOverwrite() const { 0068 return m_updateOverwrite; 0069 } 0070 0071 const Tellico::Fetch::FetchRequest& Fetcher::request() const { 0072 return m_request; 0073 } 0074 0075 void Fetcher::startSearch(const FetchRequest& request_) { 0076 m_request = request_; 0077 if(!canFetch(m_request.collectionType())) { 0078 myDebug() << "Bad collection request type for search:" << source() << m_request.collectionType(); 0079 message(i18n("%1 does not allow searching for this collection type.", source()), 0080 MessageHandler::Warning); 0081 emit signalDone(this); 0082 return; 0083 } 0084 0085 m_entries.clear(); 0086 search(); 0087 } 0088 0089 void Fetcher::startUpdate(Tellico::Data::EntryPtr entry_) { 0090 Q_ASSERT(entry_); 0091 Q_ASSERT(entry_->collection()); 0092 m_request = updateRequest(entry_); 0093 m_request.setCollectionType(entry_->collection()->type()); 0094 if(m_request.isNull()) { 0095 myLog() << "Insufficient info from" << source() << "to update" << entry_->title(); 0096 emit signalDone(this); // always need to emit this if not continuing with the search 0097 return; 0098 } else { 0099 myLog() << "Starting update from" << source() << "for" << entry_->title(); 0100 } 0101 search(); 0102 } 0103 0104 void Fetcher::readConfig(const KConfigGroup& config_) { 0105 m_configGroup = config_; 0106 0107 QString s = config_.readEntry("Name"); 0108 if(!s.isEmpty()) { 0109 m_name = s; 0110 } 0111 m_updateOverwrite = config_.readEntry("UpdateOverwrite", false); 0112 // it's called custom fields here, but it's really optional lists 0113 m_fields = config_.readEntry("Custom Fields", QStringList()); 0114 s = config_.readEntry("Uuid"); 0115 if(s.isEmpty()) { 0116 s = QUuid::createUuid().toString(); 0117 } 0118 m_uuid = s; 0119 // be sure to read config for subclass 0120 readConfigHook(config_); 0121 } 0122 0123 void Fetcher::saveConfig() { 0124 if(!m_configGroup.isValid() || m_configGroup.isImmutable()) { 0125 return; 0126 } 0127 m_configGroup.writeEntry("Uuid", m_uuid); 0128 saveConfigHook(m_configGroup); 0129 m_configGroup.sync(); 0130 } 0131 0132 void Fetcher::setConfigGroup(const KConfigGroup& group_) { 0133 m_configGroup = group_; 0134 } 0135 0136 Tellico::Data::EntryPtr Fetcher::fetchEntry(uint uid_) { 0137 // check if already fetched this entry 0138 if(m_entries.contains(uid_)) { 0139 return m_entries[uid_]; 0140 } 0141 0142 QPointer<Fetcher> ptr(this); 0143 Data::EntryPtr entry = fetchEntryHook(uid_); 0144 // could be cancelled and killed after fetching entry, check ptr 0145 if(ptr && entry) { 0146 // iterate over list of possible optional fields 0147 // and if the field is not included in the user-configured list 0148 // remove the field from the entry 0149 QHashIterator<QString, QString> i(Manager::optionalFields(type())); 0150 while(i.hasNext()) { 0151 i.next(); 0152 if(!m_fields.contains(i.key())) { 0153 entry->collection()->removeField(i.key()); 0154 } 0155 } 0156 } 0157 m_entries.insert(uid_, entry); 0158 return entry; 0159 } 0160 0161 void Fetcher::setMessageHandler(MessageHandler* handler) { 0162 m_messager = handler; 0163 } 0164 0165 void Fetcher::message(const QString& message_, int type_) const { 0166 if(m_messager) { 0167 m_messager->send(message_, static_cast<MessageHandler::Type>(type_)); 0168 } 0169 } 0170 0171 QString Fetcher::favIcon(const char* url_) { 0172 return favIcon(QUrl(QString::fromLatin1(url_))); 0173 } 0174 0175 QString Fetcher::favIcon(const QUrl& url_, const QUrl& iconUrl_) { 0176 if(!url_.isValid()) { 0177 return QString(); 0178 } 0179 0180 #if KIO_VERSION >= QT_VERSION_CHECK(5,19,0) 0181 KIO::FavIconRequestJob* job = new KIO::FavIconRequestJob(url_); 0182 // if the url has a meaningful path, then use it as the icon url 0183 if(!iconUrl_.isEmpty()) { 0184 job->setIconUrl(iconUrl_); 0185 } else if(url_.path().size() > 4 && url_.path().contains(QLatin1Char('.'))) { 0186 job->setIconUrl(url_); 0187 } 0188 0189 connect(job, &KIO::FavIconRequestJob::result, [job](KJob *) { 0190 if(job->error()) { 0191 myDebug() << job->hostUrl().host() << "error:" << job->errorString(); 0192 } else if(job->iconFile().isEmpty()) { 0193 // myDebug() << "no favIcon found for" << job->hostUrl(); 0194 } 0195 }); 0196 #endif 0197 0198 QString name = KIO::favIconForUrl(url_); 0199 // favIcons start with "/". being an absolute file path from FavIconFetchJob 0200 // but KIconLoader still expects them to start with "favicons/" and appends ".png" 0201 // since the rest of Tellico assumes KDE4 behavior, adjust here 0202 if(name.startsWith(QLatin1Char('/'))) { 0203 int pos = name.indexOf(QLatin1String("favicons/")); 0204 if(pos > -1) { 0205 name = name.mid(pos); 0206 name.chop(4); // remove ".png"; 0207 } 0208 } 0209 return name; 0210 }