C++ / fmt (pull_request) Failing after 6s
C++ / build (pull_request) Failing after 10s
C++ / clang-tidy (pull_request) Failing after 11s
JS/TS / fmt (pull_request) Successful in 10s
JS/TS / lint (pull_request) Successful in 8s
Python / static (pull_request) Failing after 32s
Rust / build (pull_request) Successful in 52s
Python / verify (pull_request) Failing after 1m23s
Rust / fmt (pull_request) Successful in 51s
Rust / clippy (pull_request) Successful in 1m2s
171 lines
4.4 KiB
C++
171 lines
4.4 KiB
C++
#include "wallpapercache.hpp"
|
|
|
|
#include <QCryptographicHash>
|
|
#include <QDir>
|
|
#include <QFileInfo>
|
|
#include <QImageReader>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QSqlDatabase>
|
|
#include <QSqlError>
|
|
#include <QSqlQuery>
|
|
#include <QThread>
|
|
|
|
namespace ZShell::wallpaper {
|
|
|
|
namespace {
|
|
|
|
QString connectionName() {
|
|
return QStringLiteral("wallpaper-cache-%1")
|
|
.arg(quintptr(QThread::currentThreadId()));
|
|
}
|
|
|
|
QSqlDatabase openDatabase(const QString& databasePath) {
|
|
const QString connection = connectionName();
|
|
|
|
QSqlDatabase database =
|
|
QSqlDatabase::contains(connection)
|
|
? QSqlDatabase::database(connection, false)
|
|
: QSqlDatabase::addDatabase("QSQLITE", connection);
|
|
|
|
if (database.databaseName() != databasePath) {
|
|
if (database.isOpen()) database.close();
|
|
database.setDatabaseName(databasePath);
|
|
}
|
|
|
|
if (!database.isOpen() && !database.open()) return {};
|
|
return database;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void WallpaperCache::setDbPath(const QString& path) {
|
|
std::lock_guard<std::mutex> lock(m_mtx);
|
|
m_dbPath = path;
|
|
}
|
|
|
|
QString WallpaperCache::dbPath() const {
|
|
std::lock_guard<std::mutex> lock(m_mtx);
|
|
return m_dbPath;
|
|
}
|
|
|
|
QByteArray WallpaperCache::cachedBlob(const QString& path) const {
|
|
if (path.isEmpty()) return {};
|
|
|
|
const QString databasePath = dbPath();
|
|
if (databasePath.isEmpty()) return {};
|
|
|
|
const QFileInfo info(path);
|
|
|
|
QSqlDatabase database = openDatabase(databasePath);
|
|
if (!database.isOpen()) return {};
|
|
|
|
QSqlQuery query(database);
|
|
query.prepare("SELECT cache, size, mtime FROM wallpapers WHERE path = ?");
|
|
query.addBindValue(info.absoluteFilePath());
|
|
if (!query.exec() || !query.next()) return {};
|
|
|
|
const QByteArray blob = query.value(0).toByteArray();
|
|
if (blob.isEmpty()) return {};
|
|
|
|
const qint64 mtime = info.lastModified().toMSecsSinceEpoch() / 1000;
|
|
if (query.value(1).toLongLong() != info.size() ||
|
|
query.value(2).toLongLong() != mtime) {
|
|
return {};
|
|
}
|
|
|
|
return blob;
|
|
}
|
|
|
|
QImage WallpaperCache::decodeImage(
|
|
const QString& path, const QSize& decodeSize) const {
|
|
if (path.isEmpty()) return {};
|
|
|
|
QImageReader probe(path);
|
|
const QSize source = probe.size();
|
|
QSize required = source.isEmpty() ? decodeSize : source;
|
|
if (!source.isEmpty() && !decodeSize.isEmpty()) {
|
|
const QSize cover =
|
|
source.scaled(decodeSize, Qt::KeepAspectRatioByExpanding);
|
|
if (cover.width() <= source.width() &&
|
|
cover.height() <= source.height())
|
|
required = cover;
|
|
}
|
|
|
|
const QByteArray blob = cachedBlob(path);
|
|
if (!blob.isEmpty()) {
|
|
QImage image = QImage::fromData(blob, "JPEG");
|
|
if (!image.isNull() && image.width() >= required.width() &&
|
|
image.height() >= required.height()) {
|
|
return image.convertToFormat(QImage::Format_RGBA8888);
|
|
}
|
|
}
|
|
|
|
QImageReader reader(path);
|
|
reader.setAutoTransform(true);
|
|
|
|
if (!decodeSize.isEmpty() && !source.isEmpty())
|
|
reader.setScaledSize(
|
|
source.scaled(decodeSize, Qt::KeepAspectRatioByExpanding));
|
|
|
|
QImage image = reader.read();
|
|
if (image.isNull()) return {};
|
|
|
|
return image.convertToFormat(QImage::Format_RGBA8888);
|
|
}
|
|
|
|
QByteArray WallpaperCache::posterBlob(const QString& path) const {
|
|
if (path.isEmpty()) return {};
|
|
|
|
const QString databasePath = dbPath();
|
|
if (databasePath.isEmpty()) return {};
|
|
|
|
const QFileInfo info(path);
|
|
|
|
QSqlDatabase database = openDatabase(databasePath);
|
|
if (!database.isOpen()) return {};
|
|
|
|
QSqlQuery query(database);
|
|
query.prepare("SELECT poster, size, mtime FROM wallpapers WHERE path = ?");
|
|
query.addBindValue(info.absoluteFilePath());
|
|
if (!query.exec() || !query.next()) return {};
|
|
|
|
const QByteArray blob = query.value(0).toByteArray();
|
|
if (blob.isEmpty()) return {};
|
|
|
|
const qint64 mtime = info.lastModified().toMSecsSinceEpoch() / 1000;
|
|
if (query.value(1).toLongLong() != info.size() ||
|
|
query.value(2).toLongLong() != mtime) {
|
|
return {};
|
|
}
|
|
|
|
return blob;
|
|
}
|
|
|
|
QVariantMap WallpaperCache::cropsForPath(const QString& path) const {
|
|
if (path.isEmpty()) return {};
|
|
|
|
const QString databasePath = dbPath();
|
|
if (databasePath.isEmpty()) return {};
|
|
|
|
const QFileInfo info(path);
|
|
|
|
QSqlDatabase database = openDatabase(databasePath);
|
|
if (!database.isOpen()) return {};
|
|
|
|
QSqlQuery query(database);
|
|
query.prepare("SELECT crop FROM wallpapers WHERE path = ?");
|
|
query.addBindValue(info.absoluteFilePath());
|
|
if (!query.exec() || !query.next()) return {};
|
|
|
|
const QByteArray json = query.value(0).toByteArray();
|
|
if (json.isEmpty()) return {};
|
|
|
|
const auto doc = QJsonDocument::fromJson(json);
|
|
if (!doc.isObject()) return {};
|
|
|
|
return doc.object().toVariantMap();
|
|
}
|
|
|
|
} // namespace ZShell::wallpaper
|