From 79eb19a19270ce7ad9e0348c4405dfaf41c146c8 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Wed, 10 Dec 2025 10:42:45 +0100 Subject: [PATCH 1/8] Add COMIC_VINE_USER_AGENT to YACReaderLibrary.ini to be able to customize the user agent --- CHANGELOG.md | 5 +++ ...comic_vine_all_volume_comics_retriever.cpp | 6 ++-- .../comic_vine_all_volume_comics_retriever.h | 3 +- .../comic_vine/comic_vine_client.cpp | 35 +++++++++++++------ .../comic_vine/comic_vine_client.h | 1 + common/http_worker.cpp | 6 ++-- common/http_worker.h | 4 +-- common/yacreader_global.h | 2 +- common/yacreader_global_gui.h | 1 + custom_widgets/whats_new_dialog.cpp | 1 + 10 files changed, 44 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e011aafae..c6b631325 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Version counting is based on semantic versioning (Major.Feature.Patch) +## 9.16.2 (WIP) + +### YACReaderLibrary +* New customizable User Agent string to use it with Comic Vine. It can be set in YACReaderLibrary.ini in the [ComicVine] section using the `COMIC_VINE_USER_AGENT` key. + ## 9.16.1 ### YACReaderLibrary diff --git a/YACReaderLibrary/comic_vine/comic_vine_all_volume_comics_retriever.cpp b/YACReaderLibrary/comic_vine/comic_vine_all_volume_comics_retriever.cpp index e03c7bb1d..58afc5a47 100644 --- a/YACReaderLibrary/comic_vine/comic_vine_all_volume_comics_retriever.cpp +++ b/YACReaderLibrary/comic_vine/comic_vine_all_volume_comics_retriever.cpp @@ -7,8 +7,8 @@ #include #include -ComicVineAllVolumeComicsRetriever::ComicVineAllVolumeComicsRetriever(const QString &volumeURLString, QObject *parent) - : QObject(parent), volumeURLString(volumeURLString) +ComicVineAllVolumeComicsRetriever::ComicVineAllVolumeComicsRetriever(const QString &volumeURLString, const QString &userAgent, QObject *parent) + : QObject(parent), volumeURLString(volumeURLString), userAgent(userAgent) { } @@ -19,7 +19,7 @@ void ComicVineAllVolumeComicsRetriever::getAllVolumeComics() void ComicVineAllVolumeComicsRetriever::getAllVolumeComics(int range) { - HttpWorker *search = new HttpWorker(volumeURLString.arg(range)); + HttpWorker *search = new HttpWorker(volumeURLString.arg(range), userAgent); connect(search, &HttpWorker::dataReady, this, &ComicVineAllVolumeComicsRetriever::appendVolumeComicsInfo); connect(search, &HttpWorker::timeout, this, &ComicVineAllVolumeComicsRetriever::timeOut); connect(search, &HttpWorker::timeout, this, &ComicVineAllVolumeComicsRetriever::finished); diff --git a/YACReaderLibrary/comic_vine/comic_vine_all_volume_comics_retriever.h b/YACReaderLibrary/comic_vine/comic_vine_all_volume_comics_retriever.h index 24e5f6fd4..5f4467c7b 100644 --- a/YACReaderLibrary/comic_vine/comic_vine_all_volume_comics_retriever.h +++ b/YACReaderLibrary/comic_vine/comic_vine_all_volume_comics_retriever.h @@ -7,7 +7,7 @@ class ComicVineAllVolumeComicsRetriever : public QObject { Q_OBJECT public: - explicit ComicVineAllVolumeComicsRetriever(const QString &volumeURLString, QObject *parent = nullptr); + explicit ComicVineAllVolumeComicsRetriever(const QString &volumeURLString, const QString &userAgent, QObject *parent = nullptr); void getAllVolumeComics(); protected: @@ -21,6 +21,7 @@ protected slots: protected: QString volumeURLString; + QString userAgent; QList jsonResponses; QString consolidateJSON(); diff --git a/YACReaderLibrary/comic_vine/comic_vine_client.cpp b/YACReaderLibrary/comic_vine/comic_vine_client.cpp index 75e2dde94..9ed084d16 100644 --- a/YACReaderLibrary/comic_vine/comic_vine_client.cpp +++ b/YACReaderLibrary/comic_vine/comic_vine_client.cpp @@ -60,6 +60,7 @@ ComicVineClient::ComicVineClient(QObject *parent) settings = new QSettings(YACReader::getSettingsPath() + "/YACReaderLibrary.ini", QSettings::IniFormat); // TODO unificar la creación del fichero de config con el servidor settings->beginGroup("ComicVine"); baseURL = settings->value(COMIC_VINE_BASE_URL, "https://comicvine.gamespot.com/api").toString(); + userAgent = settings->value(COMIC_VINE_USER_AGENT, QStringLiteral("YACReader - Yet Another Comic Reader/") + VERSION).toString(); } ComicVineClient::~ComicVineClient() @@ -70,7 +71,9 @@ ComicVineClient::~ComicVineClient() // CV_SEARCH void ComicVineClient::search(const QString &query, int page) { - HttpWorker *search = new HttpWorker(QString(CV_SEARCH).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(query).arg(page)); + HttpWorker *search = new HttpWorker( + QString(CV_SEARCH).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(query).arg(page), + userAgent); connect(search, &HttpWorker::dataReady, this, &ComicVineClient::proccessVolumesSearchData); connect(search, &HttpWorker::timeout, this, &ComicVineClient::timeOut); connect(search, &QThread::finished, search, &QObject::deleteLater); @@ -80,7 +83,9 @@ void ComicVineClient::search(const QString &query, int page) // CV_EXACT_VOLUME_SEARCH void ComicVineClient::searchExactVolume(const QString &query, int page) { - HttpWorker *search = new HttpWorker(QString(CV_EXACT_VOLUME_SEARCH).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(query).arg((page - 1) * 100)); + HttpWorker *search = new HttpWorker( + QString(CV_EXACT_VOLUME_SEARCH).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(query).arg((page - 1) * 100), + userAgent); connect(search, &HttpWorker::dataReady, this, &ComicVineClient::proccessVolumesSearchData); connect(search, &HttpWorker::timeout, this, &ComicVineClient::timeOut); connect(search, &QThread::finished, search, &QObject::deleteLater); @@ -119,7 +124,9 @@ void ComicVineClient::proccessComicDetailData(const QByteArray &data) // CV_SERIES_DETAIL void ComicVineClient::getSeriesDetail(const QString &id) { - HttpWorker *search = new HttpWorker(QString(CV_SERIES_DETAIL).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(id)); + HttpWorker *search = new HttpWorker( + QString(CV_SERIES_DETAIL).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(id), + userAgent); connect(search, &HttpWorker::dataReady, this, &ComicVineClient::proccessSeriesDetailData); connect(search, &HttpWorker::timeout, this, &ComicVineClient::timeOut); connect(search, &QThread::finished, search, &QObject::deleteLater); @@ -128,7 +135,7 @@ void ComicVineClient::getSeriesDetail(const QString &id) void ComicVineClient::getSeriesCover(const QString &url) { - auto search = new HttpWorker(url); + auto search = new HttpWorker(url, userAgent); connect(search, &HttpWorker::dataReady, this, &ComicVineClient::seriesCover); connect(search, &HttpWorker::timeout, this, &ComicVineClient::timeOut); // TODO connect(search, &QThread::finished, search, &QObject::deleteLater); @@ -138,7 +145,9 @@ void ComicVineClient::getSeriesCover(const QString &url) // CV_COMIC_IDS void ComicVineClient::getVolumeComicsInfo(const QString &idVolume, int page) { - HttpWorker *search = new HttpWorker(QString(CV_COMICS_INFO).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(idVolume).arg((page - 1) * 100)); + HttpWorker *search = new HttpWorker( + QString(CV_COMICS_INFO).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(idVolume).arg((page - 1) * 100), + userAgent); connect(search, &HttpWorker::dataReady, this, &ComicVineClient::processVolumeComicsInfo); connect(search, &HttpWorker::timeout, this, &ComicVineClient::timeOut); // TODO connect(search, &QThread::finished, search, &QObject::deleteLater); @@ -148,7 +157,7 @@ void ComicVineClient::getVolumeComicsInfo(const QString &idVolume, int page) void ComicVineClient::getAllVolumeComicsInfo(const QString &idVolume) { QString url = QString(CV_COMICS_INFO).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(idVolume); - auto comicsRetriever = new ComicVineAllVolumeComicsRetriever(url); + auto comicsRetriever = new ComicVineAllVolumeComicsRetriever(url, userAgent); connect(comicsRetriever, &ComicVineAllVolumeComicsRetriever::allVolumeComicsInfo, this, &ComicVineClient::volumeComicsInfo); connect(comicsRetriever, &ComicVineAllVolumeComicsRetriever::finished, this, &ComicVineClient::finished); @@ -168,7 +177,9 @@ void ComicVineClient::getComicId(const QString &id, int comicNumber) // CV_COMIC_DETAIL QByteArray ComicVineClient::getComicDetail(const QString &id, bool &outError, bool &outTimeout) { - HttpWorker *search = new HttpWorker(QString(CV_COMIC_DETAIL).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(id)); + HttpWorker *search = new HttpWorker( + QString(CV_COMIC_DETAIL).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(id), + userAgent); // connect(search,SIGNAL(dataReady(const QByteArray &)),this,SLOT(proccessComicDetailData(const QByteArray &))); // connect(search,SIGNAL(timeout()),this,SIGNAL(timeOut())); @@ -186,7 +197,9 @@ QByteArray ComicVineClient::getComicDetail(const QString &id, bool &outError, bo // CV_COMIC_DETAIL void ComicVineClient::getComicDetailAsync(const QString &id) { - HttpWorker *search = new HttpWorker(QString(CV_COMIC_DETAIL).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(id)); + HttpWorker *search = new HttpWorker( + QString(CV_COMIC_DETAIL).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(id), + userAgent); connect(search, &HttpWorker::dataReady, this, &ComicVineClient::proccessComicDetailData); connect(search, &HttpWorker::timeout, this, &ComicVineClient::timeOut); @@ -197,7 +210,9 @@ void ComicVineClient::getComicDetailAsync(const QString &id) // CV_STORY_ARC_DETAIL QByteArray ComicVineClient::getStoryArcDetail(const QString &id, bool &outError, bool &outTimeout) { - HttpWorker *search = new HttpWorker(QString(CV_STORY_ARC_DETAIL).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(id)); + HttpWorker *search = new HttpWorker( + QString(CV_STORY_ARC_DETAIL).replace(CV_WEB_ADDRESS, baseURL).replace(CV_API_KEY, settings->value(COMIC_VINE_API_KEY, CV_API_KEY_DEFAULT).toString()).arg(id), + userAgent); // connect(search,SIGNAL(dataReady(const QByteArray &)),this,SLOT(proccessComicDetailData(const QByteArray &))); // connect(search,SIGNAL(timeout()),this,SIGNAL(timeOut())); @@ -214,7 +229,7 @@ QByteArray ComicVineClient::getStoryArcDetail(const QString &id, bool &outError, void ComicVineClient::getComicCover(const QString &url) { - auto search = new HttpWorker(url); + auto search = new HttpWorker(url, userAgent); connect(search, &HttpWorker::dataReady, this, &ComicVineClient::comicCover); connect(search, &HttpWorker::timeout, this, &ComicVineClient::timeOut); // TODO connect(search, &QThread::finished, search, &QObject::deleteLater); diff --git a/YACReaderLibrary/comic_vine/comic_vine_client.h b/YACReaderLibrary/comic_vine/comic_vine_client.h index 43c4ba5b0..b47955d8a 100644 --- a/YACReaderLibrary/comic_vine/comic_vine_client.h +++ b/YACReaderLibrary/comic_vine/comic_vine_client.h @@ -45,5 +45,6 @@ protected slots: protected: QSettings *settings; QString baseURL; + QString userAgent; }; #endif // COMIC_VINE_CLIENT_H diff --git a/common/http_worker.cpp b/common/http_worker.cpp index 5e525503b..3ab184bec 100644 --- a/common/http_worker.cpp +++ b/common/http_worker.cpp @@ -12,8 +12,8 @@ #define PREVIOUS_VERSION "6.0.0" -HttpWorker::HttpWorker(const QString &urlString) - : QThread(), url(urlString), _error(false), _timeout(false) +HttpWorker::HttpWorker(const QString &urlString, const QString &userAgent) + : QThread(), url(urlString), userAgent(userAgent), _error(false), _timeout(false) { } @@ -50,7 +50,7 @@ void HttpWorker::run() auto request = QNetworkRequest(url); request.setHeader(QNetworkRequest::UserAgentHeader, - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/122.0 Safari/537.36"); + userAgent); QNetworkReply *reply = manager.get(request); diff --git a/common/http_worker.h b/common/http_worker.h index b0af07c46..102bc5653 100644 --- a/common/http_worker.h +++ b/common/http_worker.h @@ -4,13 +4,12 @@ #include #include #include -#include "yacreader_global.h" class HttpWorker : public QThread { Q_OBJECT public: - HttpWorker(const QString &urlString); + HttpWorker(const QString &urlString, const QString &userAgent); public slots: void get(); QByteArray getResult(); @@ -20,6 +19,7 @@ public slots: private: void run(); QUrl url; + QString userAgent; int httpGetId; QByteArray result; bool _error; diff --git a/common/yacreader_global.h b/common/yacreader_global.h index 392948cab..c47739847 100644 --- a/common/yacreader_global.h +++ b/common/yacreader_global.h @@ -9,7 +9,7 @@ class QLibrary; -#define VERSION "9.16.1" +#define VERSION "9.16.2" // Used to check if the database needs to be updated, the version is stored in the database. // This value is only incremented when the database structure changes. diff --git a/common/yacreader_global_gui.h b/common/yacreader_global_gui.h index 8d3639e03..cb7397fa0 100644 --- a/common/yacreader_global_gui.h +++ b/common/yacreader_global_gui.h @@ -68,6 +68,7 @@ #define COMIC_VINE_API_KEY "COMIC_VINE_API_KEY" #define COMIC_VINE_BASE_URL "COMIC_VINE_BASE_URL" +#define COMIC_VINE_USER_AGENT "COMIC_VINE_USER_AGENT" #define USE_BACKGROUND_IMAGE_IN_GRID_VIEW "USE_BACKGROUND_IMAGE_IN_GRID_VIEW" #define OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW "OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW" diff --git a/custom_widgets/whats_new_dialog.cpp b/custom_widgets/whats_new_dialog.cpp index f90c50e54..629fb8f76 100644 --- a/custom_widgets/whats_new_dialog.cpp +++ b/custom_widgets/whats_new_dialog.cpp @@ -68,6 +68,7 @@ YACReader::WhatsNewDialog::WhatsNewDialog(QWidget *parent) " • New button to reset to the default cover of a comic
" " • Support for storing the new image filters from iOS and Android apps
" " • Fixed cover loading in Comic Vine scraper (new in 9.16.1)
" + " • Added a customizable User Agent string to use it with Comic Vine. It can be set in YACReaderLibrary.ini in the [ComicVine] section using the COMIC_VINE_USER_AGENT key (new in 9.16.2)
" "
" "YACReaderLibraryServer
" " • Log libraries validation when the app starts
" From 626ac14d0132af058e80624bb695ee0ddfc6f56f Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Wed, 10 Dec 2025 11:10:37 +0100 Subject: [PATCH 2/8] Use the default user agent in YACReader --- YACReaderLibrary/comic_vine/comic_vine_client.cpp | 2 +- common/check_new_version.cpp | 4 +++- common/yacreader_global.h | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/YACReaderLibrary/comic_vine/comic_vine_client.cpp b/YACReaderLibrary/comic_vine/comic_vine_client.cpp index 9ed084d16..67ee031a1 100644 --- a/YACReaderLibrary/comic_vine/comic_vine_client.cpp +++ b/YACReaderLibrary/comic_vine/comic_vine_client.cpp @@ -60,7 +60,7 @@ ComicVineClient::ComicVineClient(QObject *parent) settings = new QSettings(YACReader::getSettingsPath() + "/YACReaderLibrary.ini", QSettings::IniFormat); // TODO unificar la creación del fichero de config con el servidor settings->beginGroup("ComicVine"); baseURL = settings->value(COMIC_VINE_BASE_URL, "https://comicvine.gamespot.com/api").toString(); - userAgent = settings->value(COMIC_VINE_USER_AGENT, QStringLiteral("YACReader - Yet Another Comic Reader/") + VERSION).toString(); + userAgent = settings->value(COMIC_VINE_USER_AGENT, DEFAULT_USER_AGENT).toString(); } ComicVineClient::~ComicVineClient() diff --git a/common/check_new_version.cpp b/common/check_new_version.cpp index 501191b0f..bb7738636 100644 --- a/common/check_new_version.cpp +++ b/common/check_new_version.cpp @@ -1,5 +1,7 @@ #include "check_new_version.h" +#include "yacreader_global.h" + #include #include #include @@ -14,7 +16,7 @@ #define PREVIOUS_VERSION_TESTING "6.0.0" HttpVersionChecker::HttpVersionChecker() - : HttpWorker("https://raw.githubusercontent.com/YACReader/yacreader/master/common/yacreader_global.h") + : HttpWorker("https://raw.githubusercontent.com/YACReader/yacreader/master/common/yacreader_global.h", DEFAULT_USER_AGENT) { connect(this, &HttpVersionChecker::dataReady, this, QOverload::of(&HttpVersionChecker::checkNewVersion)); } diff --git a/common/yacreader_global.h b/common/yacreader_global.h index c47739847..04c158f8a 100644 --- a/common/yacreader_global.h +++ b/common/yacreader_global.h @@ -31,6 +31,8 @@ class QLibrary; #define LIBRARIES "LIBRARIES" +#define DEFAULT_USER_AGENT "YACReader - Yet Another Comic Reader/" VERSION + #define MAX_LIBRARIES_WARNING_NUM 10 #ifdef Q_OS_MACOS From d16232dcc75f6d3fc41e9d431612012bc2ff7046 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sat, 13 Dec 2025 11:06:01 +0100 Subject: [PATCH 3/8] Prevent crash when opening the folders context menu if a folder is not selected --- YACReaderLibrary/library_window.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/YACReaderLibrary/library_window.cpp b/YACReaderLibrary/library_window.cpp index ea6e46c9e..52cfdf9a9 100644 --- a/YACReaderLibrary/library_window.cpp +++ b/YACReaderLibrary/library_window.cpp @@ -2594,6 +2594,9 @@ void LibraryWindow::showFoldersContextMenu(const QPoint &point) { QModelIndex sourceMI = foldersModelProxy->mapToSource(foldersView->indexAt(point)); + if (!sourceMI.isValid()) + return; + auto folder = foldersModel->getFolder(sourceMI); actions.setFolderAsNormalAction->setCheckable(true); From 3fb02c6fda23301e0187859dff6c21c190ff9c63 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sun, 14 Dec 2025 09:53:24 +0100 Subject: [PATCH 4/8] Update CHANGELOG --- CHANGELOG.md | 1 + custom_widgets/whats_new_dialog.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6b631325..a8a5de279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Version counting is based on semantic versioning (Major.Feature.Patch) ### YACReaderLibrary * New customizable User Agent string to use it with Comic Vine. It can be set in YACReaderLibrary.ini in the [ComicVine] section using the `COMIC_VINE_USER_AGENT` key. +* Prevent crash when opening the folders context menu if a folder is not selected. ## 9.16.1 diff --git a/custom_widgets/whats_new_dialog.cpp b/custom_widgets/whats_new_dialog.cpp index 629fb8f76..fd065a238 100644 --- a/custom_widgets/whats_new_dialog.cpp +++ b/custom_widgets/whats_new_dialog.cpp @@ -69,6 +69,7 @@ YACReader::WhatsNewDialog::WhatsNewDialog(QWidget *parent) " • Support for storing the new image filters from iOS and Android apps
" " • Fixed cover loading in Comic Vine scraper (new in 9.16.1)
" " • Added a customizable User Agent string to use it with Comic Vine. It can be set in YACReaderLibrary.ini in the [ComicVine] section using the COMIC_VINE_USER_AGENT key (new in 9.16.2)
" + " • Prevent crash when opening the folders context menu if a folder is not selected. (new in 9.16.2)
" "
" "YACReaderLibraryServer
" " • Log libraries validation when the app starts
" From 8c7916eb0c5720eaed57ef43d99e9a8f4f861d44 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sun, 14 Dec 2025 10:17:32 +0100 Subject: [PATCH 5/8] Fix accessing the root folder for setting the library type --- YACReaderLibrary/db/folder_model.cpp | 59 ++++++++++++++++++++-------- YACReaderLibrary/db/folder_model.h | 3 ++ YACReaderLibrary/library_window.cpp | 3 +- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/YACReaderLibrary/db/folder_model.cpp b/YACReaderLibrary/db/folder_model.cpp index ae24d0f92..74bb75c41 100644 --- a/YACReaderLibrary/db/folder_model.cpp +++ b/YACReaderLibrary/db/folder_model.cpp @@ -315,6 +315,35 @@ void FolderModel::takeUpdatedChildrenInfo(FolderItem *parent, const QModelIndex } } +Folder FolderModel::folderFromItem(FolderItem *folderItem) +{ + auto name = folderItem->data(FolderModel::Name).toString(); + auto parentItem = folderItem->parent(); + + QString path; + if (parentItem == nullptr) { + parentItem = rootItem; + path = "/"; + } else { + path = parentItem->data(Columns::Path).toString() + "/" + name; + } + + auto folder = Folder(folderItem->id, + parentItem->id, + name, + path, + folderItem->data(Columns::Completed).toBool(), + folderItem->data(Columns::Finished).toBool(), + folderItem->data(Columns::NumChildren).toInt(), + folderItem->data(Columns::FirstChildHash).toString(), + folderItem->data(Columns::CustomImage).toString(), + folderItem->data(Columns::Type).value(), + folderItem->data(Columns::Added).toLongLong(), + folderItem->data(Columns::Updated).toLongLong()); + + return folder; +} + void FolderModel::reload(const QModelIndex &index) { // TODO: reload just the content under index for better efficiency @@ -790,25 +819,23 @@ FolderModel *FolderModel::getSubfoldersModel(const QModelIndex &mi) return model; } +Folder FolderModel::getRootFolder() +{ + if (this->rootItem == nullptr) { + return Folder(); + } + + return folderFromItem(this->rootItem); +} + Folder FolderModel::getFolder(const QModelIndex &mi) { - auto folderItem = static_cast(mi.internalPointer()); - auto name = folderItem->data(FolderModel::Name).toString(); - auto parentItem = folderItem->parent(); - auto folder = Folder(folderItem->id, - parentItem->id, - name, - folderItem->parent()->data(Columns::Path).toString() + "/" + name, - folderItem->data(Columns::Completed).toBool(), - folderItem->data(Columns::Finished).toBool(), - folderItem->data(Columns::NumChildren).toInt(), - folderItem->data(Columns::FirstChildHash).toString(), - folderItem->data(Columns::CustomImage).toString(), - folderItem->data(Columns::Type).value(), - folderItem->data(Columns::Added).toLongLong(), - folderItem->data(Columns::Updated).toLongLong()); + if (!mi.isValid()) { + return Folder(); + } - return folder; + auto folderItem = static_cast(mi.internalPointer()); + return folderFromItem(folderItem); } QModelIndex FolderModel::getIndexFromFolderId(qulonglong folderId, const QModelIndex &parent) diff --git a/YACReaderLibrary/db/folder_model.h b/YACReaderLibrary/db/folder_model.h index 2de737f1a..85ccfa23d 100644 --- a/YACReaderLibrary/db/folder_model.h +++ b/YACReaderLibrary/db/folder_model.h @@ -76,6 +76,7 @@ class FolderModel : public QAbstractItemModel QStringList getSubfoldersNames(const QModelIndex &mi); FolderModel *getSubfoldersModel(const QModelIndex &mi); // it creates a model that contains just the direct subfolders + Folder getRootFolder(); Folder getFolder(const QModelIndex &mi); QModelIndex getIndexFromFolderId(qulonglong folderId, const QModelIndex &parent = QModelIndex()); QModelIndex getIndexFromFolder(const Folder &folder, const QModelIndex &parent = QModelIndex()); @@ -133,6 +134,8 @@ public slots: // parent contains the current data in the model (parentModelIndex is its index), updated contains fresh info loaded from the DB, void takeUpdatedChildrenInfo(FolderItem *parent, const QModelIndex &parentModelIndex, FolderItem *updated); + Folder folderFromItem(FolderItem *item); + FolderItem *rootItem; // items tree QMap items; // items lookup diff --git a/YACReaderLibrary/library_window.cpp b/YACReaderLibrary/library_window.cpp index 52cfdf9a9..78ac4f3ad 100644 --- a/YACReaderLibrary/library_window.cpp +++ b/YACReaderLibrary/library_window.cpp @@ -608,8 +608,7 @@ void LibraryWindow::createMenus() auto typeMenu = new QMenu(tr("Set type"), selectedLibrary); connect(typeMenu, &QMenu::aboutToShow, this, [=]() { - auto rootIndex = foldersModel->index(0, 0); - auto folder = foldersModel->getFolder(rootIndex); + auto folder = foldersModel->getRootFolder(); setupActions(folder.type); }); From ddaaaff74ca0299e55d4cdb0f85b4dae5a75d326 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sun, 14 Dec 2025 10:19:27 +0100 Subject: [PATCH 6/8] Update CHANGELOG --- CHANGELOG.md | 1 + custom_widgets/whats_new_dialog.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8a5de279..11ce3fc30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Version counting is based on semantic versioning (Major.Feature.Patch) ### YACReaderLibrary * New customizable User Agent string to use it with Comic Vine. It can be set in YACReaderLibrary.ini in the [ComicVine] section using the `COMIC_VINE_USER_AGENT` key. * Prevent crash when opening the folders context menu if a folder is not selected. +* Fix crash when using the `Set type` menu on libraries. ## 9.16.1 diff --git a/custom_widgets/whats_new_dialog.cpp b/custom_widgets/whats_new_dialog.cpp index fd065a238..d0ec925cc 100644 --- a/custom_widgets/whats_new_dialog.cpp +++ b/custom_widgets/whats_new_dialog.cpp @@ -70,6 +70,7 @@ YACReader::WhatsNewDialog::WhatsNewDialog(QWidget *parent) " • Fixed cover loading in Comic Vine scraper (new in 9.16.1)
" " • Added a customizable User Agent string to use it with Comic Vine. It can be set in YACReaderLibrary.ini in the [ComicVine] section using the COMIC_VINE_USER_AGENT key (new in 9.16.2)
" " • Prevent crash when opening the folders context menu if a folder is not selected. (new in 9.16.2)
" + " • Fix crash when using the `Set type` menu on libraries. (new in 9.16.2)
" "
" "YACReaderLibraryServer
" " • Log libraries validation when the app starts
" From 71b3c57b5fb85ccf28ba7ab349fd0942602400bc Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Tue, 16 Dec 2025 17:41:58 +0100 Subject: [PATCH 7/8] Add explicit timeouts to windows arm64 builds for code signing And increase it for all the jobs. --- .github/workflows/build.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b7762b4a1..bd246f114 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -321,7 +321,7 @@ jobs: artifact-configuration-slug: 'zipped-files' github-artifact-id: ${{ steps.upload_executables.outputs.artifact-id }} wait-for-completion: true - wait-for-completion-timeout-in-seconds: "3600" + wait-for-completion-timeout-in-seconds: "7200" output-artifact-directory: release64/signed - name: Replace with signed executables @@ -374,7 +374,7 @@ jobs: artifact-configuration-slug: 'zipped-files' github-artifact-id: ${{ steps.upload_unsigned.outputs.artifact-id }} wait-for-completion: true - wait-for-completion-timeout-in-seconds: "3600" + wait-for-completion-timeout-in-seconds: "7200" output-artifact-directory: ci/win/Output/signed - name: Replace with signed installer @@ -487,7 +487,7 @@ jobs: artifact-configuration-slug: 'zipped-files' github-artifact-id: ${{ steps.upload_executables.outputs.artifact-id }} wait-for-completion: true - wait-for-completion-timeout-in-seconds: "3600" + wait-for-completion-timeout-in-seconds: "7200" output-artifact-directory: release64/signed - name: Replace with signed executables @@ -540,7 +540,7 @@ jobs: artifact-configuration-slug: 'zipped-files' github-artifact-id: ${{ steps.upload_unsigned.outputs.artifact-id }} wait-for-completion: true - wait-for-completion-timeout-in-seconds: "3600" + wait-for-completion-timeout-in-seconds: "7200" output-artifact-directory: ci/win/Output/signed - name: Replace with signed installer @@ -636,6 +636,7 @@ jobs: artifact-configuration-slug: 'zipped-files' github-artifact-id: ${{ steps.upload_executables.outputs.artifact-id }} wait-for-completion: true + wait-for-completion-timeout-in-seconds: "7200" output-artifact-directory: 'release/signed' - name: Replace executables with signed versions @@ -683,6 +684,7 @@ jobs: artifact-configuration-slug: 'zipped-files' github-artifact-id: ${{ steps.upload_unsigned.outputs.artifact-id }} wait-for-completion: true + wait-for-completion-timeout-in-seconds: "7200" output-artifact-directory: 'ci/win/Output/signed' - name: Replace with signed installer and cleanup @@ -772,7 +774,7 @@ jobs: artifact-configuration-slug: 'zipped-files' github-artifact-id: ${{ steps.upload_executables.outputs.artifact-id }} wait-for-completion: true - wait-for-completion-timeout-in-seconds: "3600" + wait-for-completion-timeout-in-seconds: "7200" output-artifact-directory: release/signed - name: Replace with signed executables @@ -825,7 +827,7 @@ jobs: artifact-configuration-slug: 'zipped-files' github-artifact-id: ${{ steps.upload_unsigned.outputs.artifact-id }} wait-for-completion: true - wait-for-completion-timeout-in-seconds: "3600" + wait-for-completion-timeout-in-seconds: "7200" output-artifact-directory: ci/win/Output/signed - name: Replace with signed installer From 16e1be18b6a73c2a7e2826b60118ca8ff74f14fd Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Tue, 16 Dec 2025 17:42:17 +0100 Subject: [PATCH 8/8] Update CHANGELOG (9.16.2 release) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11ce3fc30..95ffa8fb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ Version counting is based on semantic versioning (Major.Feature.Patch) -## 9.16.2 (WIP) +## 9.16.2 ### YACReaderLibrary * New customizable User Agent string to use it with Comic Vine. It can be set in YACReaderLibrary.ini in the [ComicVine] section using the `COMIC_VINE_USER_AGENT` key.