Add new workaround for improving skipping precision on Firefox

This commit is contained in:
Ajay
2022-11-26 03:38:48 -05:00
parent 43c30bb03d
commit 5925d45f74

View File

@@ -71,12 +71,14 @@ let channelIDInfo: ChannelIDInfo;
// Locked Categories in this tab, like: ["sponsor","intro","outro"] // Locked Categories in this tab, like: ["sponsor","intro","outro"]
let lockedCategories: Category[] = []; let lockedCategories: Category[] = [];
// Used to calculate a more precise "virtual" video time // Used to calculate a more precise "virtual" video time
let lastKnownVideoTime: { videoTime: number; preciseTime: number } = { const lastKnownVideoTime: { videoTime: number; preciseTime: number; fromPause: boolean; approximateDelay: number } = {
videoTime: null, videoTime: null,
preciseTime: null preciseTime: null,
fromPause: false,
approximateDelay: null,
}; };
// It resumes with a slightly later time on chromium // It resumes with a slightly later time on chromium
let lastTimeFromWaitingEvent = null; let lastTimeFromWaitingEvent: number = null;
const lastNextChapterKeybind = { const lastNextChapterKeybind = {
time: 0, time: 0,
date: 0 date: 0
@@ -87,6 +89,7 @@ const lastNextChapterKeybind = {
// Skips are canceled every seeking event // Skips are canceled every seeking event
let currentSkipSchedule: NodeJS.Timeout = null; let currentSkipSchedule: NodeJS.Timeout = null;
let currentSkipInterval: NodeJS.Timeout = null; let currentSkipInterval: NodeJS.Timeout = null;
let currentVirtualTimeInterval: NodeJS.Timeout = null;
/** Has the sponsor been skipped */ /** Has the sponsor been skipped */
let sponsorSkipped: boolean[] = []; let sponsorSkipped: boolean[] = [];
@@ -600,6 +603,7 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
if (currentTime === undefined || currentTime === null) { if (currentTime === undefined || currentTime === null) {
currentTime = getVirtualTime(); currentTime = getVirtualTime();
} }
clearWaitingTime();
lastTimeFromWaitingEvent = null; lastTimeFromWaitingEvent = null;
updateActiveSegment(currentTime); updateActiveSegment(currentTime);
@@ -704,11 +708,23 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
// Use interval instead of timeout near the end to combat imprecise video time // Use interval instead of timeout near the end to combat imprecise video time
const startIntervalTime = performance.now(); const startIntervalTime = performance.now();
const startVideoTime = Math.max(currentTime, video.currentTime); const startVideoTime = Math.max(currentTime, video.currentTime);
let startWaitingForReportedTimeToChange = true;
const reportedVideoTimeAtStart = video.currentTime;
logDebug(`Starting setInterval skipping ${video.currentTime} to skip at ${skipTime[0]}`); logDebug(`Starting setInterval skipping ${video.currentTime} to skip at ${skipTime[0]}`);
currentSkipInterval = setInterval(() => { currentSkipInterval = setInterval(() => {
// Estimate delay, but only take the current time right after a change
// Current time remains the same for many "frames" on Firefox
if (utils.isFirefox() && !lastKnownVideoTime.fromPause && startWaitingForReportedTimeToChange
&& reportedVideoTimeAtStart !== video.currentTime) {
startWaitingForReportedTimeToChange = false;
const delay = getVirtualTime() - video.currentTime;
if (delay > 0) lastKnownVideoTime.approximateDelay = delay;
}
const intervalDuration = performance.now() - startIntervalTime; const intervalDuration = performance.now() - startIntervalTime;
if (intervalDuration >= delayTime || video.currentTime >= skipTime[0]) { if (intervalDuration + skipBuffer * 1000 >= delayTime || video.currentTime >= skipTime[0]) {
clearInterval(currentSkipInterval); clearInterval(currentSkipInterval);
if (!utils.isFirefox() && !video.muted) { if (!utils.isFirefox() && !video.muted) {
// Workaround for more accurate skipping on Chromium // Workaround for more accurate skipping on Chromium
@@ -716,7 +732,7 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
video.muted = false; video.muted = false;
} }
skippingFunction(Math.max(video.currentTime, startVideoTime + video.playbackRate * intervalDuration / 1000)); skippingFunction(Math.max(video.currentTime, startVideoTime + video.playbackRate * Math.max(delayTime, intervalDuration) / 1000));
} }
}, 1); }, 1);
} else { } else {
@@ -729,11 +745,11 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
} }
function getVirtualTime(): number { function getVirtualTime(): number {
const virtualTime = lastTimeFromWaitingEvent ?? (lastKnownVideoTime.videoTime ? const virtualTime = lastTimeFromWaitingEvent ?? (lastKnownVideoTime.videoTime !== null ?
(performance.now() - lastKnownVideoTime.preciseTime) * video.playbackRate / 1000 + lastKnownVideoTime.videoTime : null); (performance.now() - lastKnownVideoTime.preciseTime) * video.playbackRate / 1000 + lastKnownVideoTime.videoTime : null);
if (Config.config.useVirtualTime && !utils.isFirefox() && !isSafari() && virtualTime if (Config.config.useVirtualTime && !isSafari() && virtualTime
&& Math.abs(virtualTime - video.currentTime) < 0.6 && video.currentTime !== 0) { && Math.abs(virtualTime - video.currentTime) < 0.2 && video.currentTime !== 0) {
return virtualTime; return virtualTime;
} else { } else {
return video.currentTime; return video.currentTime;
@@ -878,13 +894,15 @@ function setupVideoListeners() {
} }
}); });
video.addEventListener('seeking', () => { video.addEventListener('seeking', () => {
lastKnownVideoTime.fromPause = false;
if (!video.paused){ if (!video.paused){
// Reset lastCheckVideoTime // Reset lastCheckVideoTime
lastCheckTime = Date.now(); lastCheckTime = Date.now();
lastCheckVideoTime = video.currentTime; lastCheckVideoTime = video.currentTime;
updateVirtualTime(); updateVirtualTime();
lastTimeFromWaitingEvent = null; clearWaitingTime();
startSponsorSchedule(); startSponsorSchedule();
} else { } else {
@@ -897,36 +915,38 @@ function setupVideoListeners() {
}); });
video.addEventListener('ratechange', () => { video.addEventListener('ratechange', () => {
updateVirtualTime(); updateVirtualTime();
lastTimeFromWaitingEvent = null; clearWaitingTime();
startSponsorSchedule(); startSponsorSchedule();
}); });
// Used by videospeed extension (https://github.com/igrigorik/videospeed/pull/740) // Used by videospeed extension (https://github.com/igrigorik/videospeed/pull/740)
video.addEventListener('videoSpeed_ratechange', () => { video.addEventListener('videoSpeed_ratechange', () => {
updateVirtualTime(); updateVirtualTime();
lastTimeFromWaitingEvent = null; clearWaitingTime();
startSponsorSchedule(); startSponsorSchedule();
}); });
const paused = () => { const stoppedPlayback = () => {
// Reset lastCheckVideoTime // Reset lastCheckVideoTime
lastCheckVideoTime = -1; lastCheckVideoTime = -1;
lastCheckTime = 0; lastCheckTime = 0;
lastKnownVideoTime = { lastKnownVideoTime.videoTime = null;
videoTime: null, lastKnownVideoTime.preciseTime = null;
preciseTime: null updateWaitingTime();
}
lastTimeFromWaitingEvent = video.currentTime;
cancelSponsorSchedule(); cancelSponsorSchedule();
}; };
video.addEventListener('pause', () => paused()); video.addEventListener('pause', () => {
lastKnownVideoTime.fromPause = true;
stoppedPlayback();
});
video.addEventListener('waiting', () => { video.addEventListener('waiting', () => {
logDebug("[SB] Not skipping due to buffering"); logDebug("[SB] Not skipping due to buffering");
startedWaiting = true; startedWaiting = true;
paused(); stoppedPlayback();
}); });
startSponsorSchedule(); startSponsorSchedule();
@@ -934,10 +954,43 @@ function setupVideoListeners() {
} }
function updateVirtualTime() { function updateVirtualTime() {
lastKnownVideoTime = { if (currentVirtualTimeInterval) clearInterval(currentVirtualTimeInterval);
videoTime: video.currentTime,
preciseTime: performance.now() lastKnownVideoTime.videoTime = video.currentTime;
}; lastKnownVideoTime.preciseTime = performance.now();
// If on Firefox, wait for the second time change (time remains fixed for many "frames" for privacy reasons)
if (utils.isFirefox()) {
let count = 0;
let lastTime = lastKnownVideoTime.videoTime;
if (lastKnownVideoTime.fromPause) {
currentVirtualTimeInterval = setInterval(() => {
if (lastTime !== video.currentTime) {
count++;
lastTime = video.currentTime;
}
if (count > 1) {
const delay = lastKnownVideoTime.fromPause && lastKnownVideoTime.approximateDelay ?
lastKnownVideoTime.approximateDelay : 0;
lastKnownVideoTime.videoTime = video.currentTime + delay;
lastKnownVideoTime.preciseTime = performance.now();
clearInterval(currentVirtualTimeInterval);
currentVirtualTimeInterval = null;
}
}, 1);
}
}
}
function updateWaitingTime(): void {
lastTimeFromWaitingEvent = video.currentTime;
}
function clearWaitingTime(): void {
lastTimeFromWaitingEvent = null;
} }
function setupSkipButtonControlBar() { function setupSkipButtonControlBar() {