WebPage: Render preview and audio document (#4345)

This commit is contained in:
Alexander Zinchuk 2024-03-08 12:48:52 +01:00
parent 70dfa2e160
commit f8bcd32865
8 changed files with 96 additions and 21 deletions

View File

@ -216,6 +216,39 @@ export function buildVideoFromDocument(document: GramJs.Document, isSpoiler?: bo
};
}
export function buildAudioFromDocument(document: GramJs.Document): ApiAudio | undefined {
if (document instanceof GramJs.DocumentEmpty) {
return undefined;
}
const {
id, mimeType, size, attributes,
} = document;
const audioAttributes = attributes
.find((a: any): a is GramJs.DocumentAttributeAudio => a instanceof GramJs.DocumentAttributeAudio);
if (!audioAttributes) {
return undefined;
}
const {
duration,
title,
performer,
} = audioAttributes;
return {
id: String(id),
mimeType,
duration,
fileName: getFilenameFromDocument(document, 'audio'),
title,
performer,
size: size.toJSNumber(),
};
}
function buildVideo(media: GramJs.TypeMessageMedia): ApiVideo | undefined {
if (
!(media instanceof GramJs.MessageMediaDocument)
@ -653,9 +686,13 @@ export function buildWebPage(media: GramJs.TypeMessageMedia): ApiWebPage | undef
} = media.webpage;
let video;
let audio;
if (document instanceof GramJs.Document && document.mimeType.startsWith('video/')) {
video = buildVideoFromDocument(document);
}
if (document instanceof GramJs.Document && document.mimeType.startsWith('audio/')) {
audio = buildAudioFromDocument(document);
}
let story: ApiWebPageStoryData | undefined;
const attributeStory = attributes
?.find((a: any): a is GramJs.WebPageAttributeStory => a instanceof GramJs.WebPageAttributeStory);
@ -683,8 +720,9 @@ export function buildWebPage(media: GramJs.TypeMessageMedia): ApiWebPage | undef
'duration',
]),
photo: photo instanceof GramJs.Photo ? buildApiPhoto(photo) : undefined,
document: !video && document ? buildApiDocument(document) : undefined,
document: !video && !audio && document ? buildApiDocument(document) : undefined,
video,
audio,
story,
};
}

View File

