fix(watchlist): preserve custom body sections through sync rewrite
renderNote wiped any ## heading not owned by the renderer (Synopsis, Cast, Links, My Notes) on every sync, destroying user content like ## Collection graph-link sections. extractCustomSections now pulls non-owned sections out of the existing body before rewrite, and renderNote re-emits them verbatim, in original order, between Links and My Notes.
This commit is contained in:
parent
2c663568ca
commit
fb3f52e4b0
6 changed files with 130 additions and 4 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { parseNote, extractMyNotes, noteTmdbRef } from 'packages/obsidian/src/watchlist/parse';
|
||||
import { parseNote, extractMyNotes, extractCustomSections, noteTmdbRef } from 'packages/obsidian/src/watchlist/parse';
|
||||
import { buildRecord } from 'packages/obsidian/src/watchlist/build';
|
||||
import { renderNote } from 'packages/obsidian/src/watchlist/render';
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ export async function syncFolder(deps: SyncDeps, opts: SyncOptions = {}): Promis
|
|||
}
|
||||
const detail: any = await withRateLimitRetry(() => deps.fetchDetail(ref.tmdbId, ref.isMovie), deps.sleep);
|
||||
const record = buildRecord(detail, ref.isMovie, frontmatter);
|
||||
const rendered = renderNote(record, extractMyNotes(body));
|
||||
const rendered = renderNote(record, extractMyNotes(body), extractCustomSections(body));
|
||||
report.synced++;
|
||||
if (strip(frontmatter['watch_status']) === 'Watched' && record.watchStatus === 'Unwatched') {
|
||||
report.flipped.push(note.path);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,37 @@ export function extractMyNotes(body: string): string {
|
|||
return m ? m[1].trim() : '';
|
||||
}
|
||||
|
||||
const OWNED_HEADINGS = new Set(['Synopsis', 'Cast', 'Links', 'My Notes']);
|
||||
|
||||
export interface CustomSection {
|
||||
heading: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export function extractCustomSections(body: string): CustomSection[] {
|
||||
const lines = (body ?? '').split('\n');
|
||||
const sections: CustomSection[] = [];
|
||||
let heading: string | null = null;
|
||||
let buf: string[] = [];
|
||||
const flush = (): void => {
|
||||
if (heading === null) return;
|
||||
const content = buf.join('\n').replace(/(\n\s*)+$/, '');
|
||||
if (!OWNED_HEADINGS.has(heading)) sections.push({ heading, content });
|
||||
};
|
||||
for (const line of lines) {
|
||||
const m = /^##\s+(.*)$/.exec(line);
|
||||
if (m) {
|
||||
flush();
|
||||
heading = m[1].trim();
|
||||
buf = [];
|
||||
} else if (heading !== null) {
|
||||
buf.push(line);
|
||||
}
|
||||
}
|
||||
flush();
|
||||
return sections;
|
||||
}
|
||||
|
||||
export function stripQuotes(s: string | undefined): string {
|
||||
return (s ?? '').trim().replace(/^"|"$/g, '');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import type { WatchlistRecord } from 'packages/obsidian/src/watchlist/schema';
|
||||
import { yamlList, yamlScalar, quotedOrNull } from 'packages/obsidian/src/watchlist/yaml';
|
||||
import type { CustomSection } from 'packages/obsidian/src/watchlist/parse';
|
||||
|
||||
const CATEGORY_TAG: Record<string, string> = { Movie: 'movie', Series: 'series', Anime: 'anime' };
|
||||
|
||||
export function renderNote(r: WatchlistRecord, myNotes: string): string {
|
||||
export function renderNote(r: WatchlistRecord, myNotes: string, customSections: CustomSection[] = []): string {
|
||||
const tag = CATEGORY_TAG[r.category];
|
||||
const stars = r.ratingStars;
|
||||
const fm = [
|
||||
|
|
@ -67,6 +68,7 @@ export function renderNote(r: WatchlistRecord, myNotes: string): string {
|
|||
if (r.homepage) links.push(`- [Homepage](${r.homepage})`);
|
||||
if (r.notionUrl) links.push(`- [Original Notion entry](${r.notionUrl})`);
|
||||
if (links.length) b.push('## Links', ...links, '');
|
||||
for (const s of customSections) b.push(`## ${s.heading}`, s.content, '');
|
||||
b.push('## My Notes', '', myNotes);
|
||||
if (myNotes) b.push('');
|
||||
return fm.join('\n') + '\n' + b.join('\n');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue