|
|
@@ -891,17 +891,36 @@ export async function hashContent(content: string): Promise<string> {
|
|
|
return hash.digest("hex");
|
|
|
}
|
|
|
|
|
|
-export function extractTitle(content: string, filename: string): string {
|
|
|
- const match = content.match(/^##?\s+(.+)$/m);
|
|
|
- if (match) {
|
|
|
- const title = (match[1] ?? "").trim();
|
|
|
- if (title === "📝 Notes" || title === "Notes") {
|
|
|
- const nextMatch = content.match(/^##\s+(.+)$/m);
|
|
|
- if (nextMatch?.[1]) return nextMatch[1].trim();
|
|
|
+const titleExtractors: Record<string, (content: string) => string | null> = {
|
|
|
+ '.md': (content) => {
|
|
|
+ const match = content.match(/^##?\s+(.+)$/m);
|
|
|
+ if (match) {
|
|
|
+ const title = (match[1] ?? "").trim();
|
|
|
+ if (title === "📝 Notes" || title === "Notes") {
|
|
|
+ const nextMatch = content.match(/^##\s+(.+)$/m);
|
|
|
+ if (nextMatch?.[1]) return nextMatch[1].trim();
|
|
|
+ }
|
|
|
+ return title;
|
|
|
}
|
|
|
- return title;
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+ '.org': (content) => {
|
|
|
+ const titleProp = content.match(/^#\+TITLE:\s*(.+)$/im);
|
|
|
+ if (titleProp?.[1]) return titleProp[1].trim();
|
|
|
+ const heading = content.match(/^\*+\s+(.+)$/m);
|
|
|
+ if (heading?.[1]) return heading[1].trim();
|
|
|
+ return null;
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+export function extractTitle(content: string, filename: string): string {
|
|
|
+ const ext = filename.slice(filename.lastIndexOf('.')).toLowerCase();
|
|
|
+ const extractor = titleExtractors[ext];
|
|
|
+ if (extractor) {
|
|
|
+ const title = extractor(content);
|
|
|
+ if (title) return title;
|
|
|
}
|
|
|
- return filename.replace(/\.md$/, "").split("/").pop() || filename;
|
|
|
+ return filename.replace(/\.[^.]+$/, "").split("/").pop() || filename;
|
|
|
}
|
|
|
|
|
|
// =============================================================================
|