get videos working on native
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -135,6 +135,7 @@ export function VideoItem({
|
||||
{maxWidth: 100},
|
||||
a.justify_center,
|
||||
a.align_center,
|
||||
a.rounded_xs,
|
||||
]}>
|
||||
<PlayButtonIcon size={24} />
|
||||
</View>
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user