Video compression in composer (#4638)

Co-authored-by: Samuel Newman <10959775+mozzius@users.noreply.github.com>
Co-authored-by: Hailey <me@haileyok.com>
This commit is contained in:
Samuel Newman 2024-07-06 01:50:03 +01:00 committed by GitHub
parent 56b688744e
commit 8f06ba70bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 483 additions and 33 deletions

View file

@ -48,6 +48,35 @@ export function usePhotoLibraryPermission() {
return {requestPhotoAccessIfNeeded}
}
export function useVideoLibraryPermission() {
const [res, requestPermission] = MediaLibrary.usePermissions({
granularPermissions: ['video'],
})
const requestVideoAccessIfNeeded = async () => {
// On the, we use <input type="file"> to produce a filepicker
// This does not need any permission granting.
if (isWeb) {
return true
}
if (res?.granted) {
return true
} else if (!res || res.status === 'undetermined' || res?.canAskAgain) {
const {canAskAgain, granted, status} = await requestPermission()
if (!canAskAgain && status === 'undetermined') {
openPermissionAlert('video library')
}
return granted
} else {
openPermissionAlert('video library')
return false
}
}
return {requestVideoAccessIfNeeded}
}
export function useCameraPermission() {
const [res, requestPermission] = Camera.useCameraPermissions()

View file

@ -14,3 +14,11 @@ export function useCameraPermission() {
return {requestCameraAccessIfNeeded}
}
export function useVideoLibraryPermission() {
const requestVideoAccessIfNeeded = async () => {
return true
}
return {requestVideoAccessIfNeeded}
}

View file

@ -0,0 +1,30 @@
import {getVideoMetaData, Video} from 'react-native-compressor'
export type CompressedVideo = {
uri: string
size: number
}
export async function compressVideo(
file: string,
opts?: {
getCancellationId?: (id: string) => void
onProgress?: (progress: number) => void
},
): Promise<CompressedVideo> {
const {onProgress, getCancellationId} = opts || {}
const compressed = await Video.compress(
file,
{
getCancellationId,
compressionMethod: 'manual',
bitrate: 3_000_000, // 3mbps
maxSize: 1920,
},
onProgress,
)
const info = await getVideoMetaData(compressed)
return {uri: compressed, size: info.size}
}

View file

@ -0,0 +1,28 @@
import {VideoTooLargeError} from 'lib/media/video/errors'
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,
_callbacks?: {
onProgress: (progress: number) => void
},
): Promise<CompressedVideo> {
const blob = await fetch(file).then(res => res.blob())
const video = URL.createObjectURL(blob)
if (blob.size > MAX_VIDEO_SIZE) {
throw new VideoTooLargeError()
}
return {
size: blob.size,
uri: video,
}
}

View file

@ -0,0 +1,6 @@
export class VideoTooLargeError extends Error {
constructor() {
super('Videos cannot be larger than 100MB')
this.name = 'VideoTooLargeError'
}
}

View file

@ -11,3 +11,4 @@ export type Gate =
| 'suggested_feeds_interstitial'
| 'suggested_follows_interstitial'
| 'ungroup_follow_backs'
| 'videos'