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:
parent
56b688744e
commit
8f06ba70bb
23 changed files with 483 additions and 33 deletions
|
@ -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()
|
||||
|
||||
|
|
|
@ -14,3 +14,11 @@ export function useCameraPermission() {
|
|||
|
||||
return {requestCameraAccessIfNeeded}
|
||||
}
|
||||
|
||||
export function useVideoLibraryPermission() {
|
||||
const requestVideoAccessIfNeeded = async () => {
|
||||
return true
|
||||
}
|
||||
|
||||
return {requestVideoAccessIfNeeded}
|
||||
}
|
||||
|
|
30
src/lib/media/video/compress.ts
Normal file
30
src/lib/media/video/compress.ts
Normal 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}
|
||||
}
|
28
src/lib/media/video/compress.web.ts
Normal file
28
src/lib/media/video/compress.web.ts
Normal 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,
|
||||
}
|
||||
}
|
6
src/lib/media/video/errors.ts
Normal file
6
src/lib/media/video/errors.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
export class VideoTooLargeError extends Error {
|
||||
constructor() {
|
||||
super('Videos cannot be larger than 100MB')
|
||||
this.name = 'VideoTooLargeError'
|
||||
}
|
||||
}
|
|
@ -11,3 +11,4 @@ export type Gate =
|
|||
| 'suggested_feeds_interstitial'
|
||||
| 'suggested_follows_interstitial'
|
||||
| 'ungroup_follow_backs'
|
||||
| 'videos'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue