PictureLoader: Replace downloadedPics cache with QNetworkCache (#4756)
* PictureLoader: Replace downloadedPics cache with QNetworkCache Currently when the "Download card pictures on the fly" option is enabled, Cockatrice stores downloaded pictures into a downloadedPics sub-folder, keyed on set and card name. If a picture is found in that folder, we never try to download a picture for that card ever again (until it is reprinted in a more recent set, I guess). This has the unfortunate consequence that if you change the URLs for downloading card images, the changes are not applied to cards that already have their picture downloaded. In particular, if you use localized card pictures (through !sflang!), you get a mix of cards in different languages depending on the currently configured language at the time each card was downloaded. This patch removes that mechanism in favor of setting a QNetworkDiskCache on the QNetworkAccessManager used by the PictureLoader to download pictures. The QNetworkDiskCache caches the picture keyed on their URL: if the URL changes, a new request will be made. In particular, if you use picture URLs with !sflang! and change the language, pictures for the current language will be downloaded even for cards that already have a picture. The QNetworkDiskCache is configured with a maximum size of 4GB, which should be enough to hold one high-quality JPEG for each M:TG card in existence. Note that this does not affect the existing mechanism for defining custom card art, either through the CUSTOM directory or the set-based one. Cockatrice will still read existing cards in the downloadedPics directory as before, it will just no longer write into that directory (since pictures are cached by the QNetworkDiskCache instead). To fully switch to the new cache, users should use the "Delete Downloaded Images" button in the settings: it will clear the QNetworkDiskCache but also remove the downloadedPics directory. * Do not use system cache dir for portable installs * Add settings for network cache size * Delete corrupted cache entries * Use old-style connect() syntax (Qt5 build failure) * Add setNetworkCacheSizeInMB to test mocks * setTransferTimeout was added in Qt 5.15 * Improve logging messages We now have the following messages - "Trying to download picture from url: URL" before loading a picture when picture download is enabled - "Trying to load picture from cache: URL" before loading a picture when picture download is disabled (i.e. cache-only offline mode) - "Removing corrupted cache file for url URL and retrying (ERR)" when when we fail to load a picture from the cache. Usually, this should be due to the timeout, in which case ERR will be "Operation Canceled". - "Download failed for url URL (ERR)" when there was an error downloading a picture from the network (ERR is the error message) - "Following redirect to URL" and "Following cached redirect to URL" when following a redirect (from network/from cache) - "Image successfully downloaded from URL" and "Image successfully loaded from cached url at URL" on success - "Possible cached/downloaded picture at URL could not be loaded" on ImageReader error * Clarify that network cache is on disk Also migrate "Delete Downloaded Image" to a "Clear" button right next to the network cache size. * Remove qPrintable * Move pixmap cache settings to card sources * qDebug().nospace() * some formatting on debug messages * format * inverted condition --------- Co-authored-by: ebbit1q <ebbit1q@gmail.com>
This commit is contained in:
parent
42e7a8b423
commit
c14936c63c
8 changed files with 201 additions and 100 deletions
|
@ -3,6 +3,7 @@
|
|||
#include "carddatabase.h"
|
||||
#include "gettextwithmax.h"
|
||||
#include "main.h"
|
||||
#include "pictureloader.h"
|
||||
#include "releasechannel.h"
|
||||
#include "sequenceEdit/sequenceedit.h"
|
||||
#include "settingscache.h"
|
||||
|
@ -68,18 +69,9 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
updateNotificationCheckBox.setChecked(settings.getNotifyAboutUpdates());
|
||||
newVersionOracleCheckBox.setChecked(settings.getNotifyAboutNewVersion());
|
||||
|
||||
// pixmap cache
|
||||
pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN);
|
||||
// 2047 is the max value to avoid overflowing of QPixmapCache::setCacheLimit(int size)
|
||||
pixmapCacheEdit.setMaximum(PIXMAPCACHE_SIZE_MAX);
|
||||
pixmapCacheEdit.setSingleStep(64);
|
||||
pixmapCacheEdit.setValue(settings.getPixmapCacheSize());
|
||||
pixmapCacheEdit.setSuffix(" MB");
|
||||
|
||||
showTipsOnStartup.setChecked(settings.getShowTipsOnStartup());
|
||||
|
||||
connect(&languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
|
||||
connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), &settings, SLOT(setPixmapCacheSize(int)));
|
||||
connect(&updateReleaseChannelBox, SIGNAL(currentIndexChanged(int)), &settings, SLOT(setUpdateReleaseChannel(int)));
|
||||
connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setNotifyAboutUpdate(int)));
|
||||
connect(&newVersionOracleCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setNotifyAboutNewVersion(int)));
|
||||
|
@ -90,8 +82,6 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
personalGrid->addWidget(&languageBox, 0, 1);
|
||||
personalGrid->addWidget(&updateReleaseChannelLabel, 1, 0);
|
||||
personalGrid->addWidget(&updateReleaseChannelBox, 1, 1);
|
||||
personalGrid->addWidget(&pixmapCacheLabel, 2, 0);
|
||||
personalGrid->addWidget(&pixmapCacheEdit, 2, 1);
|
||||
personalGrid->addWidget(&updateNotificationCheckBox, 3, 0, 1, 2);
|
||||
personalGrid->addWidget(&newVersionOracleCheckBox, 4, 0, 1, 2);
|
||||
personalGrid->addWidget(&showTipsOnStartup, 5, 0, 1, 2);
|
||||
|
@ -301,7 +291,6 @@ void GeneralSettingsPage::retranslateUi()
|
|||
cardDatabasePathLabel.setText(tr("Card database:"));
|
||||
customCardDatabasePathLabel.setText(tr("Custom database directory:"));
|
||||
tokenDatabasePathLabel.setText(tr("Token database:"));
|
||||
pixmapCacheLabel.setText(tr("Picture cache size:"));
|
||||
updateReleaseChannelLabel.setText(tr("Update channel"));
|
||||
updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client"));
|
||||
newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice"));
|
||||
|
@ -591,12 +580,38 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
|
|||
messageListLayout->addWidget(messageToolBar);
|
||||
messageListLayout->addWidget(urlList);
|
||||
|
||||
// pixmap cache
|
||||
pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN);
|
||||
// 2047 is the max value to avoid overflowing of QPixmapCache::setCacheLimit(int size)
|
||||
pixmapCacheEdit.setMaximum(PIXMAPCACHE_SIZE_MAX);
|
||||
pixmapCacheEdit.setSingleStep(64);
|
||||
pixmapCacheEdit.setValue(SettingsCache::instance().getPixmapCacheSize());
|
||||
pixmapCacheEdit.setSuffix(" MB");
|
||||
|
||||
networkCacheEdit.setMinimum(NETWORK_CACHE_SIZE_MIN);
|
||||
networkCacheEdit.setMaximum(NETWORK_CACHE_SIZE_MAX);
|
||||
networkCacheEdit.setSingleStep(1);
|
||||
networkCacheEdit.setValue(SettingsCache::instance().getNetworkCacheSizeInMB());
|
||||
networkCacheEdit.setSuffix(tr(" MB"));
|
||||
|
||||
auto networkCacheLayout = new QHBoxLayout;
|
||||
networkCacheLayout->addStretch();
|
||||
networkCacheLayout->addWidget(&networkCacheLabel);
|
||||
networkCacheLayout->addWidget(&networkCacheEdit);
|
||||
|
||||
auto pixmapCacheLayout = new QHBoxLayout;
|
||||
pixmapCacheLayout->addStretch();
|
||||
pixmapCacheLayout->addWidget(&pixmapCacheLabel);
|
||||
pixmapCacheLayout->addWidget(&pixmapCacheEdit);
|
||||
|
||||
// Top Layout
|
||||
lpGeneralGrid->addWidget(&picDownloadCheckBox, 0, 0);
|
||||
lpGeneralGrid->addWidget(&resetDownloadURLs, 0, 1);
|
||||
lpGeneralGrid->addLayout(messageListLayout, 1, 0, 1, 2);
|
||||
lpGeneralGrid->addWidget(&urlLinkLabel, 2, 0);
|
||||
lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 2, 1);
|
||||
lpGeneralGrid->addLayout(networkCacheLayout, 2, 0, 1, 2);
|
||||
lpGeneralGrid->addLayout(pixmapCacheLayout, 3, 0, 1, 2);
|
||||
lpGeneralGrid->addWidget(&urlLinkLabel, 4, 0);
|
||||
lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 4, 1);
|
||||
|
||||
// Spoiler Layout
|
||||
lpSpoilerGrid->addWidget(&mcDownloadSpoilersCheckBox, 0, 0);
|
||||
|
@ -611,6 +626,9 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
|
|||
connect(&mcDownloadSpoilersCheckBox, SIGNAL(toggled(bool)), &SettingsCache::instance(),
|
||||
SLOT(setDownloadSpoilerStatus(bool)));
|
||||
connect(&mcDownloadSpoilersCheckBox, SIGNAL(toggled(bool)), this, SLOT(setSpoilersEnabled(bool)));
|
||||
connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), &SettingsCache::instance(), SLOT(setPixmapCacheSize(int)));
|
||||
connect(&networkCacheEdit, SIGNAL(valueChanged(int)), &SettingsCache::instance(),
|
||||
SLOT(setNetworkCacheSizeInMB(int)));
|
||||
|
||||
mpGeneralGroupBox = new QGroupBox;
|
||||
mpGeneralGroupBox->setLayout(lpGeneralGrid);
|
||||
|
@ -635,6 +653,11 @@ void DeckEditorSettingsPage::resetDownloadedURLsButtonClicked()
|
|||
|
||||
void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked()
|
||||
{
|
||||
PictureLoader::clearNetworkCache();
|
||||
|
||||
// These are not used anymore, but we don't delete them automatically, so
|
||||
// we should do it here lest we leave pictures hanging around on users'
|
||||
// machines.
|
||||
QString picsPath = SettingsCache::instance().getPicsPath() + "/downloadedPics/";
|
||||
QStringList dirs = QDir(picsPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
|
||||
bool outerSuccessRemove = true;
|
||||
|
@ -662,6 +685,7 @@ void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked()
|
|||
}
|
||||
if (outerSuccessRemove) {
|
||||
QMessageBox::information(this, tr("Success"), tr("Downloaded card pictures have been reset."));
|
||||
QDir(SettingsCache::instance().getPicsPath()).rmdir("downloadedPics");
|
||||
} else {
|
||||
QMessageBox::critical(this, tr("Error"), tr("One or more downloaded card pictures could not be cleared."));
|
||||
}
|
||||
|
@ -785,6 +809,10 @@ void DeckEditorSettingsPage::retranslateUi()
|
|||
urlLinkLabel.setText(QString("<a href='%1'>%2</a>").arg(WIKI_CUSTOM_PIC_URL).arg(tr("How to add a custom URL")));
|
||||
clearDownloadedPicsButton.setText(tr("Delete Downloaded Images"));
|
||||
resetDownloadURLs.setText(tr("Reset Download URLs"));
|
||||
networkCacheLabel.setText(tr("Downloaded images directory size:"));
|
||||
networkCacheEdit.setToolTip(tr("On-disk cache for downloaded pictures"));
|
||||
pixmapCacheLabel.setText(tr("Picture cache size:"));
|
||||
pixmapCacheEdit.setToolTip(tr("In-memory cache for pictures not currently on screen"));
|
||||
}
|
||||
|
||||
MessagesSettingsPage::MessagesSettingsPage()
|
||||
|
|
|
@ -58,7 +58,6 @@ private:
|
|||
QLineEdit *tokenDatabasePathEdit;
|
||||
QPushButton *resetAllPathsButton;
|
||||
QLabel *allPathsResetLabel;
|
||||
QSpinBox pixmapCacheEdit;
|
||||
QGroupBox *personalGroupBox;
|
||||
QGroupBox *pathsGroupBox;
|
||||
QComboBox languageBox;
|
||||
|
@ -66,7 +65,6 @@ private:
|
|||
QCheckBox newVersionOracleCheckBox;
|
||||
QComboBox updateReleaseChannelBox;
|
||||
QLabel languageLabel;
|
||||
QLabel pixmapCacheLabel;
|
||||
QLabel deckPathLabel;
|
||||
QLabel replaysPathLabel;
|
||||
QLabel picsPathLabel;
|
||||
|
@ -168,6 +166,10 @@ private:
|
|||
QLabel infoOnSpoilersLabel;
|
||||
QPushButton *mpSpoilerPathButton;
|
||||
QPushButton *updateNowButton;
|
||||
QLabel networkCacheLabel;
|
||||
QSpinBox networkCacheEdit;
|
||||
QSpinBox pixmapCacheEdit;
|
||||
QLabel pixmapCacheLabel;
|
||||
};
|
||||
|
||||
class MessagesSettingsPage : public AbstractSettingsPage
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <QFile>
|
||||
#include <QImageReader>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QPainter>
|
||||
|
@ -116,6 +117,21 @@ PictureLoaderWorker::PictureLoaderWorker()
|
|||
connect(&SettingsCache::instance(), SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
|
||||
|
||||
networkManager = new QNetworkAccessManager(this);
|
||||
// We need a timeout to ensure requests don't hang indefinitely in case of
|
||||
// cache corruption, see related Qt bug: https://bugreports.qt.io/browse/QTBUG-111397
|
||||
// Use Qt's default timeout (30s, as of 2023-02-22)
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
networkManager->setTransferTimeout();
|
||||
#endif
|
||||
auto cache = new QNetworkDiskCache(this);
|
||||
cache->setCacheDirectory(SettingsCache::instance().getNetworkCachePath());
|
||||
// Note: the settings is in MB, but QNetworkDiskCache uses bytes
|
||||
connect(&SettingsCache::instance(), &SettingsCache::networkCacheSizeChanged, cache,
|
||||
[cache](int newSizeInMB) { cache->setMaximumCacheSize(1024L * 1024L * static_cast<qint64>(newSizeInMB)); });
|
||||
networkManager->setCache(cache);
|
||||
// Use a ManualRedirectPolicy since we keep track of redirects in picDownloadFinished
|
||||
// We can't use NoLessSafeRedirectPolicy because it is not applied with AlwaysCache
|
||||
networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
|
||||
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(picDownloadFinished(QNetworkReply *)));
|
||||
|
||||
pictureLoaderThread = new QThread;
|
||||
|
@ -149,38 +165,20 @@ void PictureLoaderWorker::processLoadQueue()
|
|||
QString cardName = cardBeingLoaded.getCard()->getName();
|
||||
QString correctedCardName = cardBeingLoaded.getCard()->getCorrectedName();
|
||||
|
||||
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName << "]: Trying to load picture";
|
||||
qDebug().nospace() << "PictureLoader: [card: " << cardName << " set: " << setName
|
||||
<< "]: Trying to load picture";
|
||||
|
||||
if (cardImageExistsOnDisk(setName, correctedCardName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (picDownload) {
|
||||
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
|
||||
<< "]: Picture not found on disk, trying to download";
|
||||
qDebug().nospace() << "PictureLoader: [card: " << cardName << " set: " << setName
|
||||
<< "]: No custom picture, trying to download";
|
||||
cardsToDownload.append(cardBeingLoaded);
|
||||
cardBeingLoaded.clear();
|
||||
if (!downloadRunning) {
|
||||
startNextPicDownload();
|
||||
}
|
||||
} else {
|
||||
if (cardBeingLoaded.nextSet()) {
|
||||
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
|
||||
<< "]: Picture NOT found and download disabled, moving to next "
|
||||
"set (new set: "
|
||||
<< setName << " card: " << cardName << ")";
|
||||
mutex.lock();
|
||||
loadQueue.prepend(cardBeingLoaded);
|
||||
cardBeingLoaded.clear();
|
||||
mutex.unlock();
|
||||
} else {
|
||||
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
|
||||
<< "]: Picture NOT found, download disabled, no more sets to "
|
||||
"try: BAILING OUT (old set: "
|
||||
<< setName << " card: " << cardName << ")";
|
||||
imageLoaded(cardBeingLoaded.getCard(), QImage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,6 +204,8 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
|
|||
|
||||
if (!setName.isEmpty()) {
|
||||
picsPaths << picsPath + "/" + setName + "/" + correctedCardname
|
||||
// We no longer store downloaded images there, but don't just ignore
|
||||
// stuff that old versions have put there.
|
||||
<< picsPath + "/downloadedPics/" + setName + "/" + correctedCardname;
|
||||
}
|
||||
|
||||
|
@ -215,21 +215,21 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
|
|||
for (const auto &picsPath : picsPaths) {
|
||||
imgReader.setFileName(picsPath);
|
||||
if (imgReader.read(&image)) {
|
||||
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
|
||||
qDebug().nospace() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
|
||||
<< "]: Picture found on disk.";
|
||||
imageLoaded(cardBeingLoaded.getCard(), image);
|
||||
return true;
|
||||
}
|
||||
imgReader.setFileName(picsPath + ".full");
|
||||
if (imgReader.read(&image)) {
|
||||
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
|
||||
qDebug().nospace() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
|
||||
<< "]: Picture.full found on disk.";
|
||||
imageLoaded(cardBeingLoaded.getCard(), image);
|
||||
return true;
|
||||
}
|
||||
imgReader.setFileName(picsPath + ".xlhq");
|
||||
if (imgReader.read(&image)) {
|
||||
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
|
||||
qDebug().nospace() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
|
||||
<< "]: Picture.xlhq found on disk.";
|
||||
imageLoaded(cardBeingLoaded.getCard(), image);
|
||||
return true;
|
||||
|
@ -385,11 +385,10 @@ void PictureLoaderWorker::startNextPicDownload()
|
|||
picDownloadFailed();
|
||||
} else {
|
||||
QUrl url(picUrl);
|
||||
QNetworkRequest req(url);
|
||||
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName()
|
||||
<< "]: Trying to download picture from url:" << url.toDisplayString();
|
||||
networkManager->get(req);
|
||||
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName() << "]: Trying to fetch picture from url "
|
||||
<< url.toDisplayString();
|
||||
makeRequest(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,10 +403,10 @@ void PictureLoaderWorker::picDownloadFailed()
|
|||
loadQueue.prepend(cardBeingDownloaded);
|
||||
mutex.unlock();
|
||||
} else {
|
||||
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName()
|
||||
<< "]: Picture NOT found, download failed, no more url combinations "
|
||||
"to try: BAILING OUT";
|
||||
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getCorrectedName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName() << "]: Picture NOT found, "
|
||||
<< (picDownload ? "download failed" : "downloads disabled")
|
||||
<< ", no more url combinations to try: BAILING OUT";
|
||||
imageLoaded(cardBeingDownloaded.getCard(), QImage());
|
||||
cardBeingDownloaded.clear();
|
||||
}
|
||||
|
@ -420,20 +419,53 @@ bool PictureLoaderWorker::imageIsBlackListed(const QByteArray &picData)
|
|||
return md5Blacklist.contains(md5sum);
|
||||
}
|
||||
|
||||
void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
|
||||
QNetworkReply *PictureLoaderWorker::makeRequest(const QUrl &url)
|
||||
{
|
||||
if (reply->error()) {
|
||||
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName() << "]: Download failed:" << reply->errorString();
|
||||
QNetworkRequest req(url);
|
||||
if (!picDownload) {
|
||||
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache);
|
||||
}
|
||||
return networkManager->get(req);
|
||||
}
|
||||
|
||||
void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
|
||||
{
|
||||
bool isFromCache = reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool();
|
||||
|
||||
if (reply->error()) {
|
||||
if (isFromCache) {
|
||||
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName()
|
||||
<< "]: Removing corrupted cache file for url " << reply->url().toDisplayString()
|
||||
<< " and retrying (" << reply->errorString() << ")";
|
||||
|
||||
networkManager->cache()->remove(reply->url());
|
||||
|
||||
makeRequest(reply->url());
|
||||
} else {
|
||||
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName()
|
||||
<< "]: " << (picDownload ? "Download" : "Cache search") << " failed for url "
|
||||
<< reply->url().toDisplayString() << " (" << reply->errorString() << ")";
|
||||
|
||||
picDownloadFailed();
|
||||
startNextPicDownload();
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// List of status codes from https://doc.qt.io/qt-6/qnetworkreply.html#redirected
|
||||
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if (statusCode == 301 || statusCode == 302) {
|
||||
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||
QNetworkRequest req(redirectUrl);
|
||||
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName() << "]: following redirect:" << req.url().toString();
|
||||
networkManager->get(req);
|
||||
if (statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 305 || statusCode == 307 ||
|
||||
statusCode == 308) {
|
||||
QUrl redirectUrl = reply->header(QNetworkRequest::LocationHeader).toUrl();
|
||||
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName() << "]: following "
|
||||
<< (isFromCache ? "cached redirect" : "redirect") << " to " << redirectUrl.toDisplayString();
|
||||
makeRequest(redirectUrl);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -441,10 +473,10 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
|
|||
const QByteArray &picData = reply->peek(reply->size());
|
||||
|
||||
if (imageIsBlackListed(picData)) {
|
||||
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName()
|
||||
<< "]:Picture downloaded, but blacklisted, will consider it as "
|
||||
"not found";
|
||||
<< "]: Picture found, but blacklisted, will consider it as not found";
|
||||
|
||||
picDownloadFailed();
|
||||
reply->deleteLater();
|
||||
startNextPicDownload();
|
||||
|
@ -456,40 +488,19 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
|
|||
QImageReader imgReader;
|
||||
imgReader.setDecideFormatFromContent(true);
|
||||
imgReader.setDevice(reply);
|
||||
// the format is determined prior to reading the QImageReader data into a QImage object, as that wipes the
|
||||
// QImageReader buffer
|
||||
QString extension = "." + imgReader.format();
|
||||
if (extension == ".jpeg") {
|
||||
extension = ".jpg";
|
||||
}
|
||||
|
||||
if (imgReader.read(&testImage)) {
|
||||
QString setName = cardBeingDownloaded.getSetName();
|
||||
if (!setName.isEmpty()) {
|
||||
if (!QDir().mkpath(picsPath + "/downloadedPics/" + setName)) {
|
||||
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName()
|
||||
<< "]: " << picsPath + "/downloadedPics/" + setName + " could not be created.";
|
||||
return;
|
||||
}
|
||||
|
||||
QFile newPic(picsPath + "/downloadedPics/" + setName + "/" +
|
||||
cardBeingDownloaded.getCard()->getCorrectedName() + extension);
|
||||
if (!newPic.open(QIODevice::WriteOnly)) {
|
||||
return;
|
||||
}
|
||||
newPic.write(picData);
|
||||
newPic.close();
|
||||
}
|
||||
|
||||
imageLoaded(cardBeingDownloaded.getCard(), testImage);
|
||||
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName() << "]: Image successfully downloaded from "
|
||||
<< reply->request().url().toDisplayString();
|
||||
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName() << "]: Image successfully "
|
||||
<< (isFromCache ? "loaded from cached" : "downloaded from") << " url "
|
||||
<< reply->url().toDisplayString();
|
||||
} else {
|
||||
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName() << "]: Possible picture at "
|
||||
<< reply->request().url().toDisplayString() << " could not be loaded";
|
||||
qDebug().nospace() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
<< " set: " << cardBeingDownloaded.getSetName() << "]: Possible "
|
||||
<< (isFromCache ? "cached" : "downloaded") << " picture at "
|
||||
<< reply->url().toDisplayString() << " could not be loaded";
|
||||
|
||||
picDownloadFailed();
|
||||
}
|
||||
|
||||
|
@ -533,6 +544,11 @@ void PictureLoaderWorker::picsPathChanged()
|
|||
customPicsPath = SettingsCache::instance().getCustomPicsPath();
|
||||
}
|
||||
|
||||
void PictureLoaderWorker::clearNetworkCache()
|
||||
{
|
||||
networkManager->cache()->clear();
|
||||
}
|
||||
|
||||
PictureLoader::PictureLoader() : QObject(nullptr)
|
||||
{
|
||||
worker = new PictureLoaderWorker;
|
||||
|
@ -613,6 +629,11 @@ void PictureLoader::clearPixmapCache()
|
|||
QPixmapCache::clear();
|
||||
}
|
||||
|
||||
void PictureLoader::clearNetworkCache()
|
||||
{
|
||||
getInstance().worker->clearNetworkCache();
|
||||
}
|
||||
|
||||
void PictureLoader::cacheCardPixmaps(QList<CardInfoPtr> cards)
|
||||
{
|
||||
QPixmap tmp;
|
||||
|
|
|
@ -73,6 +73,7 @@ public:
|
|||
~PictureLoaderWorker() override;
|
||||
|
||||
void enqueueImageLoad(CardInfoPtr card);
|
||||
void clearNetworkCache();
|
||||
|
||||
private:
|
||||
static QStringList md5Blacklist;
|
||||
|
@ -87,8 +88,9 @@ private:
|
|||
PictureToLoad cardBeingDownloaded;
|
||||
bool picDownload, downloadRunning, loadQueueRunning;
|
||||
void startNextPicDownload();
|
||||
bool cardImageExistsOnDisk(QString &, QString &);
|
||||
bool cardImageExistsOnDisk(QString &setName, QString &correctedCardName);
|
||||
bool imageIsBlackListed(const QByteArray &);
|
||||
QNetworkReply *makeRequest(const QUrl &url);
|
||||
private slots:
|
||||
void picDownloadFinished(QNetworkReply *reply);
|
||||
void picDownloadFailed();
|
||||
|
@ -97,6 +99,7 @@ private slots:
|
|||
void picsPathChanged();
|
||||
public slots:
|
||||
void processLoadQueue();
|
||||
|
||||
signals:
|
||||
void startLoadQueue();
|
||||
void imageLoaded(CardInfoPtr card, const QImage &image);
|
||||
|
@ -127,9 +130,14 @@ public:
|
|||
static void clearPixmapCache(CardInfoPtr card);
|
||||
static void clearPixmapCache();
|
||||
static void cacheCardPixmaps(QList<CardInfoPtr> cards);
|
||||
|
||||
public slots:
|
||||
static void clearNetworkCache();
|
||||
|
||||
private slots:
|
||||
void picDownloadChanged();
|
||||
void picsPathChanged();
|
||||
|
||||
public slots:
|
||||
void imageLoaded(CardInfoPtr card, const QImage &image);
|
||||
};
|
||||
|
|
|
@ -26,6 +26,19 @@ QString SettingsCache::getSettingsPath()
|
|||
return getDataPath() + "/settings/";
|
||||
}
|
||||
|
||||
QString SettingsCache::getCachePath() const
|
||||
{
|
||||
if (isPortableBuild)
|
||||
return qApp->applicationDirPath() + "/cache";
|
||||
else
|
||||
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||
}
|
||||
|
||||
QString SettingsCache::getNetworkCachePath() const
|
||||
{
|
||||
return getCachePath() + "/downloaded/";
|
||||
}
|
||||
|
||||
void SettingsCache::translateLegacySettings()
|
||||
{
|
||||
if (isPortableBuild)
|
||||
|
@ -206,6 +219,8 @@ SettingsCache::SettingsCache()
|
|||
if (pixmapCacheSize < PIXMAPCACHE_SIZE_MIN || pixmapCacheSize > PIXMAPCACHE_SIZE_MAX)
|
||||
pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT;
|
||||
|
||||
networkCacheSize = settings->value("personal/networkCacheSize", NETWORK_CACHE_SIZE_DEFAULT).toInt();
|
||||
|
||||
picDownload = settings->value("personal/picturedownload", true).toBool();
|
||||
|
||||
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
|
||||
|
@ -609,6 +624,13 @@ void SettingsCache::setPixmapCacheSize(const int _pixmapCacheSize)
|
|||
emit pixmapCacheSizeChanged(pixmapCacheSize);
|
||||
}
|
||||
|
||||
void SettingsCache::setNetworkCacheSizeInMB(const int _networkCacheSize)
|
||||
{
|
||||
networkCacheSize = _networkCacheSize;
|
||||
settings->setValue("personal/networkCacheSize", networkCacheSize);
|
||||
emit networkCacheSizeChanged(networkCacheSize);
|
||||
}
|
||||
|
||||
void SettingsCache::setClientID(const QString &_clientID)
|
||||
{
|
||||
clientID = _clientID;
|
||||
|
|
|
@ -20,6 +20,11 @@ class ReleaseChannel;
|
|||
#define PIXMAPCACHE_SIZE_MIN 64
|
||||
#define PIXMAPCACHE_SIZE_MAX 2047
|
||||
|
||||
// In MB
|
||||
constexpr int NETWORK_CACHE_SIZE_DEFAULT = 1024 * 4; // 4 GB
|
||||
constexpr int NETWORK_CACHE_SIZE_MIN = 1; // 1 MB
|
||||
constexpr int NETWORK_CACHE_SIZE_MAX = 1024 * 1024; // 1 TB
|
||||
|
||||
#define DEFAULT_LANG_NAME "English"
|
||||
#define CLIENT_INFO_NOT_SET "notset"
|
||||
|
||||
|
@ -46,6 +51,7 @@ signals:
|
|||
void ignoreUnregisteredUsersChanged();
|
||||
void ignoreUnregisteredUserMessagesChanged();
|
||||
void pixmapCacheSizeChanged(int newSizeInMBs);
|
||||
void networkCacheSizeChanged(int newSizeInMBs);
|
||||
void masterVolumeChanged(int value);
|
||||
void chatMentionCompleterChanged();
|
||||
void downloadSpoilerTimeIndexChanged();
|
||||
|
@ -106,6 +112,7 @@ private:
|
|||
QString knownMissingFeatures;
|
||||
bool useTearOffMenus;
|
||||
int pixmapCacheSize;
|
||||
int networkCacheSize;
|
||||
bool scaleCards;
|
||||
bool showMessagePopups;
|
||||
bool showMentionPopups;
|
||||
|
@ -137,6 +144,8 @@ public:
|
|||
SettingsCache();
|
||||
QString getDataPath();
|
||||
QString getSettingsPath();
|
||||
QString getCachePath() const;
|
||||
QString getNetworkCachePath() const;
|
||||
const QByteArray &getMainWindowGeometry() const
|
||||
{
|
||||
return mainWindowGeometry;
|
||||
|
@ -330,6 +339,10 @@ public:
|
|||
{
|
||||
return pixmapCacheSize;
|
||||
}
|
||||
int getNetworkCacheSizeInMB() const
|
||||
{
|
||||
return networkCacheSize;
|
||||
}
|
||||
bool getScaleCards() const
|
||||
{
|
||||
return scaleCards;
|
||||
|
@ -520,6 +533,7 @@ public slots:
|
|||
void setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers);
|
||||
void setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages);
|
||||
void setPixmapCacheSize(const int _pixmapCacheSize);
|
||||
void setNetworkCacheSizeInMB(const int _networkCacheSize);
|
||||
void setCardScaling(const int _scaleCards);
|
||||
void setShowMessagePopups(const int _showMessagePopups);
|
||||
void setShowMentionPopups(const int _showMentionPopups);
|
||||
|
|
|
@ -202,6 +202,9 @@ void SettingsCache::setTokenDialogGeometry(const QByteArray & /* _tokenDialogGeo
|
|||
void SettingsCache::setPixmapCacheSize(const int /* _pixmapCacheSize */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setNetworkCacheSizeInMB(const int /* _networkCacheSize */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setClientID(const QString & /* _clientID */)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -206,6 +206,9 @@ void SettingsCache::setTokenDialogGeometry(const QByteArray & /* _tokenDialogGeo
|
|||
void SettingsCache::setPixmapCacheSize(const int /* _pixmapCacheSize */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setNetworkCacheSizeInMB(const int /* _networkCacheSize */)
|
||||
{
|
||||
}
|
||||
void SettingsCache::setClientID(const QString & /* _clientID */)
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue