132 lines
3.7 KiB
TypeScript
132 lines
3.7 KiB
TypeScript
// Access Key ID Secret Access Key
|
||
// AKLTZDY5ZjE0ZjMxODdiNDhjODkyYzhkODY2MmUwYmZlMzc TjJaak5XVTBOR0ZtTTJRek5HWTRPRGhoT0RBellXUTNORFV3WmpOa1pERQ==
|
||
|
||
// S3 endpoint:tos-cn-beijing.volces.com
|
||
// 外网访问:tos-s3-cn-beijing.volces.com
|
||
// Bucket 域名:kdesign-offical.tos-cn-beijing.volces.com
|
||
|
||
import { TosClient } from '@volcengine/tos-sdk';
|
||
import * as fs from 'fs';
|
||
import * as path from 'path';
|
||
|
||
|
||
// 配置信息
|
||
const config = {
|
||
accessKeyId: 'AKLTZDY5ZjE0ZjMxODdiNDhjODkyYzhkODY2MmUwYmZlMzc',
|
||
secretAccessKey: 'TjJaak5XVTBOR0ZtTTJRek5HWTRPRGhoT0RBellXUTNORFV3WmpOa1pERQ==',
|
||
endpoint: 'tos-cn-beijing.volces.com',
|
||
region: 'cn-beijing',
|
||
bucket: 'kdesign-offical'
|
||
};
|
||
|
||
// 创建 TOS 客户端
|
||
const client = new TosClient({
|
||
accessKeyId: config.accessKeyId,
|
||
accessKeySecret: config.secretAccessKey,
|
||
endpoint: config.endpoint,
|
||
region: config.region
|
||
});
|
||
|
||
// 获取文件的 Content-Type
|
||
function getContentType(filePath: string): string {
|
||
const ext = path.extname(filePath).toLowerCase();
|
||
const contentTypeMap: Record<string, string> = {
|
||
'.html': 'text/html',
|
||
'.css': 'text/css',
|
||
'.js': 'application/javascript',
|
||
'.json': 'application/json',
|
||
'.png': 'image/png',
|
||
'.jpg': 'image/jpeg',
|
||
'.jpeg': 'image/jpeg',
|
||
'.gif': 'image/gif',
|
||
'.svg': 'image/svg+xml',
|
||
'.mp4': 'video/mp4',
|
||
'.webp': 'image/webp',
|
||
'.ico': 'image/x-icon',
|
||
'.txt': 'text/plain',
|
||
'.pdf': 'application/pdf',
|
||
'.zip': 'application/zip'
|
||
};
|
||
|
||
return contentTypeMap[ext] || 'application/octet-stream';
|
||
}
|
||
|
||
// 递归获取目录下所有文件
|
||
async function getAllFiles(dirPath: string, fileList: string[] = []): Promise<string[]> {
|
||
const files = fs.readdirSync(dirPath);
|
||
|
||
for (const file of files) {
|
||
const filePath = path.join(dirPath, file);
|
||
const stat = fs.statSync(filePath);
|
||
|
||
if (stat.isDirectory()) {
|
||
await getAllFiles(filePath, fileList);
|
||
} else {
|
||
fileList.push(filePath);
|
||
}
|
||
}
|
||
|
||
return fileList;
|
||
}
|
||
|
||
// 上传单个文件
|
||
async function uploadFile(filePath: string, basePath: string): Promise<void> {
|
||
try {
|
||
// 计算相对路径作为对象键名
|
||
const key = filePath.replace(basePath, '').replace(/^\//, '');
|
||
const contentType = getContentType(filePath);
|
||
const fileContent = fs.readFileSync(filePath);
|
||
|
||
console.log(`上传文件: ${filePath} -> ${key}`);
|
||
|
||
const response = await client.putObject({
|
||
bucket: config.bucket,
|
||
key: key,
|
||
body: fileContent,
|
||
contentType: contentType
|
||
});
|
||
|
||
console.log(`上传成功: ${key}, 请求ID: ${response.requestId}`);
|
||
} catch (error) {
|
||
console.error(`上传文件 ${filePath} 失败:`, error);
|
||
}
|
||
}
|
||
|
||
// 上传目录下所有文件
|
||
async function uploadDirectory(dirPath: string): Promise<void> {
|
||
try {
|
||
const basePath = path.resolve(dirPath, '..');
|
||
const allFiles = await getAllFiles(dirPath);
|
||
|
||
console.log(`找到 ${allFiles.length} 个文件需要上传`);
|
||
|
||
// 创建上传任务队列
|
||
const uploadTasks = allFiles.map(filePath => uploadFile(filePath, basePath));
|
||
|
||
// 并发上传文件
|
||
await Promise.all(uploadTasks);
|
||
|
||
console.log('所有文件上传完成');
|
||
} catch (error) {
|
||
console.error('上传目录失败:', error);
|
||
}
|
||
}
|
||
|
||
// 主函数
|
||
async function main() {
|
||
// 使用 import.meta.url 替代 __dirname (ES 模块兼容)
|
||
const currentFileUrl = import.meta.url;
|
||
const currentFilePath = new URL(currentFileUrl).pathname;
|
||
const currentDir = path.dirname(currentFilePath);
|
||
const assetsDir = path.resolve(currentDir, '../dist/assets');
|
||
console.log(`开始上传目录: ${assetsDir}`);
|
||
await uploadDirectory(assetsDir);
|
||
}
|
||
|
||
// 执行主函数
|
||
main().catch(error => {
|
||
console.error('程序执行失败:', error);
|
||
process.exit(1);
|
||
});
|
||
|