mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-05-30 18:39:18 +08:00
1. 编辑器扩展 - 自动生成框架模板功能
2. 编辑器扩展 - Tinypng 纹理压缩功能
This commit is contained in:
80
src/assets-menu.ts
Normal file
80
src/assets-menu.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { AssetInfo } from "../@types/packages/asset-db/@types/public";
|
||||
import { compress } from "./tinypng";
|
||||
|
||||
/** 资源栏右键菜单 */
|
||||
export function onAssetMenu(assetInfo: AssetInfo) {
|
||||
return [
|
||||
{
|
||||
label: 'i18n:oops-framework.name',
|
||||
submenu: [
|
||||
{
|
||||
label: `i18n:oops-framework.script`,
|
||||
submenu: [
|
||||
{
|
||||
label: `i18n:oops-framework.createGameComponent`,
|
||||
async click() {
|
||||
localStorage.setItem('create_path', assetInfo.file);
|
||||
localStorage.setItem('create_type', "GameComponent");
|
||||
Editor.Panel.open("oops-framework.set_file_name");
|
||||
},
|
||||
},
|
||||
{
|
||||
type: `separator`,
|
||||
},
|
||||
{
|
||||
label: `i18n:oops-framework.createModule`,
|
||||
click() {
|
||||
localStorage.setItem('create_path', assetInfo.file);
|
||||
localStorage.setItem('create_type', "Module");
|
||||
Editor.Panel.open("oops-framework.set_file_name");
|
||||
},
|
||||
},
|
||||
{
|
||||
label: `i18n:oops-framework.createModel`,
|
||||
click() {
|
||||
localStorage.setItem('create_path', assetInfo.file);
|
||||
localStorage.setItem('create_type', "Model");
|
||||
Editor.Panel.open("oops-framework.set_file_name");
|
||||
},
|
||||
},
|
||||
{
|
||||
label: `i18n:oops-framework.createBll`,
|
||||
click() {
|
||||
localStorage.setItem('create_path', assetInfo.file);
|
||||
localStorage.setItem('create_type', "Bll");
|
||||
Editor.Panel.open("oops-framework.set_file_name");
|
||||
},
|
||||
},
|
||||
{
|
||||
label: `i18n:oops-framework.createView`,
|
||||
click() {
|
||||
localStorage.setItem('create_path', assetInfo.file);
|
||||
localStorage.setItem('create_type', "View");
|
||||
Editor.Panel.open("oops-framework.set_file_name");
|
||||
},
|
||||
},
|
||||
{
|
||||
label: `i18n:oops-framework.createViewMvvm`,
|
||||
click() {
|
||||
localStorage.setItem('create_path', assetInfo.file);
|
||||
localStorage.setItem('create_type', "ViewMvvm");
|
||||
Editor.Panel.open("oops-framework.set_file_name");
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: `i18n:oops-framework.tools`,
|
||||
submenu: [
|
||||
{
|
||||
label: `i18n:oops-framework.tools_compress`,
|
||||
click() {
|
||||
compress(assetInfo.file);
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
];
|
||||
};
|
||||
135
src/create-script.ts
Normal file
135
src/create-script.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import { existsSync } from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
/** 写入文件 */
|
||||
export function createView(directoryPath: string, fileName: string, content: string, isEcsComp: boolean = true): Promise<void> {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
// 创建脚本
|
||||
let className = fileName + "View";
|
||||
let scriptUrl = "";
|
||||
if (isEcsComp) {
|
||||
scriptUrl = path.join(directoryPath, fileName) + "ViewComp.ts";
|
||||
}
|
||||
else {
|
||||
scriptUrl = path.join(directoryPath, fileName) + "View.ts";
|
||||
}
|
||||
|
||||
if (!existsSync(scriptUrl)) {
|
||||
content = content.replace(/<%Name%>/g, className);
|
||||
await Editor.Message.request('asset-db', 'create-asset', scriptUrl, content);
|
||||
}
|
||||
|
||||
// 创建预制
|
||||
let prefabUrl = path.join(directoryPath, fileName) + ".prefab";
|
||||
if (!existsSync(prefabUrl)) {
|
||||
if (isEcsComp) className = className + "Comp";
|
||||
await Editor.Message.request('scene', 'execute-scene-script', {
|
||||
name: "oops-framework",
|
||||
method: 'createPrefab',
|
||||
args: [fileName, className, prefabUrl]
|
||||
});
|
||||
}
|
||||
|
||||
// 闪烁提示新创建的脚本文件
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
|
||||
// 打开脚本
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
|
||||
// 打开预制
|
||||
Editor.Message.request('asset-db', 'open-asset', prefabUrl);
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function createScriptModule(directoryPath: string, fileName: string, content: string): Promise<void> {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
// 创建目录
|
||||
let pathName = fileName.toLowerCase();
|
||||
let pathModule = path.join(directoryPath, pathName);
|
||||
if (!existsSync(pathModule)) {
|
||||
await Editor.Message.request('asset-db', 'create-asset', pathModule, null);
|
||||
}
|
||||
|
||||
let subPathView = path.join(pathModule, "view");
|
||||
if (!existsSync(subPathView)) {
|
||||
await Editor.Message.request('asset-db', 'create-asset', subPathView, null);
|
||||
}
|
||||
|
||||
let subPathBll = path.join(pathModule, "bll");
|
||||
if (!existsSync(subPathBll)) {
|
||||
await Editor.Message.request('asset-db', 'create-asset', subPathBll, null);
|
||||
}
|
||||
|
||||
let subPathModel = path.join(pathModule, "model");
|
||||
if (!existsSync(subPathModel)) {
|
||||
await Editor.Message.request('asset-db', 'create-asset', subPathModel, null);
|
||||
}
|
||||
|
||||
// 创建脚本
|
||||
let scriptUrl = path.join(pathModule, fileName) + ".ts";
|
||||
if (!existsSync(scriptUrl)) {
|
||||
content = content.replace(/<%Name%>/g, fileName);
|
||||
await Editor.Message.request('asset-db', 'create-asset', scriptUrl, content);
|
||||
}
|
||||
|
||||
// 闪烁提示新创建的脚本文件
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
|
||||
// 打开脚本
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建脚本 */
|
||||
export function createScriptBll(directoryPath: string, fileName: string, content: string, moduleName: string): Promise<void> {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
let scriptUrl = path.join(directoryPath, fileName) + ".ts";
|
||||
|
||||
// 创建脚本
|
||||
if (!existsSync(scriptUrl)) {
|
||||
content = content.replace(/<%Name%>/g, fileName);
|
||||
content = content.replace(/<%ModuleName%>/g, moduleName);
|
||||
await Editor.Message.request('asset-db', 'create-asset', scriptUrl, content);
|
||||
}
|
||||
|
||||
// 闪烁提示新创建的脚本文件
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
|
||||
// 打开脚本
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建业务层脚本 */
|
||||
export function createScript(directoryPath: string, fileName: string, content: string, isEcsComp: boolean = true): Promise<void> {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
let scriptUrl = "";
|
||||
if (isEcsComp) {
|
||||
scriptUrl = path.join(directoryPath, fileName) + "Comp.ts";
|
||||
}
|
||||
else {
|
||||
scriptUrl = path.join(directoryPath, fileName) + ".ts";
|
||||
}
|
||||
|
||||
// 创建脚本
|
||||
if (!existsSync(scriptUrl)) {
|
||||
content = content.replace(/<%Name%>/g, fileName);
|
||||
await Editor.Message.request('asset-db', 'create-asset', scriptUrl, content);
|
||||
}
|
||||
|
||||
// 闪烁提示新创建的脚本文件
|
||||
Editor.Message.send('assets', 'twinkle', scriptUrl);
|
||||
|
||||
// 打开脚本
|
||||
Editor.Message.request('asset-db', 'open-asset', scriptUrl);
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
119
src/default/index.ts
Normal file
119
src/default/index.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { readFileSync } from 'fs-extra';
|
||||
import { join } from 'path';
|
||||
import { App, createApp } from 'vue';
|
||||
import { createScript, createScriptBll, createScriptModule, createView } from '../create-script';
|
||||
import { TemplateGameComponent } from '../template/GameComponent';
|
||||
import { TemplateModule } from '../template/Module';
|
||||
import { TemplateBll } from '../template/ModuleBll';
|
||||
import { TemplateModel } from '../template/ModuleModel';
|
||||
import { TemplateView } from '../template/ModuleView';
|
||||
import { TemplateViewMvvm } from '../template/ModuleViewVM';
|
||||
|
||||
const panelDataMap = new WeakMap<any, App>();
|
||||
|
||||
module.exports = Editor.Panel.define({
|
||||
listeners: {
|
||||
show() { console.log('show'); },
|
||||
hide() { console.log('hide'); },
|
||||
},
|
||||
template: readFileSync(join(__dirname, '../../static/template/default/index.html'), 'utf-8'),
|
||||
style: readFileSync(join(__dirname, '../../static/style/default/index.css'), 'utf-8'),
|
||||
$: {
|
||||
app: '#app',
|
||||
},
|
||||
ready() {
|
||||
let filename = "Default";
|
||||
let type = localStorage.getItem('create_type')!;
|
||||
localStorage.removeItem('create_type');
|
||||
let path = localStorage.getItem('create_path')!;
|
||||
localStorage.removeItem('create_path');
|
||||
let title = "???";
|
||||
let showModule = false;
|
||||
let moduleName = "ModuleName";
|
||||
|
||||
switch (type) {
|
||||
case "GameComponent":
|
||||
title = `i18n:oops-framework.createGameComponent`;
|
||||
break;
|
||||
case "Module":
|
||||
title = `i18n:oops-framework.createModule`;
|
||||
break;
|
||||
case "Model":
|
||||
title = `i18n:oops-framework.createModel`;
|
||||
break;
|
||||
case "Bll":
|
||||
title = `i18n:oops-framework.createBll`;
|
||||
showModule = true;
|
||||
break;
|
||||
case "View":
|
||||
title = `i18n:oops-framework.createView`;
|
||||
break;
|
||||
case "ViewMvvm":
|
||||
title = `i18n:oops-framework.createViewMvvm`;
|
||||
break;
|
||||
}
|
||||
|
||||
// 创建框架配置界面
|
||||
if (this.$.app) {
|
||||
const app = createApp({});
|
||||
app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('ui-');
|
||||
app.component('MyConfig', {
|
||||
template: readFileSync(join(__dirname, '../../static/template/vue/set_file_name.html'), 'utf-8'),
|
||||
data() {
|
||||
return {
|
||||
title: title,
|
||||
filename: filename,
|
||||
showModule: showModule
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 记录输入的文件名
|
||||
onInputName(event: any) {
|
||||
filename = event.target.value;
|
||||
},
|
||||
onModuleName(event: any) {
|
||||
moduleName = event.target.value;
|
||||
},
|
||||
// 创建文件
|
||||
async onConfirm() {
|
||||
if (filename.trim().length == 0) {
|
||||
await Editor.Dialog.info('请输入文件名');
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case "GameComponent":
|
||||
await createView(path, filename, TemplateGameComponent, false);
|
||||
break;
|
||||
case "Module":
|
||||
await createScriptModule(path, filename, TemplateModule);
|
||||
break;
|
||||
case "Model":
|
||||
await createScript(path, filename, TemplateModel);
|
||||
break;
|
||||
case "Bll":
|
||||
await createScriptBll(path, filename, TemplateBll, moduleName);
|
||||
break;
|
||||
case "View":
|
||||
await createView(path, filename, TemplateView);
|
||||
break;
|
||||
case "ViewMvvm":
|
||||
await createView(path, filename, TemplateViewMvvm);
|
||||
break;
|
||||
}
|
||||
close();
|
||||
}
|
||||
},
|
||||
});
|
||||
app.mount(this.$.app);
|
||||
panelDataMap.set(this, app);
|
||||
}
|
||||
},
|
||||
beforeClose() { },
|
||||
close() {
|
||||
const app = panelDataMap.get(this);
|
||||
if (app) {
|
||||
app.unmount();
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -46,5 +46,5 @@ export const methods: { [key: string]: (...any: any) => any } = {
|
||||
/** 点亮 Github 星星 */
|
||||
github() {
|
||||
shell.openExternal('https://github.com/dgflash/oops-framework');
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
36
src/scene.ts
Normal file
36
src/scene.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
export function load() { }
|
||||
|
||||
export function unload() { }
|
||||
|
||||
// 在其他扩展脚本中,我们可以使用如下代码调用 rotateCamera 函数
|
||||
// const options: ExecuteSceneScriptMethodOptions = {
|
||||
// name: scene.ts 所在的扩展包名, 如: App,
|
||||
// method: scene.ts 中定义的方法, 如: createPrefab,
|
||||
// args: 参数,可选, 只传递json
|
||||
// };
|
||||
// const result = await Editor.Message.request('scene', 'execute-scene-script', options);
|
||||
export const methods = {
|
||||
/** 创建视图层制 */
|
||||
async createPrefab(fileName: string, className: string, prefabUrl: string) {
|
||||
const { Node, js, Layers } = require('cc');
|
||||
const node = new Node(fileName);
|
||||
node.layer = Layers.Enum.UI_2D;
|
||||
|
||||
while (true) {
|
||||
const result = js.getClassByName(className);
|
||||
if (result) break;
|
||||
|
||||
await new Promise((next) => {
|
||||
setTimeout(next, 100);
|
||||
});
|
||||
}
|
||||
|
||||
const com = node.addComponent(className);
|
||||
com.resetInEditor && com.resetInEditor();
|
||||
|
||||
const info = cce.Prefab.generatePrefabDataFromNode(node) as any;
|
||||
node.destroy();
|
||||
|
||||
return Editor.Message.request('asset-db', 'create-asset', prefabUrl, info.prefabData || info);
|
||||
}
|
||||
};
|
||||
12
src/template/GameComponent.ts
Normal file
12
src/template/GameComponent.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export const TemplateGameComponent = `import { _decorator } from 'cc';
|
||||
import { GameComponent } from "db://oops-framework/module/common/GameComponent";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/** 显示对象控制 */
|
||||
@ccclass('<%Name%>')
|
||||
export class <%Name%> extends GameComponent {
|
||||
protected start() {
|
||||
|
||||
}
|
||||
}`;
|
||||
19
src/template/Module.ts
Normal file
19
src/template/Module.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export const TemplateModule = `import { ecs } from "db://oops-framework/libs/ecs/ECS";
|
||||
|
||||
/** <%Name%> 模块 */
|
||||
@ecs.register('<%Name%>')
|
||||
export class <%Name%> extends ecs.Entity {
|
||||
/** ---------- 数据层 ---------- */
|
||||
// <%Name%>Model!: <%Name%>ModelComp;
|
||||
|
||||
/** ---------- 业务层 ---------- */
|
||||
// <%Name%>Bll!: <%Name%>BllComp;
|
||||
|
||||
/** ---------- 视图层 ---------- */
|
||||
// <%Name%>View!: <%Name%>ViewComp;
|
||||
|
||||
/** 初始添加的数据层组件 */
|
||||
protected init() {
|
||||
// this.addComponents<ecs.Comp>();
|
||||
}
|
||||
}`;
|
||||
24
src/template/ModuleBll.ts
Normal file
24
src/template/ModuleBll.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
export const TemplateBll = `import { ecs } from "db://oops-framework/libs/ecs/ECS";
|
||||
|
||||
/** 业务输入参数 */
|
||||
@ecs.register('<%Name%>')
|
||||
export class <%Name%>Comp extends ecs.Comp {
|
||||
/** 业务层组件移除时,重置所有数据为默认值 */
|
||||
reset() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** 业务逻辑处理对象 */
|
||||
@ecs.register('<%ModuleName%>')
|
||||
export class <%Name%>System extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {
|
||||
filter(): ecs.IMatcher {
|
||||
return ecs.allOf(<%Name%>Comp);
|
||||
}
|
||||
|
||||
entityEnter(e: ecs.Entity): void {
|
||||
// 注:自定义业务逻辑
|
||||
|
||||
e.remove(<%Name%>Comp);
|
||||
}
|
||||
}`;
|
||||
12
src/template/ModuleModel.ts
Normal file
12
src/template/ModuleModel.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export const TemplateModel = `import { ecs } from "db://oops-framework/libs/ecs/ECS";
|
||||
|
||||
/** 数据层对象 */
|
||||
@ecs.register('<%Name%>')
|
||||
export class <%Name%>Comp extends ecs.Comp {
|
||||
id: number = -1;
|
||||
|
||||
/** 数据层组件移除时,重置所有数据为默认值 */
|
||||
reset() {
|
||||
this.id = -1;
|
||||
}
|
||||
}`;
|
||||
20
src/template/ModuleView.ts
Normal file
20
src/template/ModuleView.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export const TemplateView = `import { _decorator } from "cc";
|
||||
import { ecs } from "db://oops-framework/libs/ecs/ECS";
|
||||
import { CCComp } from "db://oops-framework/module/common/CCComp";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/** 视图层对象 */
|
||||
@ccclass('<%Name%>Comp')
|
||||
@ecs.register('<%Name%>', false)
|
||||
export class <%Name%>Comp extends CCComp {
|
||||
/** 视图层逻辑代码分离演示 */
|
||||
start() {
|
||||
// const entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象
|
||||
}
|
||||
|
||||
/** 视图对象通过 ecs.Entity.remove(<%Name%>Comp) 删除组件是触发组件处理自定义释放逻辑 */
|
||||
reset() {
|
||||
this.node.destroy();
|
||||
}
|
||||
}`;
|
||||
23
src/template/ModuleViewVM.ts
Normal file
23
src/template/ModuleViewVM.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
export const TemplateViewMvvm = `import { _decorator } from "cc";
|
||||
import { ecs } from "db://oops-framework/libs/ecs/ECS";
|
||||
import { CCVMParentComp } from "db://oops-framework/module/common/CCVMParentComp";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/** 视图层对象 - 支持 MVVM 框架的数据绑定 */
|
||||
@ccclass('<%Name%>Comp')
|
||||
@ecs.register('<%Name%>', false)
|
||||
export class <%Name%>Comp extends CCVMParentComp {
|
||||
/** 脚本控制的界面 MVVM 框架绑定数据 */
|
||||
data: any = {};
|
||||
|
||||
/** 视图层逻辑代码分离演示 */
|
||||
start() {
|
||||
// const entity = this.ent as ecs.Entity; // ecs.Entity 可转为当前模块的具体实体对象
|
||||
}
|
||||
|
||||
/** 视图对象通过 ecs.Entity.remove(<%Name%>Comp) 删除组件是触发组件处理自定义释放逻辑 */
|
||||
reset() {
|
||||
this.node.destroy();
|
||||
}
|
||||
}`
|
||||
159
src/tinypng.ts
Normal file
159
src/tinypng.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import fs from 'fs';
|
||||
import https from 'https';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
|
||||
const exts = ['.png', '.jpg', '.jpeg'];
|
||||
const max = 5200000;
|
||||
const options: any = {
|
||||
method: 'POST',
|
||||
hostname: 'tinypng.com',
|
||||
path: '/backend/opt/shrink',
|
||||
headers: {
|
||||
rejectUnauthorized: 'false',
|
||||
'Postman-Token': Date.now(),
|
||||
'Cache-Control': 'no-cache',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
|
||||
}
|
||||
};
|
||||
|
||||
export function compress(filePath: string): void {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.log(`路径不存在:${filePath}`);
|
||||
return;
|
||||
}
|
||||
const fileName = path.basename(filePath);
|
||||
if (!fs.statSync(filePath).isDirectory()) {
|
||||
if (exts.includes(path.extname(filePath))) {
|
||||
console.log(`[${fileName}] 压缩中...`);
|
||||
fileTinyUpload(filePath)
|
||||
.then(data => {
|
||||
console.log(`[1/1] [${fileName}] 压缩成功,原始: ${toSize(data.input.size)},压缩: ${toSize(data.output.size)},压缩比: ${toPercent(data.output.ratio)}`);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(`[1/1] [${fileName}] 压缩失败!报错:${err}`);
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.log(`[${fileName}] 压缩失败!报错:只支持 png、jpg 与 jpeg 格式`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
let totalCount = 0;
|
||||
let processedCount = 0;
|
||||
fileEach(filePath, (filePathInDir) => {
|
||||
totalCount++;
|
||||
const relativePath = path.relative(filePath, filePathInDir);
|
||||
fileTinyUpload(filePathInDir)
|
||||
.then(data => {
|
||||
console.log(`[${++processedCount}/${totalCount}] [${relativePath}] 压缩成功,原始: ${toSize(data.input.size)},压缩: ${toSize(data.output.size)},压缩比: ${toPercent(data.output.ratio)}`);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(`[${++processedCount}/${totalCount}] [${relativePath}] 压缩失败!报错:${err}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomIP(): string {
|
||||
return Array.from(Array(4)).map(() => Math.floor(255 * Math.random())).join('.');
|
||||
}
|
||||
|
||||
function fileEach(dir: string, callback: (filePath: string) => void): void {
|
||||
fs.readdir(dir, (err: any, files: any[]) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
files.forEach((file: any) => {
|
||||
const filePath = path.join(dir, file);
|
||||
fs.stat(filePath, (statErr: any, stats: { isDirectory: () => any; size: number; isFile: () => any; }) => {
|
||||
if (statErr) {
|
||||
console.error(statErr);
|
||||
return;
|
||||
}
|
||||
if (stats.isDirectory()) {
|
||||
fileEach(filePath, callback);
|
||||
}
|
||||
else {
|
||||
if (stats.size <= max && stats.isFile() && exts.includes(path.extname(file))) {
|
||||
callback(filePath);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function fileUpload(filePath: string): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
options.headers['X-Forwarded-For'] = getRandomIP();
|
||||
const req = https.request(options, (res: any) => {
|
||||
let data = '';
|
||||
res.on('data', (chunk: string) => {
|
||||
data += chunk;
|
||||
});
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const result = JSON.parse(data);
|
||||
if (result.error) {
|
||||
reject(result.message);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
} catch (parseErr) {
|
||||
reject(parseErr);
|
||||
}
|
||||
});
|
||||
});
|
||||
req.write(fs.readFileSync(filePath), 'binary');
|
||||
req.on('error', err => {
|
||||
reject(err);
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
function fileUpdate(filePath: string, data: any): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const urlObj = new url.URL(data.output.url);
|
||||
const req = https.request(urlObj, (res: any) => {
|
||||
let body = '';
|
||||
res.setEncoding('binary');
|
||||
res.on('data', (chunk: string) => {
|
||||
body += chunk;
|
||||
});
|
||||
res.on('end', () => {
|
||||
fs.writeFile(filePath, body, 'binary', (err: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
req.on('error', (err: any) => {
|
||||
reject(err);
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
function fileTinyUpload(filePath: string): Promise<any> {
|
||||
return fileUpload(filePath).then(data => fileUpdate(filePath, data));
|
||||
}
|
||||
|
||||
function toSize(size: number): string {
|
||||
if (size < 1024)
|
||||
return size + 'B';
|
||||
else if (size < 1048576)
|
||||
return (size / 1024).toFixed(2) + 'KB';
|
||||
else
|
||||
return (size / 1024 / 1024).toFixed(2) + 'MB';
|
||||
}
|
||||
|
||||
function toPercent(ratio: number): string {
|
||||
return (100 * ratio).toFixed(2) + '%';
|
||||
}
|
||||
Reference in New Issue
Block a user