EmDash 包含一个用于管理图片、文档和其他文件的媒体库。本指南涵盖在内容中上传、查找和使用媒体。
访问媒体库
在管理侧边栏中点击媒体打开媒体库。主库显示未分配到文件夹的文件夹和文件。打开文件夹查看其文件。
使用位置
在 EmDash 的媒体库中打开一个文件,查看引用它的内容条目。在 EmDash 扫描现有内容期间,列表包含迄今找到的引用,可能不完整。
开启媒体使用跟踪
如果媒体使用跟踪已关闭,管理员可以开启它:
- 完成所有内容编辑。如果另一个应用程序直接写入内容数据库,请暂停它并等待进行中的写入完成。
- 打开设置 → 媒体使用跟踪,选择启用跟踪,然后确认。
- 当页面显示正在索引现有内容时,编辑和其他数据库写入可以恢复。
- 保持页面打开直到显示就绪。如果离开,返回以从保存的进度继续。
一旦开启媒体使用跟踪,就不能关闭。
上传文件
从媒体库
-
在管理侧边栏中打开媒体。
-
选择上传文件,然后浏览文件选择一个或多个文件。你也可以将文件拖放到媒体库的任何位置。
-
上传自动开始。对话框显示每个文件的状态,并允许取消或重试单个文件。
从内容编辑器
-
在内容编辑器中打开图片、文件或画廊字段。
-
搜索、按类型过滤、浏览文件夹或在可用的媒体源之间切换。
-
选择现有媒体,或选择上传文件并从计算机中选择文件。你也可以将文件拖放到选择器上。每个上传都会以其当前状态出现在结果中。
-
如果上传失败,在该项目上选择重试或删除。成功的上传变成一个已选媒体卡片。
-
对于画廊,使用已选媒体下的箭头控件设置返回顺序。
-
选择选择器操作,如选择、插入图片或添加 3 张图片。
支持的文件类型
EmDash 默认接受以下文件类型:
| 类别 | 扩展名 |
|---|---|
| 图片 | .jpg, .jpeg, .png, .gif, .webp, .avif |
| 文档 | .pdf |
| 视频 | .mp4, .webm, .mov |
| 音频 | .mp3, .wav, .ogg |
图片和文件字段可以允许其他 MIME 类型,包括用于 SVG 文件的 image/svg+xml。
存储后端
EmDash 支持多个存储后端。在 Astro 配置中配置存储:
本地存储
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 from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";
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 兼容
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 创建一个待处理的媒体项。
- 客户端将文件上传到返回的目标。
- 客户端确认上传。
- EmDash 验证存储的文件并将媒体项标记为就绪。
S3 兼容存储返回签名 URL,以便文件可以绕过应用程序运行时。本地存储和原生 R2 返回同源流式端点。
查找媒体
搜索
使用搜索框按名称查找文件。搜索匹配部分文件名。
按类型过滤
使用类型过滤器显示图片、文档、视频或音频文件。
在文件夹中组织媒体
编辑者可以从主库选择添加新文件夹。选择文件夹名称打开文件夹。没有搜索词时,文件夹页面只显示分配给该文件夹的媒体。文件名搜索覆盖整个库,包括其他文件夹和主库。
要将本地文件移入可见文件夹,将其网格卡片或列表行拖到文件夹上。你也可以打开媒体详情,选择一个位置,然后选择保存。使用位置将文件返回到主库或不用拖动移动它。
作者可以移动他们上传的本地文件。编辑者可以移动任何本地文件。外部提供者的文件不能分配到文件夹。
上传进入主库。使用上述任一方法在上传后将它们移入文件夹。
删除文件夹将其媒体返回到主库。媒体文件、URL 和内容引用保持不变。
在内容中使用媒体
在富文本编辑器中
- 将光标放在你想要图片的位置
- 点击工具栏中的图片按钮
- 在选择器中找到图片或上传新的。
- 选择插入图片。
- 在图片设置中添加替代文本。
作为特色图片
- 在编辑器中打开内容条目
- 在侧边栏中找到特色图片字段
- 点击选择图片
- 从选择器中选择图片或上传一个。
- 选择选择,然后保存。
在自定义字段中
对于配置为图片或文件类型的字段,选择字段操作打开同样的媒体选择器。字段的 MIME 类型规则限制你可以选择的源和文件。
编辑选定的图片资产
本地图片字段、富文本图片和画廊图片提供三个操作:
- 替换更改当前字段、块或画廊位置中使用的图片。
- 编辑资产打开所选媒体库项目的媒体详情。你可以在内容编辑器中更新其替代文本、标题、焦点或裁剪。
- 移除清除当前内容引用。媒体库项目仍然可用。
创建裁剪副本为当前使用选择新副本。富文本和画廊图片保留其每次使用的替代文本、标题、布局和位置。替换原始保持相同的媒体引用,并在该资产使用的所有地方更改图片。
外部提供者的图片和文件字段提供替换和移除,但不提供编辑资产。
替换图片
使用替换图片更新现有本地媒体项背后的文件。作者可以替换他们上传的图片,编辑者可以替换任何本地图片。此操作适用于存储在本地磁盘、Cloudflare R2 或 S3 兼容存储上的 JPEG、PNG 和 WebP 图片。
- 打开媒体,然后从本地库中选择一张图片。
- 留在详情,然后选择替换图片。
- 选择与现有文件相同格式的非空图片。
- 查看警告,然后选择替换图片确认。
替换可以使用与现有图片不同的尺寸或宽高比。EmDash 保留媒体 ID、文件名、URL、替代文本、标题和位置,因此每个现有引用都使用替换。替换文件会清除其焦点。
替换图片从你的计算机上传另一个文件。要裁剪当前图片,从裁剪编辑器选择替换原始。
设置焦点
焦点在卡片、画廊或其他布局将本地图片裁剪为固定形状时,保持图片的重要部分可见。
- 打开媒体并从本地库中选择一张图片,或在内容编辑器中为本地图片选择编辑资产。
- 选择编辑图片,然后焦点。
- 点击或拖动标记到图片的重要部分。你也可以使用方向键。
- 检查方形、横向和纵向预览,然后选择保存。
选择重置以移除自定义焦点。保存的点在你为内容字段或画廊选择图片时被复制。已经使用该图片的其他内容保留其存储的点,直到你再次选择该图片。当你从内容字段或画廊编辑资产时,该当前使用以保存的焦点刷新。
裁剪图片
裁剪适用于上传到 EmDash 的 JPEG、PNG 和 WebP 图片。它适用于本地存储、Cloudflare R2 和 S3 兼容存储。外部媒体提供者的图片不能在媒体库中裁剪。
- 打开媒体,然后从本地库中选择一张图片。
- 选择编辑图片,然后裁剪。
- 选择原始、自由形式或常见宽高比。固定比例在调整大小时保持锁定。自由形式允许你独立更改宽度和高度。
- 在图片上移动裁剪框。对于固定比例,拖动角来调整大小。自由形式还提供四个边缘手柄。三分法网格保持可见。你可以聚焦框架或手柄并使用方向键。按住 Shift 进行更大的步幅。
- 选择裁剪操作之一:
- 创建裁剪副本创建一个单独的媒体项并保持原始不变。在你想使用它的每个内容条目中选择裁剪副本。
- 替换原始在媒体项使用的所有地方替换图片。现有内容条目保持相同的媒体引用,不会被重写或重新发布。
裁剪 WebP 文件会产生静态 WebP 图片。如果源是动画的,裁剪结果不保留动画。
在模板中显示媒体
从内容数据访问媒体 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 ?? ""}
/>
)}
响应式图片
对于 EmDash 媒体字段,使用 emdash/ui 的 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}
priority
/>
)}
priority 用于首屏主图。它设置 loading="eager" 和 fetchpriority="high":loading 控制是否延迟加载,fetchpriority 为浏览器提供请求优先级提示。
当字段值携带暗色对应版本时,Image 渲染两者并显示与访客颜色方案匹配的那个。暗色模式涵盖在字段上启用插槽以及组件依赖的 <html> 类约定。
EmDash 安装一个按需生成调整后变体的图片端点。在 Cloudflare Workers 上,该端点使用 IMAGES 绑定。图片变换涵盖绑定的来源以及缺失时的情况。
删除媒体
- 选择要删除的文件
- 点击删除
- 确认删除
媒体 API
使用 REST API 上传、列出、更新、删除和组织本地媒体。媒体端点参考记录了直接多部分上传和上传目标流程、请求参数、响应格式、权限和文件夹操作。
媒体提供者
除本地存储外,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({
mediaProviders: [
cloudflareImages({
accountId: import.meta.env.CF_ACCOUNT_ID,
apiToken: import.meta.env.CF_IMAGES_TOKEN,
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({
mediaProviders: [
cloudflareStream({
accountId: import.meta.env.CF_ACCOUNT_ID,
apiToken: import.meta.env.CF_STREAM_TOKEN,
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,
}),
],
}),
],
});
本地媒体库(“库”选项卡)始终与任何配置的提供者一起可用。
渲染提供者媒体
使用 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 变换)
文件值和当前元数据
文件字段存储引用和元数据快照。url、filename、mimeType 和 size 等缓存字段是可选的,因为持久化的值可能省略它们:
interface FileValue {
id: string;
url?: string;
src?: string;
filename?: string;
mimeType?: string;
size?: number;
provider?: string;
meta?: Record<string, unknown>;
}
getEmDashEntry() 和 getEmDashCollection() 返回此存储的值,无需额外的媒体查询。要获取当前元数据,请显式使用配置的提供者的 get() 方法。使用 getEmbed() 获取提供者特定的渲染 URL:
---
const file = post.data.attachment;
const provider = file
? Astro.locals.emdash?.getMediaProvider(file.provider ?? "local")
: undefined;
const current = file ? await provider?.get?.(file.id) : null;
const embed = file && provider ? await provider.getEmbed(file) : null;
---
经过身份验证的 HTTP 客户端可以通过 GET /_emdash/api/media/:id 查询本地媒体或通过 GET /_emdash/api/media/providers/:providerId/:itemId 查询其他提供者。
对于本地文件 URL,使用存储的 meta.storageKey 与公共 URL 助手。这尊重配置的 R2 或 S3 公共域,而无需查询媒体表:
---
const storageKey =
typeof file?.meta?.storageKey === "string" ? file.meta.storageKey : undefined;
const url = storageKey
? Astro.locals.emdash?.getPublicMediaUrl?.(storageKey)
: file?.src ?? file?.url;
---
提供者查找可能涉及网络或数据库工作。避免在未登录的集合页面上每个文件进行一次查找;除非请求需要最新的元数据,否则使用存储的快照和渲染组件。
MediaValue 类型
媒体字段存储包含提供者信息的 MediaValue 对象:
interface MediaValue {
provider?: string;
id: string;
src?: string;
previewUrl?: string;
filename?: string;
mimeType?: string;
width?: number;
height?: number;
focalX?: number;
focalY?: number;
alt?: string;
meta?: Record<string, unknown>;
}
这允许 EmDash 无论媒体托管在何处都能正确渲染。