Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Failing after 18s
Build & Deploy / 🏗️ Build (push) Failing after 25s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 4s
123 lines
4.4 KiB
TypeScript
123 lines
4.4 KiB
TypeScript
import { getPayload } from "payload";
|
|
import configPromise from "../payload.config";
|
|
import fs from "fs";
|
|
import path from "path";
|
|
import { parseMarkdownToLexical } from "../src/payload/utils/lexicalParser";
|
|
|
|
function extractFrontmatter(content: string) {
|
|
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
if (!fmMatch) return {};
|
|
const fm = fmMatch[1];
|
|
const titleMatch = fm.match(/title:\s*"?([^"\n]+)"?/);
|
|
const descMatch = fm.match(/description:\s*"?([^"\n]+)"?/);
|
|
const tagsMatch = fm.match(/tags:\s*\[(.*?)\]/);
|
|
|
|
return {
|
|
title: titleMatch ? titleMatch[1] : "Untitled Draft",
|
|
description: descMatch ? descMatch[1] : "No description",
|
|
tags: tagsMatch ? tagsMatch[1].split(",").map(s => s.trim().replace(/"/g, "")) : []
|
|
};
|
|
}
|
|
|
|
async function run() {
|
|
try {
|
|
const payload = await getPayload({ config: configPromise });
|
|
console.log("Payload initialized.");
|
|
|
|
const draftsDir = path.resolve(process.cwd(), "content/drafts");
|
|
const publicBlogDir = path.resolve(process.cwd(), "public/blog");
|
|
|
|
if (!fs.existsSync(draftsDir)) {
|
|
console.log(`Drafts directory not found at ${draftsDir}`);
|
|
process.exit(0);
|
|
}
|
|
|
|
const files = fs.readdirSync(draftsDir).filter(f => f.endsWith(".md"));
|
|
let count = 0;
|
|
|
|
for (const file of files) {
|
|
console.log(`Processing ${file}...`);
|
|
const filePath = path.join(draftsDir, file);
|
|
const content = fs.readFileSync(filePath, "utf8");
|
|
|
|
const fm = extractFrontmatter(content);
|
|
const lexicalNodes = parseMarkdownToLexical(content);
|
|
const lexicalContent = {
|
|
root: {
|
|
type: "root",
|
|
format: "" as const,
|
|
indent: 0,
|
|
version: 1,
|
|
direction: "ltr" as const,
|
|
children: lexicalNodes
|
|
}
|
|
};
|
|
|
|
// Upload thumbnail if exists
|
|
let featuredImageId = null;
|
|
const thumbPath = path.join(publicBlogDir, `${file}.png`);
|
|
if (fs.existsSync(thumbPath)) {
|
|
console.log(`Uploading thumbnail ${file}.png...`);
|
|
const fileData = fs.readFileSync(thumbPath);
|
|
const stat = fs.statSync(thumbPath);
|
|
|
|
try {
|
|
const newMedia = await payload.create({
|
|
collection: "media",
|
|
data: {
|
|
alt: `Thumbnail for ${fm.title}`,
|
|
},
|
|
file: {
|
|
data: fileData,
|
|
name: `optimized-${file}.png`,
|
|
mimetype: "image/png",
|
|
size: stat.size,
|
|
},
|
|
});
|
|
featuredImageId = newMedia.id;
|
|
} catch (e) {
|
|
console.log("Failed to upload thumbnail", e);
|
|
}
|
|
}
|
|
|
|
const tagsArray = fm.tags.map(tag => ({ tag }));
|
|
|
|
const slug = fm.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").substring(0, 60);
|
|
|
|
// Check if already exists
|
|
const existing = await payload.find({
|
|
collection: "posts",
|
|
where: { slug: { equals: slug } },
|
|
});
|
|
|
|
if (existing.totalDocs === 0) {
|
|
await payload.create({
|
|
collection: "posts",
|
|
data: {
|
|
title: fm.title,
|
|
slug: slug,
|
|
description: fm.description,
|
|
date: new Date().toISOString(),
|
|
tags: tagsArray,
|
|
featuredImage: featuredImageId,
|
|
content: lexicalContent,
|
|
_status: "published"
|
|
},
|
|
});
|
|
console.log(`Created CMS entry for ${file}.`);
|
|
count++;
|
|
} else {
|
|
console.log(`Post with slug ${slug} already exists. Skipping.`);
|
|
}
|
|
}
|
|
|
|
console.log(`Migration successful! Added ${count} new optimized posts to the database.`);
|
|
process.exit(0);
|
|
} catch (e) {
|
|
console.error("Migration failed:", e);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
run();
|