@ -329,6 +329,7 @@ export interface ApiWebPage {
title?: string;
description?: string;
photo?: ApiPhoto;
audio?: ApiAudio;
duration?: number;
document?: ApiDocument;
video?: ApiVideo;

View File

@ -16,6 +16,7 @@ import {
getMediaTransferState,
getMessageMediaFormat,
getMessageMediaHash,
getMessageWebPageAudio,
hasMessageTtl,
isMessageLocal,
isOwnMessage,
@ -67,7 +68,7 @@ type OwnProps = {
isTranscriptionError?: boolean;
autoPlay?: boolean;
onHideTranscription?: (isHidden: boolean) => void;
onPlay: (messageId: number, chatId: string) => void;
onPlay?: (messageId: number, chatId: string) => void;
onPause?: NoneToVoidFunction;
onReadMedia?: () => void;
onCancelUpload?: () => void;
@ -112,9 +113,10 @@ const Audio: FC<OwnProps> = ({
const {
content: {
audio, voice, video,
audio: contentAudio, voice, video,
}, isMediaUnread,
} = message;
const audio = contentAudio || getMessageWebPageAudio(message);
const isVoice = Boolean(voice || video);
const isSeeking = useRef<boolean>(false);
// eslint-disable-next-line no-null/no-null
@ -145,7 +147,7 @@ const Audio: FC<OwnProps> = ({
const handleForcePlay = useLastCallback(() => {
setIsActivated(true);
onPlay(message.id, message.chatId);
onPlay?.(message.id, message.chatId);
});
const handleTrackChange = useLastCallback(() => {
@ -228,7 +230,7 @@ const Audio: FC<OwnProps> = ({
}
if (!isPlaying) {
onPlay(message.id, message.chatId);
onPlay?.(message.id, message.chatId);
}
getActions().setAudioPlayerOrigin({ origin });

View File

@ -642,7 +642,7 @@
}
&.has-replies:not(.custom-shape),
&.text {
&.text:not(.web-page) {
.media-inner,
.Album {
--border-bottom-left-radius: 0;

View File

@ -1228,6 +1228,7 @@ const Message: FC<OwnProps & StateProps> = ({
backgroundEmojiId={sender?.color?.backgroundEmojiId}
shouldWarnAboutSvg={shouldWarnAboutSvg}
autoLoadFileMaxSizeMb={autoLoadFileMaxSizeMb}
onAudioPlay={handleAudioPlay}
onMediaClick={handleMediaClick}
onCancelMediaTransfer={handleCancelUpload}
/>

View File

@ -9,6 +9,10 @@
border-radius: 0.25rem;
position: relative;
overflow: hidden;
&.with-video {
padding: 0.1875rem 0.375rem;
}
&.with-document {
--file-icon-border-color: var(--accent-background-color);
@ -77,13 +81,15 @@
.media-inner {
margin: 0 !important;
margin-bottom: 0.375rem !important;
&,
& img,
& canvas,
&.small-image img {
border-radius: var(--border-radius-messages-small) !important;
--border-top-left-radius: var(--border-radius-messages-small);
--border-top-right-radius: var(--border-radius-messages-small);
--border-bottom-left-radius: var(--border-radius-messages-small);
--border-bottom-right-radius: var(--border-radius-messages-small);
}
&.square-image {
@ -100,11 +106,6 @@
}
}
&.with-video .media-inner {
margin-top: 0.5rem !important;
margin-bottom: 1rem !important;
}
.message-content:not(.has-reactions) & {
margin-bottom: calc(var(--message-meta-height)) !important;
}

View File

@ -4,7 +4,7 @@ import { getActions } from '../../../global';
import type { ApiMessage, ApiTypeStory } from '../../../api/types';
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
import type { ISettings } from '../../../types';
import { AudioOrigin, type ISettings } from '../../../types';
import { getMessageWebPage } from '../../../global/helpers';
import buildClassName from '../../../util/buildClassName';
@ -18,6 +18,7 @@ import useEnsureStory from '../../../hooks/useEnsureStory';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import Audio from '../../common/Audio';
import Document from '../../common/Document';
import EmojiIconBackground from '../../common/embedded/EmojiIconBackground';
import SafeLink from '../../common/SafeLink';
@ -47,8 +48,9 @@ type OwnProps = {
story?: ApiTypeStory;
shouldWarnAboutSvg?: boolean;
autoLoadFileMaxSizeMb?: number;
onMediaClick?: () => void;
onCancelMediaTransfer?: () => void;
onAudioPlay?: NoneToVoidFunction;
onMediaClick?: NoneToVoidFunction;
onCancelMediaTransfer?: NoneToVoidFunction;
};
const WebPage: FC<OwnProps> = ({
@ -68,6 +70,7 @@ const WebPage: FC<OwnProps> = ({
shouldWarnAboutSvg,
autoLoadFileMaxSizeMb,
onMediaClick,
onAudioPlay,
onCancelMediaTransfer,
}) => {
const { openTelegramLink } = getActions();
@ -103,6 +106,7 @@ const WebPage: FC<OwnProps> = ({
description,
photo,
video,
audio,
type,
document,
} = webPage;
@ -200,6 +204,17 @@ const WebPage: FC<OwnProps> = ({
onCancelUpload={onCancelMediaTransfer}
/>
)}
{!inPreview && audio && (
<Audio
theme={theme}
message={message}
origin={AudioOrigin.Inline}
noAvatars={noAvatars}
isDownloading={isDownloading}
onPlay={onAudioPlay}
onCancelUpload={onCancelMediaTransfer}
/>
)}
{!inPreview && document && (
<Document
message={message}
@ -211,6 +226,18 @@ const WebPage: FC<OwnProps> = ({
shouldWarnAboutSvg={shouldWarnAboutSvg}
/>
)}
{inPreview && displayUrl && !isArticle && (
<div className="WebPage-text">
{backgroundEmojiId && (
<EmojiIconBackground
emojiDocumentId={backgroundEmojiId}
className="WebPage--background-icons"
/>
)}
<p className="site-name">{displayUrl}</p>
<p className="site-description">{lang('Chat.Empty.LinkPreview')}</p>
</div>
)}
</div>
{quickButtonLangKey && renderQuickButton(quickButtonLangKey)}
</div>

View File

@ -155,6 +155,10 @@ export function getMessageWebPageVideo(message: MediaContainer) {
return getMessageWebPage(message)?.video;
}
export function getMessageWebPageAudio(message: MediaContainer) {
return getMessageWebPage(message)?.audio;
}
export function getMessageDocumentVideo(message: MediaContainer) {
return isMessageDocumentVideo(message) ? getMessageDocument(message) : undefined;
}
@ -218,8 +222,9 @@ export function getMessageMediaHash(
const actionPhoto = getMessageActionPhoto(message);
const messageVideo = video || getMessageWebPageVideo(message) || getMessageDocumentVideo(message);
const messageDocument = document || getMessageWebPageDocument(message);
const messageAudio = audio || getMessageWebPageAudio(message);
const content = actionPhoto || messagePhoto || messageVideo || sticker || audio || voice || messageDocument;
const content = actionPhoto || messagePhoto || messageVideo || sticker || messageAudio || voice || messageDocument;
if (!content) {
return undefined;
}
@ -288,13 +293,13 @@ export function getMessageMediaHash(
}
}
if (audio) {
if (messageAudio) {
switch (target) {
case 'micro':
case 'pictogram':
return getAudioHasCover(audio) ? `${base}?size=m` : undefined;
return getAudioHasCover(messageAudio) ? `${base}?size=m` : undefined;
case 'inline':
return getVideoOrAudioBaseHash(audio, base);
return getVideoOrAudioBaseHash(messageAudio, base);
case 'download':
return `${base}?download`;
}
@ -517,7 +522,7 @@ export function getMessageContentIds(
export function getMediaDuration(message: ApiMessage) {
const { audio, voice, video } = getMessageContent(message);
const media = audio || voice || video || getMessageWebPageVideo(message);
const media = audio || voice || video || getMessageWebPageVideo(message) || getMessageWebPageAudio(message);
if (!media) {
return undefined;
}