# 99 línies de codi per resoldre les fallades d'Onetab i fer còpia de seguretat de les dades originals

> Prefaci Quan anava a la universitat, vaig conèixer Onetab gairebé al mateix temps que Chrome; però, com a estudiant, navegar no suposava cap càrrega i la feia servir molt poc. Després de començar a treballar, tenir 100 pestanyes obertes al navegador es va convertir en la norma, i els superiors/companys preguntaven per documentació amb molta freqüència; en aquest moment, Onetab, com a llibreta de notes web, combinat amb Ctrl+f per cercar paraules clau, és senzill i fàcil d'utilitzar.…

- Publicat el: 2022-07-27
- Etiquetes: Chrome, vora, nodejs, onetab, Navegador, Problemes complexos
- Veure versió HTML: https://bilibili.cat/ca/posts/onetabrestore
- Traduït per IA des de 中文: https://bilibili.cat/posts/onetabrestore

---

## Prefaci

A la universitat, vaig conèixer Onetab gairebé al mateix temps que Chrome; però, com a estudiant, navegar no representava cap càrrega i la feia servir molt poc.  
Després de començar a treballar, obrir 100 pestanyes al navegador es va convertir en la norma, i els superiors/companys preguntaven per documentació amb molta freqüència; en aquest moment, Onetab, com a llibreta de notes web, combinat amb Ctrl+f per cercar paraules clau, és senzill i fàcil d'utilitzar.

### **Per què no utilitzar els marcadors?**

*El resultat final de l'ús dels marcadors per part de l'autor va ser que, en desplegar la barra de marcadors, aquesta cobreix tota la pantalla.*

### **Per què no utilitzar l'historial?**

*L'historial també conté altra informació irrellevant, i l'historial de Chrome no és fiable.*

### **Per què no utilitzar altres eines de gestió del coneixement?**

1.  *Les aplicacions de notes són massa pesades*
2.  *Les aplicacions semblants a Onetab, a causa del costum d'ús arrelat, no han permès trobar un substitut prou lleuger i més eficient*
3.  *Onetab ha actualitzat el mode fosc, i la memòria cau de la pestanya endavant/endarrere/actual és realment pràctica*

## Situació

Fa cinc dies, després que una actualització de Windows reiniciés l'ordinador, vaig tornar a obrir Edge i Onetab va quedar-se en estat de càrrega; aproximadament al cap d'una estona la pàgina va fallar i va mostrar l'error Out of Memory.

-   L'autor utilitza Onetab de manera continuada des de principis del 2020, quan va arribar el nou Edge, i té registrades seixanta mil pàgines web; no ha reinstal·lat mai el sistema.

<figure class="missing-asset"><figcaption>La imatge «Crash» s'ha perdut: no s'ha trobat ni al lloc original ni a Internet Archive.<br><code>/upload/2022/07/QQ%E6%88%AA%E5%9B%BE20220727131653.png</code></figcaption></figure>

### Tres mesures

1.  Tancar totes les pàgines web i extensions, reiniciar Edge i tornar a obrir Onetab.  
    <ins><em>Va fallar i va mostrar l'error Out of Memory.</em></ins>
2.  Reiniciar l'ordinador i, amb el segon pla buit, tornar a iniciar Edge i tornar a obrir Onetab.  
    <ins><em>Va fallar i va mostrar l'error Out of Memory.</em></ins>
