135 lines
4.5 KiB
TypeScript
135 lines
4.5 KiB
TypeScript
// scripts/fix-asset-urls.ts
|
|
import { PrismaClient } from "@prisma/client";
|
|
const prisma = new PrismaClient();
|
|
|
|
const FROM = "douyin-archive/";
|
|
const TO = "";
|
|
|
|
function escapeForPgRegex(s: string) {
|
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
}
|
|
const FROM_RE = `^${escapeForPgRegex(FROM)}`; // 只替换“以旧前缀开头”的字符串
|
|
const dryRun = false; // true: 只统计,不修改
|
|
|
|
async function main() {
|
|
if (dryRun) {
|
|
const rows = await prisma.$queryRawUnsafe<any[]>(`
|
|
WITH c AS (
|
|
SELECT 'Author.avatar_url' AS col, COUNT(*) AS n FROM "Author" WHERE avatar_url LIKE '${FROM}%'
|
|
UNION ALL
|
|
SELECT 'CommentUser.avatar_url' , COUNT(*) FROM "CommentUser" WHERE avatar_url LIKE '${FROM}%'
|
|
UNION ALL
|
|
SELECT 'CommentImage.url' , COUNT(*) FROM "CommentImage" WHERE url LIKE '${FROM}%'
|
|
UNION ALL
|
|
SELECT 'Video.cover_url' , COUNT(*) FROM "Video" WHERE cover_url LIKE '${FROM}%'
|
|
UNION ALL
|
|
SELECT 'Video.video_url' , COUNT(*) FROM "Video" WHERE video_url LIKE '${FROM}%'
|
|
UNION ALL
|
|
SELECT 'ImageFile.url' , COUNT(*) FROM "ImageFile" WHERE url LIKE '${FROM}%'
|
|
UNION ALL
|
|
SELECT 'ImageFile.animated' , COUNT(*) FROM "ImageFile" WHERE animated LIKE '${FROM}%'
|
|
UNION ALL
|
|
SELECT 'ImagePost.music_url' , COUNT(*) FROM "ImagePost" WHERE music_url LIKE '${FROM}%'
|
|
UNION ALL
|
|
SELECT 'Video.raw_json' , COUNT(*) FROM "Video" WHERE raw_json::text LIKE '%${FROM}%'
|
|
UNION ALL
|
|
SELECT 'ImagePost.raw_json' , COUNT(*) FROM "ImagePost" WHERE raw_json::text LIKE '%${FROM}%'
|
|
)
|
|
SELECT * FROM c ORDER BY col;
|
|
`);
|
|
console.table(rows);
|
|
return;
|
|
}
|
|
|
|
await prisma.$transaction(async (tx) => {
|
|
// CommentUser.avatar_url
|
|
await tx.$executeRawUnsafe(`
|
|
UPDATE "CommentUser"
|
|
SET avatar_url = regexp_replace(avatar_url, '${FROM_RE}', '${TO}')
|
|
WHERE avatar_url LIKE '${FROM}%'
|
|
`);
|
|
|
|
// CommentImage.url
|
|
await tx.$executeRawUnsafe(`
|
|
UPDATE "CommentImage"
|
|
SET url = regexp_replace(url, '${FROM_RE}', '${TO}')
|
|
WHERE url LIKE '${FROM}%'
|
|
`);
|
|
|
|
// Author.avatar_url
|
|
await tx.$executeRawUnsafe(`
|
|
UPDATE "Author"
|
|
SET avatar_url = regexp_replace(avatar_url, '${FROM_RE}', '${TO}')
|
|
WHERE avatar_url LIKE '${FROM}%'
|
|
`);
|
|
|
|
// Video.cover_url
|
|
await tx.$executeRawUnsafe(`
|
|
UPDATE "Video"
|
|
SET cover_url = regexp_replace(cover_url, '${FROM_RE}', '${TO}')
|
|
WHERE cover_url LIKE '${FROM}%'
|
|
`);
|
|
|
|
// Video.video_url
|
|
await tx.$executeRawUnsafe(`
|
|
UPDATE "Video"
|
|
SET video_url = regexp_replace(video_url, '${FROM_RE}', '${TO}')
|
|
WHERE video_url LIKE '${FROM}%'
|
|
`);
|
|
|
|
// ImageFile.url
|
|
await tx.$executeRawUnsafe(`
|
|
UPDATE "ImageFile"
|
|
SET url = regexp_replace(url, '${FROM_RE}', '${TO}')
|
|
WHERE url LIKE '${FROM}%'
|
|
`);
|
|
|
|
// ImageFile.animated
|
|
await tx.$executeRawUnsafe(`
|
|
UPDATE "ImageFile"
|
|
SET animated = regexp_replace(animated, '${FROM_RE}', '${TO}')
|
|
WHERE animated LIKE '${FROM}%'
|
|
`);
|
|
|
|
// ImagePost.music_url
|
|
await tx.$executeRawUnsafe(`
|
|
UPDATE "ImagePost"
|
|
SET music_url = regexp_replace(music_url, '${FROM_RE}', '${TO}')
|
|
WHERE music_url LIKE '${FROM}%'
|
|
`);
|
|
|
|
// (可选)raw_json:简单文本整体替换;若想更精细可用递归 JSONB 方法
|
|
await tx.$executeRawUnsafe(`
|
|
UPDATE "Video"
|
|
SET raw_json = to_jsonb(replace(raw_json::text, '${FROM}', '${TO}'))
|
|
WHERE raw_json::text LIKE '%${FROM}%'
|
|
`);
|
|
await tx.$executeRawUnsafe(`
|
|
UPDATE "ImagePost"
|
|
SET raw_json = to_jsonb(replace(raw_json::text, '${FROM}', '${TO}'))
|
|
WHERE raw_json::text LIKE '%${FROM}%'
|
|
`);
|
|
});
|
|
|
|
// 快速抽样
|
|
const sample = await prisma.$queryRawUnsafe<any[]>(`
|
|
(
|
|
SELECT 'CommentImage.url' AS col, url AS v FROM "CommentImage" WHERE url LIKE '${TO}%' LIMIT 2
|
|
) UNION ALL (
|
|
SELECT 'CommentUser.avatar_url', avatar_url FROM "CommentUser" WHERE avatar_url LIKE '${TO}%' LIMIT 2
|
|
) UNION ALL (
|
|
SELECT 'Video.video_url', video_url FROM "Video" WHERE video_url LIKE '${TO}%' LIMIT 2
|
|
)
|
|
`);
|
|
console.log("Sample after update:", sample);
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error(e);
|
|
process.exit(1);
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|