diff --git a/src/fetch/discogsfetcher.cpp b/src/fetch/discogsfetcher.cpp index 01f9dfc5..789b2ec8 100644 --- a/src/fetch/discogsfetcher.cpp +++ b/src/fetch/discogsfetcher.cpp @@ -1,466 +1,471 @@ /*************************************************************************** Copyright (C) 2008-2009 Robby Stephenson ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ #include // for TELLICO_VERSION #include "discogsfetcher.h" #include "../collections/musiccollection.h" #include "../images/imagefactory.h" #include "../utils/guiproxy.h" #include "../utils/string_utils.h" #include "../core/filehandler.h" #include "../tellico_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { static const int DISCOGS_MAX_RETURNS_TOTAL = 20; static const char* DISCOGS_API_URL = "https://api.discogs.com"; } using namespace Tellico; using Tellico::Fetch::DiscogsFetcher; DiscogsFetcher::DiscogsFetcher(QObject* parent_) : Fetcher(parent_) + , m_limit(DISCOGS_MAX_RETURNS_TOTAL) , m_started(false) { } DiscogsFetcher::~DiscogsFetcher() { } QString DiscogsFetcher::source() const { return m_name.isEmpty() ? defaultName() : m_name; } bool DiscogsFetcher::canSearch(FetchKey k) const { return k == Title || k == Person || k == Keyword; } bool DiscogsFetcher::canFetch(int type) const { return type == Data::Collection::Album; } void DiscogsFetcher::readConfigHook(const KConfigGroup& config_) { QString k = config_.readEntry("API Key"); if(!k.isEmpty()) { m_apiKey = k; } } +void DiscogsFetcher::setLimit(int limit_) { + m_limit = qBound(1, limit_, DISCOGS_MAX_RETURNS_TOTAL); +} + void DiscogsFetcher::search() { m_started = true; if(m_apiKey.isEmpty()) { myDebug() << "empty API key"; message(i18n("An access key is required to use this data source.") + QLatin1Char(' ') + i18n("Those values must be entered in the data source settings."), MessageHandler::Error); stop(); return; } QUrl u(QString::fromLatin1(DISCOGS_API_URL)); QUrlQuery q; switch(request().key) { case Title: u.setPath(QStringLiteral("/database/search")); q.addQueryItem(QStringLiteral("release_title"), request().value); q.addQueryItem(QStringLiteral("type"), QStringLiteral("release")); break; case Person: u.setPath(QStringLiteral("/database/search")); q.addQueryItem(QStringLiteral("artist"), request().value); q.addQueryItem(QStringLiteral("type"), QStringLiteral("release")); break; case Keyword: u.setPath(QStringLiteral("/database/search")); q.addQueryItem(QStringLiteral("q"), request().value); break; case Raw: u.setPath(QStringLiteral("/database/search")); q.setQuery(request().value); break; default: myWarning() << "key not recognized:" << request().key; stop(); return; } q.addQueryItem(QStringLiteral("token"), m_apiKey); u.setQuery(q); // myDebug() << "url: " << u.url(); m_job = KIO::storedGet(u, KIO::NoReload, KIO::HideProgressInfo); m_job->addMetaData(QStringLiteral("UserAgent"), QStringLiteral("Tellico/%1") .arg(QStringLiteral(TELLICO_VERSION))); KJobWidgets::setWindow(m_job, GUI::Proxy::widget()); connect(m_job.data(), &KJob::result, this, &DiscogsFetcher::slotComplete); } void DiscogsFetcher::stop() { if(!m_started) { return; } if(m_job) { m_job->kill(); m_job = nullptr; } m_started = false; emit signalDone(this); } Tellico::Data::EntryPtr DiscogsFetcher::fetchEntryHook(uint uid_) { Data::EntryPtr entry = m_entries.value(uid_); if(!entry) { myWarning() << "no entry in dict"; return Data::EntryPtr(); } QString id = entry->field(QStringLiteral("discogs-id")); if(!id.isEmpty()) { // quiet QUrl u(QString::fromLatin1(DISCOGS_API_URL)); u.setPath(QStringLiteral("/releases/%1").arg(id)); QByteArray data = FileHandler::readDataFile(u, true); #if 0 myWarning() << "Remove debug2 from discogsfetcher.cpp (/tmp/test2.json)"; QFile f(QString::fromLatin1("/tmp/test2.json")); if(f.open(QIODevice::WriteOnly)) { QTextStream t(&f); t.setCodec("UTF-8"); t << data; } f.close(); #endif QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson(data, &error); if(error.error == QJsonParseError::NoError) { populateEntry(entry, doc.object().toVariantMap(), true); } else { myDebug() << "Bad JSON results"; } } const QString image_id = entry->field(QStringLiteral("cover")); // if it's still a url, we need to load it if(image_id.contains(QLatin1Char('/'))) { const QString id = ImageFactory::addImage(QUrl::fromUserInput(image_id), true /* quiet */); if(id.isEmpty()) { myDebug() << "empty id for" << image_id; message(i18n("The cover image could not be loaded."), MessageHandler::Warning); } // empty image ID is ok entry->setField(QStringLiteral("cover"), id); } // don't want to include ID field entry->setField(QStringLiteral("discogs-id"), QString()); return entry; } Tellico::Fetch::FetchRequest DiscogsFetcher::updateRequest(Data::EntryPtr entry_) { QString title = entry_->field(QStringLiteral("title")); if(!title.isEmpty()) { return FetchRequest(Title, title); } QString artist = entry_->field(QStringLiteral("artist")); if(!artist.isEmpty()) { return FetchRequest(Person, artist); } return FetchRequest(); } void DiscogsFetcher::slotComplete(KJob*) { if(m_job->error()) { m_job->uiDelegate()->showErrorMessage(); stop(); return; } QByteArray data = m_job->data(); if(data.isEmpty()) { myDebug() << "no data"; stop(); return; } // see bug 319662. If fetcher is cancelled, job is killed // if the pointer is retained, it gets double-deleted m_job = nullptr; #if 0 myWarning() << "Remove debug from discogsfetcher.cpp"; QFile f(QString::fromLatin1("/tmp/test.json")); if(f.open(QIODevice::WriteOnly)) { QTextStream t(&f); t.setCodec("UTF-8"); t << data; } f.close(); #endif Data::CollPtr coll(new Data::MusicCollection(true)); // always add ID for fetchEntryHook Data::FieldPtr field(new Data::Field(QStringLiteral("discogs-id"), QStringLiteral("Discogs ID"), Data::Field::Line)); field->setCategory(i18n("General")); coll->addField(field); if(optionalFields().contains(QStringLiteral("discogs"))) { Data::FieldPtr field(new Data::Field(QStringLiteral("discogs"), i18n("Discogs Link"), Data::Field::URL)); field->setCategory(i18n("General")); coll->addField(field); } if(optionalFields().contains(QStringLiteral("nationality"))) { Data::FieldPtr field(new Data::Field(QStringLiteral("nationality"), i18n("Nationality"))); field->setCategory(i18n("General")); field->setFlags(Data::Field::AllowCompletion | Data::Field::AllowMultiple | Data::Field::AllowGrouped); field->setFormatType(FieldFormat::FormatPlain); coll->addField(field); } if(optionalFields().contains(QStringLiteral("producer"))) { Data::FieldPtr field(new Data::Field(QStringLiteral("producer"), i18n("Producer"))); field->setCategory(i18n("General")); field->setFlags(Data::Field::AllowCompletion | Data::Field::AllowMultiple | Data::Field::AllowGrouped); field->setFormatType(FieldFormat::FormatName); coll->addField(field); } QJsonDocument doc = QJsonDocument::fromJson(data); // const QVariantMap resultMap = doc.object().toVariantMap().value(QStringLiteral("feed")).toMap(); const QVariantMap resultMap = doc.object().toVariantMap(); if(mapValue(resultMap, "message").startsWith(QLatin1String("Invalid consumer token"))) { message(i18n("The Discogs.com server reports a token error."), MessageHandler::Error); stop(); return; } int count = 0; foreach(const QVariant& result, resultMap.value(QLatin1String("results")).toList()) { - if(count >= DISCOGS_MAX_RETURNS_TOTAL) { + if(count >= m_limit) { break; } // myDebug() << "found result:" << result; Data::EntryPtr entry(new Data::Entry(coll)); populateEntry(entry, result.toMap(), false); FetchResult* r = new FetchResult(Fetcher::Ptr(this), entry); m_entries.insert(r->uid, entry); emit signalResultFound(r); ++count; } stop(); } void DiscogsFetcher::populateEntry(Data::EntryPtr entry_, const QVariantMap& resultMap_, bool fullData_) { entry_->setField(QStringLiteral("discogs-id"), mapValue(resultMap_, "id")); entry_->setField(QStringLiteral("title"), mapValue(resultMap_, "title")); entry_->setField(QStringLiteral("year"), mapValue(resultMap_, "year")); entry_->setField(QStringLiteral("genre"), mapValue(resultMap_, "genres")); QStringList artists; foreach(const QVariant& artist, resultMap_.value(QLatin1String("artists")).toList()) { artists << mapValue(artist.toMap(), "name"); } entry_->setField(QStringLiteral("artist"), artists.join(FieldFormat::delimiterString())); QStringList labels; foreach(const QVariant& label, resultMap_.value(QLatin1String("labels")).toList()) { labels << mapValue(label.toMap(), "name"); } entry_->setField(QStringLiteral("label"), labels.join(FieldFormat::delimiterString())); /* thumb value is not always in the full data, so go ahead and set it now */ QString coverUrl = mapValue(resultMap_, "thumb"); if(!coverUrl.isEmpty()) { entry_->setField(QStringLiteral("cover"), coverUrl); } // if we only need cursory data, then we're done if(!fullData_) { return; } // check the formats, it could have multiple // if there is a CD, prefer that in the track list bool hasCD = false; foreach(const QVariant& format, resultMap_.value(QLatin1String("formats")).toList()) { if(mapValue(format.toMap(), "name") == QLatin1String("CD")) { entry_->setField(QStringLiteral("medium"), i18n("Compact Disc")); hasCD = true; } else if(mapValue(format.toMap(), "name") == QLatin1String("Vinyl")) { entry_->setField(QStringLiteral("medium"), i18n("Vinyl")); } else if(mapValue(format.toMap(), "name") == QLatin1String("Cassette")) { entry_->setField(QStringLiteral("medium"), i18n("Cassette")); } else if(!hasCD && mapValue(format.toMap(), "name") == QLatin1String("DVD")) { // sometimes a CD and DVD both are included. If we're using the CD, ignore the DVD entry_->setField(QStringLiteral("medium"), i18n("DVD")); } } QStringList tracks; foreach(const QVariant& track, resultMap_.value(QLatin1String("tracklist")).toList()) { const QVariantMap trackMap = track.toMap(); if(mapValue(trackMap, "type_") != QLatin1String("track")) { continue; } // Releases might include a CD and a DVD, for example // prefer only the tracks on the CD. Allow positions of just numbers if(hasCD && !(mapValue(trackMap, "position").at(0).isNumber() || mapValue(trackMap, "position").startsWith(QLatin1String("CD")))) { continue; } QStringList trackInfo; trackInfo << mapValue(trackMap, "title"); if(trackMap.contains(QStringLiteral("artists"))) { QStringList artists; foreach(const QVariant& artist, trackMap.value(QLatin1String("artists")).toList()) { artists << mapValue(artist.toMap(), "name"); } trackInfo << artists.join(FieldFormat::delimiterString()); } else { trackInfo << entry_->field(QStringLiteral("artist")); } trackInfo << mapValue(trackMap, "duration"); tracks << trackInfo.join(FieldFormat::columnDelimiterString()); } entry_->setField(QStringLiteral("track"), tracks.join(FieldFormat::rowDelimiterString())); if(entry_->collection()->hasField(QStringLiteral("discogs"))) { entry_->setField(QStringLiteral("discogs"), mapValue(resultMap_, "uri")); } if(entry_->collection()->hasField(QStringLiteral("nationality"))) { entry_->setField(QStringLiteral("nationality"), mapValue(resultMap_, "country")); } if(entry_->collection()->hasField(QStringLiteral("producer"))) { QStringList producers; foreach(const QVariant& extraartist, resultMap_.value(QLatin1String("extraartists")).toList()) { if(mapValue(extraartist.toMap(), "role").contains(QStringLiteral("Producer"))) { producers << mapValue(extraartist.toMap(), "name"); } } entry_->setField(QStringLiteral("producer"), producers.join(FieldFormat::delimiterString())); } entry_->setField(QStringLiteral("comments"), mapValue(resultMap_, "notes")); } Tellico::Fetch::ConfigWidget* DiscogsFetcher::configWidget(QWidget* parent_) const { return new DiscogsFetcher::ConfigWidget(parent_, this); } QString DiscogsFetcher::defaultName() { return i18n("Discogs Audio Search"); } QString DiscogsFetcher::defaultIcon() { return favIcon("http://www.discogs.com"); } Tellico::StringHash DiscogsFetcher::allOptionalFields() { StringHash hash; hash[QStringLiteral("producer")] = i18n("Producer"); hash[QStringLiteral("nationality")] = i18n("Nationality"); hash[QStringLiteral("discogs")] = i18n("Discogs Link"); return hash; } DiscogsFetcher::ConfigWidget::ConfigWidget(QWidget* parent_, const DiscogsFetcher* fetcher_) : Fetch::ConfigWidget(parent_) { QGridLayout* l = new QGridLayout(optionsWidget()); l->setSpacing(4); l->setColumnStretch(1, 10); int row = -1; QLabel* al = new QLabel(i18n("Registration is required for accessing the %1 data source. " "If you agree to the terms and conditions, sign " "up for an account, and enter your information below.", preferredName(), QLatin1String("https://www.discogs.com/developers/#page:authentication")), optionsWidget()); al->setOpenExternalLinks(true); al->setWordWrap(true); ++row; l->addWidget(al, row, 0, 1, 2); // richtext gets weird with size al->setMinimumWidth(al->sizeHint().width()); QLabel* label = new QLabel(i18n("User token: "), optionsWidget()); l->addWidget(label, ++row, 0); m_apiKeyEdit = new QLineEdit(optionsWidget()); connect(m_apiKeyEdit, &QLineEdit::textChanged, this, &ConfigWidget::slotSetModified); l->addWidget(m_apiKeyEdit, row, 1); label->setBuddy(m_apiKeyEdit); l->setRowStretch(++row, 10); if(fetcher_) { m_apiKeyEdit->setText(fetcher_->m_apiKey); } // now add additional fields widget addFieldsWidget(DiscogsFetcher::allOptionalFields(), fetcher_ ? fetcher_->optionalFields() : QStringList()); } void DiscogsFetcher::ConfigWidget::saveConfigHook(KConfigGroup& config_) { QString apiKey = m_apiKeyEdit->text().trimmed(); if(!apiKey.isEmpty()) { config_.writeEntry("API Key", apiKey); } } QString DiscogsFetcher::ConfigWidget::preferredName() const { return DiscogsFetcher::defaultName(); } diff --git a/src/fetch/discogsfetcher.h b/src/fetch/discogsfetcher.h index 468626fd..daf21ff5 100644 --- a/src/fetch/discogsfetcher.h +++ b/src/fetch/discogsfetcher.h @@ -1,110 +1,111 @@ /*************************************************************************** Copyright (C) 2008-2009 Robby Stephenson ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ #ifndef TELLICO_DISCOGSFETCHER_H #define TELLICO_DISCOGSFETCHER_H #include "fetcher.h" #include "configwidget.h" #include "../datavectors.h" #include class QLineEdit; class KJob; namespace KIO { class StoredTransferJob; } namespace Tellico { namespace Fetch { /** * A fetcher for discogs.com * * @author Robby Stephenson */ class DiscogsFetcher : public Fetcher { Q_OBJECT public: /** */ DiscogsFetcher(QObject* parent); /** */ virtual ~DiscogsFetcher(); /** */ virtual QString source() const Q_DECL_OVERRIDE; virtual bool isSearching() const Q_DECL_OVERRIDE { return m_started; } virtual bool canSearch(FetchKey k) const Q_DECL_OVERRIDE; virtual Type type() const Q_DECL_OVERRIDE { return Discogs; } virtual void stop() Q_DECL_OVERRIDE; virtual Data::EntryPtr fetchEntryHook(uint uid) Q_DECL_OVERRIDE; virtual bool canFetch(int type) const Q_DECL_OVERRIDE; virtual void readConfigHook(const KConfigGroup& config) Q_DECL_OVERRIDE; - virtual void saveConfigHook(KConfigGroup&) Q_DECL_OVERRIDE {} + void setLimit(int limit); /** * Returns a widget for modifying the fetcher's config. */ virtual Fetch::ConfigWidget* configWidget(QWidget* parent) const Q_DECL_OVERRIDE; class ConfigWidget : public Fetch::ConfigWidget { public: explicit ConfigWidget(QWidget* parent_, const DiscogsFetcher* fetcher = nullptr); virtual void saveConfigHook(KConfigGroup&) Q_DECL_OVERRIDE; virtual QString preferredName() const Q_DECL_OVERRIDE; private: QLineEdit* m_apiKeyEdit; }; friend class ConfigWidget; static QString defaultName(); static QString defaultIcon(); static StringHash allOptionalFields(); private Q_SLOTS: void slotComplete(KJob* job); private: virtual void search() Q_DECL_OVERRIDE; virtual FetchRequest updateRequest(Data::EntryPtr entry) Q_DECL_OVERRIDE; void populateEntry(Data::EntryPtr entry, const QVariantMap& resultMap, bool fullData); + int m_limit; bool m_started; QString m_apiKey; QHash m_entries; QPointer m_job; }; } // end namespace } // end namespace #endif diff --git a/src/tests/discogsfetchertest.cpp b/src/tests/discogsfetchertest.cpp index 3591e06e..433b3ca8 100644 --- a/src/tests/discogsfetchertest.cpp +++ b/src/tests/discogsfetchertest.cpp @@ -1,204 +1,206 @@ /*************************************************************************** Copyright (C) 2009-2011 Robby Stephenson ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ #undef QT_NO_CAST_FROM_ASCII #include "discogsfetchertest.h" #include "../fetch/discogsfetcher.h" #include "../entry.h" #include "../images/imagefactory.h" #include "../images/image.h" #include #include QTEST_GUILESS_MAIN( DiscogsFetcherTest ) DiscogsFetcherTest::DiscogsFetcherTest() : AbstractFetcherTest() , m_config(QFINDTESTDATA("tellicotest_private.config"), KConfig::SimpleConfig) { } void DiscogsFetcherTest::initTestCase() { Tellico::ImageFactory::init(); m_hasConfigFile = QFile::exists(QFINDTESTDATA("tellicotest_private.config")); } void DiscogsFetcherTest::testTitle() { QString groupName = QStringLiteral("Discogs"); if(!m_hasConfigFile || !m_config.hasGroup(groupName)) { QSKIP("This test requires a config file with Discogs settings.", SkipAll); } KConfigGroup cg(&m_config, groupName); Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Album, Tellico::Fetch::Title, QStringLiteral("Anywhere But Home")); Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::DiscogsFetcher(this)); fetcher->readConfig(cg, cg.name()); Tellico::Data::EntryList results = DO_FETCH(fetcher, request); QVERIFY(results.size() > 0); Tellico::Data::EntryPtr entry; // results can be randomly ordered, loop until wee find the one we want for(int i = 0; i < results.size(); ++i) { Tellico::Data::EntryPtr test = results.at(i); if(test->field(QStringLiteral("artist")).toLower() == QStringLiteral("evanescence")) { entry = test; break; } else { qDebug() << "skipping" << test->title() << test->field(QStringLiteral("artist")); } } QVERIFY(entry); QCOMPARE(entry->field(QStringLiteral("title")), QStringLiteral("Anywhere But Home")); QVERIFY(!entry->field(QStringLiteral("artist")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("label")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("genre")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("year")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("track")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("cover")).isEmpty()); const Tellico::Data::Image& img = Tellico::ImageFactory::imageById(entry->field(QStringLiteral("cover"))); QVERIFY(!img.isNull()); } void DiscogsFetcherTest::testPerson() { QString groupName = QStringLiteral("Discogs"); if(!m_hasConfigFile || !m_config.hasGroup(groupName)) { QSKIP("This test requires a config file with Discogs settings.", SkipAll); } KConfigGroup cg(&m_config, groupName); Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Album, Tellico::Fetch::Person, QStringLiteral("Evanescence")); Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::DiscogsFetcher(this)); fetcher->readConfig(cg, cg.name()); + static_cast(fetcher.data())->setLimit(1); Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1); QCOMPARE(results.size(), 1); Tellico::Data::EntryPtr entry = results.at(0); QCOMPARE(entry->field(QStringLiteral("artist")), QStringLiteral("Evanescence")); QVERIFY(!entry->field(QStringLiteral("title")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("label")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("cover")).isEmpty()); const Tellico::Data::Image& img = Tellico::ImageFactory::imageById(entry->field(QStringLiteral("cover"))); QVERIFY(!img.isNull()); } void DiscogsFetcherTest::testKeyword() { QString groupName = QStringLiteral("Discogs"); if(!m_hasConfigFile || !m_config.hasGroup(groupName)) { QSKIP("This test requires a config file with Discogs settings.", SkipAll); } KConfigGroup cg(&m_config, groupName); Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Album, Tellico::Fetch::Keyword, QStringLiteral("Fallen Evanescence 2004")); Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::DiscogsFetcher(this)); fetcher->readConfig(cg, cg.name()); + static_cast(fetcher.data())->setLimit(1); Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1); QCOMPARE(results.size(), 1); Tellico::Data::EntryPtr entry = results.at(0); QCOMPARE(entry->field(QStringLiteral("title")), QStringLiteral("Fallen")); QCOMPARE(entry->field(QStringLiteral("artist")), QStringLiteral("Evanescence")); QVERIFY(!entry->field(QStringLiteral("label")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("year")).isEmpty()); QVERIFY(!entry->field(QStringLiteral("cover")).isEmpty()); const Tellico::Data::Image& img = Tellico::ImageFactory::imageById(entry->field(QStringLiteral("cover"))); QVERIFY(!img.isNull()); } // use the Raw query type to fully test the data for a Discogs release void DiscogsFetcherTest::testRawData() { QString groupName = QStringLiteral("Discogs"); if(!m_hasConfigFile || !m_config.hasGroup(groupName)) { QSKIP("This test requires a config file with Discogs settings.", SkipAll); } KConfigGroup cg(&m_config, groupName); Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Album, Tellico::Fetch::Raw, QStringLiteral("q=r1588789")); Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::DiscogsFetcher(this)); fetcher->readConfig(cg, cg.name()); Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1); QCOMPARE(results.size(), 1); Tellico::Data::EntryPtr entry = results.at(0); QCOMPARE(entry->field(QStringLiteral("title")), QStringLiteral("Anywhere But Home")); QCOMPARE(entry->field(QStringLiteral("artist")), QStringLiteral("Evanescence")); QCOMPARE(entry->field(QStringLiteral("label")), QStringLiteral("Wind-Up")); QCOMPARE(entry->field(QStringLiteral("year")), QStringLiteral("2004")); QCOMPARE(entry->field(QStringLiteral("genre")), QStringLiteral("Rock")); QCOMPARE(entry->field(QStringLiteral("discogs")), QStringLiteral("https://www.discogs.com/Evanescence-Anywhere-But-Home/release/1588789")); QCOMPARE(entry->field(QStringLiteral("nationality")), QStringLiteral("Australia")); QCOMPARE(entry->field(QStringLiteral("medium")), QStringLiteral("Compact Disc")); QStringList trackList = Tellico::FieldFormat::splitTable(entry->field(QStringLiteral("track"))); QCOMPARE(trackList.count(), 14); QCOMPARE(trackList.at(0), QStringLiteral("Haunted::Evanescence::4:04")); QVERIFY(!entry->field(QStringLiteral("cover")).isEmpty()); } // do another check to make sure the Vinyl format is captured void DiscogsFetcherTest::testRawDataVinyl() { QString groupName = QStringLiteral("Discogs"); if(!m_hasConfigFile || !m_config.hasGroup(groupName)) { QSKIP("This test requires a config file with Discogs settings.", SkipAll); } KConfigGroup cg(&m_config, groupName); Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Album, Tellico::Fetch::Raw, QStringLiteral("q=r456552")); Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::DiscogsFetcher(this)); fetcher->readConfig(cg, cg.name()); Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1); QCOMPARE(results.size(), 1); Tellico::Data::EntryPtr entry = results.at(0); QCOMPARE(entry->field(QStringLiteral("title")), QStringLiteral("The Clash")); QCOMPARE(entry->field(QStringLiteral("artist")), QStringLiteral("The Clash")); QCOMPARE(entry->field(QStringLiteral("label")), QStringLiteral("CBS; CBS")); QCOMPARE(entry->field(QStringLiteral("year")), QStringLiteral("1977")); QCOMPARE(entry->field(QStringLiteral("genre")), QStringLiteral("Rock")); QCOMPARE(entry->field(QStringLiteral("discogs")), QStringLiteral("https://www.discogs.com/The-Clash-The-Clash/release/456552")); QCOMPARE(entry->field(QStringLiteral("nationality")), QStringLiteral("UK")); QCOMPARE(entry->field(QStringLiteral("medium")), QStringLiteral("Vinyl")); QStringList trackList = Tellico::FieldFormat::splitTable(entry->field(QStringLiteral("track"))); QCOMPARE(trackList.count(), 14); QCOMPARE(trackList.at(0), QStringLiteral("Janie Jones::The Clash::2:05")); }