mirror of
https://github.com/YACReader/yacreader
synced 2025-05-25 09:50:33 -04:00
Add support for setting custom covers on folders
This commit is contained in:
parent
f0b9d45033
commit
b976b7f809
@ -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.
|
||||
|
@ -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 \
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -72,6 +72,9 @@ public:
|
||||
QAction *setFolderAsWesternMangaAction;
|
||||
QAction *setFolderAsWebComicAction;
|
||||
QAction *setFolderAsYonkomaAction;
|
||||
//--
|
||||
QAction *setFolderCoverAction;
|
||||
QAction *deleteCustomFolderCoverAction;
|
||||
|
||||
QAction *openContainingFolderComicAction;
|
||||
QAction *setAsReadAction;
|
||||
|
@ -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()) {
|
||||
|
@ -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
18
common/cover_utils.cpp
Normal 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
9
common/cover_utils.h
Normal 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
|
@ -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
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user