|
|
|
|
@@ -34,7 +34,7 @@ import { ChapterVote } from "./render/ChapterVote";
|
|
|
|
|
import { openWarningDialog } from "./utils/warnings";
|
|
|
|
|
import { isFirefoxOrSafari, waitFor } from "../maze-utils/src";
|
|
|
|
|
import { getErrorMessage, getFormattedTime } from "../maze-utils/src/formating";
|
|
|
|
|
import { getChannelIDInfo, getVideo, getIsAdPlaying, getIsLivePremiere, setIsAdPlaying, checkVideoIDChange, getVideoID, getYouTubeVideoID, setupVideoModule, checkIfNewVideoID, isOnInvidious, isOnMobileYouTube } from "../maze-utils/src/video";
|
|
|
|
|
import { getChannelIDInfo, getVideo, getIsAdPlaying, getIsLivePremiere, setIsAdPlaying, checkVideoIDChange, getVideoID, getYouTubeVideoID, setupVideoModule, checkIfNewVideoID, isOnInvidious, isOnMobileYouTube, getLastNonInlineVideoID, triggerVideoIDChange, triggerVideoElementChange, getIsInline } from "../maze-utils/src/video";
|
|
|
|
|
import { Keybind, StorageChangesObject, isSafari, keybindEquals, keybindToString } from "../maze-utils/src/config";
|
|
|
|
|
import { findValidElement } from "../maze-utils/src/dom"
|
|
|
|
|
import { getHash, HashedValue } from "../maze-utils/src/hash";
|
|
|
|
|
@@ -49,6 +49,7 @@ import { hideDeArrowPromotion, tryShowingDeArrowPromotion } from "./dearrowPromo
|
|
|
|
|
import { asyncRequestToServer } from "./utils/requests";
|
|
|
|
|
import { isMobileControlsOpen } from "./utils/mobileUtils";
|
|
|
|
|
import { defaultPreviewTime } from "./utils/constants";
|
|
|
|
|
import { onVideoPage } from "../maze-utils/src/pageInfo";
|
|
|
|
|
|
|
|
|
|
cleanPage();
|
|
|
|
|
|
|
|
|
|
@@ -72,6 +73,8 @@ let sponsorDataFound = false;
|
|
|
|
|
let sponsorTimes: SponsorTime[] = [];
|
|
|
|
|
let existingChaptersImported = false;
|
|
|
|
|
let importingChaptersWaitingForFocus = false;
|
|
|
|
|
let importingChaptersWaiting = false;
|
|
|
|
|
let triedImportingChapters = false;
|
|
|
|
|
// List of open skip notices
|
|
|
|
|
const skipNotices: SkipNotice[] = [];
|
|
|
|
|
let activeSkipKeybindElement: ToggleSkippable = null;
|
|
|
|
|
@@ -128,9 +131,6 @@ setupVideoModule({
|
|
|
|
|
}, () => Config);
|
|
|
|
|
setupThumbnailListener();
|
|
|
|
|
|
|
|
|
|
//the video id of the last preview bar update
|
|
|
|
|
let lastPreviewBarUpdate: VideoID;
|
|
|
|
|
|
|
|
|
|
// Is the video currently being switched
|
|
|
|
|
let switchingVideos = null;
|
|
|
|
|
|
|
|
|
|
@@ -168,7 +168,6 @@ let submissionNotice: SubmissionNotice = null;
|
|
|
|
|
|
|
|
|
|
let lastResponseStatus: number;
|
|
|
|
|
let retryCount = 0;
|
|
|
|
|
let lookupWaiting = false;
|
|
|
|
|
|
|
|
|
|
// Contains all of the functions and variables needed by the skip notice
|
|
|
|
|
const skipNoticeContentContainer: ContentContainer = () => ({
|
|
|
|
|
@@ -219,7 +218,7 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
|
|
|
|
found: sponsorDataFound,
|
|
|
|
|
status: lastResponseStatus,
|
|
|
|
|
sponsorTimes: sponsorTimes,
|
|
|
|
|
time: getVideo().currentTime,
|
|
|
|
|
time: getVideo()?.currentTime ?? 0,
|
|
|
|
|
onMobileYouTube: isOnMobileYouTube()
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@@ -303,7 +302,9 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
|
|
|
|
if (!sponsorTimesSubmitting.some(
|
|
|
|
|
(s) => Math.abs(s.segment[0] - segment.segment[0]) < 1
|
|
|
|
|
&& Math.abs(s.segment[1] - segment.segment[1]) < 1)) {
|
|
|
|
|
if (segment.category === "chapter" && !utils.getCategorySelection("chapter")) {
|
|
|
|
|
const hasChaptersPermission = (Config.config.showCategoryWithoutPermission
|
|
|
|
|
|| Config.config.permissions["chapter"]);
|
|
|
|
|
if (segment.category === "chapter" && (!utils.getCategorySelection("chapter") || !hasChaptersPermission)) {
|
|
|
|
|
segment.category = "chooseACategory" as Category;
|
|
|
|
|
segment.actionType = ActionType.Skip;
|
|
|
|
|
segment.description = "";
|
|
|
|
|
@@ -382,6 +383,7 @@ function resetValues() {
|
|
|
|
|
|
|
|
|
|
sponsorTimes = [];
|
|
|
|
|
existingChaptersImported = false;
|
|
|
|
|
triedImportingChapters = false;
|
|
|
|
|
sponsorSkipped = [];
|
|
|
|
|
lastResponseStatus = 0;
|
|
|
|
|
shownSegmentFailedToFetchWarning = false;
|
|
|
|
|
@@ -398,8 +400,9 @@ function resetValues() {
|
|
|
|
|
//reset sponsor data found check
|
|
|
|
|
sponsorDataFound = false;
|
|
|
|
|
|
|
|
|
|
if (switchingVideos === null) {
|
|
|
|
|
// When first loading a video, it is not switching videos
|
|
|
|
|
// Hover play also doesn't need this check
|
|
|
|
|
if (switchingVideos === null || !onVideoPage()) {
|
|
|
|
|
switchingVideos = false;
|
|
|
|
|
} else {
|
|
|
|
|
switchingVideos = true;
|
|
|
|
|
@@ -456,6 +459,17 @@ function videoIDChange(): void {
|
|
|
|
|
updateSponsorTimesSubmitting();
|
|
|
|
|
|
|
|
|
|
tryShowingDeArrowPromotion().catch(logWarn);
|
|
|
|
|
|
|
|
|
|
checkPreviewbarState();
|
|
|
|
|
|
|
|
|
|
if (getIsInline()) {
|
|
|
|
|
// Hover preview progress bar can take some time to appear
|
|
|
|
|
// and if the miniplayer is also active then it would
|
|
|
|
|
// attach to the wrong one
|
|
|
|
|
setTimeout(checkPreviewbarState, 500);
|
|
|
|
|
setTimeout(checkPreviewbarState, 1000);
|
|
|
|
|
setTimeout(checkPreviewbarState, 3000);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleMobileControlsMutations(): void {
|
|
|
|
|
@@ -484,12 +498,7 @@ function handleMobileControlsMutations(): void {
|
|
|
|
|
createPreviewBar();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a preview bar on the video
|
|
|
|
|
*/
|
|
|
|
|
function createPreviewBar(): void {
|
|
|
|
|
if (previewBar !== null) return;
|
|
|
|
|
|
|
|
|
|
function getPreviewBarAttachElement(): HTMLElement | null {
|
|
|
|
|
const progressElementOptions = [{
|
|
|
|
|
// For new mobile YouTube (#1287)
|
|
|
|
|
selector: ".progress-bar-line",
|
|
|
|
|
@@ -499,11 +508,22 @@ function createPreviewBar(): void {
|
|
|
|
|
selector: ".YtProgressBarProgressBarLine",
|
|
|
|
|
isVisibleCheck: true
|
|
|
|
|
}, {
|
|
|
|
|
// For Desktop YouTube
|
|
|
|
|
// For newer mobile YouTube (May 2024)
|
|
|
|
|
selector: ".YtmProgressBarProgressBarLine",
|
|
|
|
|
isVisibleCheck: true
|
|
|
|
|
}, {
|
|
|
|
|
// For desktop YouTube hover play
|
|
|
|
|
// Priority is given to the hover play progress bar over the main progress bar
|
|
|
|
|
// for miniplayer + hover preview case
|
|
|
|
|
// Second is new hover play selector
|
|
|
|
|
selector: "#video-preview .ytp-progress-bar, #video-preview .YtProgressBarLineHost",
|
|
|
|
|
isVisibleCheck: true
|
|
|
|
|
}, {
|
|
|
|
|
// For desktop YouTube
|
|
|
|
|
selector: ".ytp-progress-bar",
|
|
|
|
|
isVisibleCheck: true
|
|
|
|
|
}, {
|
|
|
|
|
// For Desktop YouTube
|
|
|
|
|
// For desktop YouTube
|
|
|
|
|
selector: ".no-model.cue-range-marker",
|
|
|
|
|
isVisibleCheck: true
|
|
|
|
|
}, {
|
|
|
|
|
@@ -525,14 +545,27 @@ function createPreviewBar(): void {
|
|
|
|
|
const allElements = document.querySelectorAll(option.selector) as NodeListOf<HTMLElement>;
|
|
|
|
|
const el = option.isVisibleCheck ? findValidElement(allElements) : allElements[0];
|
|
|
|
|
|
|
|
|
|
if (el) {
|
|
|
|
|
return el;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a preview bar on the video
|
|
|
|
|
*/
|
|
|
|
|
function createPreviewBar(): void {
|
|
|
|
|
if (previewBar !== null) return;
|
|
|
|
|
|
|
|
|
|
const el = getPreviewBarAttachElement();
|
|
|
|
|
|
|
|
|
|
if (el) {
|
|
|
|
|
const chapterVote = new ChapterVote(voteAsync);
|
|
|
|
|
previewBar = new PreviewBar(el, isOnMobileYouTube(), isOnInvidious(), chapterVote, () => importExistingChapters(true));
|
|
|
|
|
|
|
|
|
|
updatePreviewBar();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -787,6 +820,8 @@ function inMuteSegment(currentTime: number, includeOverlap: boolean): boolean {
|
|
|
|
|
* This makes sure the videoID is still correct and if the sponsorTime is included
|
|
|
|
|
*/
|
|
|
|
|
function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boolean {
|
|
|
|
|
if (!onVideoPage()) return false;
|
|
|
|
|
|
|
|
|
|
const currentVideoID = getYouTubeVideoID();
|
|
|
|
|
const recordedVideoID = videoID || getVideoID();
|
|
|
|
|
if (currentVideoID !== recordedVideoID || (sponsorTime
|
|
|
|
|
@@ -810,14 +845,16 @@ let playbackRateCheckInterval: NodeJS.Timeout | null = null;
|
|
|
|
|
let lastPlaybackSpeed = 1;
|
|
|
|
|
let setupVideoListenersFirstTime = true;
|
|
|
|
|
function setupVideoListeners() {
|
|
|
|
|
const video = getVideo();
|
|
|
|
|
|
|
|
|
|
//wait until it is loaded
|
|
|
|
|
getVideo().addEventListener('loadstart', videoOnReadyListener)
|
|
|
|
|
getVideo().addEventListener('durationchange', durationChangeListener);
|
|
|
|
|
video.addEventListener('loadstart', videoOnReadyListener)
|
|
|
|
|
video.addEventListener('durationchange', durationChangeListener);
|
|
|
|
|
|
|
|
|
|
if (setupVideoListenersFirstTime) {
|
|
|
|
|
addCleanupListener(() => {
|
|
|
|
|
getVideo().removeEventListener('loadstart', videoOnReadyListener);
|
|
|
|
|
getVideo().removeEventListener('durationchange', durationChangeListener);
|
|
|
|
|
video.removeEventListener('loadstart', videoOnReadyListener);
|
|
|
|
|
video.removeEventListener('durationchange', durationChangeListener);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -833,18 +870,20 @@ function setupVideoListeners() {
|
|
|
|
|
|
|
|
|
|
startSponsorSchedule();
|
|
|
|
|
};
|
|
|
|
|
getVideo().addEventListener('ratechange', rateChangeListener);
|
|
|
|
|
video.addEventListener('ratechange', rateChangeListener);
|
|
|
|
|
// Used by videospeed extension (https://github.com/igrigorik/videospeed/pull/740)
|
|
|
|
|
getVideo().addEventListener('videoSpeed_ratechange', rateChangeListener);
|
|
|
|
|
video.addEventListener('videoSpeed_ratechange', rateChangeListener);
|
|
|
|
|
|
|
|
|
|
const playListener = () => {
|
|
|
|
|
// If it is not the first event, then the only way to get to 0 is if there is a seek event
|
|
|
|
|
// This check makes sure that changing the video resolution doesn't cause the extension to think it
|
|
|
|
|
// gone back to the begining
|
|
|
|
|
if (getVideo().readyState <= HTMLMediaElement.HAVE_CURRENT_DATA
|
|
|
|
|
&& getVideo().currentTime === 0) return;
|
|
|
|
|
if (video.readyState <= HTMLMediaElement.HAVE_CURRENT_DATA
|
|
|
|
|
&& video.currentTime === 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
updateVirtualTime();
|
|
|
|
|
checkForMiniplayerPlaying();
|
|
|
|
|
|
|
|
|
|
if (switchingVideos || lastPausedAtZero) {
|
|
|
|
|
switchingVideos = false;
|
|
|
|
|
@@ -860,15 +899,15 @@ function setupVideoListeners() {
|
|
|
|
|
updateAdFlag();
|
|
|
|
|
|
|
|
|
|
// Make sure it doesn't get double called with the playing event
|
|
|
|
|
if (Math.abs(lastCheckVideoTime - getVideo().currentTime) > 0.3
|
|
|
|
|
|| (lastCheckVideoTime !== getVideo().currentTime && Date.now() - lastCheckTime > 2000)) {
|
|
|
|
|
if (Math.abs(lastCheckVideoTime - video.currentTime) > 0.3
|
|
|
|
|
|| (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000)) {
|
|
|
|
|
lastCheckTime = Date.now();
|
|
|
|
|
lastCheckVideoTime = getVideo().currentTime;
|
|
|
|
|
lastCheckVideoTime = video.currentTime;
|
|
|
|
|
|
|
|
|
|
startSponsorSchedule();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
getVideo().addEventListener('play', playListener);
|
|
|
|
|
video.addEventListener('play', playListener);
|
|
|
|
|
|
|
|
|
|
const playingListener = () => {
|
|
|
|
|
updateVirtualTime();
|
|
|
|
|
@@ -876,8 +915,8 @@ function setupVideoListeners() {
|
|
|
|
|
|
|
|
|
|
if (startedWaiting) {
|
|
|
|
|
startedWaiting = false;
|
|
|
|
|
logDebug(`[SB] Playing event after buffering: ${Math.abs(lastCheckVideoTime - getVideo().currentTime) > 0.3
|
|
|
|
|
|| (lastCheckVideoTime !== getVideo().currentTime && Date.now() - lastCheckTime > 2000)}`);
|
|
|
|
|
logDebug(`[SB] Playing event after buffering: ${Math.abs(lastCheckVideoTime - video.currentTime) > 0.3
|
|
|
|
|
|| (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000)}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (switchingVideos) {
|
|
|
|
|
@@ -889,63 +928,63 @@ function setupVideoListeners() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure it doesn't get double called with the play event
|
|
|
|
|
if (Math.abs(lastCheckVideoTime - getVideo().currentTime) > 0.3
|
|
|
|
|
|| (lastCheckVideoTime !== getVideo().currentTime && Date.now() - lastCheckTime > 2000)) {
|
|
|
|
|
if (Math.abs(lastCheckVideoTime - video.currentTime) > 0.3
|
|
|
|
|
|| (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000)) {
|
|
|
|
|
lastCheckTime = Date.now();
|
|
|
|
|
lastCheckVideoTime = getVideo().currentTime;
|
|
|
|
|
lastCheckVideoTime = video.currentTime;
|
|
|
|
|
|
|
|
|
|
startSponsorSchedule();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (playbackRateCheckInterval) clearInterval(playbackRateCheckInterval);
|
|
|
|
|
lastPlaybackSpeed = getVideo().playbackRate;
|
|
|
|
|
lastPlaybackSpeed = video.playbackRate;
|
|
|
|
|
|
|
|
|
|
// Video speed controller compatibility
|
|
|
|
|
// That extension makes rate change events not propagate
|
|
|
|
|
if (document.body.classList.contains("vsc-initialized")) {
|
|
|
|
|
playbackRateCheckInterval = setInterval(() => {
|
|
|
|
|
if ((!getVideoID() || getVideo().paused) && playbackRateCheckInterval) {
|
|
|
|
|
if ((!getVideoID() || video.paused) && playbackRateCheckInterval) {
|
|
|
|
|
// Video is gone, stop checking
|
|
|
|
|
clearInterval(playbackRateCheckInterval);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (getVideo().playbackRate !== lastPlaybackSpeed) {
|
|
|
|
|
lastPlaybackSpeed = getVideo().playbackRate;
|
|
|
|
|
if (video.playbackRate !== lastPlaybackSpeed) {
|
|
|
|
|
lastPlaybackSpeed = video.playbackRate;
|
|
|
|
|
|
|
|
|
|
rateChangeListener();
|
|
|
|
|
}
|
|
|
|
|
}, 2000);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
getVideo().addEventListener('playing', playingListener);
|
|
|
|
|
video.addEventListener('playing', playingListener);
|
|
|
|
|
|
|
|
|
|
const seekingListener = () => {
|
|
|
|
|
lastKnownVideoTime.fromPause = false;
|
|
|
|
|
|
|
|
|
|
if (!getVideo().paused){
|
|
|
|
|
if (!video.paused){
|
|
|
|
|
// Reset lastCheckVideoTime
|
|
|
|
|
lastCheckTime = Date.now();
|
|
|
|
|
lastCheckVideoTime = getVideo().currentTime;
|
|
|
|
|
lastCheckVideoTime = video.currentTime;
|
|
|
|
|
|
|
|
|
|
updateVirtualTime();
|
|
|
|
|
clearWaitingTime();
|
|
|
|
|
|
|
|
|
|
// Sometimes looped videos loop back to almost zero, but not quite
|
|
|
|
|
if (getVideo().loop && getVideo().currentTime < 0.2) {
|
|
|
|
|
if (video.loop && video.currentTime < 0.2) {
|
|
|
|
|
startSponsorSchedule(false, 0);
|
|
|
|
|
} else {
|
|
|
|
|
startSponsorSchedule();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
updateActiveSegment(getVideo().currentTime);
|
|
|
|
|
updateActiveSegment(video.currentTime);
|
|
|
|
|
|
|
|
|
|
if (getVideo().currentTime === 0) {
|
|
|
|
|
if (video.currentTime === 0) {
|
|
|
|
|
lastPausedAtZero = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
getVideo().addEventListener('seeking', seekingListener);
|
|
|
|
|
video.addEventListener('seeking', seekingListener);
|
|
|
|
|
|
|
|
|
|
const stoppedPlayback = () => {
|
|
|
|
|
// Reset lastCheckVideoTime
|
|
|
|
|
@@ -956,7 +995,7 @@ function setupVideoListeners() {
|
|
|
|
|
|
|
|
|
|
lastKnownVideoTime.videoTime = null;
|
|
|
|
|
lastKnownVideoTime.preciseTime = null;
|
|
|
|
|
updateWaitingTime();
|
|
|
|
|
updateWaitingTime(video);
|
|
|
|
|
|
|
|
|
|
cancelSponsorSchedule();
|
|
|
|
|
};
|
|
|
|
|
@@ -965,26 +1004,26 @@ function setupVideoListeners() {
|
|
|
|
|
|
|
|
|
|
stoppedPlayback();
|
|
|
|
|
};
|
|
|
|
|
getVideo().addEventListener('pause', pauseListener);
|
|
|
|
|
video.addEventListener('pause', pauseListener);
|
|
|
|
|
const waitingListener = () => {
|
|
|
|
|
logDebug("[SB] Not skipping due to buffering");
|
|
|
|
|
startedWaiting = true;
|
|
|
|
|
|
|
|
|
|
stoppedPlayback();
|
|
|
|
|
};
|
|
|
|
|
getVideo().addEventListener('waiting', waitingListener);
|
|
|
|
|
video.addEventListener('waiting', waitingListener);
|
|
|
|
|
|
|
|
|
|
startSponsorSchedule();
|
|
|
|
|
|
|
|
|
|
if (setupVideoListenersFirstTime) {
|
|
|
|
|
addCleanupListener(() => {
|
|
|
|
|
getVideo().removeEventListener('play', playListener);
|
|
|
|
|
getVideo().removeEventListener('playing', playingListener);
|
|
|
|
|
getVideo().removeEventListener('seeking', seekingListener);
|
|
|
|
|
getVideo().removeEventListener('ratechange', rateChangeListener);
|
|
|
|
|
getVideo().removeEventListener('videoSpeed_ratechange', rateChangeListener);
|
|
|
|
|
getVideo().removeEventListener('pause', pauseListener);
|
|
|
|
|
getVideo().removeEventListener('waiting', waitingListener);
|
|
|
|
|
video.removeEventListener('play', playListener);
|
|
|
|
|
video.removeEventListener('playing', playingListener);
|
|
|
|
|
video.removeEventListener('seeking', seekingListener);
|
|
|
|
|
video.removeEventListener('ratechange', rateChangeListener);
|
|
|
|
|
video.removeEventListener('videoSpeed_ratechange', rateChangeListener);
|
|
|
|
|
video.removeEventListener('pause', pauseListener);
|
|
|
|
|
video.removeEventListener('waiting', waitingListener);
|
|
|
|
|
|
|
|
|
|
if (playbackRateCheckInterval) clearInterval(playbackRateCheckInterval);
|
|
|
|
|
});
|
|
|
|
|
@@ -1035,8 +1074,8 @@ function updateVirtualTime() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateWaitingTime(): void {
|
|
|
|
|
lastTimeFromWaitingEvent = getVideo().currentTime;
|
|
|
|
|
function updateWaitingTime(video: HTMLVideoElement): void {
|
|
|
|
|
lastTimeFromWaitingEvent = video.currentTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function clearWaitingTime(): void {
|
|
|
|
|
@@ -1070,17 +1109,6 @@ function setupCategoryPill() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function sponsorsLookup(keepOldSubmissions = true) {
|
|
|
|
|
if (lookupWaiting) return;
|
|
|
|
|
//there is still no video here
|
|
|
|
|
if (!getVideo()) {
|
|
|
|
|
lookupWaiting = true;
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
lookupWaiting = false;
|
|
|
|
|
sponsorsLookup()
|
|
|
|
|
}, 100);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const categories: string[] = Config.config.categorySelections.map((category) => category.name);
|
|
|
|
|
|
|
|
|
|
const extraRequestData: Record<string, unknown> = {};
|
|
|
|
|
@@ -1157,13 +1185,14 @@ async function sponsorsLookup(keepOldSubmissions = true) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!getVideo()) {
|
|
|
|
|
//there is still no video here
|
|
|
|
|
await waitFor(() => getVideo(), 5000, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
startSkipScheduleCheckingForStartSponsors();
|
|
|
|
|
|
|
|
|
|
//update the preview bar
|
|
|
|
|
//leave the type blank for now until categories are added
|
|
|
|
|
if (lastPreviewBarUpdate == getVideoID() || (lastPreviewBarUpdate == null && !isNaN(getVideo().duration))) {
|
|
|
|
|
//set it now
|
|
|
|
|
//otherwise the listener can handle it
|
|
|
|
|
if (!isNaN(getVideo().duration)) {
|
|
|
|
|
updatePreviewBar();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
@@ -1181,7 +1210,7 @@ async function sponsorsLookup(keepOldSubmissions = true) {
|
|
|
|
|
found: sponsorDataFound,
|
|
|
|
|
status: lastResponseStatus,
|
|
|
|
|
sponsorTimes: sponsorTimes,
|
|
|
|
|
time: getVideo().currentTime,
|
|
|
|
|
time: getVideo()?.currentTime ?? 0,
|
|
|
|
|
onMobileYouTube: isOnMobileYouTube()
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@@ -1191,10 +1220,10 @@ async function sponsorsLookup(keepOldSubmissions = true) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function importExistingChapters(wait: boolean) {
|
|
|
|
|
if (!existingChaptersImported) {
|
|
|
|
|
if (!existingChaptersImported && !importingChaptersWaiting && !triedImportingChapters && onVideoPage() && !isOnMobileYouTube()) {
|
|
|
|
|
const waitCondition = () => getVideo()?.duration && getExistingChapters(getVideoID(), getVideo().duration);
|
|
|
|
|
|
|
|
|
|
if (!waitCondition() && wait && !document.hasFocus() && !importingChaptersWaitingForFocus) {
|
|
|
|
|
if (wait && !document.hasFocus() && !importingChaptersWaitingForFocus && !waitCondition()) {
|
|
|
|
|
importingChaptersWaitingForFocus = true;
|
|
|
|
|
const listener = () => {
|
|
|
|
|
importExistingChapters(wait);
|
|
|
|
|
@@ -1202,14 +1231,17 @@ function importExistingChapters(wait: boolean) {
|
|
|
|
|
};
|
|
|
|
|
window.addEventListener("focus", listener);
|
|
|
|
|
} else {
|
|
|
|
|
importingChaptersWaiting = true;
|
|
|
|
|
waitFor(waitCondition,
|
|
|
|
|
wait ? 15000 : 0, 400, (c) => c?.length > 0).then((chapters) => {
|
|
|
|
|
importingChaptersWaiting = false;
|
|
|
|
|
|
|
|
|
|
if (!existingChaptersImported && chapters?.length > 0) {
|
|
|
|
|
sponsorTimes = (sponsorTimes ?? []).concat(...chapters).sort((a, b) => a.segment[0] - b.segment[0]);
|
|
|
|
|
existingChaptersImported = true;
|
|
|
|
|
updatePreviewBar();
|
|
|
|
|
}
|
|
|
|
|
}).catch(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function
|
|
|
|
|
}).catch(() => { importingChaptersWaiting = false; triedImportingChapters = true; }); // eslint-disable-line @typescript-eslint/no-empty-function
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1381,9 +1413,6 @@ function updatePreviewBar(): void {
|
|
|
|
|
|
|
|
|
|
showTimeWithoutSkips(skippedDuration);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update last video id
|
|
|
|
|
lastPreviewBarUpdate = getVideoID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//checks if this channel is whitelisted, should be done only after the channelID has been loaded
|
|
|
|
|
@@ -1408,6 +1437,7 @@ function videoElementChange(newVideo: boolean): void {
|
|
|
|
|
setupCategoryPill();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updatePreviewBar();
|
|
|
|
|
checkPreviewbarState();
|
|
|
|
|
|
|
|
|
|
// Incase the page is still transitioning, check again in a few seconds
|
|
|
|
|
@@ -1417,8 +1447,19 @@ function videoElementChange(newVideo: boolean): void {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let checkingPreviewbarAgain = false;
|
|
|
|
|
function checkPreviewbarState(): void {
|
|
|
|
|
if (previewBar && !utils.findReferenceNode()?.contains(previewBar.container)) {
|
|
|
|
|
if (!getPreviewBarAttachElement() && !checkingPreviewbarAgain && getVideo() && getVideoID()) {
|
|
|
|
|
checkingPreviewbarAgain = true;
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
checkingPreviewbarAgain = false;
|
|
|
|
|
checkPreviewbarState();
|
|
|
|
|
}, 500);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (previewBar && !getPreviewBarAttachElement()?.contains(previewBar.container)) {
|
|
|
|
|
previewBar.remove();
|
|
|
|
|
previewBar = null;
|
|
|
|
|
}
|
|
|
|
|
@@ -1600,6 +1641,13 @@ function previewTime(time: number, unpause = true) {
|
|
|
|
|
|
|
|
|
|
//send telemetry and count skip
|
|
|
|
|
function sendTelemetryAndCount(skippingSegments: SponsorTime[], secondsSkipped: number, fullSkip: boolean) {
|
|
|
|
|
for (const segment of skippingSegments) {
|
|
|
|
|
if (!previewedSegment && sponsorTimesSubmitting.some((s) => s.segment === segment.segment)) {
|
|
|
|
|
// Count that as a previewed segment
|
|
|
|
|
previewedSegment = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Config.config.trackViewCount || (!Config.config.trackViewCountInPrivate && chrome.extension.inIncognitoContext)) return;
|
|
|
|
|
|
|
|
|
|
let counted = false;
|
|
|
|
|
@@ -1616,9 +1664,6 @@ function sendTelemetryAndCount(skippingSegments: SponsorTime[], secondsSkipped:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fullSkip) asyncRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + segment.UUID);
|
|
|
|
|
} else if (!previewedSegment && sponsorTimesSubmitting.some((s) => s.segment === segment.segment)) {
|
|
|
|
|
// Count that as a previewed segment
|
|
|
|
|
previewedSegment = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1629,8 +1674,9 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
|
|
|
|
|
|
|
|
|
|
// There will only be one submission if it is manual skip
|
|
|
|
|
const autoSkip: boolean = forceAutoSkip || shouldAutoSkip(skippingSegments[0]);
|
|
|
|
|
const isSubmittingSegment = sponsorTimesSubmitting.some((time) => time.segment === skippingSegments[0].segment);
|
|
|
|
|
|
|
|
|
|
if ((autoSkip || sponsorTimesSubmitting.some((time) => time.segment === skippingSegments[0].segment))
|
|
|
|
|
if ((autoSkip || isSubmittingSegment)
|
|
|
|
|
&& v.currentTime !== skipTime[1]) {
|
|
|
|
|
switch(skippingSegments[0].actionType) {
|
|
|
|
|
case ActionType.Poi:
|
|
|
|
|
@@ -1711,7 +1757,7 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//send telemetry that a this sponsor was skipped
|
|
|
|
|
if (autoSkip) sendTelemetryAndCount(skippingSegments, skipTime[1] - skipTime[0], true);
|
|
|
|
|
if (autoSkip || isSubmittingSegment) sendTelemetryAndCount(skippingSegments, skipTime[1] - skipTime[0], true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createSkipNotice(skippingSegments: SponsorTime[], autoSkip: boolean, unskipTime: number, startReskip: boolean) {
|
|
|
|
|
@@ -1801,7 +1847,8 @@ function shouldAutoSkip(segment: SponsorTime): boolean {
|
|
|
|
|
return (!Config.config.manualSkipOnFullVideo || !sponsorTimes?.some((s) => s.category === segment.category && s.actionType === ActionType.Full))
|
|
|
|
|
&& (utils.getCategorySelection(segment.category)?.option === CategorySkipOption.AutoSkip ||
|
|
|
|
|
(Config.config.autoSkipOnMusicVideos && sponsorTimes?.some((s) => s.category === "music_offtopic")
|
|
|
|
|
&& segment.actionType === ActionType.Skip));
|
|
|
|
|
&& segment.actionType === ActionType.Skip)
|
|
|
|
|
|| sponsorTimesSubmitting.some((s) => s.segment === segment.segment));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function shouldSkip(segment: SponsorTime): boolean {
|
|
|
|
|
@@ -2668,3 +2715,22 @@ function setCategoryColorCSSVariables() {
|
|
|
|
|
|
|
|
|
|
styleContainer.innerText = css;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* If mini player starts playing, then videoID change might have to be called
|
|
|
|
|
*/
|
|
|
|
|
function checkForMiniplayerPlaying() {
|
|
|
|
|
const miniPlayerUI = document.querySelector(".miniplayer") as HTMLElement;
|
|
|
|
|
if (!onVideoPage() && isVisible(miniPlayerUI)) {
|
|
|
|
|
const videoID = getLastNonInlineVideoID();
|
|
|
|
|
if (videoID) {
|
|
|
|
|
triggerVideoIDChange(videoID);
|
|
|
|
|
|
|
|
|
|
// treat as if video element has changed
|
|
|
|
|
const video = miniPlayerUI.querySelector("video") as HTMLVideoElement;
|
|
|
|
|
if (video && getVideo() !== video) {
|
|
|
|
|
triggerVideoElementChange(video);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|