Add support for setting custom covers on folders

This commit is contained in:
Luis Ángel San Martín 2025-05-08 22:00:55 +02:00
parent f0b9d45033
commit b976b7f809
17 changed files with 263 additions and 34 deletions

View File

@ -16,6 +16,7 @@ Version counting is based on semantic versioning (Major.Feature.Patch)
* New setting in Comic Vine scraper to force exact volume matches.
* Better default search query in the Comic Vine scraper.
* Improved navigation in Comic Vine scraper, including keeping the current query around to make edits and refined searches easier.
* Add support for adding custom covers for folders using the context menu.
### YACReaderLibraryServer
* Log libraries validation when the app starts.

View File

@ -74,6 +74,7 @@ greaterThan(QT_MAJOR_VERSION, 5): QT += openglwidgets core5compat
# Input
HEADERS += comic_flow.h \
../common/concurrent_queue.h \
../common/cover_utils.h \
create_library_dialog.h \
db/comic_query_result_processor.h \
db/folder_query_result_processor.h \
@ -163,6 +164,7 @@ HEADERS += comic_flow.h \
SOURCES += comic_flow.cpp \
../common/concurrent_queue.cpp \
../common/cover_utils.cpp \
create_library_dialog.cpp \
db/comic_query_result_processor.cpp \
db/folder_query_result_processor.cpp \

View File

@ -370,8 +370,12 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const
if (role == FolderModel::IdRole)
return item->id;
if (role == FolderModel::CoverPathRole)
return getCoverUrlPathForComicHash(item->data(FirstChildHash).toString());
if (role == FolderModel::CoverPathRole) {
if (item->data(FolderModel::CustomImage).toString().isEmpty())
return getCoverUrlPathForComicHash(item->data(FirstChildHash).toString());
else
return getCoverUrlPathForFolderId(item->id);
}
if (role == FolderModel::NumChildrenRole)
return item->data(NumChildren);
@ -675,6 +679,50 @@ void FolderModel::updateTreeType(YACReader::FileType type)
QSqlDatabase::removeDatabase(connectionName);
}
void FolderModel::setCustomFolderCover(const QModelIndex &index, const QString &path)
{
QString connectionName = "";
{
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
db.transaction();
auto item = static_cast<FolderItem *>(index.internalPointer());
item->setData(FolderModel::CustomImage, path);
Folder f = DBHelper::loadFolder(item->id, db);
f.customImage = path;
DBHelper::update(f, db);
db.commit();
connectionName = db.connectionName();
}
QSqlDatabase::removeDatabase(connectionName);
emit dataChanged(index, index);
}
void FolderModel::resetFolderCover(const QModelIndex &index)
{
QString connectionName = "";
{
QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
db.transaction();
auto item = static_cast<FolderItem *>(index.internalPointer());
item->setData(FolderModel::CustomImage, "");
Folder f = DBHelper::loadFolder(item->id, db);
f.customImage = "";
DBHelper::update(f, db);
db.commit();
connectionName = db.connectionName();
}
QSqlDatabase::removeDatabase(connectionName);
emit dataChanged(index, index);
}
QStringList FolderModel::getSubfoldersNames(const QModelIndex &mi)
{
QStringList result;
@ -858,6 +906,12 @@ QUrl FolderModel::getCoverUrlPathForComicHash(const QString &hash) const
return QUrl::fromLocalFile(coverPath);
}
QUrl FolderModel::getCoverUrlPathForFolderId(qulonglong folderId) const
{
auto coverPath = LibraryPaths::customFolderCoverPathFromDataPath(_databasePath, QString::number(folderId));
return QUrl::fromLocalFile(coverPath);
}
void FolderModel::setShowRecent(bool showRecent)
{
if (this->showRecent == showRecent)

View File

@ -70,6 +70,8 @@ public:
void updateFolderFinishedStatus(const QModelIndexList &list, bool status);
void updateFolderType(const QModelIndexList &list, YACReader::FileType type);
void updateTreeType(YACReader::FileType type);
void setCustomFolderCover(const QModelIndex &index, const QString &path);
void resetFolderCover(const QModelIndex &index);
QStringList getSubfoldersNames(const QModelIndex &mi);
FolderModel *getSubfoldersModel(const QModelIndex &mi); // it creates a model that contains just the direct subfolders
@ -81,6 +83,7 @@ public:
QModelIndex addFolderAtParent(const QString &folderName, const QModelIndex &parent);
Q_INVOKABLE QUrl getCoverUrlPathForComicHash(const QString &hash) const;
Q_INVOKABLE QUrl getCoverUrlPathForFolderId(qulonglong folderId) const;
void setShowRecent(bool showRecent);
void setRecentRange(int days);

View File

@ -824,13 +824,34 @@ void DBHelper::updateAdded(ComicInfo *comicInfo, QSqlDatabase &db)
void DBHelper::update(const Folder &folder, QSqlDatabase &db)
{
QSqlQuery updateFolderInfo(db);
updateFolderInfo.prepare("UPDATE folder SET "
"parentId = :parentId, "
"name = :name, "
"path = :path, "
"finished = :finished, "
"completed = :completed "
"WHERE id = :id ");
"completed = :completed, "
"numChildren = :numChildren, "
"firstChildHash = :firstChildHash, "
"customImage = :customImage, "
"type = :type, "
"added = :added, "
"updated = :updated "
"WHERE id = :id");
updateFolderInfo.bindValue(":parentId", folder.parentId);
updateFolderInfo.bindValue(":name", folder.name);
updateFolderInfo.bindValue(":path", folder.path);
updateFolderInfo.bindValue(":finished", folder.finished ? 1 : 0);
updateFolderInfo.bindValue(":completed", folder.completed ? 1 : 0);
updateFolderInfo.bindValue(":numChildren", folder.numChildren);
updateFolderInfo.bindValue(":firstChildHash", folder.firstChildHash);
updateFolderInfo.bindValue(":customImage", folder.customImage);
updateFolderInfo.bindValue(":type", static_cast<int>(folder.type));
updateFolderInfo.bindValue(":added", folder.added);
updateFolderInfo.bindValue(":updated", folder.updated);
updateFolderInfo.bindValue(":id", folder.id);
updateFolderInfo.exec();
}

