195 lines
5.6 KiB
TypeScript
195 lines
5.6 KiB
TypeScript
/**
|
||
* 快速检查老素材在外网服务器上的源文件(简化版)
|
||
* 只统计,不实际检查每个文件
|
||
*/
|
||
|
||
import { PrismaClient } from '@prisma/client'
|
||
import { writeFile } from 'fs/promises'
|
||
|
||
const prisma = new PrismaClient()
|
||
const cutoffDate = new Date('2025-10-27T23:59:59.999Z')
|
||
|
||
/**
|
||
* 判断是否为老素材
|
||
*/
|
||
function isOldMaterial(material: any): boolean {
|
||
if (material.createdAt <= cutoffDate) return true
|
||
const previewUrl = material.previewUrl || ''
|
||
if (previewUrl.includes('s3.1080p.hk') &&
|
||
previewUrl.includes('/jsxiangche/') &&
|
||
!previewUrl.includes('由壹点AI/')) {
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
/**
|
||
* 构建外网服务器URL
|
||
*/
|
||
function buildExternalUrl(zipFilePath: string): string {
|
||
if (zipFilePath.startsWith('http://') || zipFilePath.startsWith('https://')) {
|
||
return zipFilePath
|
||
}
|
||
const fileName = zipFilePath.replace(/^uploads\//, '').replace(/^\/app\/uploads\//, '').replace(/^\.\/uploads\//, '')
|
||
return `http://103.118.245.6/uploads/${fileName}`
|
||
}
|
||
|
||
async function main() {
|
||
console.log('='.repeat(60))
|
||
console.log('老素材外网服务器源文件统计(快速版)')
|
||
console.log('='.repeat(60))
|
||
console.log()
|
||
|
||
// 查询所有素材
|
||
console.log('📋 查询所有素材...')
|
||
const allMaterials = await prisma.material.findMany({
|
||
where: {
|
||
deletedAt: null,
|
||
},
|
||
select: {
|
||
id: true,
|
||
materialType: true,
|
||
productModel: true,
|
||
authorName: true,
|
||
categoryName: true,
|
||
createdAt: true,
|
||
previewUrl: true,
|
||
zipFilePath: true,
|
||
zipFileName: true,
|
||
zipFileSize: true,
|
||
},
|
||
})
|
||
|
||
console.log(` 总素材数: ${allMaterials.length}`)
|
||
|
||
// 过滤老素材
|
||
const oldMaterials = allMaterials.filter(isOldMaterial)
|
||
console.log(` 老素材数: ${oldMaterials.length}`)
|
||
console.log()
|
||
|
||
// 分析源文件路径
|
||
console.log('🔍 分析源文件路径...')
|
||
|
||
const stats = {
|
||
total: oldMaterials.length,
|
||
hasLocalPath: 0, // uploads/格式
|
||
hasHttpUrl: 0, // http://格式
|
||
hasS3Url: 0, // S3 URL
|
||
noSourceFile: 0, // 没有源文件路径
|
||
}
|
||
|
||
const results: Array<{
|
||
id: string
|
||
materialType: string
|
||
productModel: string
|
||
authorName: string
|
||
categoryName: string
|
||
zipFilePath: string | null
|
||
zipFileName: string | null
|
||
zipFileSize: number | null
|
||
externalUrl: string
|
||
sourceType: string
|
||
createdAt: Date
|
||
}> = []
|
||
|
||
for (const material of oldMaterials) {
|
||
let sourceType = 'none'
|
||
let externalUrl = ''
|
||
|
||
if (material.zipFilePath) {
|
||
if (material.zipFilePath.startsWith('uploads/') ||
|
||
material.zipFilePath.startsWith('/app/uploads/') ||
|
||
material.zipFilePath.startsWith('./uploads/')) {
|
||
sourceType = 'local'
|
||
stats.hasLocalPath++
|
||
externalUrl = buildExternalUrl(material.zipFilePath)
|
||
} else if (material.zipFilePath.startsWith('http://') ||
|
||
material.zipFilePath.startsWith('https://')) {
|
||
sourceType = 'http'
|
||
stats.hasHttpUrl++
|
||
externalUrl = material.zipFilePath
|
||
}
|
||
}
|
||
|
||
// 检查zipFileName是否是S3 URL
|
||
if (material.zipFileName &&
|
||
(material.zipFileName.startsWith('http://') ||
|
||
material.zipFileName.startsWith('https://'))) {
|
||
if (sourceType === 'none') {
|
||
sourceType = 's3'
|
||
stats.hasS3Url++
|
||
}
|
||
}
|
||
|
||
if (sourceType === 'none') {
|
||
stats.noSourceFile++
|
||
}
|
||
|
||
results.push({
|
||
id: material.id,
|
||
materialType: material.materialType || '',
|
||
productModel: material.productModel || '',
|
||
authorName: material.authorName || '',
|
||
categoryName: material.categoryName || '',
|
||
zipFilePath: material.zipFilePath,
|
||
zipFileName: material.zipFileName,
|
||
zipFileSize: material.zipFileSize ? Number(material.zipFileSize) : null,
|
||
externalUrl: externalUrl || '',
|
||
sourceType,
|
||
createdAt: material.createdAt,
|
||
})
|
||
}
|
||
|
||
console.log(` 有本地路径(uploads/): ${stats.hasLocalPath} 个`)
|
||
console.log(` 有HTTP URL: ${stats.hasHttpUrl} 个`)
|
||
console.log(` 有S3 URL: ${stats.hasS3Url} 个`)
|
||
console.log(` 无源文件路径: ${stats.noSourceFile} 个`)
|
||
console.log()
|
||
|
||
// 生成CSV报告
|
||
const reportRows: string[] = []
|
||
reportRows.push('素材ID,素材类型,产品型号,作者,使用店铺,源文件路径,外网服务器URL,源文件类型,源文件大小(字节),创建时间')
|
||
|
||
for (const r of results) {
|
||
const row = [
|
||
r.id,
|
||
r.materialType,
|
||
r.productModel,
|
||
r.authorName,
|
||
r.categoryName,
|
||
r.zipFilePath || '',
|
||
r.externalUrl,
|
||
r.sourceType,
|
||
r.zipFileSize?.toString() || '',
|
||
r.createdAt.toISOString(),
|
||
]
|
||
reportRows.push(row.map(field => {
|
||
if (field === null || field === undefined) return ''
|
||
const str = String(field)
|
||
if (str.includes(',') || str.includes('"') || str.includes('\n')) {
|
||
return `"${str.replace(/"/g, '""')}"`
|
||
}
|
||
return str
|
||
}).join(','))
|
||
}
|
||
|
||
const reportFile = '/tmp/老素材外网服务器统计报告.csv'
|
||
await writeFile(reportFile, reportRows.join('\n'), 'utf-8')
|
||
|
||
console.log(`✅ 报告已生成: ${reportFile}`)
|
||
console.log(` 包含 ${results.length} 个老素材的统计信息`)
|
||
console.log()
|
||
console.log(`📊 总结:`)
|
||
console.log(` - 需要检查外网服务器的老素材: ${stats.hasLocalPath} 个(uploads/格式)`)
|
||
console.log(` - 已经是HTTP URL的: ${stats.hasHttpUrl} 个`)
|
||
console.log(` - S3 URL的: ${stats.hasS3Url} 个`)
|
||
console.log()
|
||
|
||
await prisma.$disconnect()
|
||
}
|
||
|
||
main().catch((error) => {
|
||
console.error('执行失败:', error)
|
||
process.exit(1)
|
||
})
|