@file-ud.js/plugins 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +583 -0
- package/dist/downloader/index.d.mts +2 -0
- package/dist/downloader/index.d.ts +2 -0
- package/dist/downloader/index.js +126 -0
- package/dist/downloader/index.js.map +1 -0
- package/dist/downloader/index.mjs +124 -0
- package/dist/downloader/index.mjs.map +1 -0
- package/dist/index-CVuMEvjg.d.ts +201 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +781 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +773 -0
- package/dist/index.mjs.map +1 -0
- package/dist/retry/index.d.mts +84 -0
- package/dist/retry/index.d.ts +84 -0
- package/dist/retry/index.js +126 -0
- package/dist/retry/index.js.map +1 -0
- package/dist/retry/index.mjs +124 -0
- package/dist/retry/index.mjs.map +1 -0
- package/dist/uploader/index.d.mts +2 -0
- package/dist/uploader/index.d.ts +2 -0
- package/dist/uploader/index.js +658 -0
- package/dist/uploader/index.js.map +1 -0
- package/dist/uploader/index.mjs +652 -0
- package/dist/uploader/index.mjs.map +1 -0
- package/package.json +78 -0
- package/src/uploader/compress/README.md +388 -0
- package/src/uploader/validator/README.md +563 -0
- package/src/uploader/watermark/README.md +498 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/uploader/compress/compress-image-plugin.ts","../../src/base-plugin.ts","../../src/uploader/watermark/watermark-plugin.ts","../../src/uploader/validator/file-validator-plugin.ts","../../src/uploader/validator/image-validator-plugin.ts","../../src/uploader/validator/video-validator-plugin.ts"],"names":["formatFileSize","FileUDError","ErrorCode"],"mappings":"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","sourcesContent":["// plugins/compress.plugin.ts\n\nimport {\n UploadFile,\n formatFileSize,\n type PluginContext,\n} from \"@file-ud.js/core\";\nimport { BasePlugin } from \"../../base-plugin\";\nexport interface ImageCompressPluginOptions {\n /** 压缩质量 (0-1) */\n quality?: number;\n /** 最大宽度 (px) */\n maxWidth?: number;\n /** 最大高度 (px) */\n maxHeight?: number;\n /** 输出格式 */\n format?: \"jpeg\" | \"png\" | \"webp\";\n /** 是否显示压缩信息 */\n showInfo?: boolean;\n /** 压缩开始时触发 */\n onCompressStart?: (file: UploadFile) => void;\n /** 压缩完成时触发 */\n onCompressComplete?: (file: UploadFile, compressedFile: File) => void;\n}\n\nexport class CompressImagePlugin extends BasePlugin {\n name = \"compress-image-plugin\";\n priority = 10;\n desc = \"图片压缩插件\";\n options: Required<ImageCompressPluginOptions>;\n private defaultOptions: Required<ImageCompressPluginOptions> = {\n quality: 0.8,\n maxWidth: 1920,\n maxHeight: 1080,\n format: \"jpeg\",\n showInfo: true,\n onCompressStart: function (file: UploadFile): void {\n throw new Error(\"Function not implemented.\");\n },\n onCompressComplete: function (\n file: UploadFile,\n compressedFile: File,\n ): void {\n throw new Error(\"Function not implemented.\");\n },\n };\n\n constructor(options: ImageCompressPluginOptions = {}) {\n super();\n this.options = { ...this.defaultOptions, ...options };\n }\n\n async onFileSelect(\n uploadFile: UploadFile,\n context: PluginContext<UploadFile>,\n ): Promise<UploadFile | void> {\n // 只处理图片\n if (!uploadFile.File.type.startsWith(\"image/\")) {\n return uploadFile;\n }\n\n const originalSize = uploadFile.File.size;\n\n try {\n this.options.onCompressStart?.(uploadFile);\n const compressedFile = await this.compressImage(uploadFile.File);\n const compressedSize = compressedFile.size;\n const ratio = (\n ((originalSize - compressedSize) / originalSize) *\n 100\n ).toFixed(1);\n\n if (this.options.showInfo) {\n console.log(\n `📸 压缩完成: ${uploadFile.fileName} | ${formatFileSize(originalSize)} → ${formatFileSize(compressedSize)} (减少 ${ratio}%)`,\n );\n }\n\n uploadFile.proxy.File = compressedFile;\n this.options.onCompressComplete?.(uploadFile, compressedFile);\n uploadFile.proxy.formatSize = formatFileSize(compressedSize);\n return uploadFile;\n } catch (error) {\n console.error(`压缩失败: ${uploadFile.fileName}`, error);\n return uploadFile; // 返回原文件\n }\n }\n\n private compressImage(file: File): Promise<File> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const url = URL.createObjectURL(file);\n\n img.onload = () => {\n URL.revokeObjectURL(url);\n\n // 计算压缩尺寸\n let { width, height } = img;\n if (width > this.options.maxWidth) {\n height = Math.floor(height * (this.options.maxWidth / width));\n width = this.options.maxWidth;\n }\n if (height > this.options.maxHeight) {\n width = Math.floor(width * (this.options.maxHeight / height));\n height = this.options.maxHeight;\n }\n\n // 创建 Canvas\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"无法创建 Canvas 上下文\"));\n return;\n }\n\n ctx.drawImage(img, 0, 0, width, height);\n\n // 转换为 Blob\n canvas.toBlob(\n (blob) => {\n if (blob) {\n const compressedFile = new File(\n [blob],\n file.name.replace(/\\.\\w+$/, `.${this.options.format}`),\n { type: `image/${this.options.format}` },\n );\n resolve(compressedFile);\n } else {\n reject(new Error(\"压缩失败\"));\n }\n },\n `image/${this.options.format}`,\n this.options.quality,\n );\n };\n\n img.onerror = () => reject(new Error(\"图片加载失败\"));\n img.src = url;\n });\n }\n}\n","import {\n UploadFile,\n FileUDError,\n ErrorCode,\n type IUDPlugin,\n type PluginContext,\n} from \"@file-ud.js/core\";\n/**\n * 插件基类\n * 提供通用的错误处理和日志功能\n */\nexport abstract class BasePlugin implements IUDPlugin<UploadFile> {\n /** 插件名称 */\n abstract name: string;\n \n /** 插件版本 */\n version = \"1.0.0\";\n \n /** 插件优先级 */\n priority = 0;\n \n /** 是否关键插件 */\n critical = false;\n \n /** 插件描述 */\n desc = \"\";\n\n /**\n * 安装插件 - 统一日志输出\n */\n install(transfer: any): void {\n console.log(`${this.name} ✅ 插件已安装`);\n }\n\n /**\n * 创建基础错误对象\n * @param file - 当前文件\n * @param uploader - 上传器实例\n * @returns 基础错误对象\n */\n protected createBaseError(file: UploadFile, uploader: any): FileUDError {\n return new FileUDError(\n ErrorCode.UNKNOWN,\n \"\",\n {\n uploader,\n plugin: this.name,\n fileName: file.fileName,\n fileSize: file.File.size,\n fileType: file.File.type,\n },\n );\n }\n\n /**\n * 抛出验证错误\n * @param error - 错误对象\n * @returns Promise.reject\n */\n protected throwError(error: FileUDError): Promise<never> {\n return Promise.reject(error);\n }\n\n /**\n * 文件选择时的验证逻辑(由子类实现)\n */\n abstract onFileSelect(\n file: UploadFile,\n context: PluginContext<UploadFile>,\n ): Promise<UploadFile | void>;\n\n /**\n * 销毁插件\n */\n destroy?(): void {\n console.log(`${this.name} 🔒 插件已销毁`);\n }\n}\n","// plugins/watermark/watermark-plugin.ts\nimport {\n UploadFile,\n formatFileSize,\n type PluginContext,\n} from \"@file-ud.js/core\";\nimport { BasePlugin } from \"../../base-plugin\";\nexport interface WatermarkPluginOptions {\n /** 水印文字 */\n text?: string;\n /** 水印图片URL */\n imageUrl?: string;\n /** 位置 */\n position?:\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"center\";\n /** 透明度 (0-1) */\n opacity?: number;\n /** 字体大小 */\n fontSize?: number;\n /** 字体颜色 */\n color?: string;\n /** 边距 */\n padding?: number;\n /** 水印图片宽度(可选) */\n imageWidth?: number;\n /** 水印图片高度(可选) */\n imageHeight?: number;\n}\n\nexport class WatermarkPlugin extends BasePlugin {\n name = \"watermark-plugin\";\n priority = 20;\n desc = \"水印插件(支持文字/图片水印)\";\n options: Required<WatermarkPluginOptions>;\n\n private defaultOptions: Required<WatermarkPluginOptions> = {\n text: \"© FileUD\",\n imageUrl: \"\",\n position: \"bottom-right\",\n opacity: 0.6,\n fontSize: 24,\n color: \"#ffffff\",\n padding: 20,\n imageWidth: 100,\n imageHeight: 100,\n };\n\n constructor(options: Partial<WatermarkPluginOptions> = {}) {\n super();\n this.options = { ...this.defaultOptions, ...options };\n }\n\n async onFileSelect(\n file: UploadFile,\n context: PluginContext<UploadFile>,\n ): Promise<UploadFile | void> {\n // 只处理图片\n if (!file.File.type.startsWith(\"image/\")) {\n return file;\n }\n\n try {\n const watermarkedFile = await this.addWatermark(file.File);\n\n file.proxy.File = watermarkedFile;\n file.proxy.formatSize = formatFileSize(watermarkedFile.size);\n\n console.log(`💧 水印已添加: ${file.fileName}`);\n return file;\n } catch (error) {\n console.error(`水印添加失败: ${file.fileName}`, error);\n return file;\n }\n }\n\n private addWatermark(file: File): Promise<File> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const url = URL.createObjectURL(file);\n\n img.onload = () => {\n URL.revokeObjectURL(url);\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = img.width;\n canvas.height = img.height;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"无法创建 Canvas 上下文\"));\n return;\n }\n\n // 绘制原图\n ctx.drawImage(img, 0, 0);\n ctx.globalAlpha = this.options.opacity;\n\n // ✅ 根据是否有 imageUrl 选择水印类型\n if (this.options.imageUrl) {\n // ========== 图片水印 ==========\n this.addImageWatermark(ctx, canvas, resolve, reject, file);\n } else if (this.options.text) {\n // ========== 文字水印 ==========\n this.addTextWatermark(ctx, canvas, resolve, reject, file);\n }\n };\n\n img.onerror = () => reject(new Error(\"图片加载失败\"));\n img.src = url;\n });\n }\n\n /**\n * 添加文字水印\n */\n private addTextWatermark(\n ctx: CanvasRenderingContext2D,\n canvas: HTMLCanvasElement,\n resolve: (value: File) => void,\n reject: (reason: Error) => void,\n originalFile: File,\n ) {\n // 设置文字样式\n ctx.font = `${this.options.fontSize}px Arial`;\n ctx.fillStyle = this.options.color;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n\n const text = this.options.text;\n const textWidth = ctx.measureText(text).width;\n const padding = this.options.padding;\n\n // 计算位置(传入 padding 参数)\n const { x, y } = this.calculatePosition(\n ctx,\n canvas,\n textWidth,\n this.options.fontSize,\n padding,\n );\n\n // 绘制文字水印\n ctx.fillText(text, x, y);\n\n // 转换为文件\n canvas.toBlob((blob) => {\n if (blob) {\n const watermarkedFile = new File([blob], originalFile.name, {\n type: originalFile.type,\n });\n resolve(watermarkedFile);\n } else {\n reject(new Error(\"水印添加失败\"));\n }\n }, originalFile.type);\n }\n\n /**\n * 添加图片水印\n */\n private addImageWatermark(\n ctx: CanvasRenderingContext2D,\n canvas: HTMLCanvasElement,\n resolve: (value: File) => void,\n reject: (reason: Error) => void,\n originalFile: File,\n ) {\n const watermarkImg = new Image();\n watermarkImg.crossOrigin = \"Anonymous\"; // 处理跨域\n\n watermarkImg.onload = () => {\n // 计算水印图片尺寸\n let drawWidth = this.options.imageWidth;\n let drawHeight = this.options.imageHeight;\n\n // 如果没指定尺寸,使用原图尺寸\n if (!drawWidth && !drawHeight) {\n drawWidth = watermarkImg.width;\n drawHeight = watermarkImg.height;\n } else if (drawWidth && !drawHeight) {\n drawHeight = (watermarkImg.height / watermarkImg.width) * drawWidth;\n } else if (!drawWidth && drawHeight) {\n drawWidth = (watermarkImg.width / watermarkImg.height) * drawHeight;\n }\n\n const padding = this.options.padding;\n\n // 计算位置(传入 padding 参数)\n const { x, y } = this.calculatePosition(\n ctx,\n canvas,\n drawWidth,\n drawHeight,\n padding,\n );\n\n // 绘制图片水印\n ctx.drawImage(watermarkImg, x, y, drawWidth, drawHeight);\n\n // 转换为文件\n canvas.toBlob((blob) => {\n if (blob) {\n const watermarkedFile = new File([blob], originalFile.name, {\n type: originalFile.type,\n });\n resolve(watermarkedFile);\n } else {\n reject(new Error(\"水印添加失败\"));\n }\n }, originalFile.type);\n };\n\n watermarkImg.onerror = () => {\n reject(new Error(\"水印图片加载失败\"));\n };\n\n watermarkImg.src = this.options.imageUrl;\n }\n\n /**\n * 计算水印位置\n */\n private calculatePosition(\n ctx: CanvasRenderingContext2D,\n canvas: HTMLCanvasElement,\n width: number,\n height: number,\n padding?: number,\n ): { x: number; y: number } {\n const pad = padding ?? this.options.padding;\n let x: number, y: number;\n\n switch (this.options.position) {\n case \"top-left\":\n x = pad;\n y = pad;\n break;\n case \"top-right\":\n x = canvas.width - width - pad;\n y = pad;\n break;\n case \"bottom-left\":\n x = pad;\n y = canvas.height - height - pad;\n break;\n case \"bottom-right\":\n x = canvas.width - width - pad;\n y = canvas.height - height - pad;\n break;\n default: // center\n x = (canvas.width - width) / 2;\n y = (canvas.height - height) / 2;\n }\n\n return { x, y };\n }\n}\n","import {\n UploadFile,\n FileUDError,\n ErrorCode,\n Uploader,\n formatFileSize,\n validator,\n type UploaderConfig,\n type PluginContext,\n} from \"@file-ud.js/core\";\nimport { BasePlugin } from \"../../base-plugin\";\nexport interface FileValidatorPluginOptions {\n /** 最大文件大小 (字节) */\n maxSize?: number;\n /** 最小文件大小 (字节) */\n minSize?: number;\n /** 允许的文件类型 (MIME类型或扩展名) */\n accept?: UploaderConfig[\"accept\"];\n /** 是否允许空文件 */\n allowEmpty?: boolean;\n /** 自定义验证函数 */\n customValidate?: (\n file: File,\n error: typeof FileUDError,\n ) => boolean | Promise<boolean>;\n /** 错误消息定制 */\n messages?: {\n maxSize?: (max: number, current: number) => string;\n minSize?: (min: number, current: number) => string;\n accept?: (accept: string[], fileName: string) => string;\n // maxFiles?: (max: number) => string;\n // minFiles?: (min: number) => string;\n empty?: () => string;\n custom?: (fileName: string) => string;\n };\n}\n\nexport class FileValidatorPlugin extends BasePlugin {\n name = \"file-validator-plugin\";\n priority = 0; // 最先执行\n critical = true;\n desc = \"基础验证插件(大小、类型、数量)\";\n\n private options: Required<FileValidatorPluginOptions>;\n\n private defaultOptions: Required<FileValidatorPluginOptions> = {\n maxSize: Infinity,\n minSize: 0,\n accept: [],\n allowEmpty: false,\n customValidate: async () => true,\n messages: {},\n };\n\n constructor(options: FileValidatorPluginOptions = {}) {\n super();\n this.options = { ...this.defaultOptions, ...options };\n }\n\n async created(uploader: Uploader) {\n uploader.inputHTML?.setAttribute(\"accept\", this.options.accept.join(\",\"));\n }\n async onFileSelect(file: UploadFile, context: PluginContext<UploadFile>) {\n const uploader = context.transfer as Uploader;\n const baseError = this.createBaseError(file, uploader);\n\n // 1. 空文件验证\n if (!this.options.allowEmpty && file.File.size === 0) {\n const msg =\n this.options.messages.empty?.() || `文件 ${file.fileName} 是空文件`;\n return this.throwError(\n baseError.setCode(ErrorCode.FILE_EMPTY).setMessage(msg),\n );\n }\n\n // 2. 最小大小验证\n if (file.File.size < this.options.minSize) {\n const msg =\n this.options.messages.minSize?.(this.options.minSize, file.File.size) ||\n `文件 ${file.fileName} 太小,最小 ${formatFileSize(this.options.minSize)}`;\n return this.throwError(\n baseError.setCode(ErrorCode.FILE_TOO_SMALL).setMessage(msg).setContext({\n minSize: this.options.minSize,\n currentSize: file.File.size,\n }),\n );\n }\n\n // 3. 最大大小验证\n if (file.File.size > this.options.maxSize) {\n const msg =\n this.options.messages.maxSize?.(this.options.maxSize, file.File.size) ||\n `文件 ${file.fileName} 太大,最大 ${formatFileSize(this.options.maxSize)}`;\n return this.throwError(\n baseError.setCode(ErrorCode.FILE_TOO_LARGE).setMessage(msg).setContext({\n maxSize: this.options.maxSize,\n currentSize: file.File.size,\n }),\n );\n }\n\n // 4. 文件类型验证\n if (!validator.type(this.options.accept, file)) {\n const msg =\n this.options.messages.accept?.(this.options.accept, file.fileName) ||\n `文件 ${file.fileName} 类型不支持,允许:${this.options.accept.join(\", \")}`;\n return this.throwError(\n baseError.setCode(ErrorCode.INVALID_TYPE).setMessage(msg),\n );\n }\n\n // 5. 自定义验证\n try {\n const customResult = await this.options.customValidate(\n file.File,\n FileUDError,\n );\n if (!customResult) {\n const msg =\n this.options.messages.custom?.(file.fileName) ||\n `文件 ${file.fileName} 验证失败`;\n return this.throwError(\n baseError.setCode(ErrorCode.FILE_CORRUPTED).setMessage(msg),\n );\n }\n } catch (error) {\n console.log(\"🚀 ~ FileValidatorPlugin ~ onFileSelect ~ error:\", error);\n return this.throwError(\n baseError\n .setCode(ErrorCode.PLUGIN_ERROR)\n .setMessage(\"文件验证过程出错\")\n .setContext({\n originalError: error,\n }),\n );\n }\n\n return file;\n }\n}\n","import {\n UploadFile,\n ErrorCode,\n type PluginContext,\n} from \"@file-ud.js/core\";\nimport { BasePlugin } from \"../../base-plugin\";\nexport interface ImageValidatorOptions {\n // 宽度验证\n exactWidth?: number;\n minWidth?: number;\n maxWidth?: number;\n // 高度验证\n exactHeight?: number;\n minHeight?: number;\n maxHeight?: number;\n // 正方形验证\n square?: boolean;\n // 宽高比验证\n minAspectRatio?: number;\n maxAspectRatio?: number;\n aspectRatios?: number[];\n // 分辨率验证\n minResolution?: number;\n maxResolution?: number;\n // 动画图片验证\n allowAnimated?: boolean;\n}\n\nexport class ImageValidatorPlugin extends BasePlugin {\n name = \"image-validator-plugin\";\n priority = 0;\n desc = \"图片验证插件(尺寸、比例、分辨率)\";\n\n constructor(private options: ImageValidatorOptions = {}) {\n super();\n }\n\n async onFileSelect(\n file: UploadFile,\n context: PluginContext<UploadFile>,\n ): Promise<UploadFile | void> {\n // 只验证图片\n if (!file.File.type.startsWith(\"image/\")) {\n return file;\n }\n\n // 获取图片尺寸\n const dimensions = await this.getImageDimensions(file.File);\n\n // 创建基础错误对象\n const baseError = this.createBaseError(file, context.transfer);\n\n // 1. 宽度验证\n if (\n this.options.exactWidth &&\n dimensions.width !== this.options.exactWidth\n ) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_WIDTH_INVALID)\n .setMessage(\n `宽度必须为 ${this.options.exactWidth}px,当前 ${dimensions.width}px`,\n )\n .setContext({ width: dimensions.width }),\n );\n }\n if (this.options.minWidth && dimensions.width < this.options.minWidth) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_WIDTH_INVALID)\n .setMessage(\n `宽度不能小于 ${this.options.minWidth}px,当前 ${dimensions.width}px`,\n )\n .setContext({ width: dimensions.width }),\n );\n }\n if (this.options.maxWidth && dimensions.width > this.options.maxWidth) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_WIDTH_INVALID)\n .setMessage(\n `宽度不能大于 ${this.options.maxWidth}px,当前 ${dimensions.width}px`,\n )\n .setContext({ width: dimensions.width }),\n );\n }\n\n // 2. 高度验证\n if (\n this.options.exactHeight &&\n dimensions.height !== this.options.exactHeight\n ) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_HEIGHT_INVALID)\n .setMessage(\n `高度必须为 ${this.options.exactHeight}px,当前 ${dimensions.height}px`,\n )\n .setContext({ height: dimensions.height }),\n );\n }\n if (this.options.minHeight && dimensions.height < this.options.minHeight) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_HEIGHT_INVALID)\n .setMessage(\n `高度不能小于 ${this.options.minHeight}px,当前 ${dimensions.height}px`,\n )\n .setContext({ height: dimensions.height }),\n );\n }\n if (this.options.maxHeight && dimensions.height > this.options.maxHeight) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_HEIGHT_INVALID)\n .setMessage(\n `高度不能大于 ${this.options.maxHeight}px,当前 ${dimensions.height}px`,\n )\n .setContext({ height: dimensions.height }),\n );\n }\n\n // 3. 正方形验证\n if (this.options.square && dimensions.width !== dimensions.height) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_NOT_SQUARE)\n .setMessage(\n `图片必须是正方形,当前 ${dimensions.width}x${dimensions.height}`,\n )\n .setContext({\n width: dimensions.width,\n height: dimensions.height,\n }),\n );\n }\n\n // 4. 宽高比验证\n const aspectRatio = dimensions.width / dimensions.height;\n if (\n this.options.minAspectRatio &&\n aspectRatio < this.options.minAspectRatio\n ) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_ASPECT_RATIO_INVALID)\n .setMessage(\n `宽高比不能小于 ${this.options.minAspectRatio},当前 ${aspectRatio.toFixed(2)}`,\n )\n .setContext({ aspectRatio }),\n );\n }\n if (\n this.options.maxAspectRatio &&\n aspectRatio > this.options.maxAspectRatio\n ) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_ASPECT_RATIO_INVALID)\n .setMessage(\n `宽高比不能大于 ${this.options.maxAspectRatio},当前 ${aspectRatio.toFixed(2)}`,\n )\n .setContext({ aspectRatio }),\n );\n }\n if (this.options.aspectRatios?.length) {\n const isValid = this.options.aspectRatios.some(\n (ratio) => Math.abs(aspectRatio - ratio) < 0.01,\n );\n if (!isValid) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_ASPECT_RATIO_INVALID)\n .setMessage(\n `宽高比必须为 ${this.options.aspectRatios.join(\", \")},当前 ${aspectRatio.toFixed(2)}`,\n )\n .setContext({ aspectRatio }),\n );\n }\n }\n\n // 5. 分辨率验证\n const resolution = dimensions.width * dimensions.height;\n if (this.options.minResolution && resolution < this.options.minResolution) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_RESOLUTION_INVALID)\n .setMessage(\n `分辨率不能小于 ${this.options.minResolution}px²,当前 ${resolution}px²`,\n )\n .setContext({ resolution }),\n );\n }\n if (this.options.maxResolution && resolution > this.options.maxResolution) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_RESOLUTION_INVALID)\n .setMessage(\n `分辨率不能大于 ${this.options.maxResolution}px²,当前 ${resolution}px²`,\n )\n .setContext({ resolution }),\n );\n }\n\n // 6. 动画图片验证\n if (\n this.options.allowAnimated === false &&\n file.File.type === \"image/gif\"\n ) {\n const isAnimated = await this.isAnimatedGif(file.File);\n if (isAnimated) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.IMAGE_ANIMATED)\n .setMessage(\"不支持动态图片\"),\n );\n }\n }\n\n // 保存尺寸信息到元数据\n file.metadata = {\n ...file.metadata,\n width: dimensions.width,\n height: dimensions.height,\n aspectRatio,\n resolution,\n };\n\n return file;\n }\n\n /**\n * 获取图片尺寸\n */\n private async getImageDimensions(\n file: File,\n ): Promise<{ width: number; height: number }> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve({ width: img.width, height: img.height });\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n }\n\n /**\n * 检查 GIF 是否为动态图片\n */\n private async isAnimatedGif(file: File): Promise<boolean> {\n const buffer = await file.arrayBuffer();\n const view = new DataView(buffer);\n\n // 检查 GIF 文件头\n if (\n view.getUint8(0) !== 0x47 ||\n view.getUint8(1) !== 0x49 ||\n view.getUint8(2) !== 0x46 ||\n view.getUint8(3) !== 0x38\n ) {\n return false;\n }\n\n // 读取帧数量\n let frames = 0;\n const maxFrames = 2; // 只需要知道是否大于 1 帧\n let offset = 6;\n\n while (offset < view.byteLength && frames < maxFrames) {\n const blockId = view.getUint8(offset);\n\n if (blockId === 0x21) {\n // Extension block\n offset += 2;\n const blockSize = view.getUint8(offset);\n offset += blockSize + 1;\n } else if (blockId === 0x2c) {\n // Image block\n frames++;\n offset += 10;\n } else if (blockId === 0x3b) {\n // Trailer\n break;\n } else {\n offset++;\n }\n }\n\n return frames > 1;\n }\n}\n","import {\n UploadFile,\n ErrorCode,\n type PluginContext,\n} from \"@file-ud.js/core\";\nimport { BasePlugin } from \"../../base-plugin\";\nexport interface VideoValidatorOptions {\n // 时长验证\n minDuration?: number;\n maxDuration?: number;\n // 分辨率验证\n minWidth?: number;\n minHeight?: number;\n // 比特率验证\n minBitrate?: number;\n maxBitrate?: number;\n // 编码格式验证\n allowedCodecs?: string[];\n}\n\nexport class VideoValidatorPlugin extends BasePlugin {\n name = \"video-validator-plugin\";\n version = \"1.0.0\";\n priority = 0;\n\n constructor(private options: VideoValidatorOptions = {}) {\n super();\n }\n\n async onFileSelect(\n file: UploadFile,\n context: PluginContext<UploadFile>,\n ): Promise<UploadFile | void> {\n // 只验证视频\n if (!file.File.type.startsWith(\"video/\")) {\n return file;\n }\n\n const metadata = await this.getVideoMetadata(file.File);\n\n // 创建基础错误对象\n const baseError = this.createBaseError(file, context.transfer);\n\n // 时长验证\n if (\n this.options.minDuration &&\n metadata.duration < this.options.minDuration\n ) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.VIDEO_DURATION_INVALID)\n .setMessage(\n `视频时长不能小于 ${this.options.minDuration}秒,当前 ${metadata.duration.toFixed(1)}秒`,\n )\n .setContext({ duration: metadata.duration }),\n );\n }\n if (\n this.options.maxDuration &&\n metadata.duration > this.options.maxDuration\n ) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.VIDEO_DURATION_INVALID)\n .setMessage(\n `视频时长不能大于 ${this.options.maxDuration}秒,当前 ${metadata.duration.toFixed(1)}秒`,\n )\n .setContext({ duration: metadata.duration }),\n );\n }\n\n // 分辨率验证\n if (this.options.minWidth && metadata.width < this.options.minWidth) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.VIDEO_WIDTH_INVALID)\n .setMessage(\n `视频宽度不能小于 ${this.options.minWidth}px,当前 ${metadata.width}px`,\n )\n .setContext({ width: metadata.width }),\n );\n }\n if (this.options.minHeight && metadata.height < this.options.minHeight) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.VIDEO_HEIGHT_INVALID)\n .setMessage(\n `视频高度不能小于 ${this.options.minHeight}px,当前 ${metadata.height}px`,\n )\n .setContext({ height: metadata.height }),\n );\n }\n\n // 比特率验证\n if (this.options.minBitrate && metadata.bitrate < this.options.minBitrate) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.VIDEO_BITRATE_INVALID)\n .setMessage(\n `视频比特率不能小于 ${this.options.minBitrate}kbps,当前 ${metadata.bitrate}kbps`,\n )\n .setContext({ bitrate: metadata.bitrate }),\n );\n }\n if (this.options.maxBitrate && metadata.bitrate > this.options.maxBitrate) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.VIDEO_BITRATE_INVALID)\n .setMessage(\n `视频比特率不能大于 ${this.options.maxBitrate}kbps,当前 ${metadata.bitrate}kbps`,\n )\n .setContext({ bitrate: metadata.bitrate }),\n );\n }\n\n // 编码格式验证\n if (this.options.allowedCodecs?.length) {\n const codecValid = this.options.allowedCodecs.some((codec) =>\n metadata.codec?.includes(codec),\n );\n if (!codecValid) {\n return this.throwError(\n baseError\n .setCode(ErrorCode.VIDEO_CODEC_INVALID)\n .setMessage(\n `视频编码格式不支持,当前 ${metadata.codec || \"未知\"},允许:${this.options.allowedCodecs.join(\", \")}`,\n )\n .setContext({ codec: metadata.codec }),\n );\n }\n }\n\n // 保存元数据\n file.metadata = { ...file.metadata, video: metadata };\n\n return file;\n }\n\n /**\n * 获取视频元数据\n */\n private async getVideoMetadata(file: File): Promise<{\n duration: number;\n width: number;\n height: number;\n bitrate: number;\n codec?: string;\n }> {\n return new Promise((resolve, reject) => {\n const video = document.createElement(\"video\");\n video.preload = \"metadata\";\n\n video.onloadedmetadata = () => {\n URL.revokeObjectURL(video.src);\n resolve({\n duration: video.duration,\n width: video.videoWidth,\n height: video.videoHeight,\n bitrate: 0, // 浏览器无法直接获取比特率,需要后端提供或估算\n codec: video.currentSrc.split(\",\").pop()?.split('\"')[1],\n });\n };\n\n video.onerror = () => {\n URL.revokeObjectURL(video.src);\n reject(new Error(\"Failed to load video metadata\"));\n };\n\n video.src = URL.createObjectURL(file);\n });\n }\n}\n"]}
|