add video

This commit is contained in:
lendry
2026-07-07 12:46:43 +03:00
parent 911e76f232
commit 1bd95fa99e
15 changed files with 626 additions and 42 deletions

View File

@@ -1,4 +1,4 @@
export type ChatAttachmentKind = 'IMAGE' | 'AUDIO' | 'VOICE' | 'FILE';
export type ChatAttachmentKind = 'IMAGE' | 'AUDIO' | 'VOICE' | 'VIDEO' | 'VIDEO_NOTE' | 'FILE';
const EXTENSION_TO_MIME: Record<string, string> = {
jpg: 'image/jpeg',
@@ -18,6 +18,9 @@ const EXTENSION_TO_MIME: Record<string, string> = {
flac: 'audio/flac',
mp4: 'video/mp4',
mov: 'video/quicktime',
mkv: 'video/x-matroska',
avi: 'video/x-msvideo',
'3gp': 'video/3gpp',
pdf: 'application/pdf',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
@@ -44,7 +47,9 @@ const MIME_ALIASES: Record<string, string> = {
'image/jpg': 'image/jpeg',
'image/pjpeg': 'image/jpeg',
'application/x-pdf': 'application/pdf',
'application/x-zip-compressed': 'application/zip'
'application/x-zip-compressed': 'application/zip',
'video/x-matroska': 'video/x-matroska',
'video/3gpp': 'video/3gpp'
};
function extractFileExtension(value?: string | null) {
@@ -72,21 +77,26 @@ export function resolveChatContentType(file: Pick<File, 'type' | 'name'>) {
return aliased || 'application/octet-stream';
}
export function inferChatMessageType(contentType: string, options?: { voice?: boolean }): ChatAttachmentKind {
export function inferChatMessageType(contentType: string, options?: { voice?: boolean; videoNote?: boolean }): ChatAttachmentKind {
const normalized = resolveChatContentType({ type: contentType, name: '' });
if (options?.videoNote && normalized.startsWith('video/')) return 'VIDEO_NOTE';
if (normalized.startsWith('image/')) return 'IMAGE';
if (normalized.startsWith('video/')) return 'FILE';
if (normalized.startsWith('video/')) return 'VIDEO';
if (normalized.startsWith('audio/')) {
return options?.voice ? 'VOICE' : 'AUDIO';
}
return 'FILE';
}
export function detectChatMessageType(file: File, options?: { voice?: boolean }) {
export function detectChatMessageType(file: File, options?: { voice?: boolean; videoNote?: boolean }) {
const contentType = resolveChatContentType(file);
return inferChatMessageType(contentType, options);
}
export function isVideoFile(file: Pick<File, 'type' | 'name'>) {
return resolveChatContentType(file).startsWith('video/');
}
export function formatFileSize(bytes?: number) {
if (!bytes || bytes <= 0) return '';
if (bytes < 1024) return `${bytes} Б`;
@@ -95,9 +105,9 @@ export function formatFileSize(bytes?: number) {
}
export function parseMessageMetadata(metadataJson?: string) {
if (!metadataJson) return {} as { fileName?: string; fileSize?: number; durationMs?: number };
if (!metadataJson) return {} as { fileName?: string; fileSize?: number; durationMs?: number; videoNote?: boolean };
try {
return JSON.parse(metadataJson) as { fileName?: string; fileSize?: number; durationMs?: number };
return JSON.parse(metadataJson) as { fileName?: string; fileSize?: number; durationMs?: number; videoNote?: boolean };
} catch {
return {};
}
@@ -111,6 +121,7 @@ export function fileIconLabel(fileName?: string, mimeType?: string) {
if (['ppt', 'pptx'].includes(extension)) return 'PPT';
if (['zip', 'rar', '7z'].includes(extension)) return 'ZIP';
if (extension === 'apk') return 'APK';
if (['mp4', 'mov', 'webm', 'mkv'].includes(extension) || mimeType?.startsWith('video/')) return 'VID';
if (extension) return extension.toUpperCase().slice(0, 4);
return 'FILE';
}