astro-cloudflare-media
v0.1.0
Published
Astro integration for managing media uploads to Cloudflare (Stream, R2, Images)
Maintainers
Readme
astro-cloudflare-media
A development-time Astro integration for managing media uploads to Cloudflare (Stream, R2, Images).
Features
- Video uploads to Cloudflare Stream with direct upload support
- Image uploads to Cloudflare Images with automatic variants
- Audio/file uploads to Cloudflare R2 (S3-compatible)
- Dev-only dashboard at
/_mediafor managing all uploads - TypeScript API for programmatic access
Installation
npm install astro-cloudflare-mediaConfiguration
Add the integration to your astro.config.mjs:
import { defineConfig } from 'astro/config';
import cloudflareMedia from 'astro-cloudflare-media';
export default defineConfig({
integrations: [
cloudflareMedia({
// All config is optional - uses environment variables by default
dashboardRoute: '/_media', // Default dashboard URL
}),
],
});Environment Variables
Create a .env file with your Cloudflare credentials:
# Required
CLOUDFLARE_ACCOUNT_ID=your_account_id
CLOUDFLARE_API_TOKEN=your_api_token
# Optional - for R2
CLOUDFLARE_R2_BUCKET=podcast-media
CLOUDFLARE_R2_PUBLIC_URL=https://media.yourdomain.com
# Optional - for Images
CLOUDFLARE_IMAGES_HASH=your_delivery_hashCreating a Cloudflare API Token
- Go to Cloudflare Dashboard → API Tokens
- Click "Create Token"
- Select "Create Custom Token"
- Add these permissions:
- Account > Cloudflare Stream > Edit
- Account > Cloudflare Images > Edit
- Account > Workers R2 Storage > Edit
- Save and copy your token
Usage
Dashboard
Start your dev server and visit /_media to access the media dashboard:
npm run dev
# Open http://localhost:4321/_mediaThe dashboard allows you to:
- Upload videos, images, and audio files
- Browse your media library
- Copy URLs for embedding
- Delete media
Programmatic API
You can also use the API directly in your code:
import { CloudflareClient, StreamApi, ImagesApi } from 'astro-cloudflare-media';
// Create client
const client = new CloudflareClient({
accountId: process.env.CLOUDFLARE_ACCOUNT_ID,
apiToken: process.env.CLOUDFLARE_API_TOKEN,
});
// Upload video
const streamApi = new StreamApi(client);
const { uploadURL, uid } = await streamApi.createDirectUpload({
maxDurationSeconds: 3600,
metadata: { name: 'My Video' },
});
// Upload image
const imagesApi = new ImagesApi(client);
const image = await imagesApi.upload(file, {
filename: 'cover.jpg',
metadata: { episode: '001' },
});Stream URL Helpers
import { getStreamUrls } from 'astro-cloudflare-media';
const urls = getStreamUrls('your-video-id');
// urls.iframe - Embed URL
// urls.hls - HLS manifest for custom players
// urls.mp4 - Download URL
// urls.thumbnail(0) - Thumbnail at 0 seconds
// urls.gif(0, 5) - Animated GIF from 0-5 secondsPodcast Integration
This plugin is designed to work seamlessly with podcast content collections.
Content Collection Schema
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const mediaSchema = z.object({
audioUrl: z.string(),
audioDuration: z.number(),
audioSize: z.number(),
audioType: z.string().default('audio/mpeg'),
videoUrl: z.string().optional(),
streamVideoId: z.string().optional(),
thumbnail: z.string().optional(),
});
const podcast = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
media: mediaSchema,
draft: z.boolean().default(false),
}),
});
export const collections = { podcast };Episode Example
---
title: "Episode 1: Getting Started"
description: "Introduction to the podcast"
pubDate: 2025-01-15
media:
audioUrl: "https://r2.yourdomain.com/episodes/001.mp3"
audioDuration: 1847
audioSize: 29552640
streamVideoId: "abc123xyz" # Cloudflare Stream ID
thumbnail: "/thumbnails/001.jpg"
draft: false
---
Show notes content here...Security
- The dashboard is only available in development mode
- API routes are not included in production builds
- Credentials are never exposed to the client
TypeScript
Full TypeScript support with exported types:
import type {
CloudflareMediaConfig,
StreamVideo,
CloudflareImage,
MediaItem,
} from 'astro-cloudflare-media';License
MIT
