get video restoration working on native
This commit is contained in:
@@ -42,6 +42,7 @@ import Animated, {
|
||||
ZoomOut,
|
||||
} from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import * as FileSystem from 'expo-file-system'
|
||||
import {type ImagePickerAsset} from 'expo-image-picker'
|
||||
import {
|
||||
AppBskyUnspeccedDefs,
|
||||
@@ -320,7 +321,7 @@ export const ComposePost = ({
|
||||
onInitVideo()
|
||||
}, [onInitVideo])
|
||||
|
||||
const clearVideo = React.useCallback(
|
||||
const clearVideo = useCallback(
|
||||
(postId: string) => {
|
||||
composerDispatch({
|
||||
type: 'update_post',
|
||||
@@ -333,7 +334,7 @@ export const ComposePost = ({
|
||||
[composerDispatch],
|
||||
)
|
||||
|
||||
const restoreVideo = React.useCallback(
|
||||
const restoreVideo = useCallback(
|
||||
async (postId: string, videoInfo: RestoredVideo) => {
|
||||
try {
|
||||
logger.debug('restoring video from draft', {
|
||||
@@ -354,15 +355,25 @@ export const ComposePost = ({
|
||||
})
|
||||
asset = await getVideoMetadata(file)
|
||||
} else {
|
||||
// Native: Get video metadata using react-native-compressor
|
||||
const {getVideoMetaData} = require('react-native-compressor')
|
||||
const metadata = await getVideoMetaData(videoInfo.uri)
|
||||
asset = {
|
||||
uri: videoInfo.uri,
|
||||
mimeType: videoInfo.mimeType,
|
||||
width: metadata.width,
|
||||
height: metadata.height,
|
||||
let uri = videoInfo.uri
|
||||
if (IS_ANDROID) {
|
||||
// Android: expo-file-system double-encodes filenames with special chars.
|
||||
// The file exists, but react-native-compressor's MediaMetadataRetriever
|
||||
// can't handle the double-encoded URI. Copy to a temp file with a simple name.
|
||||
const sourceFile = new FileSystem.File(videoInfo.uri)
|
||||
const tempFileName = `draft-video-${Date.now()}.${mimeToExt(videoInfo.mimeType)}`
|
||||
const tempFile = new FileSystem.File(
|
||||
FileSystem.Paths.cache,
|
||||
tempFileName,
|
||||
)
|
||||
sourceFile.copy(tempFile)
|
||||
logger.debug('restoreVideo: copied to temp file', {
|
||||
source: videoInfo.uri,
|
||||
temp: tempFile.uri,
|
||||
})
|
||||
uri = tempFile.uri
|
||||
}
|
||||
asset = await getVideoMetadata(uri)
|
||||
}
|
||||
|
||||
// Start video processing using existing flow
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {getVideoMetaData} from 'react-native-compressor'
|
||||
import {
|
||||
type ImagePickerAsset,
|
||||
launchImageLibraryAsync,
|
||||
@@ -5,6 +6,7 @@ import {
|
||||
} from 'expo-image-picker'
|
||||
|
||||
import {VIDEO_MAX_DURATION_MS} from '#/lib/constants'
|
||||
import {extToMime} from '#/lib/media/video/util'
|
||||
|
||||
export async function pickVideo() {
|
||||
return await launchImageLibraryAsync({
|
||||
@@ -18,6 +20,24 @@ export async function pickVideo() {
|
||||
})
|
||||
}
|
||||
|
||||
export const getVideoMetadata = (_file: File): Promise<ImagePickerAsset> => {
|
||||
throw new Error('getVideoMetadata is web only')
|
||||
/**
|
||||
* Gets video metadata from a file or uri, depending on the platform
|
||||
*
|
||||
* @param file File on web, uri on native
|
||||
*/
|
||||
export async function getVideoMetadata(
|
||||
file: File | string,
|
||||
): Promise<ImagePickerAsset> {
|
||||
if (typeof file !== 'string')
|
||||
throw new Error(
|
||||
'getVideoMetadata was passed a File, when on native it should be a uri',
|
||||
)
|
||||
const metadata = await getVideoMetaData(file)
|
||||
return {
|
||||
uri: file,
|
||||
mimeType: extToMime(metadata.extension),
|
||||
width: metadata.width,
|
||||
height: metadata.height,
|
||||
duration: metadata.duration,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,13 @@ export async function pickVideo(): Promise<ImagePickerResult> {
|
||||
// lets us use the ImagePickerAsset type, which the rest of the code expects.
|
||||
// We should unwind this and just pass the ArrayBuffer/objectUrl through the system
|
||||
// instead of a string -sfn
|
||||
export const getVideoMetadata = (file: File): Promise<ImagePickerAsset> => {
|
||||
export function getVideoMetadata(
|
||||
file: File | string,
|
||||
): Promise<ImagePickerAsset> {
|
||||
if (typeof file === 'string')
|
||||
throw new Error(
|
||||
'getVideoMetadata was passed a uri, when on web it should be a File',
|
||||
)
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => {
|
||||
|
||||
Reference in New Issue
Block a user