From e998ad6882ef0f571c2dcc325f2f9dac76018c5d Mon Sep 17 00:00:00 2001 From: Luca Beltrame Date: Sun, 23 Aug 2015 00:58:28 +0200 Subject: [PATCH] Add missing methods to the Konachan API --- src/libdanbooru/konachan.cpp | 247 ++++++++++++++++++++++++++++++++++- src/libdanbooru/konachan.h | 7 + 2 files changed, 252 insertions(+), 2 deletions(-) diff --git a/src/libdanbooru/konachan.cpp b/src/libdanbooru/konachan.cpp index be6b776..caa207a 100644 --- a/src/libdanbooru/konachan.cpp +++ b/src/libdanbooru/konachan.cpp @@ -62,6 +62,24 @@ const QLatin1String KonachanDanbooruService::relatedTagUri() const { return QLatin1String("tag/related.json"); } +//////////////// +// Other methods +//////////////// + +SupportedOperations KonachanDanbooruService::supportedOperations() const { + + return PostDownload | PoolDownload | TagDownload | TagSearch | RelatedTagSearch; + +} + +ApiType KonachanDanbooruService::apiType() const { + return KonachanDanbooru; +} + +////////////// +// API methods +////////////// + void KonachanDanbooruService::getPostList() { // We can't fetch more than 100 items, API limitation @@ -85,6 +103,233 @@ void KonachanDanbooruService::getPostList() { } +void KonachanDanbooruService::getPoolList() +{ + + QUrl danbooruUrl; + + if (m_currentPage == 1) { + danbooruUrl = requestUrl(m_url, poolUri(), m_username, m_password); + } else { + QMap map; + map.insert("page", QString::number(m_currentPage)); + + danbooruUrl = requestUrl(m_url, poolUri(), m_username, + m_password, map); + } + +// qCDebug(LIBDANBOORU) << "Final constructed pool list URL" << danbooruUrl.url(); + + KIO::StoredTransferJob *job = KIO::storedGet(danbooruUrl, KIO::NoReload, + KIO::HideProgressInfo); + // This job can use JSON data + job->setProperty("needsXML", false); + +// connect(job, &KIO::StoredTransferJob::result, this, &DanbooruService::processPoolList); + + connect(job, &KIO::StoredTransferJob::result, [this](KJob * job) { + + if (job->error()) { + Q_EMIT(downloadError(job->errorString())); + return; + } + + StoredTransferJob *jobResult = qobject_cast(job); + QByteArray data = jobResult->data(); + + bool ok; + QList poolList = parseDanbooruResult(data, &ok).toList(); + + if (!ok) { + Q_EMIT(downloadError(QString("Unable to decode data"))); + return; + } + + for (auto element : poolList) { + QVariantMap map = element.toMap(); + + DanbooruPool *pool = new DanbooruPool(map); + Q_EMIT(poolDownloaded(pool)); + } + + //qCDebug(LIBDANBOORU) << "Pool download finished!"; + Q_EMIT(poolDownloadFinished()); + } + + ); + +} + +void KonachanDanbooruService::getPool(int poolId, int page) +{ + + QMap parameters; + + parameters.insert("id", QString::number(poolId)); + + if (page > 1) { + parameters.insert("page", QString::number(page)); + } + + QUrl danbooruUrl = requestUrl(m_url, poolDataUri(), m_username, + m_password, parameters); + +// qCDebug(LIBDANBOORU) << "Final constructed pool URL" << danbooruUrl.url(); + + KIO::StoredTransferJob *job = KIO::storedGet(danbooruUrl, KIO::NoReload, + KIO::HideProgressInfo); + + //HACK: Most Danbooru implementations don't provide valid data on + // pools via JSON, hence we set XML and parse the XML data. + + job->setProperty("needsXML", true); + + connect(job, &KIO::StoredTransferJob::result, this, &KonachanDanbooruService::processPostList); + +} + +void KonachanDanbooruService::getTagList(int limit, QString name) +{ + QMap parameters; + parameters.insert("limit", QString::number(limit)); + + if (!name.isEmpty()) { + parameters.insert("name", name); + } + parameters.insert("order", "date"); + + QUrl danbooruUrl = requestUrl(m_url, tagUri(), m_username, m_password, + parameters); +// qCDebug(LIBDANBOORU) << "Final constructed tag URL" << danbooruUrl.url(); + + KIO::StoredTransferJob *job = KIO::storedGet(danbooruUrl, KIO::NoReload, + KIO::HideProgressInfo); + connect(job, &KIO::StoredTransferJob::result, this, &KonachanDanbooruService::processTagList); + +} + +void KonachanDanbooruService::getRelatedTags(const QStringList &tags, + DanbooruTag::TagType tagType) +{ + + QString type; + switch (tagType) { + case DanbooruTag::General: + type = "general"; + break; + case DanbooruTag::Artist: + type = "artist"; + break; + case DanbooruTag::Copyright: + type = "copyright"; + break; + case DanbooruTag::Character: + type = "character"; + break; + case DanbooruTag::Unknown: + type = "unknown"; + break; + } + + QMap parameters; + parameters.insert("type", type); + + QUrl danbooruUrl = requestUrl(m_url, relatedTagUri(), m_username, + m_password, parameters, tags); + + // qCDebug(LIBDANBOORU) << "Final constructed related tag URL" << danbooruUrl; + + StoredTransferJob *job = KIO::storedGet( + danbooruUrl, KIO::NoReload, + KIO::HideProgressInfo + ); + + connect(job, &StoredTransferJob::result, [this](KJob * job) { + + if (job->error()) { + Q_EMIT(downloadError(job->errorString())); + return; + } + + StoredTransferJob *jobResult = qobject_cast(job); + QByteArray data = jobResult->data(); + bool ok; + + QVariantMap tagList = parseDanbooruResult(data, &ok).toMap(); + + if (!ok) { + Q_EMIT(downloadError(QString("Unable to decode data"))); + return; + } + + QVariantMap::const_iterator iter; + + // The service returns a list of key-related tag list pair, + // we iterate through them and remove the empty (not found) ones, then + // we call getTagList. Unfortunately Danbooru doesn't have a method to + // fetch all tags in batch, so this is done one by one. + + for (iter = tagList.constBegin(); iter != tagList.constEnd(); ++iter) { + + QList tags = iter.value().toList(); + + if (tags.isEmpty()) { + continue; + } + + for (auto tag : tags) { + // We get the first element in the list, the second is + // the ID which is useless (no API methods in Danbooru) + QString tagName = tag.toList().at(0).toString(); + getTagList(1, tagName); + } + + } + + } + + ); + +} + +//////// +// Slots +//////// + +void KonachanDanbooruService::processTagList(KJob *job) +{ + + if (job->error()) { + Q_EMIT(downloadError(job->errorString())); + return; + } + + StoredTransferJob *jobResult = qobject_cast(job); + QByteArray data = jobResult->data(); + + bool ok; + + // Most Danbooru implementations return tags in wrong order when + // using JSON, so we have to fall back to XML + QList tagList = parseDanbooruResult(data, "tag", &ok); + + if (!ok) { + Q_EMIT(downloadError(QString("Unable to decode data"))); + return; + } + + for (auto element : tagList) { + QVariantMap map = element.toMap(); + DanbooruTag *tag = new DanbooruTag(map); + + if (!tag) { + continue; + } + + Q_EMIT(tagDownloaded(tag)); + } +} + void KonachanDanbooruService::processPostList(KJob *job) { @@ -172,8 +417,6 @@ void KonachanDanbooruService::processPostList(KJob *job) QVariant variant; variant.setValue(post); -// pixmapJob->setProperty("danbooruPost", variant); - connect(pixmapJob, &StoredTransferJob::result, [post, this, pix](KJob * job) mutable { if (job->error()) diff --git a/src/libdanbooru/konachan.h b/src/libdanbooru/konachan.h index 1088777..e959d4a 100644 --- a/src/libdanbooru/konachan.h +++ b/src/libdanbooru/konachan.h @@ -44,8 +44,15 @@ public: using DanbooruServiceBase::DanbooruServiceBase; // superclass constructor ~KonachanDanbooruService() override; + SupportedOperations supportedOperations() const override; + Danbooru::ApiType apiType() const override; + void getPostList() override; void getPoolList() override; + void getPool(int poolId, int page = 1) override; + void getTagList(int limit = 10, QString name = "") override; + void getRelatedTags(const QStringList &tags, + DanbooruTag::TagType tagType = DanbooruTag::General) override; private Q_SLOTS: void processPostList(KJob *job);