diff --git a/scripts/build_html.py b/scripts/build_html.py
index 248aba84..b144d5dc 100644
--- a/scripts/build_html.py
+++ b/scripts/build_html.py
@@ -1,5 +1,6 @@
import os
import re
+import gzip
SRC_DIR = "src"
@@ -40,12 +41,34 @@ for root, _, files in os.walk(SRC_DIR):
# minified = regex.sub("\g<1>", html_content)
minified = minify_html(html_content)
+
+ # Compress with gzip (compresslevel 9 is maximum compression)
+ # IMPORTANT: we don't use brotli because Firefox doesn't support brotli with insecured context (only supported on HTTPS)
+ compressed = gzip.compress(minified.encode('utf-8'), compresslevel=9)
+
base_name = f"{os.path.splitext(file)[0]}Html"
header_path = os.path.join(root, f"{base_name}.generated.h")
with open(header_path, "w", encoding="utf-8") as h:
h.write(f"// THIS FILE IS AUTOGENERATED, DO NOT EDIT MANUALLY\n\n")
h.write(f"#pragma once\n")
- h.write(f'constexpr char {base_name}[] PROGMEM = R"rawliteral({minified})rawliteral";\n')
+ h.write(f"#include \n\n")
+
+ # Write the compressed data as a byte array
+ h.write(f"constexpr char {base_name}[] PROGMEM = {{\n")
+
+ # Write bytes in rows of 16
+ for i in range(0, len(compressed), 16):
+ chunk = compressed[i:i+16]
+ hex_values = ', '.join(f'0x{b:02x}' for b in chunk)
+ h.write(f" {hex_values},\n")
+
+ h.write(f"}};\n\n")
+ h.write(f"constexpr size_t {base_name}CompressedSize = {len(compressed)};\n")
+ h.write(f"constexpr size_t {base_name}OriginalSize = {len(minified)};\n")
print(f"Generated: {header_path}")
+ print(f" Original: {len(html_content)} bytes")
+ print(f" Minified: {len(minified)} bytes ({100*len(minified)/len(html_content):.1f}%)")
+ print(f" Compressed: {len(compressed)} bytes ({100*len(compressed)/len(html_content):.1f}%)")
+
diff --git a/src/network/CrossPointWebServer.cpp b/src/network/CrossPointWebServer.cpp
index 3fd3ff87..91f1fd51 100644
--- a/src/network/CrossPointWebServer.cpp
+++ b/src/network/CrossPointWebServer.cpp
@@ -293,8 +293,13 @@ CrossPointWebServer::WsUploadStatus CrossPointWebServer::getWsUploadStatus() con
return status;
}
+static void sendHtmlContent(WebServer* server, const char* data, size_t len) {
+ server->sendHeader("Content-Encoding", "gzip");
+ server->send_P(200, "text/html", data, len);
+}
+
void CrossPointWebServer::handleRoot() const {
- server->send(200, "text/html", HomePageHtml);
+ sendHtmlContent(server.get(), HomePageHtml, sizeof(HomePageHtml));
LOG_DBG("WEB", "Served root page");
}
@@ -385,7 +390,9 @@ bool CrossPointWebServer::isEpubFile(const String& filename) const {
return lower.endsWith(".epub");
}
-void CrossPointWebServer::handleFileList() const { server->send(200, "text/html", FilesPageHtml); }
+void CrossPointWebServer::handleFileList() const {
+ sendHtmlContent(server.get(), FilesPageHtml, sizeof(FilesPageHtml));
+}
void CrossPointWebServer::handleFileListData() const {
// Get current path from query string (default to root)
@@ -989,7 +996,7 @@ void CrossPointWebServer::handleDelete() const {
}
void CrossPointWebServer::handleSettingsPage() const {
- server->send(200, "text/html", SettingsPageHtml);
+ sendHtmlContent(server.get(), SettingsPageHtml, sizeof(SettingsPageHtml));
LOG_DBG("WEB", "Served settings page");
}