Keepalive fix, auto-reconnect on disconnect, tab icon fix, video playback guard
Keepalive: tokio::time::sleep inside select! was resetting every iteration — keepalives never fired. Switched to tokio::time::interval which ticks reliably. This caused connections to be zombie-reaped (10min timeout with no pings). Auto-reconnect: unexpected disconnects (stream error, not SocialDisconnectNotice) now attempt direct reconnect after 3s delay using last known address from peers table or social route. Falls back to notify_growth() if direct reconnect fails. Tab icons: updateTabBadge was using textContent which destroyed the icon and label spans inside tab buttons. Now updates only the .tab-label span and manages a separate .tab-badge element. Video playback: feed re-render skipped while any video or audio is actively playing, preventing echo from DOM destruction and media element recreation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
68afc40b16
commit
6320a82852
4 changed files with 118 additions and 12 deletions
|
|
@ -591,8 +591,24 @@ const TAB_BASE_LABELS = { feed: 'Feed', myposts: 'My Posts', people: 'People', m
|
|||
function updateTabBadge(tabName, count) {
|
||||
const tab = document.querySelector(`.tab[data-tab="${tabName}"]`);
|
||||
if (!tab) return;
|
||||
// Update the label span (preserve icon span)
|
||||
const label = tab.querySelector('.tab-label');
|
||||
const base = TAB_BASE_LABELS[tabName] || tabName;
|
||||
tab.textContent = count > 0 ? `${base} (${count})` : base;
|
||||
if (label) {
|
||||
label.textContent = base;
|
||||
}
|
||||
// Update or create badge span
|
||||
let badge = tab.querySelector('.tab-badge');
|
||||
if (count > 0) {
|
||||
if (!badge) {
|
||||
badge = document.createElement('span');
|
||||
badge.className = 'tab-badge';
|
||||
tab.appendChild(badge);
|
||||
}
|
||||
badge.textContent = count;
|
||||
} else if (badge) {
|
||||
badge.remove();
|
||||
}
|
||||
}
|
||||
|
||||
let _lastFeedViewMs = 0;
|
||||
|
|
@ -743,6 +759,18 @@ async function loadFeed(force) {
|
|||
} catch (_) {}
|
||||
}
|
||||
|
||||
// Skip full re-render if any video/audio is actively playing (prevents echo/restart)
|
||||
const mediaPlaying = [...feedList.querySelectorAll('video, audio')].some(el => !el.paused);
|
||||
if (mediaPlaying) {
|
||||
// Don't destroy the DOM while media is playing — re-render on next cycle when stopped
|
||||
return;
|
||||
}
|
||||
|
||||
// Revoke old object URLs to prevent memory leaks
|
||||
feedList.querySelectorAll('video[src^="blob:"], audio[src^="blob:"], img[src^="blob:"]').forEach(el => {
|
||||
if (el.src.startsWith('blob:')) URL.revokeObjectURL(el.src);
|
||||
});
|
||||
|
||||
// Preserve expanded comment threads
|
||||
const expandedComments = new Set();
|
||||
feedList.querySelectorAll('.comment-thread:not(.hidden)').forEach(el => {
|
||||
|
|
@ -780,6 +808,13 @@ async function loadMyPosts(force) {
|
|||
const fp = mine.map(p => `${p.id}:${(p.reactionCounts||[]).map(r=>r.emoji+r.count).join(',')}:${p.commentCount||0}`).join('|');
|
||||
if (!force && fp === _myPostsFingerprint) return;
|
||||
_myPostsFingerprint = fp;
|
||||
// Skip re-render if media is playing
|
||||
const mediaPlaying = [...myPostsList.querySelectorAll('video, audio')].some(el => !el.paused);
|
||||
if (mediaPlaying) return;
|
||||
// Revoke old blob URLs
|
||||
myPostsList.querySelectorAll('video[src^="blob:"], audio[src^="blob:"], img[src^="blob:"]').forEach(el => {
|
||||
if (el.src.startsWith('blob:')) URL.revokeObjectURL(el.src);
|
||||
});
|
||||
const expandedComments = new Set();
|
||||
myPostsList.querySelectorAll('.comment-thread:not(.hidden)').forEach(el => {
|
||||
const postEl = el.closest('.post');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue