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:
Justin Mitchell
2026-01-07 03:58:37 -05:00
committed by GitHub
parent afe9672156
commit b792b792bf
22 changed files with 2287 additions and 40 deletions

View File

@@ -4,6 +4,8 @@
#include <SDCardManager.h>
#include <Serialization.h>
#include <cstring>
#include "fontIds.h"
// Initialize the static instance
@@ -12,7 +14,7 @@ CrossPointSettings CrossPointSettings::instance;
namespace {
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
// Increment this when adding new persisted settings fields
constexpr uint8_t SETTINGS_COUNT = 15;
constexpr uint8_t SETTINGS_COUNT = 16;
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
} // namespace
@@ -40,6 +42,7 @@ bool CrossPointSettings::saveToFile() const {
serialization::writePod(outputFile, paragraphAlignment);
serialization::writePod(outputFile, sleepTimeout);
serialization::writePod(outputFile, refreshFrequency);
serialization::writeString(outputFile, std::string(opdsServerUrl));
serialization::writePod(outputFile, screenMargin);
serialization::writePod(outputFile, sleepScreenCoverMode);
outputFile.close();
@@ -94,10 +97,16 @@ bool CrossPointSettings::loadFromFile() {
if (++settingsRead >= fileSettingsCount) break;
serialization::readPod(inputFile, refreshFrequency);
if (++settingsRead >= fileSettingsCount) break;
{
std::string urlStr;
serialization::readString(inputFile, urlStr);
strncpy(opdsServerUrl, urlStr.c_str(), sizeof(opdsServerUrl) - 1);
opdsServerUrl[sizeof(opdsServerUrl) - 1] = '\0';
}
if (++settingsRead >= fileSettingsCount) break;
serialization::readPod(inputFile, screenMargin);
if (++settingsRead >= fileSettingsCount) break;
serialization::readPod(inputFile, sleepScreenCoverMode);
if (++settingsRead >= fileSettingsCount) break;
} while (false);
inputFile.close();