Last active
March 2, 2025 06:46
-
-
Save uroybd/cbfce7135b8efa61964f89234e52f39d to your computer and use it in GitHub Desktop.
Obsidian Boox Highlight formatter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%* | |
// Note style prefixes we will map to callouts. | |
// It will suffice to put just this character to change the callout style. | |
// If additional notes are required, we will use a space after the prefix, | |
// and then continue to our usual note. | |
// Customize this as you see fit. With types from: https://help.obsidian.md/Editing+and+formatting/Callouts#Supported+types | |
const NOTE_STYLES = { | |
"!": { | |
type: "important", | |
title: "Striking/Intense", | |
}, | |
"@": { | |
type: "danger", | |
title: "In Discord", | |
}, | |
"?": { | |
type: "question", | |
title: "Thought Provoking", | |
}, | |
"/": { | |
type: "sceptic", | |
title: "Sceptic" | |
}, | |
"~": { | |
type: "warning", | |
title: "Unsound" | |
}, | |
"#": { | |
type: "stylish", | |
title: "Stylish" | |
} | |
} | |
const NOTE_STYLE_KEYS = Object.keys(NOTE_STYLES); | |
// Default note style, if any prefix is not present. | |
const DEFAULT_NOTE_STYLE = { | |
type: "quote", | |
title: "Quotable/Concept/General Idea" | |
} | |
function parseNoteFormat(note) { | |
let data = {...DEFAULT_NOTE_STYLE, note}; | |
for (let i = 0; i < NOTE_STYLE_KEYS.length; i++) { | |
let key = NOTE_STYLE_KEYS[i]; | |
if (note.startsWith(key)) { | |
data = {...NOTE_STYLES[key], note: note.substr(key.length + 1)}; | |
break; | |
} | |
} | |
return data | |
} | |
function getTitleAndAuthor(l) { | |
l = l.split("<<")[1].split(">>"); | |
return { | |
title: l[0], | |
authors: l[1] | |
} | |
} | |
function parseNote(note) { | |
let lines = note.split("\n"); | |
lines = lines.reverse(); | |
let content = { | |
section: "", | |
timestamp: "", | |
page: "", | |
highlight: "", | |
note: "", | |
continued: false | |
} | |
for (let i = 0; i < lines.length; i++) { | |
let l = lines[i]; | |
console.log(l) | |
// For Neoreader v3 engine replace "【Annotation】" with "【Note】" | |
if (l.includes("【Annotation】")) { | |
const noteContent = l.replace('【Annotation】', ""); | |
content.note = parseNoteFormat(noteContent); | |
} else if (l.includes(" | Page No.: ")) { | |
let meta = l.split(" | Page No.: "); | |
console.log(meta) | |
content.timestamp = window.moment(meta[0]).format("DD MMM YYYY hh:mm:ss A") | |
content.page = parseInt(meta[1]) | |
} else if (i == lines.length - 1) { | |
content.section = l; | |
} else { | |
content.highlight = content.highlight ? `${l}\n${content.highlight}` : l; | |
} | |
} | |
if (!content.note) { | |
content.note = {...DEFAULT_NOTE_STYLE, note: ""} | |
} | |
console.log(content) | |
return content | |
} | |
function format_percentages(page, total) { | |
if (page && total) { | |
return `${((page / total) * 100).toFixed(2)}%`; | |
} | |
return ""; | |
} | |
let file = app.workspace.getActiveFile() | |
const content = await tp.system.prompt("Paste the JSON content", null, true, true); | |
let total_pages = await tp.system.prompt("Number of total pages"); | |
total_pages = parseInt(total_pages); | |
let lines = content.split("\n"); | |
let titleAndAuthor = getTitleAndAuthor(lines.shift()) | |
const notes = (lines.join("\n") + "\n").split("-------------------\n").map(n => { | |
let v = n.trim("\n"); | |
if (v.length) { | |
return parseNote(v); | |
} | |
return null; | |
}).filter(n => n !== null); | |
console.log(notes) | |
let output = `# ${titleAndAuthor.title}\n##### ${titleAndAuthor.authors}\n\n`; | |
let currentSection = null; | |
let prevNoteHeader = null; | |
for (let i = 0; i < notes.length; i++) { | |
let noteData = notes[i] | |
if (noteData.section && (currentSection != noteData.section)) { | |
output += `## ${noteData.section}\n`; | |
currentSection = noteData.section; | |
} | |
let noteHeader = `Page: ${noteData.page} (${format_percentages(noteData.page, total_pages)}) @ ${noteData.timestamp}\n`; | |
if (prevNoteHeader && prevNoteHeader.split(" / ")[0] == noteHeader) { | |
noteHeader += " / " + ((parseInt(prevNoteHeader.split(" /")[1]) || 1) + 1) | |
} | |
prevNoteHeader = noteHeader | |
let highlight = noteData.highlight; | |
output += `### ${noteHeader}\n${highlight}\n\n`; | |
output += `> [!${noteData.note.type}] ${noteData.note.title}`; | |
if (noteData.note.note) { | |
if (noteData.note.note.length > 50) { | |
output += `\n> ${noteData.note.note}` | |
} else { | |
output += `: ${noteData.note.note}`; | |
} | |
output += "\n"; | |
} | |
output += "\n\n" | |
} | |
await app.vault.modify(file, output) | |
%> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment