177 lines
6.5 KiB
TypeScript
177 lines
6.5 KiB
TypeScript
import { dialog } from 'electron';
|
|
import { getPostEngine } from '../engine/PostEngine';
|
|
import { getProjectEngine } from '../engine/ProjectEngine';
|
|
import { getMetaEngine } from '../engine/MetaEngine';
|
|
import { getMediaEngine } from '../engine/MediaEngine';
|
|
import { getPostMediaEngine } from '../engine/PostMediaEngine';
|
|
import { taskManager } from '../engine/TaskManager';
|
|
import {
|
|
getBlogGenerationEngine,
|
|
resolvePublicBaseUrl,
|
|
type BlogGenerationResult,
|
|
type BlogGenerationSection,
|
|
type BlogGenerationOptions,
|
|
type SiteValidationReport,
|
|
} from '../engine/BlogGenerationEngine';
|
|
import { resolvePageTitle } from '../engine/PageRenderer';
|
|
|
|
type SafeHandle = (channel: string, handler: (...args: any[]) => Promise<any>) => void;
|
|
|
|
export function registerBlogHandlers(safeHandle: SafeHandle): void {
|
|
const resolveBlogGenerationBaseOptions = async (): Promise<BlogGenerationOptions> => {
|
|
const projectEngine = getProjectEngine();
|
|
const postEngine = getPostEngine();
|
|
const metaEngine = getMetaEngine();
|
|
const mediaEngine = getMediaEngine();
|
|
const postMediaEngine = getPostMediaEngine();
|
|
|
|
const project = await projectEngine.getActiveProject();
|
|
if (!project) {
|
|
throw new Error('No active project');
|
|
}
|
|
|
|
const dataDir = projectEngine.getDataDir(project.id, project.dataPath);
|
|
postEngine.setProjectContext(project.id, dataDir);
|
|
metaEngine.setProjectContext(project.id, dataDir);
|
|
mediaEngine.setProjectContext(project.id, dataDir, dataDir);
|
|
postMediaEngine.setProjectContext(project.id);
|
|
|
|
if (!metaEngine.isInitialized()) {
|
|
await metaEngine.syncOnStartup();
|
|
}
|
|
|
|
const metadata = await metaEngine.getProjectMetadata();
|
|
const baseUrl = resolvePublicBaseUrl(metadata?.publicUrl);
|
|
if (!baseUrl) {
|
|
await dialog.showMessageBox({
|
|
type: 'warning',
|
|
title: 'Public URL Required',
|
|
message: 'Site rendering requires a public URL.',
|
|
detail: 'Set Project → Public URL in Settings before rendering the site.',
|
|
});
|
|
throw new Error('Project public URL is not configured');
|
|
}
|
|
|
|
const language = metadata?.mainLanguage?.trim() || 'en';
|
|
const pageTitle = resolvePageTitle(metadata, project.name, project.description ?? undefined);
|
|
|
|
return {
|
|
projectId: project.id,
|
|
projectName: metadata?.name?.trim() || project.name,
|
|
projectDescription: metadata?.description,
|
|
dataDir,
|
|
baseUrl,
|
|
maxPostsPerPage: metadata?.maxPostsPerPage,
|
|
language,
|
|
pageTitle,
|
|
picoTheme: metadata?.picoTheme,
|
|
categorySettings: (metadata as any)?.categorySettings,
|
|
};
|
|
};
|
|
|
|
safeHandle('blog:generateSitemap', async () => {
|
|
const blogGenerationEngine = getBlogGenerationEngine();
|
|
const baseOptions = await resolveBlogGenerationBaseOptions();
|
|
|
|
const taskTimestamp = Date.now();
|
|
const taskGroupId = `site-render-${taskTimestamp}`;
|
|
const taskGroupName = 'Render Site';
|
|
|
|
const runSectionTask = async (
|
|
section: BlogGenerationSection,
|
|
taskName: string,
|
|
taskIdPrefix: string,
|
|
): Promise<BlogGenerationResult> => {
|
|
return taskManager.runTask({
|
|
id: `${taskIdPrefix}-${taskTimestamp}`,
|
|
name: taskName,
|
|
groupId: taskGroupId,
|
|
groupName: taskGroupName,
|
|
execute: async (onProgress) => {
|
|
return blogGenerationEngine.generate({
|
|
...baseOptions,
|
|
sections: [section],
|
|
}, (progress, message) => onProgress(progress, message || ''));
|
|
},
|
|
});
|
|
};
|
|
|
|
const mergeResults = (results: BlogGenerationResult[]): BlogGenerationResult => {
|
|
const first = results[0];
|
|
return {
|
|
path: first.path,
|
|
urlCount: Math.max(...results.map((result) => result.urlCount)),
|
|
postCount: Math.max(...results.map((result) => result.postCount)),
|
|
feedPostCount: Math.max(...results.map((result) => result.feedPostCount)),
|
|
tagCount: Math.max(...results.map((result) => result.tagCount)),
|
|
categoryCount: Math.max(...results.map((result) => result.categoryCount)),
|
|
archiveCount: Math.max(...results.map((result) => result.archiveCount)),
|
|
pagesGenerated: results.reduce((sum, result) => sum + result.pagesGenerated, 0),
|
|
feeds: {
|
|
rssPath: first.feeds.rssPath,
|
|
atomPath: first.feeds.atomPath,
|
|
},
|
|
changed: {
|
|
sitemap: results.some((result) => result.changed.sitemap),
|
|
rss: results.some((result) => result.changed.rss),
|
|
atom: results.some((result) => result.changed.atom),
|
|
},
|
|
};
|
|
};
|
|
|
|
const coreResult = await taskManager.runTask({
|
|
id: `site-render-core-${taskTimestamp}`,
|
|
name: 'Render Site Core',
|
|
groupId: taskGroupId,
|
|
groupName: taskGroupName,
|
|
execute: async (onProgress) => {
|
|
return blogGenerationEngine.generate({
|
|
...baseOptions,
|
|
sections: ['core'],
|
|
}, (progress, message) => onProgress(progress, message || ''));
|
|
},
|
|
});
|
|
|
|
const [singleResult, categoryResult, tagResult, dateResult] = await Promise.all([
|
|
runSectionTask('single', 'Render Single Posts', 'site-render-single'),
|
|
runSectionTask('category', 'Render Category Archives', 'site-render-category'),
|
|
runSectionTask('tag', 'Render Tag Archives', 'site-render-tag'),
|
|
runSectionTask('date', 'Render Date Archives', 'site-render-date'),
|
|
]);
|
|
|
|
return mergeResults([coreResult, singleResult, categoryResult, tagResult, dateResult]);
|
|
});
|
|
|
|
safeHandle('blog:validateSite', async () => {
|
|
const blogGenerationEngine = getBlogGenerationEngine();
|
|
const baseOptions = await resolveBlogGenerationBaseOptions();
|
|
|
|
const taskTimestamp = Date.now();
|
|
return taskManager.runTask({
|
|
id: `site-validate-${taskTimestamp}`,
|
|
name: 'Validate Site',
|
|
execute: async (onProgress) => {
|
|
return blogGenerationEngine.validateSite(baseOptions, (progress, message) => {
|
|
onProgress(progress, message || 'Validating site...');
|
|
});
|
|
},
|
|
});
|
|
});
|
|
|
|
safeHandle('blog:applyValidation', async (_event, report: SiteValidationReport) => {
|
|
const blogGenerationEngine = getBlogGenerationEngine();
|
|
const baseOptions = await resolveBlogGenerationBaseOptions();
|
|
|
|
const taskTimestamp = Date.now();
|
|
return taskManager.runTask({
|
|
id: `site-validate-apply-${taskTimestamp}`,
|
|
name: 'Apply Site Validation',
|
|
execute: async (onProgress) => {
|
|
return blogGenerationEngine.applyValidation(baseOptions, report, (progress, message) => {
|
|
onProgress(progress, message || 'Applying site validation...');
|
|
});
|
|
},
|
|
});
|
|
});
|
|
}
|