gongxiangp2/scripts/analyze-csv-old-materials.js

263 lines
7.8 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.

/**
* 分析CSV文件,统计老素材
* 使用Node.js原生模块,不需要额外依赖
*/
const fs = require('fs');
const path = require('path');
const csvFile = process.argv[2] || 'material-inventory-2026-01-13T09-04-07.csv';
const outputDir = process.argv[3] || 'D:\\qwertyuiop\\old-materials-backup';
const cutoffDate = new Date('2025-10-27T23:59:59.999Z');
function isOldMaterial(row) {
// 1. 检查创建时间
try {
const createdAt = new Date(row['创建时间']);
if (createdAt <= cutoffDate) {
return true;
}
} catch (e) {
// 日期解析失败
}
// 2. 检查预览图URL
const previewUrl = row['预览图URL'] || '';
if (previewUrl.includes('s3.1080p.hk') &&
previewUrl.includes('/jsxiangche/') &&
!previewUrl.includes('由壹点AI/')) {
return true;
}
return false;
}
function isOldMaterialUrl(url) {
if (!url || typeof url !== 'string') return false;
return url.includes('s3.1080p.hk') &&
url.includes('/jsxiangche/') &&
!url.includes('由壹点AI/');
}
function parseCSV(content) {
const lines = content.split('\n').filter(line => line.trim());
if (lines.length === 0) return { headers: [], rows: [] };
// 解析表头
const headers = lines[0].split(',').map(h => h.replace(/^"|"$/g, ''));
// 解析数据行
const rows = [];
for (let i = 1; i < lines.length; i++) {
const line = lines[i];
if (!line.trim()) continue;
// 简单的CSV解析(处理引号内的逗号)
const values = [];
let current = '';
let inQuotes = false;
for (let j = 0; j < line.length; j++) {
const char = line[j];
if (char === '"') {
inQuotes = !inQuotes;
} else if (char === ',' && !inQuotes) {
values.push(current.replace(/^"|"$/g, ''));
current = '';
} else {
current += char;
}
}
values.push(current.replace(/^"|"$/g, ''));
const row = {};
headers.forEach((header, index) => {
row[header] = values[index] || '';
});
rows.push(row);
}
return { headers, rows };
}
function main() {
console.log('='.repeat(60));
console.log('分析CSV文件,统计老素材');
console.log('='.repeat(60));
console.log(`CSV文件: ${csvFile}`);
console.log(`输出目录: ${outputDir}`);
console.log();
if (!fs.existsSync(csvFile)) {
console.error(`❌ CSV文件不存在: ${csvFile}`);
process.exit(1);
}
// 读取CSV文件
console.log('📋 读取CSV文件...');
const content = fs.readFileSync(csvFile, 'utf-8');
const { headers, rows } = parseCSV(content);
console.log(` 读取到 ${rows.length} 条记录`);
console.log();
// 筛选老素材
console.log('🔍 筛选老素材...');
const oldMaterials = rows.filter(isOldMaterial);
console.log(` 找到 ${oldMaterials.length} 个老素材`);
console.log();
// 统计源文件
let localPathCount = 0;
let httpUrlCount = 0;
let s3UrlCount = 0;
let emptyCount = 0;
let localPathSize = 0;
let httpUrlSize = 0;
let s3UrlSize = 0;
const downloadTasks = [];
for (const material of oldMaterials) {
const materialId = material['素材ID'];
const zipFilePath = material['压缩包路径'] || '';
const zipFileName = material['压缩包文件名'] || '';
const zipFileSize = parseInt(material['压缩包大小(字节)'] || '0', 10);
const previewUrl = material['预览图URL'] || '';
// 收集预览图
if (previewUrl && isOldMaterialUrl(previewUrl)) {
downloadTasks.push({
materialId,
url: previewUrl,
field: 'previewUrl',
type: 'S3',
});
}
// 收集源文件
if (zipFilePath) {
if (zipFilePath.startsWith('http://') || zipFilePath.startsWith('https://')) {
httpUrlCount++;
httpUrlSize += zipFileSize;
downloadTasks.push({
materialId,
url: zipFilePath,
field: 'zipFilePath',
type: 'HTTP',
size: zipFileSize,
});
} else if (zipFilePath.startsWith('uploads/') || zipFilePath.startsWith('/app/uploads/')) {
localPathCount++;
localPathSize += zipFileSize;
downloadTasks.push({
materialId,
url: zipFilePath,
field: 'zipFilePath',
type: 'LOCAL',
size: zipFileSize,
});
}
}
if (zipFileName && isOldMaterialUrl(zipFileName)) {
s3UrlCount++;
downloadTasks.push({
materialId,
url: zipFileName,
field: 'zipFileName',
type: 'S3',
});
}
if (!zipFilePath && !zipFileName) {
emptyCount++;
}
}
// 输出统计
console.log('源文件存储位置统计:');
console.log('='.repeat(60));
console.log(`本地路径(uploads/...): ${localPathCount} 个`);
console.log(` - 总大小: ${(localPathSize / 1024 / 1024 / 1024).toFixed(2)} GB`);
if (localPathCount > 0) {
console.log(` - 平均大小: ${(localPathSize / localPathCount / 1024 / 1024).toFixed(2)} MB`);
}
console.log();
console.log(`HTTP URL(http://103.118.245.6/...): ${httpUrlCount} 个`);
console.log(` - 总大小: ${(httpUrlSize / 1024 / 1024 / 1024).toFixed(2)} GB`);
if (httpUrlCount > 0) {
console.log(` - 平均大小: ${(httpUrlSize / httpUrlCount / 1024 / 1024).toFixed(2)} MB`);
}
console.log();
console.log(`S3 URL(s3.1080p.hk/...): ${s3UrlCount} 个`);
console.log();
console.log(`无源文件: ${emptyCount} 个`);
console.log();
const totalSize = localPathSize + httpUrlSize;
console.log('总计:');
console.log(` - 总素材数: ${oldMaterials.length} 个`);
console.log(` - 有源文件的素材: ${localPathCount + httpUrlCount + s3UrlCount} 个`);
console.log(` - 源文件总大小: ${(totalSize / 1024 / 1024 / 1024).toFixed(2)} GB`);
console.log(` - 下载任务数: ${downloadTasks.length} 个`);
console.log();
// 创建输出目录
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// 保存统计信息
const stats = {
totalMaterials: rows.length,
oldMaterials: oldMaterials.length,
localPathCount,
httpUrlCount,
s3UrlCount,
emptyCount,
localPathSize,
httpUrlSize,
s3UrlSize,
totalSize,
totalSizeGB: (totalSize / 1024 / 1024 / 1024).toFixed(2),
downloadTasksCount: downloadTasks.length,
timestamp: new Date().toISOString(),
};
const statsFile = path.join(outputDir, 'old-materials-stats.json');
fs.writeFileSync(statsFile, JSON.stringify(stats, null, 2), 'utf-8');
console.log(`✅ 统计信息已保存: ${statsFile}`);
// 保存老素材列表(前100个作为示例)
const sampleMaterials = oldMaterials.slice(0, 100).map(m => ({
id: m['素材ID'],
type: m['素材类型'],
createdAt: m['创建时间'],
previewUrl: m['预览图URL'],
zipFilePath: m['压缩包路径'],
zipFileSize: m['压缩包大小(字节)'],
}));
const sampleFile = path.join(outputDir, 'old-materials-sample.json');
fs.writeFileSync(sampleFile, JSON.stringify(sampleMaterials, null, 2), 'utf-8');
console.log(`✅ 示例素材列表已保存: ${sampleFile} (前100个)`);
console.log();
console.log('='.repeat(60));
console.log('分析完成');
console.log('='.repeat(60));
console.log();
console.log('📊 关键数据:');
console.log(` - 老素材总数: ${oldMaterials.length} 个`);
console.log(` - 本地路径源文件: ${localPathCount} 个, ${(localPathSize / 1024 / 1024 / 1024).toFixed(2)} GB`);
console.log(` - HTTP URL源文件: ${httpUrlCount} 个, ${(httpUrlSize / 1024 / 1024 / 1024).toFixed(2)} GB`);
console.log(` - 总下载大小: ${stats.totalSizeGB} GB`);
console.log();
console.log('✅ 确认:这些是老素材的文件(创建时间 ≤ 2025-10-27 或使用旧MinIO URL)');
}
main();