tiefen_space_h5/utils/upload.js

427 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import baseRequest from "./baseRequest";
import CryptoJS from "crypto-js";
import { Toast } from "antd-mobile";
import { generateSignature } from "@/utils/crypto";
import { generateVideoThumbnails } from "@rajesh896/video-thumbnails-generator";
//获取auth
async function getAuth(mtype) {
const base = baseRequest();
const signature = generateSignature({
mtype: mtype,
...base,
});
try {
const response = await fetch(`/api/media/auth?signature=${signature}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mtype: mtype,
...base,
}),
});
const data = await response.json();
if (data.ret === -1) {
Toast.show({
content: data.msg,
});
return;
}
return data.data.policy_token;
} catch (error) {
// console.error(error);
}
}
//计算媒体参数
async function calculateFileMetadata(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => {
try {
const fileData = event.target.result;
const wordArray = CryptoJS.lib.WordArray.create(fileData);
const md5Hash = CryptoJS.MD5(wordArray).toString();
if (typeof window == "undefined") return;
const mediaElement = document.createElement(
file.type.indexOf("image/") != -1 ? "img" : "video"
);
mediaElement.src = URL.createObjectURL(file);
mediaElement.addEventListener(
file.type.indexOf("image/") != -1 ? "load" : "loadedmetadata",
() => {
const metadata = {
md5Hash,
width: mediaElement.width || 0,
height: mediaElement.height || 0,
duration: mediaElement.duration || 0,
};
resolve(metadata);
}
);
mediaElement.addEventListener("error", () => {
const metadata = {
md5Hash,
width: 0,
height: 0,
duration: 0,
};
resolve(metadata);
});
} catch (error) {
reject(error);
}
};
reader.onerror = (error) => {
reject(error);
};
file.type?.indexOf("image/") != -1
? reader.readAsDataURL(file)
: reader.readAsArrayBuffer(file);
});
}
//计算视频封面参数
async function calculateCoverMetadata(file) {
return new Promise((resolve, reject) => {
try {
const pureBase64String = file.replace(
/^data:image\/(png|jpg|jpeg|gif);base64,/,
""
);
const binaryString = atob(pureBase64String);
const binaryData = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
binaryData[i] = binaryString.charCodeAt(i);
}
const wordArray = CryptoJS.lib.WordArray.create(binaryData);
const md5Hash = CryptoJS.MD5(wordArray).toString();
const image = new Image();
image.src = `data:image/jpeg;base64,${pureBase64String}`;
image.onload = () => {
const metadata = {
md5Hash,
width: image.width || 0,
height: image.height || 0,
duration: image.duration || 0,
};
resolve(metadata);
};
image.onerror = () => {
const metadata = {
md5Hash,
width: 0,
height: 0,
};
resolve(metadata);
};
} catch (error) {
reject(error);
}
});
}
function atob(base64) {
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var o1,
o2,
o3,
h1,
h2,
h3,
h4,
bits,
i = 0,
ac = 0,
dec = "",
tmp_arr = [];
if (!base64) {
return base64;
}
base64 += "";
do {
// unpack four hexets into three bytes using index points in b64
h1 = b64.indexOf(base64.charAt(i++));
h2 = b64.indexOf(base64.charAt(i++));
h3 = b64.indexOf(base64.charAt(i++));
h4 = b64.indexOf(base64.charAt(i++));
bits = (h1 << 18) | (h2 << 12) | (h3 << 6) | h4;
o1 = (bits >> 16) & 0xff;
o2 = (bits >> 8) & 0xff;
o3 = bits & 0xff;
if (h3 == 64) {
tmp_arr[ac++] = String.fromCharCode(o1);
} else if (h4 == 64) {
tmp_arr[ac++] = String.fromCharCode(o1, o2);
} else {
tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
}
} while (i < base64.length);
dec = tmp_arr.join("");
return dec;
}
//获取上传失败时返回的id
async function getFailId() {
const base = await baseRequest();
const signature = await generateSignature({
...base,
});
try {
const response = await fetch(
`/api/upload_media_fail_config/list?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...base,
}),
}
);
const data = await response.json();
if (data.ret === -1) {
Toast.show({
icon: "fail",
content: data.msg,
position: "top",
});
return;
}
return data.data;
} catch (e) {
// console.warn(e);
}
}
//上传单张图片
export async function uploadImage(asset, h, w) {
const auth = await getAuth(1);
try {
const formData = new FormData();
formData.append("name", auth.filename);
formData.append("policy", auth.policy);
formData.append("OSSAccessKeyId", auth.access_key_id);
formData.append("success_action_status", "200");
formData.append("signature", auth.signature);
formData.append("key", auth.directory + "/" + auth.filename);
formData.append("file", asset);
const uploadResponse = await fetch(auth.host, {
method: "POST",
body: formData,
});
if (uploadResponse.status === 200) {
const info = await calculateFileMetadata(asset);
const item = {
src_id: auth.directory + "/" + auth.filename,
md5: info.md5Hash,
h: h || info.height,
w: h || info.height,
fmt: asset.type,
};
const base = baseRequest();
const response = await fetch(`/api/media/c_upload`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mtype: 1,
item: item,
...base,
}),
});
const data = await response.json();
if (data.ret === -1) {
Toast.show({
content: data.msg,
});
return;
}
return data.data.ret_item.id;
} else {
Toast.show({
content: "上传图片失败",
});
}
} catch (error) {
// console.log("Error occurred while getting or uploading data:", error);
}
}
//上传视频封面
export async function uploadVideoCover(asset) {
const auth = await getAuth(1);
function base64toFile(base64Data) {
//去掉base64的头部信息并转换为byte
let split = base64Data.split(",");
let bytes = window.atob(split[1]);
//获取文件类型
let fileType = split[0].match(/:(.*?);/)[1];
//处理异常,将ascii码小于0的转换为大于0
let ab = new ArrayBuffer(bytes.length);
let ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
return new Blob([ab], { type: fileType });
}
const cover = await generateVideoThumbnails(asset, 1);
const blobFile = base64toFile(cover[0]);
try {
const formData = new FormData();
formData.append("name", auth.filename);
formData.append("policy", auth.policy);
formData.append("OSSAccessKeyId", auth.access_key_id);
formData.append("success_action_status", "200");
formData.append("signature", auth.signature);
formData.append("key", auth.directory + "/" + auth.filename);
formData.append("file", blobFile);
const uploadResponse = await fetch(auth.host, {
method: "POST",
body: formData,
});
if (uploadResponse.status === 200) {
const info = await calculateCoverMetadata(cover[0]);
const item = {
src_id: auth.directory + "/" + auth.filename,
md5: info.md5Hash,
h: info.height,
w: info.width,
fmt: blobFile.type,
};
const base = baseRequest();
const response = await fetch("/api/media/c_upload", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mtype: 1,
item: item,
...base,
}),
});
const data = await response.json();
if (data.ret === -1) {
alert(data.msg);
return;
}
return data.data.ret_item.id;
} else {
alert("上传图片失败");
}
} catch (error) {
// console.log("Error occurred while getting or uploading data:", error);
}
}
//上传单个视频
export async function uploadVideo(asset) {
const auth = await getAuth(2);
try {
const formData = new FormData();
formData.append("name", auth.filename);
formData.append("policy", auth.policy);
formData.append("OSSAccessKeyId", auth.access_key_id);
formData.append("success_action_status", "200");
formData.append("signature", auth.signature);
formData.append("key", auth.directory + "/" + auth.filename);
formData.append("file", asset);
const uploadResponse = await fetch(auth.host, {
method: "POST",
body: formData,
});
if (uploadResponse.status === 200) {
const videoCoverId = await uploadVideoCover(asset);
const info = await calculateFileMetadata(asset);
const item = {
src_id: auth.directory + "/" + auth.filename,
cover_id: videoCoverId,
md5: info.md5Hash,
fmt: asset?.type,
dur: info?.duration,
};
const base = baseRequest();
const response = await fetch(`/api/media/c_upload`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mtype: 2,
item: item,
...base,
}),
});
const data = await response.json();
if (data.ret === -1) {
Toast.show({
icon: "fail",
content: data.msg,
position: "top",
});
return;
}
return data.data.ret_item.id;
} else {
Toast.show({
icon: "fail",
content: "上传视频失败",
position: "top",
});
const failId = await getFailId();
return failId?.video_id_for_upload_fail;
}
} catch (error) {
// console.log("Error occurred while getting or uploading data:", error);
Toast.show({
icon: "fail",
content: "上传视频失败",
position: "top",
});
const failId = await getFailId();
return failId?.video_id_for_upload_fail;
}
}
//上传多个图片
export async function multiUploadImage(assets, type) {
let ids = { image_ids: [], video_ids: [] };
await Promise.all(
assets.map(async (asset) => {
if (type == 1) {
const id = await uploadImage(asset);
ids.image_ids.push(id);
} else {
const id = await uploadVideo(asset);
id && ids.video_ids.push(id);
}
})
);
return ids;
}