View File

@ -67,7 +67,7 @@ public:
static void update(ComicInfo *comicInfo, QSqlDatabase &db);
static void updateRead(ComicInfo *comicInfo, QSqlDatabase &db);
static void updateAdded(ComicInfo *comicInfo, QSqlDatabase &db);
static void update(const Folder &folder, QSqlDatabase &db); // only for finished/completed fields
static void update(const Folder &folder, QSqlDatabase &db);
static void propagateFolderUpdatesToParent(const Folder &folder, QSqlDatabase &db);
static Folder updateChildrenInfo(qulonglong folderId, QSqlDatabase &db);
static void updateChildrenInfo(QSqlDatabase &db);

View File

@ -5,6 +5,7 @@
#include "comic.h"
#include "compressed_archive.h"
#include "qnaturalsorting.h"
#include "cover_utils.h"
using namespace YACReader;
@ -154,17 +155,5 @@ QByteArray InitialComicInfoExtractor::getXMLInfoRawData()
void InitialComicInfoExtractor::saveCover(const QString &path, const QImage &cover)
{
QImage scaled;
if (cover.width() > cover.height()) {
scaled = cover.scaledToWidth(640, Qt::SmoothTransformation);
} else {
auto aspectRatio = static_cast<double>(cover.width()) / static_cast<double>(cover.height());
auto maxAllowedAspectRatio = 0.5;
if (aspectRatio < maxAllowedAspectRatio) { // cover is too tall, e.g. webtoon
scaled = cover.scaledToHeight(960, Qt::SmoothTransformation);
} else {
scaled = cover.scaledToWidth(480, Qt::SmoothTransformation);
}
}
scaled.save(_target, 0, 75);
YACReader::saveCover(path, cover);
}

