diff --git a/src/api/gramjs/apiBuilders/messageContent.ts b/src/api/gramjs/apiBuilders/messageContent.ts index ef67d09d8..2c8963df5 100644 --- a/src/api/gramjs/apiBuilders/messageContent.ts +++ b/src/api/gramjs/apiBuilders/messageContent.ts @@ -118,8 +118,8 @@ export function buildMessageMediaContent( if (photo) return { photo }; const video = buildVideo(media); - const altVideo = buildAltVideo(media); - if (video) return { video, altVideo }; + const altVideos = buildAltVideos(media); + if (video) return { video, altVideos }; const audio = buildAudio(media); if (audio) return { audio }; @@ -280,16 +280,20 @@ function buildVideo(media: GramJs.TypeMessageMedia): ApiVideo | undefined { return buildVideoFromDocument(media.document, media.spoiler); } -function buildAltVideo(media: GramJs.TypeMessageMedia): ApiVideo | undefined { - if ( - !(media instanceof GramJs.MessageMediaDocument) - || !(media.altDocument instanceof GramJs.Document) - || !media.altDocument.mimeType.startsWith('video') - ) { +function buildAltVideos(media: GramJs.TypeMessageMedia): ApiVideo[] | undefined { + if (!(media instanceof GramJs.MessageMediaDocument) || !media.altDocuments) { return undefined; } - return buildVideoFromDocument(media.altDocument, media.spoiler); + const altVideos = media.altDocuments.filter((d): d is GramJs.Document => ( + d instanceof GramJs.Document && d.mimeType.startsWith('video') + )).map((alt) => buildVideoFromDocument(alt, media.spoiler)) + .filter(Boolean); + if (!altVideos.length) { + return undefined; + } + + return altVideos; } function buildAudio(media: GramJs.TypeMessageMedia): ApiAudio | undefined { diff --git a/src/api/gramjs/helpers.ts b/src/api/gramjs/helpers.ts index 67656741b..d72ee3ae5 100644 --- a/src/api/gramjs/helpers.ts +++ b/src/api/gramjs/helpers.ts @@ -126,9 +126,11 @@ export function addStoryToLocalDb(story: GramJs.TypeStoryItem, peerId: string) { addDocumentToLocalDb(doc); } - if (story.media.altDocument instanceof GramJs.Document) { - const doc = addStoryRepairInfo(story.media.altDocument, peerId, story); - addDocumentToLocalDb(doc); + if (story.media.altDocuments) { + for (const altDocument of story.media.altDocuments) { + const doc = addStoryRepairInfo(altDocument, peerId, story); + addDocumentToLocalDb(doc); + } } } } diff --git a/src/api/types/messages.ts b/src/api/types/messages.ts index 57b1caacd..df5a23310 100644 --- a/src/api/types/messages.ts +++ b/src/api/types/messages.ts @@ -601,7 +601,7 @@ export type MediaContent = { text?: ApiFormattedText; photo?: ApiPhoto; video?: ApiVideo; - altVideo?: ApiVideo; + altVideos?: ApiVideo[]; document?: ApiDocument; sticker?: ApiSticker; contact?: ApiContact; diff --git a/src/components/story/hooks/useStoryPreloader.ts b/src/components/story/hooks/useStoryPreloader.ts index b257740e0..c13973821 100644 --- a/src/components/story/hooks/useStoryPreloader.ts +++ b/src/components/story/hooks/useStoryPreloader.ts @@ -101,7 +101,7 @@ function getPreloadMediaHashes(peerId: string, storyId: number) { }); // Thumbnail mediaHashes.push({ hash: getStoryMediaHash(story), format: ApiMediaFormat.BlobUrl }); - if (story.content.altVideo) { + if (story.content.altVideos) { mediaHashes.push({ hash: getStoryMediaHash(story, 'full', true)!, format: ApiMediaFormat.Progressive, diff --git a/src/global/helpers/media.ts b/src/global/helpers/media.ts index ed3080371..f8e4c2f9c 100644 --- a/src/global/helpers/media.ts +++ b/src/global/helpers/media.ts @@ -1,8 +1,9 @@ -import type { ApiStory } from '../../api/types'; +import type { ApiStory, ApiVideo } from '../../api/types'; import { getPhotoMediaHash, getVideoMediaHash } from './messageMedia'; type StorySize = 'pictogram' | 'preview' | 'full' | 'download'; +const STORY_ALT_VIDEO_WIDTH = 480; export function getStoryMediaHash( story: ApiStory, size: StorySize, isAlt: true, @@ -15,14 +16,22 @@ export function getStoryMediaHash( const isVideo = Boolean(story.content.video); if (isVideo) { - if (isAlt && !story.content.altVideo) return undefined; - const media = isAlt ? story.content.altVideo! : story.content.video!; + if (isAlt && !story.content.altVideos) return undefined; + const media = isAlt ? getPreferredAlt(story.content.altVideos!) : story.content.video!; return getVideoMediaHash(media, size); } return getPhotoMediaHash(story.content.photo!, size); } +function getPreferredAlt(alts: ApiVideo[]) { + const alt = alts.reduce((prev, curr) => ( + Math.abs((curr.width || 0) - STORY_ALT_VIDEO_WIDTH) < Math.abs((prev.width || 0) - STORY_ALT_VIDEO_WIDTH) + ? curr : prev + )); + return alt; +} + export function getStoryKey(chatId: string, storyId: number) { return `story${chatId}-${storyId}`; } diff --git a/src/lib/gramjs/tl/api.d.ts b/src/lib/gramjs/tl/api.d.ts index 0e0d9f4ee..763eed2d0 100644 --- a/src/lib/gramjs/tl/api.d.ts +++ b/src/lib/gramjs/tl/api.d.ts @@ -403,7 +403,7 @@ namespace Api { export type TypeAccessPointRule = AccessPointRule; export type TypeTlsClientHello = TlsClientHello; export type TypeTlsBlock = TlsBlockString | TlsBlockRandom | TlsBlockZero | TlsBlockDomain | TlsBlockGrease | TlsBlockScope; - + export namespace storage { export type TypeFileType = storage.FileUnknown | storage.FilePartial | storage.FileJpeg | storage.FileGif | storage.FilePng | storage.FilePdf | storage.FileMp3 | storage.FileMov | storage.FileMp4 | storage.FileWebp; @@ -1788,7 +1788,7 @@ namespace Api { round?: true; voice?: true; document?: Api.TypeDocument; - altDocument?: Api.TypeDocument; + altDocuments?: Api.TypeDocument[]; ttlSeconds?: int; } | void> { // flags: undefined; @@ -1798,7 +1798,7 @@ namespace Api { round?: true; voice?: true; document?: Api.TypeDocument; - altDocument?: Api.TypeDocument; + altDocuments?: Api.TypeDocument[]; ttlSeconds?: int; }; export class MessageMediaWebPage extends VirtualClass<{ @@ -10791,7 +10791,7 @@ namespace Api { }> { entries: Api.TypeTlsBlock[]; }; - + export namespace storage { export class FileUnknown extends VirtualClass {}; @@ -13402,7 +13402,7 @@ namespace Api { }>, Api.TypeDestroySessionRes> { sessionId: long; }; - + export namespace auth { export class SendCode extends Request