Add a setting for document matching method

This commit is contained in:
Justin Mitchell
2026-01-04 23:48:42 -05:00
parent ae34fc76e1
commit 77bb97339d
8 changed files with 133 additions and 26 deletions

View File

@@ -54,6 +54,9 @@ bool KOReaderCredentialStore::saveToFile() const {
// Write server URL
serialization::writeString(file, serverUrl);
// Write match method
serialization::writePod(file, static_cast<uint8_t>(matchMethod));
file.close();
Serial.printf("[%lu] [KRS] Saved KOReader credentials to file\n", millis());
return true;
@@ -97,6 +100,15 @@ bool KOReaderCredentialStore::loadFromFile() {
serverUrl.clear();
}
// Read match method
if (file.available()) {
uint8_t method;
serialization::readPod(file, method);
matchMethod = static_cast<DocumentMatchMethod>(method);
} else {
matchMethod = DocumentMatchMethod::FILENAME;
}
file.close();
Serial.printf("[%lu] [KRS] Loaded KOReader credentials for user: %s\n", millis(), username.c_str());
return true;
@@ -148,3 +160,9 @@ std::string KOReaderCredentialStore::getBaseUrl() const {
return serverUrl;
}
void KOReaderCredentialStore::setMatchMethod(DocumentMatchMethod method) {
matchMethod = method;
Serial.printf("[%lu] [KRS] Set match method: %s\n", millis(),
method == DocumentMatchMethod::FILENAME ? "Filename" : "Binary");
}

View File

@@ -1,6 +1,13 @@
#pragma once
#include <cstdint>
#include <string>
// Document matching method for KOReader sync
enum class DocumentMatchMethod : uint8_t {
FILENAME = 0, // Match by filename (simpler, works across different file sources)
BINARY = 1, // Match by partial MD5 of file content (more accurate, but files must be identical)
};
/**
* Singleton class for storing KOReader sync credentials on the SD card.
* Credentials are stored in /sd/.crosspoint/koreader.bin with basic
@@ -11,7 +18,8 @@ class KOReaderCredentialStore {
static KOReaderCredentialStore instance;
std::string username;
std::string password;
std::string serverUrl; // Custom sync server URL (empty = default)
std::string serverUrl; // Custom sync server URL (empty = default)
DocumentMatchMethod matchMethod = DocumentMatchMethod::FILENAME; // Default to filename for compatibility
// Private constructor for singleton
KOReaderCredentialStore() = default;
@@ -51,6 +59,10 @@ class KOReaderCredentialStore {
// Get base URL for API calls (with https:// normalization, falls back to default)
std::string getBaseUrl() const;
// Document matching method
void setMatchMethod(DocumentMatchMethod method);
DocumentMatchMethod getMatchMethod() const { return matchMethod; }
};
// Helper macro to access credential store

View File

@@ -4,6 +4,33 @@
#include <MD5Builder.h>
#include <SDCardManager.h>
namespace {
// Extract filename from path (everything after last '/')
std::string getFilename(const std::string& path) {
const size_t pos = path.rfind('/');
if (pos == std::string::npos) {
return path;
}
return path.substr(pos + 1);
}
} // namespace
std::string KOReaderDocumentId::calculateFromFilename(const std::string& filePath) {
const std::string filename = getFilename(filePath);
if (filename.empty()) {
return "";
}
MD5Builder md5;
md5.begin();
md5.add(filename.c_str());
md5.calculate();
std::string result = md5.toString().c_str();
Serial.printf("[%lu] [KODoc] Filename hash: %s (from '%s')\n", millis(), result.c_str(), filename.c_str());
return result;
}
size_t KOReaderDocumentId::getOffset(int i) {
// Offset = 1024 << (2*i)
// For i = -1: 1024 >> 2 = 256

View File

@@ -17,13 +17,22 @@
class KOReaderDocumentId {
public:
/**
* Calculate the KOReader document hash for a file.
* Calculate the KOReader document hash for a file (binary/content-based).
*
* @param filePath Path to the file (typically an EPUB)
* @return 32-character lowercase hex string, or empty string on failure
*/
static std::string calculate(const std::string& filePath);
/**
* Calculate document hash from filename only (filename-based sync mode).
* This is simpler and works when files have the same name across devices.
*
* @param filePath Path to the file (only the filename portion is used)
* @return 32-character lowercase hex MD5 of the filename
*/
static std::string calculateFromFilename(const std::string& filePath);
private:
// Size of each chunk to read at each offset
static constexpr size_t CHUNK_SIZE = 1024;