diff --git a/src/components/DescriptionPortPillComponent.tsx b/src/components/DescriptionPortPillComponent.tsx index 32718c3a..03622ff5 100644 --- a/src/components/DescriptionPortPillComponent.tsx +++ b/src/components/DescriptionPortPillComponent.tsx @@ -2,16 +2,16 @@ import { ConfigProvider, Spin } from "antd"; import * as React from "react"; import { PortVideo } from "../render/DesciptionPortPill"; import { showMessage } from "../render/MessageNotice"; -import { VideoID } from "../types"; +import { VideoID, YoutubeID } from "../types"; import { AnimationUtils } from "../utils/animationUtils"; import { parseYoutubeID } from "../utils/parseVideoID"; export interface DescriptionPortPillProps { - bvID: VideoID; - ytbID: VideoID; + videoID: VideoID; + ytbID: YoutubeID; showYtbVideoButton: boolean; - onSubmitPortVideo: (ytbID: VideoID) => Promise; + onSubmitPortVideo: (ytbID: YoutubeID) => Promise; onVote(type: number): Promise; onRefresh(): Promise; } @@ -20,8 +20,8 @@ export interface DescriptionPortPillState { show: boolean; showPreviewYtbVideo: boolean; loading: boolean; - ytbVideoID: VideoID; - previewYtbID: VideoID; + ytbVideoID: YoutubeID; + previewYtbID: YoutubeID; } export class DescriptionPortPillComponent extends React.Component { diff --git a/src/config/configUtils.ts b/src/config/configUtils.ts index adb577c5..40f8c8a7 100644 --- a/src/config/configUtils.ts +++ b/src/config/configUtils.ts @@ -1,5 +1,10 @@ import Config from "../config"; +import { VideoID } from "../types"; export function showDonationLink(): boolean { return navigator.vendor !== "Apple Computer, Inc." && Config.config.showDonationLink; } + +export function getUnsubmittedSegmentKey(videoID: VideoID): string { + return videoID.bvid + videoID.cid; +} diff --git a/src/content.ts b/src/content.ts index aa5d7549..11509fa5 100644 --- a/src/content.ts +++ b/src/content.ts @@ -1,6 +1,7 @@ import SkipNoticeComponent from "./components/SkipNoticeComponent"; import Config from "./config"; import { isSafari, Keybind, keybindEquals, keybindToString, StorageChangesObject } from "./config/config"; +import { getUnsubmittedSegmentKey } from "./config/configUtils"; import PreviewBar, { PreviewBarSegment } from "./js-components/previewBar"; import { SkipButtonControlBar } from "./js-components/skipButtonControlBar"; import { Message, MessageResponse, VoteResponse } from "./messageTypes"; @@ -359,7 +360,7 @@ function messageListener( } if (addedSegments) { - Config.local.unsubmittedSegments[getVideoID()] = sponsorTimesSubmitting; + Config.local.unsubmittedSegments[getUnsubmittedSegmentKey(getVideoID())] = sponsorTimesSubmitting; Config.forceLocalUpdate("unsubmittedSegments"); updateSegmentSubmitting(); @@ -922,11 +923,12 @@ function isSegmentMarkedNearCurrentTime(currentTime: number, range: number = 5): /** * This makes sure the videoID is still correct and if the sponsorTime is included */ -async function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): Promise { +async function incorrectVideoCheck(videoID?: VideoID, sponsorTime?: SponsorTime): Promise { const currentVideoID = await getBilibiliVideoID(); const recordedVideoID = videoID || getVideoID(); if ( - currentVideoID !== recordedVideoID || + // TODO: check cid + currentVideoID.bvid !== recordedVideoID.bvid || (sponsorTime && (!sponsorTimes || !sponsorTimes?.some( @@ -1255,7 +1257,7 @@ async function sponsorsLookup(keepOldSubmissions = true, ignoreServerCache = fal const hashParams = getHashParams(); if (hashParams.requiredSegment) extraRequestData.requiredSegment = hashParams.requiredSegment; - const hashPrefix = (await getVideoIDHash(getVideoID())).slice(0, 4) as VideoID & HashedValue; + const hashPrefix = (await getVideoIDHash(getVideoID())).slice(0, 4) as HashedValue; const response = await getSegmentsByHash(hashPrefix, extraRequestData, ignoreServerCache); // store last response status @@ -1370,7 +1372,7 @@ function getEnabledActionTypes(forceFullVideo = false): ActionType[] { } async function lockedCategoriesLookup(): Promise { - const hashPrefix = (await getHash(getVideoID(), 1)).slice(0, 4); + const hashPrefix = (await getVideoIDHash(getVideoID())).slice(0, 4); const response = await asyncRequestToServer("GET", "/api/lockCategories/" + hashPrefix); if (response.ok) { @@ -2097,7 +2099,7 @@ function startOrEndTimingNewSegment() { } // Save the newly created segment - Config.local.unsubmittedSegments[getVideoID()] = sponsorTimesSubmitting; + Config.local.unsubmittedSegments[getUnsubmittedSegmentKey(getVideoID())] = sponsorTimesSubmitting; Config.forceLocalUpdate("unsubmittedSegments"); // Make sure they know if someone has already submitted something it while they were watching @@ -2133,12 +2135,12 @@ function cancelCreatingSegment() { if (sponsorTimesSubmitting.length > 1) { // If there's more than one segment: remove last sponsorTimesSubmitting.pop(); - Config.local.unsubmittedSegments[getVideoID()] = sponsorTimesSubmitting; + Config.local.unsubmittedSegments[getUnsubmittedSegmentKey(getVideoID())] = sponsorTimesSubmitting; } else { // Otherwise delete the video entry & close submission menu resetSponsorSubmissionNotice(); sponsorTimesSubmitting = []; - delete Config.local.unsubmittedSegments[getVideoID()]; + delete Config.local.unsubmittedSegments[getUnsubmittedSegmentKey(getVideoID())]; } Config.forceLocalUpdate("unsubmittedSegments"); } @@ -2148,7 +2150,7 @@ function cancelCreatingSegment() { } function updateSponsorTimesSubmitting(getFromConfig = true) { - const segmentTimes = Config.local.unsubmittedSegments[getVideoID()]; + const segmentTimes = Config.local.unsubmittedSegments[getUnsubmittedSegmentKey(getVideoID())]; //see if this data should be saved in the sponsorTimesSubmitting variable if (getFromConfig && segmentTimes != undefined) { @@ -2233,13 +2235,13 @@ function closeInfoMenu() { function clearSponsorTimes() { const currentVideoID = getVideoID(); - const sponsorTimes = Config.local.unsubmittedSegments[currentVideoID]; + const sponsorTimes = Config.local.unsubmittedSegments[getUnsubmittedSegmentKey(currentVideoID) ]; if (sponsorTimes != undefined && sponsorTimes.length > 0) { resetSponsorSubmissionNotice(); //clear the sponsor times - delete Config.local.unsubmittedSegments[currentVideoID]; + delete Config.local.unsubmittedSegments[getUnsubmittedSegmentKey(currentVideoID)]; Config.forceLocalUpdate("unsubmittedSegments"); //clear sponsor times submitting @@ -2439,7 +2441,7 @@ async function sendSubmitMessage(): Promise { } //update sponsorTimes - Config.local.unsubmittedSegments[getVideoID()] = sponsorTimesSubmitting; + Config.local.unsubmittedSegments[getUnsubmittedSegmentKey(getVideoID())] = sponsorTimesSubmitting; Config.forceLocalUpdate("unsubmittedSegments"); // Check to see if any of the submissions are below the minimum duration set @@ -2467,7 +2469,7 @@ async function sendSubmitMessage(): Promise { stopAnimation(); // Remove segments from storage since they've already been submitted - delete Config.local.unsubmittedSegments[getVideoID()]; + delete Config.local.unsubmittedSegments[getUnsubmittedSegmentKey(getVideoID())]; Config.forceLocalUpdate("unsubmittedSegments"); const newSegments = sponsorTimesSubmitting; @@ -2740,7 +2742,7 @@ function checkForPreloadedSegment() { } if (pushed) { - Config.local.unsubmittedSegments[getVideoID()] = sponsorTimesSubmitting; + Config.local.unsubmittedSegments[getUnsubmittedSegmentKey(getVideoID())] = sponsorTimesSubmitting; Config.forceLocalUpdate("unsubmittedSegments"); } } diff --git a/src/document.ts b/src/document.ts index 61b174a3..4750bf6f 100644 --- a/src/document.ts +++ b/src/document.ts @@ -1,3 +1,4 @@ +import { AID, BvID, CID, VideoID } from "./types"; import { InjectedScriptMessageSend, sourceId } from "./utils/injectedScriptMessageUtils"; const sendMessageToContent = (messageData: InjectedScriptMessageSend, payload): void => { @@ -18,8 +19,14 @@ function windowMessageListener(message: MessageEvent) { return; } if (data?.source === sourceId && data?.responseType) { - if (data.type === "getBvID") { - sendMessageToContent(data, window?.__INITIAL_STATE__?.bvid); + if (data.type === "getVideoID") { + const videoID = { + bvid: window?.__INITIAL_STATE__?.bvid, + aid: window?.__INITIAL_STATE__?.aid, + p: window?.__INITIAL_STATE__?.p, + cid: window?.__INITIAL_STATE__?.videoData?.cid, + } as VideoID; + sendMessageToContent(data, videoID); } else if (data.type === "getFrameRate") { const currentQuality = window?.__playinfo__?.data?.quality; const frameRate = window?.__playinfo__?.data?.dash?.video.filter((v) => v.id === currentQuality)[0] diff --git a/src/globals.d.ts b/src/globals.d.ts index 65551cf2..eb6ab394 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -2,7 +2,18 @@ import SBObject from "./config"; declare global { interface Window { SB: typeof SBObject; - __INITIAL_STATE__?: { bvid: string; upInfo: { mid: number }; videoData: { desc: string } }; + __INITIAL_STATE__?: { + aid: number; + bvid: string; + p: number; + upInfo: { mid: number }; + videoData: { + aid: number; + bvid: string; + cid: number; + desc: string; + }; + }; __playinfo__?: { data: { quality: number; dash: { video: { id: number; frameRate: number }[] } } }; } } diff --git a/src/messageTypes.ts b/src/messageTypes.ts index 8bbbfca5..31cd70b0 100644 --- a/src/messageTypes.ts +++ b/src/messageTypes.ts @@ -2,7 +2,7 @@ // Message and Response Types // -import { SegmentUUID, SponsorHideType, SponsorTime } from "./types"; +import { SegmentUUID, SponsorHideType, SponsorTime, VideoID } from "./types"; interface BaseMessage { from?: string; @@ -90,7 +90,7 @@ export interface IsInfoFoundMessageResponse { } interface GetVideoIdResponse { - videoID: string; + videoID: VideoID; } export interface GetChannelIDResponse { @@ -141,7 +141,7 @@ export type InfoUpdatedMessage = IsInfoFoundMessageResponse & { export interface VideoChangedPopupMessage { message: "videoChanged"; - videoID: string; + videoID: VideoID; whitelisted: boolean; } diff --git a/src/popup/SubmitBox.tsx b/src/popup/SubmitBox.tsx index 2d22bc65..c6c63388 100644 --- a/src/popup/SubmitBox.tsx +++ b/src/popup/SubmitBox.tsx @@ -2,6 +2,7 @@ import * as React from "react"; import Config from "../config"; import { Message } from "../messageTypes"; import { SponsorTime, VideoID } from "../types"; +import { getUnsubmittedSegmentKey } from "../config/configUtils"; interface SubmitBoxProps { sendTabMessage: (data: Message, callback?) => void; @@ -9,7 +10,7 @@ interface SubmitBoxProps { } interface SubmitBoxState { - unsubmittedSegments: Record; + unsubmittedSegments: Record; currentVideoID: VideoID; showSubmitBox: boolean; @@ -27,11 +28,11 @@ class SubmitBox extends React.Component { } private sponsorTimes(): SponsorTime[] { - return this.state.unsubmittedSegments[this.state.currentVideoID] || []; + return this.state.unsubmittedSegments[getUnsubmittedSegmentKey(this.state.currentVideoID)] || []; } private isCreatingSegment(): boolean { - const segments = this.state.unsubmittedSegments[this.state.currentVideoID]; + const segments = this.state.unsubmittedSegments[getUnsubmittedSegmentKey(this.state.currentVideoID)]; if (!segments) return false; const lastSegment = segments[segments.length - 1]; return lastSegment && lastSegment?.segment?.length !== 2; diff --git a/src/render/DesciptionPortPill.tsx b/src/render/DesciptionPortPill.tsx index 7a7e5cf0..b180e874 100644 --- a/src/render/DesciptionPortPill.tsx +++ b/src/render/DesciptionPortPill.tsx @@ -6,7 +6,7 @@ import Config from "../config"; import { getPageLoaded } from "../content"; import { getPortVideoByHash, updatePortedSegments } from "../requests/portVideo"; import { asyncRequestToServer } from "../requests/requests"; -import { VideoID } from "../types"; +import { VideoID, YoutubeID } from "../types"; import { waitFor } from "../utils/"; import { waitForElement } from "../utils/dom"; import { getVideoDescriptionFromWindow } from "../utils/injectedScriptMessageUtils"; @@ -16,16 +16,16 @@ import { showMessage } from "./MessageNotice"; const id = "bsbDescriptionContainer"; export interface PortVideo { - bvID: VideoID; - ytbID: VideoID; + videoID: VideoID; + ytbID: YoutubeID; UUID: string; votes: number; locked: boolean; } export class DescriptionPortPill { - bvID: VideoID; - ytbID: VideoID; + videoID: VideoID; + ytbID: YoutubeID; portUUID: string; hasDescription: boolean; sponsorsLookup: (keepOldSubmissions: boolean, ignoreServerCache: boolean, forceUpdatePreviewBar: boolean) => void; @@ -43,10 +43,10 @@ export class DescriptionPortPill { if (!Config.config.showPortVideoButton) { return; } - if (this.bvID === videoId) { + if (this.videoID === videoId) { return; } - this.bvID = videoId; + this.videoID = videoId; this.cleanup(); @@ -96,7 +96,7 @@ export class DescriptionPortPill { this.root.render( this.submitPortVideo(ytbID)} @@ -169,7 +169,7 @@ export class DescriptionPortPill { } } - private async submitPortVideo(ytbID: VideoID): Promise { + private async submitPortVideo(ytbID: YoutubeID): Promise { const response = await asyncRequestToServer("POST", "/api/portVideo", { bvID: getVideoID(), ytbID, @@ -199,7 +199,7 @@ export class DescriptionPortPill { const response = await asyncRequestToServer("POST", "/api/votePort", { UUID: this.portUUID, - bvID: this.bvID, + bvID: this.videoID, userID: Config.config.userID, type: voteType, }); @@ -207,7 +207,7 @@ export class DescriptionPortPill { throw response?.responseText ? response.responseText : "投票失败!"; } - await this.getPortVideo(this.bvID, true); + await this.getPortVideo(this.videoID, true); this.ref.current.setState({ ytbVideoID: this.ytbID, previewYtbID: this.ytbID }); } diff --git a/src/requests/bilibiliApi.ts b/src/requests/bilibiliApi.ts index b1f26df3..b751b54d 100644 --- a/src/requests/bilibiliApi.ts +++ b/src/requests/bilibiliApi.ts @@ -1,6 +1,6 @@ -import { VideoID } from "../types"; +import { AID, VideoID } from "../types"; -export async function getBvIDfromAvIDBiliApi(avID: VideoID): Promise { +export async function getBvIDfromAvIDBiliApi(avID: AID): Promise { try { const response = await fetch(`https://api.bilibili.com/x/web-interface/view?aid=${avID}`); if (!response.ok) { diff --git a/src/requests/portVideo.ts b/src/requests/portVideo.ts index 9c0b1441..08a16939 100644 --- a/src/requests/portVideo.ts +++ b/src/requests/portVideo.ts @@ -1,6 +1,8 @@ import { VideoID } from "../types"; import { getHash } from "../utils/hash"; import { FetchResponse } from "./background-request-proxy"; +import { VideoID, YoutubeID } from "../types"; +import { getVideoIDHash } from "../utils/hash"; import { asyncRequestToServer } from "./requests"; interface RequestOptions { @@ -8,8 +10,8 @@ interface RequestOptions { } export interface PortVideoRecord { - bvID: VideoID; - ytbID: VideoID; + videoID: VideoID; + ytbID: YoutubeID; UUID: string; votes: number; locked: boolean; @@ -21,7 +23,7 @@ export async function getPortVideo(bvID: VideoID, options: RequestOptions = {}): ); if (response && response?.ok) { const responseData = JSON.parse(response?.responseText) as PortVideoRecord; - if (responseData?.bvID == bvID) { + if (responseData?.videoID == bvID) { return responseData; } } else if (response?.status == 404) { @@ -30,8 +32,8 @@ export async function getPortVideo(bvID: VideoID, options: RequestOptions = {}): throw response; } -export async function getPortVideoByHash(bvID: VideoID, options: RequestOptions = {}): Promise { - const hashedBvID = await getHash(bvID, 1); +export async function getPortVideoByHash(videoID: VideoID, options: RequestOptions = {}): Promise { + const hashedBvID = await getVideoIDHash(videoID); const response = await asyncRequestToServer( "GET", `/api/portVideo/${hashedBvID.slice(0, 3)}`, @@ -39,7 +41,8 @@ export async function getPortVideoByHash(bvID: VideoID, options: RequestOptions ).catch((e) => e); if (response && response?.ok) { const responseData = JSON.parse(response?.responseText) as PortVideoRecord[]; - const portVideo = responseData.filter((portVideo) => portVideo.bvID == bvID); + // TODO video id equality check + const portVideo = responseData.filter((portVideo) => portVideo.videoID == videoID); if (portVideo.length > 0) { return portVideo[0]; } else { diff --git a/src/requests/videoLabels.ts b/src/requests/videoLabels.ts index 1e074eba..bcc884c7 100644 --- a/src/requests/videoLabels.ts +++ b/src/requests/videoLabels.ts @@ -1,4 +1,4 @@ -import { Category, CategorySkipOption, VideoID } from "../types"; +import { BvID, Category, CategorySkipOption, VideoID } from "../types"; import Utils from "../utils"; import { getVideoIDHash } from "../utils/hash"; import { logWarn } from "../utils/logger"; @@ -8,7 +8,7 @@ const utils = new Utils(); export interface LabelCacheEntry { timestamp: number; - videos: Record; + videos: Record; } const labelCache: Record = {}; @@ -59,7 +59,7 @@ export async function getVideoLabel(videoID: VideoID, refreshCache: boolean = fa const result = await getLabelHashBlock(prefix, refreshCache); if (result) { - const category = result.videos[videoID]; + const category = result.videos[videoID.bvid]; if (category && utils.getCategorySelection(category).option !== CategorySkipOption.Disabled) { return category; } else { diff --git a/src/types.ts b/src/types.ts index 4538312c..ce4dd94d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -197,7 +197,12 @@ export interface VideoInfo { messages: unknown; } -export type VideoID = string; +export type AID = number & { __avID: never }; +export type BvID = string & { __bvID: never }; +export type CID = number & { __cID: never }; + +export type VideoID = { bvid: BvID; cid: CID; p: number; aid?: AID }; +export type YoutubeID = string & { __youtubeID: never }; export type UnEncodedSegmentTimes = [string, SponsorTime[]][]; diff --git a/src/utils/hash.ts b/src/utils/hash.ts index 8f930bf0..035f102e 100644 --- a/src/utils/hash.ts +++ b/src/utils/hash.ts @@ -1,3 +1,5 @@ +import { VideoID } from "../types"; + export type HashedValue = string & { __hashBrand: unknown }; export async function getHash(value: T, times = 5000): Promise { @@ -27,6 +29,6 @@ export async function getHash(value: T, times = 5000): Promise return hashHex as T & HashedValue; } -export async function getVideoIDHash(videoID: string): Promise { - return getHash(videoID, 1); +export async function getVideoIDHash(videoID: VideoID): Promise { + return getHash(videoID.bvid, 1); } diff --git a/src/utils/parseVideoID.ts b/src/utils/parseVideoID.ts index b43cf27d..42f66322 100644 --- a/src/utils/parseVideoID.ts +++ b/src/utils/parseVideoID.ts @@ -1,7 +1,7 @@ import { getBvIDfromAvIDBiliApi } from "../requests/bilibiliApi"; +import { AID, BvID, CID, VideoID, YoutubeID } from "../types"; import { BILI_DOMAINS } from "./constants"; import { getPropertyFromWindow } from "./injectedScriptMessageUtils"; -import { VideoID } from "./video"; export async function getBilibiliVideoID(url?: string): Promise { url ||= document?.URL; @@ -21,8 +21,8 @@ export async function getBilibiliVideoID(url?: string): Promise export function getBvIDFromWindow(timeout = 200): Promise { return getPropertyFromWindow( { - sendType: "getBvID", - responseType: "returnBvID", + sendType: "getVideoID", + responseType: "returnVideoID", }, timeout ); @@ -47,20 +47,26 @@ export function getBvIDFromURL(url: string): VideoID | null { return null; } + // TODO: parse cid and p // Get ID from url // video page if (urlObject.host == "www.bilibili.com" && urlObject.pathname.startsWith("/video/")) { const idMatch = urlObject.pathname.match(BILIBILI_VIDEO_URL_REGEX); if (idMatch && idMatch[2]) { // BV id - return idMatch[2] as VideoID; + return { bvid: idMatch[2], p: 1 } as VideoID; } else if (idMatch && idMatch[3]) { // av id - return getBvIDFromCache(idMatch[3], "-1" as VideoID); + return getBvIDFromCache(idMatch[3], { + bvid: "-1" as BvID, + aid: parseInt(idMatch[3]) as AID, + cid: 0 as CID, + p: 1, + } as VideoID); } } else if (urlObject.host == "www.bilibili.com" && urlObject.pathname.startsWith("/list/")) { const id = urlObject.searchParams.get("bvid"); - return id as VideoID; + return { bvid: id, p: 1 } as VideoID; } return null; @@ -74,7 +80,7 @@ function getBvIDFromCache(avID: string, placeholder: null | VideoID = null): Vid if (!AvToBvLoading.has(avID)) { AvToBvLoading.add(avID); - getBvIDfromAvIDBiliApi(avID.replace("av", "")).then((bvID) => { + getBvIDfromAvIDBiliApi(parseInt(avID.replace("av", "")) as AID).then((bvID) => { AvToBvMapCache.set(avID, bvID as VideoID); AvToBvLoading.delete(avID); }); @@ -96,7 +102,7 @@ export function validateYoutubeID(id: string): boolean { return exclusiveIdegex.test(id); } -export function parseYoutubeID(rawId: string): VideoID | null { +export function parseYoutubeID(rawId: string): YoutubeID | null { // first decode URI rawId = decodeURIComponent(rawId); // strict matching @@ -104,17 +110,17 @@ export function parseYoutubeID(rawId: string): VideoID | null { const urlMatch = rawId.match(urlRegex)?.[1]; const regexMatch = strictMatch - ? (strictMatch as VideoID) + ? (strictMatch as YoutubeID) : negativeRegex.test(rawId) ? null : urlMatch - ? (urlMatch as VideoID) + ? (urlMatch as YoutubeID) : null; return regexMatch ? regexMatch : parseYouTubeVideoIDFromURL(rawId); } -export function parseYouTubeVideoIDFromURL(url: string): VideoID | null { +export function parseYouTubeVideoIDFromURL(url: string): YoutubeID | null { if (url.startsWith("https://www.youtube.com/tv#/")) url = url.replace("#", ""); if (url.startsWith("https://www.youtube.com/tv?")) url = url.replace(/\?[^#]+#/, ""); @@ -132,12 +138,12 @@ export function parseYouTubeVideoIDFromURL(url: string): VideoID | null { urlObject.pathname.startsWith("/tv/watch") ) { const id = urlObject.searchParams.get("v"); - return id?.length == 11 ? (id as VideoID) : null; + return id?.length == 11 ? (id as YoutubeID) : null; } else if (urlObject.pathname.startsWith("/embed/") || urlObject.pathname.startsWith("/shorts/")) { try { const id = urlObject.pathname.split("/")[2]; if (id?.length >= 11) { - return id.slice(0, 11) as VideoID; + return id.slice(0, 11) as YoutubeID; } } catch (e) { console.error("[SB] Video ID not valid for " + url); diff --git a/src/utils/video.ts b/src/utils/video.ts index a5214ade..89b023af 100644 --- a/src/utils/video.ts +++ b/src/utils/video.ts @@ -1,7 +1,7 @@ import * as documentScript from "../../dist/js/document.js"; import Config from "../config"; import { newThumbnails } from "../thumbnail-utils/thumbnailManagement"; -import { PageType } from "../types"; +import { PageType, VideoID } from "../types"; import { waitFor } from "./"; import { addCleanupListener, setupCleanupListener } from "./cleanup"; import { getElement, isVisible, waitForElement } from "./dom"; @@ -9,7 +9,6 @@ import { getPropertyFromWindow } from "./injectedScriptMessageUtils"; import { getBilibiliVideoID } from "./parseVideoID"; import { injectScript } from "./scriptInjector"; -export type VideoID = string & { __videoID: never }; export type ChannelID = string & { __channelID: never }; export enum ChannelIDStatus { Fetching,