Skip to content

Commit c354730

Browse files
authored
[enhancement] pull review from Notion page content (#272)
1 parent cca6015 commit c354730

File tree

1 file changed

+79
-12
lines changed

1 file changed

+79
-12
lines changed

bin/shelf.js

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ const cleanupDataFields = async (notionResponse) => {
4343
pages,
4444
current_page,
4545
situ,
46-
review,
46+
review, // will be deprecated once I fully migrate to reviewed
47+
reviewed,
4748
link,
4849
} = book.properties;
4950

@@ -56,32 +57,52 @@ const cleanupDataFields = async (notionResponse) => {
5657
}
5758
if (author.select !== null) cleanBook.author = author.select.name;
5859
if (ISBN.number !== null) cleanBook.isbn = ISBN.number;
59-
if (started.date !== null) cleanBook.started = started.date.start;
60-
if (finished && finished.date !== null) {
60+
if (started?.date !== null) cleanBook.started = started.date.start;
61+
if (finished?.date !== null) {
6162
cleanBook.finished = finished.date.start;
6263
}
63-
if (publisher && publisher.select !== null) {
64+
if (publisher?.select !== null) {
6465
cleanBook.publisher = publisher.select.name;
6566
}
66-
if (pages && pages.number !== null) {
67+
if (pages?.number !== null) {
6768
cleanBook.pages = pages.number;
6869
}
69-
if (current_page && current_page.number !== null) {
70+
if (current_page?.number !== null) {
7071
cleanBook.current_page = current_page.number;
7172
}
7273

7374
if (cleanBook.finished) {
7475
const finalPath = await possiblySaveNewSituImage(title, finished, situ);
7576
if (finalPath) cleanBook.situ = finalPath;
7677
}
77-
if (review && review.rich_text.length > 0) {
78+
if (review?.rich_text.length > 0) {
7879
// Necessary to stitch rich_text components together like this to preserve any hyperlinks
79-
cleanBook.review = review.rich_text.reduce((finalText, current) => {
80-
if (current.type !== "text") return finalText;
81-
if (current.href === null) return (finalText += current.plain_text);
82-
return (finalText += `<a href=\"${current.href}\">${current.plain_text}</a>`);
83-
}, "");
80+
cleanBook.review = reduceRichTextToHTMLString(review.rich_text);
8481
}
82+
83+
/**
84+
* Setting up some more robust review infrastructure here alongside the existing one.
85+
*
86+
* Here's the loose plan:
87+
* 1. If there is no review, but there are blocks, then parse and squish all the blocks together as the review
88+
* 2. Once this is working properly, we can shift the review data from a property to entirely this.
89+
*
90+
* Note that final state is not necessarily easiest implementation for this code, but for my personal workflow.
91+
*/
92+
93+
if (reviewed?.checkbox === true) {
94+
const pageBlocks = await notion.blocks.children.list({
95+
block_id: book.id,
96+
page_size: 100,
97+
});
98+
if (pageBlocks.results.length > 0) {
99+
const htmlReview = reduceBlocksToSingleHTMLString(pageBlocks.results);
100+
if (htmlReview !== "") {
101+
cleanBook.review = htmlReview;
102+
}
103+
}
104+
}
105+
85106
if (link && link.url !== null) cleanBook.link = link.url;
86107

87108
return cleanBook;
@@ -90,6 +111,52 @@ const cleanupDataFields = async (notionResponse) => {
90111
return Promise.all(cleanBooks);
91112
};
92113

114+
const annotationsWrapper = (text, annotations) => {
115+
const applicable = Object.keys(annotations).filter(
116+
(x) => annotations[x] === true,
117+
);
118+
if (applicable.length === 0) return text;
119+
120+
let finalText = text;
121+
for (const annotation of applicable) {
122+
if (annotation === "bold") finalText = `<strong>${finalText}</strong>`;
123+
if (annotation === "italic") finalText = `<em>${finalText}</em>`;
124+
if (annotation === "underline") finalText = `<u>${finalText}</u>`;
125+
if (annotation === "strikethrough") finalText = `<s>${finalText}</s>`;
126+
if (annotation === "code") finalText = `<code>${finalText}</code>`;
127+
}
128+
129+
return finalText;
130+
};
131+
132+
const reduceRichTextToHTMLString = (richTextArray) => {
133+
return richTextArray.reduce((finalText, current) => {
134+
if (current.type !== "text") return finalText;
135+
if (current.href === null) {
136+
return (finalText += annotationsWrapper(
137+
current.plain_text,
138+
current.annotations,
139+
));
140+
}
141+
return (finalText += `<a href=\"${current.href}\">${annotationsWrapper(current.plain_text, current.annotations)}</a>`);
142+
}, "");
143+
};
144+
145+
const reduceBlocksToSingleHTMLString = (blockList) => {
146+
return blockList.reduce((finalText, currentBlock) => {
147+
// Only supporting these two types for now
148+
if (!["paragraph", "quote"].includes(currentBlock.type)) {
149+
return finalText;
150+
}
151+
if (currentBlock.type === "paragraph") {
152+
return (finalText += `<p>${reduceRichTextToHTMLString(currentBlock.paragraph.rich_text)}</p>`);
153+
}
154+
if (currentBlock.type === "quote") {
155+
return (finalText += `<blockquote><p>${reduceRichTextToHTMLString(currentBlock.quote.rich_text)}</p></blockquote>`);
156+
}
157+
}, "");
158+
};
159+
93160
const possiblySaveNewSituImage = async (title, finished, situ) => {
94161
if (!finished || finished.date === null || !title.title) {
95162
return;

0 commit comments

Comments
 (0)