Signal-Desktop/ts/components/fun/data/gifs.ts

86 lines
2.3 KiB
TypeScript

// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { strictAssert } from '../../../util/assert';
import type { GifType } from '../panels/FunPanelGifs';
import type {
TenorContentFormat,
TenorNextCursor,
TenorResponseResult,
} from './tenor';
import { tenor, isTenorTailCursor } from './tenor';
const PREVIEW_CONTENT_FORMAT: TenorContentFormat = 'tinymp4';
const ATTACHMENT_CONTENT_FORMAT: TenorContentFormat = 'mp4';
function toGif(result: TenorResponseResult): GifType {
const preview = result.media_formats[PREVIEW_CONTENT_FORMAT];
strictAssert(preview, `Missing ${PREVIEW_CONTENT_FORMAT}`);
const attachment = result.media_formats[ATTACHMENT_CONTENT_FORMAT];
strictAssert(attachment, `Missing ${ATTACHMENT_CONTENT_FORMAT}`);
return {
id: result.id,
title: result.title,
description: result.content_description,
previewMedia: {
url: preview.url,
width: preview.dims[0],
height: preview.dims[1],
},
attachmentMedia: {
url: attachment.url,
width: attachment.dims[0],
height: attachment.dims[1],
},
};
}
export type GifsPaginated = Readonly<{
next: TenorNextCursor | null;
gifs: ReadonlyArray<GifType>;
}>;
export async function fetchGifsFeatured(
limit: number,
cursor: TenorNextCursor | null,
signal?: AbortSignal
): Promise<GifsPaginated> {
const response = await tenor(
'v2/featured',
{
contentfilter: 'low',
media_filter: [PREVIEW_CONTENT_FORMAT, ATTACHMENT_CONTENT_FORMAT],
limit,
pos: cursor ?? undefined,
},
signal
);
const next = isTenorTailCursor(response.next) ? null : response.next;
const gifs = response.results.map(result => toGif(result));
return { next, gifs };
}
export async function fetchGifsSearch(
query: string,
limit: number,
cursor: TenorNextCursor | null,
signal?: AbortSignal
): Promise<GifsPaginated> {
const response = await tenor(
'v2/search',
{
q: query,
contentfilter: 'low',
media_filter: [PREVIEW_CONTENT_FORMAT, ATTACHMENT_CONTENT_FORMAT],
limit,
pos: cursor ?? undefined,
},
signal
);
const next = isTenorTailCursor(response.next) ? null : response.next;
const gifs = response.results.map(result => toGif(result));
return { next, gifs };
}