mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-25 17:08:42 +03:00
@@ -46,7 +46,6 @@
|
|||||||
],
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"storage",
|
"storage",
|
||||||
"notifications",
|
|
||||||
"https://sponsor.ajay.app/*"
|
"https://sponsor.ajay.app/*"
|
||||||
],
|
],
|
||||||
"optional_permissions": [
|
"optional_permissions": [
|
||||||
|
|||||||
@@ -97,9 +97,6 @@
|
|||||||
"wantToSubmit": {
|
"wantToSubmit": {
|
||||||
"message": "Do you want to submit for video id"
|
"message": "Do you want to submit for video id"
|
||||||
},
|
},
|
||||||
"leftTimes": {
|
|
||||||
"message": "You seem to have left some segments unsubmitted. Go back to that page to submit them (they are not deleted)."
|
|
||||||
},
|
|
||||||
"clearTimes": {
|
"clearTimes": {
|
||||||
"message": "Clear Segments"
|
"message": "Clear Segments"
|
||||||
},
|
},
|
||||||
@@ -235,6 +232,9 @@
|
|||||||
"message": "If you still don't like it, hit the never show button.",
|
"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."
|
"description": "The second line of the message displayed after the notice was upgraded."
|
||||||
},
|
},
|
||||||
|
"setSkipShortcut": {
|
||||||
|
"message": "Set key for skipping a segment"
|
||||||
|
},
|
||||||
"setStartSponsorShortcut": {
|
"setStartSponsorShortcut": {
|
||||||
"message": "Set key for start segment keybind"
|
"message": "Set key for start segment keybind"
|
||||||
},
|
},
|
||||||
@@ -631,12 +631,6 @@
|
|||||||
"categoryUpdate2": {
|
"categoryUpdate2": {
|
||||||
"message": "Open the options to skip intros, outros, merch, etc."
|
"message": "Open the options to skip intros, outros, merch, etc."
|
||||||
},
|
},
|
||||||
"unsubmittedWarning": {
|
|
||||||
"message": "Unsubmitted Segments Notification"
|
|
||||||
},
|
|
||||||
"unsubmittedWarningDescription": {
|
|
||||||
"message": "Send a notification when you leave a video with segments that are not uploaded"
|
|
||||||
},
|
|
||||||
"help": {
|
"help": {
|
||||||
"message": "Help"
|
"message": "Help"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,27 @@
|
|||||||
<br/>
|
<br/>
|
||||||
<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 option-type="keybind-change" sync-option="startSponsorKeybind">
|
||||||
<div class="option-button trigger-button">
|
<div class="option-button trigger-button">
|
||||||
__MSG_setStartSponsorShortcut__
|
__MSG_setStartSponsorShortcut__
|
||||||
@@ -152,23 +173,6 @@
|
|||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<div option-type="toggle" sync-option="unsubmittedWarning">
|
|
||||||
<label class="switch-container" label-name="__MSG_unsubmittedWarning__">
|
|
||||||
<label class="switch">
|
|
||||||
<input type="checkbox" checked>
|
|
||||||
<span class="slider round"></span>
|
|
||||||
</label>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<div class="small-description">__MSG_unsubmittedWarningDescription__</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<div option-type="toggle" sync-option="forceChannelCheck">
|
<div option-type="toggle" sync-option="forceChannelCheck">
|
||||||
<label class="switch-container" label-name="__MSG_forceChannelCheck__">
|
<label class="switch-container" label-name="__MSG_forceChannelCheck__">
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
|
|||||||
@@ -52,16 +52,6 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
|||||||
|
|
||||||
//this allows the callback to be called later
|
//this allows the callback to be called later
|
||||||
return true;
|
return true;
|
||||||
case "alertPrevious":
|
|
||||||
if (Config.config.unsubmittedWarning) {
|
|
||||||
chrome.notifications.create("stillThere" + Math.random(), {
|
|
||||||
type: "basic",
|
|
||||||
title: chrome.i18n.getMessage("wantToSubmit") + " " + request.previousVideoID + "?",
|
|
||||||
message: chrome.i18n.getMessage("leftTimes"),
|
|
||||||
iconUrl: "./icons/LogoSponsorBlocker256px.png"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "registerContentScript":
|
case "registerContentScript":
|
||||||
registerFirefoxContentScript(request);
|
registerFirefoxContentScript(request);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export interface NoticeProps {
|
|||||||
timed?: boolean,
|
timed?: boolean,
|
||||||
idSuffix?: string,
|
idSuffix?: string,
|
||||||
|
|
||||||
|
videoSpeed?: () => number,
|
||||||
|
|
||||||
fadeIn?: boolean,
|
fadeIn?: boolean,
|
||||||
|
|
||||||
// Callback for when this is closed
|
// Callback for when this is closed
|
||||||
@@ -19,7 +21,7 @@ export interface NoticeProps {
|
|||||||
export interface NoticeState {
|
export interface NoticeState {
|
||||||
noticeTitle: string,
|
noticeTitle: string,
|
||||||
|
|
||||||
maxCountdownTime?: () => number,
|
maxCountdownTime: () => number,
|
||||||
|
|
||||||
countdownTime: number,
|
countdownTime: number,
|
||||||
countdownText: string,
|
countdownText: string,
|
||||||
@@ -28,6 +30,8 @@ export interface NoticeState {
|
|||||||
|
|
||||||
class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
||||||
countdownInterval: NodeJS.Timeout;
|
countdownInterval: NodeJS.Timeout;
|
||||||
|
intervalVideoSpeed: number;
|
||||||
|
|
||||||
idSuffix: string;
|
idSuffix: string;
|
||||||
|
|
||||||
amountOfPreviousNotices: number;
|
amountOfPreviousNotices: number;
|
||||||
@@ -71,7 +75,9 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<table id={"sponsorSkipNotice" + this.idSuffix}
|
<table id={"sponsorSkipNotice" + this.idSuffix}
|
||||||
className={"sponsorSkipObject sponsorSkipNotice" + (this.props.fadeIn ? " sponsorSkipNoticeFadeIn" : "")}
|
className={"sponsorSkipObject sponsorSkipNotice"
|
||||||
|
+ (this.props.fadeIn ? " sponsorSkipNoticeFadeIn" : "")
|
||||||
|
+ (this.amountOfPreviousNotices > 0 ? " secondSkipNotice" : "")}
|
||||||
style={noticeStyle}
|
style={noticeStyle}
|
||||||
onMouseEnter={() => this.timerMouseEnter()}
|
onMouseEnter={() => this.timerMouseEnter()}
|
||||||
onMouseLeave={() => this.timerMouseLeave()}>
|
onMouseLeave={() => this.timerMouseLeave()}>
|
||||||
@@ -152,7 +158,11 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
|||||||
countdown(): void {
|
countdown(): void {
|
||||||
if (!this.props.timed) return;
|
if (!this.props.timed) return;
|
||||||
|
|
||||||
const countdownTime = this.state.countdownTime - 1;
|
const countdownTime = Math.min(this.state.countdownTime - 1, this.state.maxCountdownTime());
|
||||||
|
|
||||||
|
if (this.props.videoSpeed && this.intervalVideoSpeed != this.props.videoSpeed()) {
|
||||||
|
this.setupInterval();
|
||||||
|
}
|
||||||
|
|
||||||
if (countdownTime <= 0) {
|
if (countdownTime <= 0) {
|
||||||
//remove this from setInterval
|
//remove this from setInterval
|
||||||
@@ -176,11 +186,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 {
|
pauseCountdown(): void {
|
||||||
if (!this.props.timed) return;
|
if (!this.props.timed) return;
|
||||||
|
|
||||||
//remove setInterval
|
//remove setInterval
|
||||||
clearInterval(this.countdownInterval);
|
if (this.countdownInterval) clearInterval(this.countdownInterval);
|
||||||
this.countdownInterval = null;
|
this.countdownInterval = null;
|
||||||
|
|
||||||
//reset countdown and inform the user
|
//reset countdown and inform the user
|
||||||
@@ -189,10 +206,7 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
|||||||
countdownText: this.state.countdownManuallyPaused ? chrome.i18n.getMessage("manualPaused") : chrome.i18n.getMessage("paused")
|
countdownText: this.state.countdownManuallyPaused ? chrome.i18n.getMessage("manualPaused") : chrome.i18n.getMessage("paused")
|
||||||
});
|
});
|
||||||
|
|
||||||
//remove the fade out class if it exists
|
this.removeFadeAnimation();
|
||||||
const notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
|
|
||||||
notice.classList.remove("sponsorSkipNoticeFadeOut");
|
|
||||||
notice.style.animation = "none";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startCountdown(): void {
|
startCountdown(): void {
|
||||||
@@ -206,16 +220,29 @@ class NoticeComponent extends React.Component<NoticeProps, NoticeState> {
|
|||||||
countdownText: null
|
countdownText: null
|
||||||
});
|
});
|
||||||
|
|
||||||
this.countdownInterval = setInterval(this.countdown.bind(this), 1000);
|
this.setupInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
setupInterval(): void {
|
||||||
|
if (this.countdownInterval) clearInterval(this.countdownInterval);
|
||||||
|
|
||||||
|
const intervalDuration = this.props.videoSpeed ? 1000 / this.props.videoSpeed() : 1000;
|
||||||
|
this.countdownInterval = setInterval(this.countdown.bind(this), intervalDuration);
|
||||||
|
|
||||||
|
if (this.props.videoSpeed) this.intervalVideoSpeed = this.props.videoSpeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
resetCountdown(): void {
|
resetCountdown(): void {
|
||||||
if (!this.props.timed) return;
|
if (!this.props.timed) return;
|
||||||
|
|
||||||
|
this.setupInterval();
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
countdownTime: this.state.maxCountdownTime(),
|
countdownTime: this.state.maxCountdownTime(),
|
||||||
countdownText: null
|
countdownText: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.removeFadeAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { ContentContainer, SponsorHideType, SponsorTime } from "../types";
|
|||||||
import NoticeComponent from "./NoticeComponent";
|
import NoticeComponent from "./NoticeComponent";
|
||||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||||
|
|
||||||
enum SkipNoticeAction {
|
export enum SkipNoticeAction {
|
||||||
None,
|
None,
|
||||||
Upvote,
|
Upvote,
|
||||||
Downvote,
|
Downvote,
|
||||||
@@ -24,23 +24,23 @@ export interface SkipNoticeProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SkipNoticeState {
|
export interface SkipNoticeState {
|
||||||
noticeTitle: string;
|
noticeTitle?: string;
|
||||||
|
|
||||||
messages: string[];
|
messages?: string[];
|
||||||
messageOnClick: (event: React.MouseEvent) => unknown;
|
messageOnClick?: (event: React.MouseEvent) => unknown;
|
||||||
|
|
||||||
countdownTime: number;
|
countdownTime?: number;
|
||||||
maxCountdownTime: () => number;
|
maxCountdownTime?: () => number;
|
||||||
countdownText: string;
|
countdownText?: string;
|
||||||
|
|
||||||
unskipText: string;
|
unskipText?: string;
|
||||||
unskipCallback: (index: number) => void;
|
unskipCallback?: (index: number) => void;
|
||||||
|
|
||||||
downvoting: boolean;
|
downvoting?: boolean;
|
||||||
choosingCategory: boolean;
|
choosingCategory?: boolean;
|
||||||
thanksForVotingText: string; //null until the voting buttons should be hidden
|
thanksForVotingText?: string; //null until the voting buttons should be hidden
|
||||||
|
|
||||||
actionState: SkipNoticeAction;
|
actionState?: SkipNoticeAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeState> {
|
class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeState> {
|
||||||
@@ -91,13 +91,6 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
|||||||
}
|
}
|
||||||
this.idSuffix += this.amountOfPreviousNotices;
|
this.idSuffix += this.amountOfPreviousNotices;
|
||||||
|
|
||||||
if (this.amountOfPreviousNotices > 0) {
|
|
||||||
//another notice exists
|
|
||||||
|
|
||||||
const previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0];
|
|
||||||
previousNotice.classList.add("secondSkipNotice")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup state
|
// Setup state
|
||||||
this.state = {
|
this.state = {
|
||||||
noticeTitle,
|
noticeTitle,
|
||||||
@@ -148,6 +141,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
|||||||
fadeIn={true}
|
fadeIn={true}
|
||||||
timed={true}
|
timed={true}
|
||||||
maxCountdownTime={this.state.maxCountdownTime}
|
maxCountdownTime={this.state.maxCountdownTime}
|
||||||
|
videoSpeed={() => this.contentContainer().v?.playbackRate}
|
||||||
ref={this.noticeRef}
|
ref={this.noticeRef}
|
||||||
closeListener={() => this.closeListener()}>
|
closeListener={() => this.closeListener()}>
|
||||||
|
|
||||||
@@ -203,7 +197,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
|||||||
style={{marginLeft: "4px"}}
|
style={{marginLeft: "4px"}}
|
||||||
onClick={() => this.prepAction(SkipNoticeAction.Unskip)}>
|
onClick={() => this.prepAction(SkipNoticeAction.Unskip)}>
|
||||||
|
|
||||||
{this.state.unskipText}
|
{this.state.unskipText + " (" + Config.config.skipKeybind + ")"}
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
@@ -463,21 +457,23 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
|||||||
reskip(index: number): void {
|
reskip(index: number): void {
|
||||||
this.contentContainer().reskipSponsorTime(this.segments[index]);
|
this.contentContainer().reskipSponsorTime(this.segments[index]);
|
||||||
|
|
||||||
//reset countdown
|
const newState: SkipNoticeState = {
|
||||||
this.setState({
|
|
||||||
unskipText: chrome.i18n.getMessage("unskip"),
|
unskipText: chrome.i18n.getMessage("unskip"),
|
||||||
unskipCallback: this.unskip.bind(this),
|
unskipCallback: this.unskip.bind(this),
|
||||||
|
|
||||||
maxCountdownTime: () => 4,
|
maxCountdownTime: () => 4,
|
||||||
countdownTime: 4
|
countdownTime: 4
|
||||||
});
|
};
|
||||||
|
|
||||||
// See if the title should be changed
|
// See if the title should be changed
|
||||||
if (!this.autoSkip) {
|
if (!this.autoSkip) {
|
||||||
this.setState({
|
newState.noticeTitle = chrome.i18n.getMessage("noticeTitle");
|
||||||
noticeTitle: chrome.i18n.getMessage("noticeTitle")
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//reset countdown
|
||||||
|
this.setState(newState, () => {
|
||||||
|
this.noticeRef.current.resetCountdown();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
afterVote(segment: SponsorTime, type: number, category: string): void {
|
afterVote(segment: SponsorTime, type: number, category: string): void {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as CompileConfig from "../config.json";
|
import * as CompileConfig from "../config.json";
|
||||||
import { CategorySelection, CategorySkipOption, PreviewBarOption, SponsorTime, StorageChangesObject } from "./types";
|
import { CategorySelection, CategorySkipOption, PreviewBarOption, SponsorTime, StorageChangesObject, UnEncodedSegmentTimes as UnencodedSegmentTimes } from "./types";
|
||||||
|
|
||||||
import Utils from "./utils";
|
import Utils from "./utils";
|
||||||
const utils = new Utils();
|
const utils = new Utils();
|
||||||
@@ -10,6 +10,7 @@ interface SBConfig {
|
|||||||
defaultCategory: string,
|
defaultCategory: string,
|
||||||
whitelistedChannels: string[],
|
whitelistedChannels: string[],
|
||||||
forceChannelCheck: boolean,
|
forceChannelCheck: boolean,
|
||||||
|
skipKeybind: string,
|
||||||
startSponsorKeybind: string,
|
startSponsorKeybind: string,
|
||||||
submitKeybind: string,
|
submitKeybind: string,
|
||||||
minutesSaved: number,
|
minutesSaved: number,
|
||||||
@@ -17,7 +18,6 @@ interface SBConfig {
|
|||||||
sponsorTimesContributed: number,
|
sponsorTimesContributed: number,
|
||||||
submissionCountSinceCategories: number, // New count used to show the "Read The Guidelines!!" message
|
submissionCountSinceCategories: number, // New count used to show the "Read The Guidelines!!" message
|
||||||
showTimeWithSkips: boolean,
|
showTimeWithSkips: boolean,
|
||||||
unsubmittedWarning: boolean,
|
|
||||||
disableSkipping: boolean,
|
disableSkipping: boolean,
|
||||||
trackViewCount: boolean,
|
trackViewCount: boolean,
|
||||||
dontShowNotice: boolean,
|
dontShowNotice: boolean,
|
||||||
@@ -65,7 +65,7 @@ export interface SBObject {
|
|||||||
config: SBConfig;
|
config: SBConfig;
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
encodeStoredItem<T>(data: T): T | Array<any>;
|
encodeStoredItem<T>(data: T): T | UnencodedSegmentTimes;
|
||||||
convertJSON(): void;
|
convertJSON(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +143,7 @@ const Config: SBObject = {
|
|||||||
defaultCategory: "chooseACategory",
|
defaultCategory: "chooseACategory",
|
||||||
whitelistedChannels: [],
|
whitelistedChannels: [],
|
||||||
forceChannelCheck: false,
|
forceChannelCheck: false,
|
||||||
|
skipKeybind: "Enter",
|
||||||
startSponsorKeybind: ";",
|
startSponsorKeybind: ";",
|
||||||
submitKeybind: "'",
|
submitKeybind: "'",
|
||||||
minutesSaved: 0,
|
minutesSaved: 0,
|
||||||
@@ -150,7 +151,6 @@ const Config: SBObject = {
|
|||||||
sponsorTimesContributed: 0,
|
sponsorTimesContributed: 0,
|
||||||
submissionCountSinceCategories: 0,
|
submissionCountSinceCategories: 0,
|
||||||
showTimeWithSkips: true,
|
showTimeWithSkips: true,
|
||||||
unsubmittedWarning: true,
|
|
||||||
disableSkipping: false,
|
disableSkipping: false,
|
||||||
trackViewCount: true,
|
trackViewCount: true,
|
||||||
dontShowNotice: false,
|
dontShowNotice: false,
|
||||||
@@ -247,10 +247,10 @@ const Config: SBObject = {
|
|||||||
*
|
*
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
function encodeStoredItem<T>(data: T): T | Array<any> {
|
function encodeStoredItem<T>(data: T): T | UnencodedSegmentTimes {
|
||||||
// if data is SBMap convert to json for storing
|
// if data is SBMap convert to json for storing
|
||||||
if(!(data instanceof SBMap)) return data;
|
if(!(data instanceof SBMap)) return data;
|
||||||
return Array.from(data.entries());
|
return Array.from(data.entries()).filter((element) => element[1] === []); // Remove empty entries
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -265,7 +265,7 @@ function decodeStoredItem<T>(id: string, data: T): T | SBMap<string, SponsorTime
|
|||||||
if (Config.defaults[id] instanceof SBMap) {
|
if (Config.defaults[id] instanceof SBMap) {
|
||||||
try {
|
try {
|
||||||
if (!Array.isArray(data)) return data;
|
if (!Array.isArray(data)) return data;
|
||||||
return new SBMap(id, data);
|
return new SBMap(id, data as UnencodedSegmentTimes);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error("Failed to parse SBMap: " + id);
|
console.error("Failed to parse SBMap: " + id);
|
||||||
}
|
}
|
||||||
@@ -395,7 +395,7 @@ function migrateOldFormats(config: SBConfig) {
|
|||||||
|
|
||||||
// Migrate old "sponsorTimes"
|
// Migrate old "sponsorTimes"
|
||||||
if (config["sponsorTimes"]) {
|
if (config["sponsorTimes"]) {
|
||||||
let jsonData: any = config["sponsorTimes"];
|
let jsonData: unknown = config["sponsorTimes"];
|
||||||
|
|
||||||
// Check if data is stored in the old format for SBMap (a JSON string)
|
// Check if data is stored in the old format for SBMap (a JSON string)
|
||||||
if (typeof jsonData === "string") {
|
if (typeof jsonData === "string") {
|
||||||
|
|||||||
@@ -19,11 +19,12 @@ utils.wait(() => Config.config !== null, 5000, 10).then(addCSS);
|
|||||||
|
|
||||||
//was sponsor data found when doing SponsorsLookup
|
//was sponsor data found when doing SponsorsLookup
|
||||||
let sponsorDataFound = false;
|
let sponsorDataFound = false;
|
||||||
let previousVideoID: VideoID = null;
|
|
||||||
//the actual sponsorTimes if loaded and UUIDs associated with them
|
//the actual sponsorTimes if loaded and UUIDs associated with them
|
||||||
let sponsorTimes: SponsorTime[] = null;
|
let sponsorTimes: SponsorTime[] = null;
|
||||||
//what video id are these sponsors for
|
//what video id are these sponsors for
|
||||||
let sponsorVideoID: VideoID = null;
|
let sponsorVideoID: VideoID = null;
|
||||||
|
// List of open skip notices
|
||||||
|
const skipNotices: SkipNotice[] = [];
|
||||||
|
|
||||||
// JSON video info
|
// JSON video info
|
||||||
let videoInfo: VideoInfo = null;
|
let videoInfo: VideoInfo = null;
|
||||||
@@ -36,11 +37,13 @@ let channelID: string;
|
|||||||
let currentSkipSchedule: NodeJS.Timeout = null;
|
let currentSkipSchedule: NodeJS.Timeout = null;
|
||||||
let seekListenerSetUp = false
|
let seekListenerSetUp = false
|
||||||
|
|
||||||
/** @type {Array[boolean]} Has the sponsor been skipped */
|
/** Has the sponsor been skipped */
|
||||||
let sponsorSkipped: boolean[] = [];
|
let sponsorSkipped: boolean[] = [];
|
||||||
|
|
||||||
//the video
|
//the video
|
||||||
let video: HTMLVideoElement;
|
let video: HTMLVideoElement;
|
||||||
|
// List of videos that have had event listeners added to them
|
||||||
|
const videoRootsWithEventListeners: HTMLDivElement[] = [];
|
||||||
|
|
||||||
let onInvidious;
|
let onInvidious;
|
||||||
let onMobileYouTube;
|
let onMobileYouTube;
|
||||||
@@ -100,6 +103,7 @@ const skipNoticeContentContainer: ContentContainer = () => ({
|
|||||||
unskipSponsorTime,
|
unskipSponsorTime,
|
||||||
sponsorTimes,
|
sponsorTimes,
|
||||||
sponsorTimesSubmitting,
|
sponsorTimesSubmitting,
|
||||||
|
skipNotices,
|
||||||
v: video,
|
v: video,
|
||||||
sponsorVideoID,
|
sponsorVideoID,
|
||||||
reskipSponsorTime,
|
reskipSponsorTime,
|
||||||
@@ -198,28 +202,6 @@ if (!Config.configListeners.includes(contentConfigUpdateListener)) {
|
|||||||
Config.configListeners.push(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() {
|
function resetValues() {
|
||||||
lastCheckTime = 0;
|
lastCheckTime = 0;
|
||||||
lastCheckVideoTime = -1;
|
lastCheckVideoTime = -1;
|
||||||
@@ -310,25 +292,6 @@ async function videoIDChange(id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//warn them if they had unsubmitted times
|
|
||||||
if (previousVideoID != null) {
|
|
||||||
//get the sponsor times from storage
|
|
||||||
const sponsorTimes = Config.config.segmentTimes.get(previousVideoID);
|
|
||||||
if (sponsorTimes != undefined && sponsorTimes.length > 0 && new URL(document.URL).host !== "music.youtube.com") {
|
|
||||||
//warn them that they have unsubmitted sponsor times
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
message: "alertPrevious",
|
|
||||||
previousVideoID: previousVideoID
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//set the previous video id to the currentID
|
|
||||||
previousVideoID = id;
|
|
||||||
} else {
|
|
||||||
//set the previous id now, don't wait for chrome.storage.get
|
|
||||||
previousVideoID = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
//close popup
|
//close popup
|
||||||
closeInfoMenu();
|
closeInfoMenu();
|
||||||
|
|
||||||
@@ -532,6 +495,8 @@ async function sponsorsLookup(id: string) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addHotkeyListener();
|
||||||
|
|
||||||
if (!durationListenerSetUp) {
|
if (!durationListenerSetUp) {
|
||||||
durationListenerSetUp = true;
|
durationListenerSetUp = true;
|
||||||
|
|
||||||
@@ -1016,7 +981,7 @@ function skipToTime(v: HTMLVideoElement, skipTime: number[], skippingSegments: S
|
|||||||
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
|
||||||
if (!Config.config.dontShowNotice || !autoSkip) {
|
if (!Config.config.dontShowNotice || !autoSkip) {
|
||||||
new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer);
|
skipNotices.push(new SkipNotice(skippingSegments, autoSkip, skipNoticeContentContainer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1562,6 +1527,41 @@ function getSegmentsMessage(sponsorTimes: SponsorTime[]): string {
|
|||||||
return sponsorTimesMessage;
|
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.
|
* Is this an unlisted YouTube video.
|
||||||
* Assumes that the the privacy info is available.
|
* Assumes that the the privacy info is available.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
|
|
||||||
import SkipNoticeComponent from "../components/SkipNoticeComponent";
|
import SkipNoticeComponent, { SkipNoticeAction } from "../components/SkipNoticeComponent";
|
||||||
import { SponsorTime, ContentContainer } from "../types";
|
import { SponsorTime, ContentContainer } from "../types";
|
||||||
|
|
||||||
class SkipNotice {
|
class SkipNotice {
|
||||||
@@ -15,6 +15,8 @@ class SkipNotice {
|
|||||||
skipNoticeRef: React.MutableRefObject<SkipNoticeComponent>;
|
skipNoticeRef: React.MutableRefObject<SkipNoticeComponent>;
|
||||||
|
|
||||||
constructor(segments: SponsorTime[], autoSkip = false, contentContainer: ContentContainer) {
|
constructor(segments: SponsorTime[], autoSkip = false, contentContainer: ContentContainer) {
|
||||||
|
this.skipNoticeRef = React.createRef();
|
||||||
|
|
||||||
this.segments = segments;
|
this.segments = segments;
|
||||||
this.autoSkip = autoSkip;
|
this.autoSkip = autoSkip;
|
||||||
this.contentContainer = contentContainer;
|
this.contentContainer = contentContainer;
|
||||||
@@ -67,6 +69,13 @@ class SkipNotice {
|
|||||||
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
ReactDOM.unmountComponentAtNode(this.noticeElement);
|
||||||
|
|
||||||
this.noticeElement.remove();
|
this.noticeElement.remove();
|
||||||
|
|
||||||
|
const skipNotices = this.contentContainer().skipNotices;
|
||||||
|
skipNotices.splice(skipNotices.indexOf(this), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleSkip(): void {
|
||||||
|
this.skipNoticeRef.current.prepAction(SkipNoticeAction.Unskip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
44
src/types.ts
44
src/types.ts
@@ -1,13 +1,15 @@
|
|||||||
import SubmissionNotice from "./render/SubmissionNotice";
|
import SubmissionNotice from "./render/SubmissionNotice";
|
||||||
import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||||
|
import SkipNotice from "./render/SkipNotice";
|
||||||
|
|
||||||
interface ContentContainer {
|
export interface ContentContainer {
|
||||||
(): {
|
(): {
|
||||||
vote: (type: number, UUID: string, category?: string, skipNotice?: SkipNoticeComponent) => void,
|
vote: (type: number, UUID: string, category?: string, skipNotice?: SkipNoticeComponent) => void,
|
||||||
dontShowNoticeAgain: () => void,
|
dontShowNoticeAgain: () => void,
|
||||||
unskipSponsorTime: (segment: SponsorTime) => void,
|
unskipSponsorTime: (segment: SponsorTime) => void,
|
||||||
sponsorTimes: SponsorTime[],
|
sponsorTimes: SponsorTime[],
|
||||||
sponsorTimesSubmitting: SponsorTime[],
|
sponsorTimesSubmitting: SponsorTime[],
|
||||||
|
skipNotices: SkipNotice[],
|
||||||
v: HTMLVideoElement,
|
v: HTMLVideoElement,
|
||||||
sponsorVideoID,
|
sponsorVideoID,
|
||||||
reskipSponsorTime: (segment: SponsorTime) => void,
|
reskipSponsorTime: (segment: SponsorTime) => void,
|
||||||
@@ -22,34 +24,34 @@ interface ContentContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FetchResponse {
|
export interface FetchResponse {
|
||||||
responseText: string,
|
responseText: string,
|
||||||
status: number,
|
status: number,
|
||||||
ok: boolean
|
ok: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VideoDurationResponse {
|
export interface VideoDurationResponse {
|
||||||
duration: number;
|
duration: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CategorySkipOption {
|
export enum CategorySkipOption {
|
||||||
ShowOverlay,
|
ShowOverlay,
|
||||||
ManualSkip,
|
ManualSkip,
|
||||||
AutoSkip
|
AutoSkip
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CategorySelection {
|
export interface CategorySelection {
|
||||||
name: string;
|
name: string;
|
||||||
option: CategorySkipOption
|
option: CategorySkipOption
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SponsorHideType {
|
export enum SponsorHideType {
|
||||||
Visible = undefined,
|
Visible = undefined,
|
||||||
Downvoted = 1,
|
Downvoted = 1,
|
||||||
MinimumDuration
|
MinimumDuration
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SponsorTime {
|
export interface SponsorTime {
|
||||||
segment: number[];
|
segment: number[];
|
||||||
UUID: string;
|
UUID: string;
|
||||||
|
|
||||||
@@ -58,13 +60,13 @@ interface SponsorTime {
|
|||||||
hidden?: SponsorHideType;
|
hidden?: SponsorHideType;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PreviewBarOption {
|
export interface PreviewBarOption {
|
||||||
color: string,
|
color: string,
|
||||||
opacity: string
|
opacity: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface Registration {
|
export interface Registration {
|
||||||
message: string,
|
message: string,
|
||||||
id: string,
|
id: string,
|
||||||
allFrames: boolean,
|
allFrames: boolean,
|
||||||
@@ -73,12 +75,12 @@ interface Registration {
|
|||||||
matches: string[]
|
matches: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BackgroundScriptContainer {
|
export interface BackgroundScriptContainer {
|
||||||
registerFirefoxContentScript: (opts: Registration) => void,
|
registerFirefoxContentScript: (opts: Registration) => void,
|
||||||
unregisterFirefoxContentScript: (id: string) => void
|
unregisterFirefoxContentScript: (id: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VideoInfo {
|
export interface VideoInfo {
|
||||||
responseContext: {
|
responseContext: {
|
||||||
serviceTrackingParams: Array<{service: string, params: Array<{key: string, value: string}>}>,
|
serviceTrackingParams: Array<{service: string, params: Array<{key: string, value: string}>}>,
|
||||||
webResponseContextExtensionData: {
|
webResponseContextExtensionData: {
|
||||||
@@ -154,22 +156,8 @@ interface VideoInfo {
|
|||||||
messages: unknown;
|
messages: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
type VideoID = string;
|
export type VideoID = string;
|
||||||
|
|
||||||
type StorageChangesObject = { [key: string]: chrome.storage.StorageChange };
|
export type StorageChangesObject = { [key: string]: chrome.storage.StorageChange };
|
||||||
|
|
||||||
export {
|
export type UnEncodedSegmentTimes = [string, SponsorTime[]][];
|
||||||
FetchResponse,
|
|
||||||
VideoDurationResponse,
|
|
||||||
ContentContainer,
|
|
||||||
CategorySelection,
|
|
||||||
CategorySkipOption,
|
|
||||||
SponsorTime,
|
|
||||||
VideoID,
|
|
||||||
SponsorHideType,
|
|
||||||
PreviewBarOption,
|
|
||||||
Registration,
|
|
||||||
BackgroundScriptContainer,
|
|
||||||
VideoInfo,
|
|
||||||
StorageChangesObject,
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user