@adonis-agora/media

中文文档
0.28.2发布于 2026/11/02MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 1万

AdonisJS的媒体-图书馆——所有者收藏(MIME白名单、单文件替换、订购)、图像转换(eager/lazy)、可插件内容变压器(HLS视频通过Mediabunny、元数据探测器、图像模糊占位符)和列附件,a

中文使用文档
文档目录13 节
  1. 子路径导出
  2. 安装
  3. 配置
  4. 使用
  5. 变形器和视频流
  6. 反应图像( E) next/image - 风格)
  7. 授权( A) media.access (中文(简体) )
  8. 上传、S3和交付
  9. 盘子
  10. 诊断
  11. 测试
  12. 链接
  13. 许可证

@ados-agora/媒体

npm version npm downloads CI license

媒体图书馆 阿多尼斯·贾克,该部分 阿戈拉语Name 生态系统——生态系统 spa/lar-媒体-图书馆的感觉,上方 @adonisjs/drive。 。 。 .

将文件附加到实体,将它们组织到收藏中(MIME 白名单,单文件替换, 命令),生成图像转换(eager或懒惰)——加 内容变压器,同样的 图像外接: 捆绑 transformers.video() 用于 HLS/DASH 流媒体和 transformers.probe() 记录持续时间/编码c作为元数据,两者保持不变 record.conversions 地图。 存储完全委托给驱动器,所以您重新使用您的已有 local 编号 : s3 编号 : gcs 磁盘——这个软件包从不重新执行磁盘驱动程序.

这是 核心图书馆数字 : MediaLibrary, (中文(简体) ), AttachmentManager,则 MediaStore SPI(记忆中+) 卢西德,那个 ImageProcessor SPI (正), 缩写 Transformer SPI (HLS 视频包装+元数据) 探测器,捆绑 disks.s3() 驱动程序、代理/直接/可恢复的上传、可配置交付、 提供者 + defineConfig还有一个测试工具箱 管理层 装有控制台的船 - 登记 @adonis-agora/media/dashboard_provider 这都是消耗 应用程序需求(参见 盘子 ;没有单独的安装。 说对了 @adonis-agora/media-react 用于浏览器上传客户端.

子路径导出

软件包使用 子路径导出 (Agora idom),如此重的后端保持可选性:

子路径什麽
@adonis-agora/media枪管- defineConfig, (中文(简体) ), stores, (中文(简体) ), processors, (中文(简体) ), disks, (中文(简体) ), uploadSessions, (中文(简体) ), MediaManager, (中文(简体) ), MediaLibrary, (中文(简体) ), AttachmentManager, (中文(简体) ), UploadManager, (中文(简体) ), ResumableUploadManager, (中文(简体) ), MediaDeliveryHandler, SPIs, 错误
@adonis-agora/media/services/main应用 MediaManager 单吨- import media from '@adonis-agora/media/services/main',随时可以导入(在首次使用时可以懒散解决)
@adonis-agora/media/media_provider服务提供方(宾站) MediaManager,挂载可选上传/TUS路由)
@adonis-agora/media/dashboard_provider嵌入式管理控制台提供者( React SPA + JSON API)
@adonis-agora/media/dashboarddefineConfig + 类型 config/media_dashboard.ts, (中文(简体) ), DashboardService会场的助手们, ObjectInsightProvider
@adonis-agora/media/configurenode ace configure 钩子
@adonis-agora/media/single-filestoreSingleFile 编号 : removeSingleFile 编号 : storeSingleFileWith 编号 : removeSingleFileWith 编号 : isSingleFileStoreAvailable ——让其他软件包代表单文件上传(如:相机)到媒体,而不依赖硬性
@adonis-agora/media/stores/lucid卢西德 MediaStore (单位:千美元)@adonisjs/lucid 端点)
@adonis-agora/media/upload_sessions/lucid卢西德号可续航 UploadSessionStore (单位:千美元)@adonisjs/lucid 端点)
@adonis-agora/media/disks/s3捆绑 S3Disk (单位:千美元)@aws-sdk/client-s3 端点; 预签为手卷 SigV4
@adonis-agora/media/processors/sharp锋利 ImageProcessor (单位:千美元)sharp 端点)
@adonis-agora/media/telescopemediaTelescopeExtension (单位:千美元)@adonis-agora/telescope 可选对等点)
@adonis-agora/media/testingInMemoryMediaStore, (中文(简体) ), InMemoryDisk, (中文(简体) ), inMemoryDiskResolver, (中文(简体) ), FakeImageProcessor, (中文(简体) ), InMemoryUploadSessionStore
@adonis-agora/media/types结构 Disk 编号 : DiskResolver 编号 : ExtendedDisk 编号 : MultipartUploadDisk 合同

