Export Kindle Marker for Cosense
KindleのマーカーをCosenseにエクスポートするツール
マーカー(ハイライト)については他の記事を参照
「Kindle」ハイライトの使い方・消す方法・一覧表示のやり方 メモ機能も便利 - カイドキ
Export形式がHTMLで扱いづらかったのでwogikaze.icon
https://gyazo.com/f894b7f43dbc33722c8c53c78e36f7dc
https://gyazo.com/00787a47465a17e1e3b5e838b10bff0b
以下の形式にしたい
『アウトライン・プロセッシング入門: アウトライナーで文章を書き、考える技術』
Part 1 アウトライナーとアウトライン・プロセッシング
1.1 アウトライナーとは
アウト ライナー を 「 アウトライン を 利用 し て 文章 を 書き 、 考える ため の ソフト 」 だ と 定義 し て おき ましょ う 。 そして 「 アウトライン を 利用 し て 文章 を 書き 、 考える こと 」 が アウトライン ・ プロセッシング です 。 (14p)
アウトライン を 折りたたむ 機能
a
『アウトライン・プロセッシング入門: アウトライナーで文章を書き、考える技術』
Part 1 アウトライナーとアウトライン・プロセッシング
1.1 アウトライナーとは
アウト ライナー を 「 アウトライン を 利用 し て 文章 を 書き 、 考える ため の ソフト 」 だ と 定義 し て おき ましょ う
そして 「 アウトライン を 利用し て 文章 を 書き 、 考える こと 」 が アウトライン ・ プロセッシング です
ハイライト(ピンク) - 1.2 アウトライナーの三つの基本機能 > 16ページ ·位置No. 200 (14p)
1.2 アウトライナーの三つの基本機能
アウトライン を 折りたたむ 機能ハイライト(ピンク) - 1.2 アウトライナーの三つの基本機能 > 18ページ ·位置No. 207 (16p)
1.2 アウトライナーの三つの基本機能
アウトライン を 組み替える 機能ハイライト(オレンジ) - 1.3 アウトライナーを選ぶ > 26ページ ·位置No. 267 (18p)
1.3 アウトライナーを選ぶ
自由 な アウトライン ・ プロセッシング に 適し て いる のは 、 1 ペイン 方式 で 、 「 本文 」 と 「 見出し 」 を 区別 し ない タイプ の アウト ライナー です
ハイライト(オレンジ) - 1.4 アウトライナーを使うということ > 30ページ· 位置No. 330 (26p)
1.4 アウトライナーを使うということ
アウトライン と 聞い た 途端 に ハイスクール の 作文 の 授業 を 思い出し て この セクション を 飛ばそ う と し て いる 人 が い たら 、 ちょっと だけ 待っ てください
ハイライト(オレンジ) - 1.4 アウトライナーを使うということ > 30ページ· 位置No. 332 (30p)
1.4 アウトライナーを使うということ
要領 の いい 学生 は 、 アウトライン の 提出 期限 までに 本文 を 全部 書い て しまい 、 アウトライン を 後 から でっち上げ て い たハイライト(オレンジ) - 1.5 シェイク > 35ページ · 位置No.395 (30p)
1.5 シェイク
それ を 許容 せ ず 「 予定 通り 」 に こだわる こと は 、 せっかく の 宝物 を 捨てる よう な もの です
ハイライト(オレンジ) - 1.5 シェイク > 35ページ · 位置No.397 (35p)
1.5 シェイク
既存 の アウトライン に 収まら ない もの は 、 いったん 「 未使用 」 の 下 に 入れ て おき ます
面倒 で あれ ば 、 遠慮 せ ず その 場 に 書い て しまって 後 から 「 未使用 」 に 動かし ます
ハイライト(ピンク) - 1.5 シェイク > 37ページ · 位置No. 413 (35p)
1.5 シェイク
「 構成 を 考える こと 」 と 「 フレーズ を 考える こと 」 を 分離 する (37p)
code:js
// Create a hidden file input and a button to trigger it
const button = document.createElement('button');
button.textContent = 'Load HTML File';
button.style.padding = '8px 16px';
button.style.fontSize = '14px';
document.body.appendChild(button);
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = 'text/html';
fileInput.style.display = 'none';
document.body.appendChild(fileInput);
// When button is clicked, open the file picker
button.addEventListener('click', () => {
fileInput.click();
});
fileInput.addEventListener('change', () => {
const file = fileInput.files0;
if (!file) return;
const reader = new FileReader();
reader.onload = () => {
try {
const text = reader.result;
// Parse as HTML
const parser = new DOMParser();
const doc = parser.parseFromString(text, 'text/html');
// Check for parse errors
if (doc.querySelector('parsererror')) {
throw new Error('Invalid HTML document');
}
// Parse highlights from the HTML document
const output = parseHtmlHighlights(doc);
// Log to console
console.log(output);
// Copy to clipboard
navigator.clipboard.writeText(output).then(
() => console.log('Copied to clipboard'),
() => console.warn('Copy to clipboard failed')
);
} catch (err) {
alert(err.message);
}
};
reader.onerror = () => {
alert('Failed to read file');
};
reader.readAsText(file, 'UTF-8');
});
function parseHtmlHighlights(doc) {
const output = [];
// Ensure the script is running in a browser context with the HTML loaded
if (typeof doc === 'undefined') {
console.error("This script must be run in a browser environment.");
return "";
}
const bookTitleElement = doc.querySelector('.bookTitle');
if (!bookTitleElement) {
console.warn("Book title element (.bookTitle) not found.");
// Allow to continue if other parts can be parsed, but title will be missing.
// output.push("TITLE NOT FOUND");
} else {
const title = bookTitleElement.textContent.trim();
output.push(title);
}
output.push(""); // Blank line after title (or in place of title if not found)
const sectionElements = doc.querySelectorAll('.sectionHeading');
sectionElements.forEach(sectionElement => {
const sectionTitle = sectionElement.textContent.trim();
output.push(sectionTitle);
output.push(""); // Blank line after section title
let currentNode = sectionElement.nextElementSibling;
while (currentNode && !currentNode.classList.contains('sectionHeading')) {
if (currentNode.classList.contains('noteHeading')) {
const noteHeadingElement = currentNode;
// Check if the next sibling exists and is a .noteText element
if (noteHeadingElement.nextElementSibling && noteHeadingElement.nextElementSibling.classList.contains('noteText')) {
const noteTextElement = noteHeadingElement.nextElementSibling;
const noteHeadingText = noteHeadingElement.textContent.trim();
// Extract page number: "Highlight (color) - Page XX" -> "Page XX"
const pageNumMatch = noteHeadingText.match(/Page\s*(\d+)/);
const pageNumString = pageNumMatch ? Page ${pageNumMatch[1]} : "";
const noteContentRaw = noteTextElement.textContent;
// Process content as per the template:
// {content.split("\n").map(line => line.trim()).join("").split("。").filter(line => line).join("\n> ");+{pagenum}}
// 1. content.split("\n").map(line => line.trim()).join("")
const singleLineContent = noteContentRaw.split("\n").map(line => line.trim()).join("");
// 2. .split("。")
// 3. .filter(line => line) --- robustly: map trim, then filter non-empty
const contentParts = singleLineContent.split("。")
.map(part => part.trim()) // Trim each part resulting from split
.filter(part => part !== ""); // Filter out parts that are now empty
let formattedNoteBody = "";
if (contentParts.length > 0) {
// 4. .join("\n> ")
const joinedContent = contentParts.join("\n\n> ");
// Prepend "> " to the whole processed content block
formattedNoteBody = "> " + joinedContent;
}
// Append "+{pagenum}"
// If formattedNoteBody is empty (e.g., noteText was empty or just "。") and pageNumString exists,
// this will result in something like "+Page XX".
// If formattedNoteBody has content and pageNumString is empty, it's just the content.
const finalNoteLine = formattedNoteBody + (pageNumString ? ${pageNumString} : "");
output.push(finalNoteLine);
currentNode = noteTextElement.nextElementSibling; // Move to the element after noteText
} else {
// .noteHeading not followed by a .noteText or no next sibling
// Move to the next sibling of .noteHeading to continue search
currentNode = noteHeadingElement.nextElementSibling;
}
} else {
// Current element is not a .noteHeading (e.g., could be other elements like <hr> or text nodes)
// Move to the next sibling to continue search within the section
currentNode = currentNode.nextElementSibling;
}
}
// No extra blank line here. The separation comes from the next section's
// title being followed by its own blank line, or end of output.
});
return output.join('\n');
}