109 lines
2.8 KiB
TypeScript
109 lines
2.8 KiB
TypeScript
import { createPost, updatePost, getPost } from "@/lib/posts";
|
|
import { DEFAULT_AUTHOR, CONTENT_DIR } from "@/lib/config";
|
|
import path from "path";
|
|
|
|
export interface Session {
|
|
title: string;
|
|
slug: string;
|
|
content: string;
|
|
categories: string[];
|
|
tags: string[];
|
|
author: string;
|
|
draft: boolean;
|
|
chunks: string[];
|
|
originalSlug?: string;
|
|
dirPath: string;
|
|
_pendingAudio?: {
|
|
filename: string;
|
|
fileId: string;
|
|
name: string | null;
|
|
artist: string | null;
|
|
};
|
|
}
|
|
|
|
function computeDirPath(title: string, date?: string, slug?: 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";
|
|
const uniquePart = slug || Date.now().toString(36);
|
|
return path.join(CONTENT_DIR, year, `${dateStr}-${titlePart}-${uniquePart}`);
|
|
}
|
|
|
|
const sessions = new Map<number, Session>();
|
|
|
|
export function getSession(chatId: number): Session {
|
|
if (!sessions.has(chatId)) {
|
|
sessions.set(chatId, {
|
|
title: "",
|
|
slug: "",
|
|
content: "",
|
|
categories: [],
|
|
tags: [],
|
|
author: DEFAULT_AUTHOR,
|
|
draft: true,
|
|
chunks: [],
|
|
dirPath: "",
|
|
});
|
|
}
|
|
return sessions.get(chatId)!;
|
|
}
|
|
|
|
export function hasSession(chatId: number): boolean {
|
|
return sessions.has(chatId);
|
|
}
|
|
|
|
export function clearSession(chatId: number): void {
|
|
sessions.delete(chatId);
|
|
}
|
|
|
|
export function appendContent(chatId: number, text: string): void {
|
|
const s = getSession(chatId);
|
|
s.chunks.push(text + "\n\n");
|
|
s.content += text + "\n\n";
|
|
}
|
|
|
|
export function undoLastChunk(chatId: number): boolean {
|
|
const s = getSession(chatId);
|
|
if (s.chunks.length === 0) return false;
|
|
const lastChunk = s.chunks.pop()!;
|
|
const idx = s.content.lastIndexOf(lastChunk);
|
|
if (idx >= 0) {
|
|
s.content = s.content.slice(0, idx) + s.content.slice(idx + lastChunk.length);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export function initSessionDir(chatId: number, title: string, date?: string): void {
|
|
const s = getSession(chatId);
|
|
if (!s.dirPath) {
|
|
s.dirPath = computeDirPath(title, date, s.slug);
|
|
}
|
|
}
|
|
|
|
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: dateStr,
|
|
draft: isDraft,
|
|
categories: s.categories,
|
|
tags: s.tags,
|
|
author: s.author,
|
|
};
|
|
|
|
const existing = getPost(s.slug);
|
|
if (existing) {
|
|
const result = updatePost(s.slug, frontMatter, s.content);
|
|
if (!result.success) throw new Error("更新文章失败");
|
|
s.dirPath = result.dirPath;
|
|
} else {
|
|
const dirPath = createPost(frontMatter, s.content);
|
|
s.dirPath = dirPath;
|
|
}
|
|
}
|