833 lines
21 KiB
JavaScript
833 lines
21 KiB
JavaScript
// 媒体文件管理器 - 微信小程序专用
|
|
// 处理图片、视频、音频、文件的上传、下载、预览、缓存等
|
|
|
|
const apiClient = require('./api-client.js');
|
|
|
|
/**
|
|
* 媒体文件管理器
|
|
* 功能:
|
|
* 1. 文件选择和上传
|
|
* 2. 媒体文件预览
|
|
* 3. 文件下载和缓存
|
|
* 4. 文件压缩和优化
|
|
* 5. 云存储管理
|
|
* 6. 文件类型检测
|
|
*/
|
|
class MediaManager {
|
|
constructor() {
|
|
this.isInitialized = false;
|
|
|
|
// 媒体配置
|
|
this.mediaConfig = {
|
|
// 图片配置
|
|
image: {
|
|
maxSize: 10 * 1024 * 1024, // 10MB
|
|
maxCount: 9, // 最多选择9张
|
|
quality: 80, // 压缩质量
|
|
formats: ['jpg', 'jpeg', 'png', 'gif', 'webp'],
|
|
compressWidth: 1080 // 压缩宽度
|
|
},
|
|
|
|
// 视频配置
|
|
video: {
|
|
maxSize: 100 * 1024 * 1024, // 100MB
|
|
maxDuration: 300, // 最长5分钟
|
|
formats: ['mp4', 'mov', 'avi'],
|
|
compressQuality: 'medium'
|
|
},
|
|
|
|
// 音频配置
|
|
audio: {
|
|
maxSize: 20 * 1024 * 1024, // 20MB
|
|
maxDuration: 600, // 最长10分钟
|
|
formats: ['mp3', 'wav', 'aac', 'm4a'],
|
|
sampleRate: 16000
|
|
},
|
|
|
|
// 文件配置
|
|
file: {
|
|
maxSize: 50 * 1024 * 1024, // 50MB
|
|
allowedTypes: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'zip', 'rar'],
|
|
maxCount: 5
|
|
},
|
|
|
|
// 缓存配置
|
|
cache: {
|
|
maxSize: 200 * 1024 * 1024, // 200MB
|
|
expireTime: 7 * 24 * 60 * 60 * 1000, // 7天
|
|
cleanupInterval: 24 * 60 * 60 * 1000 // 24小时清理一次
|
|
}
|
|
};
|
|
|
|
// 文件缓存
|
|
this.fileCache = new Map();
|
|
|
|
// 上传队列
|
|
this.uploadQueue = [];
|
|
|
|
// 下载队列
|
|
this.downloadQueue = [];
|
|
|
|
// 当前上传任务
|
|
this.currentUploads = new Map();
|
|
|
|
// 缓存统计
|
|
this.cacheStats = {
|
|
totalSize: 0,
|
|
fileCount: 0,
|
|
lastCleanup: 0
|
|
};
|
|
|
|
this.init();
|
|
}
|
|
|
|
// 初始化媒体管理器
|
|
async init() {
|
|
if (this.isInitialized) return;
|
|
|
|
console.log('📁 初始化媒体文件管理器...');
|
|
|
|
try {
|
|
// 加载文件缓存信息
|
|
await this.loadCacheInfo();
|
|
|
|
// 检查存储权限
|
|
await this.checkStoragePermission();
|
|
|
|
// 启动缓存清理
|
|
this.startCacheCleanup();
|
|
|
|
this.isInitialized = true;
|
|
console.log('✅ 媒体文件管理器初始化完成');
|
|
|
|
} catch (error) {
|
|
console.error('❌ 媒体文件管理器初始化失败:', error);
|
|
}
|
|
}
|
|
|
|
// 📷 ===== 图片处理 =====
|
|
|
|
// 选择图片
|
|
async chooseImages(options = {}) {
|
|
try {
|
|
const {
|
|
count = this.mediaConfig.image.maxCount,
|
|
sizeType = ['compressed', 'original'],
|
|
sourceType = ['album', 'camera']
|
|
} = options;
|
|
|
|
console.log('📷 选择图片...');
|
|
|
|
const result = await new Promise((resolve, reject) => {
|
|
wx.chooseImage({
|
|
count: count,
|
|
sizeType: sizeType,
|
|
sourceType: sourceType,
|
|
success: resolve,
|
|
fail: reject
|
|
});
|
|
});
|
|
|
|
// 验证和处理图片
|
|
const processedImages = await this.processImages(result.tempFilePaths);
|
|
|
|
console.log(`📷 选择了 ${processedImages.length} 张图片`);
|
|
return {
|
|
success: true,
|
|
images: processedImages
|
|
};
|
|
|
|
} catch (error) {
|
|
console.error('❌ 选择图片失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error.errMsg || '选择图片失败'
|
|
};
|
|
}
|
|
}
|
|
|
|
// 处理图片
|
|
async processImages(tempFilePaths) {
|
|
const processedImages = [];
|
|
|
|
for (const tempPath of tempFilePaths) {
|
|
try {
|
|
// 获取图片信息
|
|
const imageInfo = await this.getImageInfo(tempPath);
|
|
|
|
// 检查文件大小
|
|
if (imageInfo.size > this.mediaConfig.image.maxSize) {
|
|
console.warn('⚠️ 图片过大,需要压缩:', imageInfo.size);
|
|
// 压缩图片
|
|
const compressedPath = await this.compressImage(tempPath);
|
|
imageInfo.tempFilePath = compressedPath;
|
|
}
|
|
|
|
// 生成缩略图
|
|
const thumbnailPath = await this.generateThumbnail(imageInfo.tempFilePath);
|
|
|
|
processedImages.push({
|
|
...imageInfo,
|
|
thumbnailPath: thumbnailPath,
|
|
type: 'image',
|
|
status: 'ready'
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('❌ 处理图片失败:', error);
|
|
}
|
|
}
|
|
|
|
return processedImages;
|
|
}
|
|
|
|
// 获取图片信息
|
|
async getImageInfo(src) {
|
|
return new Promise((resolve, reject) => {
|
|
wx.getImageInfo({
|
|
src: src,
|
|
success: (res) => {
|
|
// 获取文件大小
|
|
wx.getFileInfo({
|
|
filePath: src,
|
|
success: (fileInfo) => {
|
|
resolve({
|
|
...res,
|
|
size: fileInfo.size,
|
|
tempFilePath: src
|
|
});
|
|
},
|
|
fail: () => {
|
|
resolve({
|
|
...res,
|
|
size: 0,
|
|
tempFilePath: src
|
|
});
|
|
}
|
|
});
|
|
},
|
|
fail: reject
|
|
});
|
|
});
|
|
}
|
|
|
|
// 压缩图片
|
|
async compressImage(src) {
|
|
try {
|
|
const result = await new Promise((resolve, reject) => {
|
|
wx.compressImage({
|
|
src: src,
|
|
quality: this.mediaConfig.image.quality,
|
|
success: resolve,
|
|
fail: reject
|
|
});
|
|
});
|
|
|
|
console.log('📷 图片压缩完成');
|
|
return result.tempFilePath;
|
|
|
|
} catch (error) {
|
|
console.error('❌ 图片压缩失败:', error);
|
|
return src; // 压缩失败返回原图
|
|
}
|
|
}
|
|
|
|
// 生成缩略图
|
|
async generateThumbnail(src) {
|
|
try {
|
|
// 创建canvas生成缩略图
|
|
const canvas = wx.createOffscreenCanvas({ type: '2d' });
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
// 设置缩略图尺寸
|
|
const thumbnailSize = 200;
|
|
canvas.width = thumbnailSize;
|
|
canvas.height = thumbnailSize;
|
|
|
|
// 加载图片
|
|
const image = canvas.createImage();
|
|
|
|
return new Promise((resolve) => {
|
|
image.onload = () => {
|
|
// 计算绘制尺寸
|
|
const { drawWidth, drawHeight, drawX, drawY } = this.calculateDrawSize(
|
|
image.width,
|
|
image.height,
|
|
thumbnailSize,
|
|
thumbnailSize
|
|
);
|
|
|
|
// 绘制缩略图
|
|
ctx.drawImage(image, drawX, drawY, drawWidth, drawHeight);
|
|
|
|
// 导出为临时文件
|
|
wx.canvasToTempFilePath({
|
|
canvas: canvas,
|
|
success: (res) => {
|
|
resolve(res.tempFilePath);
|
|
},
|
|
fail: () => {
|
|
resolve(src); // 生成失败返回原图
|
|
}
|
|
});
|
|
};
|
|
|
|
image.onerror = () => {
|
|
resolve(src); // 加载失败返回原图
|
|
};
|
|
|
|
image.src = src;
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('❌ 生成缩略图失败:', error);
|
|
return src;
|
|
}
|
|
}
|
|
|
|
// 计算绘制尺寸
|
|
calculateDrawSize(imageWidth, imageHeight, canvasWidth, canvasHeight) {
|
|
const imageRatio = imageWidth / imageHeight;
|
|
const canvasRatio = canvasWidth / canvasHeight;
|
|
|
|
let drawWidth, drawHeight, drawX, drawY;
|
|
|
|
if (imageRatio > canvasRatio) {
|
|
// 图片更宽,以高度为准
|
|
drawHeight = canvasHeight;
|
|
drawWidth = drawHeight * imageRatio;
|
|
drawX = (canvasWidth - drawWidth) / 2;
|
|
drawY = 0;
|
|
} else {
|
|
// 图片更高,以宽度为准
|
|
drawWidth = canvasWidth;
|
|
drawHeight = drawWidth / imageRatio;
|
|
drawX = 0;
|
|
drawY = (canvasHeight - drawHeight) / 2;
|
|
}
|
|
|
|
return { drawWidth, drawHeight, drawX, drawY };
|
|
}
|
|
|
|
// 🎬 ===== 视频处理 =====
|
|
|
|
// 选择视频
|
|
async chooseVideo(options = {}) {
|
|
try {
|
|
const {
|
|
sourceType = ['album', 'camera'],
|
|
maxDuration = this.mediaConfig.video.maxDuration,
|
|
camera = 'back'
|
|
} = options;
|
|
|
|
console.log('🎬 选择视频...');
|
|
|
|
const result = await new Promise((resolve, reject) => {
|
|
wx.chooseVideo({
|
|
sourceType: sourceType,
|
|
maxDuration: maxDuration,
|
|
camera: camera,
|
|
success: resolve,
|
|
fail: reject
|
|
});
|
|
});
|
|
|
|
// 验证和处理视频
|
|
const processedVideo = await this.processVideo(result);
|
|
|
|
console.log('🎬 选择视频完成');
|
|
return {
|
|
success: true,
|
|
video: processedVideo
|
|
};
|
|
|
|
} catch (error) {
|
|
console.error('❌ 选择视频失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error.errMsg || '选择视频失败'
|
|
};
|
|
}
|
|
}
|
|
|
|
// 处理视频
|
|
async processVideo(videoResult) {
|
|
try {
|
|
// 检查文件大小
|
|
if (videoResult.size > this.mediaConfig.video.maxSize) {
|
|
throw new Error('视频文件过大');
|
|
}
|
|
|
|
// 检查时长
|
|
if (videoResult.duration > this.mediaConfig.video.maxDuration) {
|
|
throw new Error('视频时长超出限制');
|
|
}
|
|
|
|
// 生成视频缩略图
|
|
const thumbnailPath = await this.generateVideoThumbnail(videoResult.tempFilePath);
|
|
|
|
return {
|
|
tempFilePath: videoResult.tempFilePath,
|
|
duration: videoResult.duration,
|
|
size: videoResult.size,
|
|
width: videoResult.width,
|
|
height: videoResult.height,
|
|
thumbnailPath: thumbnailPath,
|
|
type: 'video',
|
|
status: 'ready'
|
|
};
|
|
|
|
} catch (error) {
|
|
console.error('❌ 处理视频失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 生成视频缩略图
|
|
async generateVideoThumbnail(videoPath) {
|
|
try {
|
|
// 微信小程序暂不支持视频帧提取,使用默认图标
|
|
return null;
|
|
} catch (error) {
|
|
console.error('❌ 生成视频缩略图失败:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// 📄 ===== 文件处理 =====
|
|
|
|
// 选择文件
|
|
async chooseFile(options = {}) {
|
|
try {
|
|
const {
|
|
count = this.mediaConfig.file.maxCount,
|
|
type = 'all'
|
|
} = options;
|
|
|
|
console.log('📄 选择文件...');
|
|
|
|
const result = await new Promise((resolve, reject) => {
|
|
wx.chooseMessageFile({
|
|
count: count,
|
|
type: type,
|
|
success: resolve,
|
|
fail: reject
|
|
});
|
|
});
|
|
|
|
// 验证和处理文件
|
|
const processedFiles = await this.processFiles(result.tempFiles);
|
|
|
|
console.log(`📄 选择了 ${processedFiles.length} 个文件`);
|
|
return {
|
|
success: true,
|
|
files: processedFiles
|
|
};
|
|
|
|
} catch (error) {
|
|
console.error('❌ 选择文件失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error.errMsg || '选择文件失败'
|
|
};
|
|
}
|
|
}
|
|
|
|
// 处理文件
|
|
async processFiles(tempFiles) {
|
|
const processedFiles = [];
|
|
|
|
for (const file of tempFiles) {
|
|
try {
|
|
// 检查文件大小
|
|
if (file.size > this.mediaConfig.file.maxSize) {
|
|
console.warn('⚠️ 文件过大:', file.name, file.size);
|
|
continue;
|
|
}
|
|
|
|
// 检查文件类型
|
|
const fileExtension = this.getFileExtension(file.name);
|
|
if (!this.isAllowedFileType(fileExtension)) {
|
|
console.warn('⚠️ 不支持的文件类型:', fileExtension);
|
|
continue;
|
|
}
|
|
|
|
processedFiles.push({
|
|
tempFilePath: file.path,
|
|
name: file.name,
|
|
size: file.size,
|
|
type: 'file',
|
|
extension: fileExtension,
|
|
status: 'ready'
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('❌ 处理文件失败:', error);
|
|
}
|
|
}
|
|
|
|
return processedFiles;
|
|
}
|
|
|
|
// 获取文件扩展名
|
|
getFileExtension(fileName) {
|
|
const lastDotIndex = fileName.lastIndexOf('.');
|
|
if (lastDotIndex === -1) return '';
|
|
return fileName.substring(lastDotIndex + 1).toLowerCase();
|
|
}
|
|
|
|
// 检查文件类型是否允许
|
|
isAllowedFileType(extension) {
|
|
return this.mediaConfig.file.allowedTypes.includes(extension);
|
|
}
|
|
|
|
// 📤 ===== 文件上传 =====
|
|
|
|
// 上传文件
|
|
async uploadFile(file, options = {}) {
|
|
try {
|
|
const {
|
|
onProgress,
|
|
onSuccess,
|
|
onError
|
|
} = options;
|
|
|
|
console.log('📤 开始上传文件:', file.name || 'unknown');
|
|
|
|
// 生成上传ID
|
|
const uploadId = this.generateUploadId();
|
|
|
|
// 添加到上传队列
|
|
const uploadTask = {
|
|
id: uploadId,
|
|
file: file,
|
|
status: 'uploading',
|
|
progress: 0,
|
|
onProgress: onProgress,
|
|
onSuccess: onSuccess,
|
|
onError: onError
|
|
};
|
|
|
|
this.currentUploads.set(uploadId, uploadTask);
|
|
|
|
// 执行上传
|
|
const result = await this.performUpload(uploadTask);
|
|
|
|
// 移除上传任务
|
|
this.currentUploads.delete(uploadId);
|
|
|
|
return result;
|
|
|
|
} catch (error) {
|
|
console.error('❌ 上传文件失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error.message
|
|
};
|
|
}
|
|
}
|
|
|
|
// 执行上传
|
|
async performUpload(uploadTask) {
|
|
return new Promise((resolve, reject) => {
|
|
const uploadTask_wx = wx.uploadFile({
|
|
url: `${apiClient.baseURL}/api/v1/files/upload`,
|
|
filePath: uploadTask.file.tempFilePath,
|
|
name: 'file',
|
|
header: {
|
|
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
|
},
|
|
formData: {
|
|
type: uploadTask.file.type,
|
|
name: uploadTask.file.name || 'unknown'
|
|
},
|
|
success: (res) => {
|
|
try {
|
|
const data = JSON.parse(res.data);
|
|
if (data.success) {
|
|
console.log('✅ 文件上传成功:', data.data.url);
|
|
|
|
const result = {
|
|
success: true,
|
|
data: {
|
|
url: data.data.url,
|
|
fileId: data.data.fileId,
|
|
fileName: uploadTask.file.name,
|
|
fileSize: uploadTask.file.size,
|
|
fileType: uploadTask.file.type
|
|
}
|
|
};
|
|
|
|
if (uploadTask.onSuccess) {
|
|
uploadTask.onSuccess(result);
|
|
}
|
|
|
|
resolve(result);
|
|
} else {
|
|
throw new Error(data.error || '上传失败');
|
|
}
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
},
|
|
fail: (error) => {
|
|
console.error('❌ 上传请求失败:', error);
|
|
if (uploadTask.onError) {
|
|
uploadTask.onError(error);
|
|
}
|
|
reject(error);
|
|
}
|
|
});
|
|
|
|
// 监听上传进度
|
|
uploadTask_wx.onProgressUpdate((res) => {
|
|
uploadTask.progress = res.progress;
|
|
|
|
if (uploadTask.onProgress) {
|
|
uploadTask.onProgress({
|
|
progress: res.progress,
|
|
totalBytesSent: res.totalBytesSent,
|
|
totalBytesExpectedToSend: res.totalBytesExpectedToSend
|
|
});
|
|
}
|
|
});
|
|
|
|
// 保存上传任务引用
|
|
uploadTask.wxTask = uploadTask_wx;
|
|
});
|
|
}
|
|
|
|
// 取消上传
|
|
cancelUpload(uploadId) {
|
|
const uploadTask = this.currentUploads.get(uploadId);
|
|
if (uploadTask && uploadTask.wxTask) {
|
|
uploadTask.wxTask.abort();
|
|
this.currentUploads.delete(uploadId);
|
|
console.log('📤 取消上传:', uploadId);
|
|
}
|
|
}
|
|
|
|
// 生成上传ID
|
|
generateUploadId() {
|
|
return `upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
}
|
|
|
|
// 📥 ===== 文件下载和缓存 =====
|
|
|
|
// 下载文件
|
|
async downloadFile(url, options = {}) {
|
|
try {
|
|
const {
|
|
fileName,
|
|
onProgress,
|
|
useCache = true
|
|
} = options;
|
|
|
|
console.log('📥 下载文件:', url);
|
|
|
|
// 检查缓存
|
|
if (useCache) {
|
|
const cachedPath = this.getCachedFilePath(url);
|
|
if (cachedPath) {
|
|
console.log('📥 使用缓存文件:', cachedPath);
|
|
return {
|
|
success: true,
|
|
tempFilePath: cachedPath,
|
|
cached: true
|
|
};
|
|
}
|
|
}
|
|
|
|
// 执行下载
|
|
const result = await this.performDownload(url, { fileName, onProgress });
|
|
|
|
// 缓存文件
|
|
if (result.success && useCache) {
|
|
this.cacheFile(url, result.tempFilePath);
|
|
}
|
|
|
|
return result;
|
|
|
|
} catch (error) {
|
|
console.error('❌ 下载文件失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error.message
|
|
};
|
|
}
|
|
}
|
|
|
|
// 执行下载
|
|
async performDownload(url, options = {}) {
|
|
return new Promise((resolve, reject) => {
|
|
const downloadTask = wx.downloadFile({
|
|
url: url,
|
|
success: (res) => {
|
|
if (res.statusCode === 200) {
|
|
console.log('✅ 文件下载成功');
|
|
resolve({
|
|
success: true,
|
|
tempFilePath: res.tempFilePath,
|
|
cached: false
|
|
});
|
|
} else {
|
|
reject(new Error(`下载失败: ${res.statusCode}`));
|
|
}
|
|
},
|
|
fail: reject
|
|
});
|
|
|
|
// 监听下载进度
|
|
if (options.onProgress) {
|
|
downloadTask.onProgressUpdate((res) => {
|
|
options.onProgress({
|
|
progress: res.progress,
|
|
totalBytesWritten: res.totalBytesWritten,
|
|
totalBytesExpectedToWrite: res.totalBytesExpectedToWrite
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// 检查存储权限
|
|
async checkStoragePermission() {
|
|
try {
|
|
const storageInfo = wx.getStorageInfoSync();
|
|
console.log('📁 存储信息:', storageInfo);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('❌ 检查存储权限失败:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// 加载缓存信息
|
|
async loadCacheInfo() {
|
|
try {
|
|
const cacheInfo = wx.getStorageSync('mediaCacheInfo') || {};
|
|
this.cacheStats = {
|
|
totalSize: cacheInfo.totalSize || 0,
|
|
fileCount: cacheInfo.fileCount || 0,
|
|
lastCleanup: cacheInfo.lastCleanup || 0
|
|
};
|
|
} catch (error) {
|
|
console.error('❌ 加载缓存信息失败:', error);
|
|
}
|
|
}
|
|
|
|
// 保存缓存信息
|
|
async saveCacheInfo() {
|
|
try {
|
|
wx.setStorageSync('mediaCacheInfo', this.cacheStats);
|
|
} catch (error) {
|
|
console.error('❌ 保存缓存信息失败:', error);
|
|
}
|
|
}
|
|
|
|
// 获取缓存文件路径
|
|
getCachedFilePath(url) {
|
|
const cacheKey = this.generateCacheKey(url);
|
|
return this.fileCache.get(cacheKey);
|
|
}
|
|
|
|
// 缓存文件
|
|
cacheFile(url, filePath) {
|
|
const cacheKey = this.generateCacheKey(url);
|
|
this.fileCache.set(cacheKey, filePath);
|
|
|
|
// 更新缓存统计
|
|
this.cacheStats.fileCount++;
|
|
this.saveCacheInfo();
|
|
}
|
|
|
|
// 生成缓存键
|
|
generateCacheKey(url) {
|
|
// 使用URL的hash作为缓存键
|
|
let hash = 0;
|
|
for (let i = 0; i < url.length; i++) {
|
|
const char = url.charCodeAt(i);
|
|
hash = ((hash << 5) - hash) + char;
|
|
hash = hash & hash; // 转换为32位整数
|
|
}
|
|
return `cache_${Math.abs(hash)}`;
|
|
}
|
|
|
|
// 启动缓存清理
|
|
startCacheCleanup() {
|
|
setInterval(() => {
|
|
this.performCacheCleanup();
|
|
}, this.mediaConfig.cache.cleanupInterval);
|
|
}
|
|
|
|
// 执行缓存清理
|
|
performCacheCleanup() {
|
|
try {
|
|
console.log('📁 执行缓存清理...');
|
|
|
|
const now = Date.now();
|
|
const expireTime = this.mediaConfig.cache.expireTime;
|
|
|
|
// 清理过期缓存
|
|
for (const [key, filePath] of this.fileCache) {
|
|
try {
|
|
const stats = wx.getFileInfo({ filePath });
|
|
if (now - stats.createTime > expireTime) {
|
|
this.fileCache.delete(key);
|
|
// 删除文件
|
|
wx.removeSavedFile({ filePath });
|
|
}
|
|
} catch (error) {
|
|
// 文件不存在,从缓存中移除
|
|
this.fileCache.delete(key);
|
|
}
|
|
}
|
|
|
|
// 更新清理时间
|
|
this.cacheStats.lastCleanup = now;
|
|
this.saveCacheInfo();
|
|
|
|
console.log('✅ 缓存清理完成');
|
|
|
|
} catch (error) {
|
|
console.error('❌ 缓存清理失败:', error);
|
|
}
|
|
}
|
|
|
|
// 获取媒体管理器状态
|
|
getStatus() {
|
|
return {
|
|
isInitialized: this.isInitialized,
|
|
uploadCount: this.currentUploads.size,
|
|
cacheStats: { ...this.cacheStats },
|
|
config: this.mediaConfig
|
|
};
|
|
}
|
|
|
|
// 清除所有缓存
|
|
clearAllCache() {
|
|
this.fileCache.clear();
|
|
this.cacheStats = {
|
|
totalSize: 0,
|
|
fileCount: 0,
|
|
lastCleanup: Date.now()
|
|
};
|
|
this.saveCacheInfo();
|
|
console.log('📁 已清除所有媒体缓存');
|
|
}
|
|
|
|
// 重置管理器
|
|
reset() {
|
|
// 取消所有上传任务
|
|
for (const [uploadId] of this.currentUploads) {
|
|
this.cancelUpload(uploadId);
|
|
}
|
|
|
|
this.clearAllCache();
|
|
}
|
|
}
|
|
|
|
// 创建全局实例
|
|
const mediaManager = new MediaManager();
|
|
|
|
module.exports = mediaManager;
|