feat: add wallpaper transitions, store crop in database per-wallpaper, move CUDA context creation to async thread
C++ / fmt (pull_request) Failing after 5s
C++ / build (pull_request) Failing after 9s
C++ / clang-tidy (pull_request) Failing after 10s
JS/TS / fmt (pull_request) Successful in 10s
JS/TS / lint (pull_request) Successful in 8s
Python / static (pull_request) Failing after 28s
Python / verify (pull_request) Failing after 1m29s
Rust / build (pull_request) Successful in 53s
Rust / fmt (pull_request) Successful in 42s
Rust / clippy (pull_request) Successful in 1m4s

This commit is contained in:
2026-10-26 14:47:47 +01:00
parent dc0f222ace
commit e655ec5bc7
26 changed files with 2338 additions and 210 deletions
+85
View File
@@ -285,6 +285,91 @@ inline QByteArray videoCacheBytes(const QString& src, const QSize& fit) {
return frame.readAll();
}
inline QByteArray videoPosterBytes(const QString& src, const QSize& fit) {
auto runProcess = [](const QString& program, const QStringList& args) {
QProcess process;
process.start(program, args);
if (!process.waitForFinished(15000)) {
process.kill();
process.waitForFinished(1000);
}
return qMakePair(process.exitCode(), process.readAllStandardOutput());
};
QSize source;
const auto resProbe = runProcess(
"ffprobe",
{
"-v",
"error",
"-select_streams",
"v:0",
"-show_entries",
"stream=width,height",
"-of",
"csv=s=x:p=0",
src,
});
if (resProbe.first == 0) {
const auto parts =
QString::fromUtf8(resProbe.second).trimmed().split('x');
if (parts.size() == 2) {
source = QSize(parts[0].toInt(), parts[1].toInt());
}
}
QSize target = coverSizeNoUpscale(source, fit);
if (target.isEmpty()) {
target = fit;
}
target.setWidth(target.width() & ~1);
target.setHeight(target.height() & ~1);
const QString scale =
QStringLiteral(
"scale=%1:%2:force_original_aspect_ratio=decrease,"
"scale=trunc(iw/2)*2:trunc(ih/2)*2")
.arg(target.width())
.arg(target.height());
QTemporaryDir tmpDir;
if (!tmpDir.isValid()) {
return {};
}
const QString framePath = tmpDir.filePath(QStringLiteral("poster.jpg"));
runProcess(
"ffmpeg",
{
"-hide_banner",
"-loglevel",
"error",
"-ss",
"0",
"-i",
src,
"-frames:v",
"1",
"-vf",
scale,
"-pix_fmt",
"yuvj420p",
"-q:v",
"2",
"-y",
framePath,
});
QFile frame(framePath);
if (!frame.open(QIODevice::ReadOnly)) {
return {};
}
return frame.readAll();
}
inline QByteArray schemeThumbBytes(const QByteArray& source, int maxSide) {
QImage image = QImage::fromData(source, "JPEG");
if (image.isNull()) {