工具完成
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing

This commit is contained in:
2025-06-28 22:38:49 +08:00
parent 2c668fedd0
commit 8400dbfab9
60 changed files with 23197 additions and 144 deletions

526
public/index.html Normal file
View File

@ -0,0 +1,526 @@
<!DOCTYPE html>
<!--
MIT License
Copyright (c) 2016 Loo Rong Jie (Rong Jie Loo)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Special thanks to David King, Hennie Rozengarden, Jeroen Van Antwerpen,
Cor Koomen and other TC/RS Chromies in refining this tool.
-->
<html lang="en">
<head>
<title>Chrome Bookmarks Recovery Tool</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,minimum-scale=1.0">
<meta name="description" content="Tool to recover your lost Chrome bookmarks">
<link rel="canonical" href="https://rongjiecomputer.github.io/chrome/bookmark-recovery/">
<link rel="alternate" hreflang="en" href="https://rongjiecomputer.github.io/chrome/bookmark-recovery/">
<link rel="alternate" hreflang="es" href="https://rongjiecomputer.github.io/chrome/bookmark-recovery/index.es.html">
<meta property="og:type" content="website">
<meta property="og:title" content="Chrome Bookmarks Recovery Tool">
<meta property="og:url" content="https://rongjiecomputer.github.io/chrome/bookmark-recovery/">
<meta property="og:site_name" content="rongjiecomputer.github.io">
<meta property="og:description" content="Tool to recover your lost Chrome bookmarks">
<meta property="og:image" content="https://rongjiecomputer.github.io/chrome/bookmark-recovery/share.png">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Chrome Bookmarks Recovery Tool">
<meta name="twitter:url" content="https://rongjiecomputer.github.io/chrome/bookmark-recovery/">
<meta name="twitter:description" content="Tool to recover your lost Chrome bookmarks">
<meta name="twitter:image" content="https://rongjiecomputer.github.io/chrome/bookmark-recovery/share.png">
<style>
html, body {
font-family: "Helvetica", Arial, sans-serif;
font-size: 14px;
background-color: #fff;
margin: 0;
padding: 0;
}
header {
background-color: #f5f5f5;
padding: 10px 30px 10px 30px;
border-bottom: 1px solid #e5e5e5;
}
h1 {
font-size: 32px;
font-weight: 400;
}
a {
color: #4285f4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.github-link {
display: block;
position: absolute;
width: 60px;
height: 60px;
top: 0;
right: 0;
z-index: 100;
}
main {
padding: 30px;
}
p, li {
line-height: 1.5em;
word-break: break-word;
}
#tabs {
height: 48px;
margin-bottom: 32px;
padding: 0;
overflow: hidden;
border-bottom: 1px solid #e0e0e0;
}
#tabs a {
display: inline-block;
float: left;
color: #9e9e9e;
font-weight: 500;
line-height: 47px;
text-transform: uppercase;
padding: 0 10px;
text-decoration: none;
}
#tabs .active {
color: #4285f4;
border-bottom: 2px solid #4285f4;
}
.soln {
display: none;
}
.show {
display: block;
}
code {
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
background-color: #f7f7f7;
}
#block {
max-width: 650px;
margin-bottom: 30px;
padding: 10px;
border: 1px solid #ccc;
}
#drop_zone {
border: 2px dashed #bbb;
border-radius: 5px;
padding: 25px;
text-align: center;
color: #bbb;
}
.is_dragover {
border: 4px dashed #4386fa !important;
color: #4386fa !important;
}
.is_dragover svg {
fill: #4386fa;
}
label {
position: relative;
}
label b {
color: #000;
}
label:hover b {
color: #4386fa;
}
input[type="file"] {
position: absolute;
width: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
}
#tooltip {
display: none;
}
#drop_zone svg, #drop_zone span {
display: block;
margin: auto;
}
output {
display: block;
padding: 25px;
text-align: center;
}
output b {
color: red;
}
output ul {
padding: 0;
margin: 0;
list-style-type: none;
text-align: left;
}
output a {
color: #555;
text-decoration: underline;
}
output a[data-disabled] {
color: #ccc;
text-decoration: line-through;
}
.zip {
border-top: 1px solid #e0e0e0;
}
.zip-h {
display: block;
background-color: #fff;
color: #4285f4;
font-size: 14px;
font-weight: normal;
padding: 16px 50px 12px 16px;
margin: 0;
position: relative;
z-index: 1;
width: 100%;
border: 0;
text-align: left;
}
.zip-h:hover {
text-decoration: none;
}
.zip-h:before {
background: no-repeat url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%234285f4' d='M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z'/%3E%3C/svg%3E");
background-size: 24px;
content: '';
margin-top: -12px;
position: absolute;
right: 18px;
top: 50%;
width: 22px;
height: 22px;
transition: transform 0.3s;
}
.zip-content {
display: none;
margin-left: 18px;
padding: 1px 26px 19px 16px;
position: relative;
}
.zip-content:before {
background-color: #e0e0e0;
content: '';
position: absolute;
width: 2px;
height: 100%;
left: 0;
top: -19px;
}
.unzip .zip-h:before {
transform: rotate(-180deg);
}
.unzip .zip-content {
display: block;
}
footer {
background-color: #f5f5f5;
border-top: 1px solid #e5e5e5;
}
footer a {
display: inline-block;
padding: 20px 14px;
color: #999;
}
</style>
</head>
<body>
<header>
<h1>Chrome Bookmarks Recovery Tool</h1>
</header>
<main>
<div id="tabs" role="tablist" aria-label="Instructions">
<a href="#windows" id="windows-tab" role="tab" aria-controls="windows-soln">Windows</a>
<a href="#mac" id="mac-tab" role="tab" aria-controls="mac-soln">Mac</a>
<a href="#linux" id="linux-tab" role="tab" aria-controls="linux-soln">Linux</a>
<a href="#google" id="google-tab" role="tab" aria-controls="google-soln">Google Server</a>
</div>
<div class="soln" id="windows-soln" role="tabpanel" aria-labelledby="windows-tab" aria-hidden="true" tabindex="0">
<p>Here is how to recover your lost bookmarks (Windows):</p>
<ol>
<li>Copy <code>C:\Users\%username%\AppData\Local\Google\Chrome\User Data</code> into File Explorer.</li>
<li>In search bar, type <code>Bookmarks</code>, you will see a list of files named <code>Bookmarks</code> and/or <code>Bookmarks.bak</code>. (<i>Note: If there is more than one user using the same Chrome, bookmarks from other users will be listed too</i>)</li>
<li>Select all the files with mouse and drag them to the block below.</li>
<li>Download all the HTML files.</li>
<li>Open each HTML file with Chrome and determine the HTML file that contains your bookmarks. (<i>Note: The largest file is most likely the correct one</i>)</li>
<li>In your Chrome browser, click the Chrome menu icon and go to Bookmarks &gt; Bookmark Manager.</li>
<li>Click the menu icon beside search bar and click "Import Bookmarks".</li>
<li>Select the HTML file that contains your bookmarks.</li>
<li>Your bookmarks should now be imported back to Chrome.</li>
</ol>
</div>
<div class="soln" id="mac-soln" role="tabpanel" aria-labelledby="mac-tab" aria-hidden="true" tabindex="0">
<p>Here is how to recover your lost bookmarks (Mac):</p>
<ol>
<li>In the Mac menu bar at the top of the screen, click Go.</li>
<li>Select Go to Folder.</li>
<li>Type <code>~/Library/Application Support/Google/Chrome</code> and click Go.</li>
<li>In search bar, type <code>Bookmarks</code>, you will see a list of files named <code>Bookmarks</code> and/or <code>Bookmarks.bak</code>. (<i>Note: If there is more than one user using the same Chrome, bookmarks from other users will be listed too</i>)</li>
<li>Select all the files with mouse and drag them to the block below.</li>
<li>Download all the HTML files.</li>
<li>Open each HTML file with Chrome and determine the HTML file that contains your bookmarks. (<i>Note: The largest file is most likely the correct one</i>)</li>
<li>In your Chrome browser, click the Chrome menu icon and go to Bookmarks &gt; Bookmark Manager.</li>
<li>Click the menu icon beside search bar and click "Import Bookmarks".</li>
<li>Select the HTML file that contains your bookmarks.</li>
<li>Your bookmarks should now be imported back to Chrome.</li>
</ol>
</div>
<div class="soln" id="linux-soln" role="tabpanel" aria-labelledby="linux-tab" aria-hidden="true" tabindex="0">
<p>Here is how to recover your lost bookmarks (Linux):</p>
<ol>
<li>Open your file explorer (<i>Nautilus, Dolphin ...</i>).</li>
<li>Go to <code>~/.config/google-chrome</code> (<i>Use Ctrl+L on Nautilus</i>).</li>
<li>Search for <code>Bookmarks*</code>, you will see a list of files named <code>Bookmarks</code> and/or <code>Bookmarks.bak</code>. (<i>Note: If there is more than one user using the same Chrome, bookmarks from other users will be listed too</i>)</li>
<li>Select all the files with mouse and drag them to the block below.</li>
<li>Download all the HTML files.</li>
<li>Open each HTML file with Chrome and determine the HTML file that contains your bookmarks. (<i>Note: The largest file is most likely the correct one</i>)</li>
<li>In your Chrome browser, click the Chrome menu icon and go to Bookmarks &gt; Bookmark Manager.</li>
<li>Click the menu icon beside search bar and click "Import Bookmarks".</li>
<li>Select the HTML file that contains your bookmarks.</li>
<li>Your bookmarks should now be imported back to Chrome.</li>
</ol>
</div>
<div class="soln" id="google-soln" role="tabpanel" aria-labelledby="google-tab" aria-hidden="true" tabindex="0">
<p>If you are sure that Chrome sync data stored in Google server still have your bookmarks, here is how to retrieve them from Google server:</p>
<ol>
<li>Go to <a href="https://takeout.google.com/settings/takeout" target="_blank">Google Takeout</a> and sign in to the Google Account used for Chrome Sync.</li>
<li>Click the "Select None" button.</li>
<li>Check "Chrome" in product list.</li>
<li>Expand "All Chrome data types".</li>
<li>Click the "Select Chrome data" option.</li>
<li>In the popup, check the "Bookmarks" option and uncheck the rest.</li>
<li>Scroll down to the bottom of the page and click "Next" button.</li>
<li>Click the "Create archive" button.</li>
<li>Download and unzip the archive.</li>
<li>In the unzipped folder, navigate to "Chrome" folder. The HTML file named "Bookmarks" is the one we need.</li>
<li>In your Chrome browser, click the Chrome menu icon and go to Bookmarks &gt; Bookmark Manager.</li>
<li>Click the menu icon beside search bar and click "Import Bookmarks".</li>
<li>Select the HTML file that contains your bookmarks.</li>
<li>Your bookmarks should now be imported back to Chrome.</li>
</ol>
</div>
<form id="block" tabindex="-1">
<div id="drop_zone">
<svg aria-hidden="true" fill="#bbb" width="48" height="48" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"/>
</svg>
<label>
<input tabindex="0" type="file" multiple id="input" aria-describedby="tooltip"/>
<b>Choose a file</b> or drag it here
</label>
<div role="tooltip" id="tooltip">Search with the keyword of "Bookmarks" and select all the files found.</div>
</div>
<output id="output" role="alert" aria-live="assertive" aria-hidden="true">The HTML file will be produced here later.</output>
</form>
<h3>Other ways to recover bookmarks</h3>
<div class="zip">
<button id="zip-h-2" class="zip-h" aria-expanded="false" aria-controls="zip-2">Personal backup</button>
<div id="zip-2" role="region" aria-labelledby="zip-h-2" aria-hidden="true" class="zip-content">
<p>In the case when backups of your computer are available, find the bookmarks files in the backups, upload them to this tool and continue with the steps above.</p>
</div>
</div>
<div class="zip">
<button id="zip-h-3" class="zip-h" aria-expanded="false" aria-controls="zip-3">Recover from old devices</button>
<div id="zip-3" role="region" aria-labelledby="zip-h-3" aria-hidden="true" class="zip-content">
<p>Do you have a device (e.g: old laptop) that is signed in to your Google Account and it hasn't been synced since the moment your bookmarks were lost? If so, find the files in this device, upload them to this tool and continue with the steps above.</p>
</div>
</div>
<div class="zip">
<button id="zip-h-4" class="zip-h" aria-expanded="false" aria-controls="zip-4">Tips and tricks</button>
<div id="zip-4" role="region" aria-labelledby="zip-h-4" aria-hidden="true" class="zip-content">
<p>You can use this tool or <i>Export Bookmarks</i> function in Bookmark Manager to generate HTML file that can be used as archive/backup of your bookmarks. Regularly making backup is useful in case your bookmarks get lost again in the future.</p>
</div>
</div>
<p><i>Disclaimer: this is not an official Google product.</i></p>
</main>
<footer>
<a href="https://support.google.com/chrome/">Chrome Help Center</a>
<a href="https://productforums.google.com/forum/#!forum/chrome">Chrome Help Forum</a>
</footer>
<a class="github-link" href="https://github.com/rongjiecomputer/chrome/tree/gh-pages/bookmark-recovery" title="Source on Github">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 60.5 60.5" width="60" height="60">
<polygon fill="#9dacb3" points="60.5,60.5 0,0 60.5,0"/>
<path fill="#f5f5f5" d="M43.1,5.8c-6.6,0-12,5.4-12,12c0,5.3,3.4,9.8,8.2,11.4c0.6,0.1,0.8-0.3,0.8-0.6c0-0.3,0-1,0-2c-3.3,0.7-4-1.6-4-1.6c-0.5-1.4-1.3-1.8-1.3-1.8c-1.1-0.7,0.1-0.7,0.1-0.7c1.2,0.1,1.8,1.2,1.8,1.2c1.1,1.8,2.8,1.3,3.5,1c0.1-0.8,0.4-1.3,0.8-1.6c-2.7-0.3-5.5-1.3-5.5-5.9c0-1.3,0.5-2.4,1.2-3.2c-0.1-0.3-0.5-1.5,0.1-3.2c0,0,1-0.3,3.3,1.2c1-0.3,2-0.4,3-0.4c1,0,2,0.1,3,0.4c2.3-1.6,3.3-1.2,3.3-1.2c0.7,1.7,0.2,2.9,0.1,3.2c0.8,0.8,1.2,1.9,1.2,3.2c0,4.6-2.8,5.6-5.5,5.9c0.4,0.4,0.8,1.1,0.8,2.2c0,1.6,0,2.9,0,3.3c0,0.3,0.2,0.7,0.8,0.6c4.8-1.6,8.2-6.1,8.2-11.4C55.1,11.2,49.7,5.8,43.1,5.8z"/>
</svg>
</a>
<script>
'use strict';
(function() {
var $ = document.querySelector.bind(document);
function Bookmark(raw) {
this.tree = JSON.parse(raw);
this.html = '';
this.count = 0;
this.first = true;
}
function chromeTime2TimeT(time) {
return Math.floor((time - 11644473600000000) / 1000000);
}
Bookmark.prototype.walk = function(node) {
if (node.type === 'folder') {
this.html += '<DT><H3 ADD_DATE="' + chromeTime2TimeT(node.date_added) + '" LAST_MODIFIED="' + chromeTime2TimeT(node.date_modified) + '"';
if (this.first) {
this.html += ' PERSONAL_TOOLBAR_FOLDER="true"';
this.first = false;
}
this.html += '>' + node.name + '</H3>\n';
this.html += '<DL><p>\n'
node.children.forEach(this.walk.bind(this));
this.html += '</DL><p>\n';
} else { // node.type == 'url'
this.html += '<DT><A HREF="' + node.url + '" ADD_DATE="' + chromeTime2TimeT(node.date_added) + '">' + node.name + '</A>\n';
this.count++;
}
}
Bookmark.prototype.parse = function() {
this.html = '<!DOCTYPE NETSCAPE-Bookmark-file-1><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"><TITLE>Bookmarks</TITLE><H1>Bookmarks</H1>\n';
this.html += '<DL><p>\n';
var roots = this.tree.roots;
this.walk(roots.bookmark_bar);
if (roots.other.children.length > 0)
this.walk(roots.other);
if (roots.synced.children.length > 0)
this.walk(roots.synced);
this.html += '<style>dt, dl { padding-left: 12px; }</style>\n';
}
Bookmark.prototype.newLink = function() {
var blob = new Blob([this.html], {type: 'text/plain'});
var a = document.createElement('a');
a.download = 'bookmark_backup.html';
a.href = window.URL.createObjectURL(blob);
a.textContent = 'Download ready (' + this.count + ' bookmarks found)';
a.onclick = function(e) {
if ('disabled' in this.dataset) {
return false;
}
this.textContent = 'Downloaded';
this.dataset.disabled = true;
setTimeout(function() {
window.URL.revokeObjectURL(this.href);
}, 1500);
};
return a;
}
function readFile(file) {
var reader = new FileReader();
var li = document.createElement('li');
li.innerHTML = '<strong>Last updated: ' + (file.lastModifiedDate !== undefined ? file.lastModifiedDate.toLocaleDateString() : 'n/a') + '</strong> (' + file.size + 'B) ';
reader.onloadend = function() {
try {
var bookmark = new Bookmark(reader.result);
bookmark.parse();
li.appendChild(bookmark.newLink());
} catch(e) {
li.innerHTML += '<b>Error! The file is invalid. Try again!</b>';
}
};
reader.readAsText(file);
return li;
}
var input = $('#input');
var output = $('#output');
function handleFile(e) {
var files = e.target.files;
output.textContent = 'Loading ...';
var ul = document.createElement('ul');
for (var i = 0; i < files.length; i++) {
ul.appendChild(readFile(files[i]));
}
output.innerHTML = '';
output.setAttribute('aria-hidden', false);
output.appendChild(ul);
}
input.addEventListener('change', handleFile, false);
function handleFileSelect(e) {
e.stopPropagation();
e.preventDefault();
var files = e.dataTransfer.files;
output.textContent = 'Loading ...';
var ul = document.createElement('ul');
for (var i = 0; i < files.length; i++) {
ul.appendChild(readFile(files[i]));
}
output.innerHTML = '';
output.appendChild(ul);
this.classList.remove('is_dragover');
}
function handleDragOver(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
this.classList.add('is_dragover');
}
function handleDragLeave(e) {
e.stopPropagation();
e.preventDefault();
this.classList.remove('is_dragover');
}
var dropZone = document.getElementById('drop_zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect, false);
dropZone.addEventListener('dragleave', handleDragLeave, false);
var solns = ["#windows", "#mac", "#linux", "#google"];
function handleHashChange(e) {
var hash = location.hash;
for (var i = 0; i < solns.length; i++) {
var id = solns[i];
var tab = $(id + '-tab');
var soln = $(id + '-soln');
var visible;
if (hash === id) {
tab.classList.add('active');
soln.classList.add('show');
visible = true;
} else {
tab.classList.remove('active');
soln.classList.remove('show');
visible = false;
}
tab.setAttribute('aria-selected', visible);
soln.setAttribute('aria-hidden', !visible);
}
}
window.addEventListener('hashchange', handleHashChange, false);
if (location.hash == '') location.hash = '#windows';
handleHashChange();
function toggleZip(e) {
var visible = this.parentNode.classList.toggle('unzip');
this.setAttribute('aria-expanded', visible);
this.nextElementSibling.setAttribute('aria-hidden', !visible);
}
var zipH = document.querySelectorAll('.zip-h');
for (var i = 0; i < zipH.length; i++) {
zipH[i].addEventListener('click', toggleZip, false);
}
}());
</script>
</body>
</html>