fix(hardcover): skip epub load for books without progress, eliminate double scan and load

This commit is contained in:
Justin Oros
2026-04-23 15:49:48 -07:00
parent b04b1932a6
commit e7618d5e51
+33 -46
View File
@@ -75,13 +75,7 @@ std::string extractIsbnFromOpf(const uint8_t* data, size_t len) {
return {}; return {};
} }
std::string getIsbnFromEpub(const std::string& path) { std::string getIsbnFromEpub(Epub& epub, const std::string& path) {
Epub epub(path, CACHE_DIR);
if (!epub.load(false, true) && !epub.load(true, true)) {
LOG_DBG("HCV", "Could not load epub: %s", path.c_str());
return {};
}
const char* opfCandidates[] = { const char* opfCandidates[] = {
"OEBPS/content.opf", "OPS/content.opf", "content.opf", "OEBPS/content.opf", "OPS/content.opf", "content.opf",
"EPUB/content.opf", nullptr "EPUB/content.opf", nullptr
@@ -124,7 +118,7 @@ std::string getIsbnFromEpub(const std::string& path) {
// ---- Progress reading ------------------------------------------------------- // ---- Progress reading -------------------------------------------------------
int epubProgressPercent(const std::string& path, const std::string& cachePath, int& outPage) { int epubProgressPercent(const std::string& cachePath, int& outPage, Epub& epub) {
FsFile f; FsFile f;
if (!Storage.openFileForRead("HCV", (cachePath + "/progress.bin").c_str(), f)) if (!Storage.openFileForRead("HCV", (cachePath + "/progress.bin").c_str(), f))
return -1; return -1;
@@ -142,9 +136,6 @@ int epubProgressPercent(const std::string& path, const std::string& cachePath, i
float spineProgress = static_cast<float>(currentPage) / static_cast<float>(pageCount); float spineProgress = static_cast<float>(currentPage) / static_cast<float>(pageCount);
Epub epub(path, CACHE_DIR);
if (!epub.load(false, true) && !epub.load(true, true)) return -1;
float pct = epub.calculateProgress(spineIndex, spineProgress) * 100.0f; float pct = epub.calculateProgress(spineIndex, spineProgress) * 100.0f;
return static_cast<int>(pct + 0.5f); return static_cast<int>(pct + 0.5f);
} }
@@ -179,43 +170,33 @@ std::string buildCachePath(const std::string& filePath) {
std::to_string(std::hash<std::string>{}(filePath)); std::to_string(std::hash<std::string>{}(filePath));
} }
std::vector<InProgressBook> collectInProgressBooks() { void collectBooks(std::vector<InProgressBook>& inProgress, std::vector<InProgressBook>& completed) {
std::vector<std::string> allBooks; std::vector<std::string> allBooks;
scanBooks("/", allBooks); scanBooks("/", allBooks);
std::vector<InProgressBook> result;
for (const auto& path : allBooks) { for (const auto& path : allBooks) {
std::string cachePath = buildCachePath(path); std::string cachePath = buildCachePath(path);
int page = 0;
int pct = epubProgressPercent(path, cachePath, page);
if (pct < 1) continue; // Skip 0% books, include 1-100%+
std::string isbn = getIsbnFromEpub(path); // Check progress.bin exists before loading the EPUB
FsFile f;
if (!Storage.openFileForRead("HCV", (cachePath + "/progress.bin").c_str(), f)) continue;
f.close();
int page = 0;
Epub epub(path, CACHE_DIR);
if (!epub.load(false, true) && !epub.load(true, true)) continue;
int pct = epubProgressPercent(cachePath, page, epub);
if (pct < 1) continue;
std::string isbn = getIsbnFromEpub(epub, path);
if (isbn.empty()) continue; if (isbn.empty()) continue;
result.push_back({isbn, page, pct}); if (pct >= 100)
completed.push_back({isbn, page, pct});
else
inProgress.push_back({isbn, page, pct});
} }
return result;
}
// New function to collect completed books (100%+)
std::vector<InProgressBook> collectCompletedBooks() {
std::vector<std::string> allBooks;
scanBooks("/", allBooks);
std::vector<InProgressBook> result;
for (const auto& path : allBooks) {
std::string cachePath = buildCachePath(path);
int page = 0;
int pct = epubProgressPercent(path, cachePath, page);
if (pct < 100) continue; // Only include 100%+ books
std::string isbn = getIsbnFromEpub(path);
if (isbn.empty()) continue;
result.push_back({isbn, page, pct});
}
return result;
} }
// ---- HTTP helper ----------------------------------------------------------- // ---- HTTP helper -----------------------------------------------------------
@@ -223,9 +204,11 @@ std::vector<InProgressBook> collectCompletedBooks() {
String graphqlPost(const char* body, const std::string& token) { String graphqlPost(const char* body, const std::string& token) {
WiFiClientSecure client; WiFiClientSecure client;
client.setInsecure(); client.setInsecure();
client.setTimeout(15);
HTTPClient http; HTTPClient http;
http.begin(client, HARDCOVER_API); http.begin(client, HARDCOVER_API);
http.setTimeout(15000);
http.addHeader("Content-Type", "application/json"); http.addHeader("Content-Type", "application/json");
char authHeader[648]; char authHeader[648];
@@ -233,6 +216,11 @@ String graphqlPost(const char* body, const std::string& token) {
http.addHeader("Authorization", authHeader); http.addHeader("Authorization", authHeader);
int code = http.POST(body); int code = http.POST(body);
if (code <= 0) {
LOG_ERR("HCV", "HTTP error %d (connection failed — check WiFi/firewall)", code);
http.end();
return "";
}
if (code != 200) { if (code != 200) {
LOG_ERR("HCV", "HTTP %d", code); LOG_ERR("HCV", "HTTP %d", code);
http.end(); http.end();
@@ -482,9 +470,11 @@ SyncResult syncProgress() {
} }
const std::string token(SETTINGS.hardcoverApiToken); const std::string token(SETTINGS.hardcoverApiToken);
auto books = collectInProgressBooks(); std::vector<InProgressBook> books;
std::vector<InProgressBook> completedBooks;
collectBooks(books, completedBooks);
if (books.empty()) { if (books.empty() && completedBooks.empty()) {
LOG_DBG("HCV", "No in-progress epub books with ISBN found."); LOG_DBG("HCV", "No in-progress epub books with ISBN found.");
return SyncResult::NO_BOOKS; return SyncResult::NO_BOOKS;
} }
@@ -493,15 +483,12 @@ SyncResult syncProgress() {
if (userId == 0) return SyncResult::API_ERROR; if (userId == 0) return SyncResult::API_ERROR;
bool allOk = true; bool allOk = true;
// Sync progress for all books with > 0% completion
for (const auto& b : books) { for (const auto& b : books) {
if (!syncBook(b, userId, token)) if (!syncBook(b, userId, token))
allOk = false; allOk = false;
} }
// Mark 100%+ books as Read
auto completedBooks = collectCompletedBooks();
for (const auto& b : completedBooks) { for (const auto& b : completedBooks) {
if (!markAsRead(b.isbn, token)) if (!markAsRead(b.isbn, token))
allOk = false; allOk = false;