安装

node ace add @adonisjs/drive   # storage backend (required)
npm i @adonis-agora/media
node ace configure @adonis-agora/media

configure 注册媒体提供者 和仪表板供应商,发表 config/media.ts 财务报告和审定财务报表 config/media_dashboard.ts,并出版 两个 移徙—— media 表格 lucid 存储和会话表 lucid 上传会话商店. 删除不需要的 等同物不需要表格; 否则 node ace migration:run。管理控制台是 住在这里 /media/dashboard 当你的应用靴子 —— 看 盘子。 。 。 .

所需对等方 : @adonisjs/core (单位:千美元)^7.3.0和 @adonisjs/drive —— 说 无论是主要, (中文(简体) ), ^3.0.0 或者说 ^4.0.0。 。 。 .

可选同伴, 仅在选中时懒惰地加载 :

  • @adonisjs/lucid (单位:千美元)^22.4.0()—— lucid MediaStore 编号 : UploadSessionStore
  • sharp (单位:千美元)^0.33.0)——图像转换
  • @aws-sdk/client-s3 (单位:千美元)^3.0.0)——捆绑 disks.s3() 驱动程序( 已签名的 URL 是手卷 SigV4, 没有预签名包)
  • @adonis-agora/telescope (单位:千美元)^0.4.0——望远镜监视器扩展

配置

// config/media.ts
import { defineConfig, stores, processors } from '@adonis-agora/media'

export default defineConfig({
  // disk: 's3',                 // omit to use Drive's default disk
  store: 'lucid',
  stores: {
    memory: stores.memory(),
    lucid: stores.lucid({ connection: 'pg' }),
  },
  imageProcessor: processors.sharp(),
  collections: [
    { name: 'avatar', single: true, acceptsMimeTypes: ['image/png', 'image/jpeg'] },
    {
      name: 'gallery',
      conversions: [
        { name: 'thumb', width: 200, height: 200 },
        { name: 'og', width: 1200, eager: true },
      ],
    },
  ],
})

使用

提供方绑定单通 MediaManager;通过服务导入(或) @inject() ) (中文(简体) ). 一个真正的上传控制器加载所有者,验证文件,并将其 tmp 字节流入一个 收藏库 :

// app/controllers/post_images_controller.ts
import { createReadStream } from 'node:fs'
import Post from '#models/post'
import media from '@adonis-agora/media/services/main'
import type { HttpContext } from '@adonisjs/core/http'

export default class PostImagesController {
  async store({ request, response, params }: HttpContext) {
    const post = await Post.findOrFail(params.id)

    const image = request.file('image', { size: '5mb', extnames: ['jpg', 'png', 'webp'] })
    if (!image) return response.badRequest({ error: 'An "image" file is required' })

    const record = await media.library.attach({
      ownerType: 'Post',
      ownerId: post.id, // string | number — coerced for you
      collection: 'gallery',
      fileName: image.clientName,
      mimeType: image.type!,
      contents: createReadStream(image.tmpPath!), // Buffer | Readable
    })

    return response.created({ id: record.id, url: await media.library.url(record.id) })
  }
}

阅读、列出和删除都经过同样的过程 media 单通 :

await media.library.url(record.id)            // public url of the original
await media.library.url(record.id, 'thumb')   // generated lazily on first call, then cached
await media.library.list('Post', post.id, 'gallery')
await media.library.delete(record.id)

