Files
AFFiNE-Mirror/blocksuite/affine/blocks/embed/src/embed-youtube-block/utils.ts
T
donteatfriedrice 0d518adc5b refactor(editor): add cache extension for link preview service (#12196)
Closes: [BS-2578](https://linear.app/affine-design/issue/BS-2578/优化-footnote-预览的逻辑:支持缓存结果,避免重复-loading)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced a link preview caching mechanism, enabling faster and more efficient reuse of link preview data across the app.
  - Added a feature flag for enabling or disabling link preview cache, configurable through workspace experimental settings.
  - Enhanced localization with new entries describing the link preview cache feature.

- **Improvements**
  - Updated link preview service architecture for better extensibility and maintainability.
  - Improved integration of feature flags throughout chat and rendering components.

- **Bug Fixes**
  - Fixed tooltip formatting for footnote URLs.

- **Chores**
  - Updated dependencies and localization completeness tracking.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-05-13 05:11:34 +00:00

115 lines
2.9 KiB
TypeScript

import type {
EmbedYoutubeBlockUrlData,
EmbedYoutubeModel,
} from '@blocksuite/affine-model';
import type { LinkPreviewProvider } from '@blocksuite/affine-shared/services';
import { isAbortError } from '@blocksuite/affine-shared/utils';
import type { EmbedYoutubeBlockComponent } from './embed-youtube-block.js';
export async function queryEmbedYoutubeData(
embedYoutubeModel: EmbedYoutubeModel,
linkPreviewer: LinkPreviewProvider,
signal?: AbortSignal
): Promise<Partial<EmbedYoutubeBlockUrlData>> {
const url = embedYoutubeModel.props.url;
const [videoOpenGraphData, videoOEmbedData] = await Promise.all([
linkPreviewer.query(url, signal),
queryYoutubeOEmbedData(url, signal),
]);
const youtubeEmbedData: Partial<EmbedYoutubeBlockUrlData> = {
...videoOpenGraphData,
...videoOEmbedData,
};
if (youtubeEmbedData.creatorUrl) {
const creatorOpenGraphData = await linkPreviewer.query(
youtubeEmbedData.creatorUrl,
signal
);
youtubeEmbedData.creatorImage = creatorOpenGraphData.image;
}
return youtubeEmbedData;
}
export async function queryYoutubeOEmbedData(
url: string,
signal?: AbortSignal
): Promise<Partial<EmbedYoutubeBlockUrlData>> {
let youtubeOEmbedData: Partial<EmbedYoutubeBlockUrlData> = {};
const oEmbedUrl = `https://youtube.com/oembed?url=${url}&format=json`;
const oEmbedResponse = await fetch(oEmbedUrl, { signal }).catch(() => null);
if (oEmbedResponse && oEmbedResponse.ok) {
const oEmbedJson = await oEmbedResponse.json();
const { title, author_name, author_url } = oEmbedJson;
youtubeOEmbedData = {
title,
creator: author_name,
creatorUrl: author_url,
};
}
return youtubeOEmbedData;
}
export async function refreshEmbedYoutubeUrlData(
embedYoutubeElement: EmbedYoutubeBlockComponent,
signal?: AbortSignal
): Promise<void> {
let image = null,
title = null,
description = null,
creator = null,
creatorUrl = null,
creatorImage = null;
try {
embedYoutubeElement.loading = true;
// TODO(@mirone): remove service
const queryUrlData = embedYoutubeElement.service?.queryUrlData;
if (!queryUrlData) {
console.error(
`Trying to refresh youtube url data, but the queryUrlData is not found.`
);
return;
}
const youtubeUrlData = await queryUrlData(
embedYoutubeElement.model,
signal
);
({
image = null,
title = null,
description = null,
creator = null,
creatorUrl = null,
creatorImage = null,
} = youtubeUrlData);
if (signal?.aborted) return;
embedYoutubeElement.store.updateBlock(embedYoutubeElement.model, {
image,
title,
description,
creator,
creatorUrl,
creatorImage,
});
} catch (error) {
if (signal?.aborted || isAbortError(error)) return;
throw error;
} finally {
embedYoutubeElement.loading = false;
}
}