/media command added for multi media posts.

This commit is contained in:
Storm Dragon
2025-07-28 19:24:10 -04:00
parent 5197af9eba
commit 4e7ceee476
+197
View File
@@ -2795,6 +2795,9 @@ Just type to talk!
/visibility [level] /visibility [level]
Show current post visibility or set to: public, unlisted, private, direct Show current post visibility or set to: public, unlisted, private, direct
/media /path/to/file
Upload media (images, video, audio) with accessibility features
/quit /quit
Resumes your boring life. Resumes your boring life.
@@ -2912,6 +2915,12 @@ EOF
&dmthump_no_skip if ($dmpause); # Also refresh DMs but don't skip timeline &dmthump_no_skip if ($dmpause); # Also refresh DMs but don't skip timeline
return 0; 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 if (m#^/a(gain)?(\s+\+\d+)?$#) { # the asynchronous form
my $countmaybe = $2; my $countmaybe = $2;
$countmaybe =~ s/[^\d]//g if (length($countmaybe)); $countmaybe =~ s/[^\d]//g if (length($countmaybe));
@@ -8061,6 +8070,194 @@ sub urlshorten {
return ($urlshort = (($rc =~ m#^http://#) ? $rc : undef)); 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 ##### ##### optimizers -- these compile into an internal format #####
# utility routine for tquery support # utility routine for tquery support