媒体库

本页内容

EmDash 提供媒体库,用于管理图片、文档等文件。本指南介绍上传、整理以及在内容中使用媒体。

打开媒体库

在管理侧栏点击 Media 即可打开。库中列出所有已上传文件,含预览、文件名与上传时间。

EmDash 媒体库,图片网格与上传按钮

上传文件

在媒体库中

  1. 在管理侧栏点击 Media

  2. 点击 Upload 或将文件拖入上传区域

  3. 在电脑中选择一个或多个文件

  4. 等待上传完成

在内容编辑器中

  1. 在富文本编辑器中点击图片按钮

  2. 在媒体选择器中点击 Upload

  3. 选择本地文件

  4. 填写替代文本后点击 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 实现安全上传:

  1. 客户端向 API 请求上传 URL

  2. 服务器生成带过期时间的签名 URL

  3. 客户端通过该 URL 直传存储

  4. 服务器将文件元数据写入数据库

大文件不经过应用服务器,可直接上传到云存储。

整理媒体

文件夹

可创建文件夹分类:

  1. 在媒体库中点击 New Folder

  2. 输入文件夹名

  3. 点击 Create

  4. 将文件拖入文件夹

搜索

在搜索框按文件名查找,支持部分匹配。

筛选

可按以下条件筛选:

  • Type — 图片、文档、视频、音频
  • Date — 上传日期范围
  • Folder — 指定文件夹

在内容中使用媒体

在富文本编辑器中

  1. 将光标放在需要插入图片的位置

  2. 点击工具栏图片按钮

  3. 从媒体库选择或上传新图片

  4. 填写替代文本

  5. 点击 Insert

作为特色图片

  1. 在编辑器中打开内容条目

  2. 在侧栏找到 Featured Image 字段

  3. 点击 Select Image

  4. 从媒体库选择或上传

  5. 点击 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}
  />
)}

删除媒体

  1. 选中要删除的文件

  2. 点击 Delete

  3. 确认删除

媒体 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 都能正确渲染。

下一步