Initial commit: SyncWatch Chrome extension + WebSocket server

This commit is contained in:
2026-05-23 22:22:19 -04:00
commit 24d88f4754
8 changed files with 649 additions and 0 deletions

66
extension/content.js Normal file
View File

@@ -0,0 +1,66 @@
let applyingRemote = false;
function getMediaElement() {
const els = Array.from(document.querySelectorAll('video, audio'));
if (!els.length) return null;
const playing = els.find((el) => !el.paused && !el.ended);
if (playing) return playing;
const videos = els.filter((el) => el.tagName === 'VIDEO');
return videos.length ? videos[0] : els[0];
}
function onPlay(e) {
if (applyingRemote) return;
chrome.runtime.sendMessage({ type: 'media_event', action: 'play', time: e.target.currentTime });
}
function onPause(e) {
if (applyingRemote) return;
chrome.runtime.sendMessage({ type: 'media_event', action: 'pause', time: e.target.currentTime });
}
function onSeeked(e) {
if (applyingRemote) return;
chrome.runtime.sendMessage({ type: 'media_event', action: 'seek', time: e.target.currentTime });
}
function attachToMedia(el) {
if (el._syncwatchAttached) return;
el._syncwatchAttached = true;
el.addEventListener('play', onPlay);
el.addEventListener('pause', onPause);
el.addEventListener('seeked', onSeeked);
}
function attachAll() {
document.querySelectorAll('video, audio').forEach(attachToMedia);
}
attachAll();
const observer = new MutationObserver(attachAll);
observer.observe(document.documentElement, { childList: true, subtree: true });
chrome.runtime.onMessage.addListener((msg) => {
if (msg.type !== 'apply_sync') return;
const el = getMediaElement();
if (!el) return;
applyingRemote = true;
// Re-sync time on any action; only seek if drift is significant
const drift = Math.abs(el.currentTime - msg.time);
if (msg.action === 'play') {
if (drift > 1) el.currentTime = msg.time;
el.play().catch(() => {});
} else if (msg.action === 'pause') {
el.pause();
if (drift > 1) el.currentTime = msg.time;
} else if (msg.action === 'seek') {
el.currentTime = msg.time;
}
setTimeout(() => { applyingRemote = false; }, 500);
});