get videos working on native

This commit is contained in:
Samuel Newman
2026-01-28 17:50:09 +02:00
parent fe57c73c38
commit b36a2e33d3
8 changed files with 33 additions and 13 deletions
+1
View File
@@ -166,6 +166,7 @@
"expo-task-manager": "~14.0.9",
"expo-updates": "~29.0.14",
"expo-video": "~3.0.15",
"expo-video-thumbnails": "^10.0.8",
"expo-web-browser": "~15.0.10",
"fast-deep-equal": "^3.1.3",
"fast-text-encoding": "^1.0.6",
+1
View File
@@ -135,6 +135,7 @@ export function VideoItem({
{maxWidth: 100},
a.justify_center,
a.align_center,
a.rounded_xs,
]}>
<PlayButtonIcon size={24} />
</View>
+5 -4
View File
@@ -354,13 +354,14 @@ export const ComposePost = ({
})
asset = await getVideoMetadata(file)
} else {
// Native: Use file URI directly with minimal asset properties
// The native compressVideo only needs uri and mimeType
// 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: 0,
height: 0,
width: metadata.width,
height: metadata.height,
}
}
+17 -4
View File
@@ -1,5 +1,6 @@
import {useCallback, useEffect, useState} from 'react'
import {Pressable, View} from 'react-native'
import * as VideoThumbnails from 'expo-video-thumbnails'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
@@ -13,6 +14,7 @@ import {DotGrid_Stroke2_Corner0_Rounded as DotsIcon} from '#/components/icons/Do
import * as MediaPreview from '#/components/MediaPreview'
import * as Prompt from '#/components/Prompt'
import {Text} from '#/components/Typography'
import {IS_WEB} from '#/env'
import {type DraftPostDisplay, type DraftSummary} from './state/schema'
import * as storage from './state/storage'
@@ -226,14 +228,25 @@ function DraftMediaPreview({post}: {post: DraftPostDisplay}) {
if (post.video?.exists && post.video.localPath) {
try {
const url = await storage.loadMediaFromLocal(post.video.localPath)
setVideoThumbnail(url)
if (IS_WEB) {
// can't generate thumbnails on web
setVideoThumbnail("yep, there's a video")
} else {
console.log('generating thumbnail of ', url)
const thumbnail = await VideoThumbnails.getThumbnailAsync(url, {
time: 0,
quality: 0.2,
})
console.log(thumbnail)
setVideoThumbnail(thumbnail.uri)
}
} catch (e) {
// Video doesn't exist locally
}
}
}
loadMedia()
void loadMedia()
}, [post.images, post.video])
// Nothing to show
@@ -249,9 +262,9 @@ function DraftMediaPreview({post}: {post: DraftPostDisplay}) {
{post.gif && (
<MediaPreview.GifItem thumbnail={post.gif.url} alt={post.gif.alt} />
)}
{post.video && (
{post.video && videoThumbnail && (
<MediaPreview.VideoItem
thumbnail={videoThumbnail}
thumbnail={IS_WEB ? undefined : videoThumbnail}
alt={post.video.altText}
/>
)}
+3 -1
View File
@@ -5,6 +5,7 @@ import {type AppBskyDraftDefs, RichText} from '@atproto/api'
import {nanoid} from 'nanoid/non-secure'
import {getImageDim} from '#/lib/media/manip'
import {mimeToExt} from '#/lib/media/video/util'
import {type ComposerImage} from '#/state/gallery'
import {type Gif} from '#/state/queries/tenor'
import {
@@ -211,7 +212,8 @@ async function serializeVideo(
// Encode mime type in the path for restoration
const mimeType = videoState.video.mimeType || 'video/mp4'
const localRefPath = `video:${mimeType}:${nanoid()}`
const ext = mimeToExt(mimeType)
const localRefPath = `video:${mimeType}:${nanoid()}.${ext}`
localRefPaths.set(localRefPath, videoState.video.uri)
// Read caption file contents as text
@@ -13,7 +13,6 @@ function getMediaDirectory(): Directory {
}
function getMediaFile(localRefPath: string): File {
// Use localRefPath as filename (URL-encoded for filesystem safety)
const safeFilename = encodeURIComponent(localRefPath)
return new File(getMediaDirectory(), safeFilename)
}
+1 -3
View File
@@ -12,8 +12,7 @@ import {PressableScale} from '#/lib/custom-animations/PressableScale'
import {useHaptics} from '#/lib/haptics'
import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
import {clamp} from '#/lib/numbers'
import {ios, useBreakpoints, useTheme} from '#/alf'
import {atoms as a} from '#/alf'
import {atoms as a, ios, useBreakpoints, useTheme} from '#/alf'
import {IS_WEB} from '#/env'
export interface FABProps extends ComponentProps<typeof Pressable> {
@@ -61,7 +60,6 @@ export function FABInner({testID, icon, onPress, style, ...props}: FABProps) {
{backgroundColor: t.palette.primary_500},
a.align_center,
a.justify_center,
a.shadow_sm,
style,
]}
{...props}>
+5
View File
@@ -9495,6 +9495,11 @@ expo-updates@~29.0.14:
ignore "^5.3.1"
resolve-from "^5.0.0"
expo-video-thumbnails@^10.0.8:
version "10.0.8"
resolved "https://registry.yarnpkg.com/expo-video-thumbnails/-/expo-video-thumbnails-10.0.8.tgz#a6313cea8e58dd0d5041d389a4fe4fa182eab176"
integrity sha512-nPUtP7ERLf5DY5V2A6gquRP5rP3Uvq6+FVkDwG9R3KKhFeTYkWZ5Ce1iQ7Yt5qDNQqcUcgEqmRpGCbJmn9ckKA==
expo-video@~3.0.15:
version "3.0.15"
resolved "https://registry.yarnpkg.com/expo-video/-/expo-video-3.0.15.tgz#38921dab5bc877572b64728acb58097716239aa7"