mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2026-03-18 03:46:33 +03:00
Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into chapters
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import * as React from "react";
|
||||
import * as CompileConfig from "../../config.json";
|
||||
import Config from "../config"
|
||||
import { Category, ContentContainer, CategoryActionType, SponsorHideType, SponsorTime, NoticeVisbilityMode, ActionType, SponsorSourceType, SegmentUUID } from "../types";
|
||||
import { Category, ContentContainer, SponsorHideType, SponsorTime, NoticeVisbilityMode, ActionType, SponsorSourceType, SegmentUUID } from "../types";
|
||||
import NoticeComponent from "./NoticeComponent";
|
||||
import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
|
||||
import Utils from "../utils";
|
||||
const utils = new Utils();
|
||||
|
||||
import { getCategoryActionType, getSkippingText } from "../utils/categoryUtils";
|
||||
import { getSkippingText } from "../utils/categoryUtils";
|
||||
|
||||
import ThumbsUpSvg from "../svg-icons/thumbs_up_svg";
|
||||
import ThumbsDownSvg from "../svg-icons/thumbs_down_svg";
|
||||
@@ -326,7 +326,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
|
||||
getSkipButton(): JSX.Element {
|
||||
if (this.state.showSkipButton && (this.segments.length > 1
|
||||
|| getCategoryActionType(this.segments[0].category) !== CategoryActionType.POI
|
||||
|| this.segments[0].actionType !== ActionType.Poi
|
||||
|| this.props.unskipTime)) {
|
||||
|
||||
const style: React.CSSProperties = {
|
||||
@@ -547,7 +547,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
getCategoryOptions(): React.ReactElement[] {
|
||||
const elements = [];
|
||||
|
||||
const categories = (CompileConfig.categoryList.filter((cat => getCategoryActionType(cat as Category) === CategoryActionType.Skippable))) as Category[];
|
||||
const categories = (CompileConfig.categoryList.filter((cat => CompileConfig.categorySupport[cat].includes(ActionType.Skip)))) as Category[];
|
||||
for (const category of categories) {
|
||||
elements.push(
|
||||
<option value={category}
|
||||
@@ -601,7 +601,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
}
|
||||
|
||||
getUnskippedModeInfo(index: number, buttonText: string): SkipNoticeState {
|
||||
const changeCountdown = getCategoryActionType(this.segments[index].category) === CategoryActionType.Skippable;
|
||||
const changeCountdown = this.segments[index].actionType !== ActionType.Poi;
|
||||
|
||||
const maxCountdownTime = changeCountdown ? () => {
|
||||
const sponsorTime = this.segments[index];
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import * as React from "react";
|
||||
import * as CompileConfig from "../../config.json";
|
||||
import Config from "../config";
|
||||
import { ActionType, Category, CategoryActionType, ChannelIDStatus, ContentContainer, SponsorTime } from "../types";
|
||||
import { ActionType, Category, ChannelIDStatus, ContentContainer, SponsorTime } from "../types";
|
||||
import Utils from "../utils";
|
||||
import { getCategoryActionType } from "../utils/categoryUtils";
|
||||
import SubmissionNoticeComponent from "./SubmissionNoticeComponent";
|
||||
import { RectangleTooltip } from "../render/RectangleTooltip";
|
||||
import SelectorComponent, { SelectorOption } from "./SelectorComponent";
|
||||
@@ -43,8 +42,9 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
|
||||
configUpdateListener: () => void;
|
||||
|
||||
previousSkipType: CategoryActionType;
|
||||
timeBeforeChangingToPOI: number; // Initialized when first selecting POI
|
||||
previousSkipType: ActionType;
|
||||
// Used when selecting POI or Full
|
||||
timesBeforeChanging: number[] = [];
|
||||
fullVideoWarningShown = false;
|
||||
|
||||
// For description auto-complete
|
||||
@@ -58,8 +58,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
this.descriptionOptionRef = React.createRef();
|
||||
|
||||
this.idSuffix = this.props.idSuffix;
|
||||
this.previousSkipType = CategoryActionType.Skippable;
|
||||
|
||||
this.previousSkipType = ActionType.Skip;
|
||||
|
||||
const sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
this.state = {
|
||||
editing: false,
|
||||
@@ -142,7 +142,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
onWheel={(e) => this.changeTimesWhenScrolling(0, e, sponsorTime)}>
|
||||
</input>
|
||||
|
||||
{getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable ? (
|
||||
{sponsorTime.actionType !== ActionType.Poi ? (
|
||||
<span>
|
||||
<span>
|
||||
{" " + chrome.i18n.getMessage("to") + " "}
|
||||
@@ -180,7 +180,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
className="sponsorTimeDisplay"
|
||||
onClick={this.toggleEditTime.bind(this)}>
|
||||
{utils.getFormattedTime(segment[0], true) +
|
||||
((!isNaN(segment[1]) && getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable)
|
||||
((!isNaN(segment[1]) && sponsorTime.actionType !== ActionType.Poi)
|
||||
? " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(segment[1], true) : "")}
|
||||
</div>
|
||||
);
|
||||
@@ -215,13 +215,13 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
{/* Action Type */}
|
||||
{CompileConfig.categorySupport[sponsorTime.category] &&
|
||||
(CompileConfig.categorySupport[sponsorTime.category]?.length > 1
|
||||
|| CompileConfig.categorySupport[sponsorTime.category]?.[0] !== "skip") ? (
|
||||
|| ![ActionType.Skip, ActionType.Poi].includes(CompileConfig.categorySupport[sponsorTime.category]?.[0])) ? (
|
||||
<div style={{position: "relative"}}>
|
||||
<select id={"sponsorTimeActionTypes" + this.idSuffix}
|
||||
className="sponsorTimeEditSelector sponsorTimeActionTypes"
|
||||
defaultValue={sponsorTime.actionType}
|
||||
ref={this.actionTypeOptionRef}
|
||||
onChange={() => this.saveEditTimes()}>
|
||||
onChange={(e) => this.actionTypeSelectionChange(e)}>
|
||||
{this.getActionTypeOptions(sponsorTime)}
|
||||
</select>
|
||||
</div>
|
||||
@@ -258,7 +258,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
{chrome.i18n.getMessage("delete")}
|
||||
</span>
|
||||
|
||||
{(!isNaN(segment[1]) && getCategoryActionType(sponsorTime.category) === CategoryActionType.Skippable) ? (
|
||||
{(!isNaN(segment[1]) && ![ActionType.Poi, ActionType.Full].includes(sponsorTime.actionType)) ? (
|
||||
<span id={"sponsorTimePreviewButton" + this.idSuffix}
|
||||
className="sponsorTimeEditButton"
|
||||
onClick={(e) => this.previewTime(e.ctrlKey, e.shiftKey)}>
|
||||
@@ -295,7 +295,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
if (0 < difference && difference < 0.5) this.showScrollToEditToolTip();
|
||||
|
||||
sponsorTimeEdits[index] = targetValue;
|
||||
if (index === 0 && getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTimeEdits[1] = targetValue;
|
||||
if (index === 0 && sponsorTime.actionType === ActionType.Poi) sponsorTimeEdits[1] = targetValue;
|
||||
|
||||
this.setState({sponsorTimeEdits}, () => this.saveEditTimes());
|
||||
}
|
||||
@@ -324,7 +324,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
}
|
||||
|
||||
sponsorTimeEdits[index] = utils.getFormattedTime(timeAsNumber, true);
|
||||
if (getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTimeEdits[1] = sponsorTimeEdits[0];
|
||||
if (sponsorTime.actionType === ActionType.Poi) sponsorTimeEdits[1] = sponsorTimeEdits[0];
|
||||
|
||||
this.setState({sponsorTimeEdits});
|
||||
this.saveEditTimes();
|
||||
@@ -415,21 +415,51 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
return;
|
||||
}
|
||||
|
||||
if (getCategoryActionType(chosenCategory) === CategoryActionType.POI) {
|
||||
if (this.previousSkipType === CategoryActionType.Skippable) this.timeBeforeChangingToPOI = utils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[1]);
|
||||
const sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
this.handleReplacingLostTimes(chosenCategory, sponsorTime.actionType);
|
||||
this.saveEditTimes();
|
||||
}
|
||||
|
||||
actionTypeSelectionChange(event: React.ChangeEvent<HTMLSelectElement>): void {
|
||||
const sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
|
||||
|
||||
this.handleReplacingLostTimes(sponsorTime.category, event.target.value as ActionType);
|
||||
this.saveEditTimes();
|
||||
}
|
||||
|
||||
private handleReplacingLostTimes(category: Category, actionType: ActionType): void {
|
||||
if (CompileConfig.categorySupport[category]?.includes(ActionType.Poi)) {
|
||||
if (this.previousSkipType !== ActionType.Poi) {
|
||||
this.timesBeforeChanging = [null, utils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[1])];
|
||||
}
|
||||
|
||||
this.setTimeTo(1, null);
|
||||
this.props.contentContainer().updateEditButtonsOnPlayer();
|
||||
|
||||
if (this.props.contentContainer().sponsorTimesSubmitting
|
||||
.some((segment, i) => segment.category === chosenCategory && i !== this.props.index)) {
|
||||
.some((segment, i) => segment.category === category && i !== this.props.index)) {
|
||||
alert(chrome.i18n.getMessage("poiOnlyOneSegment"));
|
||||
}
|
||||
} else if (getCategoryActionType(chosenCategory) === CategoryActionType.Skippable && this.previousSkipType === CategoryActionType.POI) {
|
||||
this.setTimeTo(1, this.timeBeforeChangingToPOI);
|
||||
}
|
||||
|
||||
this.previousSkipType = getCategoryActionType(chosenCategory);
|
||||
this.saveEditTimes();
|
||||
this.previousSkipType = ActionType.Poi;
|
||||
} else if (CompileConfig.categorySupport[category]?.length === 1
|
||||
&& CompileConfig.categorySupport[category]?.[0] === ActionType.Full) {
|
||||
if (this.previousSkipType !== ActionType.Full) {
|
||||
this.timesBeforeChanging = [utils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[0]), utils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[1])];
|
||||
}
|
||||
|
||||
this.previousSkipType = ActionType.Full;
|
||||
} else if (CompileConfig.categorySupport[category]?.includes(ActionType.Skip)
|
||||
&& ![ActionType.Poi, ActionType.Full].includes(this.getNextActionType(category, actionType)) && this.previousSkipType !== ActionType.Skip) {
|
||||
if (this.timesBeforeChanging[0]) {
|
||||
this.setTimeTo(0, this.timesBeforeChanging[0]);
|
||||
}
|
||||
if (this.timesBeforeChanging[1]) {
|
||||
this.setTimeTo(1, this.timesBeforeChanging[1]);
|
||||
}
|
||||
|
||||
this.previousSkipType = ActionType.Skip;
|
||||
}
|
||||
}
|
||||
|
||||
getActionTypeOptions(sponsorTime: SponsorTime): React.ReactElement[] {
|
||||
@@ -464,7 +494,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
if (time === null) time = sponsorTime.segment[0];
|
||||
|
||||
sponsorTime.segment[index] = time;
|
||||
if (getCategoryActionType(sponsorTime.category) === CategoryActionType.POI) sponsorTime.segment[1] = time;
|
||||
if (sponsorTime.actionType === ActionType.Poi) sponsorTime.segment[1] = time;
|
||||
|
||||
this.setState({
|
||||
sponsorTimeEdits: this.getFormattedSponsorTimesEdits(sponsorTime)
|
||||
@@ -511,9 +541,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
const category = this.categoryOptionRef.current.value as Category
|
||||
sponsorTimesSubmitting[this.props.index].category = category;
|
||||
|
||||
const inputActionType = this.actionTypeOptionRef?.current?.value as ActionType;
|
||||
const actionType = inputActionType && CompileConfig.categorySupport[category]?.includes(inputActionType) ? inputActionType as ActionType
|
||||
: CompileConfig.categorySupport[category]?.[0] ?? ActionType.Skip;
|
||||
const actionType = this.getNextActionType(category, this.actionTypeOptionRef?.current?.value as ActionType);
|
||||
sponsorTimesSubmitting[this.props.index].actionType = actionType;
|
||||
|
||||
const description = actionType === ActionType.Chapter ? this.descriptionOptionRef?.current?.value : "";
|
||||
@@ -530,6 +558,11 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
||||
}
|
||||
}
|
||||
|
||||
private getNextActionType(category: Category, actionType: ActionType): ActionType {
|
||||
return actionType && CompileConfig.categorySupport[category]?.includes(actionType) ? actionType
|
||||
: CompileConfig.categorySupport[category]?.[0] ?? ActionType.Skip
|
||||
}
|
||||
|
||||
previewTime(ctrlPressed = false, shiftPressed = false): void {
|
||||
const sponsorTimes = this.props.contentContainer().sponsorTimesSubmitting;
|
||||
const index = this.props.index;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Config from "./config";
|
||||
import { SponsorTime, CategorySkipOption, VideoID, SponsorHideType, VideoInfo, StorageChangesObject, CategoryActionType, ChannelIDInfo, ChannelIDStatus, SponsorSourceType, SegmentUUID, Category, SkipToTimeParams, ToggleSkippable, ActionType, ScheduledTime } from "./types";
|
||||
import { SponsorTime, CategorySkipOption, VideoID, SponsorHideType, VideoInfo, StorageChangesObject, ChannelIDInfo, ChannelIDStatus, SponsorSourceType, SegmentUUID, Category, SkipToTimeParams, ToggleSkippable, ActionType, ScheduledTime } from "./types";
|
||||
|
||||
import { ContentContainer } from "./types";
|
||||
import Utils from "./utils";
|
||||
@@ -13,7 +13,6 @@ import SkipNoticeComponent from "./components/SkipNoticeComponent";
|
||||
import SubmissionNotice from "./render/SubmissionNotice";
|
||||
import { Message, MessageResponse, VoteResponse } from "./messageTypes";
|
||||
import * as Chat from "./js-components/chat";
|
||||
import { getCategoryActionType } from "./utils/categoryUtils";
|
||||
import { SkipButtonControlBar } from "./js-components/skipButtonControlBar";
|
||||
import { getStartTimeFromUrl } from "./utils/urlParser";
|
||||
import { findValidElement, getControls, getHashParams, isVisible } from "./utils/pageUtils";
|
||||
@@ -91,13 +90,11 @@ const playerButtons: Record<string, {button: HTMLButtonElement, image: HTMLImage
|
||||
|
||||
// Direct Links after the config is loaded
|
||||
utils.wait(() => Config.config !== null, 1000, 1).then(() => videoIDChange(getYouTubeVideoID(document)));
|
||||
// wait for hover preview to appear, and refresh attachments if ever found
|
||||
window.addEventListener("DOMContentLoaded", () => utils.waitForElement(".ytp-inline-preview-ui").then(() => refreshVideoAttachments()));
|
||||
addPageListeners();
|
||||
addHotkeyListener();
|
||||
|
||||
//the amount of times the sponsor lookup has retried
|
||||
//this only happens if there is an error
|
||||
let sponsorLookupRetries = 0;
|
||||
|
||||
/** Segments created by the user which have not yet been submitted. */
|
||||
let sponsorTimesSubmitting: SponsorTime[] = [];
|
||||
|
||||
@@ -237,7 +234,6 @@ function resetValues() {
|
||||
|
||||
//reset sponsor times
|
||||
sponsorTimes = null;
|
||||
sponsorLookupRetries = 0;
|
||||
sponsorSkipped = [];
|
||||
|
||||
videoInfo = null;
|
||||
@@ -689,9 +685,6 @@ async function sponsorsLookup(id: string, keepOldSubmissions = true) {
|
||||
|
||||
setupVideoMutationListener();
|
||||
|
||||
//check database for sponsor times
|
||||
//made true once a setTimeout has been created to try again after a server error
|
||||
let recheckStarted = false;
|
||||
// Create categories list
|
||||
const categories: string[] = [];
|
||||
for (const categorySelection of Config.config.categorySelections) {
|
||||
@@ -744,7 +737,7 @@ async function sponsorsLookup(id: string, keepOldSubmissions = true) {
|
||||
if (Config.config.minDuration !== 0) {
|
||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||
if (sponsorTimes[i].segment[1] - sponsorTimes[i].segment[0] < Config.config.minDuration
|
||||
&& getCategoryActionType(sponsorTimes[i].category) !== CategoryActionType.POI) {
|
||||
&& sponsorTimes[i].actionType !== ActionType.Poi) {
|
||||
sponsorTimes[i].hidden = SponsorHideType.MinimumDuration;
|
||||
}
|
||||
}
|
||||
@@ -770,29 +763,15 @@ async function sponsorsLookup(id: string, keepOldSubmissions = true) {
|
||||
//otherwise the listener can handle it
|
||||
updatePreviewBar();
|
||||
}
|
||||
|
||||
sponsorLookupRetries = 0;
|
||||
} else if (response?.status === 404) {
|
||||
retryFetch();
|
||||
} else if (sponsorLookupRetries < 15 && !recheckStarted) {
|
||||
recheckStarted = true;
|
||||
|
||||
//TODO lower when server becomes better (back to 1 second)
|
||||
//some error occurred, try again in a second
|
||||
setTimeout(() => {
|
||||
if (sponsorVideoID && sponsorTimes?.length === 0) {
|
||||
sponsorsLookup(sponsorVideoID);
|
||||
}
|
||||
}, 5000 + Math.random() * 15000 + 5000 * sponsorLookupRetries);
|
||||
|
||||
sponsorLookupRetries++;
|
||||
}
|
||||
|
||||
lookupVipInformation(id);
|
||||
}
|
||||
|
||||
function getEnabledActionTypes(): ActionType[] {
|
||||
const actionTypes = [ActionType.Skip, ActionType.Chapter];
|
||||
const actionTypes = [ActionType.Skip, ActionType.Poi, ActionType.Chapter];
|
||||
if (Config.config.muteSegments) {
|
||||
actionTypes.push(ActionType.Mute);
|
||||
}
|
||||
@@ -860,8 +839,6 @@ function retryFetch(): void {
|
||||
sponsorsLookup(sponsorVideoID);
|
||||
}
|
||||
}, 10000 + Math.random() * 30000);
|
||||
|
||||
sponsorLookupRetries = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -877,7 +854,7 @@ function startSkipScheduleCheckingForStartSponsors() {
|
||||
let startingSegment: SponsorTime = null;
|
||||
for (const time of sponsorTimes) {
|
||||
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSegmentTime && time.segment[1] > video.currentTime
|
||||
&& getCategoryActionType(time.category) === CategoryActionType.Skippable) {
|
||||
&& time.actionType !== ActionType.Poi) {
|
||||
startingSegmentTime = time.segment[0];
|
||||
startingSegment = time;
|
||||
found = true;
|
||||
@@ -887,7 +864,7 @@ function startSkipScheduleCheckingForStartSponsors() {
|
||||
if (!found) {
|
||||
for (const time of sponsorTimesSubmitting) {
|
||||
if (time.segment[0] <= video.currentTime && time.segment[0] > startingSegmentTime && time.segment[1] > video.currentTime
|
||||
&& getCategoryActionType(time.category) === CategoryActionType.Skippable) {
|
||||
&& time.actionType !== ActionType.Poi) {
|
||||
startingSegmentTime = time.segment[0];
|
||||
startingSegment = time;
|
||||
found = true;
|
||||
@@ -898,7 +875,7 @@ function startSkipScheduleCheckingForStartSponsors() {
|
||||
|
||||
// For highlight category
|
||||
const poiSegments = sponsorTimes
|
||||
.filter((time) => time.segment[1] > video.currentTime && getCategoryActionType(time.category) === CategoryActionType.POI)
|
||||
.filter((time) => time.segment[1] > video.currentTime && time.actionType === ActionType.Poi)
|
||||
.sort((a, b) => b.segment[0] - a.segment[0]);
|
||||
for (const time of poiSegments) {
|
||||
const skipOption = utils.getCategorySelection(time.category)?.option;
|
||||
@@ -956,7 +933,7 @@ function getYouTubeVideoID(document: Document): string | boolean {
|
||||
// skip to document if matches pattern
|
||||
if (url.includes("/channel/") || url.includes("/user/") || url.includes("/c/")) return getYouTubeVideoIDFromDocument(document);
|
||||
// not sure, try URL then document
|
||||
return getYouTubeVideoIDFromURL(url) || getYouTubeVideoIDFromDocument(document);
|
||||
return getYouTubeVideoIDFromURL(url) || getYouTubeVideoIDFromDocument(document, false);
|
||||
}
|
||||
|
||||
function getYouTubeVideoIDFromDocument(document: Document, hideIcon = true): string | boolean {
|
||||
@@ -1041,8 +1018,8 @@ function updatePreviewBar(): void {
|
||||
category: segment.category,
|
||||
actionType: segment.actionType,
|
||||
unsubmitted: false,
|
||||
showLarger: getCategoryActionType(segment.category) === CategoryActionType.POI,
|
||||
description: segment.description,
|
||||
showLarger: segment.actionType === ActionType.Poi,
|
||||
description: segment.description
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1053,8 +1030,8 @@ function updatePreviewBar(): void {
|
||||
category: segment.category,
|
||||
actionType: segment.actionType,
|
||||
unsubmitted: true,
|
||||
showLarger: getCategoryActionType(segment.category) === CategoryActionType.POI,
|
||||
description: segment.description,
|
||||
showLarger: segment.actionType === ActionType.Poi,
|
||||
description: segment.description
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1226,7 +1203,7 @@ function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments:
|
||||
|| (includeIntersectingSegments && possibleTimes[i].scheduledTime < minimum && possibleTimes[i].segment[1] > minimum)))
|
||||
&& (!hideHiddenSponsors || possibleTimes[i].hidden === SponsorHideType.Visible)
|
||||
&& possibleTimes[i].segment.length === 2
|
||||
&& getCategoryActionType(possibleTimes[i].category) === CategoryActionType.Skippable) {
|
||||
&& possibleTimes[i].actionType !== ActionType.Poi) {
|
||||
|
||||
scheduledTimes.push(possibleTimes[i].scheduledTime);
|
||||
includedTimes.push(possibleTimes[i]);
|
||||
@@ -1280,6 +1257,7 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
|
||||
if ((autoSkip || sponsorTimesSubmitting.some((time) => time.segment === skippingSegments[0].segment))
|
||||
&& v.currentTime !== skipTime[1]) {
|
||||
switch(skippingSegments[0].actionType) {
|
||||
case ActionType.Poi:
|
||||
case ActionType.Skip: {
|
||||
// Fix for looped videos not working when skipping to the end #426
|
||||
// for some reason you also can't skip to 1 second before the end
|
||||
@@ -1312,7 +1290,7 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
|
||||
|
||||
if (!autoSkip
|
||||
&& skippingSegments.length === 1
|
||||
&& getCategoryActionType(skippingSegments[0].category) === CategoryActionType.POI) {
|
||||
&& skippingSegments[0].actionType === ActionType.Poi) {
|
||||
skipButtonControlBar.enable(skippingSegments[0]);
|
||||
if (onMobileYouTube) skipButtonControlBar.setShowKeybindHint(false);
|
||||
|
||||
@@ -1403,7 +1381,7 @@ function createButton(baseID: string, title: string, callback: () => void, image
|
||||
function shouldAutoSkip(segment: SponsorTime): boolean {
|
||||
return utils.getCategorySelection(segment.category)?.option === CategorySkipOption.AutoSkip ||
|
||||
(Config.config.autoSkipOnMusicVideos && sponsorTimes?.some((s) => s.category === "music_offtopic")
|
||||
&& getCategoryActionType(segment.category) === CategoryActionType.Skippable);
|
||||
&& segment.actionType !== ActionType.Poi);
|
||||
}
|
||||
|
||||
function shouldSkip(segment: SponsorTime): boolean {
|
||||
|
||||
@@ -6,10 +6,9 @@ https://github.com/videosegments/videosegments/commits/f1e111bdfe231947800c6efdd
|
||||
'use strict';
|
||||
|
||||
import Config from "../config";
|
||||
import { ActionType, Category, CategoryActionType, SegmentContainer, SponsorTime } from "../types";
|
||||
import { ActionType, Category, SegmentContainer, SponsorTime } from "../types";
|
||||
import Utils from "../utils";
|
||||
import { partition } from "../utils/arrayUtils";
|
||||
import { getCategoryActionType } from "../utils/categoryUtils";
|
||||
const utils = new Utils();
|
||||
|
||||
const TOOLTIP_VISIBLE_CLASS = 'sponsorCategoryTooltipVisible';
|
||||
@@ -585,7 +584,7 @@ class PreviewBar {
|
||||
}
|
||||
|
||||
private chapterFilter(segment: PreviewBarSegment): boolean {
|
||||
return getCategoryActionType(segment.category) !== CategoryActionType.POI
|
||||
return segment.actionType !== ActionType.Poi
|
||||
&& this.chapterGroupFilter(segment);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import Config from "./config";
|
||||
|
||||
import Utils from "./utils";
|
||||
import { SponsorTime, SponsorHideType, CategoryActionType, ActionType, SegmentUUID } from "./types";
|
||||
import { SponsorTime, SponsorHideType, ActionType, SegmentUUID } from "./types";
|
||||
import { Message, MessageResponse, IsInfoFoundMessageResponse } from "./messageTypes";
|
||||
import { showDonationLink } from "./utils/configUtils";
|
||||
import { getCategoryActionType } from "./utils/categoryUtils";
|
||||
import { AnimationUtils } from "./utils/animationUtils";
|
||||
import { GenericUtils } from "./utils/genericUtils";
|
||||
const utils = new Utils();
|
||||
@@ -456,7 +455,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
segmentTimeFromToNode.innerText = chrome.i18n.getMessage("full");
|
||||
} else {
|
||||
segmentTimeFromToNode.innerText = utils.getFormattedTime(segmentTimes[i].segment[0], true) +
|
||||
(getCategoryActionType(category) !== CategoryActionType.POI
|
||||
(actionType !== ActionType.Poi
|
||||
? " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(segmentTimes[i].segment[1], true)
|
||||
: "");
|
||||
}
|
||||
|
||||
@@ -53,16 +53,12 @@ export enum SponsorHideType {
|
||||
MinimumDuration
|
||||
}
|
||||
|
||||
export enum CategoryActionType {
|
||||
Skippable = "", // Strings are used to find proper language configs
|
||||
POI = "_POI"
|
||||
}
|
||||
|
||||
export enum ActionType {
|
||||
Skip = "skip",
|
||||
Mute = "mute",
|
||||
Chapter = "chapter",
|
||||
Full = "full"
|
||||
Full = "full",
|
||||
Poi = "poi"
|
||||
}
|
||||
|
||||
export const ActionTypes = [ActionType.Skip, ActionType.Mute];
|
||||
|
||||
43
src/utils.ts
43
src/utils.ts
@@ -21,6 +21,10 @@ export default class Utils {
|
||||
"popup.css"
|
||||
];
|
||||
|
||||
/* Used for waitForElement */
|
||||
waitingMutationObserver:MutationObserver = null;
|
||||
waitingElements: { selector: string, callback: (element: Element) => void }[] = [];
|
||||
|
||||
constructor(backgroundScriptContainer: BackgroundScriptContainer = null) {
|
||||
this.backgroundScriptContainer = backgroundScriptContainer;
|
||||
}
|
||||
@@ -29,6 +33,41 @@ export default class Utils {
|
||||
return GenericUtils.wait(condition, timeout, check);
|
||||
}
|
||||
|
||||
/* Uses a mutation observer to wait asynchronously */
|
||||
async waitForElement(selector: string): Promise<Element> {
|
||||
return await new Promise((resolve) => {
|
||||
this.waitingElements.push({
|
||||
selector,
|
||||
callback: resolve
|
||||
});
|
||||
|
||||
if (!this.waitingMutationObserver) {
|
||||
this.waitingMutationObserver = new MutationObserver(() => {
|
||||
const foundSelectors = [];
|
||||
for (const { selector, callback } of this.waitingElements) {
|
||||
const element = document.querySelector(selector);
|
||||
if (element) {
|
||||
callback(element);
|
||||
foundSelectors.push(selector);
|
||||
}
|
||||
}
|
||||
|
||||
this.waitingElements = this.waitingElements.filter((element) => !foundSelectors.includes(element.selector));
|
||||
|
||||
if (this.waitingElements.length === 0) {
|
||||
this.waitingMutationObserver.disconnect();
|
||||
this.waitingMutationObserver = null;
|
||||
}
|
||||
});
|
||||
|
||||
this.waitingMutationObserver.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
containsPermission(permissions: chrome.permissions.Permissions): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
chrome.permissions.contains(permissions, resolve)
|
||||
@@ -331,9 +370,9 @@ export default class Utils {
|
||||
|
||||
findReferenceNode(): HTMLElement {
|
||||
const selectors = [
|
||||
"#player-container-id",
|
||||
"#movie_player",
|
||||
"#c4-player", // Channel Trailer
|
||||
"#player-container", // Preview on hover
|
||||
"#main-panel.ytmusic-player-page", // YouTube music
|
||||
"#player-container .video-js", // Invidious
|
||||
".main-video-section > .video-container" // Cloudtube
|
||||
@@ -347,7 +386,7 @@ export default class Utils {
|
||||
let index = 1;
|
||||
|
||||
//find the child that is the video player (sometimes it is not the first)
|
||||
while (index < player.children.length && (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed"))) {
|
||||
while (index < player.children.length && (!referenceNode.classList?.contains("html5-video-player") || !referenceNode.classList?.contains("ytp-embed"))) {
|
||||
referenceNode = player.children[index] as HTMLElement;
|
||||
|
||||
index++;
|
||||
|
||||
@@ -1,51 +1,41 @@
|
||||
import { ActionType, Category, CategoryActionType, SponsorTime } from "../types";
|
||||
import { ActionType, Category, SponsorTime } from "../types";
|
||||
|
||||
export function getSkippingText(segments: SponsorTime[], autoSkip: boolean): string {
|
||||
const categoryName = chrome.i18n.getMessage(segments.length > 1 ? "multipleSegments"
|
||||
: "category_" + segments[0].category + "_short") || chrome.i18n.getMessage("category_" + segments[0].category);
|
||||
if (autoSkip) {
|
||||
let messageId = "";
|
||||
if (getCategoryActionType(segments[0].category) === CategoryActionType.Skippable) {
|
||||
switch (segments[0].actionType) {
|
||||
case ActionType.Skip:
|
||||
messageId = "skipped";
|
||||
break;
|
||||
case ActionType.Mute:
|
||||
messageId = "muted";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
messageId = "skipped_to_category";
|
||||
switch (segments[0].actionType) {
|
||||
case ActionType.Skip:
|
||||
messageId = "skipped";
|
||||
break;
|
||||
case ActionType.Mute:
|
||||
messageId = "muted";
|
||||
break;
|
||||
case ActionType.Poi:
|
||||
messageId = "skipped_to_category";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return chrome.i18n.getMessage(messageId).replace("{0}", categoryName);
|
||||
} else {
|
||||
let messageId = "";
|
||||
if (getCategoryActionType(segments[0].category) === CategoryActionType.Skippable) {
|
||||
switch (segments[0].actionType) {
|
||||
case ActionType.Skip:
|
||||
messageId = "skip_category";
|
||||
break;
|
||||
case ActionType.Mute:
|
||||
messageId = "mute_category";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
messageId = "skip_to_category";
|
||||
switch (segments[0].actionType) {
|
||||
case ActionType.Skip:
|
||||
messageId = "skip_category";
|
||||
break;
|
||||
case ActionType.Mute:
|
||||
messageId = "mute_category";
|
||||
break;
|
||||
case ActionType.Poi:
|
||||
messageId = "skip_to_category";
|
||||
break;
|
||||
}
|
||||
|
||||
return chrome.i18n.getMessage(messageId).replace("{0}", categoryName);
|
||||
}
|
||||
}
|
||||
|
||||
export function getCategoryActionType(category: Category): CategoryActionType {
|
||||
if (category.startsWith("poi_")) {
|
||||
return CategoryActionType.POI;
|
||||
} else {
|
||||
return CategoryActionType.Skippable;
|
||||
}
|
||||
}
|
||||
|
||||
export function getCategorySuffix(category: Category): string {
|
||||
if (category.startsWith("poi_")) {
|
||||
return "_POI";
|
||||
|
||||
Reference in New Issue
Block a user