mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {useMutation} from '@tanstack/react-query'
2import {nanoid} from 'nanoid/non-secure'
3
4import {CompressedVideo} from '#/lib/media/video/compress'
5import {UploadVideoResponse} from '#/lib/media/video/types'
6import {createVideoEndpointUrl} from '#/state/queries/video/util'
7import {useAgent, useSession} from '#/state/session'
8
9const UPLOAD_HEADER = process.env.EXPO_PUBLIC_VIDEO_HEADER ?? ''
10
11export const useUploadVideoMutation = ({
12 onSuccess,
13 onError,
14 setProgress,
15}: {
16 onSuccess: (response: UploadVideoResponse) => void
17 onError: (e: any) => void
18 setProgress: (progress: number) => void
19}) => {
20 const {currentAccount} = useSession()
21 const agent = useAgent()
22
23 return useMutation({
24 mutationFn: async (video: CompressedVideo) => {
25 const uri = createVideoEndpointUrl('/upload', {
26 did: currentAccount!.did,
27 name: `${nanoid(12)}.mp4`, // @TODO what are we limiting this to?
28 })
29
30 // a logged-in agent should have this set, but we'll check just in case
31 if (!agent.pdsUrl) {
32 throw new Error('Agent does not have a PDS URL')
33 }
34
35 const {data: serviceAuth} =
36 await agent.api.com.atproto.server.getServiceAuth({
37 aud: `did:web:${agent.pdsUrl.hostname}`,
38 lxm: 'com.atproto.repo.uploadBlob',
39 })
40
41 const bytes = await fetch(video.uri).then(res => res.arrayBuffer())
42
43 const xhr = new XMLHttpRequest()
44 const res = (await new Promise((resolve, reject) => {
45 xhr.upload.addEventListener('progress', e => {
46 const progress = e.loaded / e.total
47 setProgress(progress)
48 })
49 xhr.onloadend = () => {
50 if (xhr.readyState === 4) {
51 const uploadRes = JSON.parse(
52 xhr.responseText,
53 ) as UploadVideoResponse
54 resolve(uploadRes)
55 onSuccess(uploadRes)
56 } else {
57 reject()
58 onError(new Error('Failed to upload video'))
59 }
60 }
61 xhr.onerror = () => {
62 reject()
63 onError(new Error('Failed to upload video'))
64 }
65 xhr.open('POST', uri)
66 xhr.setRequestHeader('Content-Type', 'video/mp4') // @TODO how we we set the proper content type?
67 // @TODO remove this header for prod
68 xhr.setRequestHeader('dev-key', UPLOAD_HEADER)
69 xhr.setRequestHeader('Authorization', `Bearer ${serviceAuth.token}`)
70 xhr.send(bytes)
71 })) as UploadVideoResponse
72
73 // @TODO rm for prod
74 console.log('[VIDEO]', res)
75 return res
76 },
77 onError,
78 onSuccess,
79 })
80}