媒體庫

本頁內容

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 都能正確呈現。

下一步