Compare commits

...

13 Commits

Author SHA1 Message Date
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
16 changed files with 145 additions and 28 deletions

View File

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

View File

@@ -4,5 +4,13 @@
},
"optional_permissions": [
"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;
}
/* Vorapi compatibility */
#player-api_VORAPI_ELEMENT_ID #previewbar {
z-index: 999;
}
#previewbar {
overflow: visible;
padding: 0;
@@ -44,7 +49,16 @@
}
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 {
@@ -835,6 +849,15 @@ input::-webkit-inner-spin-button {
white-space: nowrap;
}
/* Vorapis V3 support */
#watch7-content .sponsorBlockCategoryPill {
padding-top: 5px;
padding-bottom: 5px;
}
#watch7-content .sponsorBlockCategoryPillTitle {
font-size: 15px;
}
.categoryPillClose {
display: none;
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

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

View File

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

View File

@@ -70,6 +70,7 @@ interface SBConfig {
showCategoryGuidelines: boolean;
showCategoryWithoutPermission: boolean;
showSegmentNameInChapterBar: boolean;
showAutogeneratedChapters: boolean;
useVirtualTime: boolean;
showSegmentFailedToFetchWarning: boolean;
allowScrollingToEdit: boolean;
@@ -328,6 +329,7 @@ const syncDefaults = {
showCategoryGuidelines: true,
showCategoryWithoutPermission: false,
showSegmentNameInChapterBar: true,
showAutogeneratedChapters: true,
useVirtualTime: true,
showSegmentFailedToFetchWarning: true,
allowScrollingToEdit: true,

View File

@@ -25,7 +25,7 @@ import SubmissionNotice from "./render/SubmissionNotice";
import { Message, MessageResponse, VoteResponse } from "./messageTypes";
import { SkipButtonControlBar } from "./js-components/skipButtonControlBar";
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 { AnimationUtils } from "../maze-utils/src/animationUtils";
import { GenericUtils } from "./utils/genericUtils";
@@ -43,7 +43,7 @@ import { generateUserID } from "../maze-utils/src/setup";
import { updateAll } from "../maze-utils/src/thumbnailManagement";
import { setupThumbnailListener } from "./utils/thumbnails";
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 { addCleanupListener } from "../maze-utils/src/cleanup";
import { hideDeArrowPromotion, tryShowingDeArrowPromotion } from "./dearrowPromotion";
@@ -519,7 +519,7 @@ function handleMobileControlsMutations(): void {
function getPreviewBarAttachElement(): HTMLElement | null {
const progressElementOptions = [{
// For newer mobile YouTube (Sept 2024)
selector: ".YtProgressBarLineHost, .YtChapteredProgressBarHost",
selector: ".ytChapteredProgressBarHost, .YtProgressBarLineHost, .YtChapteredProgressBarHost",
isVisibleCheck: true
}, {
// For newer mobile YouTube (May 2024)
@@ -552,6 +552,9 @@ function getPreviewBarAttachElement(): HTMLElement | null {
// For piped
selector: ".shaka-ad-markers",
isVisibleCheck: false
}, {
// For Vorapis v3
selector: ".ytp-progress-bar-container > .html5-progress-bar > .ytp-progress-list"
}
];
@@ -1284,7 +1287,13 @@ function importExistingChapters(wait: boolean) {
existingChaptersImported = true;
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
}
}
}
}
@@ -1766,11 +1775,13 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
if (!autoSkip
&& skippingSegments.length === 1
&& skippingSegments[0].actionType === ActionType.Poi) {
skipButtonControlBar.enable(skippingSegments[0]);
if (isOnMobileYouTube() || Config.config.skipKeybind == null) skipButtonControlBar.setShowKeybindHint(false);
activeSkipKeybindElement?.setShowKeybindHint(false);
activeSkipKeybindElement = skipButtonControlBar;
waitFor(() => skipButtonControlBar).then(() => {
skipButtonControlBar.enable(skippingSegments[0]);
if (isOnMobileYouTube() || Config.config.skipKeybind == null) skipButtonControlBar.setShowKeybindHint(false);
activeSkipKeybindElement?.setShowKeybindHint(false);
activeSkipKeybindElement = skipButtonControlBar;
})
} else {
if (openNotice) {
//send out the message saying that a sponsor message was skipped
@@ -2683,7 +2694,7 @@ function showTimeWithoutSkips(skippedDuration: number): void {
// YouTube player time display
const selector =
isOnInvidious() ? ".vjs-duration" :
isOnMobileYouTube() ? ".YtwPlayerTimeDisplayContent" :
isOnMobileYouTube() ? ".ytwPlayerTimeDisplayContent" :
".ytp-time-display.notranslate .ytp-time-wrapper";
const display = document.querySelector(selector);
if (!display) return;
@@ -2748,6 +2759,10 @@ function setCategoryColorCSSVariables() {
if (!styleContainer) {
styleContainer = document.createElement("style");
styleContainer.id = "sbCategoryColorStyle";
if (isVorapisInstalled()) {
// Vorapi deletes styles
styleContainer.className = 'stylus';
}
const head = (document.head || document.documentElement);
head.appendChild(styleContainer)

View File

@@ -13,7 +13,8 @@ import { DEFAULT_CATEGORY, shortCategoryName } from "../utils/categoryUtils";
import { normalizeChapterName } from "../utils/exporter";
import { findValidElement } from "../../maze-utils/src/dom";
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 MIN_CHAPTER_SIZE = 0.003;
@@ -100,13 +101,15 @@ class PreviewBar {
this.chapterTooltip.className = "ytp-tooltip-title sponsorCategoryTooltip";
// global chaper tooltip or duration tooltip
const tooltipTextWrapper = document.querySelector(".ytp-tooltip-text-wrapper") ?? document.querySelector("#progress-bar-container.ytk-player > #hover-time-info");
const originalTooltip = tooltipTextWrapper.querySelector(".ytp-tooltip-title:not(.sponsorCategoryTooltip)") as HTMLElement;
// YT, Vorapis, unknown
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;
// Grab the tooltip from the text wrapper as the tooltip doesn't have its classes on init
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;
tooltipTextWrapper.insertBefore(this.categoryTooltip, titleTooltip.nextSibling);
@@ -128,7 +131,7 @@ class PreviewBar {
seekBar.addEventListener("mousemove", (e: MouseEvent) => {
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);
// Find the segment at that location, using the shortest if multiple found
@@ -156,6 +159,11 @@ class PreviewBar {
this.setTooltipTitle(mainSegment, this.categoryTooltip);
this.setTooltipTitle(secondarySegment, this.chapterTooltip);
if (isVorapisInstalled()) {
const tooltipParent = tooltipTextWrapper.parentElement!;
tooltipParent.classList.add("with-text");
}
if (normalizeChapterName(originalTooltip.textContent) === normalizeChapterName(this.categoryTooltip.textContent)
|| normalizeChapterName(originalTooltip.textContent) === normalizeChapterName(this.chapterTooltip.textContent)) {
if (originalTooltip.style.display !== "none") originalTooltip.style.display = "none";
@@ -225,6 +233,20 @@ class PreviewBar {
this.segments = segments ?? [];
this.videoDuration = videoDuration ?? 0;
// 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();
// Sometimes video duration is inaccurate, pull from accessibility info
@@ -238,7 +260,8 @@ class PreviewBar {
}
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];
if (this.progressBar) {
@@ -342,11 +365,13 @@ class PreviewBar {
// Merge overlapping chapters
this.unfilteredChapterGroups = this.createChapterRenderGroups(segments);
}
if (segments.every((segments) => segments.source === SponsorSourceType.YouTube)
if ((segments.every((segments) => segments.source === SponsorSourceType.YouTube)
|| (!Config.config.renderSegmentsAsChapters
&& 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";
this.originalChapterBar.style.removeProperty("display");
return;
@@ -372,6 +397,15 @@ class PreviewBar {
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.customChaptersBar) this.customChaptersBar.style.display = "none";
this.originalChapterBar.style.removeProperty("display");
@@ -764,7 +798,8 @@ class PreviewBar {
updateChapterText(segments: SponsorTime[], submittingSegments: SponsorTime[], currentTime: number): SponsorTime[] {
if (!Config.config.showSegmentNameInChapterBar
|| 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();
if (chaptersContainer) {
chaptersContainer.querySelector(".sponsorChapterText")?.remove();
@@ -804,8 +839,14 @@ class PreviewBar {
return -1;
} else if (a.actionType !== ActionType.Chapter && b.actionType === ActionType.Chapter) {
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 {
return (b.segment[0] - a.segment[0]);
return (b.segment[0] - a.segment[0]) * 4;
}
})[0];
@@ -846,6 +887,18 @@ class PreviewBar {
} else {
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 {
chaptersContainer.querySelector(".sponsorChapterText")?.remove();
const chapterTitle = chaptersContainer.querySelector(".ytp-chapter-title-content") as HTMLDivElement;

View File

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

View File

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