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 }