Compare commits

...

33 Commits

Author SHA1 Message Date
Ajay
0f75953ad1 bump version 2025-01-17 04:35:52 -05:00
Ajay
0f4c1c50cb Add delay to fetch on hover to make it less easy to trigger 2025-01-17 04:33:56 -05:00
Ajay
9e4939e2e3 Fix options page layout issue 2025-01-14 15:08:01 -05:00
Ajay
4a217300a2 bump version 2025-01-12 20:03:33 -05:00
Ajay
f4822fa587 update translations 2025-01-12 20:03:21 -05:00
Ajay
e4d6fdbd97 New filler wiki page 2025-01-11 15:33:04 -05:00
Ajay
1bd72e4db1 filler is gone🦀, long live tangents 2025-01-11 15:24:23 -05:00
Ajay
307eadc2da Fix compilation error 2025-01-10 13:45:30 -05:00
Ajay
99014dd113 Handle when local storage gets reset
Might fix the age old issue where the entire extension randomly becomes corrupted
2025-01-10 03:42:36 -05:00
Ajay
89b7cb0230 Fix audio glitch when chapter boundary passes
Fixes #1596
2025-01-10 03:29:04 -05:00
Ajay
e3da6c8643 bump version 2024-12-25 23:36:48 -05:00
Ajay
136f5e7d61 Fix preview bar on mobile for videos without chapters 2024-12-25 23:36:33 -05:00
Ajay
16f24978ff Fix offset with chapters on hover preview 2024-12-24 15:20:16 -05:00
Ajay
091d67e6b3 bump version 2024-12-24 14:34:49 -05:00
Ajay
fcf9bdc68e Fix linting issues 2024-12-24 14:34:19 -05:00
Ajay
af73aabbae Fix errors 2024-12-24 14:33:28 -05:00
Ajay
778b433ad4 Remove unused auto refetch segments option 2024-12-24 14:31:17 -05:00
Ajay
dc9c08f1fa Fix chapter titles still showing on hover after they've been removed from the seek bar 2024-12-24 14:29:07 -05:00
Ajay
4efa8b464e Fix capitalization 2024-12-14 18:30:13 -05:00
Ajay
e7d0180e15 Change options page to sentence case 2024-12-14 16:36:02 -05:00
Ajay
0fa24dbae4 bump version 2024-12-13 03:10:54 -05:00
Ajay
975b876a74 Fix preview bar on mobile
Fixes #2172
2024-12-13 03:10:17 -05:00
Ajay
557e2ea2df Fix full size manual skip notices showing "unskip" button instead of "skip"
Fixes #2160
2024-12-11 00:50:55 -05:00
Ajay
11f576eb69 bump version 2024-12-10 00:00:39 -05:00
Ajay
2a9e036986 update translations 2024-12-10 00:00:30 -05:00
Ajay
15976777ed Add option to hide autogenerated chapters by YouTube 2024-12-08 20:02:32 -05:00
Ajay
9ad636fdad Make chapter similarity check more strict 2024-12-08 14:50:40 -05:00
Ajay
6bfc66740e Hide video uploader chapters if there is a sponsorblock chapter to replace it at almost the same time 2024-12-08 14:48:32 -05:00
Ajay
7e824df73d Add support for vorapis v3
Based on patch by @ten4dinosaur
2024-12-08 02:56:10 -05:00
Ajay
62c3bc1c7a Don't show server-side ad error if someone seeks the video before check occurred 2024-12-07 02:58:56 -05:00
Ajay Ramachandran
266508ca2d Merge pull request #2162 from strafe/master
Respect iOS/macOS accent color by using a monochrome toolbar icon for…
2024-11-29 00:02:50 -05:00
strafe
19ccb5e9e9 Respect iOS/macOS accent color by using a monochrome toolbar icon for Safari 2024-11-29 00:40:40 +00:00
Ajay
46b8c41db7 Wait for skip button control bar to be setup before using it 2024-11-28 10:20:42 -05:00
20 changed files with 195 additions and 86 deletions

View File

@@ -24,7 +24,7 @@
"intro": "https://wiki.sponsor.ajay.app/w/Intermission/Intro_Animation", "intro": "https://wiki.sponsor.ajay.app/w/Intermission/Intro_Animation",
"outro": "https://wiki.sponsor.ajay.app/w/Endcards/Credits", "outro": "https://wiki.sponsor.ajay.app/w/Endcards/Credits",
"preview": "https://wiki.sponsor.ajay.app/w/Preview/Recap", "preview": "https://wiki.sponsor.ajay.app/w/Preview/Recap",
"filler": "https://wiki.sponsor.ajay.app/w/Filler_Tangent", "filler": "https://wiki.sponsor.ajay.app/w/Tangents/Jokes",
"music_offtopic": "https://wiki.sponsor.ajay.app/w/Music:_Non-Music_Section", "music_offtopic": "https://wiki.sponsor.ajay.app/w/Music:_Non-Music_Section",
"poi_highlight": "https://wiki.sponsor.ajay.app/w/Highlight", "poi_highlight": "https://wiki.sponsor.ajay.app/w/Highlight",
"guidelines": "https://wiki.sponsor.ajay.app/w/Guidelines", "guidelines": "https://wiki.sponsor.ajay.app/w/Guidelines",

View File

