Sending URL Preview Bundles (MSC 4095) (#34150)
* Fetches link previews for all links in message (instead of just the first one) * message url component to display preview for multiple urls * Revert visible behaviour back to only showing one URL preview While fetching all link previews in the text message. * Moved URL preview VM to MessageComposer * Added com.beeper.linkpreviews to messages sent with the markdown compositor * MSC 4452 implemented for the older (markdown) composer * claude told me to use logger instead of console * Previews generated with snapshot instead of vm * moved attachPreviews to a separate file * added attach URL previews to rich text editor * don't let attachUrlPreviews block clearning the composer * fixed linter errors * moved url preview behind labs feature gate * passed linters * moved lab feature checking to where attach preview is used * claude wrote some unit tests for url previewing * fixed linter errors * added feature to labs.md * fixed linter errors * fixed oxfmt error * set previews to none if all previews failed * resolved PR reviews besides the ones that requires a larger code change * moved url preview VM creation to message composer * removed delay when clearing composer url preview on message send * minor changes to stop using globals everywhere * moved debouncing responsibility to urlpreviewVM * minor lint fixes * added comment * remove composer content from the state of urlpreview, moved it to the vm * urlpreviewwrapper depends on the vm only * added comments * edited the comment * updated snapshots * claude fixed tests * enable feature for tests that requires MSC4095 * updated snapshot
This commit is contained in:
@@ -160,11 +160,13 @@ export class UrlPreviewFetcher {
|
||||
let siteIcon: string | undefined;
|
||||
|
||||
if (typeof response["og:image"] === "string" && loadMedia) {
|
||||
const mxcImageFull = response["og:image"];
|
||||
const media = mediaFromMxc(response["og:image"], this.client);
|
||||
const declaredHeight = UrlPreviewFetcher.getNumberFromOpenGraph(response["og:image:height"]);
|
||||
const declaredWidth = UrlPreviewFetcher.getNumberFromOpenGraph(response["og:image:width"]);
|
||||
const imageSize = UrlPreviewFetcher.getNumberFromOpenGraph(response["matrix:image:size"]);
|
||||
const alt = typeof response["og:image:alt"] === "string" ? response["og:image:alt"] : undefined;
|
||||
const imageType = typeof response["og:image:type"] === "string" ? response["og:image:type"] : undefined;
|
||||
|
||||
if (UrlPreviewFetcher.isImagePreview(declaredWidth, declaredHeight, imageSize)) {
|
||||
const width = Math.min(declaredWidth ?? PREVIEW_WIDTH_PX, PREVIEW_WIDTH_PX);
|
||||
@@ -176,6 +178,8 @@ export class UrlPreviewFetcher {
|
||||
image = {
|
||||
imageThumb: thumb,
|
||||
imageFull: media.srcHttp ?? thumb,
|
||||
mxcImageFull,
|
||||
imageType,
|
||||
width,
|
||||
height,
|
||||
fileSize: UrlPreviewFetcher.getNumberFromOpenGraph(response["matrix:image:size"]),
|
||||
@@ -195,6 +199,7 @@ export class UrlPreviewFetcher {
|
||||
description,
|
||||
siteName,
|
||||
siteIcon,
|
||||
ogUrl: response["og:url"],
|
||||
showTooltipOnLink: !!(link !== title && this.showTooltips),
|
||||
image,
|
||||
} satisfies UrlPreview;
|
||||
|
||||
@@ -6,6 +6,7 @@ exports[`UrlPreviewFetcher > handles different kinds of opengraph responses { 'o
|
||||
"description": undefined,
|
||||
"image": undefined,
|
||||
"link": "https://example.org",
|
||||
"ogUrl": "https://example.org",
|
||||
"showTooltipOnLink": false,
|
||||
"siteIcon": undefined,
|
||||
"siteName": "example.org",
|
||||
@@ -19,6 +20,7 @@ exports[`UrlPreviewFetcher > handles different kinds of opengraph responses { 'o
|
||||
"description": undefined,
|
||||
"image": undefined,
|
||||
"link": "https://example.org",
|
||||
"ogUrl": "https://example.org",
|
||||
"showTooltipOnLink": false,
|
||||
"siteIcon": undefined,
|
||||
"siteName": "Site name",
|
||||
@@ -32,6 +34,7 @@ exports[`UrlPreviewFetcher > handles different kinds of opengraph responses { 'o
|
||||
"description": undefined,
|
||||
"image": undefined,
|
||||
"link": "https://example.org",
|
||||
"ogUrl": "https://example.org",
|
||||
"showTooltipOnLink": false,
|
||||
"siteIcon": undefined,
|
||||
"siteName": "example.org",
|
||||
@@ -45,6 +48,7 @@ exports[`UrlPreviewFetcher > handles different kinds of opengraph responses { 'o
|
||||
"description": undefined,
|
||||
"image": undefined,
|
||||
"link": "https://example.org",
|
||||
"ogUrl": "https://example.org",
|
||||
"showTooltipOnLink": false,
|
||||
"siteIcon": undefined,
|
||||
"siteName": "Cool site",
|
||||
@@ -62,10 +66,13 @@ exports[`UrlPreviewFetcher > handles different kinds of opengraph responses { 'o
|
||||
"height": 478,
|
||||
"imageFull": "https://example.org/image/src",
|
||||
"imageThumb": "https://example.org/image/thumb",
|
||||
"imageType": undefined,
|
||||
"mxcImageFull": "mxc://example.org/abc",
|
||||
"playable": false,
|
||||
"width": 478,
|
||||
},
|
||||
"link": "https://example.org",
|
||||
"ogUrl": "https://example.org",
|
||||
"showTooltipOnLink": false,
|
||||
"siteIcon": undefined,
|
||||
"siteName": "example.org",
|
||||
@@ -83,10 +90,13 @@ exports[`UrlPreviewFetcher > should preview a URL with media 1`] = `
|
||||
"height": 128,
|
||||
"imageFull": "https://example.org/image/src",
|
||||
"imageThumb": "https://example.org/image/thumb",
|
||||
"imageType": undefined,
|
||||
"mxcImageFull": "mxc://example.org/abc",
|
||||
"playable": false,
|
||||
"width": 128,
|
||||
},
|
||||
"link": "https://example.org",
|
||||
"ogUrl": "https://example.org",
|
||||
"showTooltipOnLink": false,
|
||||
"siteIcon": undefined,
|
||||
"siteName": "example.org",
|
||||
|
||||
@@ -6,9 +6,12 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type MatrixEvent, type IContent, type IMentions, type IEventRelation } from "matrix-js-sdk/src/matrix";
|
||||
import { type MessageComposerUrlPreviewSnapshot } from "@element-hq/web-shared-components";
|
||||
|
||||
import type EditorModel from "../editor/model";
|
||||
import { Type } from "../editor/parts";
|
||||
import { type RoomMessageEventContent } from "../../@types/url-preview";
|
||||
import SettingsStore from "../settings/SettingsStore";
|
||||
|
||||
/**
|
||||
* Build the mentions information based on the editor model (and any related events):
|
||||
@@ -107,3 +110,25 @@ export function attachRelation(content: IContent, relation?: IEventRelation): vo
|
||||
};
|
||||
}
|
||||
}
|
||||
export function attachUrlPreviews(
|
||||
urlPreviewSnapshot: MessageComposerUrlPreviewSnapshot,
|
||||
content: RoomMessageEventContent,
|
||||
): void {
|
||||
if (!SettingsStore.getValue("feature_msc4095_url_preview_bundle")) return;
|
||||
|
||||
if (urlPreviewSnapshot.previews.length) {
|
||||
content["com.beeper.linkpreviews"] = urlPreviewSnapshot.previews.map((preview) => {
|
||||
return {
|
||||
"matched_url": preview.link,
|
||||
"og:url": preview.ogUrl,
|
||||
"og:title": preview.title,
|
||||
"og:description": preview.description,
|
||||
"og:image": preview.image?.mxcImageFull,
|
||||
"og:image:width": preview.image?.width,
|
||||
"og:image:height": preview.image?.height,
|
||||
"og:image:type": preview.image?.imageType,
|
||||
"matrix:image:size": preview.image?.fileSize,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user