/* * Copyright 2015 Luca Beltrame * * This file is part of Danbooru Client. * * Danbooru Client 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 3 of the License, or * (at your option) any later version. * * Danbooru Client 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 Danbooru Client. If not, see . */ #include "servicebase.h" #include "libdanbooru_debug.h" #include "utils.h" #include #include using KIO::StoredTransferJob; namespace Danbooru { DanbooruServiceBase::DanbooruServiceBase(QUrl boardUrl, QObject* parent): QObject(parent), m_url(boardUrl), m_username(QString()), m_password(QString()), m_maxRating(Danbooru::Safe), m_maxPosts(10), m_currentPage(1), m_minimumWidth(-1), m_minimumHeight(-1), m_tags(QStringList()), m_postsToFetch(0) { } const QStringList DanbooruServiceBase::allowedRatings() const { QStringList ratings; if (m_maxRating.testFlag(Danbooru::Safe)) { ratings.append("Safe"); } if (m_maxRating.testFlag(Danbooru::Questionable)) { ratings.append("Questionable"); } if (m_maxRating.testFlag(Danbooru::Explicit)) { ratings.append("Explicit"); } return ratings; } Danbooru::ApiType DanbooruServiceBase::apiType() const { return Danbooru::ApiType::Unknown; } const QSet< QString > DanbooruServiceBase::blacklist() const { return m_blacklist; } int DanbooruServiceBase::currentPage() const { return m_currentPage; } const Danbooru::Ratings DanbooruServiceBase::maximumAllowedRating() const { return m_maxRating; } int DanbooruServiceBase::maxPosts() const { return m_maxPosts; } int DanbooruServiceBase::minimumHeight() const { return m_minimumHeight; } int DanbooruServiceBase::minimumWidth() const { return m_minimumWidth; } void DanbooruServiceBase::nextPostPage() { m_currentPage++; getPostList(); } void DanbooruServiceBase::nextPoolPage() { m_currentPage++; getPoolList(); } QStringList DanbooruServiceBase::postTags() const { return m_tags; } void DanbooruServiceBase::reset() { m_currentPage = 1; m_minimumHeight = -1; m_minimumWidth = -1; m_maxRating = Danbooru::Safe; m_tags = QStringList(); } ////////// // Setters ////////// void DanbooruServiceBase::setBlacklist(const QSet< QString > &blacklist) { if (!blacklist.isEmpty()) { m_blacklist = blacklist; } } void DanbooruServiceBase::setBlacklist(const QStringList &blacklist) { if (blacklist.isEmpty()) { return; } m_blacklist.clear(); for (const auto &element : blacklist) { m_blacklist.insert(element); } } void DanbooruServiceBase::setBoardUrl(const QUrl &url) { m_url = url; } void DanbooruServiceBase::setCurrentPage(int page) { m_currentPage = page; } void DanbooruServiceBase::setMaximumAllowedRating(Danbooru::Rating rating) { Danbooru::Ratings flags; switch (rating) { case Danbooru::Safe: flags = Danbooru::Safe; break; case Danbooru::Questionable: flags = Danbooru::Safe | Danbooru::Questionable; break; case Danbooru::Explicit: flags = Danbooru::Safe | Danbooru::Questionable | Danbooru::Explicit; break; } m_maxRating = flags; } void DanbooruServiceBase::setMaxPosts(int number) { m_maxPosts = number < 100 ? number : 100; } void DanbooruServiceBase::setPassword(const QString &password) { if (password.isEmpty()) { return; } m_password = password; } void DanbooruServiceBase::setPostTags(const QStringList &tags) { if (!tags.isEmpty()) { m_tags = tags; } } void DanbooruServiceBase::setUserName(const QString &username) { if (username.isEmpty()) { return; } m_username = username; } void DanbooruServiceBase::processPixmap(KJob* job) { if (job->error()) { Q_EMIT(downloadError(job->errorString())); return; } StoredTransferJob *jobResult = qobject_cast(job); if (jobResult == 0) { Q_EMIT(downloadError(QString("Internal error"))); return; } QByteArray data = jobResult->data(); Danbooru::DanbooruPost* post = job->property("post").value(); auto pix = job->property("pixmap").value(); if (!pix.loadFromData(jobResult->data())) { Q_EMIT(downloadError(QString("Pixmap data could not be loaded"))); return; } post->setPixmap(pix); m_postsToFetch--; // One less post to do qCDebug(LIBDANBOORU) << "Current posts remaining: " << m_postsToFetch; Q_EMIT(postDownloaded(post)); if (m_postsToFetch == 0) { qCDebug(LIBDANBOORU) << "Post download finished"; Q_EMIT(postDownloadFinished()); } } void DanbooruServiceBase::processPostList(KJob *job) { qCDebug(LIBDANBOORU) << "Got post data OK"; if (job->error()) { Q_EMIT(downloadError(job->errorString())); } StoredTransferJob *jobResult = qobject_cast(job); if (jobResult == 0) { Q_EMIT(downloadError(QString("Internal error"))); return; } QByteArray data = jobResult->data(); bool ok; bool is_pool = job->property("is_pool").toBool(); QList postList; if (is_pool) { // Special cases for pools QVariantMap postMap = parseResult(data, apiType(), Danbooru::Pool, &ok).at(0); auto postData = postMap.value("raw_post_data").toList(); for (const auto &post: postData) { postList.append(extractPostData(post, apiType())); } } else { postList = parseResult(data, apiType(), Danbooru::Post, &ok); } if (!ok) { Q_EMIT(downloadError(QString("Unable to decode data"))); return; } // How many posts do we have to fetch? if (postList.isEmpty()) { qCDebug(LIBDANBOORU) << "No posts found"; Q_EMIT(postDownloadFinished()); return; } m_postsToFetch = postList.length(); qCDebug(LIBDANBOORU) << "Found " << m_postsToFetch << "posts to fetch" << "with limit" << m_maxPosts; // This is mostly needed for pools if (postList.length() > m_maxPosts) { m_postsToFetch = m_maxPosts; postList = postList.mid(0, m_maxPosts); } for (const QVariantMap &element : qAsConst(postList)) { DanbooruPost *post = new DanbooruPost(element); // Remove unwanted posts if (isPostBlacklisted(post, m_blacklist, m_maxRating)) { m_postsToFetch--; delete post; continue; } QPixmap pix; qCDebug(LIBDANBOORU) << "About to download images"; qCDebug(LIBDANBOORU) << "Downloading image" << post->thumbnailUrl(); StoredTransferJob *pixmapJob = KIO::storedGet(post->thumbnailUrl(), KIO::NoReload, KIO::HideProgressInfo); // We don't want to overload the servers, so set some rational // priority KIO::Scheduler::setJobPriority(static_cast(pixmapJob), 1); QVariant variant; variant.setValue(post); pixmapJob->setProperty("post", variant); pixmapJob->setProperty("pix", pix); connect(pixmapJob, &StoredTransferJob::result, this, &DanbooruServiceBase::processPixmap); } } void DanbooruServiceBase::setMinimumHeight(int height) { if (height > 0) { m_minimumHeight = height; } } void DanbooruServiceBase::setMinimumWidth(int width) { if (width > 0) { m_minimumWidth = width; } } } // namespace Danbooru