Bluesky app fork with some witchin' additions 馃挮
at main 56 lines 1.5 kB view raw
1import {type ImagePickerAsset} from 'expo-image-picker' 2 3import {VIDEO_MAX_SIZE} from '#/lib/constants' 4import {VideoTooLargeError} from '#/lib/media/video/errors' 5import {type CompressedVideo} from './types' 6 7// doesn't actually compress, converts to ArrayBuffer 8export async function compressVideo( 9 asset: ImagePickerAsset, 10 _opts?: { 11 signal?: AbortSignal 12 onProgress?: (progress: number) => void 13 }, 14): Promise<CompressedVideo> { 15 const {mimeType, base64} = parseDataUrl(asset.uri) 16 const blob = base64ToBlob(base64, mimeType) 17 const uri = URL.createObjectURL(blob) 18 19 if (blob.size > VIDEO_MAX_SIZE) { 20 throw new VideoTooLargeError() 21 } 22 23 return { 24 size: blob.size, 25 uri, 26 bytes: await blob.arrayBuffer(), 27 mimeType, 28 } 29} 30 31function parseDataUrl(dataUrl: string) { 32 const [mimeType, base64] = dataUrl.slice('data:'.length).split(';base64,') 33 if (!mimeType || !base64) { 34 throw new Error('Invalid data URL') 35 } 36 return {mimeType, base64} 37} 38 39function base64ToBlob(base64: string, mimeType: string) { 40 const byteCharacters = atob(base64) 41 const byteArrays = [] 42 43 for (let offset = 0; offset < byteCharacters.length; offset += 512) { 44 const slice = byteCharacters.slice(offset, offset + 512) 45 const byteNumbers = new Array(slice.length) 46 47 for (let i = 0; i < slice.length; i++) { 48 byteNumbers[i] = slice.charCodeAt(i) 49 } 50 51 const byteArray = new Uint8Array(byteNumbers) 52 byteArrays.push(byteArray) 53 } 54 55 return new Blob(byteArrays, {type: mimeType}) 56}