APP-2976: Remove react-native-compressor remnants (#11588)
This commit is contained in:
@@ -408,7 +408,7 @@ export const ComposePost = ({
|
||||
asset.mimeType !== 'image/gif'
|
||||
) {
|
||||
try {
|
||||
const probed = await getVideoMetadata(asset.uri)
|
||||
const probed = await getVideoMetadata(asset.uri, asset.mimeType)
|
||||
asset = {
|
||||
...asset,
|
||||
mimeType: probed.mimeType ?? asset.mimeType,
|
||||
@@ -538,8 +538,8 @@ export const ComposePost = ({
|
||||
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.
|
||||
// The native metadata probe can't handle the double-encoded URI, so
|
||||
// copy it 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(
|
||||
@@ -553,7 +553,7 @@ export const ComposePost = ({
|
||||
})
|
||||
uri = tempFile.uri
|
||||
}
|
||||
asset = await getVideoMetadata(uri)
|
||||
asset = await getVideoMetadata(uri, videoInfo.mimeType)
|
||||
}
|
||||
|
||||
// Start video processing using existing flow
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import {clearCache, createVideoThumbnail} from 'react-native-compressor'
|
||||
import Animated, {FadeIn} from 'react-native-reanimated'
|
||||
import {File} from 'expo-file-system'
|
||||
import {Image} from 'expo-image'
|
||||
import {
|
||||
getThumbnailAsync,
|
||||
type VideoThumbnailsResult,
|
||||
} from 'expo-video-thumbnails'
|
||||
import {type QueryClient, useQuery} from '@tanstack/react-query'
|
||||
|
||||
import {atoms as a} from '#/alf'
|
||||
@@ -8,15 +12,32 @@ import {atoms as a} from '#/alf'
|
||||
export const RQKEY = 'video-thumbnail'
|
||||
|
||||
export function clearThumbnailCache(queryClient: QueryClient) {
|
||||
clearCache().catch(() => {})
|
||||
void queryClient.resetQueries({queryKey: [RQKEY]})
|
||||
for (const [, thumbnail] of queryClient.getQueriesData<VideoThumbnailsResult>(
|
||||
{queryKey: [RQKEY]},
|
||||
)) {
|
||||
if (thumbnail) {
|
||||
deleteThumbnail(thumbnail)
|
||||
}
|
||||
}
|
||||
queryClient.removeQueries({queryKey: [RQKEY]})
|
||||
}
|
||||
|
||||
function deleteThumbnail(thumbnail: VideoThumbnailsResult) {
|
||||
try {
|
||||
new File(thumbnail.uri).delete()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
export function VideoTranscodeBackdrop({uri}: {uri: string}) {
|
||||
const {data: thumbnail} = useQuery({
|
||||
queryKey: [RQKEY, uri],
|
||||
queryFn: async () => {
|
||||
return await createVideoThumbnail(uri)
|
||||
queryFn: async ({signal}) => {
|
||||
const result = await getThumbnailAsync(uri)
|
||||
if (signal.aborted) {
|
||||
deleteThumbnail(result)
|
||||
throw new Error('Thumbnail generation canceled')
|
||||
}
|
||||
return result
|
||||
},
|
||||
})
|
||||
|
||||
@@ -25,7 +46,7 @@ export function VideoTranscodeBackdrop({uri}: {uri: string}) {
|
||||
<Animated.View style={a.flex_1} entering={FadeIn}>
|
||||
<Image
|
||||
style={a.flex_1}
|
||||
source={thumbnail.path}
|
||||
source={thumbnail.uri}
|
||||
cachePolicy="none"
|
||||
accessibilityIgnoresInvertColors
|
||||
blurRadius={15}
|
||||
|
||||
@@ -1,29 +1,41 @@
|
||||
import {getVideoMetaData} from 'react-native-compressor'
|
||||
import {type ImagePickerAsset} from 'expo-image-picker'
|
||||
import {probe} from '@bsky.app/video-compressor'
|
||||
|
||||
import {extToMime} from '#/lib/media/video/util'
|
||||
|
||||
export async function getVideoMetadata(
|
||||
file: File | string,
|
||||
fallbackMimeType?: 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)
|
||||
const metadata = await probe(file)
|
||||
return {
|
||||
uri: file,
|
||||
mimeType: extToMime(metadata.extension),
|
||||
mimeType: getMimeTypeFromUri(file) ?? fallbackMimeType ?? metadata.mimeType,
|
||||
fileSize: metadata.fileSize,
|
||||
width: metadata.width,
|
||||
height: metadata.height,
|
||||
/*
|
||||
* react-native-compressor reports seconds; the rest of the app treats
|
||||
* `ImagePickerAsset.duration` as milliseconds (matching expo-image-picker).
|
||||
* The probe reports seconds; `ImagePickerAsset.duration` uses milliseconds.
|
||||
*/
|
||||
duration: metadata.duration * 1000,
|
||||
}
|
||||
}
|
||||
|
||||
function getMimeTypeFromUri(uri: string): string | undefined {
|
||||
const extension = uri.match(/\.([^.?#/]+)(?:[?#]|$)/)?.[1]
|
||||
if (!extension) return
|
||||
|
||||
try {
|
||||
return extToMime(extension)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
export function hasWebCodecs(): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ export function hasWebCodecs(): boolean {
|
||||
|
||||
export async function getVideoMetadata(
|
||||
file: File | string,
|
||||
_fallbackMimeType?: string,
|
||||
): Promise<ImagePickerAsset> {
|
||||
if (typeof file === 'string')
|
||||
throw new Error(
|
||||
|
||||
Reference in New Issue
Block a user