gongxiangp2/scripts/fix-migrated-urls.ts

192 lines
5.5 KiB
TypeScript
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.

/**
* 修复已迁移素材的错误URL格式
* 移除URL中的jsxiangche路径段
*/
import { PrismaClient } from '@prisma/client';
const DATABASE_URL = process.env.DATABASE_URL || 'postgresql://gongxiangpan:gongxiangpan123@192.168.58.20:5432/lobechat';
const prisma = new PrismaClient({
datasources: {
db: {
url: DATABASE_URL,
},
},
});
// 视频/音频素材类型
const VIDEO_TYPES = ['主图视频', '安装视频', '种草视频'];
const AUDIO_TYPES = ['音频素材', '音乐'];
/**
* 修复单个URL,移除jsxiangche路径段
*/
function fixUrl(url: string): string {
// 如果URL包含jsxiangche,移除它
// 例如: https://s3.yydd.ai/gongxiangpan/jsxiangche/由壹点AI/...
// 应该变成: https://s3.yydd.ai/gongxiangpan/由壹点AI/...
return url.replace(/\/jsxiangche\//g, '/').replace(/jsxiangche\//g, '');
}
async function main() {
console.log('='.repeat(60));
console.log('修复已迁移素材的错误URL格式');
console.log('='.repeat(60));
console.log();
const args = process.argv.slice(2);
const isDryRun = args.includes('--dry-run');
if (isDryRun) {
console.log('⚠️ 试运行模式:不会实际修改数据库,只会显示将要修复的URL');
console.log();
}
try {
// 查询所有视频/音频素材
const allMaterials = await prisma.material.findMany({
where: {
materialType: {
in: [...VIDEO_TYPES, ...AUDIO_TYPES],
},
deletedAt: null,
},
select: {
id: true,
productModel: true,
materialType: true,
previewUrl: true,
videoCoverUrl: true,
videoPreview540Url: true,
videoPreviewClipUrl: true,
} as any,
});
console.log(`查询到 ${allMaterials.length} 个视频/音频素材`);
console.log();
// 查找需要修复的素材
const materialsToFix: Array<{
id: string;
productModel: string;
materialType: string;
updates: Record<string, string>;
}> = [];
for (const material of allMaterials) {
const m = material as any;
const updates: Record<string, string> = {};
// 检查各个URL字段
const urlFields = [
{ name: 'previewUrl', value: m.previewUrl },
{ name: 'videoCoverUrl', value: m.videoCoverUrl },
{ name: 'videoPreview540Url', value: m.videoPreview540Url },
{ name: 'videoPreviewClipUrl', value: m.videoPreviewClipUrl },
];
for (const field of urlFields) {
if (field.value) {
// 如果URL指向新存储桶(s3.yydd.ai),但包含jsxiangche,需要修复
if (field.value.includes('s3.yydd.ai') && field.value.includes('jsxiangche')) {
const fixedUrl = fixUrl(field.value);
updates[field.name] = fixedUrl;
}
}
}
if (Object.keys(updates).length > 0) {
materialsToFix.push({
id: m.id,
productModel: m.productModel,
materialType: m.materialType,
updates,
});
}
}
console.log(`找到 ${materialsToFix.length} 个需要修复的素材`);
console.log();
if (materialsToFix.length === 0) {
console.log('✅ 没有需要修复的素材!');
return;
}
// 显示将要修复的内容
console.log('将要修复的素材:');
console.log();
let totalFieldsFixed = 0;
for (let i = 0; i < materialsToFix.length; i++) {
const m = materialsToFix[i];
console.log(`${i + 1}. 素材ID: ${m.id}`);
console.log(` 产品型号: ${m.productModel}`);
console.log(` 素材类型: ${m.materialType}`);
console.log(` 需要修复的字段:`);
Object.entries(m.updates).forEach(([fieldName, newUrl]) => {
console.log(` - ${fieldName}:`);
// 找到原始URL
const originalUrl = (allMaterials.find(mat => (mat as any).id === m.id) as any)?.[fieldName];
if (originalUrl) {
console.log(` 旧: ${originalUrl}`);
}
console.log(` 新: ${newUrl}`);
totalFieldsFixed++;
});
console.log();
}
console.log('='.repeat(60));
console.log('总结');
console.log('='.repeat(60));
console.log(`需要修复的素材数: ${materialsToFix.length} 个`);
console.log(`需要修复的URL字段总数: ${totalFieldsFixed} 个`);
console.log();
if (isDryRun) {
console.log('⚠️ 试运行模式:未实际修改数据库');
return;
}
// 执行修复
console.log('开始修复...');
console.log();
let successCount = 0;
let failCount = 0;
for (let i = 0; i < materialsToFix.length; i++) {
const m = materialsToFix[i];
try {
await prisma.material.update({
where: { id: m.id },
data: m.updates as any,
});
successCount++;
console.log(`[${i + 1}/${materialsToFix.length}] ✅ 已修复: ${m.productModel} (${Object.keys(m.updates).length} 个字段)`);
} catch (error: any) {
failCount++;
console.error(`[${i + 1}/${materialsToFix.length}] ❌ 修复失败: ${m.productModel}`);
console.error(` 错误: ${error.message}`);
}
}
console.log();
console.log('='.repeat(60));
console.log('修复完成');
console.log('='.repeat(60));
console.log(`成功: ${successCount} 个素材`);
console.log(`失败: ${failCount} 个素材`);
console.log();
} catch (error) {
console.error('执行失败:', error);
process.exit(1);
} finally {
await prisma.$disconnect();
}
}
main();