mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2025-12-05 20:39:59 -08:00
[Doxygen] Card Picture Loader (#6315)
* [Doxygen] Card Picture Loader Took 25 minutes Took 16 minutes # Commit time for manual adjustment: # Took 12 seconds Took 14 seconds * Remove placeholder file description. Took 1 minute * ... but do group PictureLoader again Took 28 seconds * Link to methods directly. Took 6 minutes * Forward declaration. Took 49 seconds * Remove redundant .cpp function documentation. Took 15 minutes * More fixes. Took 7 minutes --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* @file card_picture_loader.h
|
||||
* @ingroup PictureLoader
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef CARD_PICTURE_LOADER_H
|
||||
#define CARD_PICTURE_LOADER_H
|
||||
|
||||
@@ -16,10 +10,37 @@
|
||||
inline Q_LOGGING_CATEGORY(CardPictureLoaderLog, "card_picture_loader");
|
||||
inline Q_LOGGING_CATEGORY(CardPictureLoaderCardBackCacheFailLog, "card_picture_loader.card_back_cache_fail");
|
||||
|
||||
/**
|
||||
* @class CardPictureLoader
|
||||
* @ingroup PictureLoader
|
||||
* @brief Singleton class to manage card image loading and caching. Provides functionality to asynchronously load,
|
||||
* cache, and manage card images for the client.
|
||||
*
|
||||
* This class is a singleton and handles:
|
||||
* - Loading card images from disk or network.
|
||||
* - Caching images in QPixmapCache for fast reuse.
|
||||
* - Providing themed card backs, including fallback and in-progress/failed states.
|
||||
* - Emitting updates when pixmaps are loaded.
|
||||
*
|
||||
* It interacts with CardPictureLoaderWorker for background loading and
|
||||
* CardPictureLoaderStatusBar to display loading progress in the main window.
|
||||
*
|
||||
* Provides static accessors for:
|
||||
* - Card images by ExactCard.
|
||||
* - Card back images (normal, in-progress, failed).
|
||||
* - Cache management (clearPixmapCache(), clearNetworkCache(), cacheCardPixmaps(const QList<ExactCard> &cards)).
|
||||
*
|
||||
* Uses a worker thread for asynchronous image loading and a status bar widget
|
||||
* to track load progress.
|
||||
*/
|
||||
class CardPictureLoader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief Access the singleton instance of CardPictureLoader.
|
||||
* @return Reference to the singleton.
|
||||
*/
|
||||
static CardPictureLoader &getInstance()
|
||||
{
|
||||
static CardPictureLoader instance;
|
||||
@@ -29,30 +50,87 @@ public:
|
||||
private:
|
||||
explicit CardPictureLoader();
|
||||
~CardPictureLoader() override;
|
||||
// Singleton - Don't implement copy constructor and assign operator
|
||||
CardPictureLoader(CardPictureLoader const &);
|
||||
void operator=(CardPictureLoader const &);
|
||||
|
||||
CardPictureLoaderWorker *worker;
|
||||
CardPictureLoaderStatusBar *statusBar;
|
||||
// Disable copy and assignment for singleton
|
||||
CardPictureLoader(CardPictureLoader const &) = delete;
|
||||
void operator=(CardPictureLoader const &) = delete;
|
||||
|
||||
CardPictureLoaderWorker *worker; ///< Worker thread for async image loading
|
||||
CardPictureLoaderStatusBar *statusBar; ///< Status bar widget showing load progress
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Retrieve a card pixmap, either from cache or enqueued for loading.
|
||||
* @param pixmap Reference to QPixmap where result will be stored.
|
||||
* @param card ExactCard to load.
|
||||
* @param size Desired size of pixmap.
|
||||
*/
|
||||
static void getPixmap(QPixmap &pixmap, const ExactCard &card, QSize size);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a generic card back pixmap.
|
||||
* @param pixmap Reference to QPixmap where result will be stored.
|
||||
* @param size Desired size of pixmap.
|
||||
*/
|
||||
static void getCardBackPixmap(QPixmap &pixmap, QSize size);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a card back pixmap for the loading-in-progress state.
|
||||
* @param pixmap Reference to QPixmap where result will be stored.
|
||||
* @param size Desired size of pixmap.
|
||||
*/
|
||||
static void getCardBackLoadingInProgressPixmap(QPixmap &pixmap, QSize size);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a card back pixmap for the loading-failed state.
|
||||
* @param pixmap Reference to QPixmap where result will be stored.
|
||||
* @param size Desired size of pixmap.
|
||||
*/
|
||||
static void getCardBackLoadingFailedPixmap(QPixmap &pixmap, QSize size);
|
||||
static void clearPixmapCache();
|
||||
|
||||
/**
|
||||
* @brief Preload a list of cards into the pixmap cache (limited to CACHED_CARD_PER_DECK_MAX).
|
||||
* @param cards List of ExactCard objects to preload.
|
||||
*/
|
||||
static void cacheCardPixmaps(const QList<ExactCard> &cards);
|
||||
|
||||
/**
|
||||
* @brief Check if the user has custom card art in the picsPath directory.
|
||||
* @return True if any custom art exists.
|
||||
*/
|
||||
static bool hasCustomArt();
|
||||
|
||||
/**
|
||||
* @brief Clears the in-memory QPixmap cache for all cards.
|
||||
*/
|
||||
static void clearPixmapCache();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Clears the network disk cache of the worker.
|
||||
*/
|
||||
static void clearNetworkCache();
|
||||
|
||||
private slots:
|
||||
void picDownloadChanged();
|
||||
void picsPathChanged();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Slot called by the worker when an image is loaded.
|
||||
* Inserts the pixmap into the cache and emits pixmap updated signals.
|
||||
* @param card ExactCard that was loaded.
|
||||
* @param image Loaded QImage.
|
||||
*/
|
||||
void imageLoaded(const ExactCard &card, const QImage &image);
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Triggered when the user changes the picture download settings.
|
||||
* Clears the QPixmap cache to reload images.
|
||||
*/
|
||||
void picDownloadChanged();
|
||||
|
||||
/**
|
||||
* @brief Triggered when the pictures path changes.
|
||||
* Clears the QPixmap cache to reload images.
|
||||
*/
|
||||
void picsPathChanged();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -47,12 +47,6 @@ void CardPictureLoaderLocal::refreshIndex()
|
||||
<< customFolderIndex.size() << "entries.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to load the card image from the local images.
|
||||
*
|
||||
* @param toLoad The card to load
|
||||
* @return The loaded image, or an empty QImage if loading failed.
|
||||
*/
|
||||
QImage CardPictureLoaderLocal::tryLoad(const ExactCard &toLoad) const
|
||||
{
|
||||
PrintingInfo setInstance = toLoad.getPrinting();
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* @file card_picture_loader_local.h
|
||||
* @ingroup PictureLoader
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef PICTURE_LOADER_LOCAL_H
|
||||
#define PICTURE_LOADER_LOCAL_H
|
||||
|
||||
@@ -15,32 +9,80 @@
|
||||
inline Q_LOGGING_CATEGORY(CardPictureLoaderLocalLog, "card_picture_loader.local");
|
||||
|
||||
/**
|
||||
* Handles searching for and loading card images from the local pics and custom image folders.
|
||||
* This class maintains an index of the CUSTOM folder, to avoid repeatedly searching the entire directory.
|
||||
* @class CardPictureLoaderLocal
|
||||
* @ingroup PictureLoader
|
||||
* @brief Handles searching for and loading card images from local and custom image folders.
|
||||
*
|
||||
* This class maintains an index of the CUSTOM folder to avoid repeatedly scanning
|
||||
* directories, and supports periodic refreshes to update the index.
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Load images for ExactCard objects from local disk or custom folders.
|
||||
* - Maintain an index for fast lookup of images in the CUSTOM folder.
|
||||
* - Refresh the index periodically to account for changes in local image directories.
|
||||
*/
|
||||
class CardPictureLoaderLocal : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a CardPictureLoaderLocal object.
|
||||
* @param parent Optional parent QObject.
|
||||
*
|
||||
* Initializes paths from SettingsCache, connects to settings change signals,
|
||||
* builds the initial folder index, and starts a periodic refresh timer.
|
||||
*/
|
||||
explicit CardPictureLoaderLocal(QObject *parent);
|
||||
|
||||
/**
|
||||
* @brief Attempts to load a card image from local disk or custom folders.
|
||||
* @param toLoad ExactCard object representing the card to load.
|
||||
* @return Loaded QImage if found; otherwise, an empty QImage.
|
||||
*
|
||||
* Uses a set of name variants and folder paths to attempt to locate the correct image.
|
||||
*/
|
||||
QImage tryLoad(const ExactCard &toLoad) const;
|
||||
|
||||
private:
|
||||
QString picsPath, customPicsPath;
|
||||
QString picsPath; ///< Path to standard card image folder
|
||||
QString customPicsPath; ///< Path to custom card image folder
|
||||
|
||||
QMultiHash<QString, QString> customFolderIndex; // multimap of cardName to picPaths
|
||||
QTimer *refreshTimer;
|
||||
QMultiHash<QString, QString> customFolderIndex; ///< Multimap from cardName to file paths in CUSTOM folder
|
||||
QTimer *refreshTimer; ///< Timer for periodic folder index refresh
|
||||
|
||||
/**
|
||||
* @brief Rebuilds the index of the custom image folder.
|
||||
*
|
||||
* Iterates through all subdirectories of the CUSTOM folder and populates
|
||||
* `customFolderIndex` with all discovered image files keyed by base name
|
||||
* and complete base name.
|
||||
*/
|
||||
void refreshIndex();
|
||||
|
||||
/**
|
||||
* @brief Attempts to load a card image from disk given its set and name info.
|
||||
* @param setName Corrected short name of the card's set.
|
||||
* @param correctedCardName Corrected card name (e.g., normalized name).
|
||||
* @param collectorNumber Collector number of the card.
|
||||
* @param providerId Optional provider UUID of the card.
|
||||
* @return Loaded QImage if found; otherwise, an empty QImage.
|
||||
*
|
||||
* Searches in both the custom folder index and standard pictures paths.
|
||||
* Uses several filename patterns to match card images, in order from
|
||||
* most-specific to least-specific.
|
||||
*/
|
||||
QImage tryLoadCardImageFromDisk(const QString &setName,
|
||||
const QString &correctedCardName,
|
||||
const QString &collectorNumber,
|
||||
const QString &providerId) const;
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Updates internal paths when the user changes picture settings.
|
||||
*
|
||||
* Triggered by `SettingsCache::picsPathChanged`.
|
||||
*/
|
||||
void picsPathChanged();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,26 +1,43 @@
|
||||
/**
|
||||
* @file card_picture_loader_request_status_display_widget.h
|
||||
* @ingroup PictureLoader
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
||||
#define PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
||||
|
||||
#include "card_picture_loader_worker_work.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
|
||||
/**
|
||||
* @class CardPictureLoaderRequestStatusDisplayWidget
|
||||
* @ingroup PictureLoader
|
||||
* @brief A small widget to display the status of a single card image request.
|
||||
*
|
||||
* Displays:
|
||||
* - Card name
|
||||
* - Set short name
|
||||
* - Provider ID
|
||||
* - Start time of request
|
||||
* - Elapsed time since start
|
||||
* - Finished status
|
||||
* - URL of the requested image
|
||||
*/
|
||||
class CardPictureLoaderRequestStatusDisplayWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a new status widget for a specific card image request.
|
||||
* @param parent Parent widget
|
||||
* @param url URL of the image being requested
|
||||
* @param card The ExactCard being downloaded
|
||||
* @param setName Set name for the card
|
||||
*/
|
||||
CardPictureLoaderRequestStatusDisplayWidget(QWidget *parent,
|
||||
const QUrl &url,
|
||||
const ExactCard &card,
|
||||
const QString &setName);
|
||||
|
||||
/** Marks the request as finished */
|
||||
void setFinished()
|
||||
{
|
||||
finished->setText("True");
|
||||
@@ -28,19 +45,25 @@ public:
|
||||
repaint();
|
||||
}
|
||||
|
||||
/** Returns whether the request has finished */
|
||||
bool getFinished() const
|
||||
{
|
||||
return finished->text() == "True";
|
||||
}
|
||||
|
||||
/** Updates the elapsed time display */
|
||||
void setElapsedTime(const QString &_elapsedTime) const
|
||||
{
|
||||
elapsedTime->setText(_elapsedTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Queries the elapsed time in seconds since the request started
|
||||
* @return Elapsed time in seconds
|
||||
*/
|
||||
int queryElapsedSeconds()
|
||||
{
|
||||
if (!finished) {
|
||||
if (!getFinished()) {
|
||||
int elapsedSeconds = QDateTime::fromString(startTime->text()).secsTo(QDateTime::currentDateTime());
|
||||
elapsedTime->setText(QString::number(elapsedSeconds));
|
||||
update();
|
||||
@@ -50,25 +73,27 @@ public:
|
||||
return elapsedTime->text().toInt();
|
||||
}
|
||||
|
||||
/** Returns the start time as a string */
|
||||
QString getStartTime() const
|
||||
{
|
||||
return startTime->text();
|
||||
}
|
||||
|
||||
/** Returns the URL of the request */
|
||||
QString getUrl() const
|
||||
{
|
||||
return url->text();
|
||||
}
|
||||
|
||||
private:
|
||||
QHBoxLayout *layout;
|
||||
QLabel *name;
|
||||
QLabel *setShortname;
|
||||
QLabel *providerId;
|
||||
QLabel *startTime;
|
||||
QLabel *elapsedTime;
|
||||
QLabel *finished;
|
||||
QLabel *url;
|
||||
QHBoxLayout *layout; ///< Horizontal layout for arranging labels
|
||||
QLabel *name; ///< Card name
|
||||
QLabel *setShortname; ///< Set short name
|
||||
QLabel *providerId; ///< Provider ID for the card
|
||||
QLabel *startTime; ///< Start time of the request
|
||||
QLabel *elapsedTime; ///< Elapsed time since start
|
||||
QLabel *finished; ///< Whether the request has finished
|
||||
QLabel *url; ///< URL of the requested image
|
||||
};
|
||||
|
||||
#endif // PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* @file card_picture_loader_status_bar.h
|
||||
* @ingroup PictureLoader
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef PICTURE_LOADER_STATUS_BAR_H
|
||||
#define PICTURE_LOADER_STATUS_BAR_H
|
||||
|
||||
@@ -12,24 +6,56 @@
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QProgressBar>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
/**
|
||||
* @class CardPictureLoaderStatusBar
|
||||
* @ingroup PictureLoader
|
||||
* @brief Displays the status of card image downloads in a horizontal progress bar with a log popup.
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Shows overall progress of image downloads.
|
||||
* - Maintains a log of individual requests via a popup (SettingsButtonWidget).
|
||||
* - Cleans up finished request entries automatically after a delay.
|
||||
*/
|
||||
class CardPictureLoaderStatusBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a status bar with progress bar and log button.
|
||||
* @param parent Parent widget
|
||||
*/
|
||||
explicit CardPictureLoaderStatusBar(QWidget *parent);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Adds a queued image download to the log and increments the progress bar maximum.
|
||||
* @param url URL of the image
|
||||
* @param card The card being loaded
|
||||
* @param setName The set name of the card
|
||||
*/
|
||||
void addQueuedImageLoad(const QUrl &url, const ExactCard &card, const QString &setName);
|
||||
|
||||
/**
|
||||
* @brief Marks an image as successfully loaded.
|
||||
* Updates the progress bar and marks the corresponding log entry as finished.
|
||||
* @param url URL of the successfully loaded image
|
||||
*/
|
||||
void addSuccessfulImageLoad(const QUrl &url);
|
||||
|
||||
/**
|
||||
* @brief Cleans up old entries from the log that have finished more than 10 seconds ago.
|
||||
* Adjusts the progress bar accordingly.
|
||||
*/
|
||||
void cleanOldEntries();
|
||||
|
||||
private:
|
||||
QHBoxLayout *layout;
|
||||
QProgressBar *progressBar;
|
||||
SettingsButtonWidget *loadLog;
|
||||
QTimer *cleaner;
|
||||
QHBoxLayout *layout; ///< Horizontal layout containing progress bar and log button
|
||||
QProgressBar *progressBar; ///< Progress bar showing overall download progress
|
||||
SettingsButtonWidget *loadLog; ///< Popup log showing individual request statuses
|
||||
QTimer *cleaner; ///< Timer for periodically cleaning old log entries
|
||||
};
|
||||
|
||||
#endif // PICTURE_LOADER_STATUS_BAR_H
|
||||
|
||||
@@ -105,9 +105,6 @@ void CardPictureLoaderWorker::resetRequestQuota()
|
||||
processQueuedRequests();
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps processing requests from the queue until it is empty or until the quota runs out.
|
||||
*/
|
||||
void CardPictureLoaderWorker::processQueuedRequests()
|
||||
{
|
||||
while (requestQuota > 0 && processSingleRequest()) {
|
||||
@@ -115,10 +112,6 @@ void CardPictureLoaderWorker::processQueuedRequests()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately processes a single queued request. No-ops if the load queue is empty
|
||||
* @return If a request was processed
|
||||
*/
|
||||
bool CardPictureLoaderWorker::processSingleRequest()
|
||||
{
|
||||
if (!requestLoadQueue.isEmpty()) {
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* @file card_picture_loader_worker.h
|
||||
* @ingroup PictureLoader
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef PICTURE_LOADER_WORKER_H
|
||||
#define PICTURE_LOADER_WORKER_H
|
||||
|
||||
@@ -27,57 +21,131 @@
|
||||
#define REDIRECT_TIMESTAMP "timestamp"
|
||||
#define REDIRECT_CACHE_FILENAME "cache.ini"
|
||||
|
||||
inline Q_LOGGING_CATEGORY(CardPictureLoaderWorkerLog, "card_picture_loader.worker");
|
||||
inline Q_LOGGING_CATEGORY(CardPictureLoaderWorkerLog, "card_picture_loader.worker")
|
||||
|
||||
class CardPictureLoaderWorkerWork;
|
||||
class CardPictureLoaderWorkerWork;
|
||||
|
||||
/**
|
||||
* @class CardPictureLoaderWorker
|
||||
* @ingroup PictureLoader
|
||||
* @brief Handles asynchronous loading of card images, both locally and via network.
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Maintain a queue of network image requests with rate-limiting.
|
||||
* - Load images from local cache first via CardPictureLoaderLocal.
|
||||
* - Handle network redirects and persistent caching of redirects.
|
||||
* - Deduplicate simultaneous requests for the same card.
|
||||
* - Emit signals for status updates and loaded images.
|
||||
*/
|
||||
class CardPictureLoaderWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a CardPictureLoaderWorker.
|
||||
*
|
||||
* Initializes network manager, cache, redirect cache, local loader, and request quota timer.
|
||||
*/
|
||||
explicit CardPictureLoaderWorker();
|
||||
|
||||
~CardPictureLoaderWorker() override;
|
||||
|
||||
void enqueueImageLoad(const ExactCard &card); // Starts a thread for the image to be loaded
|
||||
void queueRequest(const QUrl &url, CardPictureLoaderWorkerWork *worker); // Queues network requests for load threads
|
||||
/**
|
||||
* @brief Enqueues an ExactCard for loading.
|
||||
* @param card ExactCard to load
|
||||
*
|
||||
* This will first try to load the image locally; if that fails, it will enqueue a network request.
|
||||
*/
|
||||
void enqueueImageLoad(const ExactCard &card);
|
||||
|
||||
/**
|
||||
* @brief Queues a network request for a given URL and worker thread.
|
||||
* @param url URL to load
|
||||
* @param worker Worker handling this request
|
||||
*/
|
||||
void queueRequest(const QUrl &url, CardPictureLoaderWorkerWork *worker);
|
||||
|
||||
/** @brief Clears the network cache and redirect cache. */
|
||||
void clearNetworkCache();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Makes a network request for the given URL using the specified worker.
|
||||
* @param url URL to load
|
||||
* @param workThread Worker handling the request
|
||||
* @return The QNetworkReply object representing the request
|
||||
*/
|
||||
QNetworkReply *makeRequest(const QUrl &url, CardPictureLoaderWorkerWork *workThread);
|
||||
|
||||
/** @brief Processes all queued requests respecting the request quota. */
|
||||
void processQueuedRequests();
|
||||
|
||||
/**
|
||||
* @brief Processes a single queued request.
|
||||
* @return true if a request was processed, false if queue is empty.
|
||||
*/
|
||||
bool processSingleRequest();
|
||||
|
||||
/**
|
||||
* @brief Handles an image that has finished loading.
|
||||
* @param card The ExactCard that was loaded
|
||||
* @param image The loaded QImage; empty if loading failed
|
||||
*/
|
||||
void handleImageLoaded(const ExactCard &card, const QImage &image);
|
||||
|
||||
/** @brief Caches a redirect mapping between original and redirected URL. */
|
||||
void cacheRedirect(const QUrl &originalUrl, const QUrl &redirectUrl);
|
||||
|
||||
/** @brief Removes a URL from the network cache. */
|
||||
void removedCachedUrl(const QUrl &url);
|
||||
|
||||
private:
|
||||
QThread *pictureLoaderThread;
|
||||
QNetworkAccessManager *networkManager;
|
||||
QNetworkDiskCache *cache;
|
||||
QHash<QUrl, QPair<QUrl, QDateTime>> redirectCache; // Stores redirect and timestamp
|
||||
QString cacheFilePath; // Path to persistent storage
|
||||
static constexpr int CacheTTLInDays = 30; // TODO: Make user configurable
|
||||
bool picDownload;
|
||||
QQueue<QPair<QUrl, CardPictureLoaderWorkerWork *>> requestLoadQueue;
|
||||
QThread *pictureLoaderThread; ///< Thread for executing worker tasks
|
||||
QNetworkAccessManager *networkManager; ///< Network manager for HTTP requests
|
||||
QNetworkDiskCache *cache; ///< Disk cache for downloaded images
|
||||
QHash<QUrl, QPair<QUrl, QDateTime>> redirectCache; ///< Maps original URLs to redirects with timestamp
|
||||
QString cacheFilePath; ///< Path to persistent redirect cache file
|
||||
static constexpr int CacheTTLInDays = 30; ///< Time-to-live for redirect cache entries (days)
|
||||
bool picDownload; ///< Whether downloading images from network is enabled
|
||||
QQueue<QPair<QUrl, CardPictureLoaderWorkerWork *>> requestLoadQueue; ///< Queue of pending network requests
|
||||
|
||||
int requestQuota;
|
||||
QTimer requestTimer; // Timer for refreshing request quota
|
||||
int requestQuota; ///< Remaining requests allowed per second
|
||||
QTimer requestTimer; ///< Timer to reset the request quota
|
||||
|
||||
CardPictureLoaderLocal *localLoader;
|
||||
QSet<QString> currentlyLoading; // for deduplication purposes. Contains pixmapCacheKey
|
||||
CardPictureLoaderLocal *localLoader; ///< Loader for local images
|
||||
QSet<QString> currentlyLoading; ///< Deduplication: contains pixmapCacheKey currently being loaded
|
||||
|
||||
/** @brief Returns cached redirect URL for the given original URL, if available. */
|
||||
QUrl getCachedRedirect(const QUrl &originalUrl) const;
|
||||
|
||||
/** @brief Loads redirect cache from disk. */
|
||||
void loadRedirectCache();
|
||||
|
||||
/** @brief Saves redirect cache to disk. */
|
||||
void saveRedirectCache() const;
|
||||
|
||||
/** @brief Removes stale redirect entries older than TTL. */
|
||||
void cleanStaleEntries();
|
||||
|
||||
private slots:
|
||||
/** @brief Resets the request quota for rate-limiting. */
|
||||
void resetRequestQuota();
|
||||
|
||||
/** @brief Handles image load requests enqueued on this worker. */
|
||||
void handleImageLoadEnqueued(const ExactCard &card);
|
||||
|
||||
signals:
|
||||
/** @brief Emitted when an image load is enqueued. */
|
||||
void imageLoadEnqueued(const ExactCard &card);
|
||||
|
||||
/** @brief Emitted when an image has finished loading. */
|
||||
void imageLoaded(const ExactCard &card, const QImage &image);
|
||||
|
||||
/** @brief Emitted when a request is added to the network queue. */
|
||||
void imageRequestQueued(const QUrl &url, const ExactCard &card, const QString &setName);
|
||||
|
||||
/** @brief Emitted when a network request successfully completes. */
|
||||
void imageRequestSucceeded(const QUrl &url);
|
||||
};
|
||||
|
||||
|
||||
@@ -51,10 +51,6 @@ void CardPictureLoaderWorkerWork::startNextPicDownload()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts another pic download using the next possible url combination for the card.
|
||||
* If all possibilities are exhausted, then concludes the image loading with an empty QImage.
|
||||
*/
|
||||
void CardPictureLoaderWorkerWork::picDownloadFailed()
|
||||
{
|
||||
/* Take advantage of short-circuiting here to call the nextUrl until one
|
||||
@@ -73,10 +69,6 @@ void CardPictureLoaderWorkerWork::picDownloadFailed()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param reply The reply. Takes ownership of the object
|
||||
*/
|
||||
void CardPictureLoaderWorkerWork::handleNetworkReply(QNetworkReply *reply)
|
||||
{
|
||||
QVariant redirectTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
@@ -180,10 +172,6 @@ void CardPictureLoaderWorkerWork::handleSuccessfulReply(QNetworkReply *reply)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reply The reply to load the image from
|
||||
* @return The loaded image, or an empty QImage if loading failed
|
||||
*/
|
||||
QImage CardPictureLoaderWorkerWork::tryLoadImageFromReply(QNetworkReply *reply)
|
||||
{
|
||||
static constexpr int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h
|
||||
@@ -207,10 +195,6 @@ QImage CardPictureLoaderWorkerWork::tryLoadImageFromReply(QNetworkReply *reply)
|
||||
return imgReader.read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method when the image has finished being loaded.
|
||||
* @param image The image that was loaded. Empty QImage indicates failure.
|
||||
*/
|
||||
void CardPictureLoaderWorkerWork::concludeImageLoad(const QImage &image)
|
||||
{
|
||||
emit imageLoaded(cardToDownload.getCard(), image);
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* @file picture_loader_worker_work.h
|
||||
* @ingroup PictureLoader
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef PICTURE_LOADER_WORKER_WORK_H
|
||||
#define PICTURE_LOADER_WORKER_WORK_H
|
||||
|
||||
@@ -17,55 +11,96 @@
|
||||
#include <QThread>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
|
||||
#define REDIRECT_HEADER_NAME "redirects"
|
||||
#define REDIRECT_ORIGINAL_URL "original"
|
||||
#define REDIRECT_URL "redirect"
|
||||
#define REDIRECT_TIMESTAMP "timestamp"
|
||||
#define REDIRECT_CACHE_FILENAME "cache.ini"
|
||||
|
||||
inline Q_LOGGING_CATEGORY(CardPictureLoaderWorkerWorkLog, "card_picture_loader.worker");
|
||||
|
||||
class CardPictureLoaderWorker;
|
||||
|
||||
/**
|
||||
* @class CardPictureLoaderWorkerWork
|
||||
* @ingroup PictureLoader
|
||||
* @brief Handles downloading a single card image from network or local sources.
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Try to load images from all possible URLs and sets for a given ExactCard.
|
||||
* - Handle network redirects and cache invalidation.
|
||||
* - Check for blacklisted images and discard them.
|
||||
* - Emit signals when image is successfully loaded or all attempts fail.
|
||||
* - Delete itself after loading completes.
|
||||
*/
|
||||
class CardPictureLoaderWorkerWork : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a worker for downloading a specific card image.
|
||||
* @param worker The orchestrating CardPictureLoaderWorker
|
||||
* @param toLoad The ExactCard to download
|
||||
*/
|
||||
explicit CardPictureLoaderWorkerWork(const CardPictureLoaderWorker *worker, const ExactCard &toLoad);
|
||||
|
||||
CardPictureToLoad cardToDownload;
|
||||
CardPictureToLoad cardToDownload; ///< The card and associated URLs to try downloading
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Handles a finished network reply for the card image.
|
||||
* @param reply The QNetworkReply object to process. Ownership is transferred.
|
||||
*/
|
||||
void handleNetworkReply(QNetworkReply *reply);
|
||||
|
||||
private:
|
||||
bool picDownload;
|
||||
bool picDownload; ///< Whether network downloading is enabled
|
||||
|
||||
/** @brief Starts downloading the next URL for this card. */
|
||||
void startNextPicDownload();
|
||||
|
||||
/** @brief Called when all URLs have been exhausted or download failed. */
|
||||
void picDownloadFailed();
|
||||
|
||||
/** @brief Processes a failed network reply. */
|
||||
void handleFailedReply(const QNetworkReply *reply);
|
||||
|
||||
/** @brief Processes a successful network reply. */
|
||||
void handleSuccessfulReply(QNetworkReply *reply);
|
||||
|
||||
/**
|
||||
* @brief Attempts to read an image from a network reply.
|
||||
* @param reply The network reply
|
||||
* @return The loaded QImage or an empty image if reading failed
|
||||
*/
|
||||
QImage tryLoadImageFromReply(QNetworkReply *reply);
|
||||
|
||||
/**
|
||||
* @brief Finalizes the image loading process.
|
||||
* @param image The loaded image (empty if failed)
|
||||
*
|
||||
* Emits imageLoaded() and deletes this object.
|
||||
*/
|
||||
void concludeImageLoad(const QImage &image);
|
||||
|
||||
private slots:
|
||||
/** @brief Updates the picDownload setting when it changes. */
|
||||
void picDownloadChanged();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* Emitted when this worker has successfully loaded the image or has exhausted all attempts at loading the image.
|
||||
* Failures are represented by an empty QImage.
|
||||
* Note that this object will delete itself as this signal is emitted.
|
||||
* @brief Emitted when the image has been loaded or all attempts failed.
|
||||
* @param card The card corresponding to the image
|
||||
* @param image The loaded image (empty if failed)
|
||||
*
|
||||
* The worker deletes itself after emitting this signal.
|
||||
*/
|
||||
void imageLoaded(const ExactCard &card, const QImage &image);
|
||||
|
||||
/**
|
||||
* Emitted when a request did not return a 400 or 500 response
|
||||
*/
|
||||
/** @brief Emitted when a network request completes successfully. */
|
||||
void requestSucceeded(const QUrl &url);
|
||||
|
||||
/** @brief Request that a URL be downloaded. */
|
||||
void requestImageDownload(const QUrl &url, CardPictureLoaderWorkerWork *instance);
|
||||
|
||||
/** @brief Emitted when a URL has been redirected. */
|
||||
void urlRedirected(const QUrl &originalUrl, const QUrl &redirectUrl);
|
||||
|
||||
/** @brief Emitted when a cached URL is invalid and must be removed. */
|
||||
void cachedUrlInvalidated(const QUrl &url);
|
||||
};
|
||||
|
||||
|
||||
@@ -20,12 +20,6 @@ CardPictureToLoad::CardPictureToLoad(const ExactCard &_card)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a list of all the sets from the card, sorted in priority order.
|
||||
* If the card does not contain any sets, then a dummy set will be inserted into the list.
|
||||
*
|
||||
* @return A list of sets. Will not be empty.
|
||||
*/
|
||||
QList<CardSetPtr> CardPictureToLoad::extractSetsSorted(const ExactCard &card)
|
||||
{
|
||||
QList<CardSetPtr> sortedSets;
|
||||
@@ -109,11 +103,6 @@ void CardPictureToLoad::populateSetUrls()
|
||||
(void)nextUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the currentSet to the next set in the list. Then repopulates the url list with the urls from that set.
|
||||
* If we are already at the end of the list, then currentSet is set to empty.
|
||||
* @return If we are already at the end of the list
|
||||
*/
|
||||
bool CardPictureToLoad::nextSet()
|
||||
{
|
||||
if (!sortedSets.isEmpty()) {
|
||||
@@ -125,11 +114,6 @@ bool CardPictureToLoad::nextSet()
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the currentUrl to the next url in the list.
|
||||
* If we are already at the end of the list, then currentUrl is set to empty.
|
||||
* @return If we are already at the end of the list
|
||||
*/
|
||||
bool CardPictureToLoad::nextUrl()
|
||||
{
|
||||
if (!currentSetUrls.isEmpty()) {
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* @file card_picture_to_load.h
|
||||
* @ingroup PictureLoader
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef PICTURE_TO_LOAD_H
|
||||
#define PICTURE_TO_LOAD_H
|
||||
|
||||
@@ -12,37 +6,97 @@
|
||||
|
||||
inline Q_LOGGING_CATEGORY(CardPictureToLoadLog, "card_picture_loader.picture_to_load");
|
||||
|
||||
/**
|
||||
* @class CardPictureToLoad
|
||||
* @ingroup PictureLoader
|
||||
* @brief Manages all URLs and sets for downloading a specific card image.
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Maintains a sorted list of sets for a card.
|
||||
* - Generates URLs to download images from, including custom URLs and URL templates.
|
||||
* - Tracks which URL and set is currently being attempted.
|
||||
* - Provides helper methods to advance to next URL or set.
|
||||
*/
|
||||
class CardPictureToLoad
|
||||
{
|
||||
private:
|
||||
ExactCard card;
|
||||
QList<CardSetPtr> sortedSets;
|
||||
QList<QString> urlTemplates;
|
||||
QList<QString> currentSetUrls;
|
||||
QString currentUrl;
|
||||
CardSetPtr currentSet;
|
||||
ExactCard card; ///< The ExactCard being downloaded
|
||||
QList<CardSetPtr> sortedSets; ///< All sets for this card, sorted by priority
|
||||
QList<QString> urlTemplates; ///< URL templates from settings
|
||||
QList<QString> currentSetUrls; ///< URLs for the current set being attempted
|
||||
QString currentUrl; ///< Currently active URL to download
|
||||
CardSetPtr currentSet; ///< Currently active set
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a CardPictureToLoad for a given ExactCard.
|
||||
* @param _card The card to download
|
||||
*
|
||||
* Initializes URL templates and pre-populates the first set URLs.
|
||||
*/
|
||||
explicit CardPictureToLoad(const ExactCard &_card);
|
||||
|
||||
/** @return The card being loaded. */
|
||||
const ExactCard &getCard() const
|
||||
{
|
||||
return card;
|
||||
}
|
||||
|
||||
/** @return The current URL being attempted. */
|
||||
QString getCurrentUrl() const
|
||||
{
|
||||
return currentUrl;
|
||||
}
|
||||
|
||||
/** @return The current set being attempted. */
|
||||
CardSetPtr getCurrentSet() const
|
||||
{
|
||||
return currentSet;
|
||||
}
|
||||
|
||||
/** @return The short name of the current set, or empty string if no set. */
|
||||
QString getSetName() const;
|
||||
|
||||
/**
|
||||
* @brief Transforms a URL template into a concrete URL for this card/set.
|
||||
* @param urlTemplate The URL template to transform
|
||||
* @return The transformed URL or empty string if the template cannot be fulfilled
|
||||
*/
|
||||
QString transformUrl(const QString &urlTemplate) const;
|
||||
|
||||
/**
|
||||
* @brief Advance to the next set in the list.
|
||||
* @return True if a next set exists and was selected, false if at the end.
|
||||
*
|
||||
* Updates currentSet and repopulates currentSetUrls.
|
||||
* If we are already at the end of the list, then currentSet is set to empty.
|
||||
*/
|
||||
bool nextSet();
|
||||
|
||||
/**
|
||||
* @brief Advance to the next URL in the current set's list.
|
||||
* @return True if a next URL exists, false if at the end.
|
||||
*
|
||||
* Updates currentUrl.
|
||||
* If we are already at the end of the list, then currentUrl is set to empty.
|
||||
*/
|
||||
bool nextUrl();
|
||||
|
||||
/**
|
||||
* @brief Populates the currentSetUrls list with URLs for the current set.
|
||||
*
|
||||
* Includes custom URLs first, followed by template-based URLs.
|
||||
*/
|
||||
void populateSetUrls();
|
||||
|
||||
/**
|
||||
* @brief Extract all sets from the card and sort them by priority.
|
||||
* @param card The card to extract sets from
|
||||
* @return A non-empty list of CardSetPtr, sorted by priority
|
||||
*
|
||||
* If the card has no sets, a dummy set is inserted. Also ensures
|
||||
* the printing corresponding to the ExactCard is first in the list.
|
||||
*/
|
||||
static QList<CardSetPtr> extractSetsSorted(const ExactCard &card);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user