2024-12-16 20:56:14 +08:00
|
|
|
|
import * as fs from 'fs';
|
|
|
|
|
import { resolve } from 'path';
|
|
|
|
|
import { execSync } from 'child_process';
|
|
|
|
|
import * as path from 'path';
|
|
|
|
|
import consola from 'consola';
|
|
|
|
|
import axios from 'axios';
|
|
|
|
|
import { URL } from 'url';
|
|
|
|
|
|
|
|
|
|
// 错误信息常量
|
|
|
|
|
const ErrorMessages = {
|
|
|
|
|
NO_SOURCE: '请提供源文件路径或URL',
|
|
|
|
|
INVALID_FILE_TYPE: '无效的文件类型,仅支持 PNG、JPG、JPEG 和 GIF',
|
|
|
|
|
FILE_NOT_EXIST: '源文件不存在',
|
|
|
|
|
DOWNLOAD_FAILED: '文件下载失败:',
|
|
|
|
|
COPY_FAILED: '文件复制失败:',
|
2024-12-17 09:23:24 +08:00
|
|
|
|
CONVERT_FAILED: '文件转换失败:',
|
2024-12-16 20:56:14 +08:00
|
|
|
|
UNEXPECTED_ERROR: '发生意外错误:',
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-17 09:23:24 +08:00
|
|
|
|
// 配置常量
|
|
|
|
|
const CONFIG = {
|
|
|
|
|
ALLOWED_EXTENSIONS: ['.png', '.jpg', '.jpeg', '.gif'],
|
|
|
|
|
OUTPUT_FILENAME: 'logo.png',
|
|
|
|
|
TEMP_PREFIX: 'temp-logo-'
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-16 20:56:14 +08:00
|
|
|
|
/**
|
|
|
|
|
* 从URL下载文件到指定目录
|
|
|
|
|
* @param url 文件的URL地址
|
|
|
|
|
* @param destination 目标保存路径
|
|
|
|
|
*/
|
|
|
|
|
async function downloadFile(url: string, destination: string): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
const response = await axios({
|
|
|
|
|
url,
|
|
|
|
|
method: 'GET',
|
2024-12-17 09:23:24 +08:00
|
|
|
|
responseType: 'stream',
|
|
|
|
|
timeout: 10000 // 10秒超时
|
2024-12-16 20:56:14 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const writer = fs.createWriteStream(destination);
|
|
|
|
|
|
|
|
|
|
response.data.pipe(writer);
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
writer.on('finish', resolve);
|
|
|
|
|
writer.on('error', reject);
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
throw new Error(`${ErrorMessages.DOWNLOAD_FAILED} ${error.message}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-12-17 09:23:24 +08:00
|
|
|
|
* 转换图片为PNG格式
|
2024-12-16 20:56:14 +08:00
|
|
|
|
* @param source 源文件路径
|
2024-12-17 09:23:24 +08:00
|
|
|
|
* @param destination 目标文件路径
|
2024-12-16 20:56:14 +08:00
|
|
|
|
*/
|
2024-12-17 09:23:24 +08:00
|
|
|
|
function convertToPng(source: string, destination: string): void {
|
2024-12-16 20:56:14 +08:00
|
|
|
|
try {
|
2024-12-17 09:23:24 +08:00
|
|
|
|
// 使用 ImageMagick 转换图片格式
|
|
|
|
|
execSync(`convert "${source}" "${destination}"`);
|
2024-12-16 20:56:14 +08:00
|
|
|
|
} catch (error) {
|
2024-12-17 09:23:24 +08:00
|
|
|
|
throw new Error(`${ErrorMessages.CONVERT_FAILED} ${error.message}`);
|
2024-12-16 20:56:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 验证字符串是否为有效URL
|
|
|
|
|
* @param string 待验证的字符串
|
|
|
|
|
*/
|
|
|
|
|
function isValidUrl(string: string): boolean {
|
|
|
|
|
try {
|
|
|
|
|
new URL(string);
|
|
|
|
|
return true;
|
|
|
|
|
} catch {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 验证文件是否为支持的图片类型
|
|
|
|
|
* @param filePath 文件路径
|
|
|
|
|
*/
|
|
|
|
|
function isValidImageFile(filePath: string): boolean {
|
|
|
|
|
const ext = path.extname(filePath).toLowerCase();
|
2024-12-17 09:23:24 +08:00
|
|
|
|
return CONFIG.ALLOWED_EXTENSIONS.includes(ext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 清理临时文件
|
|
|
|
|
* @param filePath 文件路径
|
|
|
|
|
*/
|
|
|
|
|
function cleanupTempFile(filePath: string): void {
|
|
|
|
|
if (fs.existsSync(filePath)) {
|
|
|
|
|
try {
|
|
|
|
|
fs.unlinkSync(filePath);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
consola.warn('清理临时文件失败:', error.message);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-16 20:56:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 主函数 - 处理Logo替换逻辑
|
|
|
|
|
*/
|
|
|
|
|
async function main(): Promise<void> {
|
2024-12-17 09:23:24 +08:00
|
|
|
|
const tempFiles: string[] = [];
|
|
|
|
|
|
2024-12-16 20:56:14 +08:00
|
|
|
|
try {
|
|
|
|
|
// 获取命令行参数中的源文件路径
|
|
|
|
|
const sourcePath = process.argv[2];
|
|
|
|
|
|
|
|
|
|
if (!sourcePath) {
|
|
|
|
|
throw new Error(ErrorMessages.NO_SOURCE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const baseDir: string = resolve('./');
|
2024-12-17 09:23:24 +08:00
|
|
|
|
const finalDestination = path.join(baseDir, CONFIG.OUTPUT_FILENAME);
|
2024-12-16 20:56:14 +08:00
|
|
|
|
|
|
|
|
|
// 打印初始信息
|
2024-12-17 09:23:24 +08:00
|
|
|
|
consola.info('开始处理Logo');
|
|
|
|
|
consola.info('源文件:', sourcePath);
|
|
|
|
|
consola.info('目标位置:', finalDestination);
|
2024-12-16 20:56:14 +08:00
|
|
|
|
|
|
|
|
|
// 验证文件类型
|
|
|
|
|
if (!isValidImageFile(sourcePath)) {
|
|
|
|
|
throw new Error(ErrorMessages.INVALID_FILE_TYPE);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-17 09:23:24 +08:00
|
|
|
|
// 处理URL或本地文件
|
2024-12-16 20:56:14 +08:00
|
|
|
|
if (isValidUrl(sourcePath)) {
|
|
|
|
|
consola.info('正在从URL下载文件...');
|
2024-12-17 09:23:24 +08:00
|
|
|
|
const tempFile = path.join(baseDir, CONFIG.TEMP_PREFIX + Date.now() + path.extname(sourcePath));
|
|
|
|
|
tempFiles.push(tempFile);
|
2024-12-16 20:56:14 +08:00
|
|
|
|
|
2024-12-17 09:23:24 +08:00
|
|
|
|
// 下载文件
|
|
|
|
|
await downloadFile(sourcePath, tempFile);
|
|
|
|
|
consola.success('文件下载完成');
|
|
|
|
|
|
|
|
|
|
// 转换为PNG(如果需要)
|
|
|
|
|
if (path.extname(tempFile).toLowerCase() !== '.png') {
|
|
|
|
|
consola.info('正在转换为PNG格式...');
|
|
|
|
|
convertToPng(tempFile, finalDestination);
|
|
|
|
|
} else {
|
|
|
|
|
fs.copyFileSync(tempFile, finalDestination);
|
2024-12-16 20:56:14 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 处理本地文件
|
|
|
|
|
const localPath = path.resolve(sourcePath);
|
|
|
|
|
if (!fs.existsSync(localPath)) {
|
|
|
|
|
throw new Error(ErrorMessages.FILE_NOT_EXIST);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-17 09:23:24 +08:00
|
|
|
|
// 转换为PNG(如果需要)
|
|
|
|
|
if (path.extname(localPath).toLowerCase() !== '.png') {
|
|
|
|
|
consola.info('正在转换为PNG格式...');
|
|
|
|
|
convertToPng(localPath, finalDestination);
|
|
|
|
|
} else {
|
|
|
|
|
fs.copyFileSync(localPath, finalDestination);
|
|
|
|
|
}
|
2024-12-16 20:56:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-12-17 09:23:24 +08:00
|
|
|
|
consola.success('Logo处理完成');
|
|
|
|
|
consola.info(`文件已保存至: ${finalDestination}`);
|
|
|
|
|
|
2024-12-16 20:56:14 +08:00
|
|
|
|
} catch (error) {
|
2024-12-17 09:23:24 +08:00
|
|
|
|
consola.error('Logo处理失败:', error.message);
|
2024-12-16 20:56:14 +08:00
|
|
|
|
process.exit(1);
|
2024-12-17 09:23:24 +08:00
|
|
|
|
} finally {
|
|
|
|
|
// 清理所有临时文件
|
|
|
|
|
tempFiles.forEach(cleanupTempFile);
|
2024-12-16 20:56:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 执行主函数
|
|
|
|
|
main().catch(error => {
|
|
|
|
|
consola.error(ErrorMessages.UNEXPECTED_ERROR, error);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
});
|