diff options
author | Ajay <[email protected]> | 2022-12-24 00:54:56 -0500 |
---|---|---|
committer | Ajay <[email protected]> | 2022-12-24 00:54:56 -0500 |
commit | 7dd2c9eb3e4af690024319f32a075fef90bb2d88 (patch) | |
tree | 77a3a04d46ae3ed04ace804945a9f6ca3fe7152f | |
parent | 7bf17e17461a1d8b3958cb0d9cda223808ebaadd (diff) | |
download | SponsorBlock-7dd2c9eb3e4af690024319f32a075fef90bb2d88.tar.gz SponsorBlock-7dd2c9eb3e4af690024319f32a075fef90bb2d88.zip |
Move some generic functions to a new package
-rw-r--r-- | package-lock.json | 32 | ||||
-rw-r--r-- | package.json | 3 | ||||
-rw-r--r-- | src/components/SponsorTimeEditComponent.tsx | 23 | ||||
-rw-r--r-- | src/content.ts | 8 | ||||
-rw-r--r-- | src/help.ts | 4 | ||||
-rw-r--r-- | src/js-components/previewBar.ts | 4 | ||||
-rw-r--r-- | src/popup.ts | 5 | ||||
-rw-r--r-- | src/render/CategoryPill.tsx | 11 | ||||
-rw-r--r-- | src/utils.ts | 4 | ||||
-rw-r--r-- | src/utils/exporter.ts | 9 | ||||
-rw-r--r-- | src/utils/genericUtils.ts | 70 | ||||
-rw-r--r-- | src/utils/pageUtils.ts | 4 |
12 files changed, 71 insertions, 106 deletions
diff --git a/package-lock.json b/package-lock.json index 9eff316a..29ce129d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ ], "license": "LGPL-3.0-or-later", "dependencies": { + "@ajayyy/maze-utils": "^1.0.3", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -65,6 +66,32 @@ "node": ">=16" } }, + "node_modules/@ajayyy/maze-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@ajayyy/maze-utils/-/maze-utils-1.0.3.tgz", + "integrity": "sha512-sdQyU/2VAmJ9FiyUIdjE8FbO5b5IofN9vK/7lkZiUw91V+NZi7aSG/LSYMqmQ3OuTYRE5PLN9Jyknuo2ZnljjA==", + "funding": [ + { + "type": "individual", + "url": "https://sponsor.ajay.app/donate" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ajayyy-org" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/ajayyy" + }, + { + "type": "individual", + "url": "https://paypal.me/ajayyy" + } + ], + "engines": { + "node": ">=16" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -13336,6 +13363,11 @@ } }, "dependencies": { + "@ajayyy/maze-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@ajayyy/maze-utils/-/maze-utils-1.0.3.tgz", + "integrity": "sha512-sdQyU/2VAmJ9FiyUIdjE8FbO5b5IofN9vK/7lkZiUw91V+NZi7aSG/LSYMqmQ3OuTYRE5PLN9Jyknuo2ZnljjA==" + }, "@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", diff --git a/package.json b/package.json index 824abd6a..e96403cf 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "background.js", "dependencies": { "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "@ajayyy/maze-utils": "^1.0.3" }, "devDependencies": { "@types/chrome": "^0.0.199", diff --git a/src/components/SponsorTimeEditComponent.tsx b/src/components/SponsorTimeEditComponent.tsx index 01bee538..2cd9f984 100644 --- a/src/components/SponsorTimeEditComponent.tsx +++ b/src/components/SponsorTimeEditComponent.tsx @@ -6,10 +6,9 @@ import Utils from "../utils"; import SubmissionNoticeComponent from "./SubmissionNoticeComponent"; import { RectangleTooltip } from "../render/RectangleTooltip"; import SelectorComponent, { SelectorOption } from "./SelectorComponent"; -import { GenericUtils } from "../utils/genericUtils"; import { noRefreshFetchingChaptersAllowed } from "../utils/licenseKey"; import { DEFAULT_CATEGORY } from "../utils/categoryUtils"; - +import { getFormattedTime, getFormattedTimeToSeconds } from "@ajayyy/maze-utils/lib/formating"; const utils = new Utils(); @@ -181,9 +180,9 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo style={timeDisplayStyle} className="sponsorTimeDisplay" onClick={this.toggleEditTime.bind(this)}> - {GenericUtils.getFormattedTime(segment[0], true) + + {getFormattedTime(segment[0], true) + ((!isNaN(segment[1]) && sponsorTime.actionType !== ActionType.Poi) - ? " " + chrome.i18n.getMessage("to") + " " + GenericUtils.getFormattedTime(segment[1], true) : "")} + ? " " + chrome.i18n.getMessage("to") + " " + getFormattedTime(segment[1], true) : "")} </div> ); } @@ -308,8 +307,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo const sponsorTimeEdits = this.state.sponsorTimeEdits; // check if change is small engough to show tooltip - const before = GenericUtils.getFormattedTimeToSeconds(sponsorTimeEdits[index]); - const after = GenericUtils.getFormattedTimeToSeconds(targetValue); + const before = getFormattedTimeToSeconds(sponsorTimeEdits[index]); + const after = getFormattedTimeToSeconds(targetValue); const difference = Math.abs(before - after); if (0 < difference && difference < 0.5) this.showScrollToEditToolTip(); @@ -333,7 +332,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo } const sponsorTimeEdits = this.state.sponsorTimeEdits; - let timeAsNumber = GenericUtils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[index]); + let timeAsNumber = getFormattedTimeToSeconds(this.state.sponsorTimeEdits[index]); if (timeAsNumber !== null && e.deltaY != 0) { if (e.deltaY < 0) { timeAsNumber += step; @@ -343,7 +342,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo timeAsNumber = 0; } - sponsorTimeEdits[index] = GenericUtils.getFormattedTime(timeAsNumber, true); + sponsorTimeEdits[index] = getFormattedTime(timeAsNumber, true); if (sponsorTime.actionType === ActionType.Poi) sponsorTimeEdits[1] = sponsorTimeEdits[0]; this.setState({sponsorTimeEdits}); @@ -575,8 +574,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo /** Returns an array in the sponsorTimeEdits form (formatted time string) from a normal seconds sponsor time */ getFormattedSponsorTimesEdits(sponsorTime: SponsorTime): [string, string] { - return [GenericUtils.getFormattedTime(sponsorTime.segment[0], true), - GenericUtils.getFormattedTime(sponsorTime.segment[1], true)]; + return [getFormattedTime(sponsorTime.segment[0], true), + getFormattedTime(sponsorTime.segment[1], true)]; } saveEditTimes(): void { @@ -584,8 +583,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo const category = this.categoryOptionRef.current.value as Category if (this.state.editing) { - const startTime = GenericUtils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[0]); - const endTime = GenericUtils.getFormattedTimeToSeconds(this.state.sponsorTimeEdits[1]); + const startTime = getFormattedTimeToSeconds(this.state.sponsorTimeEdits[0]); + const endTime = getFormattedTimeToSeconds(this.state.sponsorTimeEdits[1]); // Change segment time only if the format was correct if (startTime !== null && endTime !== null) { diff --git a/src/content.ts b/src/content.ts index f98e2ed9..db6d9886 100644 --- a/src/content.ts +++ b/src/content.ts @@ -39,6 +39,8 @@ import { ChapterVote } from "./render/ChapterVote"; import { openWarningDialog } from "./utils/warnings"; import { Tooltip } from "./render/Tooltip"; import { noRefreshFetchingChaptersAllowed } from "./utils/licenseKey"; +import { waitFor } from "@ajayyy/maze-utils"; +import { getFormattedTime } from "@ajayyy/maze-utils/lib/formating"; const utils = new Utils(); @@ -1203,7 +1205,7 @@ async function sponsorsLookup(keepOldSubmissions = true) { function importExistingChapters(wait: boolean) { if (!existingChaptersImported) { - GenericUtils.wait(() => video?.duration && getExistingChapters(sponsorVideoID, video.duration), + waitFor(() => video?.duration && getExistingChapters(sponsorVideoID, video.duration), wait ? 5000 : 0, 100, (c) => c?.length > 0).then((chapters) => { if (!existingChaptersImported && chapters?.length > 0) { sponsorTimes = (sponsorTimes ?? []).concat(...chapters).sort((a, b) => a.segment[0] - b.segment[0]); @@ -2364,7 +2366,7 @@ function getSegmentsMessage(sponsorTimes: SponsorTime[]): string { for (let i = 0; i < sponsorTimes.length; i++) { for (let s = 0; s < sponsorTimes[i].segment.length; s++) { - let timeMessage = GenericUtils.getFormattedTime(sponsorTimes[i].segment[s]); + let timeMessage = getFormattedTime(sponsorTimes[i].segment[s]); //if this is an end time if (s == 1) { timeMessage = " " + chrome.i18n.getMessage("to") + " " + timeMessage; @@ -2592,7 +2594,7 @@ function showTimeWithoutSkips(skippedDuration: number): void { display.appendChild(duration); } - const durationAfterSkips = GenericUtils.getFormattedTime(video?.duration - skippedDuration); + const durationAfterSkips = getFormattedTime(video?.duration - skippedDuration); duration.innerText = (durationAfterSkips == null || skippedDuration <= 0) ? "" : " (" + durationAfterSkips + ")"; } diff --git a/src/help.ts b/src/help.ts index 9cc6b4bd..10bd86cf 100644 --- a/src/help.ts +++ b/src/help.ts @@ -2,14 +2,14 @@ import Config from "./config"; import { showDonationLink } from "./utils/configUtils"; import { localizeHtmlPage } from "./utils/pageUtils"; -import { GenericUtils } from "./utils/genericUtils"; +import { waitFor } from "@ajayyy/maze-utils"; window.addEventListener('DOMContentLoaded', init); async function init() { localizeHtmlPage(); - await GenericUtils.wait(() => Config.config !== null); + await waitFor(() => Config.config !== null); if (!Config.config.darkMode) { document.documentElement.setAttribute("data-theme", "light"); diff --git a/src/js-components/previewBar.ts b/src/js-components/previewBar.ts index 4842afc0..0afb7f96 100644 --- a/src/js-components/previewBar.ts +++ b/src/js-components/previewBar.ts @@ -11,8 +11,8 @@ import { ActionType, Category, SegmentContainer, SponsorHideType, SponsorSourceT import { partition } from "../utils/arrayUtils"; import { DEFAULT_CATEGORY, shortCategoryName } from "../utils/categoryUtils"; import { normalizeChapterName } from "../utils/exporter"; -import { GenericUtils } from "../utils/genericUtils"; import { findValidElement } from "../utils/pageUtils"; +import { getFormattedTimeToSeconds } from "@ajayyy/maze-utils/lib/formating"; const TOOLTIP_VISIBLE_CLASS = 'sponsorCategoryTooltipVisible'; const MIN_CHAPTER_SIZE = 0.003; @@ -140,7 +140,7 @@ class PreviewBar { const tooltipText = tooltipTextElement.textContent; if (tooltipText === null || tooltipText.length === 0) continue; - timeInSeconds = GenericUtils.getFormattedTimeToSeconds(tooltipText); + timeInSeconds = getFormattedTimeToSeconds(tooltipText); if (timeInSeconds !== null) break; } diff --git a/src/popup.ts b/src/popup.ts index 3584fba5..f631d7cd 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -27,6 +27,7 @@ import { localizeHtmlPage } from "./utils/pageUtils"; import { exportTimes } from "./utils/exporter"; import GenericNotice from "./render/GenericNotice"; import { noRefreshFetchingChaptersAllowed } from "./utils/licenseKey"; +import { getFormattedTime } from "@ajayyy/maze-utils/lib/formating"; const utils = new Utils(); @@ -593,9 +594,9 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> { if (downloadedTimes[i].actionType === ActionType.Full) { segmentTimeFromToNode.innerText = chrome.i18n.getMessage("full"); } else { - segmentTimeFromToNode.innerText = GenericUtils.getFormattedTime(downloadedTimes[i].segment[0], true) + + segmentTimeFromToNode.innerText = getFormattedTime(downloadedTimes[i].segment[0], true) + (actionType !== ActionType.Poi - ? " " + chrome.i18n.getMessage("to") + " " + GenericUtils.getFormattedTime(downloadedTimes[i].segment[1], true) + ? " " + chrome.i18n.getMessage("to") + " " + getFormattedTime(downloadedTimes[i].segment[1], true) : ""); } diff --git a/src/render/CategoryPill.tsx b/src/render/CategoryPill.tsx index f8ec1791..aeace093 100644 --- a/src/render/CategoryPill.tsx +++ b/src/render/CategoryPill.tsx @@ -4,8 +4,9 @@ import CategoryPillComponent, { CategoryPillState } from "../components/Category import Config from "../config"; import { VoteResponse } from "../messageTypes"; import { Category, SegmentUUID, SponsorTime } from "../types"; -import { GenericUtils } from "../utils/genericUtils"; import { Tooltip } from "./Tooltip"; +import { waitFor } from "@ajayyy/maze-utils"; +import { getYouTubeTitleNode } from "@ajayyy/maze-utils/lib/elements"; export class CategoryPill { container: HTMLElement; @@ -23,9 +24,7 @@ export class CategoryPill { async attachToPage(onMobileYouTube: boolean, onInvidious: boolean, vote: (type: number, UUID: SegmentUUID, category?: Category) => Promise<VoteResponse>): Promise<void> { const referenceNode = - await GenericUtils.wait(() => - // New YouTube Title, YouTube, Mobile YouTube, Invidious - document.querySelector("#title h1, .ytd-video-primary-info-renderer.title, .slim-video-information-title, #player-container + .h-box > h1") as HTMLElement); + await waitFor(() => getYouTubeTitleNode()); if (referenceNode && !referenceNode.contains(this.container)) { this.container = document.createElement('span'); @@ -43,7 +42,7 @@ export class CategoryPill { this.root.render(<CategoryPillComponent ref={this.ref} vote={vote} />); if (this.unsavedState) { - GenericUtils.wait(() => this.ref.current).then(() => { + waitFor(() => this.ref.current).then(() => { this.ref.current?.setState(this.unsavedState); this.unsavedState = null; }); @@ -99,7 +98,7 @@ export class CategoryPill { if (!Config.config.categoryPillUpdate) { Config.config.categoryPillUpdate = true; - const watchDiv = await GenericUtils.wait(() => document.querySelector("#info.ytd-watch-flexy") as HTMLElement); + const watchDiv = await waitFor(() => document.querySelector("#info.ytd-watch-flexy") as HTMLElement); if (watchDiv) { new Tooltip({ text: chrome.i18n.getMessage("categoryPillNewFeature"), diff --git a/src/utils.ts b/src/utils.ts index 1ee5781d..90bd5418 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,7 +3,7 @@ import { CategorySelection, SponsorTime, FetchResponse, BackgroundScriptContaine import * as CompileConfig from "../config.json"; import { findValidElement, findValidElementFromSelector } from "./utils/pageUtils"; -import { GenericUtils } from "./utils/genericUtils"; +import { waitFor } from "@ajayyy/maze-utils"; export default class Utils { @@ -31,7 +31,7 @@ export default class Utils { } async wait<T>(condition: () => T, timeout = 5000, check = 100): Promise<T> { - return GenericUtils.wait(condition, timeout, check); + return waitFor(condition, timeout, check); } /* Uses a mutation observer to wait asynchronously */ diff --git a/src/utils/exporter.ts b/src/utils/exporter.ts index ec67133b..3c2ca6f9 100644 --- a/src/utils/exporter.ts +++ b/src/utils/exporter.ts @@ -2,6 +2,7 @@ import { ActionType, Category, SegmentUUID, SponsorSourceType, SponsorTime } fro import { shortCategoryName } from "./categoryUtils"; import { GenericUtils } from "./genericUtils"; import * as CompileConfig from "../../config.json"; +import { getFormattedTime, getFormattedTimeToSeconds } from "@ajayyy/maze-utils/lib/formating"; const inTest = typeof chrome === "undefined"; @@ -26,9 +27,9 @@ export function exportTimes(segments: SponsorTime[]): string { function exportTime(segment: SponsorTime): string { const name = segment.description || shortCategoryName(segment.category); - return `${GenericUtils.getFormattedTime(segment.segment[0], true)}${ + return `${getFormattedTime(segment.segment[0], true)}${ segment.segment[1] && segment.segment[0] !== segment.segment[1] - ? ` - ${GenericUtils.getFormattedTime(segment.segment[1], true)}` : ""} ${name}`; + ? ` - ${getFormattedTime(segment.segment[1], true)}` : ""} ${name}`; } export function importTimes(data: string, videoDuration: number): SponsorTime[] { @@ -37,7 +38,7 @@ export function importTimes(data: string, videoDuration: number): SponsorTime[] for (const line of lines) { const match = line.match(/(?:((?:\d+:)?\d+:\d+)+(?:\.\d+)?)|(?:\d+(?=s| second))/g); if (match) { - const startTime = GenericUtils.getFormattedTimeToSeconds(match[0]); + const startTime = getFormattedTimeToSeconds(match[0]); if (startTime !== null) { // Remove "seconds", "at", special characters, and ")" if there was a "(" const specialCharsMatcher = /^(?:\s+seconds?)?[-:()\s]*|(?:\s+at)?[-:(\s]+$|(?<=^\s*\(.+)[-:()\s]*$/g @@ -51,7 +52,7 @@ export function importTimes(data: string, videoDuration: number): SponsorTime[] const determinedCategory = chapterNames.find(c => c.names.includes(title))?.code as Category; const segment: SponsorTime = { - segment: [startTime, GenericUtils.getFormattedTimeToSeconds(match[1])], + segment: [startTime, getFormattedTimeToSeconds(match[1])], category: determinedCategory ?? ("chapter" as Category), actionType: determinedCategory ? ActionType.Skip : ActionType.Chapter, description: title, diff --git a/src/utils/genericUtils.ts b/src/utils/genericUtils.ts index 144c0438..675f7096 100644 --- a/src/utils/genericUtils.ts +++ b/src/utils/genericUtils.ts @@ -1,70 +1,3 @@ -/** Function that can be used to wait for a condition before returning. */ -async function wait<T>(condition: () => T, timeout = 5000, check = 100, predicate?: (obj: T) => boolean): Promise<T> { - return await new Promise((resolve, reject) => { - setTimeout(() => { - clearInterval(interval); - reject("TIMEOUT"); - }, timeout); - - const intervalCheck = () => { - const result = condition(); - if (predicate ? predicate(result) : result) { - resolve(result); - clearInterval(interval); - } - }; - - const interval = setInterval(intervalCheck, check); - - //run the check once first, this speeds it up a lot - intervalCheck(); - }); -} - -function getFormattedTimeToSeconds(formatted: string): number | null { - const fragments = /^(?:(?:(\d+):)?(\d+):)?(\d*(?:[.,]\d+)?)$/.exec(formatted); - - if (fragments === null) { - return null; - } - - const hours = fragments[1] ? parseInt(fragments[1]) : 0; - const minutes = fragments[2] ? parseInt(fragments[2] || '0') : 0; - const seconds = fragments[3] ? parseFloat(fragments[3].replace(',', '.')) : 0; - - return hours * 3600 + minutes * 60 + seconds; -} - -function getFormattedTime(seconds: number, precise?: boolean): string { - seconds = Math.max(seconds, 0); - - const hours = Math.floor(seconds / 60 / 60); - const minutes = Math.floor(seconds / 60) % 60; - let minutesDisplay = String(minutes); - let secondsNum = seconds % 60; - if (!precise) { - secondsNum = Math.floor(secondsNum); - } - - let secondsDisplay = String(precise ? secondsNum.toFixed(3) : secondsNum); - - if (secondsNum < 10) { - //add a zero - secondsDisplay = "0" + secondsDisplay; - } - if (hours && minutes < 10) { - //add a zero - minutesDisplay = "0" + minutesDisplay; - } - if (isNaN(hours) || isNaN(minutes)) { - return null; - } - - const formatted = (hours ? hours + ":" : "") + minutesDisplay + ":" + secondsDisplay; - - return formatted; -} - /** * Gets the error message in a nice string * @@ -148,9 +81,6 @@ function generateUserID(length = 36): string { } export const GenericUtils = { - wait, - getFormattedTime, - getFormattedTimeToSeconds, getErrorMessage, getLuminance, generateUserID, diff --git a/src/utils/pageUtils.ts b/src/utils/pageUtils.ts index 42766fef..beda1585 100644 --- a/src/utils/pageUtils.ts +++ b/src/utils/pageUtils.ts @@ -1,5 +1,5 @@ import { ActionType, Category, SponsorSourceType, SponsorTime, VideoID } from "../types"; -import { GenericUtils } from "./genericUtils"; +import { getFormattedTimeToSeconds } from "@ajayyy/maze-utils/lib/formating"; export function getControls(): HTMLElement { const controlsSelectors = [ @@ -80,7 +80,7 @@ export function getExistingChapters(currentVideoID: VideoID, duration: number): const timeElement = link.querySelector("#time") as HTMLElement; const description = link.querySelector("#details h4") as HTMLElement; if (timeElement && description?.innerText?.length > 0 && link.getAttribute("href")?.includes(currentVideoID)) { - const time = GenericUtils.getFormattedTimeToSeconds(timeElement.innerText); + const time = getFormattedTimeToSeconds(timeElement.innerText); if (time === null) return []; if (lastSegment) { |