Media Upload
The client.media API handles file uploads and exposes the server's async
processing state without adding a client-side waiting deadline.
Uploading media
import 'dart:io';
final bytes = await File('photo.jpg').readAsBytes();
final attachment = await client.media.upload(
bytes,
'photo.jpg',
description: 'Alt text for accessibility',
);
print(attachment.id);
print(attachment.url);
Upload with thumbnail
final thumbnailBytes = await File('thumb.jpg').readAsBytes();
final attachment = await client.media.upload(
videoBytes,
'video.mp4',
description: 'A short clip',
thumbnail: thumbnailBytes,
thumbnailFilename: 'thumb.jpg',
);
Focal point
The focal point determines which part of the image remains visible when cropped. Values range from -1.0 to 1.0 for both axes:
final attachment = await client.media.upload(
bytes,
'photo.jpg',
focus: '0.0,-0.5', // Center horizontally, upper half
);
Async processing
When the server returns HTTP 202, upload() returns the attachment immediately
with a null url. Call fetchById() when your application needs to check the
status. HTTP 206 means processing is still in progress, while HTTP 200 means the
latest attachment state is available. The library does not poll or impose a
processing deadline.
If Mastodon reports HTTP 422, fetchById() surfaces the processing failure as
MastodonValidationException through the standard error conversion path.
final attachment = await client.media.upload(bytes, 'large-video.mp4');
if (attachment.url == null) {
// Check later according to the application's own policy.
final current = await client.media.fetchById(attachment.id);
print(current.url == null ? 'Still processing' : current.url);
}
Updating media attributes
Update alt text, thumbnail, or focal point before attaching to a status:
final updated = await client.media.update(
attachment.id,
description: 'Updated alt text',
focus: '0.5,0.0',
);
Deleting unattached media
Only media not yet attached to a status can be deleted:
await client.media.delete(attachment.id);
API version fallback
The library prefers POST /api/v2/media and automatically falls back to POST /api/v1/media for servers that do not support v2 (HTTP 404, 405, or 501). This is handled transparently.
Attaching to a status
final attachment = await client.media.upload(bytes, 'photo.jpg',
description: 'A scenic view',
);
final result = await client.statuses.create(
MastodonStatusCreateRequest(
status: 'Check out this view!',
mediaIds: [attachment.id],
),
);
Up to 4 images or 1 video/audio can be attached per status (server-dependent).