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.0

Usage

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);