3.  Copiar completament la carpeta «C:\\User» (el directori de dades d'usuari de Windows) i restaurar-ho en un PC amb Windows 10 recent instal·lat.  
    <ins><em>Va fallar i va mostrar l'error Out of Memory.</em></ins>

En aquest punt es pot concloure bàsicament que la fallada de l'extensió és deguda a una quantitat de dades massa gran.

-   De fet, quan hi havia cinquanta mil registres, ja s'obria molt lentament i calien més de 30 s.
-   Només que no m'esperava que Chrome, el devorador de memòria, també limités l'ús de memòria de les seves extensions.

![mem de Chrome](https://i.pinimg.com/originals/95/11/f8/9511f847798db5ec08a51a3fa597d4c5.jpg)

## Objectiu

En aquest moment ja s'ha trobat el problema; per sort, les dades no s'han perdut, tot i que se'n desconeix la integritat.  
Les dades acumulades durant més de dos anys també tenen una freqüència d'ús diària molt alta, i cal restaurar-les.

1.  Recuperar tant com sigui possible les dades d'Onetab i exportar-les a un format de dades que puguin reconèixer tant les màquines com les persones
2.  Sobre la base del punt 1, implementar una eina automatitzada de còpia de seguretat completa d'Onetab  
    ***L'exportació integrada d'Onetab és un fitxer txt pur, encara cal copiar-lo manualment i hi manca el camp de la data de creació del grup de pestanyes***
3.  Implementar una aplicació compatible amb Onetab, millorar la funció de cerca de dades i que sigui compatible amb el format de dades exportat al punt 1 i amb el format de dades original d'Onetab

## Accions

Ara que ja tenim la causa i l'objectiu, posar-ho en pràctica ja no serà com anar a les palpentes.

### 1\. Cercar l'experiència d'altres a Google

Cercar «onetab data location»  
Aviat vaig trobar Onetab, o més aviat la ubicació on es desen les dades de les extensions dels navegadors basats en Chromium  

<figure class="missing-asset"><figcaption>La imatge «QQ图片20220727175536» s'ha perdut: no s'ha trobat ni al lloc original ni a Internet Archive.<br><code>/upload/2022/07/QQ%E5%9B%BE%E7%89%8720220727175536.png</code></figcaption></figure>

  
Després cercar «onetab data export», vaig trobar també una solució de codi obert d'algú que ja ho havia fet, basada en Go.  
[![jianyuan/onetab-export-to-json](https://opengraph.githubassets.com/e99b6d5fccc2c9ee0d3a4d515f8b337bd98f88bbb64bf7cb3102d0ec121f84f5/jianyuan/onetab-export-to-json)](https://github.com/jianyuan/onetab-export-to-json)  
Originalment pensava que acabaria aquí i seguiria el camí de copiar i enganxar, però hi havia un registre en una incidència que deia que ja no funcionava; l'autor tampoc tenia experiència de depuració amb Go, va mirar el codi, que no arribava a 100 línies, i va decidir implementar-ho ell mateix.

### 2\. Coneixem una mica leveldb

[![google/leveldb](https://opengraph.githubassets.com/e99b6d5fccc2c9ee0d3a4d515f8b337bd98f88bbb64bf7cb3102d0ec121f84f5/google/leveldb)](https://github.com/google/leveldb)

-   Base de dades NoSQL de codi obert creada per Google
-   Monofil, d'alt rendiment i només amb instàncies locals
-   Durant l'execució utilitza intensament la memòria per accelerar-se

#### Una instància estàndard de base de dades leveldb té la forma d'una carpeta

<figure class="missing-asset"><figcaption>La imatge «instància de leveldb» s'ha perdut: no s'ha trobat ni al lloc original ni a Internet Archive.<br><code>/upload/2022/07/QQ%E5%9B%BE%E7%89%8720220727190212.png</code></figcaption></figure>

-   LOCK: bloqueig de la base de dades
-   MANIFEST: fitxer de capçalera
-   \*.ldb: fitxer principal de dades

A partir de la presentació de la solució de codi obert es pot saber que Onetab utilitza leveldb per desar les dades dels usuaris.  
L'autor també havia desenvolupat extensions de Chrome, i recorda que només es podien fer servir les dues API localStorge i indexDB per a la localització, perquè les extensions que s'executen al navegador no tenen capacitat de lectura i escriptura de fitxers ni de connexions TCP.  
Entre aquestes, localStorge té un màxim de 5M, i cinquanta mil registres JSON força llargs no hi caben de cap manera; Onetab hauria d'utilitzar indexDB per desar les dades, oi? Què hi fa, doncs, aquest leveldb, i a més el contribuent també és Google.  
Després d'una cerca vaig saber que leveldb és la implementació subjacent d'indexDB, i que indexDB en realitat és l'API superior (una sèrie de noms que porten a engany).

> Algunes dades que el navegador Chrome desa en Local Storage en format SQLite (fitxers .localstorage) es troben en carpetes.  
> Algunes altres dades desades a la carpeta IndexedDB (per a cada perfil) utilitzen el format LevelDB. És un format de magatzem clau-valor de codi obert desenvolupat per Google i allotjat a GitHub.  
> Modificar fitxers en format LevelDB fora de Chrome no és un procés senzill, perquè cal implementar un comparador compatible per verificar la instància Indexed DB leveldb de Chrome.

### 3\. Eines GUI per a leveldb

Després d'entendre'n el context, amb l'objectiu de ~confirmar (fer un cop d'ull)~ la situació de les dades, l'autor va buscar primer eines GUI per a leveldb.  
És clar que Navicat i DataGrip, els més habituals, no ho admeten; vaig continuar navegant per GitHub.

[![heapwolf/levelui](https://opengraph.githubassets.com/e99b6d5fccc2c9ee0d3a4d515f8b337bd98f88bbb64bf7cb3102d0ec121f84f5/heapwolf/levelui)](https://github.com/heapwolf/levelui)

#### Una implementació GUI amb Electron que no va compilar

[![klausgao/electron-linvodb-manager](https://opengraph.githubassets.com/e99b6d5fccc2c9ee0d3a4d515f8b337bd98f88bbb64bf7cb3102d0ec121f84f5/klausgao/electron-linvodb-manager)](https://github.com/klausgao/electron-linvodb-manager)

#### Una altra implementació GUI amb Electron que no va poder llegir les dades

[![fastogt/fastonosql](https://opengraph.githubassets.com/e99b6d5fccc2c9ee0d3a4d515f8b337bd98f88bbb64bf7cb3102d0ec121f84f5/fastogt/fastonosql)](https://github.com/fastogt/fastonosql)

#### Una implementació GUI amb C++/Qt que va poder llegir les dades correctament

<figure class="missing-asset"><figcaption>La imatge «captura de pantalla del programari» s'ha perdut: no s'ha trobat ni al lloc original ni a Internet Archive.<br><code>/upload/2022/07/QQ%E6%88%AA%E5%9B%BE20220727183055.png</code></figcaption></figure>

  
I es poden veure clarament els noms de les claus que utilitza Onetab.

-   *Nota: aquest programari és de codi obert sota la GPL v3, però la versió binària és de pagament; els usuaris nous poden provar-lo. Quan l'autor va escriure aquest article, el lloc web oficial va caure i no es podia registrar; es pot [descarregar una versió antiga](https://wwc.lanzouf.com/idgFq08i16va) i executar-la sense necessitat de registrar-se ni iniciar sessió.*

### 4\. Implementació del codi basada en Node.js 16.15

Tot i que les dues implementacions GUI amb Electron anteriors no van tenir èxit, també vaig descobrir el paquet level del qual depenien, que ofereix una API molt pràctica i es pot utilitzar directament.

-   *Aquí l'autor va pensar primer a fer-ho amb Python, però la dependència level de Python s'ha de compilar i instal·lar en Linux, així que ho va deixar estar.*

```shell
$ npm install level
$ npm install mongodb
```

```JavaScript
const {promises: {writeFile, mkdir}} = requir('fs');
const {Level} = requir('level')
const MongoClient = requir('mongodb').MongoClient
// halo有点bug, 出现require会崩溃

const USER_HOME = (process.env.HOME || process.env.USERPROFILE).replaceAll("\\", "/")

const chrome = {
    name: "Google/Chrome",
    uuid: "chphlpgkkbolifaimnlloiipkdnihall"
}
const edge = {
    name: "Microsoft/Edge", // Edge || Edge Beta || Edge Dev || Edge Canary
    uuid: "hoimpamkkoehapgenciaoajfkfkpgfop"
}
// const firefox = "" // 火狐的扩展和目录结构与以上两位好兄弟不太一样, 无使用经验, 请自行修改

const winPath = `${USER_HOME}/AppData/Local/${edge.name}/User Data/Default/Local Extension Settings/${edge.uuid}`
// 以下两条为 Copilot 智能添加的代码, 请自行核对路径是否正确
// const macPath = `${USER_HOME}/Library/Application Support/${edge.name}/User Data/Default/Local Extension Settings/${edge.uuid}`
// const linuxPath = `${USER_HOME}/AppData/Local/${edge.name}/User Data/Default/Local Extension Settings/${edge.uuid}`

const ldb = new Level(winPath)
const url = "mongodb://alpha:123456aB@localhost:27017/?authSource=admin"

// 异步读取onetab的leveldb中的数据
const getOnetabData = async () => {
    await ldb.open()
    const str = await ldb.get('state')
    return JSON.parse(JSON.parse(str))
}

// 异步处理数据, 获得一个每条记录的数组
const getItems = async (onetabs) => {
    const items = []
    onetabs.forEach((ele, index) => {
        console.log(ele.id)
        ele.tabsMeta.map(ele => items.push(ele))
    })
    return items
}

// 异步连接mongo
const getMongoDB = async () => {
    const db = await MongoClient.connect(url)
    return await db
}

// 异步写入tab组
const insertGroups = async (db, onetabs) => {
    const dbo = await db.db("onetab")
    await dbo.collection("onetab_groups").insertMany(onetabs)
}

// 异步写入每条onetab记录
const insertItems = async (db, items) => {
    const dbo = db.db("onetab")
    await dbo.collection("onetab_items").insertMany(items)
}

// 生成用于备份的json数据文件和方便查看的CSV文件
const genExtFiles = async (items, onetabs) => {
    /*
     * 生成表头，\ufeff 是防止乱码
     * csv中以 `,` 换列，`\n`换行
     */
    let title = Object.keys(items[1])
    let csvContent = '\ufeff' + title.join(',') + '\n'

    // 添加表体
    items.forEach((item, index) => {
        let c = Object.values(item).join(',') + '\n'
        csvContent += c
    })
    // 生成文件夹
    await mkdir('onetab')

    // 生成csv文件
    await writeFile('./onetab/tab_items.csv', csvContent)

    // 生成JSON
    await writeFile('./onetab/tab_ori.json', JSON.stringify(onetabs))
    console.log('数据文件生成完毕, 请打开当前目录下的onetab文件夹查看.')
}

// 主函数
const main = async () => {
    const json = await getOnetabData()
    const db = await getMongoDB()
    const items = await getItems(json.tabGroups)
    await insertItems(db, items)
    await insertGroups(db, json.tabGroups)
    await genExtFiles(items, json)

    await db.close()
    console.log("写入MongoDB完成, 程序执行完毕. ")
}

main()
```

## Resultat

Finalment, l'autor va empaquetar una aplicació d'escriptori binària basada en Tauri, que fa poc és molt popular.

> Encara no coneixes Tauri?  
> Mira aquí [Deixa de banda Electron i abraça Tauri, desenvolupat amb Rust](https://segmentfault.com/a/1190000041440043)

### Les funcionalitats que implementa

-   Veure totes les dades exportades amb l'estil original d'Onetab
-   Ha afegit paginació per fer front a grans quantitats de dades
-   Ha afegit filtres per data i paraula clau

### S'afegirà properament

-   Còpia de seguretat automatitzada implementada en Rust, sense necessitat d'instal·lar Node addicionalment
-   Sincronització al núvol WebDAV o altres
-   Anàlisi de dades, núvol de paraules, NLP

### Adreça del repositori

[![endcloud/Onetab Re](https://opengraph.githubassets.com/e99b6d5fccc2c9ee0d3a4d515f8b337bd98f88bbb64bf7cb3102d0ec121f84f5/endcloud/onetab_restore_tauri)](https://github.com/endcloud/onetab_restore_tauri)
