mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-10 05:27:03 +03:00
@@ -232,6 +232,9 @@
|
||||
"message": "If you still don't like it, hit the never show button.",
|
||||
"description": "The second line of the message displayed after the notice was upgraded."
|
||||
},
|
||||
"setSkipShortcut": {
|
||||
"message": "Set key for skipping a segment"
|
||||
},
|
||||
"setStartSponsorShortcut": {
|
||||
"message": "Set key for start segment keybind"
|
||||
},
|
||||
|
||||
@@ -84,6 +84,27 @@
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="keybind-change" sync-option="skipKeybind">
|
||||
<div class="option-button trigger-button">
|
||||
__MSG_setSkipShortcut__
|
||||
</div>
|
||||
|
||||
<div class="option-hidden-section hidden">
|
||||
<br/>
|
||||
|
||||
<div class="medium-description keybind-status">
|
||||
__MSG_keybindDescription__
|
||||
</div>
|
||||
|
||||
<span class="medium-description bold keybind-status-key">
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div option-type="keybind-change" sync-option="startSponsorKeybind">
|
||||
<div class="option-button trigger-button">
|
||||
__MSG_setStartSponsorShortcut__
|
||||
|
||||
@@ -178,11 +178,18 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
})
|
||||
}
|
||||
|
||||
removeFadeAnimation(): void {
|
||||
//remove the fade out class if it exists
|
||||
const notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
notice.classList.remove("sponsorSkipNoticeFadeOut");
|
||||
notice.style.animation = "none";
|
||||
}
|
||||
|
||||
pauseCountdown(): void {
|
||||
if (!this.props.timed) return;
|
||||
|
||||
//remove setInterval
|
||||
clearInterval(this.countdownInterval);
|
||||
if (this.countdownInterval) clearInterval(this.countdownInterval);
|
||||
this.countdownInterval = null;
|
||||
|
||||
//reset countdown and inform the user
|
||||
@@ -191,10 +198,7 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
countdownText: this.state.countdownManuallyPaused ? chrome.i18n.getMessage("manualPaused") : chrome.i18n.getMessage("paused")
|
||||
});
|
||||
|
||||
//remove the fade out class if it exists
|
||||
const notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
||||
notice.classList.remove("sponsorSkipNoticeFadeOut");
|
||||
notice.style.animation = "none";
|
||||
this.removeFadeAnimation();
|
||||
}
|
||||
|
||||
startCountdown(): void {
|
||||
@@ -208,16 +212,25 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||
countdownText: null
|
||||
});
|
||||
|
||||
this.setupInterval();
|
||||
}
|
||||
|
||||
setupInterval(): void {
|
||||
if (this.countdownInterval) clearInterval(this.countdownInterval);
|
||||
this.countdownInterval = setInterval(this.countdown.bind(this), 1000);
|
||||
}
|
||||
|
||||
resetCountdown(): void {
|
||||
if (!this.props.timed) return;
|
||||
|
||||
this.setupInterval();
|
||||
|
||||
this.setState({
|
||||
countdownTime: this.state.maxCountdownTime(),
|
||||
countdownText: null
|
||||
});
|
||||
|
||||
this.removeFadeAnimation();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ContentContainer, SponsorHideType, SponsorTime } from "../types";
|
||||
import NoticeComponent from "./NoticeComponent";
|
||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||
|
||||
enum SkipNoticeAction {
|
||||
export enum SkipNoticeAction {
|
||||
None,
|
||||
Upvote,
|
||||
Downvote,
|
||||
@@ -24,23 +24,23 @@ export interface SkipNoticeProps {
|
||||
}
|
||||
|
||||
export interface SkipNoticeState {
|
||||
noticeTitle: string;
|
||||
noticeTitle?: string;
|
||||
|
||||
messages: string[];
|
||||
messageOnClick: (event: React.MouseEvent) => unknown;
|
||||
messages?: string[];
|
||||
messageOnClick?: (event: React.MouseEvent) => unknown;
|
||||
|
||||
countdownTime: number;
|
||||
maxCountdownTime: () => number;
|
||||
countdownText: string;
|
||||
countdownTime?: number;
|
||||
maxCountdownTime?: () => number;
|
||||
countdownText?: string;
|
||||
|
||||
unskipText: string;
|
||||
unskipCallback: (index: number) => void;
|
||||
unskipText?: string;
|
||||
unskipCallback?: (index: number) => void;
|
||||
|
||||
downvoting: boolean;
|
||||
choosingCategory: boolean;
|
||||
thanksForVotingText: string; //null until the voting buttons should be hidden
|
||||
downvoting?: boolean;
|
||||
choosingCategory?: boolean;
|
||||
thanksForVotingText?: string; //null until the voting buttons should be hidden
|
||||
|
||||
actionState: SkipNoticeAction;
|
||||
actionState?: SkipNoticeAction;
|
||||
}
|
||||
|
||||
class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeState> {
|
||||
@@ -196,7 +196,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
style={{marginLeft: "4px"}}
|
||||
onClick={() => this.prepAction(SkipNoticeAction.Unskip)}>
|
||||
|
||||
{this.state.unskipText}
|
||||
{this.state.unskipText + " (" + Config.config.skipKeybind + ")"}
|
||||
</button>
|
||||
</td>
|
||||
|
||||
@@ -456,21 +456,23 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
reskip(index: number): void {
|
||||
this.contentContainer().reskipSponsorTime(this.segments[index]);
|
||||
|
||||
//reset countdown
|
||||
this.setState({
|
||||
const newState: SkipNoticeState = {
|
||||
unskipText: chrome.i18n.getMessage("unskip"),
|
||||
unskipCallback: this.unskip.bind(this),
|
||||
|
||||
maxCountdownTime: () => 4,
|
||||
countdownTime: 4
|
||||
});
|
||||
};
|
||||
|
||||
// See if the title should be changed
|
||||
if (!this.autoSkip) {
|
||||
this.setState({
|
||||
noticeTitle: chrome.i18n.getMessage("noticeTitle")
|
||||
});
|
||||
newState.noticeTitle = chrome.i18n.getMessage("noticeTitle");
|
||||
}
|
||||
|
||||
//reset countdown
|
||||
this.setState(newState, () => {
|
||||
this.noticeRef.current.resetCountdown();
|
||||
});
|
||||
}
|
||||
|
||||
afterVote(segment: SponsorTime, type: number, category: string): void {
|
||||
|
||||
@@ -10,6 +10,7 @@ interface SBConfig {
|
||||
defaultCategory: string,
|
||||
whitelistedChannels: string[],
|
||||
forceChannelCheck: boolean,
|
||||
skipKeybind: string,
|
||||
startSponsorKeybind: string,
|
||||
submitKeybind: string,
|
||||
minutesSaved: number,
|
||||
@@ -142,6 +143,7 @@ const Config: SBObject = {
|
||||
defaultCategory: "chooseACategory",
|
||||
whitelistedChannels: [],
|
||||
forceChannelCheck: false,
|
||||
skipKeybind: "Enter",
|
||||
startSponsorKeybind: ";",
|
||||
submitKeybind: "'",
|
||||
minutesSaved: 0,
|
||||
|
||||
@@ -23,6 +23,8 @@ let sponsorDataFound = false;
|
||||
let sponsorTimes: SponsorTime[] = null;
|
||||
//what video id are these sponsors for
|
||||
let sponsorVideoID: VideoID = null;
|
||||
// List of open skip notices
|
||||
const skipNotices: SkipNotice[] = [];
|
||||
|
||||
// JSON video info
|
||||
let videoInfo: VideoInfo = null;
|
||||
@@ -35,11 +37,13 @@ let channelID: string;
|
||||
let currentSkipSchedule: NodeJS.Timeout = null;
|
||||
let seekListenerSetUp = false
|
||||
|
||||
/** @type {Array[boolean]} Has the sponsor been skipped */
|
||||
/** Has the sponsor been skipped */
|
||||
let sponsorSkipped: boolean[] = [];
|
||||
|
||||
//the video
|
||||
let video: HTMLVideoElement;
|
||||
// List of videos that have had event listeners added to them
|
||||
const videoRootsWithEventListeners: HTMLDivElement[] = [];
|
||||
|
||||
let onInvidious;
|
||||
let onMobileYouTube;
|
||||
@@ -99,6 +103,7 @@ const skipNoticeContentContainer: ContentContainer = () => ({
|
||||
unskipSponsorTime,
|
||||
sponsorTimes,
|
||||
sponsorTimesSubmitting,
|
||||
skipNotices,
|
||||
v: video,
|
||||
sponsorVideoID,
|
||||
reskipSponsorTime,
|
||||
@@ -197,28 +202,6 @@ if (!Config.configListeners.includes(contentConfigUpdateListener)) {
|
||||
Config.configListeners.push(contentConfigUpdateListener);
|
||||
}
|
||||
|
||||
//check for hotkey pressed
|
||||
document.onkeydown = function(e: KeyboardEvent){
|
||||
const key = e.key;
|
||||
|
||||
const video = document.getElementById("movie_player");
|
||||
|
||||
const startSponsorKey = Config.config.startSponsorKeybind;
|
||||
|
||||
const submitKey = Config.config.submitKeybind;
|
||||
|
||||
//is the video in focus, otherwise they could be typing a comment
|
||||
if (document.activeElement === video) {
|
||||
if(key == startSponsorKey){
|
||||
//semicolon
|
||||
startSponsorClicked();
|
||||
} else if (key == submitKey) {
|
||||
//single quote
|
||||
submitSponsorTimes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetValues() {
|
||||
lastCheckTime = 0;
|
||||
lastCheckVideoTime = -1;
|
||||
@@ -512,6 +495,8 @@ async function sponsorsLookup(id: string) {
|
||||
return;
|
||||
}
|
||||
|
||||
addHotkeyListener();
|
||||
|
||||
if (!durationListenerSetUp) {
|
||||
durationListenerSetUp = true;
|
||||
|
||||
@@ -996,7 +981,7 @@ function skipToTime(v: HTMLVideoElement, skipTime: number[], skippingSegments: S
|
||||
if (openNotice) {
|
||||
//send out the message saying that a sponsor message was skipped
|
||||
if (!Config.config.dontShowNotice || !autoSkip) {
|
||||
new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer);
|
||||
skipNotices.push(new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1542,6 +1527,41 @@ function getSegmentsMessage(sponsorTimes: SponsorTime[]): string {
|
||||
return sponsorTimesMessage;
|
||||
}
|
||||
|
||||
function addHotkeyListener(): boolean {
|
||||
const videoRoot = document.getElementById("movie_player") as HTMLDivElement;
|
||||
|
||||
if (!videoRootsWithEventListeners.includes(videoRoot)) {
|
||||
videoRoot.addEventListener("keydown", hotkeyListener);
|
||||
videoRootsWithEventListeners.push(videoRoot);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function hotkeyListener(e: KeyboardEvent): void {
|
||||
const key = e.key;
|
||||
|
||||
const skipKey = Config.config.skipKeybind;
|
||||
const startSponsorKey = Config.config.startSponsorKeybind;
|
||||
const submitKey = Config.config.submitKeybind;
|
||||
|
||||
switch (key) {
|
||||
case skipKey:
|
||||
if (skipNotices.length > 0) {
|
||||
const latestSkipNotice = skipNotices[skipNotices.length - 1];
|
||||
latestSkipNotice.toggleSkip.call(latestSkipNotice);
|
||||
}
|
||||
break;
|
||||
case startSponsorKey:
|
||||
startSponsorClicked();
|
||||
break;
|
||||
case submitKey:
|
||||
submitSponsorTimes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this an unlisted YouTube video.
|
||||
* Assumes that the the privacy info is available.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
import SkipNoticeComponent from "../components/SkipNoticeComponent";
|
||||
import SkipNoticeComponent, { SkipNoticeAction } from "../components/SkipNoticeComponent";
|
||||
import { SponsorTime, ContentContainer } from "../types";
|
||||
|
||||
class SkipNotice {
|
||||
@@ -15,6 +15,8 @@ class SkipNotice {
|
||||
skipNoticeRef: React.MutableRefObject<SkipNoticeComponent>;
|
||||
|
||||
constructor(segments: SponsorTime[], autoSkip = false, contentContainer: ContentContainer) {
|
||||
this.skipNoticeRef = React.createRef();
|
||||
|
||||
this.segments = segments;
|
||||
this.autoSkip = autoSkip;
|
||||
this.contentContainer = contentContainer;
|
||||
@@ -67,6 +69,13 @@ class SkipNotice {
|
||||
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||
|
||||
this.noticeElement.remove();
|
||||
|
||||
const skipNotices = this.contentContainer().skipNotices;
|
||||
skipNotices.splice(skipNotices.indexOf(this), 1);
|
||||
}
|
||||
|
||||
toggleSkip(): void {
|
||||
this.skipNoticeRef.current.prepAction(SkipNoticeAction.Unskip);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import SubmissionNotice from "./render/SubmissionNotice";
|
||||
import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||
import SkipNotice from "./render/SkipNotice";
|
||||
|
||||
export interface ContentContainer {
|
||||
(): {
|
||||
@@ -8,6 +9,7 @@ export interface ContentContainer {
|
||||
unskipSponsorTime: (segment: SponsorTime) => void,
|
||||
sponsorTimes: SponsorTime[],
|
||||
sponsorTimesSubmitting: SponsorTime[],
|
||||
skipNotices: SkipNotice[],
|
||||
v: HTMLVideoElement,
|
||||
sponsorVideoID,
|
||||
reskipSponsorTime: (segment: SponsorTime) => void,
|
||||
|
||||
Reference in New Issue
Block a user