From 0e5c0518b885de7873da301dac3f0cc61bbde984 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Fri, 29 Nov 2024 18:36:13 +0800 Subject: [PATCH 1/2] chore: bump version to 2.29.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ec98a6dfefb..af2aa19c799d 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "yarn": ">=999.0.0", "npm": ">=999.0.0" }, - "version": "2.29.0", + "version": "2.29.1", "private": true, "license": "AGPL-3.0-or-later", "scripts": { From d1420af4b42d352fa5c4e9bc9c0df7392c9d52be Mon Sep 17 00:00:00 2001 From: Jack Works <5390719+Jack-Works@users.noreply.github.com> Date: Fri, 29 Nov 2024 18:35:39 +0800 Subject: [PATCH 2/2] fix: x image with correct size and no dup (#11961) --- .../content-script/site-adaptor-infra/ui.ts | 8 ++++++- .../twitter.com/collecting/post.ts | 10 +++++---- .../customization/render-fragments.tsx | 9 ++++++++ .../site-adaptors/twitter.com/utils/fetch.ts | 21 +++++++++++++------ .../react/src/Renderer/Core/Image.tsx | 8 ++++++- .../src/Renderer/utils/RenderFragments.tsx | 2 ++ 6 files changed, 46 insertions(+), 12 deletions(-) diff --git a/packages/mask/content-script/site-adaptor-infra/ui.ts b/packages/mask/content-script/site-adaptor-infra/ui.ts index e898b735edc8..a947ec7c5915 100644 --- a/packages/mask/content-script/site-adaptor-infra/ui.ts +++ b/packages/mask/content-script/site-adaptor-infra/ui.ts @@ -54,8 +54,14 @@ export async function activateSiteAdaptorUIInner(ui_deferred: SiteAdaptorUI.Defe sharedUIComponentOverwrite.value = ui.customization.sharedComponentOverwrite } - console.log('[Mask] Provider activated. globalThis.ui =', ui) + console.log( + '[Mask] Provider activated. globalThis.ui =', + ui, + 'globalThis.currentPosts =', + ui.collecting.postsProvider?.posts, + ) setDebugObject('ui', ui) + setDebugObject('currentPosts', ui.collecting.postsProvider?.posts) const abort = new AbortController() const { signal } = abort diff --git a/packages/mask/content-script/site-adaptors/twitter.com/collecting/post.ts b/packages/mask/content-script/site-adaptors/twitter.com/collecting/post.ts index e64cbaac2484..e26dbbd41650 100644 --- a/packages/mask/content-script/site-adaptors/twitter.com/collecting/post.ts +++ b/packages/mask/content-script/site-adaptors/twitter.com/collecting/post.ts @@ -7,7 +7,6 @@ import { FlattenTypedMessage, extractTextFromTypedMessage, makeTypedMessageEmpty, - makeTypedMessageImage, makeTypedMessagePromise, makeTypedMessageTuple, makeTypedMessageTupleFromList, @@ -191,9 +190,12 @@ function collectPostInfo( // don't add await on this const images = untilElementAvailable(postsImageSelector(tweetNode), 10000) .then(() => postImagesParser(tweetNode)) - .then((urls) => { - for (const url of urls) info.postMetadataImages.add(url) - if (urls.length) return makeTypedMessageTupleFromList(...urls.map((x) => makeTypedMessageImage(x))) + .then((images) => { + for (const image of images) { + if (typeof image.image === 'string') info.postMetadataImages.add(image.image) + } + if (images.length === 1) return images[0] + if (images.length) return makeTypedMessageTupleFromList(...images) return makeTypedMessageEmpty() }) .catch(() => makeTypedMessageEmpty()) diff --git a/packages/mask/content-script/site-adaptors/twitter.com/customization/render-fragments.tsx b/packages/mask/content-script/site-adaptors/twitter.com/customization/render-fragments.tsx index b9dacb5f8e5e..172d6bdaf2d3 100644 --- a/packages/mask/content-script/site-adaptors/twitter.com/customization/render-fragments.tsx +++ b/packages/mask/content-script/site-adaptors/twitter.com/customization/render-fragments.tsx @@ -3,6 +3,10 @@ import { Link } from '@mui/material' import type { RenderFragmentsContextType } from '@masknet/typed-message-react' import { useTagEnhancer } from '../../../../shared-ui/TypedMessageRender/Components/Text.js' +/** + * For images that are rendered at the end of the post (parsed by postImagesParser), hide it in the render fragment so it won't render twice. + */ +export const IMAGE_RENDER_IGNORE = 'IMAGE_RENDER_IGNORE' export const TwitterRenderFragments: RenderFragmentsContextType = { AtLink: memo(function (props) { const target = '/' + props.children.slice(1) @@ -24,4 +28,9 @@ export const TwitterRenderFragments: RenderFragmentsContextType = { const { hasMatch, ...events } = useTagEnhancer('cash', props.children.slice(1)) return }), + Image: memo(function ImageFragment(props: RenderFragmentsContextType.ImageProps) { + return props.width === 0 || props.meta?.get(IMAGE_RENDER_IGNORE) ? + null + : + }), } diff --git a/packages/mask/content-script/site-adaptors/twitter.com/utils/fetch.ts b/packages/mask/content-script/site-adaptors/twitter.com/utils/fetch.ts index 84e7862e4bc6..84ff7653bedc 100644 --- a/packages/mask/content-script/site-adaptors/twitter.com/utils/fetch.ts +++ b/packages/mask/content-script/site-adaptors/twitter.com/utils/fetch.ts @@ -15,6 +15,7 @@ import { type TypedMessageImage, } from '@masknet/typed-message' import { collectNodeText, collectTwitterEmoji } from '../../../utils/index.js' +import { IMAGE_RENDER_IGNORE } from '../customization/render-fragments.js' /** * Get post id from dom, including normal tweet, quoted tweet and retweet one @@ -175,16 +176,24 @@ function getElementStyle(element: Element | null): Meta | undefined { return undefined } -export async function postImagesParser(node: HTMLElement): Promise { +export async function postImagesParser(node: HTMLElement): Promise { const isQuotedTweet = !!node.closest('div[role="link"]') const imgNodes = node.querySelectorAll('img[src*="twimg.com/media"]') if (!imgNodes.length) return [] - const imgUrls = Array.from(imgNodes) + const tms = Array.from(imgNodes) .filter((node) => isQuotedTweet || !node.closest('div[role="link"]')) - .flatMap((node) => normalizeImageURL(node.getAttribute('src') ?? '')) - .filter(Boolean) - if (!imgUrls.length) return [] - return imgUrls + .flatMap((node) => { + let src = normalizeImageURL(node.getAttribute('src') ?? '') + if (Array.isArray(src)) src = src.filter(Boolean) + if (!src.length) return [] + // TODO: the parser may return 2 different URLs for png and jpeg + return makeTypedMessageImage( + Array.isArray(src) ? src[0] : src, + { width: node.width, height: node.height }, + new Map([[IMAGE_RENDER_IGNORE, true]]), + ) + }) + return tms } export function postParser(node: HTMLElement) { diff --git a/packages/typed-message/react/src/Renderer/Core/Image.tsx b/packages/typed-message/react/src/Renderer/Core/Image.tsx index 2f70d968ec9d..f2310ac90375 100644 --- a/packages/typed-message/react/src/Renderer/Core/Image.tsx +++ b/packages/typed-message/react/src/Renderer/Core/Image.tsx @@ -26,7 +26,13 @@ export const TypedMessageImageRender = memo(function TypedMessageImageRender(pro return ( <> - + {meta} ) diff --git a/packages/typed-message/react/src/Renderer/utils/RenderFragments.tsx b/packages/typed-message/react/src/Renderer/utils/RenderFragments.tsx index b7ab6e1a91d9..3e6cd2a20105 100644 --- a/packages/typed-message/react/src/Renderer/utils/RenderFragments.tsx +++ b/packages/typed-message/react/src/Renderer/utils/RenderFragments.tsx @@ -1,5 +1,6 @@ import { createContext, memo } from 'react' import type { MetadataRenderProps } from '../MetadataRender.js' +import type { Meta } from '@masknet/typed-message' export const DefaultRenderFragments = { Text: memo(function TextFragment(props: RenderFragmentsContextType.TextProps) { @@ -72,6 +73,7 @@ export declare namespace RenderFragmentsContextType { width?: number height?: number aspectRatio?: number + meta?: Meta } } export const RenderFragmentsContext = createContext(DefaultRenderFragments)