// Or bind an owner once for a bulk upload
const gallery = media.library.for('Post', post.id)
await gallery.attach({ collection: 'gallery', fileName: image.clientName, mimeType: image.type!, contents })

// Column attachments (adonis-attachment style) — store the value object on a JSON column
const att = await media.attachments.createFromFile(
  { fileName: image.clientName, mimeType: image.type!, contents },
  { variants: [{ name: 'thumb', width: 100 }] },
)
user.avatarData = att.toJSON()
await media.attachments.url(att, 'thumb')

A 类 ConversionPreset 实值 { name, width?, height?, fit?, format?, quality?, eager? }。 Eager 预设为 同步生成 attach其它的都是懒散的 url(id, name) 财务报告和审定财务报表 被隐藏在记录. fit 财务报告和审定财务报表 format 地图直指尖端.

变形器和视频流

图像转换回答"相同的图像,大小不同". 变形器 回答其他问题: 将此内容转换为。变压器取出存储的媒体字节并生成许多 文件(一个视频包),一个文件(一个已提取的音频音轨),或者根本没有(一个元数据探测器)—— 坚持不变 record.conversions 地图,所以预设和变压器共享一个命名空间 每个收藏.

带包裹的两艘飞船,都放在可选位置上 mediabunny 端点( 纯类型脚本 -) 无ffmpeg 二进制),在第一个输入的懒散 transform() 电话 :

// config/media.ts
import { defineConfig, transformers } from '@adonis-agora/media'

export default defineConfig({
  collections: [
    {
      name: 'videos',
      acceptsMimeTypes: ['video/mp4'],
      transformers: [
        transformers.video(),                // CMAF segments + an HLS master + a DASH manifest
        transformers.probe({ eager: true }),     // duration / resolution / codecs, no artifact
      ],
    },
  ],
})

变形被假定为很重,所以除非你标出,否则任何动静都不能运行 eager触发 1 从你的工作 - transform(id, name) 具有一能性,所以重试直接跳过:

await media.library.transform(mediaId, 'video')

transformers.video() 写入 CMAF 中标 默认的段, HLS 和 DASH 都播放, 所以一个副本 视频的两张名单. segments: 'ts' 为旧玩家撰写 MPEG- TS 上的 HLS,以及 engine: engines.ffmpeg({ ladder }) 用 ffmpeg 系统转码为 ABR 梯子。 服务于 软件包中有一个路由,可以授权每个显示和分区请求与 收藏库 access.read数字 :

router.get('/media/:id/stream/:conversion/*', media.access.streamRoute())
const video = await media.access.stream(ctx, mediaId) // manifest URLs for the player

与 delivery.signing,则整个软件包的URL签名,所以片段请求带有 授权随行,签名比视频有效。 写入自己的变压器是一个接口( Namename + 键 transform(context)(三); 上下文将记录交给你 原作的字节/流 和一个沙盒 write() 键 每个在转换前缀下的文物.

反应图像( E)next/image- 风格)

media.library.image(id) 返回全部为 <img> 需要作为简单的JSON: src页:1 srcSet 已建成 从收藏的同相图预设,内在 width编号 :height,模糊起来 placeholder 编辑 focalPoint把它变成 <MediaImage> 从 @adonis-agora/media-react这是一个 <img> 与懒惰的载荷, priority, (中文(简体) ), fill页:1 layout 计算 sizes,其后面的模糊预览直到装入为止.

// config/media.ts — presets at standard widths + the placeholder, from one flag
{ name: 'banner', responsive: true, stripMetadata: true }

// controller
return inertia.render('courses/show', { banner: await media.library.image(course.bannerMediaId) })
<MediaImage image={banner} alt={course.title} layout="constrained" priority />

