mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-13 15:07:02 +03:00
Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into pr/Acors24/2086
This commit is contained in:
150
src/content.ts
150
src/content.ts
@@ -51,6 +51,7 @@ import { asyncRequestToServer } from "./utils/requests";
|
||||
import { isMobileControlsOpen } from "./utils/mobileUtils";
|
||||
import { defaultPreviewTime } from "./utils/constants";
|
||||
import { onVideoPage } from "../maze-utils/src/pageInfo";
|
||||
import { getSegmentsForVideo } from "./utils/segmentData";
|
||||
|
||||
cleanPage();
|
||||
|
||||
@@ -75,7 +76,6 @@ let sponsorTimes: SponsorTime[] = [];
|
||||
let existingChaptersImported = false;
|
||||
let importingChaptersWaitingForFocus = false;
|
||||
let importingChaptersWaiting = false;
|
||||
let triedImportingChapters = false;
|
||||
// List of open skip notices
|
||||
const skipNotices: SkipNotice[] = [];
|
||||
let upcomingNotice: UpcomingNotice | null = null;
|
||||
@@ -142,6 +142,9 @@ let switchingVideos = null;
|
||||
let lastCheckTime = 0;
|
||||
let lastCheckVideoTime = -1;
|
||||
|
||||
// To determine if a video resolution change is happening
|
||||
let firstPlay = true;
|
||||
|
||||
//is this channel whitelised from getting sponsors skipped
|
||||
let channelWhitelisted = false;
|
||||
|
||||
@@ -267,7 +270,7 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
||||
sendResponse({ hasVideo: getVideoID() != null });
|
||||
// fetch segments
|
||||
if (getVideoID()) {
|
||||
sponsorsLookup(false);
|
||||
sponsorsLookup(false, true);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -345,6 +348,12 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
||||
metaKey: request.metaKey
|
||||
}));
|
||||
break;
|
||||
case "getLogs":
|
||||
sendResponse({
|
||||
debug: window["SBLogs"].debug,
|
||||
warn: window["SBLogs"].warn
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
sendResponse({});
|
||||
@@ -362,7 +371,7 @@ function contentConfigUpdateListener(changes: StorageChangesObject) {
|
||||
updateVisibilityOfPlayerControlsButton()
|
||||
break;
|
||||
case "categorySelections":
|
||||
sponsorsLookup();
|
||||
sponsorsLookup(true, true);
|
||||
break;
|
||||
case "barTypes":
|
||||
setCategoryColorCSSVariables();
|
||||
@@ -384,10 +393,10 @@ function resetValues() {
|
||||
lastCheckVideoTime = -1;
|
||||
retryCount = 0;
|
||||
previewedSegment = false;
|
||||
firstPlay = true;
|
||||
|
||||
sponsorTimes = [];
|
||||
existingChaptersImported = false;
|
||||
triedImportingChapters = false;
|
||||
sponsorSkipped = [];
|
||||
lastResponseStatus = 0;
|
||||
shownSegmentFailedToFetchWarning = false;
|
||||
@@ -509,12 +518,8 @@ function handleMobileControlsMutations(): void {
|
||||
|
||||
function getPreviewBarAttachElement(): HTMLElement | null {
|
||||
const progressElementOptions = [{
|
||||
// For new mobile YouTube (#1287)
|
||||
selector: ".progress-bar-line",
|
||||
isVisibleCheck: true
|
||||
}, {
|
||||
// For newer mobile YouTube (Jan 2024)
|
||||
selector: ".YtProgressBarProgressBarLine",
|
||||
// For newer mobile YouTube (Sept 2024)
|
||||
selector: ".YtProgressBarLineHost, .YtChapteredProgressBarHost",
|
||||
isVisibleCheck: true
|
||||
}, {
|
||||
// For newer mobile YouTube (May 2024)
|
||||
@@ -646,7 +651,7 @@ async function startSponsorSchedule(includeIntersectingSegments = false, current
|
||||
|
||||
updateActiveSegment(currentTime);
|
||||
|
||||
if (getVideo().paused
|
||||
if ((getVideo().paused && getCurrentTime() !== 0) // Allow autoplay disabled videos to skip before playing
|
||||
|| (getCurrentTime() >= getVideoDuration() - 0.01 && getVideoDuration() > 1)) return;
|
||||
const skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments, includeNonIntersectingSegments);
|
||||
|
||||
@@ -874,6 +879,7 @@ let lastPlaybackSpeed = 1;
|
||||
let setupVideoListenersFirstTime = true;
|
||||
function setupVideoListeners() {
|
||||
const video = getVideo();
|
||||
if (!video) return; // Maybe video became invisible
|
||||
|
||||
//wait until it is loaded
|
||||
video.addEventListener('loadstart', videoOnReadyListener)
|
||||
@@ -891,6 +897,7 @@ function setupVideoListeners() {
|
||||
|
||||
let startedWaiting = false;
|
||||
let lastPausedAtZero = true;
|
||||
let lastVideoDataChange = 0;
|
||||
|
||||
const rateChangeListener = () => {
|
||||
updateVirtualTime();
|
||||
@@ -903,13 +910,10 @@ function setupVideoListeners() {
|
||||
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 (video.readyState <= HTMLMediaElement.HAVE_CURRENT_DATA
|
||||
&& video.currentTime === 0) return;
|
||||
// Prevent video resolution changes from causing skips
|
||||
if (!firstPlay && Date.now() - lastVideoDataChange < 200 && video.currentTime === 0) return;
|
||||
|
||||
|
||||
firstPlay = false;
|
||||
updateVirtualTime();
|
||||
checkForMiniplayerPlaying();
|
||||
|
||||
@@ -1041,6 +1045,24 @@ function setupVideoListeners() {
|
||||
};
|
||||
video.addEventListener('waiting', waitingListener);
|
||||
|
||||
// When video data is changed
|
||||
const emptyListener = () => {
|
||||
lastVideoDataChange = Date.now();
|
||||
|
||||
if (firstPlay && video.currentTime === 0) {
|
||||
playListener();
|
||||
}
|
||||
}
|
||||
video.addEventListener('emptied', emptyListener);
|
||||
|
||||
// For when autoplay is off to skip before starting playback
|
||||
const metadataLoadedListener = () => {
|
||||
if (firstPlay && getCurrentTime() === 0) {
|
||||
playListener();
|
||||
}
|
||||
}
|
||||
video.addEventListener('loadedmetadata', metadataLoadedListener)
|
||||
|
||||
startSponsorSchedule();
|
||||
|
||||
if (setupVideoListenersFirstTime) {
|
||||
@@ -1052,6 +1074,8 @@ function setupVideoListeners() {
|
||||
video.removeEventListener('videoSpeed_ratechange', rateChangeListener);
|
||||
video.removeEventListener('pause', pauseListener);
|
||||
video.removeEventListener('waiting', waitingListener);
|
||||
video.removeEventListener('empty', emptyListener);
|
||||
video.removeEventListener('loadedmetadata', metadataLoadedListener);
|
||||
|
||||
if (playbackRateCheckInterval) clearInterval(playbackRateCheckInterval);
|
||||
});
|
||||
@@ -1136,38 +1160,23 @@ function setupCategoryPill() {
|
||||
categoryPill.attachToPage(isOnMobileYouTube(), isOnInvidious(), voteAsync);
|
||||
}
|
||||
|
||||
async function sponsorsLookup(keepOldSubmissions = true) {
|
||||
const categories: string[] = Config.config.categorySelections.map((category) => category.name);
|
||||
|
||||
const extraRequestData: Record<string, unknown> = {};
|
||||
const hashParams = getHashParams();
|
||||
if (hashParams.requiredSegment) extraRequestData.requiredSegment = hashParams.requiredSegment;
|
||||
|
||||
const videoID = getVideoID()
|
||||
async function sponsorsLookup(keepOldSubmissions = true, ignoreCache = false) {
|
||||
const videoID = getVideoID();
|
||||
if (!videoID) {
|
||||
console.error("[SponsorBlock] Attempted to fetch segments with a null/undefined videoID.");
|
||||
return;
|
||||
}
|
||||
const hashPrefix = (await getHash(videoID, 1)).slice(0, 4) as VideoID & HashedValue;
|
||||
const response = await asyncRequestToServer('GET', "/api/skipSegments/" + hashPrefix, {
|
||||
categories,
|
||||
actionTypes: getEnabledActionTypes(),
|
||||
userAgent: `${chrome.runtime.id}`,
|
||||
...extraRequestData
|
||||
});
|
||||
|
||||
const segmentData = await getSegmentsForVideo(videoID, ignoreCache);
|
||||
|
||||
// Make sure an old pending request doesn't get used.
|
||||
if (videoID !== getVideoID()) return;
|
||||
|
||||
// store last response status
|
||||
lastResponseStatus = response?.status;
|
||||
lastResponseStatus = segmentData.status;
|
||||
if (segmentData.status === 200) {
|
||||
const receivedSegments = segmentData.segments;
|
||||
|
||||
if (response?.ok) {
|
||||
const receivedSegments: SponsorTime[] = JSON.parse(response.responseText)
|
||||
?.filter((video) => video.videoID === getVideoID())
|
||||
?.map((video) => video.segments)?.[0]
|
||||
?.map((segment) => ({
|
||||
...segment,
|
||||
source: SponsorSourceType.Server
|
||||
}))
|
||||
?.sort((a, b) => a.segment[0] - b.segment[0]);
|
||||
if (receivedSegments && receivedSegments.length) {
|
||||
sponsorDataFound = true;
|
||||
|
||||
@@ -1207,6 +1216,7 @@ async function sponsorsLookup(keepOldSubmissions = true) {
|
||||
}
|
||||
|
||||
// See if some segments should be hidden
|
||||
const hashPrefix = (await getHash(videoID, 1)).slice(0, 4) as VideoID & HashedValue;
|
||||
const downvotedData = Config.local.downvotedSegments[hashPrefix];
|
||||
if (downvotedData) {
|
||||
for (const segment of sponsorTimes) {
|
||||
@@ -1253,7 +1263,7 @@ async function sponsorsLookup(keepOldSubmissions = true) {
|
||||
}
|
||||
|
||||
function importExistingChapters(wait: boolean) {
|
||||
if (!existingChaptersImported && !importingChaptersWaiting && !triedImportingChapters && onVideoPage() && !isOnMobileYouTube()) {
|
||||
if (!existingChaptersImported && !importingChaptersWaiting && onVideoPage() && !isOnMobileYouTube()) {
|
||||
const waitCondition = () => getVideoDuration() && getExistingChapters(getVideoID(), getVideoDuration());
|
||||
|
||||
if (wait && !document.hasFocus() && !importingChaptersWaitingForFocus && !waitCondition()) {
|
||||
@@ -1274,23 +1284,11 @@ function importExistingChapters(wait: boolean) {
|
||||
existingChaptersImported = true;
|
||||
updatePreviewBar();
|
||||
}
|
||||
}).catch(() => { importingChaptersWaiting = false; triedImportingChapters = true; }); // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
}).catch(() => { importingChaptersWaiting = false; }); // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEnabledActionTypes(forceFullVideo = false): ActionType[] {
|
||||
const actionTypes = [ActionType.Skip, ActionType.Poi, ActionType.Chapter];
|
||||
if (Config.config.muteSegments) {
|
||||
actionTypes.push(ActionType.Mute);
|
||||
}
|
||||
if (Config.config.fullVideoSegments || forceFullVideo) {
|
||||
actionTypes.push(ActionType.Full);
|
||||
}
|
||||
|
||||
return actionTypes;
|
||||
}
|
||||
|
||||
async function lockedCategoriesLookup(): Promise<void> {
|
||||
const hashPrefix = (await getHash(getVideoID(), 1)).slice(0, 4);
|
||||
const response = await asyncRequestToServer("GET", "/api/lockCategories/" + hashPrefix);
|
||||
@@ -1750,7 +1748,7 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
|
||||
|
||||
if (autoSkip && Config.config.audioNotificationOnSkip
|
||||
&& !isSubmittingSegment && !getVideo()?.muted) {
|
||||
const beep = new Audio(chrome.runtime.getURL("icons/beep.ogg"));
|
||||
const beep = new Audio(chrome.runtime.getURL("icons/beep.oga"));
|
||||
beep.volume = getVideo().volume * 0.1;
|
||||
const oldMetadata = navigator.mediaSession.metadata
|
||||
beep.play();
|
||||
@@ -2031,7 +2029,7 @@ function startOrEndTimingNewSegment() {
|
||||
Config.forceLocalUpdate("unsubmittedSegments");
|
||||
|
||||
// Make sure they know if someone has already submitted something it while they were watching
|
||||
sponsorsLookup();
|
||||
sponsorsLookup(true, true);
|
||||
|
||||
updateEditButtonsOnPlayer();
|
||||
updateSponsorTimesSubmitting(false);
|
||||
@@ -2568,8 +2566,10 @@ function addHotkeyListener(): void {
|
||||
}
|
||||
|
||||
function hotkeyListener(e: KeyboardEvent): void {
|
||||
if (["textarea", "input"].includes(document.activeElement?.tagName?.toLowerCase())
|
||||
|| document.activeElement?.id?.toLowerCase()?.includes("editable")) return;
|
||||
if ((["textarea", "input"].includes(document.activeElement?.tagName?.toLowerCase())
|
||||
|| (document.activeElement as HTMLElement)?.isContentEditable
|
||||
|| document.activeElement?.id?.toLowerCase()?.match(/editable|input/))
|
||||
&& document.hasFocus()) return;
|
||||
|
||||
const key: Keybind = {
|
||||
key: e.key,
|
||||
@@ -2616,6 +2616,8 @@ function hotkeyListener(e: KeyboardEvent): void {
|
||||
submitSegments();
|
||||
return;
|
||||
} else if (keybindEquals(key, openSubmissionMenuKey)) {
|
||||
e.preventDefault();
|
||||
|
||||
openSubmissionMenu();
|
||||
return;
|
||||
} else if (keybindEquals(key, previewKey)) {
|
||||
@@ -2630,16 +2632,6 @@ function hotkeyListener(e: KeyboardEvent): void {
|
||||
previousChapter();
|
||||
return;
|
||||
}
|
||||
|
||||
//legacy - to preserve keybinds for skipKey, startSponsorKey and submitKey for people who set it before the update. (shouldn't be changed for future keybind options)
|
||||
if (key.key == skipKey?.key && skipKey.code == null && !keybindEquals(Config.syncDefaults.skipKeybind, skipKey)) {
|
||||
if (activeSkipKeybindElement)
|
||||
activeSkipKeybindElement.toggleSkip.call(activeSkipKeybindElement);
|
||||
} else if (key.key == startSponsorKey?.key && startSponsorKey.code == null && !keybindEquals(Config.syncDefaults.startSponsorKeybind, startSponsorKey)) {
|
||||
startOrEndTimingNewSegment();
|
||||
} else if (key.key == submitKey?.key && submitKey.code == null && !keybindEquals(Config.syncDefaults.submitKeybind, submitKey)) {
|
||||
openSubmissionMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2687,11 +2679,11 @@ function showTimeWithoutSkips(skippedDuration: number): void {
|
||||
}
|
||||
|
||||
// YouTube player time display
|
||||
const displayClass =
|
||||
isOnInvidious() ? "vjs-duration" :
|
||||
isOnMobileYouTube() ? "ytm-time-display" :
|
||||
"ytp-time-display.notranslate";
|
||||
const display = document.querySelector(`.${displayClass}`);
|
||||
const selector =
|
||||
isOnInvidious() ? ".vjs-duration" :
|
||||
isOnMobileYouTube() ? ".YtwPlayerTimeDisplayContent" :
|
||||
".ytp-time-display.notranslate .ytp-time-wrapper";
|
||||
const display = document.querySelector(selector);
|
||||
if (!display) return;
|
||||
|
||||
const durationID = "sponsorBlockDurationAfterSkips";
|
||||
@@ -2701,9 +2693,13 @@ function showTimeWithoutSkips(skippedDuration: number): void {
|
||||
if (duration === null) {
|
||||
duration = document.createElement('span');
|
||||
duration.id = durationID;
|
||||
if (!isOnInvidious()) duration.classList.add(displayClass);
|
||||
|
||||
display.appendChild(duration);
|
||||
if (isOnMobileYouTube()) {
|
||||
duration.style.paddingLeft = "4px";
|
||||
display.insertBefore(duration, display.lastChild);
|
||||
} else {
|
||||
display.appendChild(duration);
|
||||
}
|
||||
}
|
||||
|
||||
const durationAfterSkips = getFormattedTime(getVideoDuration() - skippedDuration);
|
||||
|
||||
Reference in New Issue
Block a user