feat: 并发
This commit is contained in:
parent
036a7c7fa1
commit
19ed3bba52
@ -71,7 +71,7 @@ export default function OwnerPage() {
|
||||
|
||||
{/* 资源数据 */}
|
||||
<View style={styles.resourceContainer}>
|
||||
<ResourceComponent title={t("generalSetting.usedStorage", { ns: "personal" })} subtitle={`${countData?.counter?.total_count?.video_count || 0}videos/${countData?.counter?.total_count?.photo_count || 0}photos`} data={{ all: countData.total_bytes, used: countData.used_bytes }} icon={<UsedStorageSvg />} style={{ flex: 1 }} isFormatBytes={true} />
|
||||
<ResourceComponent title={t("generalSetting.usedStorage", { ns: "personal" })} subtitle={`${countData?.counter?.total_count?.video_count || 0}videos/${countData?.counter?.total_count?.photo_count || 0}photos`} data={{ all: userInfoDetails.total_bytes, used: countData.used_bytes }} icon={<UsedStorageSvg />} style={{ flex: 1 }} isFormatBytes={true} />
|
||||
<ResourceComponent title={t("generalSetting.remainingPoints", { ns: "personal" })} data={{ all: userInfoDetails.total_points, used: userInfoDetails.remain_points }} icon={<PointsSvg />} style={{ flex: 1 }} />
|
||||
</View>
|
||||
{/* 数据统计 */}
|
||||
|
||||
@ -4,6 +4,7 @@ import * as FileSystem from 'expo-file-system';
|
||||
import * as ImageManipulator from 'expo-image-manipulator';
|
||||
import * as MediaLibrary from 'expo-media-library';
|
||||
import * as TaskManager from 'expo-task-manager';
|
||||
import pLimit from 'p-limit';
|
||||
import { Alert } from 'react-native';
|
||||
import { transformData } from '../utils/objectFlat';
|
||||
|
||||
@ -14,6 +15,30 @@ type ExtendedAsset = MediaLibrary.Asset & {
|
||||
const BACKGROUND_UPLOAD_TASK = 'background-upload-task';
|
||||
// 设置最大并发数
|
||||
const CONCURRENCY_LIMIT = 10; // 同时最多上传10个文件
|
||||
// 在 CONCURRENCY_LIMIT 定义后添加
|
||||
const limit = pLimit(CONCURRENCY_LIMIT);
|
||||
|
||||
// 获取文件扩展名
|
||||
const getFileExtension = (filename: string) => {
|
||||
return filename.split('.').pop()?.toLowerCase() || '';
|
||||
};
|
||||
|
||||
// 获取 MIME 类型
|
||||
const getMimeType = (filename: string, isVideo: boolean) => {
|
||||
if (!isVideo) return 'image/jpeg';
|
||||
|
||||
const ext = getFileExtension(filename);
|
||||
switch (ext) {
|
||||
case 'mov':
|
||||
return 'video/quicktime';
|
||||
case 'mp4':
|
||||
return 'video/mp4';
|
||||
case 'm4v':
|
||||
return 'video/x-m4v';
|
||||
default:
|
||||
return 'video/mp4'; // 默认值
|
||||
}
|
||||
};
|
||||
|
||||
// 将 HEIC 图片转化
|
||||
const convertHeicToJpeg = async (uri: string): Promise<File> => {
|
||||
@ -274,42 +299,67 @@ const processMediaUpload = async (asset: ExtendedAsset) => {
|
||||
const uploadOriginalFile = async () => {
|
||||
try {
|
||||
let fileToUpload: File;
|
||||
let mimeType = isVideo ? 'video/mp4' : 'image/jpeg';
|
||||
const isVideo = asset.mediaType === 'video';
|
||||
const mimeType = getMimeType(asset.filename || '', isVideo);
|
||||
|
||||
// 生成文件名,保留原始扩展名
|
||||
let filename = asset.filename ||
|
||||
`${isVideo ? 'video' : 'image'}_${Date.now()}_original.${isVideo ? 'mp4' : 'jpg'}`;
|
||||
`${isVideo ? 'video' : 'image'}_${Date.now()}_original.${isVideo ? (getFileExtension(asset.filename || 'mp4') || 'mp4') : 'jpg'}`;
|
||||
|
||||
// 处理 HEIC 格式
|
||||
if (filename.toLowerCase().endsWith('.heic') || filename.toLowerCase().endsWith('.heif')) {
|
||||
try {
|
||||
fileToUpload = await convertHeicToJpeg(asset.uri);
|
||||
filename = filename.replace(/\.(heic|heif)$/i, '.jpg');
|
||||
} catch (conversionError) {
|
||||
console.error('HEIC conversion failed, trying fallback:', conversionError);
|
||||
// 如果转换失败,尝试使用 MediaLibrary 获取文件
|
||||
try {
|
||||
const assetInfo = await MediaLibrary.getAssetInfoAsync(asset.id);
|
||||
if (assetInfo.localUri) {
|
||||
const response = await fetch(assetInfo.localUri);
|
||||
const blob = await response.blob();
|
||||
fileToUpload = new File([blob], filename, { type: 'image/jpeg' });
|
||||
} else {
|
||||
throw new Error('No local URI available for the asset');
|
||||
}
|
||||
} catch (fallbackError) {
|
||||
console.error('Fallback method also failed:', fallbackError);
|
||||
// 如果所有方法都失败,尝试直接使用原始 URI
|
||||
const response = await fetch(asset.uri);
|
||||
const blob = await response.blob();
|
||||
fileToUpload = new File([blob], filename, { type: 'image/jpeg' });
|
||||
}
|
||||
}
|
||||
fileToUpload = await convertHeicToJpeg(asset.uri);
|
||||
filename = filename.replace(/\.(heic|heif)$/i, '.jpg');
|
||||
} else {
|
||||
// 普通图片处理
|
||||
const response = await fetch(asset.uri);
|
||||
// 获取资源信息
|
||||
const assetInfo = await MediaLibrary.getAssetInfoAsync(asset.id, {
|
||||
shouldDownloadFromNetwork: true
|
||||
});
|
||||
|
||||
if (!assetInfo.localUri) {
|
||||
throw new Error('无法获取资源的本地路径');
|
||||
}
|
||||
|
||||
// 获取文件扩展名
|
||||
const fileExtension = getFileExtension(assetInfo.filename || '') ||
|
||||
(isVideo ? 'mp4' : 'jpg');
|
||||
|
||||
// 确保文件名有正确的扩展名
|
||||
if (!filename.toLowerCase().endsWith(`.${fileExtension}`)) {
|
||||
const baseName = filename.split('.')[0];
|
||||
filename = `${baseName}.${fileExtension}`;
|
||||
}
|
||||
|
||||
// 获取文件内容
|
||||
const response = await fetch(assetInfo.localUri);
|
||||
const blob = await response.blob();
|
||||
|
||||
// 创建文件对象
|
||||
fileToUpload = new File([blob], filename, { type: mimeType });
|
||||
console.log('文件准备上传:', {
|
||||
name: fileToUpload.name,
|
||||
type: fileToUpload.type,
|
||||
size: fileToUpload.size
|
||||
});
|
||||
}
|
||||
let exifData = asset?.exif ? { ...transformData({ ...asset, exif: { ...asset?.exif, '{MakerApple}': undefined } }) } : {};
|
||||
|
||||
// 准备元数据
|
||||
let exifData = {};
|
||||
if (asset.exif) {
|
||||
try {
|
||||
exifData = transformData({
|
||||
...asset,
|
||||
exif: {
|
||||
...asset.exif,
|
||||
'{MakerApple}': undefined
|
||||
}
|
||||
});
|
||||
} catch (exifError) {
|
||||
console.warn('处理 EXIF 数据时出错:', exifError);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取上传 URL
|
||||
const { upload_url, file_id } = await getUploadUrl(fileToUpload, {
|
||||
originalUri: asset.uri,
|
||||
creationTime: asset.creationTime,
|
||||
@ -319,26 +369,31 @@ const processMediaUpload = async (asset: ExtendedAsset) => {
|
||||
GPSVersionID: undefined
|
||||
});
|
||||
|
||||
// 上传文件
|
||||
await uploadFile(fileToUpload, upload_url);
|
||||
await confirmUpload(file_id);
|
||||
|
||||
return { success: true, file_id };
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error('Error in uploadOriginalFile:', {
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
stack: error.stack,
|
||||
asset: {
|
||||
id: asset.id,
|
||||
uri: asset.uri,
|
||||
filename: asset.filename
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error('An unknown error occurred:', error);
|
||||
}
|
||||
throw error;
|
||||
console.log('文件上传成功:', {
|
||||
fileId: file_id,
|
||||
filename: fileToUpload.name,
|
||||
type: fileToUpload.type
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
file_id,
|
||||
filename: fileToUpload.name
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
const errorMessage = error instanceof Error ? error.message : '未知错误';
|
||||
console.error('上传原始文件时出错:', {
|
||||
error: errorMessage,
|
||||
assetId: asset.id,
|
||||
filename: asset.filename,
|
||||
uri: asset.uri
|
||||
});
|
||||
throw new Error(`上传失败: ${errorMessage}`);
|
||||
}
|
||||
};
|
||||
|
||||
@ -467,62 +522,51 @@ export const triggerManualUpload = async (startDate: Date, endDate: Date) => {
|
||||
// 分离图片和视频
|
||||
const photos = media.filter(item => item.mediaType === 'photo');
|
||||
const videos = media.filter(item => item.mediaType === 'video');
|
||||
console.log('videos11111111', videos);
|
||||
|
||||
const results = [];
|
||||
const results: any[] = [];
|
||||
|
||||
// 先处理所有图片
|
||||
for (const item of photos) {
|
||||
// 处理所有图片(带并发控制)
|
||||
const processPhoto = async (item: any) => {
|
||||
try {
|
||||
const result = await processMediaUpload(item);
|
||||
results.push({
|
||||
id: item.id,
|
||||
...result
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
|
||||
console.error('Error processing photo upload:', {
|
||||
error: error instanceof Error ? {
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
stack: error.stack
|
||||
} : error,
|
||||
assetId: item.id
|
||||
});
|
||||
} catch (error: any) {
|
||||
results.push({
|
||||
id: item.id,
|
||||
originalSuccess: false,
|
||||
compressedSuccess: false,
|
||||
error: errorMessage
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 再处理所有视频
|
||||
for (const item of videos) {
|
||||
// 处理所有视频(带并发控制)
|
||||
const processVideo = async (item: any) => {
|
||||
try {
|
||||
const result = await processMediaUpload(item);
|
||||
results.push({
|
||||
id: item.id,
|
||||
...result
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
|
||||
console.error('Error processing video upload:', {
|
||||
error: error instanceof Error ? {
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
stack: error.stack
|
||||
} : error,
|
||||
assetId: item.id
|
||||
});
|
||||
} catch (error: any) {
|
||||
results.push({
|
||||
id: item.id,
|
||||
originalSuccess: false,
|
||||
compressedSuccess: false,
|
||||
error: errorMessage
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 并发处理图片和视频
|
||||
await Promise.all([
|
||||
...photos.map(photo => limit(() => processPhoto(photo))),
|
||||
...videos.map(video => limit(() => processVideo(video)))
|
||||
]);
|
||||
|
||||
return results;
|
||||
} catch (error) {
|
||||
|
||||
@ -57,7 +57,7 @@ export default function UserInfo({ userInfo }: { userInfo: UserInfoDetails }) {
|
||||
{userInfo?.user_info?.avatar_file_url
|
||||
?
|
||||
<Image
|
||||
source={{ uri: "http://cdn.fairclip.cn/files/7348942720074911745/original_1752124481039_198d7b9a428c67f2bfd87ec128daad1b.jpg" }}
|
||||
source={{ uri: userInfo?.user_info?.avatar_file_url }}
|
||||
style={{ width: 80, height: 80, borderRadius: 40 }}
|
||||
/>
|
||||
:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user