Something went wrong. Try again.
Bluesky app fork with some witchin' additions 💫 forked from jollywhoppers.com/witchsky.app
Something went wrong. Try again.
2.5 kB · 94 lines
TypeScript
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495import {type AppBskyVideoDefs, type BskyAgent} from '@atproto/api'import {type I18n} from '@lingui/core'import {msg} from '@lingui/core/macro'import {nanoid} from 'nanoid/non-secure'
import {AbortError} from '#/lib/async/cancelable'import {ServerError} from '#/lib/media/video/errors'import {type CompressedVideo} from '#/lib/media/video/types'import {getServiceAuthToken, getVideoUploadLimits} from './upload.shared'import {createVideoEndpointUrl, mimeToExt} from './util'
export async function uploadVideo({ video, agent, did, setProgress, signal, _,}: { video: CompressedVideo agent: BskyAgent did: string setProgress: (progress: number) => void signal: AbortSignal _: I18n['_']}) { if (signal.aborted) { throw new AbortError() } await getVideoUploadLimits(agent, _)
const uri = createVideoEndpointUrl('/xrpc/app.bsky.video.uploadVideo', { did, name: `${nanoid(12)}.${mimeToExt(video.mimeType)}`, })
let bytes = video.bytes if (!bytes) { if (signal.aborted) { throw new AbortError() } bytes = await fetch(video.uri).then(res => res.arrayBuffer()) }
if (signal.aborted) { throw new AbortError() } const token = await getServiceAuthToken({ agent, lxm: 'com.atproto.repo.uploadBlob', exp: Date.now() / 1000 + 60 * 30, // 30 minutes })
if (signal.aborted) { throw new AbortError() } const xhr = new XMLHttpRequest() const res = await new Promise<AppBskyVideoDefs.JobStatus>( (resolve, reject) => { xhr.upload.addEventListener('progress', e => { const progress = e.loaded / e.total setProgress(progress) }) xhr.onloadend = () => { if (signal.aborted) { reject(new AbortError()) } else if (xhr.readyState === 4) { const uploadRes = JSON.parse( xhr.responseText, ) as AppBskyVideoDefs.JobStatus resolve(uploadRes) } else { reject(new ServerError(_(msg`Failed to upload video`))) } } xhr.onerror = () => { reject(new ServerError(_(msg`Failed to upload video`))) } xhr.open('POST', uri) xhr.setRequestHeader('Content-Type', video.mimeType) xhr.setRequestHeader('Authorization', `Bearer ${token}`) xhr.send(bytes) }, )
if (!res.jobId) { throw new ServerError(res.error || _(msg`Failed to upload video`)) }
if (signal.aborted) { throw new AbortError() } return res}