mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-15 17:25:26 -04:00
Prefetch adjacent emails while reading
This commit is contained in:
+13
-6
@@ -1285,17 +1285,24 @@ def setup_email_routes():
|
|||||||
logger.debug(f"mark-seen after cached read failed uid={uid}: {e}")
|
logger.debug(f"mark-seen after cached read failed uid={uid}: {e}")
|
||||||
|
|
||||||
@router.get("/read/{uid}")
|
@router.get("/read/{uid}")
|
||||||
async def read_email_by_uid(uid: str, folder: str = Query("INBOX"), account_id: str | None = Query(None), owner: str = Depends(require_owner)):
|
async def read_email_by_uid(
|
||||||
|
uid: str,
|
||||||
|
folder: str = Query("INBOX"),
|
||||||
|
account_id: str | None = Query(None),
|
||||||
|
mark_seen: bool = Query(True),
|
||||||
|
owner: str = Depends(require_owner),
|
||||||
|
):
|
||||||
"""Read email body. Cached for 30m, sync IMAP work runs in a thread."""
|
"""Read email body. Cached for 30m, sync IMAP work runs in a thread."""
|
||||||
ck = _read_cache_key(account_id, folder, uid, owner=owner)
|
ck = _read_cache_key(account_id, folder, uid, owner=owner)
|
||||||
cached = _read_cache_get(ck)
|
cached = _read_cache_get(ck)
|
||||||
if cached is not None:
|
if cached is not None:
|
||||||
try:
|
if mark_seen:
|
||||||
_asyncio.create_task(_asyncio.to_thread(_mark_email_seen_sync, uid, folder, account_id, owner))
|
try:
|
||||||
except RuntimeError:
|
_asyncio.create_task(_asyncio.to_thread(_mark_email_seen_sync, uid, folder, account_id, owner))
|
||||||
pass
|
except RuntimeError:
|
||||||
|
pass
|
||||||
return cached
|
return cached
|
||||||
result = await _asyncio.to_thread(_read_email_sync, uid, folder, account_id, owner)
|
result = await _asyncio.to_thread(_read_email_sync, uid, folder, account_id, owner, mark_seen)
|
||||||
if result and not result.get("error"):
|
if result and not result.get("error"):
|
||||||
_read_cache_put(ck, result)
|
_read_cache_put(ck, result)
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -1788,6 +1788,34 @@ function _syncCardNavArrows(card) {
|
|||||||
if (next) next.disabled = !_findSiblingEmailCard(card, 1);
|
if (next) next.disabled = !_findSiblingEmailCard(card, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _emailReadPrefetching = new Set();
|
||||||
|
|
||||||
|
function _prefetchAdjacentEmails(card, count = 3) {
|
||||||
|
if (!card || state._libFolder === '__scheduled__') return;
|
||||||
|
const grid = card.closest('.doclib-grid');
|
||||||
|
if (!grid) return;
|
||||||
|
const cards = [...grid.querySelectorAll('.doclib-card[data-uid]')];
|
||||||
|
const idx = cards.indexOf(card);
|
||||||
|
if (idx === -1) return;
|
||||||
|
const targets = [];
|
||||||
|
for (let i = 1; i <= count; i++) {
|
||||||
|
if (cards[idx + i]) targets.push(cards[idx + i]);
|
||||||
|
}
|
||||||
|
if (targets.length < count) {
|
||||||
|
for (let i = 1; targets.length < count && cards[idx - i]; i++) targets.push(cards[idx - i]);
|
||||||
|
}
|
||||||
|
for (const target of targets) {
|
||||||
|
const uid = target.dataset.uid;
|
||||||
|
if (!uid) continue;
|
||||||
|
const key = `${state._libAccountId || ''}|${state._libFolder}|${uid}`;
|
||||||
|
if (_emailReadPrefetching.has(key)) continue;
|
||||||
|
_emailReadPrefetching.add(key);
|
||||||
|
fetch(`${API_BASE}/api/email/read/${encodeURIComponent(uid)}?folder=${encodeURIComponent(state._libFolder)}${_acct()}&mark_seen=false`)
|
||||||
|
.catch(() => {})
|
||||||
|
.finally(() => _emailReadPrefetching.delete(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function _toggleCardPreview(card, em) {
|
async function _toggleCardPreview(card, em) {
|
||||||
const grid = card.closest('.doclib-grid');
|
const grid = card.closest('.doclib-grid');
|
||||||
|
|
||||||
@@ -1843,6 +1871,7 @@ async function _toggleCardPreview(card, em) {
|
|||||||
|
|
||||||
// Mark as read locally
|
// Mark as read locally
|
||||||
_syncEmailReadState(em.uid, true);
|
_syncEmailReadState(em.uid, true);
|
||||||
|
_prefetchAdjacentEmails(card);
|
||||||
|
|
||||||
// Build the attachments wrap using the shared helper so the signature-
|
// Build the attachments wrap using the shared helper so the signature-
|
||||||
// image filter (small inline PNGs/JPGs, Outlook image001 placeholders,
|
// image filter (small inline PNGs/JPGs, Outlook image001 placeholders,
|
||||||
|
|||||||
Reference in New Issue
Block a user