your personal website on atproto - mirror blento.app
at map 63 lines 1.5 kB view raw
1import { uploadBlob } from '$lib/atproto'; 2import type { CardDefinition } from '../types'; 3import VideoCard from './VideoCard.svelte'; 4import VideoCardSettings from './VideoCardSettings.svelte'; 5 6async function getAspectRatio(videoBlob: Blob): Promise<{ width: number; height: number }> { 7 return new Promise((resolve, reject) => { 8 const video = document.createElement('video'); 9 video.preload = 'metadata'; 10 11 video.onloadedmetadata = () => { 12 URL.revokeObjectURL(video.src); 13 resolve({ 14 width: video.videoWidth, 15 height: video.videoHeight 16 }); 17 }; 18 19 video.onerror = () => { 20 URL.revokeObjectURL(video.src); 21 reject(new Error('Failed to load video metadata')); 22 }; 23 24 video.src = URL.createObjectURL(videoBlob); 25 }); 26} 27 28export const VideoCardDefinition = { 29 type: 'video', 30 contentComponent: VideoCard, 31 createNew: (card) => { 32 card.cardType = 'video'; 33 card.cardData = { 34 video: null, 35 href: '' 36 }; 37 }, 38 upload: async (item) => { 39 if (item.cardData.blob) { 40 const blob = item.cardData.blob; 41 const aspectRatio = await getAspectRatio(blob); 42 const uploadedBlob = await uploadBlob({ blob }); 43 44 item.cardData.video = { 45 $type: 'app.bsky.embed.video', 46 video: uploadedBlob, 47 aspectRatio 48 }; 49 50 delete item.cardData.blob; 51 } 52 53 if (item.cardData.objectUrl) { 54 URL.revokeObjectURL(item.cardData.objectUrl); 55 delete item.cardData.objectUrl; 56 } 57 58 return item; 59 }, 60 settingsComponent: VideoCardSettings, 61 62 name: 'Video Card' 63} as CardDefinition & { type: 'video' };