更多图像侧:

  • 联络点: media.library.setFocalPoint(id, { x, y }) 使每个作物都保留这个部分 object-fit: cover 在浏览器中。 预设也要 position: 'attention'。 。 。 .
  • 艺术方向 : image(id, { conversions: [...] }) 返回组合,该组合 <MediaPicture> 在屏幕上互换.
  • 点播调整大小 : 运送路线 ?w=640,调整一次并缓存为WebP(或AVIF,当你选择加入时),取决于 Accept。只提供白色的宽度,除非 URL 签名.
  • 已签名的 URL : 与 delivery.signing, (中文(简体) ), media.library.deliveryUrl() 财务报告和审定财务报表 image() 发送签名, 过期 URL, 而路由没有其他服务 .
  • stripMetadata: true数字 : 从上传的原件中删除GPS,相机和时间戳.

授权( A)media.access(中文(简体) )

图书馆从不决定谁可以看文件,但它为你应用了你的规则. 你个 声明每个收藏中谁可以阅读和上传,并告知当前用户是谁(authkit, @adonisjs/auth 或自用,或自用,或自用,或自用,或自用

import { authorizers } from '@adonis-agora/media'
import { authkitIdentity } from '@adonis-agora/media/authkit'
import { authz } from '@adonis-agora/media/authz'

defineConfig({
  access: { identity: authkitIdentity() },
  collections: [
    { name: 'avatar', access: { read: authorizers.owner(), write: authorizers.authenticated() } },
    { name: 'reports', access: { read: authz.can('reports.read') } },
  ],
})

const serveMedia = media.access.deliveryRoute()          // build once, at route definition
router.get('/media/:id', serveMedia)                      // 401/403/404/400 handled
const banner = await media.access.image(ctx, id)                       // authorized descriptor

@adonis-agora/media/authkit 财务报告和审定财务报表 @adonis-agora/media/authz 仅在使用时装入他们的包. 两者都是可选的同龄人.

上传、S3和交付

大文件上传了三道花的飞船—— 代理服务器 (字节流出你的应用程序), 直接S3级 多块 (浏览器通过预先签名的部分URL直接上传到桶上),并 暂存 s 会话(可插入内存+ Lucid会话存储). 打开下面 uploads 内 config/media.ts; 供应商将路线挂起 /media/uploads 财务报告和审定财务报表 /media/uploads/tus。 。 。 .

export default defineConfig({
  // ...
  uploads: {
    mode: 'auto', // 'direct' | 'proxy' | 'auto'
    routes: { enabled: true },
    resumable: { routes: { enabled: true } },
  },
  delivery: { mode: 'auto' }, // 'public' | 'signed' | 'proxy' | 'auto'
})

delivery 读侧对等器为 uploads.mode数字 : MediaLibrary.deliver(id, options?) 决心成立受歧视的工会—— { kind: 'redirect', url } 页:1 public编号 :signed,或 { kind: 'stream', stream, mimeType, size, fileName } 页:1 proxy 所以,一个私人桶不需要 手卷出流道. MediaDeliveryHandler 财务报告和审定财务报表 TusUploadHandler 框架不可知性 路径将您的应用程序与它的中间软件相接; 既不执行授权 - 守卫 呼叫前的路径 handle。 。 。 .

同一送货路线根据需要调整大小(delivery.handle({ mediaId, width: qs.w, quality: qs.q, accept })) (中文(简体) ). 只有宽度 delivery.images.widths 除非请求被签名,否则 谈判 AVIF/WebP 来自 Accept与 delivery.signing (单位:千美元){ secret, expiresIn }),它只服务于 由 : media.library.deliveryUrl() 或者说 image(),直到他们过期.

捆绑起来 disks.s3() 驱动程序添加扩展操作(复制/移动/删除Mny/list/size/stat)和 本地多段, 相对于可选的 AWS SDK 端点 。 用浏览器驱动它 @adonis-agora/media-react。 。 。 .

盘子

