media
File and media upload package with pluggable storage backends (disk, S3).
Features
- Pluggable storage backends (local disk, AWS S3, S3-compatible services)
- File validation (MIME type filtering, size limits)
- Custom metadata support (JSON)
- Per-user storage usage tracking
- Date-based file organization (disk backend)
- AWS Signature Version 4 signing (no SDK required)
- S3-compatible: MinIO, Cloudflare R2, DigitalOcean Spaces
- PostgreSQL and SQLite support
Installation
dependencies:
media: ^1.0.0Usage
Setup
import 'package:media/media.dart';
final mediaService = MediaService(
repository: PostgresMediaRepository(pool),
backends: {
'disk': DiskStorageBackend(
baseDirectory: Directory('./uploads'),
baseUrl: 'https://example.com/media',
organizeDated: true,
),
's3': S3StorageBackend(
accessKeyId: env.getString('AWS_ACCESS_KEY_ID'),
secretAccessKey: env.getString('AWS_SECRET_ACCESS_KEY'),
region: 'us-east-1',
bucketName: 'my-bucket',
),
},
defaultBackend: 'disk',
);S3-Compatible Services
// Cloudflare R2
S3StorageBackend(
accessKeyId: env.getString('R2_ACCESS_KEY'),
secretAccessKey: env.getString('R2_SECRET_KEY'),
region: 'auto',
bucketName: 'my-bucket',
endpoint: 'https://ACCOUNT_ID.r2.cloudflarestorage.com',
cdnUrl: 'https://cdn.example.com',
)Upload Files
final mediaFile = await mediaService.uploadMedia(
fileBytes: fileBytes,
originalFilename: 'photo.jpg',
mimeType: 'image/jpeg',
uploadedBy: accountId,
config: UploadConfig(
allowedMimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
maxSizeBytes: 10 * 1024 * 1024, // 10 MB
customMetadata: {'category': 'profile'},
),
);Download and Manage Files
// Download file bytes
final bytes = await mediaService.downloadMedia(fileId);
// Get file metadata
final file = await mediaService.getMediaFile(fileId);
// List user's files (paginated)
final files = await mediaService.listUserMedia(accountId, limit: 50);
// Get user's total storage usage
final bytes = await mediaService.getUserStorageUsage(accountId);
// Delete a file
await mediaService.deleteMedia(fileId);