Lazily load better quality jumbomoji

This commit is contained in:
Fedor Indutny 2024-06-21 18:35:56 -04:00 committed by GitHub
parent ac04d02d4f
commit 5e41701516
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 4566 additions and 137 deletions

View file

@ -11,6 +11,8 @@ import { missingCaseError } from '../../util/missingCaseError';
import type { SizeClassType } from '../emoji/lib';
import { emojiToImage } from '../emoji/lib';
const JUMBO_SIZES = new Set<SizeClassType>(['large', 'extra-large', 'max']);
// Some of this logic taken from emoji-js/replacement
// the DOM structure for this getImageTag should match the other emoji implementations:
// ts/components/emoji/Emoji.tsx
@ -32,10 +34,16 @@ function getImageTag({
return match;
}
let srcSet: string | undefined;
if (sizeClass != null && JUMBO_SIZES.has(sizeClass)) {
srcSet = `emoji://jumbo?emoji=${encodeURIComponent(match)}, ${img}`;
}
return (
<img
key={key}
src={img}
srcSet={srcSet}
aria-label={match}
className={classNames(
'emoji',

103
ts/scripts/get-jumbomoji.ts Normal file
View file

@ -0,0 +1,103 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { writeFile, readFile } from 'node:fs/promises';
import { createHash } from 'node:crypto';
import { join } from 'node:path';
import z from 'zod';
import prettier from 'prettier';
import type { OptionalResourceType } from '../types/OptionalResource';
import { OptionalResourcesDictSchema } from '../types/OptionalResource';
const VERSION = 10;
const MANIFEST_URL = `https://updates.signal.org/static/android/emoji/${VERSION}/emoji_data.json`;
const ManifestSchema = z.object({
jumbomoji: z.record(z.string(), z.string().array()),
});
async function fetchJSON(url: string): Promise<unknown> {
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to fetch ${url}`);
}
return res.json();
}
async function main(): Promise<void> {
const { jumbomoji } = ManifestSchema.parse(await fetchJSON(MANIFEST_URL));
const extraResources = new Map<string, OptionalResourceType>();
await Promise.all(
Array.from(Object.keys(jumbomoji)).map(async sheet => {
const publicUrl =
'https://updates.signal.org/static/android/emoji/' +
`${VERSION}/xhdpi/jumbo/${sheet}.proto`;
const res = await fetch(publicUrl);
if (!res.ok) {
throw new Error(`Failed to fetch ${publicUrl}`);
}
const data = Buffer.from(await res.arrayBuffer());
const digest = createHash('sha512').update(data).digest('base64');
const pinnedUrl =
'https://updates2.signal.org/static/android/emoji/' +
`${VERSION}/xhdpi/jumbo/${sheet}.proto`;
extraResources.set(sheet, {
url: pinnedUrl,
size: data.length,
digest,
});
})
);
const manifestPath = join(__dirname, '..', '..', 'build', 'jumbomoji.json');
const resourcesPath = join(
__dirname,
'..',
'..',
'build',
'optional-resources.json'
);
const resources = OptionalResourcesDictSchema.parse(
JSON.parse(await readFile(resourcesPath, 'utf8'))
);
for (const [sheet, resource] of extraResources) {
resources[`emoji-sheet-${sheet}.proto`] = resource;
}
const prettierConfig = await prettier.resolveConfig(
join(__dirname, '..', '..', 'build')
);
{
const output = prettier.format(JSON.stringify(jumbomoji, null, 2), {
...prettierConfig,
filepath: manifestPath,
});
await writeFile(manifestPath, output);
}
{
const output = prettier.format(JSON.stringify(resources, null, 2), {
...prettierConfig,
filepath: resourcesPath,
});
await writeFile(resourcesPath, output);
}
}
main().catch(err => {
console.error(err);
process.exit(1);
});