媒体库

本页内容

EmDash 包含一个用于管理图片、文档和其他文件的媒体库。本指南涵盖在内容中上传、查找和使用媒体。

访问媒体库

在管理侧边栏中点击媒体打开媒体库。主库显示未分配到文件夹的文件夹和文件。打开文件夹查看其文件。

显示带上传按钮的图片网格的 EmDash 媒体库

使用位置

在 EmDash 的媒体库中打开一个文件,查看引用它的内容条目。在 EmDash 扫描现有内容期间,列表包含迄今找到的引用,可能不完整。

开启媒体使用跟踪

如果媒体使用跟踪已关闭,管理员可以开启它:

  1. 完成所有内容编辑。如果另一个应用程序直接写入内容数据库,请暂停它并等待进行中的写入完成。
  2. 打开设置 → 媒体使用跟踪,选择启用跟踪,然后确认。
  3. 当页面显示正在索引现有内容时,编辑和其他数据库写入可以恢复。
  4. 保持页面打开直到显示就绪。如果离开,返回以从保存的进度继续。

一旦开启媒体使用跟踪,就不能关闭。

上传文件

从媒体库

  1. 在管理侧边栏中打开媒体

  2. 选择上传文件,然后浏览文件选择一个或多个文件。你也可以将文件拖放到媒体库的任何位置。

  3. 上传自动开始。对话框显示每个文件的状态,并允许取消或重试单个文件。

从内容编辑器

  1. 在内容编辑器中打开图片、文件或画廊字段。

  2. 搜索、按类型过滤、浏览文件夹或在可用的媒体源之间切换。

  3. 选择现有媒体,或选择上传文件并从计算机中选择文件。你也可以将文件拖放到选择器上。每个上传都会以其当前状态出现在结果中。

  4. 如果上传失败,在该项目上选择重试删除。成功的上传变成一个已选媒体卡片。

  5. 对于画廊,使用已选媒体下的箭头控件设置返回顺序。

  6. 选择选择器操作,如选择插入图片添加 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 兼容服务。

上传的工作原理

管理界面使用上传目标流程

  1. 客户端请求上传目标,EmDash 创建一个待处理的媒体项。
  2. 客户端将文件上传到返回的目标。
  3. 客户端确认上传。
  4. EmDash 验证存储的文件并将媒体项标记为就绪。

S3 兼容存储返回签名 URL,以便文件可以绕过应用程序运行时。本地存储和原生 R2 返回同源流式端点。

查找媒体

搜索

使用搜索框按名称查找文件。搜索匹配部分文件名。

按类型过滤

使用类型过滤器显示图片、文档、视频或音频文件。

在文件夹中组织媒体

编辑者可以从主库选择添加新文件夹。选择文件夹名称打开文件夹。没有搜索词时,文件夹页面只显示分配给该文件夹的媒体。文件名搜索覆盖整个库,包括其他文件夹和主库。

要将本地文件移入可见文件夹,将其网格卡片或列表行拖到文件夹上。你也可以打开媒体详情,选择一个位置,然后选择保存。使用位置将文件返回到主库或不用拖动移动它。

作者可以移动他们上传的本地文件。编辑者可以移动任何本地文件。外部提供者的文件不能分配到文件夹。

上传进入主库。使用上述任一方法在上传后将它们移入文件夹。

删除文件夹将其媒体返回到主库。媒体文件、URL 和内容引用保持不变。

在内容中使用媒体

在富文本编辑器中

  1. 将光标放在你想要图片的位置
  2. 点击工具栏中的图片按钮
  3. 在选择器中找到图片或上传新的。
  4. 选择插入图片
  5. 在图片设置中添加替代文本。

作为特色图片

  1. 在编辑器中打开内容条目
  2. 在侧边栏中找到特色图片字段
  3. 点击选择图片
  4. 从选择器中选择图片或上传一个。
  5. 选择选择,然后保存

