bigbuffet-rw/packages/pl-api/lib/entities/media-attachment.ts

106 lines
3.1 KiB
TypeScript
Raw Normal View History

import { isBlurhashValid } from 'blurhash';
import { z } from 'zod';
import { mimeSchema } from './utils';
const blurhashSchema = z.string().superRefine((value, ctx) => {
const r = isBlurhashValid(value);
if (!r.result) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: r.errorReason,
});
}
});
const baseAttachmentSchema = z.object({
id: z.string(),
type: z.string(),
url: z.string().url().catch(''),
preview_url: z.string().url().catch(''),
remote_url: z.string().url().nullable().catch(null),
description: z.string().catch(''),
blurhash: blurhashSchema.nullable().catch(null),
mime_type: mimeSchema.nullable().catch(null),
});
const imageMetaSchema = z.object({
width: z.number(),
height: z.number(),
size: z.string().regex(/\d+x\d+$/).nullable().catch(null),
aspect: z.number().nullable().catch(null),
});
const imageAttachmentSchema = baseAttachmentSchema.extend({
type: z.literal('image'),
meta: z.object({
original: imageMetaSchema.optional().catch(undefined),
small: imageMetaSchema.optional().catch(undefined),
focus: z.object({
x: z.number().min(-1).max(1),
y: z.number().min(-1).max(1),
}).optional().catch(undefined),
}).catch({}),
});
const videoAttachmentSchema = baseAttachmentSchema.extend({
type: z.literal('video'),
meta: z.object({
duration: z.number().optional().catch(undefined),
original: imageMetaSchema.extend({
frame_rate: z.string().regex(/\d+\/\d+$/).nullable().catch(null),
duration: z.number().nonnegative().nullable().catch(null),
}).optional().catch(undefined),
small: imageMetaSchema.optional().catch(undefined),
// WIP: add rest
}).catch({}),
});
const gifvAttachmentSchema = baseAttachmentSchema.extend({
type: z.literal('gifv'),
meta: z.object({
duration: z.number().optional().catch(undefined),
original: imageMetaSchema.optional().catch(undefined),
}).catch({}),
});
const audioAttachmentSchema = baseAttachmentSchema.extend({
type: z.literal('audio'),
meta: z.object({
duration: z.number().optional().catch(undefined),
colors: z.object({
background: z.string().optional().catch(undefined),
foreground: z.string().optional().catch(undefined),
accent: z.string().optional().catch(undefined),
duration: z.number().optional().catch(undefined),
}).optional().catch(undefined),
original: z.object({
duration: z.number().optional().catch(undefined),
bitrate: z.number().nonnegative().optional().catch(undefined),
}).optional().catch(undefined),
}).catch({}),
});
const unknownAttachmentSchema = baseAttachmentSchema.extend({
type: z.literal('unknown'),
});
/** @see {@link https://docs.joinmastodon.org/entities/MediaAttachment} */
const mediaAttachmentSchema = z.preprocess((data: any) => ({
mime_type: data.pleroma?.mime_type,
preview_url: data.url,
...data,
}), z.discriminatedUnion('type', [
imageAttachmentSchema,
videoAttachmentSchema,
gifvAttachmentSchema,
audioAttachmentSchema,
unknownAttachmentSchema,
]));
type MediaAttachment = z.infer<typeof mediaAttachmentSchema>;
export { blurhashSchema, mediaAttachmentSchema, type MediaAttachment };