feat: publish av-tools 0.1.0

This commit is contained in:
2026-07-24 14:58:03 +02:00
commit fcc537b024
254 changed files with 63270 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
import {
AV_PROJECT_SCHEMA_VERSION,
type AvProjectV1,
type BrowserFileIdentity,
type CreateMediaAssetOptions,
type CreateProjectOptions,
type MediaAssetReference,
} from './project.types';
export function createEmptyProject(
options: CreateProjectOptions = {}
): AvProjectV1 {
const timestamp = options.timestamp ?? new Date().toISOString();
if (!isIsoDate(timestamp)) {
throw new TypeError('Project timestamp must be a valid ISO-8601 date.');
}
return {
schemaVersion: AV_PROJECT_SCHEMA_VERSION,
id: options.id ?? createProjectId(),
name: options.name?.trim() || 'Untitled project',
createdAt: timestamp,
updatedAt: timestamp,
assets: [],
timeline: [],
output: {
presetId: options.output?.presetId ?? 'mp4-h264-balanced',
fileName: options.output?.fileName ?? 'output.mp4',
container: options.output?.container ?? 'mp4',
videoEnabled: options.output?.videoEnabled ?? true,
audioEnabled: options.output?.audioEnabled ?? true,
...(options.output?.width === undefined
? {}
: { width: options.output.width }),
...(options.output?.height === undefined
? {}
: { height: options.output.height }),
...(options.output?.frameRate === undefined
? {}
: { frameRate: options.output.frameRate }),
sampleRate: options.output?.sampleRate ?? 48_000,
channelLayout: options.output?.channelLayout ?? 'stereo',
missingAudioPolicy:
options.output?.missingAudioPolicy ?? 'insert-silence',
},
metadata: {
custom: {},
},
chapters: [],
subtitles: [],
};
}
export function createMediaAssetReference(
file: BrowserFileIdentity,
options: CreateMediaAssetOptions = {}
): MediaAssetReference {
if (!file.name.trim()) {
throw new TypeError('A source file must have a name.');
}
if (!Number.isSafeInteger(file.size) || file.size < 0) {
throw new TypeError('A source file size must be a non-negative integer.');
}
if (!Number.isSafeInteger(file.lastModified) || file.lastModified < 0) {
throw new TypeError(
'A source last-modified time must be a non-negative integer.'
);
}
return {
id: options.id ?? createId('asset'),
originalName: file.name,
size: file.size,
lastModified: file.lastModified,
mimeType: file.type,
sourceStatus: options.sourceStatus ?? 'attached',
...(options.probe === undefined ? {} : { probe: options.probe }),
...(options.hash === undefined ? {} : { hash: options.hash }),
};
}
function createProjectId(): string {
return createId('project');
}
function createId(prefix: string): string {
if (
typeof globalThis.crypto !== 'undefined' &&
typeof globalThis.crypto.randomUUID === 'function'
) {
return globalThis.crypto.randomUUID();
}
return `${prefix}-${Date.now().toString(36)}-${Math.random()
.toString(36)
.slice(2, 10)}`;
}
function isIsoDate(value: string): boolean {
return (
/^\d{4}-\d{2}-\d{2}T/.test(value) && Number.isFinite(Date.parse(value))
);
}