Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/o0101/Bookmate
Watch changes in Chrome bookmarks, and use bookmarks as an append-only key-value store via an fs-like API.
https://github.com/o0101/Bookmate
append-only async-generator browser-bookmarks chrome chrome-bookmarks filesystem-api key-value nodejs observer
Last synced: 24 days ago
JSON representation
Watch changes in Chrome bookmarks, and use bookmarks as an append-only key-value store via an fs-like API.
- Host: GitHub
- URL: https://github.com/o0101/Bookmate
- Owner: o0101
- License: agpl-3.0
- Created: 2022-01-01T07:06:26.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2022-10-29T08:19:42.000Z (over 2 years ago)
- Last Synced: 2025-01-20T23:43:08.292Z (25 days ago)
- Topics: append-only, async-generator, browser-bookmarks, chrome, chrome-bookmarks, filesystem-api, key-value, nodejs, observer
- Language: JavaScript
- Homepage:
- Size: 491 KB
- Stars: 9
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# [π Bookmate](https://github.com/crisdosyago/Bookmate) [![npm](https://img.shields.io/npm/dt/bookmate)](https://www.npmjs.com/package/bookmate) [![npm](https://img.shields.io/npm/v/bookmate?color=%2300ff44)](https://www.npmjs.com/package/bookmate) [![visitors+++](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fcrisdosyago%2Fbookmate&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=visits%20%28today%2Ftotal%29%20since%20Jan%204%202022&edge_flat=false)](https://hits.seeyoufarm.com)
**An append-only key-value store built on Chrome bookmarks, plus an asychronous stream of Bookmark changes. For NodeJS**
*./src/demo.js:*
```js
import Bookmate from './index.js';console.log(Bookmate);
const path = Bookmate.tryToFindBookmarksLocation();
console.log({path});
Bookmate.mount(path);
const entries = Bookmate.readdirSync(
'bookmark_bar',
{withFileTypes:true}
);console.log(entries);
```----------------------------------------
## Features
Bookmate:
- efficiently observes changes to bookmarks and emits these as an asychronous iterator readable stream
- automatically locates the right [Chrome Profile directory](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/user_data_dir.md) in a platform-agnostic way by observing bookmark changes
- is possesed of an [fs](https://nodejs.org/docs/latest/api/fs.html#file-system)-like, and simple, NodeJS API: [readFileSync, writeFileSync, promisesWatch etc](#api)## Get
```shell
$ npm i --save bookmate@latest
```## Demo
```js
import Bookmate from './index.js';console.log(Bookmate);
const path = Bookmate.tryToFindBookmarksLocation();
console.log({path});
Bookmate.mount(path);
{
const entries = Bookmate.readdirSync('bookmark_bar', {withFileTypes:true});console.log(entries);
}let entry;
try {
entry = Bookmate.readFileSync([
'bookmark_bar',
'https://www.dia.mil/'
], {encoding: 'json'});entry.name += " Hello ";
} catch(e) {
entry = {
name: "DIA",
type: "url"
}
}
console.log({entry});Bookmate.writeFileSync(['bookmark_bar', 'https://www.dia.mil/'], entry);
{
const entries = Bookmate.readdirSync('bookmark_bar', {withFileTypes:true});console.log(entries);
}
```*Above creates (if not exists) a bookmark to [DIA](https://www.dia.mil/), and appends "Hello" to its bookmark name (the title) otherwise*
## API
## `readFileSync(path[, options])`
- `path` [``](#type-serializedpatharray) | [``](#type-patharray) | [``](https://nodejs.org/docs/latest/api/url.html#the-whatwg-url-api) path to Bookmark URL
- `options` [``](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
- `encoding` [``](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) | [``](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Null_type) **Default:** `null`
- Returns: [``](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) | [``](https://nodejs.org/docs/latest/api/buffer.html#class-buffer) | [``](#type-bookmarknode)Returns the contents of the Bookmark at the path.
If the encoding option is `'json'` then this function returns a [``](#type-bookmarknode). Otherwise, if the encoding option is specified then this function returns a string, otherwise it returns a buffer.
It cannot be called on a folder. To get the contents of a folder use [`readdirSync()`](#readdirsync-path-options)
## `readdirSync(path[, options])`
- `path` [``](#type-serializedpatharray) | [``](#type-patharray)
- `options` [``](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
- `withFileTypes` [``](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type) **Default:** `false`
- Returns: [``](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) | [``](#type-bookmarknode)Reads the contents of the folder.
If `options.withFileTypes` is set to true, the result will contain [``](#type-bookmarknode) objects.
## Basic usage
*See the demo above*
1. Find your Bookmark folder location
2. Mount it
3. Read a top-level bookmark folder
4. Do anything!A note about path syntax.
You can supply a path in three ways. Here's the code that enumerates that (and I'll explain it below):
```js
function guardAndNormalizePath(path) {
if ( isSerializedPath(path) ) {
return JSON.parse(path);
} else if ( isArrayPath(path) ) {
return path;
} else if ( typeof path === "string" ) {
if ( isURL(path) ) {
return [path];
} else if ( ! /https?:/.test(path) ) {
return path.split('/').filter(seg => seg.length);
} else {
throw new SystemError('EINVAL',
`Sorry path shorthand ('/' separator syntax)
can not be used with Bookmark URLs.
Please use a path array instead.
`
);
}
} else {
throw new SystemError('EINVAL',
`Sorry path ${
path
} was not in a valid format. Please see the documentation at ${
LIBRARY_REPO
}`
);
}
}
```You can supply a path as a JSON.stringified string, like:
```js
const musicFolderPath = [
'bookmark_bar',
'Music Research'
];const stringifiedPathArray = JSON.stringify(musicFolderPath);
```
To refer to the folder "Music Research" in your bookmarks bar. Or
```js
const stringifiedPathArray = JSON.stringify([
'bookmark_bar',
'Music Research',
'https://sheetmusic.com'
]);
```To refer to the bookmark with URL `https://sheetmusic.com` in the same folder.
You can also supply it as simple an array.
```js
Bookmate.readdirSync(musicFolder);Bookmate.readFileSync(musicFolder.push('https://spotify.com'), {encoding: 'json'});
```I'm sure you get it now.
Equivalent to the above are is:
```js
Bookmate.readdirSync('bookmark_bar/Music reserach');
```But the following throws an `EINVAL` error:
```
Bookmate.readFileSync('bookmark_bar/Music research/https://spotify.com');
```Because URLs can be used as part of this "path shorthand".
## β¦ π§
Well this is a little embarrassing π β I'm sorry, other documentation should go here. π·ββοΈ
The outstanding fs-like functions to document currently are:
- existsSync : does a path exist
- writeFileSync : create a bookmark
- mkdirSync : create a bookmark folder
- promisesWatch (*aka bookmarkChanges) : watch for changes to bookmarks (added, deleted, altered)And other additional functions to document currently are:
- mount : attach Bookmate to the bookmarks directory (fs-like API now works)
- tryToFindBookmarksLocation : try to find the bookmarks directory
- unmount : un-attach Bookmate
- getProfileRootDir : try to get the root profile directory for Chrome
- saveWithChecksum : Chrome bookmarks require a checksum, this ensures that works
- and bookmarkChanges (same as promisesWatch, actually--just an alias! π π xx π)And, finally, the types that currently need documenting are:
- BookmarkNode : an object containing bookmark data
- SerializedPathArray : a JSON-ified array containing bookmark path segments
- PathArray : the JSON.parsed version of the aboveBut, not to worry--they (the fs-ones anyway) are [pretty much like the NodeJS fs versions](https://nodejs.org/docs/latest/api/fs.html) so you can head over [there](https://nodejs.org/docs/latest/api/fs.html) or [read the code](https://github.com/crisdosyago/Bookmate/blob/main/src/index.js) to know moreβuntil somebody
gets around to finishing these docs.## Implementation Progress & Roadmap πΉ
- [x] emit change events for URL bookmark additions, deletions and name changes
- [x] existsSync
- [x] readFileSync
- [x] writeFileSync
- [x] readdirSync
- [x] mkdirSync
- [x] promisesWatch (*aka bookmarkChanges)
- [ ] emit events for Folder additions, deletions and name changes## Disclaimer
No connection or endorsement expressed or implied with Google, Alphabet, Chrome, Sync or the Chromium authors.
## Contributions β€οΈ
Welcome! It's all kind of new so many you can help also set up a contributing guidelines, documentation and so on πΉ
## License βοΈ
AGPL-3.0 Β© [Cris](https://github.com/crisdosyago)
## More examples
*Actual [production example](https://github.com/crisdosyago/DiskerNet/blob/1d4675d3d17126246ca8989da6470ba3ffb799af/src/archivist.js#L699):*
```js
import {bookmarkChanges} from 'bookmate';// ...
async function startObservingBookmarkChanges() {
for await ( const change of bookmarkChanges() ) {
switch(change.type) {
case 'new': archiveAndIndexURL(change.url); break;
case 'delete': deleteFromIndexAndSearch(change.url); break;
default: break;
}
}
}
```-----------------------
# *[π Bookmate](https://github.com/crisdosyago/Bookmate)*