// NOTE: this uses Deno import { AppBskyEmbedVideo, AtpAgent } from "npm:@atproto/api"; const userAgent = new AtpAgent({ service: prompt("Service URL (default: https://bsky.social):") || "https://bsky.social", }); await userAgent.login({ identifier: prompt("Handle:")!, password: prompt("Password:")!, }); console.log(`Logged in as ${userAgent.session?.handle}`); const videoPath = prompt("Video file (.mp4):")!; const file = await Deno.open(videoPath); const { size } = await file.stat(); // optional: print upload progress let bytesUploaded = 0; const progressTrackingStream = new TransformStream({ transform(chunk, controller) { controller.enqueue(chunk); bytesUploaded += chunk.byteLength; console.log( "upload progress:", Math.trunc(bytesUploaded / size * 100) + "%", ); }, flush() { console.log("upload complete ✨"); }, }); const { data } = await userAgent.com.atproto.repo.uploadBlob( // @ts-expect-error - expecting an Uint8Array, but a ReadableStream is fine file.readable.pipeThrough(progressTrackingStream), ); console.log("video uploaded, posting..."); await userAgent.post({ text: "This post should have a video attached", langs: ["en"], embed: { $type: "app.bsky.embed.video", video: data.blob, aspectRatio: await getAspectRatio(videoPath), } satisfies AppBskyEmbedVideo.Main, }); console.log("done ✨ (video will take a little bit to process)"); // bonus: get aspect ratio using ffprobe // in the browser, you can just put the video uri in a