Skip to content

Instantly share code, notes, and snippets.

@shahmal1yev
Last active April 4, 2025 09:37
Show Gist options
  • Save shahmal1yev/edef78f9a8c6f711ffde0abb87435438 to your computer and use it in GitHub Desktop.
Save shahmal1yev/edef78f9a8c6f711ffde0abb87435438 to your computer and use it in GitHub Desktop.
Bluesky PHP Video Upload Example
<?php
use Atproto\Client;
use Atproto\DataModel\Blob\Blob;
use Atproto\Lexicons\App\Bsky\Embed\Video;
use Atproto\Responses\App\Bsky\Video\UploadVideoResponse;
use Atproto\Support\FileSupport;
// Authenticate the client with Bluesky credentials
$client = new Client();
$client->authenticate('your-handle.bsky.social', 'your-password');
// Retrieve the PDS server url from the authenticated session
$pdsUrl = null;
foreach ($client->authenticated()->didDoc()['service'] ?? [] as $service) {
if (($service['id'] ?? null) === '#atproto_pds') {
$pdsUrl = $service['serviceEndpoint'] ?? null;
break;
}
}
if (! $pdsUrl) {
throw new LogicException("Could not resolve PDS endpoint from DID document."); // If this happens, please report it
}
// Extract the host part from the PDS endpoint
$pdsHost = str_replace(
["https://", "http://"],
"did:web:",
$pdsUrl
);
// Generate a temporary authentication token for uploading the video
$token = bskyFacade($client)->getServiceAuth()
->aud($pdsHost)
->lxm(bskyFacade()->uploadBlob()->nsid())
->exp(\Carbon\Carbon::now()->addMinutes(15)->timestamp)
->send()
->token();
// Define the video file path
$filePath = '/path/to/your/video.mp4';
$file = new FileSupport($filePath);
// Upload the video to Bluesky
$uploadedVideo = bskyFacade()->uploadVideo(basename($filePath), $file, $token)->send();
// Check if the upload response includes a video blob reference
$videoBlob = null;
if ($uploadedVideo->has('blob')) {
$videoBlob = Blob::viaArray($uploadedVideo->blob());
}
// If the video blob is not immediately available, wait for job completion
while (! $videoBlob) {
$jobStatusResponse = bskyFacade()->getJobStatus($uploadedVideo->jobId())->send();
// If the upload job has completed, retrieve the video blob
if ($jobStatusResponse->jobStatus()->state() === 'JOB_STATE_COMPLETED') {
$videoBlob = Blob::viaArray($jobStatusResponse->jobStatus()->blob());
}
// Wait briefly before checking again
sleep(0.5);
}
// Create a new post with the uploaded video
$post = bskyFacade()->post()
->text("Hello, BlueSky! This is a video.")
->embed(new Video($videoBlob));
// Publish the post and retrieve the created post's URI
$createdRecordRes = bskyFacade()->createRecord()
->repo($client->authenticated()->handle())
->collection($post->nsid())
->record($post)
->send();
// Construct the public URL of the posted video
$username = $client->authenticated()->handle();
$postNsid = $post->nsid();
$segments = explode("/", $createdRecordRes->uri());
$postId = end($segments);
$uri = "https://bsky.app/profile/$username/post/$postId";
// Output the post URL
echo $uri . PHP_EOL;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment