Skip to content

Instantly share code, notes, and snippets.

@mozzius
Created October 18, 2024 21:00
Show Gist options
  • Save mozzius/39a21b19f0d3af4caead07a3152257f9 to your computer and use it in GitHub Desktop.
Save mozzius/39a21b19f0d3af4caead07a3152257f9 to your computer and use it in GitHub Desktop.
Bluesky video upload - indirect upload
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 <video> element
// and measure the dimensions once it loads. in React Native, the image picker
// will give you the dimensions directly
import { ffprobe } from "https://deno.land/x/[email protected]/ffprobe.ts";
async function getAspectRatio(fileName: string) {
const { streams } = await ffprobe(fileName, {});
const videoSteam = streams.find((stream) => stream.codec_type === "video");
return {
width: videoSteam.width,
height: videoSteam.height,
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment