feat: fit-contain letterbox + smart queue refill

- Replace center-crop with fit-contain (no photo cropping)
- Letterbox bars filled with adjacent edge average color
- Queue fetches in batches until 50 usable assets
- Auto-refill queue on exhaustion, dedup via shown history
- Filter RAW files from asset selection

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-03 14:39:55 -04:00
parent 4b9a7f2fa7
commit b80f6e4bde
10 changed files with 985 additions and 411 deletions

View File

@@ -157,6 +157,31 @@ void AppWebServer::setupAPIRoutes() {
_power->enterDeepSleep();
});
// Test Immich connectivity
_server.on("/api/test-connection", HTTP_POST,
[this](AsyncWebServerRequest* req) {
Settings s = _settings->get();
Serial.printf("[web] Testing connection to: %s (key: %s...)\n",
s.immich_url.c_str(),
s.immich_key.substring(0, 8).c_str());
// Reinitialize immich client with current settings
_immich->begin(s.immich_url, s.immich_key);
auto albums = _immich->fetchAlbums();
JsonDocument doc;
if (!albums.empty()) {
doc["ok"] = true;
doc["msg"] = String("Connected! Found ") + String(albums.size()) + " albums.";
} else {
doc["ok"] = false;
doc["msg"] = "Failed to connect. Check URL and API key.";
}
String response;
serializeJson(doc, response);
req->send(200, "application/json", response);
});
_server.on("/api/action/reboot", HTTP_POST,
[](AsyncWebServerRequest* req) {
req->send(200, "application/json", "{\"ok\":true,\"msg\":\"Rebooting...\"}");
@@ -259,6 +284,7 @@ void AppWebServer::handleGetSettings(AsyncWebServerRequest* request) {
doc["meta_pos"] = static_cast<uint8_t>(s.meta_pos);
doc["led_brightness"] = s.led_brightness;
doc["immich_url"] = s.immich_url;
doc["immich_key"] = s.immich_key;
doc["albums_json"] = s.albums_json;
String response;