在自定义字段中

对于配置为图片或文件类型的字段,选择字段操作打开同样的媒体选择器。字段的 MIME 类型规则限制你可以选择的源和文件。

编辑选定的图片资产

本地图片字段、富文本图片和画廊图片提供三个操作:

  • 替换更改当前字段、块或画廊位置中使用的图片。
  • 编辑资产打开所选媒体库项目的媒体详情。你可以在内容编辑器中更新其替代文本、标题、焦点或裁剪。
  • 移除清除当前内容引用。媒体库项目仍然可用。

创建裁剪副本为当前使用选择新副本。富文本和画廊图片保留其每次使用的替代文本、标题、布局和位置。替换原始保持相同的媒体引用,并在该资产使用的所有地方更改图片。

外部提供者的图片和文件字段提供替换移除,但不提供编辑资产

替换图片

使用替换图片更新现有本地媒体项背后的文件。作者可以替换他们上传的图片,编辑者可以替换任何本地图片。此操作适用于存储在本地磁盘、Cloudflare R2 或 S3 兼容存储上的 JPEG、PNG 和 WebP 图片。

  1. 打开媒体,然后从本地库中选择一张图片。
  2. 留在详情,然后选择替换图片
  3. 选择与现有文件相同格式的非空图片。
  4. 查看警告,然后选择替换图片确认。

替换可以使用与现有图片不同的尺寸或宽高比。EmDash 保留媒体 ID、文件名、URL、替代文本、标题和位置,因此每个现有引用都使用替换。替换文件会清除其焦点。

替换图片从你的计算机上传另一个文件。要裁剪当前图片,从裁剪编辑器选择替换原始

设置焦点

焦点在卡片、画廊或其他布局将本地图片裁剪为固定形状时,保持图片的重要部分可见。

  1. 打开媒体并从本地库中选择一张图片,或在内容编辑器中为本地图片选择编辑资产
  2. 选择编辑图片,然后焦点
  3. 点击或拖动标记到图片的重要部分。你也可以使用方向键。
  4. 检查方形、横向和纵向预览,然后选择保存

选择重置以移除自定义焦点。保存的点在你为内容字段或画廊选择图片时被复制。已经使用该图片的其他内容保留其存储的点,直到你再次选择该图片。当你从内容字段或画廊编辑资产时,该当前使用以保存的焦点刷新。

裁剪图片

裁剪适用于上传到 EmDash 的 JPEG、PNG 和 WebP 图片。它适用于本地存储、Cloudflare R2 和 S3 兼容存储。外部媒体提供者的图片不能在媒体库中裁剪。

  1. 打开媒体,然后从本地库中选择一张图片。
  2. 选择编辑图片,然后裁剪
  3. 选择原始自由形式或常见宽高比。固定比例在调整大小时保持锁定。自由形式允许你独立更改宽度和高度。
  4. 在图片上移动裁剪框。对于固定比例,拖动角来调整大小。自由形式还提供四个边缘手柄。三分法网格保持可见。你可以聚焦框架或手柄并使用方向键。按住 Shift 进行更大的步幅。
  5. 选择裁剪操作之一:
    • 创建裁剪副本创建一个单独的媒体项并保持原始不变。在你想使用它的每个内容条目中选择裁剪副本。
    • 替换原始在媒体项使用的所有地方替换图片。现有内容条目保持相同的媒体引用,不会被重写或重新发布。

裁剪 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/uiImage 组件:

---
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 绑定。图片变换涵盖绑定的来源以及缺失时的情况。

删除媒体

  1. 选择要删除的文件
  2. 点击删除
  3. 确认删除

媒体 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 变换)

文件值和当前元数据

文件字段存储引用和元数据快照。urlfilenamemimeTypesize 等缓存字段是可选的,因为持久化的值可能省略它们:

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 无论媒体托管在何处都能正确渲染。

下一步