/media command added for multi media posts.
This commit is contained in:
+197
@@ -2795,6 +2795,9 @@ Just type to talk!
|
||||
/visibility [level]
|
||||
Show current post visibility or set to: public, unlisted, private, direct
|
||||
|
||||
/media /path/to/file
|
||||
Upload media (images, video, audio) with accessibility features
|
||||
|
||||
/quit
|
||||
Resumes your boring life.
|
||||
|
||||
@@ -2912,6 +2915,12 @@ EOF
|
||||
&dmthump_no_skip if ($dmpause); # Also refresh DMs but don't skip timeline
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Media upload command
|
||||
if (m#^/media\s+(.+)$#) {
|
||||
my $file_path = $1;
|
||||
return &handle_media_upload($file_path);
|
||||
}
|
||||
if (m#^/a(gain)?(\s+\+\d+)?$#) { # the asynchronous form
|
||||
my $countmaybe = $2;
|
||||
$countmaybe =~ s/[^\d]//g if (length($countmaybe));
|
||||
@@ -8061,6 +8070,194 @@ sub urlshorten {
|
||||
return ($urlshort = (($rc =~ m#^http://#) ? $rc : undef));
|
||||
}
|
||||
|
||||
##### Media Upload Functions #####
|
||||
|
||||
sub handle_media_upload {
|
||||
my $file_path = shift;
|
||||
|
||||
# Validate file exists and is readable
|
||||
unless (-f $file_path && -r $file_path) {
|
||||
print $stdout "-- ERROR: File '$file_path' not found or not readable\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Check file size (Mastodon limit is typically 8MB for images, 40MB for video)
|
||||
my $file_size = -s $file_path;
|
||||
if ($file_size > 40 * 1024 * 1024) { # 40MB
|
||||
print $stdout "-- ERROR: File too large (max 40MB)\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Detect MIME type
|
||||
my $mime_type = &detect_mime_type($file_path);
|
||||
unless ($mime_type) {
|
||||
print $stdout "-- ERROR: Unable to determine file type\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
print $stdout "-- Detected file type: $mime_type\n" if ($verbose);
|
||||
|
||||
# Handle alt-text for images (REQUIRED for accessibility)
|
||||
my $alt_text = "";
|
||||
if ($mime_type =~ /^image\//) {
|
||||
print $stdout "-- Images require alt-text for accessibility\n";
|
||||
$alt_text = &linein("Enter alt text for " . (split('/', $file_path))[-1] . ": ");
|
||||
|
||||
# Empty alt-text cancels the upload (enforce accessibility)
|
||||
unless (defined($alt_text) && length($alt_text) > 0) {
|
||||
print $stdout "-- Upload cancelled: Alt-text is required for images\n";
|
||||
print $stdout "-- If you're going to use a client maintained by a blind guy, you can damn well describe your images!\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
# Get optional post message
|
||||
my $post_message = &linein("Enter post message (optional): ");
|
||||
$post_message = "" unless defined($post_message);
|
||||
|
||||
# Upload media and create post
|
||||
return &upload_media_and_post($file_path, $mime_type, $alt_text, $post_message);
|
||||
}
|
||||
|
||||
sub detect_mime_type {
|
||||
my $file_path = shift;
|
||||
|
||||
# Try using 'file' command first (most reliable)
|
||||
my $file_output = `file -b --mime-type "$file_path" 2>/dev/null`;
|
||||
chomp($file_output);
|
||||
if ($file_output && $file_output =~ /^[\w-]+\/[\w-]+$/) {
|
||||
return $file_output;
|
||||
}
|
||||
|
||||
# Fallback to file extension
|
||||
my $extension = lc((split(/\./, $file_path))[-1]);
|
||||
my %ext_to_mime = (
|
||||
'jpg' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'png' => 'image/png',
|
||||
'gif' => 'image/gif',
|
||||
'webp' => 'image/webp',
|
||||
'mp4' => 'video/mp4',
|
||||
'webm' => 'video/webm',
|
||||
'mov' => 'video/quicktime',
|
||||
'mp3' => 'audio/mpeg',
|
||||
'ogg' => 'audio/ogg',
|
||||
'wav' => 'audio/wav',
|
||||
'flac' => 'audio/flac'
|
||||
);
|
||||
|
||||
return $ext_to_mime{$extension} || undef;
|
||||
}
|
||||
|
||||
sub upload_media_and_post {
|
||||
my ($file_path, $mime_type, $alt_text, $post_message) = @_;
|
||||
|
||||
print $stdout "-- Uploading media file...\n";
|
||||
|
||||
# Step 1: Upload media to get media ID
|
||||
my $media_id = &upload_media_file($file_path, $mime_type, $alt_text);
|
||||
unless ($media_id) {
|
||||
print $stdout "-- ERROR: Media upload failed\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
print $stdout "-- Media uploaded successfully (ID: $media_id)\n";
|
||||
|
||||
# Step 2: Create post with media attachment
|
||||
return &create_post_with_media($media_id, $post_message);
|
||||
}
|
||||
|
||||
sub upload_media_file {
|
||||
my ($file_path, $mime_type, $alt_text) = @_;
|
||||
|
||||
# Mastodon media upload endpoint
|
||||
my $media_url = "${apibase}/media";
|
||||
|
||||
# Build curl command for multipart file upload
|
||||
my $curl_cmd = "$baseagent";
|
||||
|
||||
# Add standard auth and options (from @wend)
|
||||
foreach my $arg (@wend) {
|
||||
$curl_cmd .= " '$arg'";
|
||||
}
|
||||
|
||||
# Add OAuth Bearer token authentication
|
||||
my $bearer_header = &signrequest($media_url, '');
|
||||
if ($bearer_header) {
|
||||
$curl_cmd .= " $bearer_header";
|
||||
}
|
||||
|
||||
# Add multipart form data
|
||||
$curl_cmd .= " -X POST";
|
||||
$curl_cmd .= " -F 'file=\@$file_path;type=$mime_type'";
|
||||
|
||||
# Add alt-text if provided (for images)
|
||||
if (length($alt_text)) {
|
||||
my $escaped_alt = $alt_text;
|
||||
$escaped_alt =~ s/'/'\\''/g; # Escape single quotes for shell
|
||||
$curl_cmd .= " -F 'description=$escaped_alt'";
|
||||
}
|
||||
|
||||
$curl_cmd .= " '$media_url'";
|
||||
|
||||
print $stdout "-- DEBUG: Upload command: $curl_cmd\n" if ($superverbose);
|
||||
print $stdout "-- DEBUG: Uploading to $media_url\n" if ($verbose);
|
||||
|
||||
# Execute the upload
|
||||
my $response = `$curl_cmd 2>/dev/null`;
|
||||
my $exit_code = $? >> 8;
|
||||
|
||||
if ($exit_code != 0) {
|
||||
print $stdout "-- ERROR: Upload failed (curl exit code: $exit_code)\n";
|
||||
return undef;
|
||||
}
|
||||
|
||||
print $stdout "-- DEBUG: Upload response: $response\n" if ($superverbose);
|
||||
|
||||
# Parse JSON response to get media ID
|
||||
my $media_data = &parsejson($response);
|
||||
unless ($media_data && ref($media_data) eq 'HASH') {
|
||||
print $stdout "-- ERROR: Invalid response from media upload\n";
|
||||
print $stdout "-- Response: $response\n" if ($verbose);
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $media_id = $media_data->{'id'};
|
||||
unless ($media_id) {
|
||||
print $stdout "-- ERROR: No media ID in response\n";
|
||||
print $stdout "-- Response: $response\n" if ($verbose);
|
||||
return undef;
|
||||
}
|
||||
|
||||
return $media_id;
|
||||
}
|
||||
|
||||
sub create_post_with_media {
|
||||
my ($media_id, $post_message) = @_;
|
||||
|
||||
# Build post data
|
||||
my $post_data = "media_ids[]=$media_id";
|
||||
if (length($post_message)) {
|
||||
$post_data .= "&status=" . &url_oauth_sub($post_message);
|
||||
}
|
||||
|
||||
# Add current visibility setting
|
||||
$post_data .= "&visibility=$post_visibility" if defined($post_visibility);
|
||||
|
||||
print $stdout "-- Creating post with media attachment...\n";
|
||||
|
||||
# Use existing postjson function for creating the post
|
||||
my $result = &postjson($update, $post_data);
|
||||
|
||||
if ($result) {
|
||||
print $stdout "-- Post created successfully!\n";
|
||||
return 1;
|
||||
} else {
|
||||
print $stdout "-- ERROR: Failed to create post\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
##### optimizers -- these compile into an internal format #####
|
||||
|
||||
# utility routine for tquery support
|
||||
|
||||
Reference in New Issue
Block a user