Files
bookmarks2csv/index.html

93 lines
4.1 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'sha256-GrbW/7V8Uz8EhUWpt5wG+cXD0+oSGGwhtN58oOLkO80='; style-src 'sha256-obdhBsAz/wb7TcBO6Wel5haALofvN0sAMw8qwcpWG8c='; base-uri 'none'; form-action 'none'">
<title>本地安全书签转换器</title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; text-align: center; background: #f9f9f9; }
.box { background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
input { margin: 20px 0; }
button { background: #4CAF50; color: white; border: none; padding: 10px 20px; font-size: 16px; border-radius: 4px; cursor: pointer; }
button:hover { background: #45a049; }
#status { margin-top: 15px; color: #666; }
</style>
</head>
<body>
<div class="box">
<h2>本地离线书签转换器</h2>
<p>所有处理均在您的电脑本地完成,<b>不会上传书签文件</b>。</p>
<input type="file" id="fileInput" accept=".html"><br>
<button id="convertButton" type="button">一键转换并下载 CSV</button>
<p id="status" role="status"></p>
</div>
<script>
function toCsvField(value) {
// A visible text prefix avoids spreadsheet formula interpretation.
if (/^[\s\u0000-\u001f\u007f]*[=+@\-=+@-]/u.test(value) || /^[\u0000-\u001f\u007f]/u.test(value)) {
value = `文本:${value}`;
}
return `"${value.replace(/"/g, '""')}"`;
}
function bookmarkHtmlToCsv(htmlContent) {
// Template contents stay in an inert document and are never mounted.
const template = document.createElement('template');
template.innerHTML = htmlContent;
const rows = ['\uFEFFTitle,URL'];
let count = 0;
template.content.querySelectorAll('a[href]').forEach(link => {
let url;
try {
url = new URL(link.getAttribute('href'));
} catch {
return;
}
if (url.protocol !== 'http:' && url.protocol !== 'https:') return;
rows.push(`${toCsvField(link.textContent)},${toCsvField(url.href)}`);
count++;
});
return { csvContent: rows.join('\r\n') + '\r\n', count };
}
function convertBookmarks() {
const fileInput = document.getElementById('fileInput');
const status = document.getElementById('status');
if (fileInput.files.length === 0) {
alert('请先选择从 Chrome 导出的 bookmarks.html 文件!');
return;
}
const file = fileInput.files[0];
const reader = new FileReader();
reader.onload = function(e) {
const htmlContent = e.target.result;
const { csvContent, count } = bookmarkHtmlToCsv(htmlContent);
// 触发本地浏览器下载
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'bookmarks_output.csv';
document.body.appendChild(a);
try {
a.click();
} finally {
a.remove();
setTimeout(() => URL.revokeObjectURL(url), 1000);
}
status.textContent = `🎉 转换成功!共提取了 ${count} 个书签,已自动下载 CSV 文件。`;
};
reader.onerror = () => {
status.textContent = '无法读取文件,请重新选择文件后重试。';
};
reader.readAsText(file);
}
document.getElementById('convertButton').addEventListener('click', convertBookmarks);
</script>
</body>
</html>