EmDash 提供媒体库,用于管理图片、文档等文件。本指南介绍上传、整理以及在内容中使用媒体。
打开媒体库
在管理侧栏点击 Media 即可打开。库中列出所有已上传文件,含预览、文件名与上传时间。
上传文件
在媒体库中
-
在管理侧栏点击 Media
-
点击 Upload 或将文件拖入上传区域
-
在电脑中选择一个或多个文件
-
等待上传完成
在内容编辑器中
-
在富文本编辑器中点击图片按钮
-
在媒体选择器中点击 Upload
-
选择本地文件
-
填写替代文本后点击 Insert
支持的文件类型
EmDash 支持常见 Web 文件类型:
| 类别 | 扩展名 |
|---|---|
| 图片 | .jpg, .jpeg, .png, .gif, .webp, .avif, .svg |
| 文档 | .pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx |
| 视频 | .mp4, .webm, .mov |
| 音频 | .mp3, .wav, .ogg |
存储后端
EmDash 支持多种存储后端,在 Astro 配置中设置:
Local Storage
import { defineConfig } from "astro/config";
import emdash, { local } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
}),
],
});文件保存在 ./uploads 目录。适合开发与单机部署。
Cloudflare R2
import { defineConfig } from "astro/config";
import emdash, { r2 } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
storage: r2({
binding: "MEDIA_BUCKET",
publicUrl: "https://media.example.com",
}),
}),
],
});需在 wrangler.jsonc 中配置 R2 存储桶:
{
"r2_buckets": [
{
"binding": "MEDIA_BUCKET",
"bucket_name": "my-media-bucket",
},
],
} S3-Compatible
import { defineConfig } from "astro/config";
import emdash, { s3 } from "emdash/astro";
export default defineConfig({
integrations: [
emdash({
storage: s3({
endpoint: "https://s3.amazonaws.com",
bucket: "my-media-bucket",
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
region: "us-east-1",
publicUrl: "https://media.example.com",
}),
}),
],
});可与 Cloudflare R2(S3 API)、MinIO 及其他 S3 兼容服务配合使用。
上传流程
EmDash 使用签名 URL 实现安全上传:
-
客户端向 API 请求上传 URL
-
服务器生成带过期时间的签名 URL
-
客户端通过该 URL 直传存储
-
服务器将文件元数据写入数据库
大文件不经过应用服务器,可直接上传到云存储。
整理媒体
文件夹
可创建文件夹分类:
-
在媒体库中点击 New Folder
-
输入文件夹名
-
点击 Create
-
将文件拖入文件夹
搜索
在搜索框按文件名查找,支持部分匹配。
筛选
可按以下条件筛选:
- Type — 图片、文档、视频、音频
- Date — 上传日期范围
- Folder — 指定文件夹
在内容中使用媒体
在富文本编辑器中
-
将光标放在需要插入图片的位置
-
点击工具栏图片按钮
-
从媒体库选择或上传新图片
-
填写替代文本
-
点击 Insert
作为特色图片
-
在编辑器中打开内容条目
-
在侧栏找到 Featured Image 字段
-
点击 Select Image
-
从媒体库选择或上传
-
点击 Save
在自定义字段中
对配置为图片或文件的字段,点击字段即可打开媒体选择器。
在模板中展示媒体
从内容数据读取媒体 URL:
---
import { getEmDashEntry } from "emdash";
const { entry: post } = await getEmDashEntry("posts", Astro.params.slug);
---
{post?.data.featured_image && (
<img
src={post.data.featured_image}
alt={post.data.featured_image_alt ?? ""}
/>
)}
响应式图片
对外部 URL 使用 Astro 的 Image 组件实现响应式图片:
响应式图片
对外部 URL 使用 Astro 的 Image 组件实现响应式图片:
---
import { Image } from "astro:assets";
import { getEmDashEntry } from "emdash";
const { entry: post } = await getEmDashEntry("posts", Astro.params.slug);
---
{post?.data.featured_image && (
<Image
src={post.data.featured_image}
alt={post.data.featured_image_alt ?? ""}
width={800}
height={450}
/>
)}
删除媒体
-
选中要删除的文件
-
点击 Delete
-
确认删除
媒体 API
通过管理 API 以编程方式访问媒体。
上传文件
以 multipart/form-data 上传:
POST /_emdash/api/media
Content-Type: multipart/form-data
Authorization: Bearer YOUR_API_TOKEN
file=<binary file data>
响应示例:
{
"success": true,
"data": {
"item": {
"id": "01ABC123",
"filename": "hero-image.jpg",
"mime_type": "image/jpeg",
"storage_key": "media/abc123/hero-image.jpg",
"width": 1200,
"height": 800
}
}
}
列出媒体
GET /_emdash/api/media?prefix=images/&limit=20
Authorization: Bearer YOUR_API_TOKEN
删除媒体
DELETE /_emdash/api/media/images/hero.jpg
Authorization: Bearer YOUR_API_TOKEN
媒体提供商
除本地存储外,EmDash 支持外部媒体提供商,用于专业图片与视频托管。提供商在媒体选择器中显示为标签页。
可用提供商
Cloudflare Images
Cloudflare Images 提供图片托管,支持自动优化、缩放与格式转换。
import { defineConfig } from "astro/config";
import emdash from "emdash/astro";
import { cloudflareImages } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
// ... database, storage config
mediaProviders: [
cloudflareImages({
accountId: import.meta.env.CF_ACCOUNT_ID,
apiToken: import.meta.env.CF_IMAGES_TOKEN,
// Optional: custom delivery domain
deliveryDomain: "images.example.com",
}),
],
}),
],
});功能:
- 在后台浏览并上传图片
- 自动优化与格式转换
- 基于 URL 的变换(尺寸、裁剪、格式)
- 灵活的响应式变体
Cloudflare Stream
Cloudflare Stream 提供视频托管与 HLS/DASH 自适应流。
import { defineConfig } from "astro/config";
import emdash from "emdash/astro";
import { cloudflareStream } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
// ... database, storage config
mediaProviders: [
cloudflareStream({
accountId: import.meta.env.CF_ACCOUNT_ID,
apiToken: import.meta.env.CF_STREAM_TOKEN,
// Optional: player settings
controls: true,
autoplay: false,
loop: false,
}),
],
}),
],
});功能:
- 在后台浏览、搜索并上传视频
- HLS 与 DASH 自适应流
- 自动生成缩略图
- 大文件直传
多个提供商
可配置多个提供商,每个在选择器中显示为一个标签:
import { defineConfig } from "astro/config";
import emdash from "emdash/astro";
import { cloudflareImages, cloudflareStream } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: d1({ binding: "DB" }),
storage: r2({ binding: "MEDIA" }),
mediaProviders: [
cloudflareImages({
accountId: import.meta.env.CF_ACCOUNT_ID,
apiToken: import.meta.env.CF_IMAGES_TOKEN,
}),
cloudflareStream({
accountId: import.meta.env.CF_ACCOUNT_ID,
apiToken: import.meta.env.CF_STREAM_TOKEN,
}),
],
}),
],
});
本地媒体库(「Library」标签)始终与已配置的提供商并存。
渲染提供商媒体
使用 Image 组件渲染:
---
import { Image } from "emdash/ui";
import { getEmDashEntry } from "emdash";
const { entry: post } = await getEmDashEntry("posts", Astro.params.slug);
---
{post?.data.featured_image && (
<Image
image={post.data.featured_image}
width={800}
height={450}
/>
)}
组件会:
- 根据存储值识别提供商
- 渲染优化的
<img> - 应用提供商专属优化(如 Cloudflare Images 变换)
MediaValue 类型
媒体字段存储包含提供商信息的 MediaValue 对象:
interface MediaValue {
provider?: string; // Provider ID, defaults to "local"
id: string; // Provider-specific ID
src?: string; // Direct URL (for local media or legacy data)
previewUrl?: string; // Preview URL for admin display (external providers)
filename?: string; // Original filename
mimeType?: string; // MIME type
width?: number; // Image/video width
height?: number; // Image/video height
alt?: string; // Alt text
meta?: Record<string, unknown>; // Provider-specific metadata
}
这样无论资源托管在何处,EmDash 都能正确渲染。
下一步
- Working with Content — 在内容中使用媒体
- Create a Blog — 为文章添加图片
- Querying Content — 在模板中展示媒体