File indexing completed on 2024-05-12 05:09:34
0001 /*************************************************************************** 0002 Copyright (C) 2010 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 "giantbombfetcher.h" 0026 #include "../translators/xslthandler.h" 0027 #include "../translators/tellicoimporter.h" 0028 #include "../utils/guiproxy.h" 0029 #include "../utils/string_utils.h" 0030 #include "../core/tellico_strings.h" 0031 #include "../tellico_debug.h" 0032 0033 #include <KLocalizedString> 0034 #include <KConfigGroup> 0035 0036 #include <QLabel> 0037 #include <QFile> 0038 #include <QTextStream> 0039 #include <QGridLayout> 0040 #include <QDomDocument> 0041 #include <QTextCodec> 0042 #include <QUrlQuery> 0043 0044 namespace { 0045 static const int GIANTBOMB_MAX_RETURNS_TOTAL = 20; 0046 static const char* GIANTBOMB_API_URL = "https://www.giantbomb.com/api"; 0047 static const char* GIANTBOMB_API_KEY = "291bfe4b2d77a460e67dd8f90c1e7e56c3e4f05a"; 0048 } 0049 0050 using namespace Tellico; 0051 using Tellico::Fetch::GiantBombFetcher; 0052 0053 GiantBombFetcher::GiantBombFetcher(QObject* parent_) 0054 : XMLFetcher(parent_) 0055 , m_total(-1) 0056 , m_apiKey(QLatin1String(GIANTBOMB_API_KEY)) { 0057 setLimit(GIANTBOMB_MAX_RETURNS_TOTAL); 0058 setXSLTFilename(QStringLiteral("giantbomb2tellico.xsl")); 0059 } 0060 0061 GiantBombFetcher::~GiantBombFetcher() { 0062 } 0063 0064 QString GiantBombFetcher::source() const { 0065 return m_name.isEmpty() ? defaultName() : m_name; 0066 } 0067 0068 QString GiantBombFetcher::attribution() const { 0069 return i18n(providedBy, QLatin1String("https://giantbomb.com"), QLatin1String("Giant Bomb")); 0070 } 0071 0072 bool GiantBombFetcher::canFetch(int type) const { 0073 return type == Data::Collection::Game; 0074 } 0075 0076 void GiantBombFetcher::readConfigHook(const KConfigGroup& config_) { 0077 QString k = config_.readEntry("API Key", GIANTBOMB_API_KEY); 0078 if(!k.isEmpty()) { 0079 m_apiKey = k; 0080 } 0081 } 0082 0083 void GiantBombFetcher::resetSearch() { 0084 m_total = -1; 0085 } 0086 0087 QUrl GiantBombFetcher::searchUrl() { 0088 QUrl u(QString::fromLatin1(GIANTBOMB_API_URL)); 0089 QUrlQuery q; 0090 q.addQueryItem(QStringLiteral("format"), QStringLiteral("xml")); 0091 q.addQueryItem(QStringLiteral("api_key"), m_apiKey); 0092 0093 switch(request().key()) { 0094 case Keyword: 0095 u.setPath(u.path() + QStringLiteral("/search")); 0096 q.addQueryItem(QStringLiteral("query"), request().value()); 0097 q.addQueryItem(QStringLiteral("resources"), QStringLiteral("game")); 0098 break; 0099 0100 default: 0101 myWarning() << source() << "- key not recognized:" << request().key(); 0102 return QUrl(); 0103 } 0104 u.setQuery(q); 0105 0106 // myDebug() << "url: " << u.url(); 0107 return u; 0108 } 0109 0110 void GiantBombFetcher::parseData(QByteArray& data_) { 0111 Q_UNUSED(data_); 0112 #if 0 0113 if(m_total == -1) { 0114 QDomDocument dom; 0115 if(!dom.setContent(data, false)) { 0116 myWarning() << "server did not return valid XML."; 0117 return; 0118 } 0119 // total is /resp/fetchresults/@numResults 0120 QDomNode n = dom.documentElement().namedItem(QLatin1String("resp")) 0121 .namedItem(QLatin1String("fetchresults")); 0122 QDomElement e = n.toElement(); 0123 if(!e.isNull()) { 0124 m_total = e.attribute(QLatin1String("numResults")).toInt(); 0125 myDebug() << "total = " << m_total; 0126 } 0127 } 0128 m_start = m_entries.count() + 1; 0129 // not sure how to specify start in the REST url 0130 // m_hasMoreResults = m_start <= m_total; 0131 #endif 0132 } 0133 0134 Tellico::Data::EntryPtr GiantBombFetcher::fetchEntryHookData(Data::EntryPtr entry_) { 0135 Q_ASSERT(entry_); 0136 0137 const QString id = entry_->field(QStringLiteral("giantbomb-id")); 0138 if(id.isEmpty()) { 0139 myDebug() << "no giantbomb id found"; 0140 return entry_; 0141 } 0142 0143 QUrl u(QString::fromLatin1(GIANTBOMB_API_URL)); 0144 u.setPath(u.path() + QStringLiteral("/game/%1/").arg(id)); 0145 QUrlQuery q; 0146 q.addQueryItem(QStringLiteral("format"), QStringLiteral("xml")); 0147 q.addQueryItem(QStringLiteral("api_key"), m_apiKey); 0148 u.setQuery(q); 0149 // myDebug() << "url: " << u; 0150 0151 // quiet 0152 QString output = FileHandler::readXMLFile(u, true); 0153 0154 #if 0 0155 myWarning() << "Remove output debug from giantbombfetcher.cpp"; 0156 QFile f(QStringLiteral("/tmp/test2.xml")); 0157 if(f.open(QIODevice::WriteOnly)) { 0158 QTextStream t(&f); 0159 t.setCodec("UTF-8"); 0160 t << output; 0161 } 0162 f.close(); 0163 #endif 0164 0165 Import::TellicoImporter imp(xsltHandler()->applyStylesheet(output)); 0166 // be quiet when loading images 0167 imp.setOptions(imp.options() ^ Import::ImportShowImageErrors); 0168 Data::CollPtr coll = imp.collection(); 0169 // getTracks(entry); 0170 if(!coll) { 0171 myWarning() << "no collection pointer"; 0172 return entry_; 0173 } 0174 0175 if(coll->entryCount() > 1) { 0176 myDebug() << "weird, more than one entry found"; 0177 } 0178 0179 // don't want to include id 0180 coll->removeField(QStringLiteral("giantbomb-id")); 0181 return coll->entries().front(); 0182 } 0183 0184 Tellico::Fetch::FetchRequest GiantBombFetcher::updateRequest(Data::EntryPtr entry_) { 0185 QString title = entry_->field(QStringLiteral("title")); 0186 if(!title.isEmpty()) { 0187 return FetchRequest(Keyword, title); 0188 } 0189 return FetchRequest(); 0190 } 0191 0192 Tellico::Fetch::ConfigWidget* GiantBombFetcher::configWidget(QWidget* parent_) const { 0193 return new GiantBombFetcher::ConfigWidget(parent_, this); 0194 } 0195 0196 QString GiantBombFetcher::defaultName() { 0197 return QStringLiteral("Giant Bomb"); 0198 } 0199 0200 QString GiantBombFetcher::defaultIcon() { 0201 return favIcon("http://www.giantbomb.com"); 0202 } 0203 0204 Tellico::StringHash GiantBombFetcher::allOptionalFields() { 0205 StringHash hash; 0206 hash[QStringLiteral("giantbomb")] = i18n("GiantBomb Link"); 0207 hash[QStringLiteral("pegi")] = i18n("PEGI Rating"); 0208 return hash; 0209 } 0210 0211 GiantBombFetcher::ConfigWidget::ConfigWidget(QWidget* parent_, const GiantBombFetcher* fetcher_) 0212 : Fetch::ConfigWidget(parent_) { 0213 QGridLayout* l = new QGridLayout(optionsWidget()); 0214 l->setSpacing(4); 0215 l->setColumnStretch(1, 10); 0216 0217 int row = -1; 0218 0219 QLabel* al = new QLabel(i18n("Registration is required for accessing this data source. " 0220 "If you agree to the terms and conditions, <a href='%1'>sign " 0221 "up for an account</a>, and enter your information below.", 0222 QLatin1String("http://api.giantbomb.com")), 0223 optionsWidget()); 0224 al->setOpenExternalLinks(true); 0225 al->setWordWrap(true); 0226 ++row; 0227 l->addWidget(al, row, 0, 1, 2); 0228 // richtext gets weird with size 0229 al->setMinimumWidth(al->sizeHint().width()); 0230 0231 QLabel* label = new QLabel(i18n("Access key: "), optionsWidget()); 0232 l->addWidget(label, ++row, 0); 0233 0234 m_apiKeyEdit = new QLineEdit(optionsWidget()); 0235 connect(m_apiKeyEdit, &QLineEdit::textChanged, this, &ConfigWidget::slotSetModified); 0236 l->addWidget(m_apiKeyEdit, row, 1); 0237 QString w = i18n("The default Tellico key may be used, but searching may fail due to reaching access limits."); 0238 label->setWhatsThis(w); 0239 m_apiKeyEdit->setWhatsThis(w); 0240 label->setBuddy(m_apiKeyEdit); 0241 0242 l->setRowStretch(++row, 10); 0243 0244 // now add additional fields widget 0245 addFieldsWidget(GiantBombFetcher::allOptionalFields(), fetcher_ ? fetcher_->optionalFields() : QStringList()); 0246 0247 if(fetcher_) { 0248 // only show the key if it is not the default Tellico one... 0249 // that way the user is prompted to apply for their own 0250 if(fetcher_->m_apiKey != QLatin1String(GIANTBOMB_API_KEY)) { 0251 m_apiKeyEdit->setText(fetcher_->m_apiKey); 0252 } 0253 } 0254 } 0255 0256 void GiantBombFetcher::ConfigWidget::saveConfigHook(KConfigGroup& config_) { 0257 QString apiKey = m_apiKeyEdit->text().trimmed(); 0258 if(!apiKey.isEmpty()) { 0259 config_.writeEntry("API Key", apiKey); 0260 } 0261 } 0262 0263 QString GiantBombFetcher::ConfigWidget::preferredName() const { 0264 return GiantBombFetcher::defaultName(); 0265 }