Calibre Web Epub Downloading + Calibre Wireless Device Syncing (#219)
## Summary Adds support for browsing and downloading books from a Calibre-web server via OPDS. How it works 1. Configure server URL in Settings → Calibre Web URL (e.g., https://myserver.com:port I use Cloudflare tunnel to make my server accessible anywhere fwiw) 2. "Calibre Library" will now show on the the home screen 3. Browse the catalog - navigate through categories like "By Newest", "By Author", "By Series", etc. 4. Download books - select a book and press Confirm to download the EPUB to your device Navigation - Up/Down - Move through entries - Confirm - Open folder or download book - Back - Go to parent catalog, or exit to home if at root - Navigation entries show with > prefix, books show title and author - Button hints update dynamically ("Open" for folders, "Download" for books) Technical details - Fetches OPDS catalog from {server_url}/opds - Parses both navigation feeds (catalog links) and acquisition feeds (downloadable books) - Maintains navigation history stack for back navigation - Handles absolute paths in OPDS links correctly (e.g., /books/opds/navcatalog/...) - Downloads EPUBs directly to the SD card root Note The server URL should be typed to include https:// if the server requires it - HTTP→HTTPS redirects may cause SSL errors on ESP32. ## Additional Context * I also changed the home titles to use uppercase for each word and added a setting to change the size of the side margins --------- Co-authored-by: Dave Allie <dave@daveallie.com>
This commit is contained in:
36
src/util/StringUtils.cpp
Normal file
36
src/util/StringUtils.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "StringUtils.h"
|
||||
|
||||
namespace StringUtils {
|
||||
|
||||
std::string sanitizeFilename(const std::string& name, size_t maxLength) {
|
||||
std::string result;
|
||||
result.reserve(name.size());
|
||||
|
||||
for (char c : name) {
|
||||
// Replace invalid filename characters with underscore
|
||||
if (c == '/' || c == '\\' || c == ':' || c == '*' || c == '?' || c == '"' || c == '<' || c == '>' || c == '|') {
|
||||
result += '_';
|
||||
} else if (c >= 32 && c < 127) {
|
||||
// Keep printable ASCII characters
|
||||
result += c;
|
||||
}
|
||||
// Skip non-printable characters
|
||||
}
|
||||
|
||||
// Trim leading/trailing spaces and dots
|
||||
size_t start = result.find_first_not_of(" .");
|
||||
if (start == std::string::npos) {
|
||||
return "book"; // Fallback if name is all invalid characters
|
||||
}
|
||||
size_t end = result.find_last_not_of(" .");
|
||||
result = result.substr(start, end - start + 1);
|
||||
|
||||
// Limit filename length
|
||||
if (result.length() > maxLength) {
|
||||
result.resize(maxLength);
|
||||
}
|
||||
|
||||
return result.empty() ? "book" : result;
|
||||
}
|
||||
|
||||
} // namespace StringUtils
|
||||
Reference in New Issue
Block a user