[update] update tool scripts
This commit is contained in:
@@ -1,14 +1,17 @@
|
||||
import { Config } from "@/data/config";
|
||||
import { getCurrentTime } from "@/lib/date";
|
||||
import path from "path";
|
||||
import process from "process";
|
||||
|
||||
export const LatestPostCountInHomePage = 10;
|
||||
export const PostCountPerPagination = 10;
|
||||
export const PostsRootDirectory = path.join(process.cwd(), "./data/posts");
|
||||
export const UserDataDirectory = path.join(process.cwd(), "./data");
|
||||
export const PostFilesDirectory = path.join(UserDataDirectory, "/posts");
|
||||
|
||||
export const RSSFeedURL = `https://${Config.SiteDomain}/rss.xml`;
|
||||
export const WebsiteURL = `https://${Config.SiteDomain}/`;
|
||||
export const PostURL = (postId: string) => `https://${Config.SiteDomain}/blog/${postId}`;
|
||||
export const SearchURL = (keyword: string) => `https://${Config.SiteDomain}/search/?q=${keyword}`;
|
||||
|
||||
export const CopyrightAnnouncement = `COPYRIGHT © ${Config.YearStart}-${new Date().getFullYear()} ${
|
||||
Config.AuthorName
|
||||
} ALL RIGHTS RESERVED`;
|
||||
const year = getCurrentTime().year;
|
||||
export const CopyrightAnnouncement = `COPYRIGHT © ${Config.YearStart}-${year} ${Config.AuthorName} ALL RIGHTS RESERVED`;
|
||||
|
||||
19
lib/date.ts
19
lib/date.ts
@@ -24,3 +24,22 @@ export const normalizeDate = (date: string = "1970-01-01"): string => {
|
||||
};
|
||||
return `${day_num} ${month_en[month_num]}, ${year}`;
|
||||
};
|
||||
|
||||
export const getCurrentTime = (): {
|
||||
year: string;
|
||||
month: string;
|
||||
day: string;
|
||||
hours: string;
|
||||
minutes: string;
|
||||
seconds: string;
|
||||
} => {
|
||||
const today = new Date();
|
||||
return {
|
||||
year: today.getFullYear().toString(),
|
||||
month: String(today.getMonth() + 1).padStart(2, "0"),
|
||||
day: String(today.getDate()).padStart(2, "0"),
|
||||
hours: String(today.getHours()).padStart(2, "0"),
|
||||
minutes: String(today.getMinutes()).padStart(2, "0"),
|
||||
seconds: String(today.getSeconds()).padStart(2, "0"),
|
||||
};
|
||||
};
|
||||
|
||||
25
lib/file.ts
Normal file
25
lib/file.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import * as fs from "fs";
|
||||
|
||||
export function checkAndCreateDirectory(dirPath: string) {
|
||||
try {
|
||||
if (!fs.existsSync(dirPath)) {
|
||||
fs.mkdirSync(dirPath, { recursive: true });
|
||||
}
|
||||
fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
|
||||
return true;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export function isDirectoryEmptySync(directory: string) {
|
||||
try {
|
||||
if (!fs.existsSync(directory)) {
|
||||
fs.mkdirSync(directory, { recursive: true });
|
||||
}
|
||||
const files = fs.readdirSync(directory);
|
||||
return files.length === 0;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PostsRootDirectory } from "@/consts/consts";
|
||||
import { PostFilesDirectory } from "@/consts/consts";
|
||||
import { TFrontmatter } from "@/types/frontmatter.type";
|
||||
import { TPostListItem, TPostsByTag } from "@/types/post-list";
|
||||
import fs from "fs";
|
||||
@@ -36,8 +36,8 @@ async function extractFrontmatters(filepath: string): Promise<TFrontmatter> {
|
||||
|
||||
function readPostsDirectory(): string[] {
|
||||
const result: string[] = [];
|
||||
fs.readdirSync(PostsRootDirectory).forEach((fileName) => {
|
||||
const filePath = path.join(PostsRootDirectory, fileName);
|
||||
fs.readdirSync(PostFilesDirectory).forEach((fileName) => {
|
||||
const filePath = path.join(PostFilesDirectory, fileName);
|
||||
const fileStat = fs.statSync(filePath);
|
||||
|
||||
if (fileStat.isFile() && fileName.endsWith(".md")) {
|
||||
@@ -48,7 +48,7 @@ function readPostsDirectory(): string[] {
|
||||
}
|
||||
|
||||
export const getPostFileContent = (postId: string): string | null => {
|
||||
const filePath = path.join(PostsRootDirectory, `${postId}.md`);
|
||||
const filePath = path.join(PostFilesDirectory, `${postId}.md`);
|
||||
if (!fs.existsSync(filePath)) return null;
|
||||
const content = fs.readFileSync(filePath, "utf-8");
|
||||
return content;
|
||||
|
||||
141
package-lock.json
generated
141
package-lock.json
generated
@@ -67,6 +67,7 @@
|
||||
"tailwind-merge": "^2.0.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"title-case": "^4.3.1",
|
||||
"typescript": "5.2.2",
|
||||
"url-join": "^5.0.0",
|
||||
"zustand": "^4.4.7"
|
||||
@@ -87,6 +88,7 @@
|
||||
"@types/tar": "^6.1.11",
|
||||
"archiver": "^7.0.1",
|
||||
"autocorrect-node": "^2.11.1",
|
||||
"bun": "^1.1.22",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"feed": "^4.2.2",
|
||||
@@ -1203,6 +1205,110 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@oven/bun-darwin-aarch64": {
|
||||
"version": "1.1.22",
|
||||
"resolved": "https://registry.npmmirror.com/@oven/bun-darwin-aarch64/-/bun-darwin-aarch64-1.1.22.tgz",
|
||||
"integrity": "sha512-1sNo/mXEWmf/opHyQElIZwUUwamR97d/xreQ3rTypDdqObbWbTH7Y8EhpOwqMeP+WKW/+WgyXAks0dI+guFr8Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@oven/bun-darwin-x64": {
|
||||
"version": "1.1.22",
|
||||
"resolved": "https://registry.npmmirror.com/@oven/bun-darwin-x64/-/bun-darwin-x64-1.1.22.tgz",
|
||||
"integrity": "sha512-keEPJtDlvu/36J+NX1JUh6+u0PiyoRLVGdDNaVU5LsphnYIVL8A4VLAE+xA5FMPlvMyjVua8kYbgUuTTHJJGpg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@oven/bun-darwin-x64-baseline": {
|
||||
"version": "1.1.22",
|
||||
"resolved": "https://registry.npmmirror.com/@oven/bun-darwin-x64-baseline/-/bun-darwin-x64-baseline-1.1.22.tgz",
|
||||
"integrity": "sha512-r1IOBt7A3NVfM3/PYkfpef3fo1cIdznRzCpE/XwEquYBbMFcvRETWWRUUNK80MFttYaPQuhyHui/b0VLJhoaEw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@oven/bun-linux-aarch64": {
|
||||
"version": "1.1.22",
|
||||
"resolved": "https://registry.npmmirror.com/@oven/bun-linux-aarch64/-/bun-linux-aarch64-1.1.22.tgz",
|
||||
"integrity": "sha512-qL7IVUIaCFzSYae1UhX0rSbG1I1ARH7t3d9EMUxG//nBOqdI5xgEmpFCWPh8Y1mdpPl3bPMT0EvmNx/HjFrUJw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@oven/bun-linux-x64": {
|
||||
"version": "1.1.22",
|
||||
"resolved": "https://registry.npmmirror.com/@oven/bun-linux-x64/-/bun-linux-x64-1.1.22.tgz",
|
||||
"integrity": "sha512-y4ugmfIg9GlXgZPj2mE5D9g+ou8kwMgSraR4zWvaPPSGDB2nbULGAA9S5DCVEBAuTBxMgh3wXlEgZwQKPmDPuQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@oven/bun-linux-x64-baseline": {
|
||||
"version": "1.1.22",
|
||||
"resolved": "https://registry.npmmirror.com/@oven/bun-linux-x64-baseline/-/bun-linux-x64-baseline-1.1.22.tgz",
|
||||
"integrity": "sha512-xTaKbyAxn4jI5CaL13mhkj/wCNphDVHrxMIEfPW4rkVbnY/4Ci2uG9dRrNAXCxwRmyflcp8t2KWmmAUBS95McQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@oven/bun-windows-x64": {
|
||||
"version": "1.1.22",
|
||||
"resolved": "https://registry.npmmirror.com/@oven/bun-windows-x64/-/bun-windows-x64-1.1.22.tgz",
|
||||
"integrity": "sha512-VNgJaK54MnyS4o47JBN0oMh+75kgaHrMt3HWS3Ree1zn2qYyAexeC9m6KPynHGtNFQrxuhHv5ULxJ0Z0pAU7+A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@oven/bun-windows-x64-baseline": {
|
||||
"version": "1.1.22",
|
||||
"resolved": "https://registry.npmmirror.com/@oven/bun-windows-x64-baseline/-/bun-windows-x64-baseline-1.1.22.tgz",
|
||||
"integrity": "sha512-Xdf0ZgonVup+YgFSTaGkzDpgcxojc2whFcaNvV0BJtTsl2MeAwGFl98AziGJSCh0ooG80ipUEIUoxDJBWxaEYw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmmirror.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
@@ -3539,6 +3645,36 @@
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/bun": {
|
||||
"version": "1.1.22",
|
||||
"resolved": "https://registry.npmmirror.com/bun/-/bun-1.1.22.tgz",
|
||||
"integrity": "sha512-G2HCPhzhjDc2jEDkZsO9vwPlpHrTm7a8UVwx9oNS5bZqo5OcSK5GPuWYDWjj7+37bRk5OVLfeIvUMtSrbKeIjQ==",
|
||||
"cpu": [
|
||||
"arm64",
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"os": [
|
||||
"darwin",
|
||||
"linux",
|
||||
"win32"
|
||||
],
|
||||
"bin": {
|
||||
"bun": "bin/bun.exe",
|
||||
"bunx": "bin/bun.exe"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@oven/bun-darwin-aarch64": "1.1.22",
|
||||
"@oven/bun-darwin-x64": "1.1.22",
|
||||
"@oven/bun-darwin-x64-baseline": "1.1.22",
|
||||
"@oven/bun-linux-aarch64": "1.1.22",
|
||||
"@oven/bun-linux-x64": "1.1.22",
|
||||
"@oven/bun-linux-x64-baseline": "1.1.22",
|
||||
"@oven/bun-windows-x64": "1.1.22",
|
||||
"@oven/bun-windows-x64-baseline": "1.1.22"
|
||||
}
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz",
|
||||
@@ -18573,6 +18709,11 @@
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/title-case": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/title-case/-/title-case-4.3.1.tgz",
|
||||
"integrity": "sha512-VnPxQ+/j0X2FZ4ceGq1oLruTLjtN5Ul4sam5ypd4mDZLm1eHwkwip1gLxqhON/j4qyTlUlfPKslE/t4NPSlxhg=="
|
||||
},
|
||||
"node_modules/tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmmirror.com/tmp/-/tmp-0.0.33.tgz",
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"format": "npx prettier . --write && npx autocorrect --fix",
|
||||
"lint": "next lint",
|
||||
"lint:fix": "npx eslint --fix .",
|
||||
"newpost": "node ./scripts/newpost.mjs",
|
||||
"archive": "node ./scripts/archive.mjs"
|
||||
"newpost": "bun ./scripts/newpost.ts",
|
||||
"archive": "bun ./scripts/archive.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@giscus/react": "^3.0.0",
|
||||
@@ -83,6 +83,7 @@
|
||||
"tailwind-merge": "^2.0.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"title-case": "^4.3.1",
|
||||
"typescript": "5.2.2",
|
||||
"url-join": "^5.0.0",
|
||||
"zustand": "^4.4.7"
|
||||
@@ -103,6 +104,7 @@
|
||||
"@types/tar": "^6.1.11",
|
||||
"archiver": "^7.0.1",
|
||||
"autocorrect-node": "^2.11.1",
|
||||
"bun": "^1.1.22",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"feed": "^4.2.2",
|
||||
|
||||
@@ -1,37 +1,14 @@
|
||||
import { UserDataDirectory } from "@/consts/consts";
|
||||
import { getCurrentTime } from "@/lib/date";
|
||||
import { checkAndCreateDirectory, isDirectoryEmptySync } from "@/lib/file";
|
||||
import archiver from "archiver";
|
||||
import Color from "colors";
|
||||
import fs from "fs";
|
||||
import * as fs from "fs";
|
||||
import inquirer from "inquirer";
|
||||
import path from "path";
|
||||
import tar from "tar";
|
||||
import * as path from "path";
|
||||
import * as tar from "tar";
|
||||
|
||||
const UserDataDirectory = "./data";
|
||||
|
||||
function checkAndCreateDirectory(dirPath) {
|
||||
try {
|
||||
if (!fs.existsSync(dirPath)) {
|
||||
fs.mkdirSync(dirPath, { recursive: true });
|
||||
}
|
||||
fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
|
||||
return true;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function isDirectoryEmptySync(directory) {
|
||||
try {
|
||||
if (!fs.existsSync(directory)) {
|
||||
fs.mkdirSync(directory, { recursive: true });
|
||||
}
|
||||
const files = fs.readdirSync(directory);
|
||||
return files.length === 0;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function packageDirectory(sourceDir, outputFilePath) {
|
||||
function packageDirectory(sourceDir: string, outputFilePath: string) {
|
||||
const output = fs.createWriteStream(outputFilePath);
|
||||
const archive = archiver("tar", {
|
||||
gzip: true,
|
||||
@@ -51,7 +28,7 @@ function packageDirectory(sourceDir, outputFilePath) {
|
||||
archive.finalize();
|
||||
}
|
||||
|
||||
function extractTarGz(tarGzPath, targetDir) {
|
||||
function extractTarGz(tarGzPath: string, targetDir: string) {
|
||||
tar
|
||||
.x({
|
||||
file: tarGzPath,
|
||||
@@ -83,16 +60,13 @@ async function main() {
|
||||
})
|
||||
.then((answers) => {
|
||||
const { OutputDirPath } = answers;
|
||||
const date = new Date();
|
||||
const filename = `archive-${date.getFullYear()}-${
|
||||
date.getMonth() + 1
|
||||
}-${date.getDate()}-${date.getHours()}-${date.getMinutes()}-${date.getSeconds()}.tar.gz`;
|
||||
const { year, month, day, hours, minutes, seconds } = getCurrentTime();
|
||||
const filename = `archive-${year}-${month}-${day}-${hours}-${minutes}-${seconds}.tar.gz`;
|
||||
const outFilePath = path.join(OutputDirPath, filename);
|
||||
if (checkAndCreateDirectory(OutputDirPath)) {
|
||||
packageDirectory(UserDataDirectory, outFilePath);
|
||||
}
|
||||
checkAndCreateDirectory(OutputDirPath) && packageDirectory(UserDataDirectory, outFilePath);
|
||||
});
|
||||
break;
|
||||
|
||||
case "Unpack and restore user data":
|
||||
if (!isDirectoryEmptySync(UserDataDirectory)) {
|
||||
const { confirm } = await inquirer.prompt([
|
||||
@@ -106,25 +80,25 @@ async function main() {
|
||||
),
|
||||
},
|
||||
]);
|
||||
if (!confirm) {
|
||||
console.log("Operation canceled.");
|
||||
if (confirm) {
|
||||
inquirer
|
||||
.prompt({
|
||||
type: "input",
|
||||
name: "ArchivedPackagePath",
|
||||
message: "The archive package's path:",
|
||||
})
|
||||
.then((answers) => {
|
||||
const { ArchivedPackagePath } = answers;
|
||||
if (fs.existsSync(ArchivedPackagePath)) {
|
||||
extractTarGz(ArchivedPackagePath, UserDataDirectory);
|
||||
} else {
|
||||
console.log(Color.red("The archive package does not exist."));
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
inquirer
|
||||
.prompt({
|
||||
type: "input",
|
||||
name: "ArchiveFilePath",
|
||||
message: "The archive package's path:",
|
||||
})
|
||||
.then((answers) => {
|
||||
const { ArchiveFilePath } = answers;
|
||||
if (fs.existsSync(ArchiveFilePath)) {
|
||||
extractTarGz(ArchiveFilePath, UserDataDirectory);
|
||||
} else {
|
||||
console.log(Color.red("The archive package does not exist."));
|
||||
}
|
||||
});
|
||||
console.log("Operation canceled.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
import { spawn } from "child_process";
|
||||
import Color from "colors";
|
||||
import fs from "fs";
|
||||
import inquirer from "inquirer";
|
||||
import path from "path";
|
||||
import process from "process";
|
||||
|
||||
let today = new Date();
|
||||
|
||||
let year = today.getFullYear();
|
||||
let month = today.getMonth() + 1;
|
||||
let day = today.getDate();
|
||||
|
||||
month = month < 10 ? "0" + month : month;
|
||||
day = day < 10 ? "0" + day : day;
|
||||
|
||||
let formattedDate = year + "-" + month + "-" + day;
|
||||
|
||||
const questions = [
|
||||
{
|
||||
type: "input",
|
||||
name: "title",
|
||||
message: "What's the title?",
|
||||
validate: function (input) {
|
||||
if (input.trim() === "") {
|
||||
return "Please enter a title.";
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
name: "subtitle",
|
||||
message: "What's the subtitle?",
|
||||
},
|
||||
{
|
||||
type: "tags",
|
||||
name: "tags",
|
||||
message: "Assign tags for the posts and separate them with commas.",
|
||||
},
|
||||
{
|
||||
type: "confirm",
|
||||
name: "noPrompt",
|
||||
message: "Do NOT prompt this post? (D:false)",
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
type: "confirm",
|
||||
name: "pin",
|
||||
message: "Do you want to pin this post? (D:false)",
|
||||
default: false,
|
||||
},
|
||||
{
|
||||
type: "confirm",
|
||||
name: "allowShare",
|
||||
message: "Do you allow everybody share this post? (D:true)",
|
||||
default: true,
|
||||
},
|
||||
];
|
||||
|
||||
const template = (title, subtitle, tags, noPrompt, pin, allowShare) => `---
|
||||
title: ${JSON.stringify(title.toLowerCase())}
|
||||
subtitle: ${JSON.stringify(subtitle)}
|
||||
summary: ""
|
||||
coverURL: ""
|
||||
time: "${formattedDate}"
|
||||
tags: ${JSON.stringify(tags)}
|
||||
noPrompt: ${noPrompt}
|
||||
pin: ${pin}
|
||||
allowShare: ${allowShare}
|
||||
closed: false
|
||||
---
|
||||
`;
|
||||
|
||||
inquirer.prompt(questions).then((answers) => {
|
||||
const tags = answers.tags
|
||||
.split(",")
|
||||
.map((tag) => tag.trim())
|
||||
.filter((tag) => tag !== "");
|
||||
const content = template(answers.title, answers.subtitle, tags, answers.noPrompt, answers.pin, answers.allowShare);
|
||||
const sluggedTitle = answers.title.replace(/\s/g, "-");
|
||||
const postFileName = `${formattedDate}-${sluggedTitle}.md`;
|
||||
const postFilePath = path.resolve(path.join("./data/posts", postFileName));
|
||||
fs.writeFile(postFilePath, content, "utf-8", (err) => {
|
||||
if (err) console.log(err);
|
||||
console.log(Color.green(Color.bold("Create Post Succeed.")));
|
||||
console.log(`Open the file ${Color.cyan(postFilePath)} to write your blog now.`);
|
||||
console.log("Some fields, such as summary, need to be filled in by yourself after opening the file.");
|
||||
if (process.platform === "win32") {
|
||||
spawn("cmd", ["/c", "start", postFilePath]);
|
||||
return;
|
||||
}
|
||||
if (["darwin", "linux", "freebsd"].includes(process.platform)) {
|
||||
spawn("open", [postFilePath]);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
92
scripts/newpost.ts
Normal file
92
scripts/newpost.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { PostFilesDirectory } from "@/consts/consts";
|
||||
import { getCurrentTime } from "@/lib/date";
|
||||
import { ChildProcessWithoutNullStreams, SpawnSyncReturns, spawn, spawnSync } from "child_process";
|
||||
import colors from "colors";
|
||||
import fs from "fs";
|
||||
import inquirer, { QuestionCollection } from "inquirer";
|
||||
import _ from "lodash";
|
||||
import path from "path";
|
||||
import { titleCase } from "title-case";
|
||||
|
||||
type TAnswer = {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
tags: string;
|
||||
noPrompt: boolean;
|
||||
pin: boolean;
|
||||
allowShare: boolean;
|
||||
};
|
||||
|
||||
const questions: QuestionCollection<TAnswer> = [
|
||||
{
|
||||
type: "input",
|
||||
name: "title",
|
||||
message: "What's the title?",
|
||||
validate: (input: string) => (input.trim() === "" ? "Please enter a title." : true),
|
||||
},
|
||||
{ type: "input", name: "subtitle", message: "What's the subtitle?" },
|
||||
{ type: "input", name: "tags", message: "Assign tags for the posts and separate them with commas." },
|
||||
{ type: "confirm", name: "noPrompt", message: "Do NOT prompt this post? (D:false)", default: false },
|
||||
{ type: "confirm", name: "pin", message: "Do you want to pin this post? (D:false)", default: false },
|
||||
{ type: "confirm", name: "allowShare", message: "Do you allow everybody share this post? (D:true)", default: true },
|
||||
];
|
||||
|
||||
const createTemplate = (answers: TAnswer): string => {
|
||||
const { year, month, day } = getCurrentTime();
|
||||
const tags = JSON.stringify(
|
||||
answers.tags
|
||||
.split(",")
|
||||
.map((tag) => tag.trim())
|
||||
.filter((tag) => tag !== ""),
|
||||
);
|
||||
|
||||
return `---
|
||||
title: "${titleCase(answers.title)}"
|
||||
subtitle: "${answers.subtitle}"
|
||||
summary: ""
|
||||
author: ""
|
||||
coverURL: ""
|
||||
time: "${year}-${month}-${day}"
|
||||
tags: ${tags}
|
||||
noPrompt: ${answers.noPrompt}
|
||||
pin: ${answers.pin}
|
||||
allowShare: ${answers.allowShare}
|
||||
closed: false
|
||||
---`;
|
||||
};
|
||||
|
||||
const writePostFile = (filePath: string, content: string): void => {
|
||||
fs.writeFile(filePath, content, "utf-8", (err) => {
|
||||
if (err) {
|
||||
console.error("Error writing file:", err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(colors.green(colors.bold("Create Post Succeed.")));
|
||||
console.log(`Open the file ${colors.cyan(filePath)} to write your blog now.`);
|
||||
console.log("Some fields, such as summary, need to be filled in by yourself after opening the file.");
|
||||
|
||||
const openFileCommand: Record<string, () => ChildProcessWithoutNullStreams | SpawnSyncReturns<Buffer>> = {
|
||||
win32: () => spawn("cmd", ["/c", "start", filePath]),
|
||||
darwin: () => spawnSync("open", [filePath]),
|
||||
linux: () => spawnSync("xdg-open", [filePath]),
|
||||
freebsd: () => spawnSync("xdg-open", [filePath]),
|
||||
};
|
||||
|
||||
const command = openFileCommand[process.platform];
|
||||
if (command) command();
|
||||
else {
|
||||
console.log("Unsupported platform. Open the file manually please.");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
inquirer.prompt<TAnswer>(questions).then((answers) => {
|
||||
const { year, month, day } = getCurrentTime();
|
||||
const content = createTemplate(answers);
|
||||
const sluggedTitle = _.kebabCase(answers.title);
|
||||
const postFileName = `${year}-${month}-${day}-${sluggedTitle}.md`;
|
||||
const postFilePath = path.resolve(path.join(PostFilesDirectory, postFileName));
|
||||
|
||||
writePostFile(postFilePath, content);
|
||||
});
|
||||
Reference in New Issue
Block a user