Uploading a Video to Bluesky: Sending a Video File, Managing the Process, and Creating a Post
Uploading a video to Bluesky and sharing it in a post requires several steps. In this post, we will walk through the process using the Bluesky SDK, including:
- Uploading a video file,
- Managing the upload process,
- Posting the uploaded video.
Media uploads on the Bluesky platform are handled through a job-based system. This means that after uploading a file, it may not be immediately available for posting, as it requires processing time. To handle this correctly, we need to check the job status.
If you're ready, let's get started! 🚀
Introduction
Uploading videos to Bluesky involves more than just sending a file—it requires authentication, handling the upload process, and ensuring the video is processed before posting. This guide walks you through each step, from authentication to publishing your video.
1. Authentication
Before uploading a video, we need to authenticate by either retrieving an existing session or creating a new one.
Using an Existing Session
If you have a saved session, you can load it like this:
use Atproto\Responses\Com\Atproto\Server\CreateSessionResponse;
$sessionJSON = \fetchSavedSessionFromDatabase(); // Replace with your function
$session = new CreateSessionResponse(json_decode($sessionJSON, true));
Creating a New Session
If there's no existing session, authenticate with your credentials:
use Atproto\Client;
$client = new Client();
$client->authenticate('handle', 'password'); // Replace with your credentials
Once authenticated, we’ll use this session to retrieve our PDS details and generate a new token in the next step.
2. Generating a Temporary Key
To upload a video to our PDS server, we need the necessary permissions, which means authenticating and obtaining an additional token.
First, we retrieve the PDS server address associated with our account. This will be required when requesting the token.
Since this information is already included in the session we created earlier, we can access it directly without making extra requests:
$session = $client->authenticated();
$pdsEndpoint = $session->didDoc()->service()
->firstWhere('id', '#atproto_pds')['serviceEndpoint'];
// Extracting only the host part from the PDS endpoint for our request
$pdsHost = str_replace(
["https://", "http://"],
"did:web:",
$pdsEndpoint
);
Now that we have identified our PDS host, we can set an expiration time for the temporary token.
use Carbon\Carbon;
// Setting expiration time to 15 minutes
$tokenExpiredTime = Carbon::now()->addMinutes(15)->timestamp;
Next, we define the purpose of the token request. This can be considered similar to a scope
. Here, we use the
NSID of the lexicon.
$scope = bskyFacade()->uploadBlob()->nsid();
With all the required data in place, we are now ready to send the request and obtain our token:
$token = bskyFacade()->getServiceAuth()
->lxm($scope)
->aud($pdsHost)
->exp($tokenExpiredTime)
->send()
->token();
Now that we have successfully obtained the temporary token, we can proceed to the next step and use it to upload our video. 🚀
3. Uploading the Video to PDS
First, we send the video file to the PDS server.
use Atproto\Support\FileSupport;
$filePath = 'path/to/video.mp4';
$file = new FileSupport($filePath);
$uploadedVideo = bskyFacade()->uploadVideo(basename($filePath), $file, $token)->send();
Handling the Uploaded Video
Before using the uploaded video in a post creation request (com.atproto.repo.createRecord
lexicon), we need
to ensure that it has been fully processed.
Since small videos might upload instantly depending on size, speed, and server conditions, it's good practice to first check if the response already contains a blob field instead of immediately entering a loop.
use Atproto\DataModel\Blob\Blob;
// Check if the video upload returned a blob
if ($videoBlob = $uploadedVideo->has('blob')) {
$videoBlob = Blob::viaArray($uploadedVideo->blob());
}
If the condition is not met, we need to keep checking until we receive the required blob value.
while (! $videoBlob) {
$jobStatusResponse = bskyFacade()
->getJobStatus($uploadedVideo->jobId()) // Use the job ID from the upload response
->send();
if ($jobStatusResponse->jobStatus()->state() === 'JOB_STATE_COMPLETED') {
$videoBlob = Blob::viaArray($jobStatusResponse->jobStatus()->blob());
}
// Wait for 0.5 seconds before checking again
sleep(0.5);
}
This ensures that our variable receives the required value. Now, let’s move on to the next step—creating and publishing a post with the uploaded video. 🚀
4. Creating a New Post
To use the video blob in our post, we first need to convert it into an embed.
use Atproto\Lexicons\App\Bsky\Embed\Video;
$videoEmbed = new Video($videoBlob);
Now, let's create our post.
$post = bskyFacade()->post()
->text("Hello, BlueSky! This is a video.")
->embed($videoEmbed);
To publish the post, we send the request.
$createdRecordRes = bskyFacade()->createRecord()
->repo($client->authenticated()->handle())
->collection($post->nsid())
->record($post)
->send();
Finally, we extract the post ID and generate the URI to access it.
$username = $session->handle();
$postNsid = $post->nsid();
$segments = explode("/", $createdRecordRes->uri());
$postId = end($segments);
$uri = "https://bsky.app/profile/$username/post/$postId";
echo $uri . PHP_EOL;
And here’s our result: https://bsky.app/profile/shahmal1yevv.bsky.social/post/3lk6krhhtyn2e 🚀
Conclusion
In this guide, we covered the complete process of uploading a video to Bluesky using the Bluesky SDK. We walked through:
- Authenticating and retrieving a session,
- Generating a temporary token for the PDS server,
- Uploading the video and managing the job-based processing,
- Creating and publishing a post with the uploaded video.
By following these steps, you can seamlessly integrate video uploads into your Bluesky applications. For the full example, check out the Video Upload Example in the documentation.
Now, it's time to experiment and enhance your content with videos! 🚀