View File

@ -83,6 +83,8 @@
#include "recent_visibility_coordinator.h"
#include "cover_utils.h"
#include "QsLog.h"
#include "yacreader_http_server.h"
@ -536,6 +538,10 @@ void LibraryWindow::createMenus()
foldersView->addAction(actions.setFolderAsWesternMangaAction);
foldersView->addAction(actions.setFolderAsWebComicAction);
foldersView->addAction(actions.setFolderAsYonkomaAction);
YACReader::addSperator(foldersView);
foldersView->addAction(actions.setFolderCoverAction);
foldersView->addAction(actions.deleteCustomFolderCoverAction);
selectedLibrary->addAction(actions.updateLibraryAction);
selectedLibrary->addAction(actions.renameLibraryAction);
@ -669,11 +675,14 @@ void LibraryWindow::createMenus()
folderMenu->addAction(actions.setFolderAsReadAction);
folderMenu->addAction(actions.setFolderAsUnreadAction);
folderMenu->addSeparator();
foldersView->addAction(actions.setFolderAsNormalAction);
foldersView->addAction(actions.setFolderAsMangaAction);
foldersView->addAction(actions.setFolderAsWesternMangaAction);
foldersView->addAction(actions.setFolderAsWebComicAction);
foldersView->addAction(actions.setFolderAsYonkomaAction);
folderMenu->addAction(actions.setFolderAsNormalAction);
folderMenu->addAction(actions.setFolderAsMangaAction);
folderMenu->addAction(actions.setFolderAsWesternMangaAction);
folderMenu->addAction(actions.setFolderAsWebComicAction);
folderMenu->addAction(actions.setFolderAsYonkomaAction);
folderMenu->addSeparator();
folderMenu->addAction(actions.setFolderCoverAction);
folderMenu->addAction(actions.deleteCustomFolderCoverAction);
// comic
QMenu *comicMenu = new QMenu(tr("Comic"));
@ -823,11 +832,15 @@ void LibraryWindow::loadLibrary(const QString &name)
showRootWidget();
QString rootPath = libraries.getPath(name);
QString path = LibraryPaths::libraryDataPath(rootPath);
QString customFolderCoversPath = LibraryPaths::libraryCustomFoldersCoverPath(rootPath);
QString databasePath = LibraryPaths::libraryDatabasePath(rootPath);
QDir d; // TODO change this by static methods (utils class?? with delTree for example)
QString dbVersion;
if (d.exists(path) && d.exists(databasePath) && (dbVersion = DataBaseManagement::checkValidDB(databasePath)) != "") // si existe en disco la biblioteca seleccionada, y es válida..
{
// this folde was added in 9.16, it needs to exist before the user starts importing custom covers for folders
d.mkdir(customFolderCoversPath);
int comparation = DataBaseManagement::compareVersions(dbVersion, DB_VERSION);
if (comparation < 0) {
@ -1441,6 +1454,12 @@ void LibraryWindow::showGridFoldersContextMenu(QPoint point, Folder folder)
auto setFolderAs4KomaAction = new QAction();
setFolderAs4KomaAction->setText(tr("4koma (top to botom)"));
auto setFolderCoverAction = new QAction();
setFolderCoverAction->setText(tr("Set custom cover"));
auto deleteCustomFolderCoverAction = new QAction();
deleteCustomFolderCoverAction->setText(tr("Delete custom cover"));
menu.addAction(openContainingFolderAction);
menu.addAction(updateFolderAction);
menu.addSeparator();
@ -1536,6 +1555,20 @@ void LibraryWindow::showGridFoldersContextMenu(QPoint point, Folder folder)
foldersModel->updateFolderType(QModelIndexList() << foldersModel->getIndexFromFolder(folder), FileType::Yonkoma);
subfolderModel->updateFolderType(QModelIndexList() << foldersModel->getIndexFromFolder(folder), FileType::Yonkoma);
});
connect(setFolderCoverAction, &QAction::triggered, this, [=]() {
setCustomFolderCover(folder);
});
connect(deleteCustomFolderCoverAction, &QAction::triggered, this, [=]() {
resetFolderCover(folder);
});
menu.addSeparator();
menu.addAction(setFolderCoverAction);
if (!folder.customImage.isEmpty()) {
menu.addAction(deleteCustomFolderCoverAction);
}
menu.exec(contentViewsManager->folderContentView->mapToGlobal(point));
}
@ -2272,6 +2305,55 @@ void LibraryWindow::setFolderType(FileType type)
foldersModel->updateFolderType(QModelIndexList() << foldersModelProxy->mapToSource(foldersView->currentIndex()), type);
}
void LibraryWindow::setFolderCover()
{
auto folder = foldersModel->getFolder(foldersModelProxy->mapToSource(foldersView->currentIndex()));
setCustomFolderCover(folder);
}
void LibraryWindow::setCustomFolderCover(Folder folder)
{
QString supportedImageFormatsString;
for (const QByteArray &format : QImageReader::supportedImageFormats()) {
supportedImageFormatsString += QString("*.%1 ").arg(QString(format));
}
QString customCoverPath = QFileDialog::getOpenFileName(this, tr("Select custom cover"), QDir::homePath(), tr("Images (%1)").arg(supportedImageFormatsString));
if (!customCoverPath.isEmpty()) {
QImage cover(customCoverPath);
if (cover.isNull()) {
QMessageBox::warning(this, tr("Invalid image"), tr("The selected file is not a valid image."));
return;
}
auto folderCoverPath = LibraryPaths::customFolderCoverPath(libraries.getPath(selectedLibrary->currentText()), QString::number(folder.id));
if (!YACReader::saveCover(folderCoverPath, cover)) {
QMessageBox::warning(this, tr("Error saving cover"), tr("There was an error saving the cover image."));
}
QModelIndex folderIndex = foldersModel->getIndexFromFolder(folder);
auto coversPath = LibraryPaths::libraryCoversFolderPath(libraries.getPath(selectedLibrary->currentText()));
auto relativePath = folderCoverPath.remove(coversPath);
foldersModel->setCustomFolderCover(folderIndex, relativePath);
}
}
void LibraryWindow::deleteCustomFolderCover()
{
auto folder = foldersModel->getFolder(foldersModelProxy->mapToSource(foldersView->currentIndex()));
resetFolderCover(folder);
}
void LibraryWindow::resetFolderCover(Folder folder)
{
auto folderCoverPath = LibraryPaths::customFolderCoverPath(libraries.getPath(selectedLibrary->currentText()), QString::number(folder.id));
if (QFile::exists(folderCoverPath)) {
QFile::remove(folderCoverPath);
}
QModelIndex folderIndex = foldersModel->getIndexFromFolder(folder);
foldersModel->resetFolderCover(folderIndex);
}
void LibraryWindow::exportLibrary(QString destPath)
{
QString currentLibrary = selectedLibrary->currentText();
@ -2513,9 +2595,7 @@ void LibraryWindow::showFoldersContextMenu(const QPoint &point)
{
QModelIndex sourceMI = foldersModelProxy->mapToSource(foldersView->indexAt(point));
bool isCompleted = sourceMI.data(FolderModel::CompletedRole).toBool();
bool isRead = sourceMI.data(FolderModel::FinishedRole).toBool();
auto type = sourceMI.data(FolderModel::TypeRole).value<YACReader::FileType>();
auto folder = foldersModel->getFolder(sourceMI);
actions.setFolderAsNormalAction->setCheckable(true);
actions.setFolderAsMangaAction->setCheckable(true);
@ -2529,7 +2609,7 @@ void LibraryWindow::showFoldersContextMenu(const QPoint &point)
actions.setFolderAsWebComicAction->setChecked(false);
actions.setFolderAsYonkomaAction->setChecked(false);
switch (type) {
switch (folder.type) {
case FileType::Comic:
actions.setFolderAsNormalAction->setChecked(true);
break;
@ -2554,12 +2634,12 @@ void LibraryWindow::showFoldersContextMenu(const QPoint &point)
menu.addSeparator(); //-------------------------------
menu.addAction(actions.rescanXMLFromCurrentFolderAction);
menu.addSeparator(); //-------------------------------
if (isCompleted)
if (folder.completed)
menu.addAction(actions.setFolderAsNotCompletedAction);
else
menu.addAction(actions.setFolderAsCompletedAction);
menu.addSeparator(); //-------------------------------
if (isRead)
if (folder.finished)
menu.addAction(actions.setFolderAsUnreadAction);
else
menu.addAction(actions.setFolderAsReadAction);
@ -2571,6 +2651,11 @@ void LibraryWindow::showFoldersContextMenu(const QPoint &point)
typeMenu->addAction(actions.setFolderAsWesternMangaAction);
typeMenu->addAction(actions.setFolderAsWebComicAction);
typeMenu->addAction(actions.setFolderAsYonkomaAction);
menu.addSeparator(); //-------------------------------
menu.addAction(actions.setFolderCoverAction);
if (!folder.customImage.isEmpty()) {
menu.addAction(actions.deleteCustomFolderCoverAction);
}
menu.exec(foldersView->mapToGlobal(point));
}

View File

@ -246,6 +246,10 @@ public slots:
void setFolderAsRead();
void setFolderAsUnread();
void setFolderType(FileType type);
void setFolderCover();
void setCustomFolderCover(Folder folder);
void deleteCustomFolderCover();
void resetFolderCover(Folder folder);
void openContainingFolderComic();
void deleteCurrentLibrary();
void removeLibrary();

View File

@ -281,6 +281,16 @@ void LibraryWindowActions::createActions(LibraryWindow *window, QSettings *setti
setFolderAsUnreadAction->setData(SET_FOLDER_AS_UNREAD_ACTION_YL);
setFolderAsUnreadAction->setShortcut(ShortcutsManager::getShortcutsManager().getShortcut(SET_FOLDER_AS_UNREAD_ACTION_YL));
setFolderCoverAction = new QAction(window);
setFolderCoverAction->setText(tr("Set custom cover"));
setFolderCoverAction->setData(SET_FOLDER_COVER_ACTION_YL);
setFolderCoverAction->setShortcut(ShortcutsManager::getShortcutsManager().getShortcut(SET_FOLDER_COVER_ACTION_YL));
deleteCustomFolderCoverAction = new QAction(window);
deleteCustomFolderCoverAction->setText(tr("Delete custom cover"));
deleteCustomFolderCoverAction->setData(DELETE_CUSTOM_FOLDER_COVER_ACTION_YL);
deleteCustomFolderCoverAction->setShortcut(ShortcutsManager::getShortcutsManager().getShortcut(DELETE_CUSTOM_FOLDER_COVER_ACTION_YL));
setFolderAsMangaAction = new QAction(window);
setFolderAsMangaAction->setText(tr("manga"));
setFolderAsMangaAction->setData(SET_FOLDER_AS_MANGA_ACTION_YL);
@ -445,6 +455,8 @@ void LibraryWindowActions::createActions(LibraryWindow *window, QSettings *setti
window->addAction(setFolderAsWesternMangaAction);
window->addAction(setFolderAsWebComicAction);
window->addAction(setFolderAsYonkomaAction);
window->addAction(setFolderCoverAction);
window->addAction(deleteCustomFolderCoverAction);
window->addAction(deleteMetadataAction);
window->addAction(rescanXMLFromCurrentFolderAction);
window->addAction(openContainingFolderComicAction);
@ -512,6 +524,8 @@ void LibraryWindowActions::createConnections(
QObject::connect(setFolderAsReadAction, &QAction::triggered, window, &LibraryWindow::setFolderAsRead);
QObject::connect(setFolderAsUnreadAction, &QAction::triggered, window, &LibraryWindow::setFolderAsUnread);
QObject::connect(openContainingFolderAction, &QAction::triggered, window, &LibraryWindow::openContainingFolder);
QObject::connect(setFolderCoverAction, &QAction::triggered, window, &LibraryWindow::setFolderCover);
QObject::connect(deleteCustomFolderCoverAction, &QAction::triggered, window, &LibraryWindow::deleteCustomFolderCover);
QObject::connect(setFolderAsMangaAction, &QAction::triggered, window, [=]() {
window->setFolderType(FileType::Manga);
@ -630,7 +644,9 @@ void LibraryWindowActions::setUpShortcutsManagement(EditShortcutsDialog *editSho
<< setFolderAsMangaAction
<< setFolderAsNormalAction
<< updateCurrentFolderAction
<< rescanXMLFromCurrentFolderAction);
<< rescanXMLFromCurrentFolderAction
<< setFolderCoverAction
<< deleteCustomFolderCoverAction);
allActions << tmpList;
editShortcutsDialog->addActionsGroup("Lists", QIcon(":/images/shortcuts_group_folders.svg"), // TODO change icon

View File

@ -72,6 +72,9 @@ public:
QAction *setFolderAsWesternMangaAction;
QAction *setFolderAsWebComicAction;
QAction *setFolderAsYonkomaAction;
//--
QAction *setFolderCoverAction;
QAction *deleteCustomFolderCoverAction;
QAction *openContainingFolderComicAction;
QAction *setAsReadAction;

View File

@ -18,7 +18,8 @@ void CoverControllerV2::service(HttpRequest &request, HttpResponse &response)
QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8();
QStringList pathElements = path.split('/');
QString libraryName = DBHelper::getLibraryName(pathElements.at(3).toInt());
QString fileName = pathElements.at(5);
QStringList remainingPathElements = pathElements.mid(5);
QString fileName = remainingPathElements.join('/');
QImage img(YACReader::LibraryPaths::coverPathWithFileName(libraries.getPath(libraryName), fileName));
if (!img.isNull()) {

View File

@ -246,7 +246,7 @@ void RequestMapper::serviceV2(HttpRequest &request, HttpResponse &response)
QRegExp comicFullInfo("/v2/library/.+/comic/[0-9]+/fullinfo/?"); // get comic info
QRegExp comicUpdate("/v2/library/.+/comic/[0-9]+/update/?"); // get comic info
QRegExp comicClose("/v2/library/.+/comic/[0-9]+/close/?"); // the server will close the comic and free memory
QRegExp cover("/v2/library/.+/cover/[0-9a-f]+.jpg"); // get comic cover (navigation)
QRegExp cover("/v2/library/.+/cover/.+"); // get comic cover (navigation)
QRegExp comicPage("/v2/library/.+/comic/[0-9]+/page/[0-9]+/?"); // get comic page
QRegExp comicPageRemote("/v2/library/.+/comic/[0-9]+/page/[0-9]+/remote?"); // get comic page (remote reading)
QRegExp serverVersion("/v2/version/?");

18
common/cover_utils.cpp Normal file
View File

@ -0,0 +1,18 @@
#include "cover_utils.h"
bool YACReader::saveCover(const QString &path, const QImage &cover)
{
QImage scaled;
if (cover.width() > cover.height()) {
scaled = cover.scaledToWidth(640, Qt::SmoothTransformation);
} else {
auto aspectRatio = static_cast<double>(cover.width()) / static_cast<double>(cover.height());
auto maxAllowedAspectRatio = 0.5;
if (aspectRatio < maxAllowedAspectRatio) { // cover is too tall, e.g. webtoon
scaled = cover.scaledToHeight(960, Qt::SmoothTransformation);
} else {
scaled = cover.scaledToWidth(480, Qt::SmoothTransformation);
}
}
return scaled.save(path, 0, 75);
}

9
common/cover_utils.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef COVER_UTILS_H
#define COVER_UTILS_H
#include <QImage>
namespace YACReader {
bool saveCover(const QString &path, const QImage &image);
}
#endif // COVER_UTILS_H

View File

@ -109,6 +109,7 @@ void iterate(const QModelIndex &index,
const QAbstractItemModel *model,
const std::function<bool(const QModelIndex &)> &iteration);
// TODO: remove all the dataPath variants and always use the root folder of a library `libraryPath` to get all the paths.
struct LibraryPaths {
LibraryPaths() = delete; // Prevent instantiation
@ -137,14 +138,34 @@ struct LibraryPaths {
return QDir(libraryCoversFolderPath(libraryPath)).filePath(coverFileName(hash));
}
static QString libraryCustomFoldersCoverPath(const QString &libraryPath) // libraryPath + /.yacreaderlibrary/covers/folders
{
return QDir(libraryCoversFolderPath(libraryPath)).filePath("folders");
}
static QString libraryCustomFoldersCoverPathFromLibraryDataPath(const QString &libraryDataPath)
{
return QDir(libraryCoversPathFromLibraryDataPath(libraryDataPath)).filePath("folders");
}
static QString customFolderCoverPath(const QString &libraryPath, const QString &folderId)
{
return QDir(libraryCustomFoldersCoverPath(libraryPath)).filePath(coverFileName(folderId));
}
static QString customFolderCoverPathFromDataPath(const QString &libraryDataPath, const QString &folderId)
{
return QDir(libraryCustomFoldersCoverPathFromLibraryDataPath(libraryDataPath)).filePath(coverFileName(folderId));
}
static QString coverPathFromLibraryDataPath(const QString &libraryDataPath, const QString &hash) // libraryDataPath + /covers/hash + .jpg
{
return QDir(libraryCoversPathFromLibraryDataPath(libraryDataPath)).filePath(coverFileName(hash));
}
static QString coverFileName(const QString &hash) // hash + .jpg
static QString coverFileName(const QString &id) // id + .jpg (it can be a comic hash or a folder id)
{
return hash + ".jpg";
return id + ".jpg";
}
static QString coverPathWithFileName(const QString &libraryPath, const QString &fileName) // libraryPath + /.yacreaderlibrary/covers/hash + fileName

View File

@ -74,6 +74,8 @@ public:
#define SET_FOLDER_AS_NORMAL_ACTION_YL "SET_FOLDER_AS_NORMAL_ACTION_YL"
#define SET_FOLDER_AS_WEB_COMIC_ACTION_YL "SET_FOLDER_AS_WEB_COMIC_ACTION_YL"
#define SET_FOLDER_AS_YONKOMA_ACTION_YL "SET_FOLDER_AS_YONKOMA_ACTION_YL"
#define SET_FOLDER_COVER_ACTION_YL "SET_FOLDER_COVER_ACTION_YL"
#define DELETE_CUSTOM_FOLDER_COVER_ACTION_YL "DELETE_CUSTOM_FOLDER_COVER_ACTION_YL"
#define OPEN_CONTAINING_FOLDER_COMIC_ACTION_YL "OPEN_CONTAINING_FOLDER_COMIC_ACTION_YL"
#define RESET_COMIC_RATING_ACTION_YL "RESET_COMIC_RATING_ACTION_YL"
#define SELECT_ALL_COMICS_ACTION_YL "SELECT_ALL_COMICS_ACTION_YL"