mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-06 19:47:04 +03:00
Merge pull request #569 from opl-/cleanup/segment-creation
Clean up segment creation code
This commit is contained in:
@@ -79,6 +79,9 @@
|
|||||||
"sponsorEnd": {
|
"sponsorEnd": {
|
||||||
"message": "Segment Ends Now"
|
"message": "Segment Ends Now"
|
||||||
},
|
},
|
||||||
|
"sponsorCancel": {
|
||||||
|
"message": "Cancel Creating Segment"
|
||||||
|
},
|
||||||
"noVideoID": {
|
"noVideoID": {
|
||||||
"message": "No YouTube video found.\nIf this is incorrect, refresh the tab."
|
"message": "No YouTube video found.\nIf this is incorrect, refresh the tab."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -79,6 +79,9 @@
|
|||||||
"sponsorEnd": {
|
"sponsorEnd": {
|
||||||
"message": "Koniec segmentu"
|
"message": "Koniec segmentu"
|
||||||
},
|
},
|
||||||
|
"sponsorCancel": {
|
||||||
|
"message": "Anuluj tworzenie segmentu"
|
||||||
|
},
|
||||||
"noVideoID": {
|
"noVideoID": {
|
||||||
"message": "Nie znaleziono filmu YouTube.\nJeżeli to błąd, odśwież stronę."
|
"message": "Nie znaleziono filmu YouTube.\nJeżeli to błąd, odśwież stronę."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="submissionSection" style="display: none">
|
<div id="submissionSection" style="display: none">
|
||||||
<b style="display: block; margin-top: 12px;">__MSG_submissionEditHint__</b>
|
<b style="display: block; margin-top: 12px;">__MSG_submissionEditHint__</b>
|
||||||
<div id="submitTimesContainer" style="display: none; margin-top: 12px;">
|
<div id="submitTimesContainer" style="margin-top: 12px;">
|
||||||
<button id="submitTimes" class="mediumButton">__MSG_submitTimesButton__</button>
|
<button id="submitTimes" class="mediumButton">__MSG_submitTimesButton__</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
|||||||
//if it is not a complete sponsor time
|
//if it is not a complete sponsor time
|
||||||
if (sponsorTimes[index].segment.length < 2) {
|
if (sponsorTimes[index].segment.length < 2) {
|
||||||
//update video player
|
//update video player
|
||||||
this.props.contentContainer().changeStartSponsorButton(true, false);
|
this.props.contentContainer().updateEditButtonsOnPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
sponsorTimes.splice(index, 1);
|
sponsorTimes.splice(index, 1);
|
||||||
@@ -359,7 +359,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
|
|||||||
this.props.submissionNotice.cancel();
|
this.props.submissionNotice.cancel();
|
||||||
|
|
||||||
//update video player
|
//update video player
|
||||||
this.props.contentContainer().changeStartSponsorButton(true, false);
|
this.props.contentContainer().updateEditButtonsOnPlayer();
|
||||||
} else {
|
} else {
|
||||||
//update display
|
//update display
|
||||||
this.props.submissionNotice.forceUpdate();
|
this.props.submissionNotice.forceUpdate();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const utils = new Utils();
|
|||||||
|
|
||||||
interface SBConfig {
|
interface SBConfig {
|
||||||
userID: string,
|
userID: string,
|
||||||
|
/** Contains unsubmitted segments that the user has created. */
|
||||||
segmentTimes: SBMap<string, SponsorTime[]>,
|
segmentTimes: SBMap<string, SponsorTime[]>,
|
||||||
defaultCategory: string,
|
defaultCategory: string,
|
||||||
whitelistedChannels: string[],
|
whitelistedChannels: string[],
|
||||||
|
|||||||
327
src/content.ts
327
src/content.ts
@@ -1,6 +1,6 @@
|
|||||||
import Config from "./config";
|
import Config from "./config";
|
||||||
|
|
||||||
import { SponsorTime, CategorySkipOption, VideoID, SponsorHideType, FetchResponse, VideoInfo, StorageChangesObject } from "./types";
|
import { SponsorTime, IncompleteSponsorTime, CategorySkipOption, VideoID, SponsorHideType, FetchResponse, VideoInfo, StorageChangesObject } from "./types";
|
||||||
|
|
||||||
import { ContentContainer } from "./types";
|
import { ContentContainer } from "./types";
|
||||||
import Utils from "./utils";
|
import Utils from "./utils";
|
||||||
@@ -71,8 +71,11 @@ let channelWhitelisted = false;
|
|||||||
// create preview bar
|
// create preview bar
|
||||||
let previewBar: PreviewBar = null;
|
let previewBar: PreviewBar = null;
|
||||||
|
|
||||||
//the player controls on the YouTube player
|
/** Element containing the player controls on the YouTube player. */
|
||||||
let controls = null;
|
let controls: HTMLElement | null = null;
|
||||||
|
|
||||||
|
/** Contains buttons created by `createButton()`. */
|
||||||
|
const playerButtons: Record<string, {button: HTMLButtonElement, image: HTMLImageElement}> = {};
|
||||||
|
|
||||||
// Direct Links after the config is loaded
|
// Direct Links after the config is loaded
|
||||||
utils.wait(() => Config.config !== null, 1000, 1).then(() => videoIDChange(getYouTubeVideoID(document.URL)));
|
utils.wait(() => Config.config !== null, 1000, 1).then(() => videoIDChange(getYouTubeVideoID(document.URL)));
|
||||||
@@ -81,10 +84,10 @@ utils.wait(() => Config.config !== null, 1000, 1).then(() => videoIDChange(getYo
|
|||||||
//this only happens if there is an error
|
//this only happens if there is an error
|
||||||
let sponsorLookupRetries = 0;
|
let sponsorLookupRetries = 0;
|
||||||
|
|
||||||
//if showing the start sponsor button or the end sponsor button on the player
|
/** Currently timed segment, which will be added to the unsubmitted segments when ready. */
|
||||||
let showingStartSponsor = true;
|
let currentlyTimedSegment: IncompleteSponsorTime | null = null;
|
||||||
|
|
||||||
//the sponsor times being prepared to be submitted
|
/** Segments created by the user which have not yet been submitted. */
|
||||||
let sponsorTimesSubmitting: SponsorTime[] = [];
|
let sponsorTimesSubmitting: SponsorTime[] = [];
|
||||||
|
|
||||||
//becomes true when isInfoFound is called
|
//becomes true when isInfoFound is called
|
||||||
@@ -111,7 +114,7 @@ const skipNoticeContentContainer: ContentContainer = () => ({
|
|||||||
onMobileYouTube,
|
onMobileYouTube,
|
||||||
sponsorSubmissionNotice: submissionNotice,
|
sponsorSubmissionNotice: submissionNotice,
|
||||||
resetSponsorSubmissionNotice,
|
resetSponsorSubmissionNotice,
|
||||||
changeStartSponsorButton,
|
updateEditButtonsOnPlayer,
|
||||||
previewTime,
|
previewTime,
|
||||||
videoInfo,
|
videoInfo,
|
||||||
getRealCurrentTime: getRealCurrentTime
|
getRealCurrentTime: getRealCurrentTime
|
||||||
@@ -127,11 +130,11 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
|||||||
videoIDChange(getYouTubeVideoID(document.URL));
|
videoIDChange(getYouTubeVideoID(document.URL));
|
||||||
break;
|
break;
|
||||||
case "sponsorStart":
|
case "sponsorStart":
|
||||||
sponsorMessageStarted(sendResponse);
|
startOrEndTimingNewSegment()
|
||||||
|
|
||||||
break;
|
sendResponse({
|
||||||
case "sponsorDataChanged":
|
creatingSegment: currentlyTimedSegment !== null,
|
||||||
updateSponsorTimesSubmitting();
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "isInfoFound":
|
case "isInfoFound":
|
||||||
@@ -150,7 +153,8 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
|||||||
break;
|
break;
|
||||||
case "getVideoID":
|
case "getVideoID":
|
||||||
sendResponse({
|
sendResponse({
|
||||||
videoID: sponsorVideoID
|
videoID: sponsorVideoID,
|
||||||
|
creatingSegment: currentlyTimedSegment !== null,
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -170,10 +174,6 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
|
|||||||
channelWhitelisted = request.value;
|
channelWhitelisted = request.value;
|
||||||
sponsorsLookup(sponsorVideoID);
|
sponsorsLookup(sponsorVideoID);
|
||||||
|
|
||||||
break;
|
|
||||||
case "changeStartSponsorButton":
|
|
||||||
changeStartSponsorButton(request.showStartSponsor, request.uploadButtonVisible);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "submitTimes":
|
case "submitTimes":
|
||||||
submitSponsorTimes();
|
submitSponsorTimes();
|
||||||
@@ -301,30 +301,18 @@ async function videoIDChange(id) {
|
|||||||
|
|
||||||
sponsorsLookup(id);
|
sponsorsLookup(id);
|
||||||
|
|
||||||
//make sure everything is properly added
|
// Make sure all player buttons are properly added
|
||||||
updateVisibilityOfPlayerControlsButton().then(() => {
|
|
||||||
//see if the onvideo control image needs to be changed
|
|
||||||
const segments = Config.config.segmentTimes.get(sponsorVideoID);
|
|
||||||
if (segments != null && segments.length > 0 && segments[segments.length - 1].segment.length >= 2) {
|
|
||||||
changeStartSponsorButton(true, true);
|
|
||||||
} else if (segments != null && segments.length > 0 && segments[segments.length - 1].segment.length < 2) {
|
|
||||||
changeStartSponsorButton(false, true);
|
|
||||||
} else {
|
|
||||||
changeStartSponsorButton(true, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//reset sponsor times submitting
|
|
||||||
sponsorTimesSubmitting = [];
|
|
||||||
updateSponsorTimesSubmitting();
|
|
||||||
|
|
||||||
//see if video controls buttons should be added
|
|
||||||
if (!onInvidious) {
|
|
||||||
updateVisibilityOfPlayerControlsButton();
|
updateVisibilityOfPlayerControlsButton();
|
||||||
}
|
|
||||||
|
// Clear unsubmitted segments from the previous video
|
||||||
|
sponsorTimesSubmitting = [];
|
||||||
|
currentlyTimedSegment = null;
|
||||||
|
updateSponsorTimesSubmitting();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMobileControlsMutations(): void {
|
function handleMobileControlsMutations(): void {
|
||||||
|
updateVisibilityOfPlayerControlsButton();
|
||||||
|
|
||||||
if (previewBar !== null) {
|
if (previewBar !== null) {
|
||||||
if (document.body.contains(previewBar.container)) {
|
if (document.body.contains(previewBar.container)) {
|
||||||
const progressBarBackground = document.querySelector<HTMLElement>(".progress-bar-background");
|
const progressBarBackground = document.querySelector<HTMLElement>(".progress-bar-background");
|
||||||
@@ -1043,8 +1031,9 @@ function reskipSponsorTime(segment: SponsorTime) {
|
|||||||
startSponsorSchedule(true, segment.segment[1], false);
|
startSponsorSchedule(true, segment.segment[1], false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createButton(baseID, title, callback, imageName, isDraggable=false): boolean {
|
function createButton(baseID: string, title: string, callback: () => void, imageName: string, isDraggable = false): HTMLElement {
|
||||||
if (document.getElementById(baseID + "Button") != null) return false;
|
const existingElement = document.getElementById(baseID + "Button");
|
||||||
|
if (existingElement !== null) return existingElement;
|
||||||
|
|
||||||
// Button HTML
|
// Button HTML
|
||||||
const newButton = document.createElement("button");
|
const newButton = document.createElement("button");
|
||||||
@@ -1068,9 +1057,15 @@ function createButton(baseID, title, callback, imageName, isDraggable=false): bo
|
|||||||
newButton.appendChild(newButtonImage);
|
newButton.appendChild(newButtonImage);
|
||||||
|
|
||||||
// Add the button to player
|
// Add the button to player
|
||||||
controls.prepend(newButton);
|
if (controls) controls.prepend(newButton);
|
||||||
|
|
||||||
return true;
|
// Store the elements to prevent unnecessary querying
|
||||||
|
playerButtons[baseID] = {
|
||||||
|
button: newButton,
|
||||||
|
image: newButtonImage,
|
||||||
|
};
|
||||||
|
|
||||||
|
return newButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getControls(): HTMLElement | false {
|
function getControls(): HTMLElement | false {
|
||||||
@@ -1080,8 +1075,8 @@ function getControls(): HTMLElement | false {
|
|||||||
// Mobile YouTube
|
// Mobile YouTube
|
||||||
".player-controls-top",
|
".player-controls-top",
|
||||||
// Invidious/videojs video element's controls element
|
// Invidious/videojs video element's controls element
|
||||||
".vjs-control-bar"
|
".vjs-control-bar",
|
||||||
]
|
];
|
||||||
|
|
||||||
for (const controlsSelector of controlsSelectors) {
|
for (const controlsSelector of controlsSelectors) {
|
||||||
const controls = document.querySelectorAll(controlsSelector);
|
const controls = document.querySelectorAll(controlsSelector);
|
||||||
@@ -1094,53 +1089,75 @@ function getControls(): HTMLElement | false {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//adds all the player controls buttons
|
/** Creates any missing buttons on the YouTube player if possible. */
|
||||||
async function createButtons(): Promise<boolean> {
|
async function createButtons(): Promise<void> {
|
||||||
if (onMobileYouTube) return;
|
if (onMobileYouTube) return;
|
||||||
|
|
||||||
const result = await utils.wait(getControls).catch();
|
controls = await utils.wait(getControls).catch();
|
||||||
|
|
||||||
//set global controls variable
|
|
||||||
controls = result;
|
|
||||||
|
|
||||||
let createdButton = false;
|
|
||||||
|
|
||||||
// Add button if does not already exist in html
|
// Add button if does not already exist in html
|
||||||
createdButton = createButton("startSponsor", "sponsorStart", startSponsorClicked, "PlayerStartIconSponsorBlocker256px.png") || createdButton;
|
createButton("startSponsor", "sponsorStart", () => closeInfoMenuAnd(() => startOrEndTimingNewSegment()), "PlayerStartIconSponsorBlocker256px.png");
|
||||||
createdButton = createButton("info", "openPopup", openInfoMenu, "PlayerInfoIconSponsorBlocker256px.png") || createdButton;
|
createButton("cancelSponsor", "sponsorCancel", () => closeInfoMenuAnd(() => cancelCreatingSegment()), "PlayerUploadFailedIconSponsorBlocker256px.png");
|
||||||
createdButton = createButton("delete", "clearTimes", clearSponsorTimes, "PlayerDeleteIconSponsorBlocker256px.png") || createdButton;
|
createButton("info", "openPopup", openInfoMenu, "PlayerInfoIconSponsorBlocker256px.png");
|
||||||
createdButton = createButton("submit", "SubmitTimes", submitSponsorTimes, "PlayerUploadIconSponsorBlocker256px.png") || createdButton;
|
createButton("delete", "clearTimes", () => closeInfoMenuAnd(() => clearSponsorTimes()), "PlayerDeleteIconSponsorBlocker256px.png");
|
||||||
|
createButton("submit", "SubmitTimes", submitSponsorTimes, "PlayerUploadIconSponsorBlocker256px.png");
|
||||||
return createdButton;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//adds or removes the player controls button to what it should be
|
/** Creates any missing buttons on the player and updates their visiblity. */
|
||||||
async function updateVisibilityOfPlayerControlsButton(): Promise<boolean> {
|
async function updateVisibilityOfPlayerControlsButton(): Promise<void> {
|
||||||
//not on a proper video yet
|
// Not on a proper video yet
|
||||||
if (!sponsorVideoID) return false;
|
if (!sponsorVideoID) return;
|
||||||
|
|
||||||
const createdButtons = await createButtons();
|
await createButtons();
|
||||||
if (!createdButtons) return;
|
|
||||||
|
|
||||||
if (Config.config.hideVideoPlayerControls || onInvidious) {
|
updateEditButtonsOnPlayer();
|
||||||
document.getElementById("startSponsorButton").style.display = "none";
|
|
||||||
document.getElementById("submitButton").style.display = "none";
|
|
||||||
} else {
|
|
||||||
document.getElementById("startSponsorButton").style.removeProperty("display");
|
|
||||||
}
|
|
||||||
|
|
||||||
//don't show the info button on embeds
|
// Don't show the info button on embeds
|
||||||
if (Config.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious) {
|
if (Config.config.hideInfoButtonPlayerControls || document.URL.includes("/embed/") || onInvidious) {
|
||||||
document.getElementById("infoButton").style.display = "none";
|
playerButtons.info.button.style.display = "none";
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("infoButton").style.removeProperty("display");
|
playerButtons.info.button.style.removeProperty("display");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.config.hideDeleteButtonPlayerControls || onInvidious) {
|
/** Updates the visibility of buttons on the player related to creating segments. */
|
||||||
document.getElementById("deleteButton").style.display = "none";
|
function updateEditButtonsOnPlayer(): void {
|
||||||
|
// Don't try to update the buttons if we aren't on a YouTube video page
|
||||||
|
if (!sponsorVideoID) return;
|
||||||
|
|
||||||
|
const buttonsEnabled = !Config.config.hideVideoPlayerControls && !onInvidious;
|
||||||
|
|
||||||
|
let creatingSegment = false;
|
||||||
|
let submitButtonVisible = false;
|
||||||
|
let deleteButtonVisible = false;
|
||||||
|
|
||||||
|
// Only check if buttons should be visible if they're enabled
|
||||||
|
if (buttonsEnabled) {
|
||||||
|
creatingSegment = currentlyTimedSegment !== null;
|
||||||
|
|
||||||
|
// Show only if there are any segments to submit
|
||||||
|
submitButtonVisible = sponsorTimesSubmitting.length > 0;
|
||||||
|
|
||||||
|
// Show only if there are any segments to delete
|
||||||
|
deleteButtonVisible = sponsorTimesSubmitting.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return createdButtons;
|
// Update the elements
|
||||||
|
playerButtons.startSponsor.button.style.display = buttonsEnabled ? "unset" : "none";
|
||||||
|
playerButtons.cancelSponsor.button.style.display = buttonsEnabled && creatingSegment ? "unset" : "none";
|
||||||
|
|
||||||
|
if (buttonsEnabled) {
|
||||||
|
if (creatingSegment) {
|
||||||
|
playerButtons.startSponsor.image.src = chrome.extension.getURL("icons/PlayerStopIconSponsorBlocker256px.png");
|
||||||
|
playerButtons.startSponsor.button.setAttribute("title", chrome.i18n.getMessage("sponsorEnd"));
|
||||||
|
} else {
|
||||||
|
playerButtons.startSponsor.image.src = chrome.extension.getURL("icons/PlayerStartIconSponsorBlocker256px.png");
|
||||||
|
playerButtons.startSponsor.button.setAttribute("title", chrome.i18n.getMessage("sponsorStart"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
playerButtons.submit.button.style.display = submitButtonVisible && !Config.config.hideUploadButtonPlayerControls ? "unset" : "none";
|
||||||
|
playerButtons.delete.button.style.display = deleteButtonVisible && !Config.config.hideDeleteButtonPlayerControls ? "unset" : "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1161,30 +1178,40 @@ function getRealCurrentTime(): number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startSponsorClicked() {
|
function startOrEndTimingNewSegment() {
|
||||||
//it can't update to this info yet
|
if (!currentlyTimedSegment) {
|
||||||
closeInfoMenu();
|
// Start a new segment
|
||||||
|
currentlyTimedSegment = {
|
||||||
toggleStartSponsorButton();
|
|
||||||
|
|
||||||
//add to sponsorTimes
|
|
||||||
if (sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment.length < 2) {
|
|
||||||
//it is an end time
|
|
||||||
sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment[1] = getRealCurrentTime();
|
|
||||||
sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].segment.sort((a, b) => a > b ? 1 : (a < b ? -1 : 0));
|
|
||||||
} else {
|
|
||||||
//it is a start time
|
|
||||||
sponsorTimesSubmitting.push({
|
|
||||||
segment: [getRealCurrentTime()],
|
segment: [getRealCurrentTime()],
|
||||||
UUID: null,
|
UUID: null,
|
||||||
category: Config.config.defaultCategory
|
category: Config.config.defaultCategory,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Finish creating the new segment
|
||||||
|
const existingTime = currentlyTimedSegment.segment[0];
|
||||||
|
const currentTime = getRealCurrentTime();
|
||||||
|
|
||||||
|
sponsorTimesSubmitting.push({
|
||||||
|
...currentlyTimedSegment,
|
||||||
|
// Swap timestamps if the user put the segment end before the start
|
||||||
|
segment: [Math.min(existingTime, currentTime), Math.max(existingTime, currentTime)],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
currentlyTimedSegment = null;
|
||||||
|
|
||||||
|
// Save the newly created segment
|
||||||
|
Config.config.segmentTimes.set(sponsorVideoID, sponsorTimesSubmitting);
|
||||||
}
|
}
|
||||||
|
|
||||||
//save this info
|
updateEditButtonsOnPlayer();
|
||||||
Config.config.segmentTimes.set(sponsorVideoID, sponsorTimesSubmitting);
|
|
||||||
|
|
||||||
updateSponsorTimesSubmitting(false)
|
updateSponsorTimesSubmitting(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelCreatingSegment() {
|
||||||
|
currentlyTimedSegment = null;
|
||||||
|
|
||||||
|
updateEditButtonsOnPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSponsorTimesSubmitting(getFromConfig = true) {
|
function updateSponsorTimesSubmitting(getFromConfig = true) {
|
||||||
@@ -1213,38 +1240,6 @@ function updateSponsorTimesSubmitting(getFromConfig = true) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeStartSponsorButton(showStartSponsor: boolean, uploadButtonVisible: boolean): Promise<boolean> {
|
|
||||||
if(!sponsorVideoID || onMobileYouTube) return false;
|
|
||||||
|
|
||||||
//if it isn't visible, there is no data
|
|
||||||
const shouldHide = (uploadButtonVisible && !(Config.config.hideDeleteButtonPlayerControls || onInvidious)) ? "unset" : "none"
|
|
||||||
document.getElementById("deleteButton").style.display = shouldHide;
|
|
||||||
|
|
||||||
if (showStartSponsor) {
|
|
||||||
showingStartSponsor = true;
|
|
||||||
(<HTMLImageElement> document.getElementById("startSponsorImage")).src = chrome.extension.getURL("icons/PlayerStartIconSponsorBlocker256px.png");
|
|
||||||
document.getElementById("startSponsorButton").setAttribute("title", chrome.i18n.getMessage("sponsorStart"));
|
|
||||||
|
|
||||||
if (document.getElementById("startSponsorImage").style.display != "none" && uploadButtonVisible && !Config.config.hideUploadButtonPlayerControls && !onInvidious) {
|
|
||||||
document.getElementById("submitButton").style.display = "unset";
|
|
||||||
} else if (!uploadButtonVisible || onInvidious) {
|
|
||||||
//disable submit button
|
|
||||||
document.getElementById("submitButton").style.display = "none";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showingStartSponsor = false;
|
|
||||||
(<HTMLImageElement> document.getElementById("startSponsorImage")).src = chrome.extension.getURL("icons/PlayerStopIconSponsorBlocker256px.png");
|
|
||||||
document.getElementById("startSponsorButton").setAttribute("title", chrome.i18n.getMessage("sponsorEND"));
|
|
||||||
|
|
||||||
//disable submit button
|
|
||||||
document.getElementById("submitButton").style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleStartSponsorButton() {
|
|
||||||
changeStartSponsorButton(!showingStartSponsor, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function openInfoMenu() {
|
function openInfoMenu() {
|
||||||
if (document.getElementById("sponsorBlockPopupContainer") != null) {
|
if (document.getElementById("sponsorBlockPopupContainer") != null) {
|
||||||
//it's already added
|
//it's already added
|
||||||
@@ -1254,7 +1249,7 @@ function openInfoMenu() {
|
|||||||
popupInitialised = false;
|
popupInitialised = false;
|
||||||
|
|
||||||
//hide info button
|
//hide info button
|
||||||
document.getElementById("infoButton").style.display = "none";
|
if (playerButtons.info) playerButtons.info.button.style.display = "none";
|
||||||
|
|
||||||
sendRequestToCustomServer('GET', chrome.extension.getURL("popup.html"), function(xmlhttp) {
|
sendRequestToCustomServer('GET', chrome.extension.getURL("popup.html"), function(xmlhttp) {
|
||||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||||
@@ -1316,20 +1311,28 @@ function openInfoMenu() {
|
|||||||
|
|
||||||
function closeInfoMenu() {
|
function closeInfoMenu() {
|
||||||
const popup = document.getElementById("sponsorBlockPopupContainer");
|
const popup = document.getElementById("sponsorBlockPopupContainer");
|
||||||
if (popup != null) {
|
if (popup === null) return;
|
||||||
|
|
||||||
popup.remove();
|
popup.remove();
|
||||||
|
|
||||||
//show info button if it's not an embed
|
// Show info button if it's not an embed
|
||||||
if (!document.URL.includes("/embed/")) {
|
if (!document.URL.includes("/embed/") && playerButtons.info) {
|
||||||
document.getElementById("infoButton").style.display = "unset";
|
playerButtons.info.button.style.display = "unset";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content script currently has no way to notify the info menu of changes. As a workaround we close it, thus making it query the new information when reopened.
|
||||||
|
*
|
||||||
|
* This function and all its uses should be removed when this issue is fixed.
|
||||||
|
* */
|
||||||
|
function closeInfoMenuAnd<T>(func: () => T): T {
|
||||||
|
closeInfoMenu();
|
||||||
|
|
||||||
|
return func();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearSponsorTimes() {
|
function clearSponsorTimes() {
|
||||||
//it can't update to this info yet
|
|
||||||
closeInfoMenu();
|
|
||||||
|
|
||||||
const currentVideoID = sponsorVideoID;
|
const currentVideoID = sponsorVideoID;
|
||||||
|
|
||||||
const sponsorTimes = Config.config.segmentTimes.get(currentVideoID);
|
const sponsorTimes = Config.config.segmentTimes.get(currentVideoID);
|
||||||
@@ -1347,8 +1350,7 @@ function clearSponsorTimes() {
|
|||||||
|
|
||||||
updatePreviewBar();
|
updatePreviewBar();
|
||||||
|
|
||||||
//set buttons to be correct
|
updateEditButtonsOnPlayer();
|
||||||
changeStartSponsorButton(true, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1414,18 +1416,6 @@ function dontShowNoticeAgain() {
|
|||||||
closeAllSkipNotices();
|
closeAllSkipNotices();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sponsorMessageStarted(callback: (response: MessageResponse) => void) {
|
|
||||||
video = document.querySelector('video');
|
|
||||||
|
|
||||||
//send back current time
|
|
||||||
callback({
|
|
||||||
time: video.currentTime
|
|
||||||
})
|
|
||||||
|
|
||||||
//update button
|
|
||||||
toggleStartSponsorButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method for the submission notice to clear itself when it closes
|
* Helper method for the submission notice to clear itself when it closes
|
||||||
*/
|
*/
|
||||||
@@ -1436,9 +1426,6 @@ function resetSponsorSubmissionNotice() {
|
|||||||
function submitSponsorTimes() {
|
function submitSponsorTimes() {
|
||||||
if (submissionNotice !== null) return;
|
if (submissionNotice !== null) return;
|
||||||
|
|
||||||
//it can't update to this info yet
|
|
||||||
closeInfoMenu();
|
|
||||||
|
|
||||||
if (sponsorTimesSubmitting !== undefined && sponsorTimesSubmitting.length > 0) {
|
if (sponsorTimesSubmitting !== undefined && sponsorTimesSubmitting.length > 0) {
|
||||||
submissionNotice = new SubmissionNotice(skipNoticeContentContainer, sendSubmitMessage);
|
submissionNotice = new SubmissionNotice(skipNoticeContentContainer, sendSubmitMessage);
|
||||||
}
|
}
|
||||||
@@ -1447,10 +1434,10 @@ function submitSponsorTimes() {
|
|||||||
|
|
||||||
//send the message to the background js
|
//send the message to the background js
|
||||||
//called after all the checks have been made that it's okay to do so
|
//called after all the checks have been made that it's okay to do so
|
||||||
async function sendSubmitMessage(): Promise<void> {
|
async function sendSubmitMessage() {
|
||||||
//add loading animation
|
// Add loading animation
|
||||||
(<HTMLImageElement> document.getElementById("submitImage")).src = chrome.extension.getURL("icons/PlayerUploadIconSponsorBlocker256px.png");
|
playerButtons.submit.image.src = chrome.extension.getURL("icons/PlayerUploadIconSponsorBlocker256px.png");
|
||||||
document.getElementById("submitButton").style.animation = "rotate 1s 0s infinite";
|
playerButtons.submit.button.style.animation = "rotate 1s 0s infinite";
|
||||||
|
|
||||||
//check if a sponsor exceeds the duration of the video
|
//check if a sponsor exceeds the duration of the video
|
||||||
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
|
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
|
||||||
@@ -1477,17 +1464,19 @@ async function sendSubmitMessage(): Promise<void> {
|
|||||||
const response = await utils.asyncRequestToServer("POST", "/api/skipSegments", {
|
const response = await utils.asyncRequestToServer("POST", "/api/skipSegments", {
|
||||||
videoID: sponsorVideoID,
|
videoID: sponsorVideoID,
|
||||||
userID: Config.config.userID,
|
userID: Config.config.userID,
|
||||||
segments: sponsorTimesSubmitting
|
segments: sponsorTimesSubmitting,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
//hide loading message
|
// Handle submission success
|
||||||
const submitButton = document.getElementById("submitButton");
|
const submitButton = playerButtons.submit.button;
|
||||||
|
|
||||||
|
// Make the animation finite
|
||||||
submitButton.style.animation = "rotate 1s";
|
submitButton.style.animation = "rotate 1s";
|
||||||
//finish this animation
|
|
||||||
//when the animation is over, hide the button
|
// When the animation is over, hide the button
|
||||||
const animationEndListener = function() {
|
const animationEndListener = () => {
|
||||||
changeStartSponsorButton(true, false);
|
updateEditButtonsOnPlayer();
|
||||||
|
|
||||||
submitButton.style.animation = "none";
|
submitButton.style.animation = "none";
|
||||||
|
|
||||||
@@ -1496,13 +1485,12 @@ async function sendSubmitMessage(): Promise<void> {
|
|||||||
|
|
||||||
submitButton.addEventListener("animationend", animationEndListener);
|
submitButton.addEventListener("animationend", animationEndListener);
|
||||||
|
|
||||||
//clear the sponsor times
|
// Remove segments from storage since they've already been submitted
|
||||||
Config.config.segmentTimes.delete(sponsorVideoID);
|
Config.config.segmentTimes.delete(sponsorVideoID);
|
||||||
|
|
||||||
//add submissions to current sponsors list
|
// Add submissions to current sponsors list
|
||||||
if (sponsorTimes === null) sponsorTimes = [];
|
// FIXME: segments from sponsorTimesSubmitting do not contain UUIDs .-.
|
||||||
|
sponsorTimes = (sponsorTimes || []).concat(sponsorTimesSubmitting);
|
||||||
sponsorTimes = sponsorTimes.concat(sponsorTimesSubmitting);
|
|
||||||
|
|
||||||
// Increase contribution count
|
// Increase contribution count
|
||||||
Config.config.sponsorTimesContributed = Config.config.sponsorTimesContributed + sponsorTimesSubmitting.length;
|
Config.config.sponsorTimesContributed = Config.config.sponsorTimesContributed + sponsorTimesSubmitting.length;
|
||||||
@@ -1512,13 +1500,14 @@ async function sendSubmitMessage(): Promise<void> {
|
|||||||
Config.config.submissionCountSinceCategories = Config.config.submissionCountSinceCategories + 1;
|
Config.config.submissionCountSinceCategories = Config.config.submissionCountSinceCategories + 1;
|
||||||
|
|
||||||
// Empty the submitting times
|
// Empty the submitting times
|
||||||
|
currentlyTimedSegment = null;
|
||||||
sponsorTimesSubmitting = [];
|
sponsorTimesSubmitting = [];
|
||||||
|
|
||||||
updatePreviewBar();
|
updatePreviewBar();
|
||||||
} else {
|
} else {
|
||||||
//show that the upload failed
|
// Show that the upload failed
|
||||||
document.getElementById("submitButton").style.animation = "unset";
|
playerButtons.submit.button.style.animation = "unset";
|
||||||
(<HTMLImageElement> document.getElementById("submitImage")).src = chrome.extension.getURL("icons/PlayerUploadFailedIconSponsorBlocker256px.png");
|
playerButtons.submit.image.src = chrome.extension.getURL("icons/PlayerUploadFailedIconSponsorBlocker256px.png");
|
||||||
|
|
||||||
alert(utils.getErrorMessage(response.status, response.responseText));
|
alert(utils.getErrorMessage(response.status, response.responseText));
|
||||||
}
|
}
|
||||||
@@ -1575,7 +1564,7 @@ function hotkeyListener(e: KeyboardEvent): void {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case startSponsorKey:
|
case startSponsorKey:
|
||||||
startSponsorClicked();
|
startOrEndTimingNewSegment();
|
||||||
break;
|
break;
|
||||||
case submitKey:
|
case submitKey:
|
||||||
submitSponsorTimes();
|
submitSponsorTimes();
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ interface DefaultMessage {
|
|||||||
message:
|
message:
|
||||||
"update"
|
"update"
|
||||||
| "sponsorStart"
|
| "sponsorStart"
|
||||||
| "sponsorDataChanged"
|
|
||||||
| "isInfoFound"
|
| "isInfoFound"
|
||||||
| "getVideoID"
|
| "getVideoID"
|
||||||
| "getChannelID"
|
| "getChannelID"
|
||||||
@@ -25,13 +24,7 @@ interface BoolValueMessage {
|
|||||||
value: boolean;
|
value: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ChangeStartSponsorButtonMessage {
|
export type Message = BaseMessage & (DefaultMessage | BoolValueMessage);
|
||||||
message: "changeStartSponsorButton";
|
|
||||||
showStartSponsor: boolean;
|
|
||||||
uploadButtonVisible: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Message = BaseMessage & (DefaultMessage | BoolValueMessage | ChangeStartSponsorButtonMessage);
|
|
||||||
|
|
||||||
interface IsInfoFoundMessageResponse {
|
interface IsInfoFoundMessageResponse {
|
||||||
found: boolean;
|
found: boolean;
|
||||||
@@ -47,7 +40,7 @@ interface GetChannelIDResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface SponsorStartResponse {
|
interface SponsorStartResponse {
|
||||||
time: number;
|
creatingSegment: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IsChannelWhitelistedResponse {
|
interface IsChannelWhitelistedResponse {
|
||||||
|
|||||||
106
src/popup.ts
106
src/popup.ts
@@ -126,8 +126,8 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
|||||||
PageElements.optionsButton.addEventListener("click", openOptions);
|
PageElements.optionsButton.addEventListener("click", openOptions);
|
||||||
PageElements.helpButton.addEventListener("click", openHelp);
|
PageElements.helpButton.addEventListener("click", openHelp);
|
||||||
|
|
||||||
//if true, the button now selects the end time
|
/** If true, the content script is in the process of creating a new segment. */
|
||||||
let startTimeChosen = false;
|
let creatingSegment = false;
|
||||||
|
|
||||||
//the start and end time pairs (2d)
|
//the start and end time pairs (2d)
|
||||||
let sponsorTimes: SponsorTime[] = [];
|
let sponsorTimes: SponsorTime[] = [];
|
||||||
@@ -233,10 +233,12 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
|||||||
|
|
||||||
function onTabs(tabs) {
|
function onTabs(tabs) {
|
||||||
messageHandler.sendMessage(tabs[0].id, {message: 'getVideoID'}, function(result) {
|
messageHandler.sendMessage(tabs[0].id, {message: 'getVideoID'}, function(result) {
|
||||||
if (result != undefined && result.videoID) {
|
if (result !== undefined && result.videoID) {
|
||||||
currentVideoID = result.videoID;
|
currentVideoID = result.videoID;
|
||||||
|
creatingSegment = result.creatingSegment;
|
||||||
|
|
||||||
loadTabData(tabs);
|
loadTabData(tabs);
|
||||||
} else if (result == undefined && chrome.runtime.lastError) {
|
} else if (result === undefined && chrome.runtime.lastError) {
|
||||||
//this isn't a YouTube video then, or at least the content script is not loaded
|
//this isn't a YouTube video then, or at least the content script is not loaded
|
||||||
displayNoVideo();
|
displayNoVideo();
|
||||||
}
|
}
|
||||||
@@ -253,19 +255,11 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
|||||||
//load video times for this video
|
//load video times for this video
|
||||||
const sponsorTimesStorage = Config.config.segmentTimes.get(currentVideoID);
|
const sponsorTimesStorage = Config.config.segmentTimes.get(currentVideoID);
|
||||||
if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) {
|
if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) {
|
||||||
if (sponsorTimesStorage[sponsorTimesStorage.length - 1] != undefined && sponsorTimesStorage[sponsorTimesStorage.length - 1].segment.length < 2) {
|
|
||||||
startTimeChosen = true;
|
|
||||||
PageElements.sponsorStart.innerHTML = chrome.i18n.getMessage("sponsorEnd");
|
|
||||||
}
|
|
||||||
|
|
||||||
sponsorTimes = sponsorTimesStorage;
|
sponsorTimes = sponsorTimesStorage;
|
||||||
|
|
||||||
//show submission section
|
|
||||||
PageElements.submissionSection.style.display = "unset";
|
|
||||||
|
|
||||||
showSubmitTimesIfNecessary();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateSegmentEditingUI();
|
||||||
|
|
||||||
//check if this video's sponsors are known
|
//check if this video's sponsors are known
|
||||||
messageHandler.sendMessage(
|
messageHandler.sendMessage(
|
||||||
tabs[0].id,
|
tabs[0].id,
|
||||||
@@ -321,51 +315,44 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
|||||||
//the content script will get the message if a YouTube page is open
|
//the content script will get the message if a YouTube page is open
|
||||||
messageHandler.query({
|
messageHandler.query({
|
||||||
active: true,
|
active: true,
|
||||||
currentWindow: true
|
currentWindow: true,
|
||||||
}, tabs => {
|
}, (tabs) => {
|
||||||
messageHandler.sendMessage(
|
messageHandler.sendMessage(
|
||||||
tabs[0].id,
|
tabs[0].id,
|
||||||
{from: 'popup', message: 'sponsorStart'},
|
{from: 'popup', message: 'sponsorStart'},
|
||||||
startSponsorCallback
|
async (response) => {
|
||||||
);
|
startSponsorCallback(response);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function startSponsorCallback(response) {
|
// Perform a second update after the config changes take effect as a workaround for a race condition
|
||||||
const sponsorTimesIndex = sponsorTimes.length - (startTimeChosen ? 1 : 0);
|
const removeListener = (listener: typeof lateUpdate) => {
|
||||||
|
const index = Config.configListeners.indexOf(listener);
|
||||||
if (sponsorTimes[sponsorTimesIndex] == undefined) {
|
if (index !== -1) Config.configListeners.splice(index, 1);
|
||||||
sponsorTimes[sponsorTimesIndex] = {
|
|
||||||
segment: [],
|
|
||||||
category: Config.config.defaultCategory,
|
|
||||||
UUID: null
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
sponsorTimes[sponsorTimesIndex].segment[startTimeChosen ? 1 : 0] = response.time;
|
const lateUpdate = () => {
|
||||||
|
startSponsorCallback(response);
|
||||||
|
removeListener(lateUpdate);
|
||||||
|
};
|
||||||
|
|
||||||
const localStartTimeChosen = startTimeChosen;
|
Config.configListeners.push(lateUpdate);
|
||||||
Config.config.segmentTimes.set(currentVideoID, sponsorTimes);
|
|
||||||
|
|
||||||
//send a message to the client script
|
// Remove the listener after 200ms in case the changes were propagated by the time we got the response
|
||||||
if (localStartTimeChosen) {
|
setTimeout(() => removeListener(lateUpdate), 200);
|
||||||
messageHandler.query({
|
},
|
||||||
active: true,
|
|
||||||
currentWindow: true
|
|
||||||
}, tabs => {
|
|
||||||
messageHandler.sendMessage(
|
|
||||||
tabs[0].id,
|
|
||||||
{message: "sponsorDataChanged"}
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStartTimeChosen();
|
function startSponsorCallback(response: {creatingSegment: boolean}) {
|
||||||
|
creatingSegment = response.creatingSegment;
|
||||||
|
|
||||||
//show submission section
|
// Only update the segments after a segment was created
|
||||||
PageElements.submissionSection.style.display = "unset";
|
if (!creatingSegment) {
|
||||||
|
sponsorTimes = Config.config.segmentTimes.get(currentVideoID) || [];
|
||||||
|
}
|
||||||
|
|
||||||
showSubmitTimesIfNecessary();
|
// Update the UI
|
||||||
|
updateSegmentEditingUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
//display the video times from the array at the top, in a different section
|
//display the video times from the array at the top, in a different section
|
||||||
@@ -484,32 +471,11 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
|||||||
PageElements.showNoticeAgain.style.display = "none";
|
PageElements.showNoticeAgain.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateStartTimeChosen() {
|
/** Updates any UI related to segment editing and submission according to the current state. */
|
||||||
//update startTimeChosen letiable
|
function updateSegmentEditingUI() {
|
||||||
if (!startTimeChosen) {
|
PageElements.sponsorStart.innerText = chrome.i18n.getMessage(creatingSegment ? "sponsorEnd" : "sponsorStart");
|
||||||
startTimeChosen = true;
|
|
||||||
PageElements.sponsorStart.innerHTML = chrome.i18n.getMessage("sponsorEnd");
|
|
||||||
} else {
|
|
||||||
resetStartTimeChosen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//set it to false
|
PageElements.submissionSection.style.display = sponsorTimes && sponsorTimes.length > 0 ? "unset" : "none";
|
||||||
function resetStartTimeChosen() {
|
|
||||||
startTimeChosen = false;
|
|
||||||
PageElements.sponsorStart.innerHTML = chrome.i18n.getMessage("sponsorStart");
|
|
||||||
}
|
|
||||||
|
|
||||||
//hides and shows the submit times button when needed
|
|
||||||
function showSubmitTimesIfNecessary() {
|
|
||||||
//check if an end time has been specified for the latest sponsor time
|
|
||||||
if (sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].segment.length > 1) {
|
|
||||||
//show submit times button
|
|
||||||
document.getElementById("submitTimesContainer").style.display = "flex";
|
|
||||||
} else {
|
|
||||||
//hide submit times button
|
|
||||||
document.getElementById("submitTimesContainer").style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//make the options div visible
|
//make the options div visible
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export interface ContentContainer {
|
|||||||
onMobileYouTube: boolean,
|
onMobileYouTube: boolean,
|
||||||
sponsorSubmissionNotice: SubmissionNotice,
|
sponsorSubmissionNotice: SubmissionNotice,
|
||||||
resetSponsorSubmissionNotice: () => void,
|
resetSponsorSubmissionNotice: () => void,
|
||||||
changeStartSponsorButton: (showStartSponsor: boolean, uploadButtonVisible: boolean) => Promise<boolean>,
|
updateEditButtonsOnPlayer: () => void,
|
||||||
previewTime: (time: number, unpause?: boolean) => void,
|
previewTime: (time: number, unpause?: boolean) => void,
|
||||||
videoInfo: VideoInfo,
|
videoInfo: VideoInfo,
|
||||||
getRealCurrentTime: () => number
|
getRealCurrentTime: () => number
|
||||||
@@ -60,6 +60,10 @@ export interface SponsorTime {
|
|||||||
hidden?: SponsorHideType;
|
hidden?: SponsorHideType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type IncompleteSponsorTime = Omit<SponsorTime, 'segment'> & {
|
||||||
|
segment: [number];
|
||||||
|
};
|
||||||
|
|
||||||
export interface PreviewBarOption {
|
export interface PreviewBarOption {
|
||||||
color: string,
|
color: string,
|
||||||
opacity: string
|
opacity: string
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ export default class Utils {
|
|||||||
this.backgroundScriptContainer = backgroundScriptContainer;
|
this.backgroundScriptContainer = backgroundScriptContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function that can be used to wait for a condition before returning
|
/** Function that can be used to wait for a condition before returning. */
|
||||||
async wait(condition: () => HTMLElement | boolean, timeout = 5000, check = 100): Promise<HTMLElement | boolean> {
|
async wait<T>(condition: () => T | false, timeout = 5000, check = 100): Promise<T> {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
setTimeout(() => reject("TIMEOUT"), timeout);
|
setTimeout(() => reject("TIMEOUT"), timeout);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user