From de392d8d57dbda6e014233ef626ff1a59ac9f3cb Mon Sep 17 00:00:00 2001 From: rainbow napkin Date: Thu, 1 Oct 2026 00:47:54 -0400 Subject: [PATCH] Server-side sync tick syncs by tick delta, preventing video desync during server-slowdowns. --- src/app/channel/media/queue.js | 37 ++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/app/channel/media/queue.js b/src/app/channel/media/queue.js index e6d9c2c..1b975d0 100644 --- a/src/app/channel/media/queue.js +++ b/src/app/channel/media/queue.js @@ -57,11 +57,18 @@ class queue{ /** * Sync Delta in MS */ - this.syncDelta = 1000; + this.syncDelay = 1000; + + /** + * Epoch of last sync + */ + this.syncEpoch; + /** * Current Timestamp in Media */ this.timestamp = 0; + //Delay between pre-switch function call and start of media //This should be enough time to do things like pre-fetch updated raw links from youtube /** @@ -1193,7 +1200,7 @@ class queue{ clearTimeout(this.syncTimer); //Kick off the sync timer - this.syncTimer = setTimeout(this.sync.bind(this), this.syncDelta); + this.syncTimer = setTimeout(this.sync.bind(this), this.syncDelay); //Setup the next video this.refreshNextTimer(); @@ -1207,6 +1214,21 @@ class queue{ * Called auto-magically by the Synchronization Timer */ sync(){ + //define sync delta + let syncDelta = 0; + + //Get current time by epoch + const now = new Date().getTime(); + + //if this isnt the first sync call + if(this.syncEpoch != null && this.syncEpoch != 0){ + //Get time between now and last sync tick + syncDelta = now - this.syncEpoch; + } + + //Increment the time stamp by delta between now and last sync tick + this.timestamp += (syncDelta / 1000); + //Send sync signal out to the channel this.server.io.in(this.channel.name).emit("sync", {timestamp: this.timestamp}); @@ -1218,11 +1240,8 @@ class queue{ //If the media has over a second to go if((this.timestamp + 1) < this.nowPlaying.duration){ - //Increment the time stamp - this.timestamp += (this.syncDelta / 1000); - //Call the sync function in another second - this.syncTimer = setTimeout(this.sync.bind(this), this.syncDelta); + this.syncTimer = setTimeout(this.sync.bind(this), this.syncDelay); }else{ //Get leftover video length in ms const leftover = (this.nowPlaying.duration - this.timestamp) * 1000; @@ -1230,6 +1249,9 @@ class queue{ //Call the end function once the video is over this.syncTimer = setTimeout(this.end.bind(this), leftover); } + + //Set sync epoch for the next go-around + this.syncEpoch = now; } /** @@ -1259,6 +1281,9 @@ class queue{ //Clear now playing this.nowPlaying = null; + //Drop epoch timer like a bad habit + this.syncEpoch = null; + //Clear timestamp this.timestamp = 0;