diff --git a/app/routes/api.py b/app/routes/api.py
index ad4a229..b6aeda3 100644
--- a/app/routes/api.py
+++ b/app/routes/api.py
@@ -696,6 +696,7 @@ def get_cached_contacts():
Query params:
?format=names - Return just name strings for @mentions (default)
?format=full - Return full cache entries with public_key, timestamps, etc.
+ ?format=count - Return only the count (lightweight)
"""
try:
fmt = request.args.get('format', 'names')
@@ -704,7 +705,12 @@ def get_cached_contacts():
db = _get_db()
if db:
db_contacts = db.get_contacts()
- if fmt == 'full':
+ if fmt == 'count':
+ return jsonify({
+ 'success': True,
+ 'count': len(db_contacts)
+ }), 200
+ elif fmt == 'full':
ignored_keys = db.get_ignored_keys()
blocked_keys = db.get_blocked_keys()
contacts = []
@@ -745,7 +751,13 @@ def get_cached_contacts():
}), 200
else:
# Fallback to contacts_cache
- if fmt == 'full':
+ if fmt == 'count':
+ contacts = get_all_contacts()
+ return jsonify({
+ 'success': True,
+ 'count': len(contacts)
+ }), 200
+ elif fmt == 'full':
contacts = get_all_contacts()
for c in contacts:
c['public_key_prefix'] = c.get('public_key', '')[:12]
diff --git a/app/static/js/contacts.js b/app/static/js/contacts.js
index e91f375..dafb33f 100644
--- a/app/static/js/contacts.js
+++ b/app/static/js/contacts.js
@@ -263,15 +263,20 @@ async function loadContactCounts() {
pendingBadge.classList.remove('spinner-border', 'spinner-border-sm');
}
- // Fetch existing count
- const existingResp = await fetch('/api/contacts/detailed');
+ // Fetch existing count (device + cached in parallel)
+ const [existingResp, cachedResp] = await Promise.all([
+ fetch('/api/contacts/detailed'),
+ fetch('/api/contacts/cached?format=count')
+ ]);
const existingData = await existingResp.json();
+ const cachedData = await cachedResp.json();
const existingBadge = document.getElementById('existingBadge');
if (existingBadge && existingData.success) {
const count = existingData.count || 0;
const limit = existingData.limit || 350;
- existingBadge.textContent = `${count} / ${limit}`;
+ const totalKnown = cachedData.success ? (cachedData.count || 0) : count;
+ existingBadge.innerHTML = `${totalKnown} ( ${count}/${limit})`;
existingBadge.classList.remove('spinner-border', 'spinner-border-sm');
// Apply counter color coding
@@ -1872,11 +1877,8 @@ function updateCounter(count, limit, totalKnown) {
const counterEl = document.getElementById('contactsCounter');
if (!counterEl) return;
- let text = `${count} / ${limit}`;
- if (totalKnown && totalKnown > count) {
- text += ` (${totalKnown} cached)`;
- }
- counterEl.textContent = text;
+ const total = totalKnown || count;
+ counterEl.innerHTML = `${total} ( ${count}/${limit})`;
counterEl.style.display = 'inline-block';
// Remove all counter classes