mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2026-03-17 00:31:40 +03:00
Added skip button in control bar instead of using skip notice
This commit is contained in:
@@ -4,6 +4,7 @@ import Config from "../config"
|
||||
import { Category, CategorySkipOption } from "../types";
|
||||
|
||||
import Utils from "../utils";
|
||||
import { getCategoryActionType } from "../utils/categoryUtils";
|
||||
const utils = new Utils();
|
||||
|
||||
export interface CategorySkipOptionsProps {
|
||||
@@ -152,12 +153,12 @@ class CategorySkipOptionsComponent extends React.Component<CategorySkipOptionsPr
|
||||
|
||||
const optionNames = ["disable", "showOverlay", "manualSkip", "autoSkip"];
|
||||
|
||||
console.log(utils.getCategoryActionType(this.props.category))
|
||||
console.log(getCategoryActionType(this.props.category))
|
||||
|
||||
for (const optionName of optionNames) {
|
||||
elements.push(
|
||||
<option key={optionName} value={optionName}>
|
||||
{chrome.i18n.getMessage(optionName !== "disable" ? optionName + utils.getCategoryActionType(this.props.category)
|
||||
{chrome.i18n.getMessage(optionName !== "disable" ? optionName + getCategoryActionType(this.props.category)
|
||||
: optionName)}
|
||||
</option>
|
||||
);
|
||||
|
||||
@@ -5,8 +5,7 @@ import { Category, ContentContainer, CategoryActionType, SponsorHideType, Sponso
|
||||
import NoticeComponent from "./NoticeComponent";
|
||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||
|
||||
import Utils from "../utils";
|
||||
const utils = new Utils();
|
||||
import { getCategoryActionType, getSkippingText } from "../utils/categoryUtils";
|
||||
|
||||
export enum SkipNoticeAction {
|
||||
None,
|
||||
@@ -82,18 +81,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
this.contentContainer = props.contentContainer;
|
||||
this.audio = null;
|
||||
|
||||
const categoryName = chrome.i18n.getMessage(this.segments.length > 1 ? "multipleSegments"
|
||||
: "category_" + this.segments[0].category + "_short") || chrome.i18n.getMessage("category_" + this.segments[0].category);
|
||||
let noticeTitle = "";
|
||||
if (this.autoSkip) {
|
||||
const messageId = utils.getCategoryActionType(this.segments[0].category) === CategoryActionType.Skippable
|
||||
? "skipped" : "skipped_to_category";
|
||||
noticeTitle = chrome.i18n.getMessage(messageId).replace("{0}", categoryName);
|
||||
} else {
|
||||
const messageId = utils.getCategoryActionType(this.segments[0].category) === CategoryActionType.Skippable
|
||||
? "skip_category" : "skip_to_category";
|
||||
noticeTitle = chrome.i18n.getMessage(messageId).replace("{0}", categoryName);
|
||||
}
|
||||
const noticeTitle = getSkippingText(this.segments, this.props.autoSkip);
|
||||
|
||||
const previousSkipNotices = document.getElementsByClassName("sponsorSkipNoticeParent");
|
||||
this.amountOfPreviousNotices = previousSkipNotices.length;
|
||||
@@ -308,7 +296,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
|
||||
getSkipButton(): JSX.Element {
|
||||
if (this.segments.length > 1
|
||||
|| utils.getCategoryActionType(this.segments[0].category) !== CategoryActionType.POI
|
||||
|| getCategoryActionType(this.segments[0].category) !== CategoryActionType.POI
|
||||
|| this.props.unskipTime) {
|
||||
return (
|
||||
<span className="sponsorSkipNoticeUnskipSection">
|
||||
@@ -451,7 +439,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
getCategoryOptions(): React.ReactElement[] {
|
||||
const elements = [];
|
||||
|
||||
const categories = CompileConfig.categoryList.filter((cat => utils.getCategoryActionType(cat as Category) === CategoryActionType.Skippable));
|
||||
const categories = CompileConfig.categoryList.filter((cat => getCategoryActionType(cat as Category) === CategoryActionType.Skippable));
|
||||
for (const category of categories) {
|
||||
elements.push(
|
||||
<option value={category}
|
||||
@@ -479,7 +467,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
}
|
||||
|
||||
getUnskippedModeInfo(index: number, buttonText: string): SkipNoticeState {
|
||||
const changeCountdown = utils.getCategoryActionType(this.segments[index].category) === CategoryActionType.Skippable;
|
||||
const changeCountdown = getCategoryActionType(this.segments[index].category) === CategoryActionType.Skippable;
|
||||
|
||||
const maxCountdownTime = changeCountdown ? () => {
|
||||
const sponsorTime = this.segments[index];
|
||||
|
||||
@@ -6,6 +6,7 @@ import * as CompileConfig from "../../config.json";
|
||||
import Utils from "../utils";
|
||||
import { Category, CategoryActionType, ContentContainer, SponsorTime } from "../types";
|
||||
import SubmissionNoticeComponent from "./SubmissionNoticeComponent";
|
||||
import { getCategoryActionType } from "../utils/categoryUtils";
|
||||
const utils = new Utils();
|
||||
|
||||
export interface SponsorTimeEditProps {
|
||||
@@ -107,14 +108,14 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
onChange={(e) => {
|
||||
const sponsorTimeEdits = this.state.sponsorTimeEdits;
|
||||
sponsorTimeEdits[0] = e.target.value;
|
||||
if (utils.getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTimeEdits[1] = e.target.value;
|
||||
if (getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTimeEdits[1] = e.target.value;
|
||||
|
||||
this.setState({sponsorTimeEdits});
|
||||
this.saveEditTimes();
|
||||
}}>
|
||||
</input>
|
||||
|
||||
{utils.getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable ? (
|
||||
{getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable ? (
|
||||
<span>
|
||||
<span>
|
||||
{" " + chrome.i18n.getMessage("to") + " "}
|
||||
@@ -156,7 +157,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
className="sponsorTimeDisplay"
|
||||
onClick={this.toggleEditTime.bind(this)}>
|
||||
{utils.getFormattedTime(segment[0], true) +
|
||||
((!isNaN(segment[1]) && utils.getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable)
|
||||
((!isNaN(segment[1]) && getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable)
|
||||
? " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(segment[1], true) : "")}
|
||||
</div>
|
||||
);
|
||||
@@ -197,7 +198,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
{chrome.i18n.getMessage("delete")}
|
||||
</span>
|
||||
|
||||
{(!isNaN(segment[1]) && utils.getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable) ? (
|
||||
{(!isNaN(segment[1]) && getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable) ? (
|
||||
<span id={"sponsorTimePreviewButton" + this.idSuffix}
|
||||
className="sponsorTimeEditButton"
|
||||
onClick={this.previewTime.bind(this)}>
|
||||
@@ -260,7 +261,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils.getCategoryActionType(event.target.value as Category) === CategoryActionType.POI) {
|
||||
if (getCategoryActionType(event.target.value as Category) === CategoryActionType.POI) {
|
||||
this.setTimeTo(1, null);
|
||||
this.props.contentContainer().updateEditButtonsOnPlayer();
|
||||
}
|
||||
@@ -285,7 +286,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
if (time === null) time = sponsorTime.segment[0];
|
||||
|
||||
sponsorTime.segment[index] = time;
|
||||
if (utils.getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTime.segment[1] = time;
|
||||
if (getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTime.segment[1] = time;
|
||||
|
||||
this.setState({
|
||||
sponsorTimeEdits: this.getFormattedSponsorTimesEdits(sponsorTime)
|
||||
|
||||
@@ -13,6 +13,8 @@ import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||
import SubmissionNotice from "./render/SubmissionNotice";
|
||||
import { Message, MessageResponse } from "./messageTypes";
|
||||
import * as Chat from "./js-components/chat";
|
||||
import { getCategoryActionType } from "./utils/categoryUtils";
|
||||
import { SkipButtonControlBar } from "./js-components/skipButtonControlBar";
|
||||
|
||||
// Hack to get the CSS loaded on permission-based sites (Invidious)
|
||||
utils.wait(() => Config.config !== null, 5000, 10).then(addCSS);
|
||||
@@ -68,6 +70,7 @@ let channelWhitelisted = false;
|
||||
|
||||
// create preview bar
|
||||
let previewBar: PreviewBar = null;
|
||||
let skipButtonControlBar: SkipButtonControlBar = null;
|
||||
|
||||
/** Element containing the player controls on the YouTube player. */
|
||||
let controls: HTMLElement | null = null;
|
||||
@@ -515,6 +518,7 @@ function refreshVideoAttachments() {
|
||||
videosWithEventListeners.push(video);
|
||||
|
||||
setupVideoListeners();
|
||||
setupSkipButtonControlBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -569,7 +573,7 @@ function setupVideoListeners() {
|
||||
|
||||
if (!Config.config.dontShowNotice) {
|
||||
const currentPoiSegment = sponsorTimes.find((segment) =>
|
||||
utils.getCategoryActionType(segment.category) === CategoryActionType.POI &&
|
||||
getCategoryActionType(segment.category) === CategoryActionType.POI &&
|
||||
video.currentTime - segment.segment[0] > 0 &&
|
||||
video.currentTime - segment.segment[0] < video.duration * 0.006); // Approximate size on preview bar
|
||||
if (currentPoiSegment && !skipNotices.some((notice) => notice.segments.some((s) => s.UUID === currentPoiSegment.UUID))) {
|
||||
@@ -598,6 +602,22 @@ function setupVideoListeners() {
|
||||
}
|
||||
}
|
||||
|
||||
function setupSkipButtonControlBar() {
|
||||
if (!skipButtonControlBar) {
|
||||
skipButtonControlBar = new SkipButtonControlBar({
|
||||
skip: (segment) => skipToTime({
|
||||
v: video,
|
||||
skipTime: segment.segment,
|
||||
skippingSegments: [segment],
|
||||
openNotice: true,
|
||||
forceAutoSkip: true
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
skipButtonControlBar.attachToPage();
|
||||
}
|
||||
|
||||
async function sponsorsLookup(id: string, keepOldSubmissions = true) {
|
||||
if (!video) refreshVideoAttachments();
|
||||
//there is still no video here
|
||||
@@ -731,7 +751,7 @@ function startSkipScheduleCheckingForStartSponsors() {
|
||||
let startingSegment: SponsorTime = null;
|
||||
for (const time of sponsorTimes) {
|
||||
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSegmentTime && time.segment[1] > video.currentTime
|
||||
&& utils.getCategoryActionType(time.category) === CategoryActionType.Skippable) {
|
||||
&& getCategoryActionType(time.category) === CategoryActionType.Skippable) {
|
||||
startingSegmentTime = time.segment[0];
|
||||
startingSegment = time;
|
||||
break;
|
||||
@@ -740,7 +760,7 @@ function startSkipScheduleCheckingForStartSponsors() {
|
||||
if (startingSegmentTime === -1) {
|
||||
for (const time of sponsorTimesSubmitting) {
|
||||
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSegmentTime && time.segment[1] > video.currentTime
|
||||
&& utils.getCategoryActionType(time.category) === CategoryActionType.Skippable) {
|
||||
&& getCategoryActionType(time.category) === CategoryActionType.Skippable) {
|
||||
startingSegmentTime = time.segment[0];
|
||||
startingSegment = time;
|
||||
break;
|
||||
@@ -750,7 +770,7 @@ function startSkipScheduleCheckingForStartSponsors() {
|
||||
|
||||
// For highlight category
|
||||
const poiSegments = sponsorTimes
|
||||
.filter((time) => time.segment[1] > video.currentTime && utils.getCategoryActionType(time.category) === CategoryActionType.POI)
|
||||
.filter((time) => time.segment[1] > video.currentTime && getCategoryActionType(time.category) === CategoryActionType.POI)
|
||||
.sort((a, b) => b.segment[0] - a.segment[0]);
|
||||
for (const time of poiSegments) {
|
||||
const skipOption = utils.getCategorySelection(time.category)?.option;
|
||||
@@ -862,7 +882,7 @@ function updatePreviewBar(): void {
|
||||
segment: segment.segment as [number, number],
|
||||
category: segment.category,
|
||||
unsubmitted: false,
|
||||
showLarger: utils.getCategoryActionType(segment.category) === CategoryActionType.POI
|
||||
showLarger: getCategoryActionType(segment.category) === CategoryActionType.POI
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -872,7 +892,7 @@ function updatePreviewBar(): void {
|
||||
segment: segment.segment as [number, number],
|
||||
category: segment.category,
|
||||
unsubmitted: true,
|
||||
showLarger: utils.getCategoryActionType(segment.category) === CategoryActionType.POI
|
||||
showLarger: getCategoryActionType(segment.category) === CategoryActionType.POI
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1022,7 +1042,7 @@ function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments:
|
||||
|| (includeIntersectingSegments && sponsorTimes[i].segment[0] < minimum && sponsorTimes[i].segment[1] > minimum)))
|
||||
&& (!onlySkippableSponsors || utils.getCategorySelection(sponsorTimes[i].category).option !== CategorySkipOption.ShowOverlay)
|
||||
&& (!hideHiddenSponsors || sponsorTimes[i].hidden === SponsorHideType.Visible)
|
||||
&& utils.getCategoryActionType(sponsorTimes[i].category) === CategoryActionType.Skippable) {
|
||||
&& getCategoryActionType(sponsorTimes[i].category) === CategoryActionType.Skippable) {
|
||||
|
||||
startTimes.push(sponsorTimes[i].segment[0]);
|
||||
}
|
||||
@@ -1080,11 +1100,17 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
|
||||
}
|
||||
}
|
||||
|
||||
if (openNotice) {
|
||||
//send out the message saying that a sponsor message was skipped
|
||||
if (!Config.config.dontShowNotice || !autoSkip) {
|
||||
skipNotices.forEach((notice) => notice.setShowKeybindHint(false));
|
||||
skipNotices.push(new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer, unskipTime));
|
||||
if (!autoSkip
|
||||
&& skippingSegments.length === 1
|
||||
&& getCategoryActionType(skippingSegments[0].category) === CategoryActionType.POI) {
|
||||
skipButtonControlBar.enable(skippingSegments[0]);
|
||||
} else {
|
||||
if (openNotice) {
|
||||
//send out the message saying that a sponsor message was skipped
|
||||
if (!Config.config.dontShowNotice || !autoSkip) {
|
||||
skipNotices.forEach((notice) => notice.setShowKeybindHint(false));
|
||||
skipNotices.push(new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer, unskipTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
70
src/js-components/skipButtonControlBar.ts
Normal file
70
src/js-components/skipButtonControlBar.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import Config from "../config";
|
||||
import { SponsorTime } from "../types";
|
||||
import { getSkippingText } from "../utils/categoryUtils";
|
||||
|
||||
|
||||
export interface SkipButtonControlBarProps {
|
||||
skip: (segment: SponsorTime) => void;
|
||||
}
|
||||
|
||||
export class SkipButtonControlBar {
|
||||
|
||||
container: HTMLElement;
|
||||
skipIcon: HTMLImageElement;
|
||||
textContainer: HTMLElement;
|
||||
chapterText: HTMLElement;
|
||||
segment: SponsorTime;
|
||||
|
||||
timeout: NodeJS.Timeout;
|
||||
|
||||
skip: (segment: SponsorTime) => void;
|
||||
|
||||
constructor(props: SkipButtonControlBarProps) {
|
||||
this.skip = props.skip;
|
||||
|
||||
this.container = document.createElement("div");
|
||||
this.container.classList.add("skipButtonControlBarContainer");
|
||||
this.container.classList.add("hidden");
|
||||
|
||||
this.skipIcon = document.createElement("img");
|
||||
this.skipIcon.src = chrome.runtime.getURL("icons/skipIcon.svg");
|
||||
this.skipIcon.classList.add("ytp-button");
|
||||
this.skipIcon.id = "sbSkipIconControlBarImage";
|
||||
|
||||
this.textContainer = document.createElement("div");
|
||||
|
||||
this.container.appendChild(this.skipIcon);
|
||||
this.container.appendChild(this.textContainer);
|
||||
this.container.addEventListener("click", () => this.onClick());
|
||||
}
|
||||
|
||||
attachToPage(): void {
|
||||
const leftControlsContainer = document.querySelector(".ytp-left-controls");
|
||||
this.chapterText = document.querySelector(".ytp-chapter-container");
|
||||
|
||||
if (!leftControlsContainer.contains(this.container)) {
|
||||
leftControlsContainer.insertBefore(this.container, this.chapterText);
|
||||
}
|
||||
}
|
||||
|
||||
enable(segment: SponsorTime): void {
|
||||
this.segment = segment;
|
||||
this.chapterText?.classList?.add("hidden");
|
||||
this.container.classList.remove("hidden");
|
||||
this.textContainer.innerText = getSkippingText([segment], false);
|
||||
|
||||
if (this.timeout) clearTimeout(this.timeout);
|
||||
this.timeout = setTimeout(() => this.disable(), Config.config.skipNoticeDuration * 1000);
|
||||
}
|
||||
|
||||
disable(): void {
|
||||
this.container.classList.add("hidden");
|
||||
this.chapterText?.classList?.remove("hidden");
|
||||
}
|
||||
|
||||
onClick(): void {
|
||||
this.skip(this.segment);
|
||||
this.disable();
|
||||
}
|
||||
}
|
||||
|
||||
12
src/utils.ts
12
src/utils.ts
@@ -1,5 +1,5 @@
|
||||
import Config from "./config";
|
||||
import { CategorySelection, SponsorTime, FetchResponse, BackgroundScriptContainer, Registration, Category, CategoryActionType } from "./types";
|
||||
import { CategorySelection, SponsorTime, FetchResponse, BackgroundScriptContainer, Registration } from "./types";
|
||||
|
||||
import * as CompileConfig from "../config.json";
|
||||
|
||||
@@ -43,14 +43,6 @@ export default class Utils {
|
||||
});
|
||||
}
|
||||
|
||||
getCategoryActionType(category: Category): CategoryActionType {
|
||||
if (category.startsWith("poi_")) {
|
||||
return CategoryActionType.POI;
|
||||
} else {
|
||||
return CategoryActionType.Skippable;
|
||||
}
|
||||
}
|
||||
|
||||
containsPermission(permissions: chrome.permissions.Permissions): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
chrome.permissions.contains(permissions, resolve)
|
||||
@@ -364,7 +356,7 @@ export default class Utils {
|
||||
}, (response) => {
|
||||
resolve(response);
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
23
src/utils/categoryUtils.ts
Normal file
23
src/utils/categoryUtils.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Category, CategoryActionType, SponsorTime } from "../types";
|
||||
|
||||
export function getSkippingText(segments: SponsorTime[], autoSkip: boolean): string {
|
||||
const categoryName = chrome.i18n.getMessage(segments.length > 1 ? "multipleSegments"
|
||||
: "category_" + segments[0].category + "_short") || chrome.i18n.getMessage("category_" + segments[0].category);
|
||||
if (autoSkip) {
|
||||
const messageId = getCategoryActionType(segments[0].category) === CategoryActionType.Skippable
|
||||
? "skipped" : "skipped_to_category";
|
||||
return chrome.i18n.getMessage(messageId).replace("{0}", categoryName);
|
||||
} else {
|
||||
const messageId = getCategoryActionType(segments[0].category) === CategoryActionType.Skippable
|
||||
? "skip_category" : "skip_to_category";
|
||||
return chrome.i18n.getMessage(messageId).replace("{0}", categoryName);
|
||||
}
|
||||
}
|
||||
|
||||
export function getCategoryActionType(category: Category): CategoryActionType {
|
||||
if (category.startsWith("poi_")) {
|
||||
return CategoryActionType.POI;
|
||||
} else {
|
||||
return CategoryActionType.Skippable;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user