Skip to content

Commit

Permalink
Add type for different selectors
Browse files Browse the repository at this point in the history
  • Loading branch information
hanydd committed Jan 13, 2025
1 parent de204bb commit 2abd89e
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 36 deletions.
4 changes: 2 additions & 2 deletions src/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { getPortVideoByHash, postPortVideo, postPortVideoVote, updatePortedSegme
import { asyncRequestToServer } from "./requests/requests";
import { getSegmentsByHash } from "./requests/segments";
import { getVideoLabel } from "./requests/videoLabels";
import { setupThumbnailListener, updateAll } from "./thumbnail-utils/thumbnailManagement";
import { checkPageForNewThumbnails, setupThumbnailListener } from "./thumbnail-utils/thumbnailManagement";
import {
ActionType,
Category,
Expand Down Expand Up @@ -436,7 +436,7 @@ function contentConfigUpdateListener(changes: StorageChangesObject) {
break;
case "fullVideoSegments":
case "fullVideoLabelsOnThumbnails":
updateAll();
checkPageForNewThumbnails();
break;
}
}
Expand Down
12 changes: 8 additions & 4 deletions src/requests/videoLabels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ const labelCache: Record<string, LabelCacheEntry> = {};
const cacheLimit = 1000;

async function getLabelHashBlock(hashPrefix: string, refreshCache: boolean = false): Promise<LabelCacheEntry | null> {
// Check cache
const cachedEntry = labelCache[hashPrefix];
if (cachedEntry && !refreshCache) {
return cachedEntry;
if (refreshCache) {
delete labelCache[hashPrefix];
} else {
// Check cache
const cachedEntry = labelCache[hashPrefix];
if (cachedEntry) {
return cachedEntry;
}
}

const response = await asyncRequestToServer("GET", `/api/videoLabels/${hashPrefix}`, {}, refreshCache);
Expand Down
29 changes: 24 additions & 5 deletions src/thumbnail-utils/thumbnail-selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ interface ThumbnailSelector {
containerSelector: string;
thumbnailSelector: string;
customLinkSelector?: string;
customLinkAttribute?: string;
}

// TODO: support customLinkSelector
Expand All @@ -22,7 +23,6 @@ const thumbnailSelectors: { [key: string]: ThumbnailSelector } = {
// 历史视频弹出框
containerSelector: ".bili-header .right-entry .v-popover-wrap:nth-of-type(5) div.v-popover-content",
thumbnailSelector: "a.header-history-card",
customLinkSelector: "",
},
"mainPageRecommendation": {
// 主页
Expand Down Expand Up @@ -110,6 +110,14 @@ const pageTypeSepecialSelector: { [key in PageType]: string[] } = {
[PageType.Embed]: [],
};

const combinedPageTypeSelectors = {};
for (const pageType in pageTypeSepecialSelector) {
combinedPageTypeSelectors[pageType as PageType] = [
...commonSelector,
...pageTypeSepecialSelector[pageType as PageType],
];
}

const pageTypeSelector: { [key in PageType]?: ThumbnailSelector } = {};
const thumbnailElementSelectors: { [key in PageType]?: string[] } = {};
const thumbnailContainerSelectors: { [key in PageType]?: string[] } = {};
Expand All @@ -122,14 +130,25 @@ for (const [key, value] of Object.entries(pageTypeSepecialSelector)) {
thumbnailContainerSelectors[key] = combinedSelector.map((s) => thumbnailSelectors[s].containerSelector);
}

export function getThumbnailContainerElements(pageType: PageType) {
return thumbnailContainerSelectors[pageType];
export function getThumbnailContainerElements(pageType: PageType): { containerType: string; selector: string }[] {
return combinedPageTypeSelectors[pageType].map((type: string) => ({
containerType: type,
selector: thumbnailSelectors[type].containerSelector,
}));
}

export function getThumbnailLink(thumbnail: HTMLElement): HTMLElement | null {
return thumbnail.querySelector("a");
}

export function getThumbnailSelectors(pageType: PageType) {
return thumbnailElementSelectors[pageType].join(", ");
export function getThumbnailSelectors(containerType: string) {
return thumbnailSelectors[containerType].thumbnailSelector;
}

export function getLinkSelectors(containerType: string) {
return thumbnailSelectors[containerType].customLinkSelector ?? "a[href]";
}

export function getLinkAttribute(containerType: string) {
return thumbnailSelectors[containerType].customLinkAttribute ?? "href";
}
22 changes: 10 additions & 12 deletions src/thumbnail-utils/thumbnailManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { waitFor } from "../utils/";
import { addCleanupListener } from "../utils/cleanup";
import { getPageType } from "../utils/video";
import { getThumbnailContainerElements, getThumbnailSelectors } from "./thumbnail-selectors";
import { insertSBIconDefinition, labelThumbnail, labelThumbnails } from "./thumbnails";
import { insertSBIconDefinition, labelThumbnail } from "./thumbnails";

export type ThumbnailListener = (newThumbnails: HTMLElement[]) => void;

Expand All @@ -15,10 +15,11 @@ export function setupThumbnailListener(): void {
onInitialLoad();

// listen to container child changes
getThumbnailContainerElements(getPageType()).forEach((selector) => {
getThumbnailContainerElements(getPageType()).forEach(({ containerType, selector }) => {
console.log(containerType, selector);
void waitFor(() => document.querySelector(selector), 10000)
.then((thumbnailContainer) => {
labelNewThumbnails(thumbnailContainer); // fire thumbnail check once when the container is loaded
labelNewThumbnails(thumbnailContainer, containerType); // fire thumbnail check once when the container is loaded
if (!thumbnailContainer) return;
thumbnailContainerObserver ??= new MutationObserver(() => checkPageForNewThumbnails());
thumbnailContainerObserver?.observe(thumbnailContainer, { childList: true, subtree: true });
Expand Down Expand Up @@ -70,19 +71,16 @@ export function checkPageForNewThumbnails() {
}
lastThumbnailCheck = performance.now();

for (const selector of getThumbnailContainerElements(getPageType())) {
for (const { containerType, selector } of getThumbnailContainerElements(getPageType())) {
waitFor(() => document.querySelector(selector), 10000)
.then((thumbnailContainer) => labelNewThumbnails(thumbnailContainer))
.then((thumbnailContainer) => labelNewThumbnails(thumbnailContainer, containerType))
.catch((err) => console.log(err));
}
}

async function labelNewThumbnails(container: Element) {
async function labelNewThumbnails(container: Element, containerType: string) {
if (!container || !document.body.contains(container)) return;
const thumbnails = container.querySelectorAll(getThumbnailSelectors(getPageType())) as NodeListOf<HTMLElement>;
thumbnails.forEach((t) => labelThumbnail(t as HTMLImageElement));
}

export function updateAll(): void {
labelThumbnails([...handledThumbnailsObserverMap.keys()]);
const thumbnails = container.querySelectorAll(getThumbnailSelectors(containerType)) as NodeListOf<HTMLElement>;
console.log(thumbnails);
thumbnails.forEach((t) => labelThumbnail(t as HTMLImageElement, containerType));
}
28 changes: 15 additions & 13 deletions src/thumbnail-utils/thumbnails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,31 @@ import Config from "../config";
import { getVideoLabel } from "../requests/videoLabels";
import { waitFor } from "../utils/";
import { getBvIDFromURL } from "../utils/parseVideoID";
import { getLinkAttribute, getLinkSelectors } from "./thumbnail-selectors";

export async function labelThumbnails(thumbnails: HTMLElement[]): Promise<void> {
await Promise.all(thumbnails.map((t) => labelThumbnail(t as HTMLElement)));
export async function labelThumbnails(thumbnails: HTMLElement[], containerType: string): Promise<void> {
await Promise.all(thumbnails.map((t) => labelThumbnail(t as HTMLElement, containerType)));
}

export async function labelThumbnail(thumbnail: HTMLElement, thumbnailOldHref?: string): Promise<HTMLElement | null> {
export async function labelThumbnail(thumbnail: HTMLElement, containerType: string): Promise<HTMLElement | null> {
if (!Config.config?.fullVideoSegments || !Config.config?.fullVideoLabelsOnThumbnails) {
hideThumbnailLabel(thumbnail);
return null;
}

// find all links in the thumbnail, reduce to only one video ID
const links: HTMLAnchorElement[] = thumbnail.matches("a[href]") ? [thumbnail as HTMLAnchorElement] : [];
links.push(...Array.from(thumbnail.querySelectorAll("a[href]") as NodeListOf<HTMLAnchorElement>));
const links: HTMLAnchorElement[] = thumbnail.matches(getLinkSelectors(containerType))
? [thumbnail as HTMLAnchorElement]
: [];
links.push(
...Array.from(thumbnail.querySelectorAll(getLinkSelectors(containerType)) as NodeListOf<HTMLAnchorElement>)
);
const videoIDs = new Set(
(await Promise.allSettled(links.filter((link) => link && link.href).map((link) => getBvIDFromURL(link.href))))
(
await Promise.allSettled(
links.map((link) => getBvIDFromURL(link.getAttribute(getLinkAttribute(containerType))))
)
)
.filter((result) => result.status === "fulfilled")
.map((result) => result.value)
.filter((id) => !!id)
Expand All @@ -32,13 +41,6 @@ export async function labelThumbnail(thumbnail: HTMLElement, thumbnailOldHref?:
// 获取或创建缩略图标签
const { overlay, text } = await createOrGetThumbnail(thumbnail);

if (thumbnailOldHref) {
const oldVideoID = await getBvIDFromURL(thumbnailOldHref);
if (oldVideoID && oldVideoID == videoID) {
return overlay;
}
}

const category = await getVideoLabel(videoID);
if (!category) {
hideThumbnailLabel(thumbnail);
Expand Down

0 comments on commit 2abd89e

Please sign in to comment.