@@ -1,7 +1,7 @@
{ {
"name": "__MSG_fullName__", "name": "__MSG_fullName__",
"short_name": "SponsorBlock", "short_name": "SponsorBlock",
"version": "5.10.1", "version": "5.11.1",
"default_locale": "en", "default_locale": "en",
"description": "__MSG_Description__", "description": "__MSG_Description__",
"homepage_url": "https://sponsor.ajay.app", "homepage_url": "https://sponsor.ajay.app",

View File

@@ -4,5 +4,13 @@
}, },
"optional_permissions": [ "optional_permissions": [
"webNavigation" "webNavigation"
] ],
"browser_action": {
"default_icon": {
"16": "icons/SafariIconSponsorBlocker16px.png",
"32": "icons/SafariIconSponsorBlocker32px.png",
"64": "icons/SafariIconSponsorBlocker64px.png",
"128": "icons/SafariIconSponsorBlocker128px.png"
}
}
} }

View File

@@ -11,6 +11,11 @@
display: none; display: none;
} }
/* Vorapi compatibility */
#player-api_VORAPI_ELEMENT_ID #previewbar {
z-index: 999;
}
#previewbar { #previewbar {
overflow: visible; overflow: visible;
padding: 0; padding: 0;
@@ -44,7 +49,16 @@
} }
div:hover > #previewbar.sbNotInvidious { div:hover > #previewbar.sbNotInvidious {
transform: scaleY(1) transform: scaleY(1);
}
/* Vorapis */
.v3 #previewbar.sbNotInvidious {
transform: scaleY(1);
}
.sponsorCategoryTooltipVisible.ytp-progress-tooltip {
width: 216px !important;
/* left: 264.308px !important; */
} }
.previewbar { .previewbar {
@@ -74,7 +88,7 @@ div:hover > #previewbar.sbNotInvidious {
display: none !important; display: none !important;
} }
.ytp-tooltip.sponsorCategoryTooltipVisible { .ytp-tooltip.sponsorCategoryTooltipVisible:not(.sponsorTooltipHasYTChapters) {
transform: translateY(-1em) !important; transform: translateY(-1em) !important;
} }
@@ -835,6 +849,15 @@ input::-webkit-inner-spin-button {
white-space: nowrap; white-space: nowrap;
} }
/* Vorapis V3 support */
#watch7-content .sponsorBlockCategoryPill {
padding-top: 5px;
padding-bottom: 5px;
}
#watch7-content .sponsorBlockCategoryPillTitle {
font-size: 15px;
}
.categoryPillClose { .categoryPillClose {
display: none; display: none;
height: 10px; height: 10px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -373,6 +373,7 @@ input[type='number'] {
display: inline-block; display: inline-block;
width: 40px; width: 40px;
height: 24px; height: 24px;
min-width: 40px;
} }
.switch input { .switch input {

View File

@@ -154,20 +154,6 @@
<div class="small-description">__MSG_whatForceChannelCheck__</div> <div class="small-description">__MSG_whatForceChannelCheck__</div>
</div> </div>
<div data-type="toggle" data-sync="refetchWhenNotFound">
<div class="switch-container">
<label class="switch">
<input id="refetchWhenNotFound" type="checkbox" checked>
<span class="slider round"></span>
</label>
<label class="switch-label" for="refetchWhenNotFound">
__MSG_enableRefetchWhenNotFound__
</label>
</div>
<div class="small-description">__MSG_whatRefetchWhenNotFound__</div>
</div>
<div data-type="toggle" data-sync="showCategoryWithoutPermission"> <div data-type="toggle" data-sync="showCategoryWithoutPermission">
<div class="switch-container"> <div class="switch-container">
<label class="switch"> <label class="switch">

View File

@@ -669,7 +669,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
const skipButtonStates = this.state.skipButtonStates; const skipButtonStates = this.state.skipButtonStates;
const skipButtonCallbacks = this.state.skipButtonCallbacks; const skipButtonCallbacks = this.state.skipButtonCallbacks;
if (buttonIndex === null) { if (buttonIndex === null) {
for (let i = 0; i < this.segments.length; i++) { for (let i = 0; i < skipButtonStates.length; i++) {
skipButtonStates[i] = skipButtonState; skipButtonStates[i] = skipButtonState;
skipButtonCallbacks[i] = this.reskip.bind(this); skipButtonCallbacks[i] = this.reskip.bind(this);
} }

View File

@@ -234,6 +234,10 @@ class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsPr
configKey: "showSegmentNameInChapterBar", configKey: "showSegmentNameInChapterBar",
label: chrome.i18n.getMessage("showSegmentNameInChapterBar"), label: chrome.i18n.getMessage("showSegmentNameInChapterBar"),
dontDisable: true dontDisable: true
}, {
configKey: "showAutogeneratedChapters",
label: chrome.i18n.getMessage("showAutogeneratedChapters"),
dontDisable: true
}]; }];
case "music_offtopic": case "music_offtopic":
return [{ return [{

View File

@@ -48,7 +48,6 @@ interface SBConfig {
audioNotificationOnSkip: boolean; audioNotificationOnSkip: boolean;
checkForUnlistedVideos: boolean; checkForUnlistedVideos: boolean;
testingServer: boolean; testingServer: boolean;
refetchWhenNotFound: boolean;
ytInfoPermissionGranted: boolean; ytInfoPermissionGranted: boolean;
allowExpirements: boolean; allowExpirements: boolean;
showDonationLink: boolean; showDonationLink: boolean;
@@ -70,6 +69,7 @@ interface SBConfig {
showCategoryGuidelines: boolean; showCategoryGuidelines: boolean;
showCategoryWithoutPermission: boolean; showCategoryWithoutPermission: boolean;
showSegmentNameInChapterBar: boolean; showSegmentNameInChapterBar: boolean;
showAutogeneratedChapters: boolean;
useVirtualTime: boolean; useVirtualTime: boolean;
showSegmentFailedToFetchWarning: boolean; showSegmentFailedToFetchWarning: boolean;
allowScrollingToEdit: boolean; allowScrollingToEdit: boolean;
@@ -311,7 +311,6 @@ const syncDefaults = {
audioNotificationOnSkip: false, audioNotificationOnSkip: false,
checkForUnlistedVideos: false, checkForUnlistedVideos: false,
testingServer: false, testingServer: false,
refetchWhenNotFound: true,
ytInfoPermissionGranted: false, ytInfoPermissionGranted: false,
allowExpirements: true, allowExpirements: true,
showDonationLink: true, showDonationLink: true,
@@ -328,6 +327,7 @@ const syncDefaults = {
showCategoryGuidelines: true, showCategoryGuidelines: true,
showCategoryWithoutPermission: false, showCategoryWithoutPermission: false,
showSegmentNameInChapterBar: true, showSegmentNameInChapterBar: true,
showAutogeneratedChapters: true,
useVirtualTime: true, useVirtualTime: true,
showSegmentFailedToFetchWarning: true, showSegmentFailedToFetchWarning: true,
allowScrollingToEdit: true, allowScrollingToEdit: true,

View File

@@ -25,7 +25,7 @@ import SubmissionNotice from "./render/SubmissionNotice";
import { Message, MessageResponse, VoteResponse } from "./messageTypes"; import { Message, MessageResponse, VoteResponse } from "./messageTypes";
import { SkipButtonControlBar } from "./js-components/skipButtonControlBar"; import { SkipButtonControlBar } from "./js-components/skipButtonControlBar";
import { getStartTimeFromUrl } from "./utils/urlParser"; import { getStartTimeFromUrl } from "./utils/urlParser";
import { getControls, getExistingChapters, getHashParams, isPlayingPlaylist, isVisible } from "./utils/pageUtils"; import { getControls, getExistingChapters, getHashParams, hasAutogeneratedChapters, isPlayingPlaylist, isVisible } from "./utils/pageUtils";
import { CategoryPill } from "./render/CategoryPill"; import { CategoryPill } from "./render/CategoryPill";
import { AnimationUtils } from "../maze-utils/src/animationUtils"; import { AnimationUtils } from "../maze-utils/src/animationUtils";
import { GenericUtils } from "./utils/genericUtils"; import { GenericUtils } from "./utils/genericUtils";
@@ -43,7 +43,7 @@ import { generateUserID } from "../maze-utils/src/setup";
import { updateAll } from "../maze-utils/src/thumbnailManagement"; import { updateAll } from "../maze-utils/src/thumbnailManagement";
import { setupThumbnailListener } from "./utils/thumbnails"; import { setupThumbnailListener } from "./utils/thumbnails";
import * as documentScript from "../dist/js/document.js"; import * as documentScript from "../dist/js/document.js";
import { runCompatibilityChecks } from "./utils/compatibility"; import { isVorapisInstalled, runCompatibilityChecks } from "./utils/compatibility";
import { cleanPage } from "./utils/pageCleaner"; import { cleanPage } from "./utils/pageCleaner";
import { addCleanupListener } from "../maze-utils/src/cleanup"; import { addCleanupListener } from "../maze-utils/src/cleanup";
import { hideDeArrowPromotion, tryShowingDeArrowPromotion } from "./dearrowPromotion"; import { hideDeArrowPromotion, tryShowingDeArrowPromotion } from "./dearrowPromotion";
@@ -80,7 +80,6 @@ let importingChaptersWaiting = false;
const skipNotices: SkipNotice[] = []; const skipNotices: SkipNotice[] = [];
let upcomingNotice: UpcomingNotice | null = null; let upcomingNotice: UpcomingNotice | null = null;
let activeSkipKeybindElement: ToggleSkippable = null; let activeSkipKeybindElement: ToggleSkippable = null;
let retryFetchTimeout: NodeJS.Timeout = null;
let shownSegmentFailedToFetchWarning = false; let shownSegmentFailedToFetchWarning = false;
let selectedSegment: SegmentUUID | null = null; let selectedSegment: SegmentUUID | null = null;
let previewedSegment = false; let previewedSegment = false;
@@ -173,7 +172,6 @@ let popupInitialised = false;
let submissionNotice: SubmissionNotice = null; let submissionNotice: SubmissionNotice = null;
let lastResponseStatus: number; let lastResponseStatus: number;
let retryCount = 0;
// Contains all of the functions and variables needed by the skip notice // Contains all of the functions and variables needed by the skip notice
const skipNoticeContentContainer: ContentContainer = () => ({ const skipNoticeContentContainer: ContentContainer = () => ({
@@ -391,7 +389,6 @@ if (!Config.configSyncListeners.includes(contentConfigUpdateListener)) {
function resetValues() { function resetValues() {
lastCheckTime = 0; lastCheckTime = 0;
lastCheckVideoTime = -1; lastCheckVideoTime = -1;
retryCount = 0;
previewedSegment = false; previewedSegment = false;
firstPlay = true; firstPlay = true;
@@ -519,7 +516,7 @@ function handleMobileControlsMutations(): void {
function getPreviewBarAttachElement(): HTMLElement | null { function getPreviewBarAttachElement(): HTMLElement | null {
const progressElementOptions = [{ const progressElementOptions = [{
// For newer mobile YouTube (Sept 2024) // For newer mobile YouTube (Sept 2024)
selector: ".YtProgressBarLineHost, .YtChapteredProgressBarHost", selector: ".ytChapteredProgressBarHost, .ytProgressBarLineHost, .YtProgressBarLineHost, .YtChapteredProgressBarHost",
isVisibleCheck: true isVisibleCheck: true
}, { }, {
// For newer mobile YouTube (May 2024) // For newer mobile YouTube (May 2024)
@@ -552,6 +549,9 @@ function getPreviewBarAttachElement(): HTMLElement | null {
// For piped // For piped
selector: ".shaka-ad-markers", selector: ".shaka-ad-markers",
isVisibleCheck: false isVisibleCheck: false
}, {
// For Vorapis v3
selector: ".ytp-progress-bar-container > .html5-progress-bar > .ytp-progress-list"
} }
]; ];
@@ -757,7 +757,8 @@ async function startSponsorSchedule(includeIntersectingSegments = false, current
skippingFunction(currentTime); skippingFunction(currentTime);
} else { } else {
let delayTime = timeUntilSponsor * 1000 * (1 / getVideo().playbackRate); let delayTime = timeUntilSponsor * 1000 * (1 / getVideo().playbackRate);
if (delayTime < (isFirefoxOrSafari() && !isSafari() ? 750 : 300)) { if (delayTime < (isFirefoxOrSafari() && !isSafari() ? 750 : 300)
&& shouldAutoSkip(skippingSegments[0])) {
let forceStartIntervalTime: number | null = null; let forceStartIntervalTime: number | null = null;
if (isFirefoxOrSafari() && !isSafari() && delayTime > 300) { if (isFirefoxOrSafari() && !isSafari() && delayTime > 300) {
forceStartIntervalTime = await waitForNextTimeChange(); forceStartIntervalTime = await waitForNextTimeChange();
@@ -1238,11 +1239,7 @@ async function sponsorsLookup(keepOldSubmissions = true, ignoreCache = false) {
if (!isNaN(getVideoDuration())) { if (!isNaN(getVideoDuration())) {
updatePreviewBar(); updatePreviewBar();
} }
} else {
retryFetch(404);
} }
} else {
retryFetch(lastResponseStatus);
} }
importExistingChapters(true); importExistingChapters(true);
@@ -1284,7 +1281,13 @@ function importExistingChapters(wait: boolean) {
existingChaptersImported = true; existingChaptersImported = true;
updatePreviewBar(); updatePreviewBar();
} }
}).catch(() => { importingChaptersWaiting = false; }); // eslint-disable-line @typescript-eslint/no-empty-function }).catch(() => { importingChaptersWaiting = false; });
if (!Config.config.showAutogeneratedChapters) {
waitFor(() => hasAutogeneratedChapters(), wait ? 15000 : 0, 400).then(() => {
updateActiveSegment(getCurrentTime());
}).catch(() => { }); // eslint-disable-line @typescript-eslint/no-empty-function
}
} }
} }
} }
@@ -1303,27 +1306,6 @@ async function lockedCategoriesLookup(): Promise<void> {
} }
} }
function retryFetch(errorCode: number): void {
sponsorDataFound = false;
if (!Config.config.refetchWhenNotFound) return;
if (retryFetchTimeout) clearTimeout(retryFetchTimeout);
if ((errorCode !== 404 && retryCount > 1) || (errorCode !== 404 && retryCount > 10)) {
// Too many errors (50x), give up
return;
}
retryCount++;
const delay = errorCode === 404 ? (30000 + Math.random() * 30000) : (2000 + Math.random() * 10000);
retryFetchTimeout = setTimeout(() => {
if (getVideoID() && sponsorTimes?.length === 0
|| sponsorTimes.every((segment) => segment.source !== SponsorSourceType.Server)) {
// sponsorsLookup();
}
}, delay);
}
/** /**
* Only should be used when it is okay to skip a sponsor when in the middle of it * Only should be used when it is okay to skip a sponsor when in the middle of it
* *
@@ -1766,11 +1748,13 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
if (!autoSkip if (!autoSkip
&& skippingSegments.length === 1 && skippingSegments.length === 1
&& skippingSegments[0].actionType === ActionType.Poi) { && skippingSegments[0].actionType === ActionType.Poi) {
skipButtonControlBar.enable(skippingSegments[0]); waitFor(() => skipButtonControlBar).then(() => {
if (isOnMobileYouTube() || Config.config.skipKeybind == null) skipButtonControlBar.setShowKeybindHint(false); skipButtonControlBar.enable(skippingSegments[0]);
if (isOnMobileYouTube() || Config.config.skipKeybind == null) skipButtonControlBar.setShowKeybindHint(false);
activeSkipKeybindElement?.setShowKeybindHint(false);
activeSkipKeybindElement = skipButtonControlBar; activeSkipKeybindElement?.setShowKeybindHint(false);
activeSkipKeybindElement = skipButtonControlBar;
})
} else { } else {
if (openNotice) { if (openNotice) {
//send out the message saying that a sponsor message was skipped //send out the message saying that a sponsor message was skipped
@@ -2683,7 +2667,7 @@ function showTimeWithoutSkips(skippedDuration: number): void {
// YouTube player time display // YouTube player time display
const selector = const selector =
isOnInvidious() ? ".vjs-duration" : isOnInvidious() ? ".vjs-duration" :
isOnMobileYouTube() ? ".YtwPlayerTimeDisplayContent" : isOnMobileYouTube() ? ".ytwPlayerTimeDisplayContent" :
".ytp-time-display.notranslate .ytp-time-wrapper"; ".ytp-time-display.notranslate .ytp-time-wrapper";
const display = document.querySelector(selector); const display = document.querySelector(selector);
if (!display) return; if (!display) return;
@@ -2748,6 +2732,10 @@ function setCategoryColorCSSVariables() {
if (!styleContainer) { if (!styleContainer) {
styleContainer = document.createElement("style"); styleContainer = document.createElement("style");
styleContainer.id = "sbCategoryColorStyle"; styleContainer.id = "sbCategoryColorStyle";
if (isVorapisInstalled()) {
// Vorapi deletes styles
styleContainer.className = 'stylus';
}
const head = (document.head || document.documentElement); const head = (document.head || document.documentElement);
head.appendChild(styleContainer) head.appendChild(styleContainer)

View File

@@ -13,7 +13,8 @@ import { DEFAULT_CATEGORY, shortCategoryName } from "../utils/categoryUtils";
import { normalizeChapterName } from "../utils/exporter"; import { normalizeChapterName } from "../utils/exporter";
import { findValidElement } from "../../maze-utils/src/dom"; import { findValidElement } from "../../maze-utils/src/dom";
import { addCleanupListener } from "../../maze-utils/src/cleanup"; import { addCleanupListener } from "../../maze-utils/src/cleanup";
import { isVisible } from "../utils/pageUtils"; import { hasAutogeneratedChapters, isVisible } from "../utils/pageUtils";
import { isVorapisInstalled } from "../utils/compatibility";
const TOOLTIP_VISIBLE_CLASS = 'sponsorCategoryTooltipVisible'; const TOOLTIP_VISIBLE_CLASS = 'sponsorCategoryTooltipVisible';
const MIN_CHAPTER_SIZE = 0.003; const MIN_CHAPTER_SIZE = 0.003;
@@ -51,6 +52,7 @@ class PreviewBar {
progressBar: HTMLElement; progressBar: HTMLElement;
segments: PreviewBarSegment[] = []; segments: PreviewBarSegment[] = [];
hasYouTubeChapters = false;
existingChapters: PreviewBarSegment[] = []; existingChapters: PreviewBarSegment[] = [];
videoDuration = 0; videoDuration = 0;
updateExistingChapters: () => void; updateExistingChapters: () => void;
@@ -100,13 +102,15 @@ class PreviewBar {
this.chapterTooltip.className = "ytp-tooltip-title sponsorCategoryTooltip"; this.chapterTooltip.className = "ytp-tooltip-title sponsorCategoryTooltip";
// global chaper tooltip or duration tooltip // global chaper tooltip or duration tooltip
const tooltipTextWrapper = document.querySelector(".ytp-tooltip-text-wrapper") ?? document.querySelector("#progress-bar-container.ytk-player > #hover-time-info"); // YT, Vorapis, unknown
const originalTooltip = tooltipTextWrapper.querySelector(".ytp-tooltip-title:not(.sponsorCategoryTooltip)") as HTMLElement; const tooltipTextWrapper = document.querySelector(".ytp-tooltip-text-wrapper, .ytp-progress-tooltip-text-container") ?? document.querySelector("#progress-bar-container.ytk-player > #hover-time-info");
const originalTooltip = tooltipTextWrapper.querySelector(".ytp-tooltip-title:not(.sponsorCategoryTooltip), .ytp-progress-tooltip-text:not(.sponsorCategoryTooltip)") as HTMLElement;
if (!tooltipTextWrapper || !tooltipTextWrapper.parentElement) return; if (!tooltipTextWrapper || !tooltipTextWrapper.parentElement) return;
// Grab the tooltip from the text wrapper as the tooltip doesn't have its classes on init // Grab the tooltip from the text wrapper as the tooltip doesn't have its classes on init
this.categoryTooltipContainer = tooltipTextWrapper.parentElement; this.categoryTooltipContainer = tooltipTextWrapper.parentElement;
const titleTooltip = tooltipTextWrapper.querySelector(".ytp-tooltip-title") as HTMLElement; // YT, Vorapis
const titleTooltip = tooltipTextWrapper.querySelector(".ytp-tooltip-title, .ytp-progress-tooltip-text") as HTMLElement;
if (!this.categoryTooltipContainer || !titleTooltip) return; if (!this.categoryTooltipContainer || !titleTooltip) return;
tooltipTextWrapper.insertBefore(this.categoryTooltip, titleTooltip.nextSibling); tooltipTextWrapper.insertBefore(this.categoryTooltip, titleTooltip.nextSibling);
@@ -128,12 +132,12 @@ class PreviewBar {
seekBar.addEventListener("mousemove", (e: MouseEvent) => { seekBar.addEventListener("mousemove", (e: MouseEvent) => {
if (!mouseOnSeekBar || !this.categoryTooltip || !this.categoryTooltipContainer || !chrome.runtime?.id) return; if (!mouseOnSeekBar || !this.categoryTooltip || !this.categoryTooltipContainer || !chrome.runtime?.id) return;
let noYoutubeChapters = !!tooltipTextWrapper.querySelector(".ytp-tooltip-text.ytp-tooltip-text-no-title"); let noYoutubeChapters = !!tooltipTextWrapper.querySelector(".ytp-tooltip-text.ytp-tooltip-text-no-title, .ytp-progress-tooltip-timestamp");
const timeInSeconds = this.decimalToTime((e.clientX - seekBar.getBoundingClientRect().x) / seekBar.clientWidth); const timeInSeconds = this.decimalToTime((e.clientX - seekBar.getBoundingClientRect().x) / seekBar.clientWidth);
// Find the segment at that location, using the shortest if multiple found // Find the segment at that location, using the shortest if multiple found
const [normalSegments, chapterSegments] = const [normalSegments, chapterSegments] =
partition(this.segments.filter((s) => s.source !== SponsorSourceType.YouTube), partition(this.segments,
(segment) => segment.actionType !== ActionType.Chapter); (segment) => segment.actionType !== ActionType.Chapter);
let mainSegment = this.getSmallestSegment(timeInSeconds, normalSegments, "normal"); let mainSegment = this.getSmallestSegment(timeInSeconds, normalSegments, "normal");
let secondarySegment = this.getSmallestSegment(timeInSeconds, chapterSegments, "chapter"); let secondarySegment = this.getSmallestSegment(timeInSeconds, chapterSegments, "chapter");
@@ -142,13 +146,28 @@ class PreviewBar {
secondarySegment = this.getSmallestSegment(timeInSeconds, chapterSegments.filter((s) => s !== secondarySegment)); secondarySegment = this.getSmallestSegment(timeInSeconds, chapterSegments.filter((s) => s !== secondarySegment));
} }
const hasAYouTubeChapterRemoved = this.hasYouTubeChapters
|| (!Config.config.showAutogeneratedChapters && hasAutogeneratedChapters());
if (hasAYouTubeChapterRemoved) {
// Hide original tooltip if some chapter has been filtered out
originalTooltip.style.display = "none";
noYoutubeChapters = true;
originalTooltip.classList.add("sponsorTooltipHasYTChapters");
} else {
originalTooltip.classList.remove("sponsorTooltipHasYTChapters");
}
if (mainSegment === null && secondarySegment === null) { if (mainSegment === null && secondarySegment === null) {
this.categoryTooltipContainer.classList.remove(TOOLTIP_VISIBLE_CLASS); if (!hasAYouTubeChapterRemoved) {
originalTooltip.style.removeProperty("display"); this.categoryTooltipContainer.classList.remove(TOOLTIP_VISIBLE_CLASS);
originalTooltip.style.removeProperty("display");
}
} else { } else {
this.categoryTooltipContainer.classList.add(TOOLTIP_VISIBLE_CLASS); this.categoryTooltipContainer.classList.add(TOOLTIP_VISIBLE_CLASS);
if (mainSegment !== null && secondarySegment !== null) { if (mainSegment !== null && secondarySegment !== null) {
this.categoryTooltipContainer.classList.add("sponsorTwoTooltips"); this.categoryTooltipContainer.classList.add("sponsorTwoTooltips");
originalTooltip.classList.remove("sponsorTooltipHasYTChapters");
} else { } else {
this.categoryTooltipContainer.classList.remove("sponsorTwoTooltips"); this.categoryTooltipContainer.classList.remove("sponsorTwoTooltips");
} }
@@ -156,6 +175,11 @@ class PreviewBar {
this.setTooltipTitle(mainSegment, this.categoryTooltip); this.setTooltipTitle(mainSegment, this.categoryTooltip);
this.setTooltipTitle(secondarySegment, this.chapterTooltip); this.setTooltipTitle(secondarySegment, this.chapterTooltip);
if (isVorapisInstalled()) {
const tooltipParent = tooltipTextWrapper.parentElement!;
tooltipParent.classList.add("with-text");
}
if (normalizeChapterName(originalTooltip.textContent) === normalizeChapterName(this.categoryTooltip.textContent) if (normalizeChapterName(originalTooltip.textContent) === normalizeChapterName(this.categoryTooltip.textContent)
|| normalizeChapterName(originalTooltip.textContent) === normalizeChapterName(this.chapterTooltip.textContent)) { || normalizeChapterName(originalTooltip.textContent) === normalizeChapterName(this.chapterTooltip.textContent)) {
if (originalTooltip.style.display !== "none") originalTooltip.style.display = "none"; if (originalTooltip.style.display !== "none") originalTooltip.style.display = "none";
@@ -164,16 +188,16 @@ class PreviewBar {
originalTooltip.style.removeProperty("display"); originalTooltip.style.removeProperty("display");
} }
// Used to prevent overlapping
this.categoryTooltip.classList.toggle("ytp-tooltip-text-no-title", noYoutubeChapters);
this.chapterTooltip.classList.toggle("ytp-tooltip-text-no-title", noYoutubeChapters);
// To prevent offset issue // To prevent offset issue
this.categoryTooltip.style.right = titleTooltip.style.right; this.categoryTooltip.style.right = titleTooltip.style.right;
this.chapterTooltip.style.right = titleTooltip.style.right; this.chapterTooltip.style.right = titleTooltip.style.right;
this.categoryTooltip.style.textAlign = titleTooltip.style.textAlign; this.categoryTooltip.style.textAlign = titleTooltip.style.textAlign;
this.chapterTooltip.style.textAlign = titleTooltip.style.textAlign; this.chapterTooltip.style.textAlign = titleTooltip.style.textAlign;
} }
// Used to prevent overlapping
this.categoryTooltip.classList.toggle("ytp-tooltip-text-no-title", noYoutubeChapters);
this.chapterTooltip.classList.toggle("ytp-tooltip-text-no-title", noYoutubeChapters);
}); });
} }
@@ -224,7 +248,22 @@ class PreviewBar {
set(segments: PreviewBarSegment[], videoDuration: number): void { set(segments: PreviewBarSegment[], videoDuration: number): void {
this.segments = segments ?? []; this.segments = segments ?? [];
this.videoDuration = videoDuration ?? 0; this.videoDuration = videoDuration ?? 0;
this.hasYouTubeChapters = segments.some((segment) => segment.source === SponsorSourceType.YouTube);
// Remove unnecessary original chapters if submitted replacements exist
for (const chapter of this.segments.filter((s) => s.actionType === ActionType.Chapter && s.source === SponsorSourceType.Server)) {
const segmentDuration = chapter.segment[1] - chapter.segment[0];
const duplicate = this.segments.find((s) => s.actionType === ActionType.Chapter
&& s.source === SponsorSourceType.YouTube
&& Math.abs(s.segment[0] - chapter.segment[0]) < Math.min(3, segmentDuration / 3)
&& Math.abs(s.segment[1] - chapter.segment[1]) < Math.min(3, segmentDuration / 3));
if (duplicate) {
const index = this.segments.indexOf(duplicate);
this.segments.splice(index, 1);
}
}
this.updatePageElements(); this.updatePageElements();
// Sometimes video duration is inaccurate, pull from accessibility info // Sometimes video duration is inaccurate, pull from accessibility info
@@ -238,7 +277,8 @@ class PreviewBar {
} }
private updatePageElements(): void { private updatePageElements(): void {
const allProgressBars = document.querySelectorAll(".ytp-progress-bar") as NodeListOf<HTMLElement>; // YT, Vorapis v3
const allProgressBars = document.querySelectorAll(".ytp-progress-bar, .ytp-progress-bar-container > .html5-progress-bar > .ytp-progress-list") as NodeListOf<HTMLElement>;
this.progressBar = findValidElement(allProgressBars) ?? allProgressBars?.[0]; this.progressBar = findValidElement(allProgressBars) ?? allProgressBars?.[0];
if (this.progressBar) { if (this.progressBar) {
@@ -342,11 +382,13 @@ class PreviewBar {
// Merge overlapping chapters // Merge overlapping chapters
this.unfilteredChapterGroups = this.createChapterRenderGroups(segments); this.unfilteredChapterGroups = this.createChapterRenderGroups(segments);
} }
if (segments.every((segments) => segments.source === SponsorSourceType.YouTube) if ((segments.every((segments) => segments.source === SponsorSourceType.YouTube)
|| (!Config.config.renderSegmentsAsChapters || (!Config.config.renderSegmentsAsChapters
&& segments.every((segment) => segment.actionType !== ActionType.Chapter && segments.every((segment) => segment.actionType !== ActionType.Chapter
|| segment.source === SponsorSourceType.YouTube))) { || segment.source === SponsorSourceType.YouTube)))
&& !(hasAutogeneratedChapters() && !Config.config.showAutogeneratedChapters)) {
if (this.customChaptersBar) this.customChaptersBar.style.display = "none"; if (this.customChaptersBar) this.customChaptersBar.style.display = "none";
this.originalChapterBar.style.removeProperty("display"); this.originalChapterBar.style.removeProperty("display");
return; return;
@@ -372,6 +414,15 @@ class PreviewBar {
this.chapterGroups = this.unfilteredChapterGroups; this.chapterGroups = this.unfilteredChapterGroups;
} }
if (this.chapterGroups.length === 0 && !Config.config.showAutogeneratedChapters && hasAutogeneratedChapters()) {
// Add placeholder chapter group for whole video
this.chapterGroups = [{
segment: [0, this.videoDuration],
originalDuration: 0,
actionType: null
}];
}
if (!this.chapterGroups || this.chapterGroups.length <= 0) { if (!this.chapterGroups || this.chapterGroups.length <= 0) {
if (this.customChaptersBar) this.customChaptersBar.style.display = "none"; if (this.customChaptersBar) this.customChaptersBar.style.display = "none";
this.originalChapterBar.style.removeProperty("display"); this.originalChapterBar.style.removeProperty("display");
@@ -764,7 +815,8 @@ class PreviewBar {
updateChapterText(segments: SponsorTime[], submittingSegments: SponsorTime[], currentTime: number): SponsorTime[] { updateChapterText(segments: SponsorTime[], submittingSegments: SponsorTime[], currentTime: number): SponsorTime[] {
if (!Config.config.showSegmentNameInChapterBar if (!Config.config.showSegmentNameInChapterBar
|| Config.config.disableSkipping || Config.config.disableSkipping
|| ((!segments || segments.length <= 0) && submittingSegments?.length <= 0)) { || ((!segments || segments.length <= 0) && submittingSegments?.length <= 0
&& (Config.config.showAutogeneratedChapters || !hasAutogeneratedChapters()))) {
const chaptersContainer = this.getChaptersContainer(); const chaptersContainer = this.getChaptersContainer();
if (chaptersContainer) { if (chaptersContainer) {
chaptersContainer.querySelector(".sponsorChapterText")?.remove(); chaptersContainer.querySelector(".sponsorChapterText")?.remove();
@@ -804,8 +856,14 @@ class PreviewBar {
return -1; return -1;
} else if (a.actionType !== ActionType.Chapter && b.actionType === ActionType.Chapter) { } else if (a.actionType !== ActionType.Chapter && b.actionType === ActionType.Chapter) {
return 1; return 1;
} else if (a.actionType === ActionType.Chapter && b.actionType === ActionType.Chapter
&& a.source === SponsorSourceType.Server && b.source !== SponsorSourceType.Server) {
return -0.5;
} else if (a.actionType === ActionType.Chapter && b.actionType === ActionType.Chapter
&& a.source !== SponsorSourceType.Server && b.source === SponsorSourceType.Server) {
return 0.5;
} else { } else {
return (b.segment[0] - a.segment[0]); return (b.segment[0] - a.segment[0]) * 4;
} }
})[0]; })[0];
@@ -846,6 +904,18 @@ class PreviewBar {
} else { } else {
this.chapterVote.setVisibility(false); this.chapterVote.setVisibility(false);
} }
} else if (!Config.config.showAutogeneratedChapters && hasAutogeneratedChapters()) {
// Keep original hidden
chaptersContainer.querySelector(".sponsorChapterText")?.remove();
const chapterTitle = chaptersContainer.querySelector(".ytp-chapter-title-content") as HTMLDivElement;
chapterTitle.style.display = "none";
chaptersContainer.classList.remove("sponsorblock-chapter-visible");
const titlePrefixDot = chaptersContainer.querySelector(".ytp-chapter-title-prefix") as HTMLElement;
if (titlePrefixDot) titlePrefixDot.style.display = "none";
this.chapterVote.setVisibility(false);
} else { } else {
chaptersContainer.querySelector(".sponsorChapterText")?.remove(); chaptersContainer.querySelector(".sponsorChapterText")?.remove();
const chapterTitle = chaptersContainer.querySelector(".ytp-chapter-title-content") as HTMLDivElement; const chapterTitle = chaptersContainer.querySelector(".ytp-chapter-title-content") as HTMLDivElement;

View File

@@ -12,4 +12,8 @@ export function runCompatibilityChecks() {
Config.config.showZoomToFillError2 = false; Config.config.showZoomToFillError2 = false;
}, 10000); }, 10000);
} }
}
export function isVorapisInstalled() {
return document.querySelector(`.v3`);
} }

View File

@@ -1,5 +1,6 @@
import { ActionType, Category, SponsorSourceType, SponsorTime, VideoID } from "../types"; import { ActionType, Category, SponsorSourceType, SponsorTime, VideoID } from "../types";
import { getFormattedTimeToSeconds } from "../../maze-utils/src/formating"; import { getFormattedTimeToSeconds } from "../../maze-utils/src/formating";
import Config from "../config";
export function getControls(): HTMLElement { export function getControls(): HTMLElement {
const controlsSelectors = [ const controlsSelectors = [
@@ -10,7 +11,9 @@ export function getControls(): HTMLElement {
// Invidious/videojs video element's controls element // Invidious/videojs video element's controls element
".vjs-control-bar", ".vjs-control-bar",
// Piped shaka player // Piped shaka player
".shaka-bottom-controls" ".shaka-bottom-controls",
// Vorapis v3
".html5-player-chrome"
]; ];
for (const controlsSelector of controlsSelectors) { for (const controlsSelector of controlsSelectors) {
@@ -53,10 +56,15 @@ export function getHashParams(): Record<string, unknown> {
return {}; return {};
} }
export function hasAutogeneratedChapters(): boolean {
return !!document.querySelector("ytd-engagement-panel-section-list-renderer ytd-macro-markers-list-renderer #menu");
}
export function getExistingChapters(currentVideoID: VideoID, duration: number): SponsorTime[] { export function getExistingChapters(currentVideoID: VideoID, duration: number): SponsorTime[] {
const chaptersBox = document.querySelector("ytd-macro-markers-list-renderer"); const chaptersBox = document.querySelector("ytd-macro-markers-list-renderer");
const title = chaptersBox?.closest("ytd-engagement-panel-section-list-renderer")?.querySelector("#title-text.ytd-engagement-panel-title-header-renderer"); const title = chaptersBox?.closest("ytd-engagement-panel-section-list-renderer")?.querySelector("#title-text.ytd-engagement-panel-title-header-renderer");
if (title?.textContent?.includes("Key moment")) return []; if (title?.textContent?.includes("Key moment")) return [];
if (!Config.config.showAutogeneratedChapters && hasAutogeneratedChapters()) return [];
const chapters: SponsorTime[] = []; const chapters: SponsorTime[] = [];
// .ytp-timed-markers-container indicates that key-moments are present, which should not be divided // .ytp-timed-markers-container indicates that key-moments are present, which should not be divided

View File

@@ -58,10 +58,27 @@ function thumbnailHoverListener(e: MouseEvent) {
if (!thumbnail) return; if (!thumbnail) return;
// Pre-fetch data for this video // Pre-fetch data for this video
const videoID = extractVideoID(thumbnail); let fetched = false;
if (videoID) { const preFetch = () => {
void getSegmentsForVideo(videoID, false); fetched = true;
} const videoID = extractVideoID(thumbnail);
if (videoID) {
void getSegmentsForVideo(videoID, false);
}
};
const timeout = setTimeout(preFetch, 200);
const onMouseDown = () => {
clearTimeout(timeout);
if (!fetched) {
preFetch();
}
};
e.target.addEventListener("mousedown", onMouseDown, { once: true });
e.target.addEventListener("mouseleave", () => {
clearTimeout(timeout);
e.target.removeEventListener("mousedown", onMouseDown);
}, { once: true });
} }
function getLink(thumbnail: HTMLImageElement): HTMLAnchorElement | null { function getLink(thumbnail: HTMLImageElement): HTMLAnchorElement | null {