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:
43
data/app.js
43
data/app.js
@@ -162,14 +162,53 @@ async function renderDisplay(el) {
|
||||
}
|
||||
|
||||
async function renderDevice(el) {
|
||||
const settings = await api('/api/settings');
|
||||
el.innerHTML = `
|
||||
<div class="card">
|
||||
<h2>Device</h2>
|
||||
<h2>Immich Connection</h2>
|
||||
<div class="field">
|
||||
<label>Immich URL</label>
|
||||
<input type="url" id="immichUrl" value="${settings.immich_url || ''}" placeholder="https://photos.example.com">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>API Key</label>
|
||||
<input type="password" id="immichKey" value="${settings.immich_key || ''}" placeholder="Your Immich API key">
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-primary" id="saveImmich">Save</button>
|
||||
<button class="btn" id="testConn">Test Connection</button>
|
||||
</div>
|
||||
<div id="connStatus" style="margin-top:12px"></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>Device Actions</h2>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-danger" onclick="if(confirm('Enter deep sleep?'))api('/api/action/sleep',{method:'POST'})">Deep Sleep</button>
|
||||
<button class="btn btn-danger" onclick="if(confirm('Reboot?'))fetch('/api/action/reboot',{method:'POST'})">Reboot</button>
|
||||
<button class="btn btn-danger" onclick="if(confirm('Reboot device?'))fetch('/api/action/reboot',{method:'POST'})">Reboot</button>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
document.getElementById('saveImmich').onclick = async () => {
|
||||
const url = document.getElementById('immichUrl').value.trim();
|
||||
const key = document.getElementById('immichKey').value.trim();
|
||||
if (!url || !key) return toast('URL and API key are required');
|
||||
await api('/api/settings', { method: 'POST', body: JSON.stringify({ immich_url: url, immich_key: key }) });
|
||||
toast('Immich settings saved. Reboot to apply.');
|
||||
};
|
||||
|
||||
document.getElementById('testConn').onclick = async () => {
|
||||
const status = document.getElementById('connStatus');
|
||||
status.textContent = 'Testing...';
|
||||
status.style.color = '';
|
||||
try {
|
||||
const result = await api('/api/test-connection', { method: 'POST' });
|
||||
status.textContent = result.msg;
|
||||
status.style.color = result.ok ? '#2e7d32' : '#c62828';
|
||||
} catch (e) {
|
||||
status.textContent = 'Request failed: ' + e.message;
|
||||
status.style.color = '#c62828';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function renderFirmware(el) {
|
||||
|
||||
Reference in New Issue
Block a user