fix: unify comment counts across frontmatter, history sidebar, and comments file using recursive count

This commit is contained in:
@gapmiss 2026-07-13 11:51:46 -05:00
parent 4561bfe699
commit c9bd606f4c
3 changed files with 34 additions and 3 deletions

View file

@ -94,6 +94,21 @@ function renderComment(
return md;
}
function countNestedComments(comments: Comment[]): number {
let total = 0;
for (const c of comments) {
total += 1;
if (c.children) {
total += countNestedComments(c.children);
}
}
return total;
}
export function countAllComments(data: CommentsResponse): number {
return countNestedComments(data.comments);
}
export function renderComments(
data: CommentsResponse,
slug: string,

View file

@ -1,7 +1,7 @@
import { ItemView, normalizePath, Notice, setIcon, TFile, type WorkspaceLeaf } from 'obsidian';
import type SubstackClipperPlugin from './main';
import type { HistoryEntry } from './types';
import { fetchComments, renderComments } from './comments';
import { countAllComments, fetchComments, renderComments } from './comments';
export const HISTORY_VIEW_TYPE = 'substack-clipper-history';
@ -256,7 +256,22 @@ export class HistoryView extends ItemView {
`${this.plugin.settings.saveDirectory}/${entry.username}/${entry.slug}-comments.md`,
);
await this.plugin.writeFile(commentsPath, commentsMd);
entry.commentCount = commentsData.comments.length;
entry.commentCount = countAllComments(commentsData);
const notePath = normalizePath(
`${this.plugin.settings.saveDirectory}/${entry.username}/${entry.slug}.md`,
);
const noteFile = this.app.vault.getAbstractFileByPath(notePath);
if (noteFile instanceof TFile) {
const content = await this.app.vault.read(noteFile);
const updated = content.replace(
/^comment-count: \d+$/m,
`comment-count: ${String(entry.commentCount)}`,
);
if (updated !== content) {
await this.app.vault.modify(noteFile, updated);
}
}
}
entry.lastUpdated = new Date().toISOString();
succeeded++;

View file

@ -8,7 +8,7 @@ import { fetchHtml, extractPreloads, parsePost, parseUrl, extractImages, extract
import { htmlToMarkdown } from './converter';
import { postprocessMarkdown } from './postprocess';
import { downloadAllMedia } from './downloader';
import { fetchComments, renderComments } from './comments';
import { countAllComments, fetchComments, renderComments } from './comments';
export default class SubstackClipperPlugin extends Plugin {
settings: SubstackClipperSettings;
@ -115,6 +115,7 @@ export default class SubstackClipperPlugin extends Plugin {
await this.writeFile(commentsJsonPath, JSON.stringify(commentsData, null, 2));
}
article.commentCount = countAllComments(commentsData);
const commentsMd = renderComments(commentsData, slug, domain);
const commentsPath = normalizePath(`${this.settings.saveDirectory}/${username}/${slug}-comments.md`);
await this.writeFile(commentsPath, commentsMd);