Files
RedPacketRain/extensions/app/engine/dist/menu/tinyPNG.js
2026-03-04 11:30:40 +08:00

165 lines
5.5 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 strict";
/**
*
* 参考: https://segmentfault.com/a/1190000015467084
* 优化:通过 X-Forwarded-For 添加了动态随机伪IP绕过 tinypng 的上传数量限制
*
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const https_1 = __importDefault(require("https"));
const path_1 = __importDefault(require("path"));
const url_1 = require("url");
const exts = ['.png', '.jpg', '.jpeg'];
const max = 5200000; // 5MB == 5242848.754299136
const options = {
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'
}
};
// 生成随机IP 赋值给 X-Forwarded-For
function getRandomIP() {
return Array.from(Array(4)).map(() => Math.floor(Math.random() * 255)).join('.');
}
// 遍历文件列表
function fileEach(folder, callback) {
fs_1.default.readdir(folder, (err, files) => {
if (err)
console.error(err);
files.forEach(file => {
const filePath = path_1.default.join(folder, file);
fs_1.default.stat(filePath, (err, stats) => {
if (err)
return console.error(err);
if (stats.isDirectory()) {
fileEach(filePath, callback);
}
else if (
// 必须是文件小于5MB后缀 jpg||png
stats.size <= max &&
stats.isFile() &&
exts.includes(path_1.default.extname(file))) {
callback(filePath);
}
});
});
});
}
// 压缩图片
async function fileUpload(img_path) {
return new Promise((resolve, reject) => {
// 通过 X-Forwarded-For 头部伪造客户端IP
options.headers['X-Forwarded-For'] = getRandomIP();
const req = https_1.default.request(options, function (res) {
res.on('data', buf => {
const data = JSON.parse(buf.toString());
if (data.error) {
reject(data.message);
}
else {
resolve(data);
}
});
});
req.write(fs_1.default.readFileSync(img_path), 'binary');
req.on('error', err => {
reject(err);
});
req.end();
});
}
// 该方法被循环调用,请求图片数据
function fileUpdate(img_path, obj) {
return new Promise((resolve, reject) => {
const options = new url_1.URL(obj.output.url);
const req = https_1.default.request(options, res => {
let body = '';
res.setEncoding('binary');
res.on('data', function (data) {
body += data;
});
res.on('end', function () {
fs_1.default.writeFile(img_path, body, 'binary', err => {
if (err) {
return reject(err);
}
resolve(obj);
});
});
});
req.on('error', err => {
reject(err);
});
req.end();
});
}
// 根据字节大小转成B、KB、MB
function toSize(b) {
if (b < 1024) {
return b + 'B';
}
else if (b < 1024 * 1024) {
return (b / 1024).toFixed(2) + 'KB';
}
else {
return (b / 1024 / 1024).toFixed(2) + 'MB';
}
}
// 根据小数转成百分比字符串
function toPercent(num) {
return (num * 100).toFixed(2) + '%';
}
async function fileTiny(filePath) {
return fileUpload(filePath)
.then(obj => fileUpdate(filePath, obj));
}
function default_1(folder) {
// 路径是否存在
if (!fs_1.default.existsSync(folder)) {
console.log(`路径不存在:${folder}`);
return;
}
const basename = path_1.default.basename(folder);
console.log(`[${basename}] 压缩中...`);
// 是文件
if (!fs_1.default.statSync(folder).isDirectory()) {
if (!exts.includes(path_1.default.extname(folder))) {
console.log(`[${basename}] 压缩失败报错只支持png、jpg与jpeg格式`);
return;
}
fileTiny(folder)
.then(obj => {
console.log('[1/1]', `[${basename}]`, `压缩成功,原始: ${toSize(obj.input.size)},压缩: ${toSize(obj.output.size)},压缩比: ${toPercent(obj.output.ratio)}`);
})
.catch(err => {
console.log('[1/1]', `[${basename}]`, `压缩失败!报错:${err}`);
});
return;
}
let total = 0;
let finished = 0;
// 是文件夹
fileEach(folder, (filePath => {
total++;
const relativePath = path_1.default.relative(folder, filePath);
fileTiny(filePath)
.then(obj => {
console.log(`[${++finished}/${total}]`, `[${relativePath}]`, `压缩成功,原始: ${toSize(obj.input.size)},压缩: ${toSize(obj.output.size)},压缩比: ${toPercent(obj.output.ratio)}`);
})
.catch(err => {
console.log(`[${++finished}/${total}]`, `[${relativePath}]`, `压缩失败!报错:${err}`);
});
}));
}
exports.default = default_1;