get videos working on native
This commit is contained in:
@@ -166,6 +166,7 @@
|
|||||||
"expo-task-manager": "~14.0.9",
|
"expo-task-manager": "~14.0.9",
|
||||||
"expo-updates": "~29.0.14",
|
"expo-updates": "~29.0.14",
|
||||||
"expo-video": "~3.0.15",
|
"expo-video": "~3.0.15",
|
||||||
|
"expo-video-thumbnails": "^10.0.8",
|
||||||
"expo-web-browser": "~15.0.10",
|
"expo-web-browser": "~15.0.10",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"fast-text-encoding": "^1.0.6",
|
"fast-text-encoding": "^1.0.6",
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ export function VideoItem({
|
|||||||
{maxWidth: 100},
|
{maxWidth: 100},
|
||||||
a.justify_center,
|
a.justify_center,
|
||||||
a.align_center,
|
a.align_center,
|
||||||
|
a.rounded_xs,
|
||||||
]}>
|
]}>
|
||||||
<PlayButtonIcon size={24} />
|
<PlayButtonIcon size={24} />
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -354,13 +354,14 @@ export const ComposePost = ({
|
|||||||
})
|
})
|
||||||
asset = await getVideoMetadata(file)
|
asset = await getVideoMetadata(file)
|
||||||
} else {
|
} else {
|
||||||
// Native: Use file URI directly with minimal asset properties
|
// Native: Get video metadata using react-native-compressor
|
||||||
// The native compressVideo only needs uri and mimeType
|
const {getVideoMetaData} = require('react-native-compressor')
|
||||||
|
const metadata = await getVideoMetaData(videoInfo.uri)
|
||||||
asset = {
|
asset = {
|
||||||
uri: videoInfo.uri,
|
uri: videoInfo.uri,
|
||||||
mimeType: videoInfo.mimeType,
|
mimeType: videoInfo.mimeType,
|
||||||
width: 0,
|
width: metadata.width,
|
||||||
height: 0,
|
height: metadata.height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {useCallback, useEffect, useState} from 'react'
|
import {useCallback, useEffect, useState} from 'react'
|
||||||
import {Pressable, View} from 'react-native'
|
import {Pressable, View} from 'react-native'
|
||||||
|
import * as VideoThumbnails from 'expo-video-thumbnails'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
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 MediaPreview from '#/components/MediaPreview'
|
||||||
import * as Prompt from '#/components/Prompt'
|
import * as Prompt from '#/components/Prompt'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {IS_WEB} from '#/env'
|
||||||
import {type DraftPostDisplay, type DraftSummary} from './state/schema'
|
import {type DraftPostDisplay, type DraftSummary} from './state/schema'
|
||||||
import * as storage from './state/storage'
|
import * as storage from './state/storage'
|
||||||
|
|
||||||
@@ -226,14 +228,25 @@ function DraftMediaPreview({post}: {post: DraftPostDisplay}) {
|
|||||||
if (post.video?.exists && post.video.localPath) {
|
if (post.video?.exists && post.video.localPath) {
|
||||||
try {
|
try {
|
||||||
const url = await storage.loadMediaFromLocal(post.video.localPath)
|
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) {
|
} catch (e) {
|
||||||
// Video doesn't exist locally
|
// Video doesn't exist locally
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMedia()
|
void loadMedia()
|
||||||
}, [post.images, post.video])
|
}, [post.images, post.video])
|
||||||
|
|
||||||
// Nothing to show
|
// Nothing to show
|
||||||
@@ -249,9 +262,9 @@ function DraftMediaPreview({post}: {post: DraftPostDisplay}) {
|
|||||||
{post.gif && (
|
{post.gif && (
|
||||||
<MediaPreview.GifItem thumbnail={post.gif.url} alt={post.gif.alt} />
|
<MediaPreview.GifItem thumbnail={post.gif.url} alt={post.gif.alt} />
|
||||||
)}
|
)}
|
||||||
{post.video && (
|
{post.video && videoThumbnail && (
|
||||||
<MediaPreview.VideoItem
|
<MediaPreview.VideoItem
|
||||||
thumbnail={videoThumbnail}
|
thumbnail={IS_WEB ? undefined : videoThumbnail}
|
||||||
alt={post.video.altText}
|
alt={post.video.altText}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {type AppBskyDraftDefs, RichText} from '@atproto/api'
|
|||||||
import {nanoid} from 'nanoid/non-secure'
|
import {nanoid} from 'nanoid/non-secure'
|
||||||
|
|
||||||
import {getImageDim} from '#/lib/media/manip'
|
import {getImageDim} from '#/lib/media/manip'
|
||||||
|
import {mimeToExt} from '#/lib/media/video/util'
|
||||||
import {type ComposerImage} from '#/state/gallery'
|
import {type ComposerImage} from '#/state/gallery'
|
||||||
import {type Gif} from '#/state/queries/tenor'
|
import {type Gif} from '#/state/queries/tenor'
|
||||||
import {
|
import {
|
||||||
@@ -211,7 +212,8 @@ async function serializeVideo(
|
|||||||
|
|
||||||
// Encode mime type in the path for restoration
|
// Encode mime type in the path for restoration
|
||||||
const mimeType = videoState.video.mimeType || 'video/mp4'
|
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)
|
localRefPaths.set(localRefPath, videoState.video.uri)
|
||||||
|
|
||||||
// Read caption file contents as text
|
// Read caption file contents as text
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ function getMediaDirectory(): Directory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getMediaFile(localRefPath: string): File {
|
function getMediaFile(localRefPath: string): File {
|
||||||
// Use localRefPath as filename (URL-encoded for filesystem safety)
|
|
||||||
const safeFilename = encodeURIComponent(localRefPath)
|
const safeFilename = encodeURIComponent(localRefPath)
|
||||||
return new File(getMediaDirectory(), safeFilename)
|
return new File(getMediaDirectory(), safeFilename)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
|||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
|
import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
|
||||||
import {clamp} from '#/lib/numbers'
|
import {clamp} from '#/lib/numbers'
|
||||||
import {ios, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, ios, useBreakpoints, useTheme} from '#/alf'
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
|
|
||||||
export interface FABProps extends ComponentProps<typeof Pressable> {
|
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},
|
{backgroundColor: t.palette.primary_500},
|
||||||
a.align_center,
|
a.align_center,
|
||||||
a.justify_center,
|
a.justify_center,
|
||||||
a.shadow_sm,
|
|
||||||
style,
|
style,
|
||||||
]}
|
]}
|
||||||
{...props}>
|
{...props}>
|
||||||
|
|||||||
@@ -9495,6 +9495,11 @@ expo-updates@~29.0.14:
|
|||||||
ignore "^5.3.1"
|
ignore "^5.3.1"
|
||||||
resolve-from "^5.0.0"
|
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:
|
expo-video@~3.0.15:
|
||||||
version "3.0.15"
|
version "3.0.15"
|
||||||
resolved "https://registry.yarnpkg.com/expo-video/-/expo-video-3.0.15.tgz#38921dab5bc877572b64728acb58097716239aa7"
|
resolved "https://registry.yarnpkg.com/expo-video/-/expo-video-3.0.15.tgz#38921dab5bc877572b64728acb58097716239aa7"
|
||||||
|
|||||||
Reference in New Issue
Block a user