精简若干功能,优化slug生成规则
This commit is contained in:
1 parent
05bf116c20
commit
f9b2a0e77b
15 files changed
+76
-41
No files matched your search
@@ -5,7 +5,7 @@ import { deployQueue } from "@/lib/git";
|
||||
import { hugo } from "@/lib/hugo";
|
||||
import { getLanIP, DEFAULT_AUTHOR } from "@/lib/config";
|
||||
import { sendMessage, tg } from "./tg";
|
||||
import { getSession, hasSession, clearSession, saveSession, undoLastChunk } from "./sessions";
|
||||
import { getSession, hasSession, clearSession, saveSession, undoLastChunk, initSessionDir } from "./sessions";
|
||||
import { makeSlug, sessionSummary, truncateText } from "./helpers";
|
||||
import { getCached, setCache, invalidateByPrefix } from "./cache";
|
||||
|
||||
@@ -221,6 +221,7 @@ handlers.new = async (chatId, title) => {
|
||||
s.draft = true;
|
||||
s.author = DEFAULT_AUTHOR;
|
||||
s.chunks = [];
|
||||
initSessionDir(chatId, title);
|
||||
await tg("sendMessage", {
|
||||
chat_id: chatId,
|
||||
text: "📝 开始写:<b>" + title + "</b>\n\n📂 设置分类(可选)",
|
||||
@@ -320,6 +321,7 @@ handlers.edit = async (chatId, slug) => {
|
||||
s.originalSlug = post.frontMatter.slug;
|
||||
s.content = "";
|
||||
s.chunks = [];
|
||||
s.dirPath = post.dirPath;
|
||||
s.categories = (post.frontMatter.categories as string[]) || [];
|
||||
s.tags = (post.frontMatter.tags as string[]) || [];
|
||||
s.author = post.frontMatter.author || DEFAULT_AUTHOR;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import path from "path";
|
||||
import { CONTENT_DIR } from "@/lib/config";
|
||||
|
||||
export function makeSlug(title: string): string {
|
||||
const dateStr = new Date().toISOString().slice(0, 10);
|
||||
const slugPart = (title || "untitled")
|
||||
.replace(/[^\w一-鿿㐀-䶿]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "")
|
||||
.toLowerCase() || "post";
|
||||
return dateStr + "-" + slugPart;
|
||||
const now = new Date();
|
||||
const y = now.getFullYear();
|
||||
const m = String(now.getMonth() + 1).padStart(2, "0");
|
||||
const d = String(now.getDate()).padStart(2, "0");
|
||||
const h = String(now.getHours()).padStart(2, "0");
|
||||
const mi = String(now.getMinutes()).padStart(2, "0");
|
||||
const s = String(now.getSeconds()).padStart(2, "0");
|
||||
return `${y}${m}${d}${h}${mi}${s}`;
|
||||
}
|
||||
|
||||
export function sessionSummary(s: {
|
||||
@@ -26,11 +25,6 @@ export function sessionSummary(s: {
|
||||
return parts.filter(Boolean).join(" · ");
|
||||
}
|
||||
|
||||
export function getArticleDirPath(slug: string): string {
|
||||
const year = slug.slice(0, 4);
|
||||
return path.join(CONTENT_DIR, year, slug);
|
||||
}
|
||||
|
||||
export function truncateText(text: string, maxLen: number): string {
|
||||
if (text.length <= maxLen) return text;
|
||||
return text.slice(0, maxLen) + "\n\n... 前 " + maxLen + " 字";
|
||||
|
||||
@@ -171,11 +171,14 @@ async function handlePhoto(chatId: number, photos: { file_id: string }[], captio
|
||||
try {
|
||||
const fs = await import("fs");
|
||||
const path = await import("path");
|
||||
const { CONTENT_DIR } = await import("@/lib/config");
|
||||
const { getSession } = await import("./sessions");
|
||||
const { getArticleDirPath } = await import("./helpers");
|
||||
|
||||
const s = getSession(chatId);
|
||||
if (!s.dirPath) {
|
||||
await sendMessage(chatId, "❌ 请先发 /new 或 /edit 开始写作");
|
||||
return;
|
||||
}
|
||||
|
||||
const largestPhoto = photos[photos.length - 1];
|
||||
const fileRes = await tg<{ file_path?: string }>("getFile", { file_id: largestPhoto.file_id });
|
||||
if (!fileRes.ok || !fileRes.result?.file_path) return;
|
||||
@@ -185,7 +188,7 @@ async function handlePhoto(chatId: number, photos: { file_id: string }[], captio
|
||||
const imgBuffer = await fetch(fileUrl).then((r) => r.arrayBuffer());
|
||||
|
||||
// Save to article's own folder (Hugo page bundle)
|
||||
const articleDir = getArticleDirPath(s.slug);
|
||||
const articleDir = s.dirPath;
|
||||
if (!fs.existsSync(articleDir)) fs.mkdirSync(articleDir, { recursive: true });
|
||||
|
||||
const ext = filePath.split(".").pop() || "jpg";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createPost, updatePost, getPost } from "@/lib/posts";
|
||||
import { DEFAULT_AUTHOR } from "@/lib/config";
|
||||
import { DEFAULT_AUTHOR, CONTENT_DIR } from "@/lib/config";
|
||||
import path from "path";
|
||||
|
||||
export interface Session {
|
||||
title: string;
|
||||
@@ -11,6 +12,18 @@ export interface Session {
|
||||
draft: boolean;
|
||||
chunks: string[];
|
||||
originalSlug?: string;
|
||||
dirPath: string;
|
||||
}
|
||||
|
||||
function computeDirPath(title: string, date?: string): string {
|
||||
const d = date ? new Date(date) : new Date();
|
||||
const year = d.getFullYear().toString();
|
||||
const dateStr = d.toISOString().slice(0, 10);
|
||||
const titlePart = (title || "untitled")
|
||||
.replace(/[^\w一-鿿㐀-䶿]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "")
|
||||
.toLowerCase() || "post";
|
||||
return path.join(CONTENT_DIR, year, `${dateStr}-${titlePart}`);
|
||||
}
|
||||
|
||||
const sessions = new Map<number, Session>();
|
||||
@@ -26,6 +39,7 @@ export function getSession(chatId: number): Session {
|
||||
author: DEFAULT_AUTHOR,
|
||||
draft: true,
|
||||
chunks: [],
|
||||
dirPath: "",
|
||||
});
|
||||
}
|
||||
return sessions.get(chatId)!;
|
||||
@@ -56,11 +70,19 @@ export function undoLastChunk(chatId: number): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function initSessionDir(chatId: number, title: string, date?: string): void {
|
||||
const s = getSession(chatId);
|
||||
if (!s.dirPath) {
|
||||
s.dirPath = computeDirPath(title, date);
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveSession(s: Session, isDraft: boolean): Promise<void> {
|
||||
const dateStr = new Date().toISOString().slice(0, 10);
|
||||
const frontMatter = {
|
||||
title: s.title,
|
||||
slug: s.slug,
|
||||
date: new Date().toISOString().slice(0, 10),
|
||||
date: dateStr,
|
||||
draft: isDraft,
|
||||
categories: s.categories,
|
||||
tags: s.tags,
|
||||
@@ -71,7 +93,9 @@ export async function saveSession(s: Session, isDraft: boolean): Promise<void> {
|
||||
if (existing) {
|
||||
const result = updatePost(s.slug, frontMatter, s.content);
|
||||
if (!result.success) throw new Error("更新文章失败");
|
||||
s.dirPath = result.dirPath;
|
||||
} else {
|
||||
createPost(frontMatter, s.content);
|
||||
const dirPath = createPost(frontMatter, s.content);
|
||||
s.dirPath = dirPath;
|
||||
}
|
||||
}
|
||||
@@ -155,7 +155,7 @@ export function createPost(frontMatter: PostFrontMatter, content: string): strin
|
||||
const date = new Date(frontMatter.date || new Date());
|
||||
const year = date.getFullYear().toString();
|
||||
const dateStr = date.toISOString().slice(0, 10);
|
||||
// Folder name: date + sanitized title (Chinese-friendly)
|
||||
// Folder name: date + sanitized title (human-readable on disk)
|
||||
const titlePart = (frontMatter.title || "untitled")
|
||||
.replace(/[^\w一-鿿㐀-䶿]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "")
|
||||
@@ -202,7 +202,11 @@ export function updatePost(
|
||||
const newDate = new Date(merged.date || post.frontMatter.date);
|
||||
const newYear = newDate.getFullYear().toString();
|
||||
const newDateStr = newDate.toISOString().slice(0, 10);
|
||||
const newDirName = `${newDateStr}-${frontMatter.slug}`;
|
||||
const titlePart = (merged.title || "untitled")
|
||||
.replace(/[^\w一-鿿㐀-䶿]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "")
|
||||
.toLowerCase() || "post";
|
||||
const newDirName = `${newDateStr}-${titlePart}`;
|
||||
const newDirPath = path.join(CONTENT_DIR, newYear, newDirName);
|
||||
|
||||
if (fs.existsSync(newDirPath) && newDirPath !== post.dirPath) {
|
||||
|
||||
Vendored
+2
-2
@@ -1,4 +1,4 @@
|
||||
declare module "marked" {
|
||||
export function marked(src: string): string;
|
||||
export function parse(src: string): string;
|
||||
export function parse(src: string, options?: Record<string, unknown>): string;
|
||||
export const marked: { parse: typeof parse };
|
||||
}
|
||||
Reference in new issue
Block a user