Skip to content

Commit

Permalink
[Videos] avoid using fetch for blob handling where possible (#5041)
Browse files Browse the repository at this point in the history
* avoid using fetch where possible

* whoopsie wrong branch

* more import fixes
  • Loading branch information
mozzius authored Aug 30, 2024
1 parent c70ec1c commit 8647c8e
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 18 deletions.
5 changes: 1 addition & 4 deletions src/lib/media/video/compress.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import {getVideoMetaData, Video} from 'react-native-compressor'

export type CompressedVideo = {
uri: string
size: number
}
import {CompressedVideo} from './types'

export async function compressVideo(
file: string,
Expand Down
41 changes: 33 additions & 8 deletions src/lib/media/video/compress.web.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import {VideoTooLargeError} from 'lib/media/video/errors'
import {CompressedVideo} from './types'

const MAX_VIDEO_SIZE = 1024 * 1024 * 100 // 100MB

export type CompressedVideo = {
uri: string
size: number
}

// doesn't actually compress, but throws if >100MB
export async function compressVideo(
file: string,
Expand All @@ -15,15 +11,44 @@ export async function compressVideo(
onProgress?: (progress: number) => void
},
): Promise<CompressedVideo> {
const blob = await fetch(file).then(res => res.blob())
const video = URL.createObjectURL(blob)
const {mimeType, base64} = parseDataUrl(file)
const blob = base64ToBlob(base64, mimeType)
const uri = URL.createObjectURL(blob)

if (blob.size > MAX_VIDEO_SIZE) {
throw new VideoTooLargeError()
}

return {
size: blob.size,
uri: video,
uri,
bytes: await blob.arrayBuffer(),
}
}

function parseDataUrl(dataUrl: string) {
const [mimeType, base64] = dataUrl.slice('data:'.length).split(';base64,')
if (!mimeType || !base64) {
throw new Error('Invalid data URL')
}
return {mimeType, base64}
}

function base64ToBlob(base64: string, mimeType: string) {
const byteCharacters = atob(base64)
const byteArrays = []

for (let offset = 0; offset < byteCharacters.length; offset += 512) {
const slice = byteCharacters.slice(offset, offset + 512)
const byteNumbers = new Array(slice.length)

for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i)
}

const byteArray = new Uint8Array(byteNumbers)
byteArrays.push(byteArray)
}

return new Blob(byteArrays, {type: mimeType})
}
6 changes: 6 additions & 0 deletions src/lib/media/video/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type CompressedVideo = {
uri: string
size: number
// web only, can fall back to uri if missing
bytes?: ArrayBuffer
}
3 changes: 2 additions & 1 deletion src/state/queries/video/compress-video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import {ImagePickerAsset} from 'expo-image-picker'
import {useMutation} from '@tanstack/react-query'

import {cancelable} from '#/lib/async/cancelable'
import {CompressedVideo, compressVideo} from 'lib/media/video/compress'
import {CompressedVideo} from '#/lib/media/video/types'
import {compressVideo} from 'lib/media/video/compress'

export function useCompressVideoMutation({
onProgress,
Expand Down
2 changes: 1 addition & 1 deletion src/state/queries/video/video-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {useMutation} from '@tanstack/react-query'
import {nanoid} from 'nanoid/non-secure'

import {cancelable} from '#/lib/async/cancelable'
import {CompressedVideo} from '#/lib/media/video/compress'
import {CompressedVideo} from '#/lib/media/video/types'
import {createVideoEndpointUrl} from '#/state/queries/video/util'
import {useAgent, useSession} from '#/state/session'
import {getServiceAuthAudFromUrl} from 'lib/strings/url-helpers'
Expand Down
2 changes: 1 addition & 1 deletion src/state/queries/video/video-upload.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {useMutation} from '@tanstack/react-query'
import {nanoid} from 'nanoid/non-secure'

import {cancelable} from '#/lib/async/cancelable'
import {CompressedVideo} from '#/lib/media/video/compress'
import {CompressedVideo} from '#/lib/media/video/types'
import {createVideoEndpointUrl} from '#/state/queries/video/util'
import {useAgent, useSession} from '#/state/session'
import {getServiceAuthAudFromUrl} from 'lib/strings/url-helpers'
Expand Down
2 changes: 1 addition & 1 deletion src/state/queries/video/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {useLingui} from '@lingui/react'
import {QueryClient, useQuery, useQueryClient} from '@tanstack/react-query'

import {logger} from '#/logger'
import {CompressedVideo} from 'lib/media/video/compress'
import {VideoTooLargeError} from 'lib/media/video/errors'
import {CompressedVideo} from 'lib/media/video/types'
import {useCompressVideoMutation} from 'state/queries/video/compress-video'
import {useVideoAgent} from 'state/queries/video/util'
import {useUploadVideoMutation} from 'state/queries/video/video-upload'
Expand Down
2 changes: 1 addition & 1 deletion src/view/com/composer/videos/VideoPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {View} from 'react-native'
import {ImagePickerAsset} from 'expo-image-picker'
import {useVideoPlayer, VideoView} from 'expo-video'

import {CompressedVideo} from '#/lib/media/video/compress'
import {CompressedVideo} from '#/lib/media/video/types'
import {ExternalEmbedRemoveBtn} from 'view/com/composer/ExternalEmbedRemoveBtn'
import {atoms as a, useTheme} from '#/alf'

Expand Down
2 changes: 1 addition & 1 deletion src/view/com/composer/videos/VideoPreview.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {useEffect, useRef} from 'react'
import {View} from 'react-native'
import {ImagePickerAsset} from 'expo-image-picker'

import {CompressedVideo} from '#/lib/media/video/compress'
import {CompressedVideo} from '#/lib/media/video/types'
import {ExternalEmbedRemoveBtn} from 'view/com/composer/ExternalEmbedRemoveBtn'
import {atoms as a, useTheme} from '#/alf'

Expand Down

0 comments on commit 8647c8e

Please sign in to comment.