123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- import JSZip from 'jszip';
- import { s8 } from './random';
- import axios from 'axios';
- import CryptoJS from 'crypto-js';
- import { deepClone } from '@meta2d/core';
- export const MESH_SUFFIXES = ['.glb', '.l3db'];
- export const TEMPLATE_SUFFIXES = ['.l3dm'];
- export const IMAGE_SUFFIXES = ['.png', '.jpg', '.jpeg', '.svg', '.bmp', '.gif'];
- export const HDR_SUFFIXES = ['.hdr', '.dds', '.env'];
- export async function load3d(zip: JSZip, key: string) {
- const _filename = key.split('/')[0];
- const dataStr = await zip.file(key).async('string');
- const { data, map } = JSON.parse(dataStr);
- const newUrlMap: { [oldUrl: string]: string } = {};
- await Promise.all(
- Object.keys(map).map(async (url) => {
- try {
- const file = await zip
- .file(_filename + '/files/' + map[url])
- ?.async('arraybuffer');
- if (file) {
- const names = filename(url, true).split('.');
- names.splice(-1, 0, s8());
- const name = names.join('.');
- const newFile = new File([file], name);
- const suffix = '.' + names[names.length - 1];
- let directory = '';
- let type = '';
- let tags = '';
- if (MESH_SUFFIXES.includes(suffix)) {
- directory = '/3D/模型/未分类';
- type = '3D模型';
- tags = '我的模型';
- } else if (TEMPLATE_SUFFIXES.includes(suffix)) {
- directory = '/3D/面板/未分类';
- type = 'L3DM';
- tags = '我的面板';
- } else if (IMAGE_SUFFIXES.includes(suffix)) {
- directory = '/3D/图片/未分类';
- type = '图片';
- tags = '我的图片';
- } else if (HDR_SUFFIXES.includes(suffix)) {
- directory = '/3D/HDR/未分类';
- type = 'HDR';
- tags = '我的HDR';
- }
- if (directory) {
- const res:any = await uploadFile({
- file: newFile,
- directory,
- type,
- tags,
- });
- if (res) {
- newUrlMap[url] = res.url;
- // uploaded++;
- return;
- }
- }
- }
- // failed++;
- } catch (e) {
- // failed++;
- } finally {
- }
- })
- );
- const newData = meta3dReplaceUrl(data, newUrlMap);
- //上传
- const projectData = meta3dCrypto(JSON.stringify(newData));
- const res: any = await axios.post('/api/data/3d/add', {
- data: {
- data: projectData,
- scenes: [],
- updatedCount: 1,
- },
- image: 'xxx',
- name: newData.name,
- });
- if (res) {
- return res.id;
- } else {
- return '';
- }
- }
- export function s16() {
- let chars = [
- '0',
- '1',
- '2',
- '3',
- '4',
- '5',
- '6',
- '7',
- '8',
- '9',
- 'A',
- 'B',
- 'C',
- 'D',
- 'E',
- 'F',
- 'G',
- 'H',
- 'I',
- 'J',
- 'K',
- 'L',
- 'M',
- 'N',
- 'O',
- 'P',
- 'Q',
- 'R',
- 'S',
- 'T',
- 'U',
- 'V',
- 'W',
- 'X',
- 'Y',
- 'Z',
- 'a',
- 'b',
- 'c',
- 'd',
- 'e',
- 'f',
- 'g',
- 'h',
- 'i',
- 'j',
- 'k',
- 'l',
- 'm',
- 'n',
- 'o',
- 'p',
- 'q',
- 'r',
- 's',
- 't',
- 'u',
- 'v',
- 'w',
- 'x',
- 'y',
- 'z',
- ];
- let strs = '';
- for (let i = 0; i < 16; i++) {
- let id = Math.ceil(Math.random() * 61);
- strs += chars[id];
- }
- return strs;
- }
- const a = (word: string, k: string, i: string) => {
- let srcs = CryptoJS.enc.Utf8.parse(word);
- let encrypted = CryptoJS.AES.encrypt(srcs, CryptoJS.enc.Utf8.parse(k), {
- iv: CryptoJS.enc.Utf8.parse(i),
- mode: CryptoJS.mode.CBC,
- padding: CryptoJS.pad.Pkcs7,
- });
- return encrypted.ciphertext.toString().toUpperCase();
- };
- const c = (word: string): string => {
- const k = s16().toUpperCase();
- const i = s16().toUpperCase();
- const d = a(word, k, i);
- return k + d + i;
- };
- const meta3dCrypto = (data: string) => {
- return c(data);
- };
- export const getUrlWithoutSearch = (url: string) => {
- return url.split('?')[0];
- };
- export function filename(str: string, withSuffix = false) {
- const paths = getUrlWithoutSearch(str).split('/');
- const name = paths[paths.length - 1];
- if (withSuffix) {
- return name;
- }
- const i = name.lastIndexOf('.');
- if (i === -1) {
- return name;
- }
- return name.substring(0, i);
- }
- export const uploadFile = async (info: {
- file: File;
- directory: string;
- type: UploadFileType;
- tags?: string;
- remarks?: string;
- name?: string;
- }) => {
- const { file, directory, type, tags = '', remarks = '', name = '' } = info;
- const formData = new FormData();
- formData.append('file', file);
- formData.append('directory', directory);
- formData.append('type', type);
- formData.append('tags', tags);
- formData.append('remarks', remarks);
- formData.append('shared', 'true');
- if (name) {
- formData.append('name', name);
- }
- const res = (await axios.post(
- '/api/file/upload',
- formData
- )) as ResponseResult<FileData>;
- if (res.error) {
- }
- return res;
- };
- export type UploadFileType =
- | '文档'
- | '图片'
- | '3D模型'
- | '视频'
- | '音乐'
- | '其他'
- | string;
- export interface ResponseResult<T> {
- success: boolean;
- data?: T;
- error?: string;
- detail?: string;
- }
- export interface FileData {
- createdAt: string;
- directory: string;
- fullname: string;
- id: string;
- name: string;
- ownerId: string;
- ownerName: string;
- shared: boolean;
- size: number;
- tags: string[];
- type: UploadFileType;
- updatedAt: string;
- url: string;
- }
- const b = (word: string, k: string, i: string) => {
- let encryptedHexStr = CryptoJS.enc.Hex.parse(word);
- let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
- let decrypt = CryptoJS.AES.decrypt(srcs, CryptoJS.enc.Utf8.parse(k), {
- iv: CryptoJS.enc.Utf8.parse(i),
- mode: CryptoJS.mode.CBC,
- padding: CryptoJS.pad.Pkcs7,
- });
- let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
- return decryptedStr.toString();
- };
- const d = (word: string): string => {
- const k = word.substring(0, 16);
- const i = word.substring(word.length - 16);
- return b(word.substring(16, word.length - 16), k, i);
- };
- const parseData = (data: Partial<any> | string): Partial<any> => {
- if (typeof data === 'string') {
- data = data.startsWith('{') ? data : d(data);
- return JSON.parse(data);
- }
- return data;
- };
- export function filepath(str: string) {
- const paths = str.split('/');
- paths[paths.length - 1] = '';
- return paths.join('/');
- }
- const meta3dReplaceUrl = (
- data: any | string,
- urlMap: { [url: string]: string }
- ) => {
- const _data = parseData(data);
- const { scenes } = _data;
- const transUrl = (url: string): string => {
- if (url in urlMap) {
- return urlMap[url];
- }
- return url;
- };
- for (const sceneData of scenes) {
- if (!sceneData) {
- continue;
- }
- const {
- nodes = [],
- scene = {},
- glbMap = {},
- textures = {},
- materials = {},
- DOMDatas = [],
- } = sceneData;
- Object.keys(glbMap).forEach((glbId) => {
- const { url, name } = glbMap[glbId];
- const fullUrl = url + name;
- if (fullUrl in urlMap) {
- glbMap[glbId].url = filepath(urlMap[fullUrl]);
- glbMap[glbId].name = filename(urlMap[fullUrl], true);
- }
- });
- for (const node of [
- scene,
- ...nodes,
- ...DOMDatas,
- ...Object.keys(materials).map((id) => materials[id]),
- ...Object.keys(textures).map((id) => textures[id]),
- ]) {
- convertResourceAddress(node, transUrl);
- }
- }
- return _data;
- };
- const urlProps = [
- 'url',
- 'imageSource',
- 'skyboxUrl',
- 'hdrUrl',
- 'colorGradingTexture',
- 'source',
- 'backgroundImage',
- ];
- function convertResourceAddress(
- data: any,
- transFn: (url: string) => any,
- reset = true
- ) {
- for (const urlProp of urlProps) {
- if (urlProp in data === false) {
- continue;
- }
- const url = data[urlProp] || '';
- const newUrl = transFn(url);
- if (reset) {
- data[urlProp] = newUrl;
- }
- }
- if (data.contents) {
- data.contents.forEach((content: any) =>
- convertResourceAddress(content, transFn, reset)
- );
- }
- if (data.__initOption) {
- convertResourceAddress(data.__initOption, transFn, reset);
- }
- if (data.children) {
- data.children.forEach((child: any) =>
- convertResourceAddress(child, transFn, reset)
- );
- }
- }
|