mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2024-11-13 02:14:23 +01:00
commit
ef942fca8e
11 changed files with 318 additions and 94 deletions
|
@ -52,6 +52,9 @@
|
||||||
"reskip": {
|
"reskip": {
|
||||||
"message": "Reskip"
|
"message": "Reskip"
|
||||||
},
|
},
|
||||||
|
"unmute": {
|
||||||
|
"message": "Unmute"
|
||||||
|
},
|
||||||
"paused": {
|
"paused": {
|
||||||
"message": "Paused"
|
"message": "Paused"
|
||||||
},
|
},
|
||||||
|
@ -302,6 +305,9 @@
|
||||||
"skip": {
|
"skip": {
|
||||||
"message": "Skip"
|
"message": "Skip"
|
||||||
},
|
},
|
||||||
|
"mute": {
|
||||||
|
"message": "Mute"
|
||||||
|
},
|
||||||
"skip_category": {
|
"skip_category": {
|
||||||
"message": "Skip {0}?"
|
"message": "Skip {0}?"
|
||||||
},
|
},
|
||||||
|
@ -604,6 +610,9 @@
|
||||||
"autoSkipOnMusicVideos": {
|
"autoSkipOnMusicVideos": {
|
||||||
"message": "Auto skip all segments when there is a non-music segment"
|
"message": "Auto skip all segments when there is a non-music segment"
|
||||||
},
|
},
|
||||||
|
"muteSegments": {
|
||||||
|
"message": "Allow segments that mute audio instead of skip"
|
||||||
|
},
|
||||||
"colorFormatIncorrect": {
|
"colorFormatIncorrect": {
|
||||||
"message": "Your color is formatted incorrectly. It should be a 3 or 6 digit hex code with a number sign at the beginning."
|
"message": "Your color is formatted incorrectly. It should be a 3 or 6 digit hex code with a number sign at the beginning."
|
||||||
},
|
},
|
||||||
|
|
|
@ -472,7 +472,7 @@ input::-webkit-inner-spin-button {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sponsorTimeCategories {
|
.sponsorTimeEditSelector {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,22 @@
|
||||||
<br/>
|
<br/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div option-type="toggle" sync-option="muteSegments">
|
||||||
|
<label class="switch-container">
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" checked>
|
||||||
|
<span class="slider round"></span>
|
||||||
|
</label>
|
||||||
|
<div class="switch-label">
|
||||||
|
__MSG_muteSegments__
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as CompileConfig from "../../config.json";
|
import * as CompileConfig from "../../config.json";
|
||||||
import Config from "../config"
|
import Config from "../config"
|
||||||
import { Category, ContentContainer, CategoryActionType, SponsorHideType, SponsorTime, NoticeVisbilityMode } from "../types";
|
import { Category, ContentContainer, CategoryActionType, SponsorHideType, SponsorTime, NoticeVisbilityMode, ActionType } from "../types";
|
||||||
import NoticeComponent from "./NoticeComponent";
|
import NoticeComponent from "./NoticeComponent";
|
||||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||||
|
|
||||||
|
@ -39,8 +39,9 @@ export interface SkipNoticeState {
|
||||||
maxCountdownTime?: () => number;
|
maxCountdownTime?: () => number;
|
||||||
countdownText?: string;
|
countdownText?: string;
|
||||||
|
|
||||||
unskipText?: string;
|
skipButtonText?: string;
|
||||||
unskipCallback?: (index: number) => void;
|
skipButtonCallback?: (index: number) => void;
|
||||||
|
showSkipButton?: boolean;
|
||||||
|
|
||||||
downvoting?: boolean;
|
downvoting?: boolean;
|
||||||
choosingCategory?: boolean;
|
choosingCategory?: boolean;
|
||||||
|
@ -110,8 +111,9 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||||
countdownTime: Config.config.skipNoticeDuration,
|
countdownTime: Config.config.skipNoticeDuration,
|
||||||
countdownText: null,
|
countdownText: null,
|
||||||
|
|
||||||
unskipText: chrome.i18n.getMessage("unskip"),
|
skipButtonText: this.getUnskipText(),
|
||||||
unskipCallback: (index) => this.unskip(index),
|
skipButtonCallback: (index) => this.unskip(index),
|
||||||
|
showSkipButton: true,
|
||||||
|
|
||||||
downvoting: false,
|
downvoting: false,
|
||||||
choosingCategory: false,
|
choosingCategory: false,
|
||||||
|
@ -126,7 +128,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||||
|
|
||||||
if (!this.autoSkip) {
|
if (!this.autoSkip) {
|
||||||
// Assume manual skip is only skipping 1 submission
|
// Assume manual skip is only skipping 1 submission
|
||||||
Object.assign(this.state, this.getUnskippedModeInfo(0, chrome.i18n.getMessage("skip")));
|
Object.assign(this.state, this.getUnskippedModeInfo(0, this.getSkipText()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,9 +299,9 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||||
}
|
}
|
||||||
|
|
||||||
getSkipButton(): JSX.Element {
|
getSkipButton(): JSX.Element {
|
||||||
if (this.segments.length > 1
|
if (this.state.showSkipButton && (this.segments.length > 1
|
||||||
|| getCategoryActionType(this.segments[0].category) !== CategoryActionType.POI
|
|| getCategoryActionType(this.segments[0].category) !== CategoryActionType.POI
|
||||||
|| this.props.unskipTime) {
|
|| this.props.unskipTime)) {
|
||||||
return (
|
return (
|
||||||
<span className="sponsorSkipNoticeUnskipSection">
|
<span className="sponsorSkipNoticeUnskipSection">
|
||||||
<button id={"sponsorSkipUnskipButton" + this.idSuffix}
|
<button id={"sponsorSkipUnskipButton" + this.idSuffix}
|
||||||
|
@ -307,7 +309,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.showKeybindHint ? " (" + Config.config.skipKeybind + ")" : "")}
|
{this.state.skipButtonText + (this.state.showKeybindHint ? " (" + Config.config.skipKeybind + ")" : "")}
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
@ -397,7 +399,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||||
this.contentContainer().vote(undefined, this.segments[index].UUID, this.categoryOptionRef.current.value as Category, this)
|
this.contentContainer().vote(undefined, this.segments[index].UUID, this.categoryOptionRef.current.value as Category, this)
|
||||||
break;
|
break;
|
||||||
case SkipNoticeAction.Unskip:
|
case SkipNoticeAction.Unskip:
|
||||||
this.state.unskipCallback(index);
|
this.state.skipButtonCallback(index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,7 +459,29 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||||
unskip(index: number): void {
|
unskip(index: number): void {
|
||||||
this.contentContainer().unskipSponsorTime(this.segments[index], this.props.unskipTime);
|
this.contentContainer().unskipSponsorTime(this.segments[index], this.props.unskipTime);
|
||||||
|
|
||||||
this.unskippedMode(index, chrome.i18n.getMessage("reskip"));
|
this.unskippedMode(index, this.getReskipText());
|
||||||
|
}
|
||||||
|
|
||||||
|
reskip(index: number): void {
|
||||||
|
this.contentContainer().reskipSponsorTime(this.segments[index]);
|
||||||
|
|
||||||
|
const newState: SkipNoticeState = {
|
||||||
|
skipButtonText: this.getUnskipText(),
|
||||||
|
skipButtonCallback: this.unskip.bind(this),
|
||||||
|
|
||||||
|
maxCountdownTime: () => Config.config.skipNoticeDuration,
|
||||||
|
countdownTime: Config.config.skipNoticeDuration
|
||||||
|
};
|
||||||
|
|
||||||
|
// See if the title should be changed
|
||||||
|
if (!this.autoSkip) {
|
||||||
|
newState.noticeTitle = chrome.i18n.getMessage("noticeTitle");
|
||||||
|
}
|
||||||
|
|
||||||
|
//reset countdown
|
||||||
|
this.setState(newState, () => {
|
||||||
|
this.noticeRef.current.resetCountdown();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets up notice to be not skipped yet */
|
/** Sets up notice to be not skipped yet */
|
||||||
|
@ -479,36 +503,14 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||||
} : this.state.maxCountdownTime;
|
} : this.state.maxCountdownTime;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
unskipText: buttonText,
|
skipButtonText: buttonText,
|
||||||
unskipCallback: (index) => this.reskip(index),
|
skipButtonCallback: (index) => this.reskip(index),
|
||||||
// change max duration to however much of the sponsor is left
|
// change max duration to however much of the sponsor is left
|
||||||
maxCountdownTime: maxCountdownTime,
|
maxCountdownTime: maxCountdownTime,
|
||||||
countdownTime: maxCountdownTime()
|
countdownTime: maxCountdownTime()
|
||||||
} as SkipNoticeState;
|
} as SkipNoticeState;
|
||||||
}
|
}
|
||||||
|
|
||||||
reskip(index: number): void {
|
|
||||||
this.contentContainer().reskipSponsorTime(this.segments[index]);
|
|
||||||
|
|
||||||
const newState: SkipNoticeState = {
|
|
||||||
unskipText: chrome.i18n.getMessage("unskip"),
|
|
||||||
unskipCallback: this.unskip.bind(this),
|
|
||||||
|
|
||||||
maxCountdownTime: () => Config.config.skipNoticeDuration,
|
|
||||||
countdownTime: Config.config.skipNoticeDuration
|
|
||||||
};
|
|
||||||
|
|
||||||
// See if the title should be changed
|
|
||||||
if (!this.autoSkip) {
|
|
||||||
newState.noticeTitle = chrome.i18n.getMessage("noticeTitle");
|
|
||||||
}
|
|
||||||
|
|
||||||
//reset countdown
|
|
||||||
this.setState(newState, () => {
|
|
||||||
this.noticeRef.current.resetCountdown();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
afterVote(segment: SponsorTime, type: number, category: Category): void {
|
afterVote(segment: SponsorTime, type: number, category: Category): void {
|
||||||
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
|
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
|
||||||
|
|
||||||
|
@ -559,6 +561,52 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||||
|
|
||||||
this.props.closeListener();
|
this.props.closeListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unmutedListener(): void {
|
||||||
|
if (this.props.segments.length === 1
|
||||||
|
&& this.props.segments[0].actionType === ActionType.Mute
|
||||||
|
&& this.contentContainer().v.currentTime >= this.props.segments[0].segment[1]) {
|
||||||
|
this.setState({
|
||||||
|
showSkipButton: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getUnskipText(): string {
|
||||||
|
switch (this.props.segments[0].actionType) {
|
||||||
|
case ActionType.Mute: {
|
||||||
|
return chrome.i18n.getMessage("unmute");
|
||||||
|
}
|
||||||
|
case ActionType.Skip:
|
||||||
|
default: {
|
||||||
|
return chrome.i18n.getMessage("unskip");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getReskipText(): string {
|
||||||
|
switch (this.props.segments[0].actionType) {
|
||||||
|
case ActionType.Mute: {
|
||||||
|
return chrome.i18n.getMessage("mute");
|
||||||
|
}
|
||||||
|
case ActionType.Skip:
|
||||||
|
default: {
|
||||||
|
return chrome.i18n.getMessage("reskip");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSkipText(): string {
|
||||||
|
switch (this.props.segments[0].actionType) {
|
||||||
|
case ActionType.Mute: {
|
||||||
|
return chrome.i18n.getMessage("mute");
|
||||||
|
}
|
||||||
|
case ActionType.Skip:
|
||||||
|
default: {
|
||||||
|
return chrome.i18n.getMessage("skip");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SkipNoticeComponent;
|
export default SkipNoticeComponent;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
import Config from "../config";
|
|
||||||
import * as CompileConfig from "../../config.json";
|
import * as CompileConfig from "../../config.json";
|
||||||
|
import Config from "../config";
|
||||||
|
import { ActionType, ActionTypes, Category, CategoryActionType, ContentContainer, SponsorTime } from "../types";
|
||||||
import Utils from "../utils";
|
import Utils from "../utils";
|
||||||
import { Category, CategoryActionType, ContentContainer, SponsorTime } from "../types";
|
|
||||||
import SubmissionNoticeComponent from "./SubmissionNoticeComponent";
|
|
||||||
import { getCategoryActionType } from "../utils/categoryUtils";
|
import { getCategoryActionType } from "../utils/categoryUtils";
|
||||||
|
import SubmissionNoticeComponent from "./SubmissionNoticeComponent";
|
||||||
|
|
||||||
|
|
||||||
const utils = new Utils();
|
const utils = new Utils();
|
||||||
|
|
||||||
export interface SponsorTimeEditProps {
|
export interface SponsorTimeEditProps {
|
||||||
|
@ -32,6 +32,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||||
idSuffix: string;
|
idSuffix: string;
|
||||||
|
|
||||||
categoryOptionRef: React.RefObject<HTMLSelectElement>;
|
categoryOptionRef: React.RefObject<HTMLSelectElement>;
|
||||||
|
actionTypeOptionRef: React.RefObject<HTMLSelectElement>;
|
||||||
|
|
||||||
configUpdateListener: () => void;
|
configUpdateListener: () => void;
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.categoryOptionRef = React.createRef();
|
this.categoryOptionRef = React.createRef();
|
||||||
|
this.actionTypeOptionRef = React.createRef();
|
||||||
|
|
||||||
this.idSuffix = this.props.idSuffix;
|
this.idSuffix = this.props.idSuffix;
|
||||||
|
|
||||||
|
@ -171,7 +173,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||||
{/* Category */}
|
{/* Category */}
|
||||||
<div style={{position: "relative"}}>
|
<div style={{position: "relative"}}>
|
||||||
<select id={"sponsorTimeCategories" + this.idSuffix}
|
<select id={"sponsorTimeCategories" + this.idSuffix}
|
||||||
className="sponsorTimeCategories"
|
className="sponsorTimeEditSelector sponsorTimeCategories"
|
||||||
defaultValue={sponsorTime.category}
|
defaultValue={sponsorTime.category}
|
||||||
ref={this.categoryOptionRef}
|
ref={this.categoryOptionRef}
|
||||||
onChange={this.categorySelectionChange.bind(this)}>
|
onChange={this.categorySelectionChange.bind(this)}>
|
||||||
|
@ -188,6 +190,19 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Action Type */}
|
||||||
|
{getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable ? (
|
||||||
|
<div style={{position: "relative"}}>
|
||||||
|
<select id={"sponsorTimeActionTypes" + this.idSuffix}
|
||||||
|
className="sponsorTimeEditSelector sponsorTimeActionTypes"
|
||||||
|
defaultValue={sponsorTime.actionType}
|
||||||
|
ref={this.actionTypeOptionRef}
|
||||||
|
onChange={() => this.saveEditTimes()}>
|
||||||
|
{this.getActionTypeOptions()}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
): ""}
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
{/* Editing Tools */}
|
{/* Editing Tools */}
|
||||||
|
@ -269,6 +284,21 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||||
this.saveEditTimes();
|
this.saveEditTimes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getActionTypeOptions(): React.ReactElement[] {
|
||||||
|
const elements = [];
|
||||||
|
|
||||||
|
for (const actionType of ActionTypes) {
|
||||||
|
elements.push(
|
||||||
|
<option value={actionType}
|
||||||
|
key={actionType}>
|
||||||
|
{chrome.i18n.getMessage(actionType)}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
setTimeToNow(index: number): void {
|
setTimeToNow(index: number): void {
|
||||||
this.setTimeTo(index, this.props.contentContainer().getRealCurrentTime());
|
this.setTimeTo(index, this.props.contentContainer().getRealCurrentTime());
|
||||||
}
|
}
|
||||||
|
@ -331,6 +361,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||||
}
|
}
|
||||||
|
|
||||||
sponsorTimesSubmitting[this.props.index].category = this.categoryOptionRef.current.value as Category;
|
sponsorTimesSubmitting[this.props.index].category = this.categoryOptionRef.current.value as Category;
|
||||||
|
sponsorTimesSubmitting[this.props.index].actionType =
|
||||||
|
this.actionTypeOptionRef?.current ? this.actionTypeOptionRef.current.value as ActionType : ActionType.Skip;
|
||||||
|
|
||||||
Config.config.segmentTimes.set(this.props.contentContainer().sponsorVideoID, sponsorTimesSubmitting);
|
Config.config.segmentTimes.set(this.props.contentContainer().sponsorVideoID, sponsorTimesSubmitting);
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ interface SBConfig {
|
||||||
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,
|
||||||
disableSkipping: boolean,
|
disableSkipping: boolean,
|
||||||
|
muteSegments: boolean,
|
||||||
trackViewCount: boolean,
|
trackViewCount: boolean,
|
||||||
trackViewCountInPrivate: boolean,
|
trackViewCountInPrivate: boolean,
|
||||||
dontShowNotice: boolean,
|
dontShowNotice: boolean,
|
||||||
|
@ -162,6 +163,7 @@ const Config: SBObject = {
|
||||||
submissionCountSinceCategories: 0,
|
submissionCountSinceCategories: 0,
|
||||||
showTimeWithSkips: true,
|
showTimeWithSkips: true,
|
||||||
disableSkipping: false,
|
disableSkipping: false,
|
||||||
|
muteSegments: true,
|
||||||
trackViewCount: true,
|
trackViewCount: true,
|
||||||
trackViewCountInPrivate: true,
|
trackViewCountInPrivate: true,
|
||||||
dontShowNotice: false,
|
dontShowNotice: false,
|
||||||
|
|
165
src/content.ts
165
src/content.ts
|
@ -1,5 +1,5 @@
|
||||||
import Config from "./config";
|
import Config from "./config";
|
||||||
import { SponsorTime, CategorySkipOption, VideoID, SponsorHideType, VideoInfo, StorageChangesObject, CategoryActionType, ChannelIDInfo, ChannelIDStatus, SponsorSourceType, SegmentUUID, Category, SkipToTimeParams, ToggleSkippable } from "./types";
|
import { SponsorTime, CategorySkipOption, VideoID, SponsorHideType, VideoInfo, StorageChangesObject, CategoryActionType, ChannelIDInfo, ChannelIDStatus, SponsorSourceType, SegmentUUID, Category, SkipToTimeParams, ToggleSkippable, ActionType, ScheduledTime } from "./types";
|
||||||
|
|
||||||
import { ContentContainer } from "./types";
|
import { ContentContainer } from "./types";
|
||||||
import Utils from "./utils";
|
import Utils from "./utils";
|
||||||
|
@ -45,6 +45,7 @@ let sponsorSkipped: boolean[] = [];
|
||||||
|
|
||||||
//the video
|
//the video
|
||||||
let video: HTMLVideoElement;
|
let video: HTMLVideoElement;
|
||||||
|
let videoMuted = false; // Has it been attempted to be muted
|
||||||
let videoMutationObserver: MutationObserver = null;
|
let videoMutationObserver: MutationObserver = null;
|
||||||
// List of videos that have had event listeners added to them
|
// List of videos that have had event listeners added to them
|
||||||
const videosWithEventListeners: HTMLVideoElement[] = [];
|
const videosWithEventListeners: HTMLVideoElement[] = [];
|
||||||
|
@ -396,7 +397,6 @@ function cancelSponsorSchedule(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @param currentTime Optional if you don't want to use the actual current time
|
* @param currentTime Optional if you don't want to use the actual current time
|
||||||
*/
|
*/
|
||||||
function startSponsorSchedule(includeIntersectingSegments = false, currentTime?: number, includeNonIntersectingSegments = true): void {
|
function startSponsorSchedule(includeIntersectingSegments = false, currentTime?: number, includeNonIntersectingSegments = true): void {
|
||||||
|
@ -412,6 +412,17 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!video || video.paused) return;
|
if (!video || video.paused) return;
|
||||||
|
if (currentTime === undefined || currentTime === null) currentTime = video.currentTime;
|
||||||
|
|
||||||
|
if (videoMuted && !inMuteSegment(currentTime)) {
|
||||||
|
video.muted = false;
|
||||||
|
videoMuted = false;
|
||||||
|
|
||||||
|
for (const notice of skipNotices) {
|
||||||
|
// So that the notice can hide buttons
|
||||||
|
notice.unmutedListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Config.config.disableSkipping || channelWhitelisted || (channelIDInfo.status === ChannelIDStatus.Fetching && Config.config.forceChannelCheck)){
|
if (Config.config.disableSkipping || channelWhitelisted || (channelIDInfo.status === ChannelIDStatus.Fetching && Config.config.forceChannelCheck)){
|
||||||
return;
|
return;
|
||||||
|
@ -419,14 +430,12 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
|
||||||
|
|
||||||
if (incorrectVideoCheck()) return;
|
if (incorrectVideoCheck()) return;
|
||||||
|
|
||||||
if (currentTime === undefined || currentTime === null) currentTime = video.currentTime;
|
|
||||||
|
|
||||||
const skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments, includeNonIntersectingSegments);
|
const skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments, includeNonIntersectingSegments);
|
||||||
|
|
||||||
if (skipInfo.index === -1) return;
|
if (skipInfo.index === -1) return;
|
||||||
|
|
||||||
const currentSkip = skipInfo.array[skipInfo.index];
|
const currentSkip = skipInfo.array[skipInfo.index];
|
||||||
const skipTime: number[] = [currentSkip.segment[0], skipInfo.array[skipInfo.endIndex].segment[1]];
|
const skipTime: number[] = [currentSkip.scheduledTime, skipInfo.array[skipInfo.endIndex].segment[1]];
|
||||||
const timeUntilSponsor = skipTime[0] - currentTime;
|
const timeUntilSponsor = skipTime[0] - currentTime;
|
||||||
const videoID = sponsorVideoID;
|
const videoID = sponsorVideoID;
|
||||||
|
|
||||||
|
@ -461,7 +470,8 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
|
||||||
openNotice: skipInfo.openNotice
|
openNotice: skipInfo.openNotice
|
||||||
});
|
});
|
||||||
|
|
||||||
if (utils.getCategorySelection(currentSkip.category)?.option === CategorySkipOption.ManualSkip) {
|
if (utils.getCategorySelection(currentSkip.category)?.option === CategorySkipOption.ManualSkip
|
||||||
|
|| currentSkip.actionType === ActionType.Mute) {
|
||||||
forcedSkipTime = skipTime[0] + 0.001;
|
forcedSkipTime = skipTime[0] + 0.001;
|
||||||
} else {
|
} else {
|
||||||
forcedSkipTime = skipTime[1];
|
forcedSkipTime = skipTime[1];
|
||||||
|
@ -480,12 +490,19 @@ function startSponsorSchedule(includeIntersectingSegments = false, currentTime?:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function inMuteSegment(currentTime: number): boolean {
|
||||||
|
const checkFunction = (segment) => segment.actionType === ActionType.Mute && segment.segment[0] <= currentTime && segment.segment[1] > currentTime;
|
||||||
|
return sponsorTimes?.some(checkFunction) || sponsorTimesSubmitting.some(checkFunction);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This makes sure the videoID is still correct and if the sponsorTime is included
|
* This makes sure the videoID is still correct and if the sponsorTime is included
|
||||||
*/
|
*/
|
||||||
function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boolean {
|
function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boolean {
|
||||||
const currentVideoID = getYouTubeVideoID(document.URL);
|
const currentVideoID = getYouTubeVideoID(document.URL);
|
||||||
if (currentVideoID !== (videoID || sponsorVideoID) || (sponsorTime && (!sponsorTimes || !sponsorTimes.includes(sponsorTime)) && !sponsorTimesSubmitting.includes(sponsorTime))) {
|
if (currentVideoID !== (videoID || sponsorVideoID) || (sponsorTime
|
||||||
|
&& (!sponsorTimes || !sponsorTimes?.some((time) => time.segment === sponsorTime.segment))
|
||||||
|
&& !sponsorTimesSubmitting.some((time) => time.segment === sponsorTime.segment))) {
|
||||||
// Something has really gone wrong
|
// Something has really gone wrong
|
||||||
console.error("[SponsorBlock] The videoID recorded when trying to skip is different than what it should be.");
|
console.error("[SponsorBlock] The videoID recorded when trying to skip is different than what it should be.");
|
||||||
console.error("[SponsorBlock] VideoID recorded: " + sponsorVideoID + ". Actual VideoID: " + currentVideoID);
|
console.error("[SponsorBlock] VideoID recorded: " + sponsorVideoID + ". Actual VideoID: " + currentVideoID);
|
||||||
|
@ -575,7 +592,7 @@ function setupVideoListeners() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Config.config.dontShowNotice) {
|
if (!Config.config.dontShowNotice) {
|
||||||
const currentPoiSegment = sponsorTimes.find((segment) =>
|
const currentPoiSegment = sponsorTimes?.find((segment) =>
|
||||||
getCategoryActionType(segment.category) === CategoryActionType.POI &&
|
getCategoryActionType(segment.category) === CategoryActionType.POI &&
|
||||||
video.currentTime - segment.segment[0] > 0 &&
|
video.currentTime - segment.segment[0] > 0 &&
|
||||||
video.currentTime - segment.segment[0] < previewBar.getMinimumSize(true));
|
video.currentTime - segment.segment[0] < previewBar.getMinimumSize(true));
|
||||||
|
@ -644,6 +661,7 @@ async function sponsorsLookup(id: string, keepOldSubmissions = true) {
|
||||||
const hashPrefix = (await utils.getHash(id, 1)).substr(0, 4);
|
const hashPrefix = (await utils.getHash(id, 1)).substr(0, 4);
|
||||||
const response = await utils.asyncRequestToServer('GET', "/api/skipSegments/" + hashPrefix, {
|
const response = await utils.asyncRequestToServer('GET', "/api/skipSegments/" + hashPrefix, {
|
||||||
categories,
|
categories,
|
||||||
|
actionTypes: Config.config.muteSegments ? [ActionType.Skip, ActionType.Mute] : [ActionType.Skip],
|
||||||
userAgent: `${chrome.runtime.id}`
|
userAgent: `${chrome.runtime.id}`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -945,31 +963,33 @@ async function whitelistCheck() {
|
||||||
* Returns info about the next upcoming sponsor skip
|
* Returns info about the next upcoming sponsor skip
|
||||||
*/
|
*/
|
||||||
function getNextSkipIndex(currentTime: number, includeIntersectingSegments: boolean, includeNonIntersectingSegments: boolean):
|
function getNextSkipIndex(currentTime: number, includeIntersectingSegments: boolean, includeNonIntersectingSegments: boolean):
|
||||||
{array: SponsorTime[], index: number, endIndex: number, openNotice: boolean} {
|
{array: ScheduledTime[], index: number, endIndex: number, openNotice: boolean} {
|
||||||
|
|
||||||
const sponsorStartTimes = getStartTimes(sponsorTimes, includeIntersectingSegments, includeNonIntersectingSegments);
|
const { includedTimes: submittedArray, startTimeIndexes: sponsorStartTimes } =
|
||||||
const sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, includeIntersectingSegments, includeNonIntersectingSegments, currentTime, true, true);
|
getStartTimes(sponsorTimes, includeIntersectingSegments, includeNonIntersectingSegments);
|
||||||
|
const { startTimeIndexes: sponsorStartTimesAfterCurrentTime } = getStartTimes(sponsorTimes, includeIntersectingSegments, includeNonIntersectingSegments, currentTime, true, true);
|
||||||
|
|
||||||
const minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime));
|
const minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime));
|
||||||
const endTimeIndex = getLatestEndTimeIndex(sponsorTimes, minSponsorTimeIndex);
|
const endTimeIndex = getLatestEndTimeIndex(submittedArray, minSponsorTimeIndex);
|
||||||
|
|
||||||
const unsubmittedSponsorStartTimes = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, includeNonIntersectingSegments);
|
const { includedTimes: unsubmittedArray, startTimeIndexes: unsubmittedSponsorStartTimes } =
|
||||||
const unsubmittedSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, includeNonIntersectingSegments, currentTime, false, false);
|
getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, includeNonIntersectingSegments);
|
||||||
|
const { startTimeIndexes: unsubmittedSponsorStartTimesAfterCurrentTime } = getStartTimes(sponsorTimesSubmitting, includeIntersectingSegments, includeNonIntersectingSegments, currentTime, false, false);
|
||||||
|
|
||||||
const minUnsubmittedSponsorTimeIndex = unsubmittedSponsorStartTimes.indexOf(Math.min(...unsubmittedSponsorStartTimesAfterCurrentTime));
|
const minUnsubmittedSponsorTimeIndex = unsubmittedSponsorStartTimes.indexOf(Math.min(...unsubmittedSponsorStartTimesAfterCurrentTime));
|
||||||
const previewEndTimeIndex = getLatestEndTimeIndex(sponsorTimesSubmitting, minUnsubmittedSponsorTimeIndex);
|
const previewEndTimeIndex = getLatestEndTimeIndex(unsubmittedArray, minUnsubmittedSponsorTimeIndex);
|
||||||
|
|
||||||
if ((minUnsubmittedSponsorTimeIndex === -1 && minSponsorTimeIndex !== -1) ||
|
if ((minUnsubmittedSponsorTimeIndex === -1 && minSponsorTimeIndex !== -1) ||
|
||||||
sponsorStartTimes[minSponsorTimeIndex] < unsubmittedSponsorStartTimes[minUnsubmittedSponsorTimeIndex]) {
|
sponsorStartTimes[minSponsorTimeIndex] < unsubmittedSponsorStartTimes[minUnsubmittedSponsorTimeIndex]) {
|
||||||
return {
|
return {
|
||||||
array: sponsorTimes.filter((segment) => getCategoryActionType(segment.category) === CategoryActionType.Skippable),
|
array: submittedArray,
|
||||||
index: minSponsorTimeIndex,
|
index: minSponsorTimeIndex,
|
||||||
endIndex: endTimeIndex,
|
endIndex: endTimeIndex,
|
||||||
openNotice: true
|
openNotice: true
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
array: sponsorTimesSubmitting.filter((segment) => getCategoryActionType(segment.category) === CategoryActionType.Skippable),
|
array: unsubmittedArray,
|
||||||
index: minUnsubmittedSponsorTimeIndex,
|
index: minUnsubmittedSponsorTimeIndex,
|
||||||
endIndex: previewEndTimeIndex,
|
endIndex: previewEndTimeIndex,
|
||||||
openNotice: false
|
openNotice: false
|
||||||
|
@ -993,7 +1013,10 @@ function getNextSkipIndex(currentTime: number, includeIntersectingSegments: bool
|
||||||
function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideHiddenSponsors = true): number {
|
function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideHiddenSponsors = true): number {
|
||||||
// Only combine segments for AutoSkip
|
// Only combine segments for AutoSkip
|
||||||
if (index == -1 ||
|
if (index == -1 ||
|
||||||
!shouldAutoSkip(sponsorTimes[index])) return index;
|
!shouldAutoSkip(sponsorTimes[index])
|
||||||
|
|| sponsorTimes[index].actionType !== ActionType.Skip) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
// Default to the normal endTime
|
// Default to the normal endTime
|
||||||
let latestEndTimeIndex = index;
|
let latestEndTimeIndex = index;
|
||||||
|
@ -1004,7 +1027,8 @@ function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideH
|
||||||
|
|
||||||
if (currentSegment[0] <= latestEndTime && currentSegment[1] > latestEndTime
|
if (currentSegment[0] <= latestEndTime && currentSegment[1] > latestEndTime
|
||||||
&& (!hideHiddenSponsors || sponsorTimes[i].hidden === SponsorHideType.Visible)
|
&& (!hideHiddenSponsors || sponsorTimes[i].hidden === SponsorHideType.Visible)
|
||||||
&& shouldAutoSkip(sponsorTimes[i])) {
|
&& shouldAutoSkip(sponsorTimes[i])
|
||||||
|
&& sponsorTimes[i].actionType === ActionType.Skip) {
|
||||||
// Overlapping segment
|
// Overlapping segment
|
||||||
latestEndTimeIndex = i;
|
latestEndTimeIndex = i;
|
||||||
}
|
}
|
||||||
|
@ -1029,24 +1053,43 @@ function getLatestEndTimeIndex(sponsorTimes: SponsorTime[], index: number, hideH
|
||||||
* the current time, but end after
|
* the current time, but end after
|
||||||
*/
|
*/
|
||||||
function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments: boolean, includeNonIntersectingSegments: boolean,
|
function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments: boolean, includeNonIntersectingSegments: boolean,
|
||||||
minimum?: number, onlySkippableSponsors = false, hideHiddenSponsors = false): number[] {
|
minimum?: number, onlySkippableSponsors = false, hideHiddenSponsors = false): {includedTimes: ScheduledTime[], startTimeIndexes: number[]} {
|
||||||
if (sponsorTimes === null) return [];
|
if (!sponsorTimes) return {includedTimes: [], startTimeIndexes: []};
|
||||||
|
|
||||||
const startTimes: number[] = [];
|
const includedTimes: ScheduledTime[] = [];
|
||||||
|
const startTimeIndexes: number[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < sponsorTimes?.length; i++) {
|
const possibleTimes = sponsorTimes.flatMap((sponsorTime) => {
|
||||||
|
const results = [{
|
||||||
|
...sponsorTime,
|
||||||
|
scheduledTime: sponsorTime.segment[0]
|
||||||
|
}]
|
||||||
|
|
||||||
|
if (sponsorTime.actionType === ActionType.Mute) {
|
||||||
|
// Schedule at the end time to know when to unmute
|
||||||
|
results.push({
|
||||||
|
...sponsorTime,
|
||||||
|
scheduledTime: sponsorTime.segment[1]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
})
|
||||||
|
|
||||||
|
for (let i = 0; i < possibleTimes.length; i++) {
|
||||||
if ((minimum === undefined
|
if ((minimum === undefined
|
||||||
|| ((includeNonIntersectingSegments && sponsorTimes[i].segment[0] >= minimum)
|
|| ((includeNonIntersectingSegments && possibleTimes[i].scheduledTime >= minimum)
|
||||||
|| (includeIntersectingSegments && sponsorTimes[i].segment[0] < minimum && sponsorTimes[i].segment[1] > minimum)))
|
|| (includeIntersectingSegments && possibleTimes[i].scheduledTime < minimum && possibleTimes[i].segment[1] > minimum)))
|
||||||
&& (!onlySkippableSponsors || shouldSkip(sponsorTimes[i]))
|
&& (!onlySkippableSponsors || shouldSkip(possibleTimes[i]))
|
||||||
&& (!hideHiddenSponsors || sponsorTimes[i].hidden === SponsorHideType.Visible)
|
&& (!hideHiddenSponsors || possibleTimes[i].hidden === SponsorHideType.Visible)
|
||||||
&& getCategoryActionType(sponsorTimes[i].category) === CategoryActionType.Skippable) {
|
&& getCategoryActionType(possibleTimes[i].category) === CategoryActionType.Skippable) {
|
||||||
|
|
||||||
startTimes.push(sponsorTimes[i].segment[0]);
|
startTimeIndexes.push(possibleTimes[i].scheduledTime);
|
||||||
|
includedTimes.push(possibleTimes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return startTimes;
|
return { includedTimes, startTimeIndexes };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1092,13 +1135,27 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
|
||||||
|
|
||||||
if ((autoSkip || sponsorTimesSubmitting.some((time) => time.segment === skippingSegments[0].segment))
|
if ((autoSkip || sponsorTimesSubmitting.some((time) => time.segment === skippingSegments[0].segment))
|
||||||
&& v.currentTime !== skipTime[1]) {
|
&& v.currentTime !== skipTime[1]) {
|
||||||
// Fix for looped videos not working when skipping to the end #426
|
switch(skippingSegments[0].actionType) {
|
||||||
// for some reason you also can't skip to 1 second before the end
|
case ActionType.Skip: {
|
||||||
if (v.loop && v.duration > 1 && skipTime[1] >= v.duration - 1) {
|
// Fix for looped videos not working when skipping to the end #426
|
||||||
v.currentTime = 0;
|
// for some reason you also can't skip to 1 second before the end
|
||||||
} else {
|
if (v.loop && v.duration > 1 && skipTime[1] >= v.duration - 1) {
|
||||||
v.currentTime = skipTime[1];
|
v.currentTime = 0;
|
||||||
|
} else {
|
||||||
|
v.currentTime = skipTime[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ActionType.Mute: {
|
||||||
|
if (!v.muted) {
|
||||||
|
v.muted = true;
|
||||||
|
videoMuted = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!autoSkip
|
if (!autoSkip
|
||||||
|
@ -1138,19 +1195,29 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
|
||||||
}
|
}
|
||||||
|
|
||||||
function unskipSponsorTime(segment: SponsorTime, unskipTime: number = null) {
|
function unskipSponsorTime(segment: SponsorTime, unskipTime: number = null) {
|
||||||
//add a tiny bit of time to make sure it is not skipped again
|
if (segment.actionType === ActionType.Mute) {
|
||||||
console.log(unskipTime)
|
video.muted = false;
|
||||||
video.currentTime = unskipTime ?? segment.segment[0] + 0.001;
|
videoMuted = false;
|
||||||
|
} else {
|
||||||
|
//add a tiny bit of time to make sure it is not skipped again
|
||||||
|
video.currentTime = unskipTime ?? segment.segment[0] + 0.001;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function reskipSponsorTime(segment: SponsorTime) {
|
function reskipSponsorTime(segment: SponsorTime) {
|
||||||
const skippedTime = Math.max(segment.segment[1] - video.currentTime, 0);
|
if (segment.actionType === ActionType.Mute) {
|
||||||
const segmentDuration = segment.segment[1] - segment.segment[0];
|
video.muted = true;
|
||||||
const fullSkip = skippedTime / segmentDuration > manualSkipPercentCount;
|
videoMuted = true;
|
||||||
|
} else {
|
||||||
video.currentTime = segment.segment[1];
|
const skippedTime = Math.max(segment.segment[1] - video.currentTime, 0);
|
||||||
sendTelemetryAndCount([segment], skippedTime, fullSkip);
|
const segmentDuration = segment.segment[1] - segment.segment[0];
|
||||||
startSponsorSchedule(true, segment.segment[1], false);
|
const fullSkip = skippedTime / segmentDuration > manualSkipPercentCount;
|
||||||
|
|
||||||
|
video.currentTime = segment.segment[1];
|
||||||
|
sendTelemetryAndCount([segment], skippedTime, fullSkip);
|
||||||
|
startSponsorSchedule(true, segment.segment[1], false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createButton(baseID: string, title: string, callback: () => void, imageName: string, isDraggable = false): HTMLElement {
|
function createButton(baseID: string, title: string, callback: () => void, imageName: string, isDraggable = false): HTMLElement {
|
||||||
|
@ -1193,13 +1260,13 @@ function createButton(baseID: string, title: string, callback: () => void, image
|
||||||
|
|
||||||
function shouldAutoSkip(segment: SponsorTime): boolean {
|
function shouldAutoSkip(segment: SponsorTime): boolean {
|
||||||
return utils.getCategorySelection(segment.category)?.option === CategorySkipOption.AutoSkip ||
|
return utils.getCategorySelection(segment.category)?.option === CategorySkipOption.AutoSkip ||
|
||||||
(Config.config.autoSkipOnMusicVideos && sponsorTimes.some((s) => s.category === "music_offtopic")
|
(Config.config.autoSkipOnMusicVideos && sponsorTimes?.some((s) => s.category === "music_offtopic")
|
||||||
&& getCategoryActionType(segment.category) === CategoryActionType.Skippable);
|
&& getCategoryActionType(segment.category) === CategoryActionType.Skippable);
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldSkip(segment: SponsorTime): boolean {
|
function shouldSkip(segment: SponsorTime): boolean {
|
||||||
return utils.getCategorySelection(segment.category)?.option !== CategorySkipOption.ShowOverlay ||
|
return utils.getCategorySelection(segment.category)?.option !== CategorySkipOption.ShowOverlay ||
|
||||||
(Config.config.autoSkipOnMusicVideos && sponsorTimes.some((s) => s.category === "music_offtopic"));
|
(Config.config.autoSkipOnMusicVideos && sponsorTimes?.some((s) => s.category === "music_offtopic"));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getControls(): HTMLElement | false {
|
function getControls(): HTMLElement | false {
|
||||||
|
@ -1333,6 +1400,7 @@ function startOrEndTimingNewSegment() {
|
||||||
segment: [getRealCurrentTime()],
|
segment: [getRealCurrentTime()],
|
||||||
UUID: null,
|
UUID: null,
|
||||||
category: Config.config.defaultCategory,
|
category: Config.config.defaultCategory,
|
||||||
|
actionType: ActionType.Skip,
|
||||||
source: SponsorSourceType.Local
|
source: SponsorSourceType.Local
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -1389,6 +1457,7 @@ function updateSponsorTimesSubmitting(getFromConfig = true) {
|
||||||
segment: segmentTime.segment,
|
segment: segmentTime.segment,
|
||||||
UUID: segmentTime.UUID,
|
UUID: segmentTime.UUID,
|
||||||
category: segmentTime.category,
|
category: segmentTime.category,
|
||||||
|
actionType: segmentTime.actionType,
|
||||||
source: segmentTime.source
|
source: segmentTime.source
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,10 @@ class SkipNotice {
|
||||||
toggleSkip(): void {
|
toggleSkip(): void {
|
||||||
this.skipNoticeRef?.current?.prepAction(SkipNoticeAction.Unskip);
|
this.skipNoticeRef?.current?.prepAction(SkipNoticeAction.Unskip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unmutedListener(): void {
|
||||||
|
this.skipNoticeRef?.current?.unmutedListener();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SkipNotice;
|
export default SkipNotice;
|
12
src/types.ts
12
src/types.ts
|
@ -56,6 +56,13 @@ export enum CategoryActionType {
|
||||||
POI = "_POI"
|
POI = "_POI"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ActionType {
|
||||||
|
Skip = "skip",
|
||||||
|
Mute = "mute"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ActionTypes = [ActionType.Skip, ActionType.Mute];
|
||||||
|
|
||||||
export type SegmentUUID = string & { __segmentUUIDBrand: unknown };
|
export type SegmentUUID = string & { __segmentUUIDBrand: unknown };
|
||||||
export type Category = string & { __categoryBrand: unknown };
|
export type Category = string & { __categoryBrand: unknown };
|
||||||
|
|
||||||
|
@ -69,11 +76,16 @@ export interface SponsorTime {
|
||||||
UUID: SegmentUUID;
|
UUID: SegmentUUID;
|
||||||
|
|
||||||
category: Category;
|
category: Category;
|
||||||
|
actionType: ActionType;
|
||||||
|
|
||||||
hidden?: SponsorHideType;
|
hidden?: SponsorHideType;
|
||||||
source?: SponsorSourceType;
|
source?: SponsorSourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ScheduledTime extends SponsorTime {
|
||||||
|
scheduledTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PreviewBarOption {
|
export interface PreviewBarOption {
|
||||||
color: string,
|
color: string,
|
||||||
opacity: string
|
opacity: string
|
||||||
|
|
|
@ -13,8 +13,11 @@ test("Selenium Chrome test", async () => {
|
||||||
await createSegment(driver, "4", "10.33", "0:04.000 to 0:10.330");
|
await createSegment(driver, "4", "10.33", "0:04.000 to 0:10.330");
|
||||||
|
|
||||||
await editSegments(driver, 0, "0:04.000", "0:10.330", "5", "13.211", "0:05.000 to 0:13.211", false);
|
await editSegments(driver, 0, "0:04.000", "0:10.330", "5", "13.211", "0:05.000 to 0:13.211", false);
|
||||||
|
|
||||||
await autoskipSegment(driver, 5, 13.211);
|
await autoskipSegment(driver, 5, 13.211);
|
||||||
|
|
||||||
|
await setSegmentActionType(driver, 0, 1, false);
|
||||||
|
await editSegments(driver, 0, "0:05.000", "0:13.211", "5", "7.5", "0:05.000 to 0:07.500", false);
|
||||||
|
await muteSkipSegment(driver, 5, 7.5);
|
||||||
} finally {
|
} finally {
|
||||||
await driver.quit();
|
await driver.quit();
|
||||||
}
|
}
|
||||||
|
@ -24,7 +27,7 @@ async function setup(): Promise<WebDriver> {
|
||||||
const options = new Chrome.Options();
|
const options = new Chrome.Options();
|
||||||
options.addArguments("--load-extension=" + Path.join(__dirname, "../dist/"));
|
options.addArguments("--load-extension=" + Path.join(__dirname, "../dist/"));
|
||||||
options.addArguments("--mute-audio");
|
options.addArguments("--mute-audio");
|
||||||
options.addArguments("--disable-features=PreloadMediaEngagementData, MediaEngagementBypassAutoplayPolicies")
|
options.addArguments("--disable-features=PreloadMediaEngagementData, MediaEngagementBypassAutoplayPolicies");
|
||||||
|
|
||||||
const driver = await new Builder().forBrowser("chrome").setChromeOptions(options).build();
|
const driver = await new Builder().forBrowser("chrome").setChromeOptions(options).build();
|
||||||
driver.manage().setTimeouts({
|
driver.manage().setTimeouts({
|
||||||
|
@ -106,6 +109,16 @@ async function editSegments(driver: WebDriver, index: number, expectedStartTimeB
|
||||||
await driver.wait(until.elementTextIs(sponsorTimeDisplay, expectedDisplayedTime));
|
await driver.wait(until.elementTextIs(sponsorTimeDisplay, expectedDisplayedTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function setSegmentActionType(driver: WebDriver, index: number, actionTypeIndex: number, openSubmitBox: boolean): Promise<void> {
|
||||||
|
if (openSubmitBox) {
|
||||||
|
const submitButton = await driver.findElement(By.id("submitButton"));
|
||||||
|
await submitButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionTypeSelection = await driver.findElement(By.css(`#sponsorTimeActionTypesSubmissionNotice${index} > option:nth-child(${actionTypeIndex + 1})`));
|
||||||
|
actionTypeSelection.click();
|
||||||
|
}
|
||||||
|
|
||||||
async function autoskipSegment(driver: WebDriver, startTime: number, endTime: number): Promise<void> {
|
async function autoskipSegment(driver: WebDriver, startTime: number, endTime: number): Promise<void> {
|
||||||
const video = await driver.findElement(By.css("video"));
|
const video = await driver.findElement(By.css("video"));
|
||||||
|
|
||||||
|
@ -113,7 +126,21 @@ async function autoskipSegment(driver: WebDriver, startTime: number, endTime: nu
|
||||||
await driver.executeScript("document.querySelector('video').play()");
|
await driver.executeScript("document.querySelector('video').play()");
|
||||||
|
|
||||||
await driver.sleep(1300);
|
await driver.sleep(1300);
|
||||||
|
|
||||||
expect(parseFloat(await video.getAttribute("currentTime"))).toBeGreaterThan(endTime);
|
expect(parseFloat(await video.getAttribute("currentTime"))).toBeGreaterThan(endTime);
|
||||||
await driver.executeScript("document.querySelector('video').pause()");
|
await driver.executeScript("document.querySelector('video').pause()");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function muteSkipSegment(driver: WebDriver, startTime: number, endTime: number): Promise<void> {
|
||||||
|
const duration = endTime - startTime;
|
||||||
|
const video = await driver.findElement(By.css("video"));
|
||||||
|
|
||||||
|
await driver.executeScript("document.querySelector('video').currentTime = " + (startTime - 0.5));
|
||||||
|
await driver.executeScript("document.querySelector('video').play()");
|
||||||
|
|
||||||
|
await driver.sleep(1300);
|
||||||
|
expect(await video.getAttribute("muted")).toEqual("true");
|
||||||
|
|
||||||
|
await driver.sleep(duration * 1000 + 300);
|
||||||
|
expect(await video.getAttribute("muted")).toBeNull(); // Default is null for some reason
|
||||||
|
await driver.executeScript("document.querySelector('video').pause()");
|
||||||
}
|
}
|
|
@ -8,6 +8,11 @@
|
||||||
"noEmitOnError": false,
|
"noEmitOnError": false,
|
||||||
"typeRoots": [ "node_modules/@types" ],
|
"typeRoots": [ "node_modules/@types" ],
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"jsx": "react"
|
"jsx": "react",
|
||||||
|
"lib": [
|
||||||
|
"es2019",
|
||||||
|
"dom",
|
||||||
|
"dom.iterable"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue