Add Lyra Carousel home theme

This commit is contained in:
jpirnay
2026-05-07 23:42:35 +02:00
parent 0b93445450
commit 4005bf55e5
17 changed files with 875 additions and 103 deletions
+63
View File
@@ -816,6 +816,9 @@ bool Epub::generateCoverBmp(bool cropped) const {
std::string Epub::getThumbBmpPath() const { return cachePath + "/thumb_[HEIGHT].bmp"; }
std::string Epub::getThumbBmpPath(int height) const { return cachePath + "/thumb_" + std::to_string(height) + ".bmp"; }
std::string Epub::getThumbBmpPath(int width, int height) const {
return cachePath + "/thumb_" + std::to_string(width) + "x" + std::to_string(height) + ".bmp";
}
bool Epub::generateThumbBmp(int height) const {
// Already generated, return true
@@ -908,6 +911,66 @@ bool Epub::generateThumbBmp(int height) const {
return false;
}
bool Epub::generateThumbBmp(int width, int height) const {
if (Storage.exists(getThumbBmpPath(width, height).c_str())) return true;
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
LOG_ERR("EBP", "Cannot generate thumb BMP, cache not loaded");
return false;
}
const auto coverImageHref = bookMetadataCache->coreMetadata.coverItemHref;
if (coverImageHref.empty()) {
LOG_DBG("EBP", "No known cover image for thumbnail");
} else if (FsHelpers::hasJpgExtension(coverImageHref)) {
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
FsFile coverJpg;
if (!Storage.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) return false;
readItemContentsToStream(coverImageHref, coverJpg, 1024);
coverJpg.close();
if (!Storage.openFileForRead("EBP", coverJpgTempPath, coverJpg)) return false;
FsFile thumbBmp;
if (!Storage.openFileForWrite("EBP", getThumbBmpPath(width, height), thumbBmp)) {
coverJpg.close();
return false;
}
const bool success = JpegToBmpConverter::jpegFileTo1BitBmpStreamWithSize(coverJpg, thumbBmp, width, height);
coverJpg.close();
thumbBmp.close();
Storage.remove(coverJpgTempPath.c_str());
if (!success) Storage.remove(getThumbBmpPath(width, height).c_str());
LOG_DBG("EBP", "Generated %dx%d thumb BMP from JPG, success: %s", width, height, success ? "yes" : "no");
return success;
} else if (FsHelpers::hasPngExtension(coverImageHref)) {
const auto coverPngTempPath = getCachePath() + "/.cover.png";
FsFile coverPng;
if (!Storage.openFileForWrite("EBP", coverPngTempPath, coverPng)) return false;
readItemContentsToStream(coverImageHref, coverPng, 1024);
coverPng.close();
if (!Storage.openFileForRead("EBP", coverPngTempPath, coverPng)) return false;
FsFile thumbBmp;
if (!Storage.openFileForWrite("EBP", getThumbBmpPath(width, height), thumbBmp)) {
coverPng.close();
return false;
}
const bool success = PngToBmpConverter::pngFileTo1BitBmpStreamWithSize(coverPng, thumbBmp, width, height);
coverPng.close();
thumbBmp.close();
Storage.remove(coverPngTempPath.c_str());
if (!success) Storage.remove(getThumbBmpPath(width, height).c_str());
LOG_DBG("EBP", "Generated %dx%d thumb BMP from PNG, success: %s", width, height, success ? "yes" : "no");
return success;
} else {
LOG_ERR("EBP", "Cover image is not a supported format, skipping thumbnail");
}
// Write empty sentinel to avoid repeated generation attempts
FsFile thumbBmp;
Storage.openFileForWrite("EBP", getThumbBmpPath(width, height), thumbBmp);
thumbBmp.close();
return false;
}
uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size, const bool trailingNullByte) const {
if (itemHref.empty()) {
LOG_DBG("EBP", "Failed to read item, empty href");