一个管理控制台——浏览桶,监视正在更新的上传,上传对象,以及 复制/移动/取出横跨桶-船只 内嵌 在此包中:注册 @adonis-agora/media/dashboard_provider (自动由 node ace configure这一切都是一个 消费应用需求. 不单独安装软件包,不单独注册供应商.

// adonisrc.ts
providers: [
  () => import('@adonis-agora/media/media_provider'),
  () => import('@adonis-agora/media/dashboard_provider'),
]
// config/media_dashboard.ts
import { defineConfig } from '@adonis-agora/media/dashboard'
import { middleware } from '#start/kernel'

export default defineConfig({
  basePath: '/media/dashboard',   // where the SPA mounts (default)
  actions: true,                  // enable copy/move/delete (default: false — read-only)
  disks: ['s3', 'backups'],       // browsable disks (default: derived from media config)
  middleware: middleware.auth(),  // gate the whole console — SPA + API
})

控制台读取/写出真实 @adonis-agora/media 表面( 磁盘) list编号 :stat编号 :copy编号 :move编号 :deleteMany,可恢复的会话商店 MediaStore)——无 关于存储被重新执行。 完整配置引用、路径和文件夹操作语义 记录 @adonis-agora/media-dashboard, (中文(简体) ), 现在 构建时间源 用于控制台的 SPA 捆绑(安装时装在这里)和 仍可安装 独立 ——它自己的提供商是本作的瘦子代表,为主机保管 它已经直接注册。 不要在同一个应用程序中注册两个供应商.

诊断

所有九起生命周期事件—— attach, (中文(简体) ), delete, (中文(简体) ), conversion, (中文(简体) ), attachment.create, (中文(简体) ), attachment.delete, (中文(简体) ), upload.start, (中文(简体) ), upload.progress, (中文(简体) ), upload.complete, (中文(简体) ), upload.abort - 已经 发射在 agora:media:* 通过 @agora/diagnostics:emit 全球时段——读取 结构,与 无硬依赖 打开 @adonis-agora/diagnostics当包裹不是时 已安装,排放是惰性不开放;当是时,望远镜通用监视器(或 @adonis-agora/media/telescope)自动捕捉出每个媒体事件.

测试

@adonis-agora/media/testing 用于 SPIs 的双相轮船, 这样您就可以练习库 没有磁盘、数据库或锐口:

import { MediaLibrary, StorageManager } from '@adonis-agora/media'
import { InMemoryMediaStore, inMemoryDiskResolver, FakeImageProcessor } from '@adonis-agora/media/testing'

const { resolve, disks } = inMemoryDiskResolver(['fs'])
const library = new MediaLibrary({
  storage: new StorageManager({ default: 'fs', resolve }),
  store: new InMemoryMediaStore(),
  imageProcessor: new FakeImageProcessor(),
})

在真正的应用程序中,你也可以 drive.fake() 从 @adonisjs/drive 在磁盘后加内存 假的,同时保持其余的线条完好无损.

许可证

麻省理工学院

版本与发布记录

@adonis-agora/media 共发布 49 个版本,首次发布于 2026/06/24;过去 12 个月发布了 49 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.28.2latest2026/11/023 天前
0.28.12026/10/289 天前
0.28.02026/10/289 天前
0.27.02026/10/2710 天前
0.26.22026/10/2412 天前
0.26.12026/10/2412 天前

关于 @adonis-agora/media 的常见问题

@adonis-agora/media 是什么?

AdonisJS的媒体-图书馆——所有者收藏(MIME白名单、单文件替换、订购)、图像转换(eager/lazy)、可插件内容变压器(HLS视频通过Mediabunny、元数据探测器、图像模糊占位符)和列附件,a

如何安装 @adonis-agora/media?

在项目目录运行 npm install @adonis-agora/media,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@adonisjs/core(^7.3.0)、@adonisjs/drive(^3.0.0 || ^4.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@adonis-agora/media 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@adonis-agora/media 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@adonis-agora/media 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@adonis-agora/media 可以商用吗?

@adonis-agora/media 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@adonis-agora/media 的下载量有多少?

根据 npm 官方下载统计,@adonis-agora/media 在 2026/10/05 – 2026/11/03 这 30 天内被下载 10,081 次,日均约 336 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@adonis-agora/media 还在维护吗?

最新版本 0.28.2 发布于 2026/11/02(3 天前);至今共发布 49 个版本,其中过去 12 个月发布了 49 个;首次发布于 2026/06/24。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。