122 lines
3.7 KiB
TypeScript
122 lines
3.7 KiB
TypeScript
import { isBlurhashValid } from 'blurhash';
|
|
import * as v from 'valibot';
|
|
|
|
import { mimeSchema } from './utils';
|
|
|
|
/**
|
|
* @category Schemas
|
|
*/
|
|
const blurhashSchema = v.pipe(v.string(), v.check(
|
|
(value) => isBlurhashValid(value).result,
|
|
'invalid blurhash', // .errorReason
|
|
));
|
|
|
|
const baseAttachmentSchema = v.object({
|
|
id: v.string(),
|
|
type: v.string(),
|
|
url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
|
preview_url: v.fallback(v.pipe(v.string(), v.url()), ''),
|
|
remote_url: v.fallback(v.nullable(v.pipe(v.string(), v.url())), null),
|
|
description: v.fallback(v.string(), ''),
|
|
blurhash: v.fallback(v.nullable(blurhashSchema), null),
|
|
|
|
mime_type: v.fallback(v.nullable(mimeSchema), null),
|
|
});
|
|
|
|
const imageMetaSchema = v.object({
|
|
width: v.number(),
|
|
height: v.number(),
|
|
size: v.fallback(v.nullable(v.pipe(v.string(), v.regex(/\d+x\d+$/))), null),
|
|
aspect: v.fallback(v.nullable(v.number()), null),
|
|
});
|
|
|
|
const imageAttachmentSchema = v.object({
|
|
...baseAttachmentSchema.entries,
|
|
type: v.literal('image'),
|
|
meta: v.fallback(v.object({
|
|
original: v.fallback(v.optional(imageMetaSchema), undefined),
|
|
small: v.fallback(v.optional(imageMetaSchema), undefined),
|
|
focus: v.fallback(v.optional(v.object({
|
|
x: v.pipe(v.number(), v.minValue(-1), v.maxValue(1)),
|
|
y: v.pipe(v.number(), v.minValue(-1), v.maxValue(1)),
|
|
})), undefined),
|
|
}), {}),
|
|
});
|
|
|
|
const videoAttachmentSchema = v.object({
|
|
...baseAttachmentSchema.entries,
|
|
type: v.literal('video'),
|
|
meta: v.fallback(v.object({
|
|
duration: v.fallback(v.optional(v.number()), undefined),
|
|
original: v.fallback(v.optional(v.object({
|
|
...imageMetaSchema.entries,
|
|
frame_rate: v.fallback(v.nullable(v.pipe(v.string(), v.regex(/\d+\/\d+$/))), null),
|
|
duration: v.fallback(v.nullable(v.pipe(v.number(), v.minValue(0))), null),
|
|
})), undefined),
|
|
small: v.fallback(v.optional(imageMetaSchema), undefined),
|
|
// WIP: add rest
|
|
}), {}),
|
|
});
|
|
|
|
const gifvAttachmentSchema = v.object({
|
|
...baseAttachmentSchema.entries,
|
|
type: v.literal('gifv'),
|
|
meta: v.fallback(v.object({
|
|
duration: v.fallback(v.optional(v.number()), undefined),
|
|
original: v.fallback(v.optional(imageMetaSchema), undefined),
|
|
}), {}),
|
|
});
|
|
|
|
const audioAttachmentSchema = v.object({
|
|
...baseAttachmentSchema.entries,
|
|
type: v.literal('audio'),
|
|
meta: v.fallback(v.object({
|
|
duration: v.fallback(v.optional(v.number()), undefined),
|
|
colors: v.fallback(v.optional(v.object({
|
|
background: v.fallback(v.optional(v.string()), undefined),
|
|
foreground: v.fallback(v.optional(v.string()), undefined),
|
|
accent: v.fallback(v.optional(v.string()), undefined),
|
|
duration: v.fallback(v.optional(v.number()), undefined),
|
|
})), undefined),
|
|
original: v.fallback(v.optional(v.object({
|
|
duration: v.fallback(v.optional(v.number()), undefined),
|
|
bitrate: v.fallback(v.optional(v.pipe(v.number(), v.minValue(0))), undefined),
|
|
})), undefined),
|
|
}), {}),
|
|
});
|
|
|
|
const unknownAttachmentSchema = v.object({
|
|
...baseAttachmentSchema.entries,
|
|
type: v.literal('unknown'),
|
|
});
|
|
|
|
/**
|
|
* @category Schemas
|
|
* @see {@link https://docs.joinmastodon.org/entities/MediaAttachment}
|
|
*/
|
|
const mediaAttachmentSchema = v.pipe(
|
|
v.any(),
|
|
v.transform((data: any) => {
|
|
if (!data) return null;
|
|
|
|
return {
|
|
mime_type: data.pleroma?.mime_type,
|
|
preview_url: data.url,
|
|
...data,
|
|
};
|
|
}),
|
|
v.variant('type', [
|
|
imageAttachmentSchema,
|
|
videoAttachmentSchema,
|
|
gifvAttachmentSchema,
|
|
audioAttachmentSchema,
|
|
unknownAttachmentSchema,
|
|
]),
|
|
);
|
|
|
|
/**
|
|
* @category Entity types
|
|
*/
|
|
type MediaAttachment = v.InferOutput<typeof mediaAttachmentSchema>;
|
|
|
|
export { blurhashSchema, mediaAttachmentSchema, type MediaAttachment };
|