aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/content.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/content.ts')
-rw-r--r--src/content.ts152
1 files changed, 74 insertions, 78 deletions
diff --git a/src/content.ts b/src/content.ts
index 88dfefcf..663edc8a 100644
--- a/src/content.ts
+++ b/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;
-
- 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]);
+ lastResponseStatus = segmentData.status;
+ if (segmentData.status === 200) {
+ const receivedSegments = segmentData.segments;
+
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);