Skip to content

Instantly share code, notes, and snippets.

@toodooleedoo
Last active September 25, 2017 16:02
Show Gist options
  • Select an option

  • Save toodooleedoo/fe0b2b83c4d5faf9ac92c82c224d506d to your computer and use it in GitHub Desktop.

Select an option

Save toodooleedoo/fe0b2b83c4d5faf9ac92c82c224d506d to your computer and use it in GitHub Desktop.

Revisions

  1. Soukenka, Eric (ETW - FLEX) revised this gist Sep 25, 2017. 1 changed file with 11 additions and 6 deletions.
    17 changes: 11 additions & 6 deletions sync-notes.js
    Original file line number Diff line number Diff line change
    @@ -199,12 +199,17 @@ clean = () => {
    csonObj.updatedAt = moment().toISOString()
    csonObj.title = fs.readFileSync(txtDir + '/' + readfile).toString().trim().split('\n')[0];
    csonObj.content = fs.readFileSync(txtDir + '/' + readfile).toString().trim();
    filename = crypto.randomBytes(10).toString('hex');
    writeFile = csonDir + '/' + filename + '.cson';
    fs.writeFileSync(writeFile, CSON.stringify(csonObj))
    fs.renameSync(txtDir + '/' + readfile, txtDir + '/' + filename + '.txt');
    console.log(`WROTE: ${writeFile} - ${csonObj.title}`);
    console.log(`RENAMED: ${txtDir + '/' + readfile} --> ${txtDir + '/' + filename + '.txt'}`);
    if(csonObj.title && csonObj.content) {
    filename = crypto.randomBytes(10).toString('hex');
    writeFile = csonDir + '/' + filename + '.cson';
    fs.writeFileSync(writeFile, CSON.stringify(csonObj))
    fs.renameSync(txtDir + '/' + readfile, txtDir + '/' + filename + '.txt');
    console.log(`WROTE: ${writeFile} - ${csonObj.title}`);
    console.log(`RENAMED: ${txtDir + '/' + readfile} --> ${txtDir + '/' + filename + '.txt'}`);
    } else {
    fs.unlink(`${txtDir}/${readfile}`);
    console.log(`Removed invalid/empty note found at ${txtDir}/${readfile}`);
    }
    }
    }
    });
  2. Soukenka, Eric (ETW - FLEX) revised this gist Sep 25, 2017. 1 changed file with 17 additions and 8 deletions.
    25 changes: 17 additions & 8 deletions sync-notes.js
    Original file line number Diff line number Diff line change
    @@ -127,14 +127,18 @@ processor = (file) => {
    filename = readFile.replace(/\.[^/.]+$/, "");
    writeFile = txtDir + '/' + filename + '.txt';
    csonObj = CSON.parse(fs.readFileSync(file).toString())
    if (fs.existsSync(writeFile)) {
    if (fs.readFileSync(writeFile).toString().trim() != csonObj.content.trim()) {
    console.log(`MODIFED: cson ${csonObj.title.trim()}`)
    if(csonObj.content) {
    if (fs.existsSync(writeFile)) {
    if (fs.readFileSync(writeFile).toString().trim() != csonObj.content.trim()) {
    console.log(`MODIFED: cson ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    } else {
    console.log(`ADDED: cson ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    } else {
    console.log(`ADDED: cson ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    console.log(`ERROR: ${file} does not have content and we do not support snippets yet2`)
    }
    }
    if (path.extname(file) == '.txt') {
    @@ -210,9 +214,13 @@ clean = () => {
    if (extension == 'cson') {
    if (!fs.existsSync(txtDir + '/' + filename + '.txt')) {
    csonObj = CSON.parse(fs.readFileSync(csonDir + '/' + readfile))
    writeFile = txtDir + '/' + filename + '.txt';
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    console.log(`WROTE: ${writeFile} - ${csonObj.title}`);
    if(csonObj.content) {
    writeFile = txtDir + '/' + filename + '.txt';
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    console.log(`WROTE: ${writeFile} - ${csonObj.title}`);
    } else {
    console.log(`ERROR: ${csonDir}/${readfile} does not have content and we do not support snippets yet`)
    }
    }
    }
    });
    @@ -227,6 +235,7 @@ if (mode == '-h' || mode == undefined) {
    console.log(`node ${process.argv[1]} sync`);
    console.log(`node ${process.argv[1]} duplicates`);
    console.log(`node ${process.argv[1]} counter`);
    console.log(`node ${process.argv[1]} clean`);
    } else if (mode == 'counter') {
    noteCounter();
    } else if (mode == 'clean') {
  3. Soukenka, Eric (ETW - FLEX) revised this gist Apr 26, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -18,4 +18,4 @@ some migration and changes like i did.

    # Instructions
    Read the comment block at the top of sync-notes.js
    TL;DR You will have to have nvALT setup as Plain Text Storage, update storage paths and foldername from Boostnote. Then run $ ndoe sync-notes.js sync
    TL;DR You will have to have nvALT setup as Plain Text Storage, update storage paths and foldername from Boostnote. Then run $ node sync-notes.js sync
  4. Soukenka, Eric (ETW - FLEX) revised this gist Apr 26, 2017. 1 changed file with 12 additions and 12 deletions.
    24 changes: 12 additions & 12 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,21 +1,21 @@
    # Boostrap and Simplenote Syncronization tool.
    sync-notes.js will keep Simplenote and Boostrap in sync allowing you to continue using whichever app meets your needs
    at that time. For instance i like updating Boostnote and then editing on my Android in Simplenote or updating notes
    in vim. I also find nvALT to be a speady way to delete and reorganize in bulk. They each have there pros and cons for me.

    sync-notes.js also comes with a couple of utility scripts like search and interactively cleanup duplicates. See
    instructions at the top of the script for more.

    # Description
    While wanting to switch from a Simplenote workflow and using nvALT to Boostrap I realized a manually import was going to be too
    complicated so i started a utility script.

    Then i realized I could use this tool to continue parts of my note taking workflow in Simplenote including Cloud Syncronization,
    multiple device editing and there Android app which Boostrap still lacks.

    # Warning
    This was a utility script so it is not yet very polished. It also does not keep tags from either app or modified time. I recommend
    understanding the script a bit and doing some tests. (See next)

    # Boostrap Duplicate cleanup utility script is also included.
    This was created as i learned the hardway Boostrap maintains in memory reference to it's persistence and after migrations editing
    notes will cause duplicate entries.

    I was unable to get a smart enough regex done after a good round of note cleanup so i leveraged a [String Similiary library](https://www.npmjs.com/package/string-similarity)
    Which turned out to be REALLY cool and I imagine I will use this for other projects.
    The final script is sync-notes.js and probably all you need to run. The other scripts are for reference in case you want to do
    some migration and changes like i did.

    # Instructions
    Read the comment block at the top for instructions but as quickstart modify read and write dir's, change id in skeleton.js and
    run. You will have to have nvALT setup as Plain Text Storage.
    Read the comment block at the top of sync-notes.js
    TL;DR You will have to have nvALT setup as Plain Text Storage, update storage paths and foldername from Boostnote. Then run $ ndoe sync-notes.js sync
  5. Soukenka, Eric (ETW - FLEX) revised this gist Apr 26, 2017. 1 changed file with 28 additions and 34 deletions.
    62 changes: 28 additions & 34 deletions sync-notes.js
    Original file line number Diff line number Diff line change
    @@ -5,9 +5,11 @@
    * @DESCRIPTION: Keeps Simplenote and Boostnote insync
    *
    * @INSTRUCTIONS:
    * Set Resophnotes to save as Plain Text.
    * Change csonDir and txtDir accordingly
    * Run npm install
    * - Set Resophnotes to save as Plain Text.
    * - Change csonDir and txtDir accordingly
    * - Change csonObj.folder = '94b8c2e8acf3448698d7' with
    * foldername determined by a sample cson on your system.
    * - Run npm install
    *
    * Run in sync mode and make changes and watch output.
    *
    @@ -19,8 +21,13 @@
    *
    *
    * @TODO:
    * Allow adding of new txt notes
    * Remove resophnotes dependency by using Simplenote directly.
    * - Allow adding of new txt notes without restart of program
    * - Remove resophnotes dependency by using Simplenote directly.
    * - Cleanup duplicate reduntant code
    *
    * !!!WARNING!!! Boostrap stores references and notes in memory
    * after making external changes you should do a cmd+r to reload
    * boostrap or you may encounter note loss and/or duplication.
    *
    * @AUTHOR: Eric Soukenka
    * @DATE: April 20th 2017
    @@ -79,7 +86,6 @@ duplicates = () => {
    console.log(`LOGGING: ${csonDir}/${csonFile2} ${csonObj2.title}`);
    }
    loop = false;
    //console.log(`DUP: "${csonObj1.title.trim()}" "${csonObj2.title.trim()}" - ${x}`);
    dupCounter++;
    }
    }
    @@ -99,7 +105,6 @@ similiar = (file) => {
    if (path.extname(file) == '.cson' && fs.existsSync(file)) {
    status = 'new';
    csonObj = CSON.parse(fs.readFileSync(file).toString());
    //console.log(`SIMILIARITY: check ${csonObj.title.trim()}`);
    fs.readdirSync(txtDir).forEach(function(txtFile) {
    if (path.extname(txtFile) == '.txt') {
    txtContent = fs.readFileSync(txtDir + '/' + txtFile).toString()
    @@ -122,20 +127,13 @@ processor = (file) => {
    filename = readFile.replace(/\.[^/.]+$/, "");
    writeFile = txtDir + '/' + filename + '.txt';
    csonObj = CSON.parse(fs.readFileSync(file).toString())
    //if(csonObj.title.substring(0,1) != '#') {
    //csonObj.title = csonObj.title.substring(1)
    //}
    if (fs.existsSync(writeFile)) {
    if (fs.readFileSync(writeFile).toString().trim() != csonObj.content.trim()) {
    if (fs.statSync(writeFile).mtime > fs.statSync(file).mtime) {
    console.log('write > read')
    } else {
    console.log(`MODIFED: cson ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    }
    console.log(`MODIFED: cson ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    } else {
    console.log(`ADDED NEW FILE ${csonObj.title.trim()}`)
    console.log(`ADDED: cson ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    }
    @@ -146,22 +144,17 @@ processor = (file) => {
    if (fs.existsSync(writeFile)) {
    csonObj = CSON.parse(fs.readFileSync(writeFile).toString())
    if (fs.readFileSync(file).toString().trim() != csonObj.content.trim()) {
    if (fs.statSync(writeFile).mtime > fs.statSync(file).mtime) {
    console.log('write > read')
    } else {
    csonObj.content = fs.readFileSync(file).toString().trim()
    csonObj.title = fs.readFileSync(file).toString().trim().split('\n')[0] + '\n';
    csonObj.updatedAt = moment().toISOString()
    if (csonObj.title.substring(0, 1) == '#') {
    csonObj.title = csonObj.title.substring(1)
    }
    console.log(`MODIFIED: txt ${fs.readFileSync(file).toString().trim().split('\n')[0]}`);
    fs.writeFileSync(writeFile, CSON.stringify(csonObj));
    csonObj.content = fs.readFileSync(file).toString().trim()
    csonObj.title = fs.readFileSync(file).toString().trim().split('\n')[0] + '\n';
    csonObj.updatedAt = moment().toISOString()
    if (csonObj.title.substring(0, 1) == '#') {
    csonObj.title = csonObj.title.substring(1)
    }
    console.log(`MODIFIED: txt ${fs.readFileSync(file).toString().trim().split('\n')[0]}`);
    fs.writeFileSync(writeFile, CSON.stringify(csonObj));
    }
    } else {
    //TODO: Add simplenote without the need to restart program
    console.log(`SKIPPING: NEW NOTE: ${writeFile} - ${csonObj.title}}`);
    console.log(`SKIPPING: NEW NOTE: ${writeFile}`);
    console.log(`NOTE: will be created upon restart of this program`);
    }
    }
    @@ -181,11 +174,13 @@ noteCounter = () => {
    txtCount++;
    }
    });
    console.log(`boost/simple ${csonCount}/${txtCount}`);
    console.log(`COUNTER: Boostnote: ${csonCount}`);
    console.log(`COUNTER: Simplenote: ${txtCount}`);
    }

    clean = () => {
    noteCounter();
    console.log("Running clean mode to ensure clean start");
    fs.readdirSync(txtDir).forEach(function(readfile) {
    filename = readfile.split('.').shift()
    extension = readfile.split('.').pop()
    @@ -250,7 +245,6 @@ if (mode == '-h' || mode == undefined) {
    },
    }).on('all', (event, path) => {
    if (csonWatcherReady) {
    console.log(`EVENT CSON-->TXT: ${event}`);
    noteCounter();
    similiar(path);
    }
    @@ -281,7 +275,6 @@ if (mode == '-h' || mode == undefined) {
    if (txtWatcherReady) {
    similiar(path);
    noteCounter();
    console.log(`EVENT TXT-->CSON: ${event}`);
    }
    if (event != 'unlink') {
    processor(path)
    @@ -298,4 +291,5 @@ if (mode == '-h' || mode == undefined) {
    txtWatcher.on('ready', () => txtWatcherReady = true);
    //end simple-to-boost
    clean();
    console.log(`Watching ${txtDir} and ${csonDir}`)
    }
  6. Soukenka, Eric (ETW - FLEX) revised this gist Apr 26, 2017. 1 changed file with 11 additions and 28 deletions.
    39 changes: 11 additions & 28 deletions sync-notes.js
    Original file line number Diff line number Diff line change
    @@ -133,9 +133,7 @@ processor = (file) => {
    console.log(`MODIFED: cson ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    } else {
    console.log(`UNCHANGED: ${csonObj.title.trim()}`)
    }
    }
    } else {
    console.log(`ADDED NEW FILE ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    @@ -160,24 +158,11 @@ processor = (file) => {
    console.log(`MODIFIED: txt ${fs.readFileSync(file).toString().trim().split('\n')[0]}`);
    fs.writeFileSync(writeFile, CSON.stringify(csonObj));
    }
    } else {
    console.log(`UNCHANGED: ${csonObj.title.trim()}`)
    }
    } else {
    csonObj = {}
    csonObj.type = 'MARKDOWN_NOTE'
    csonObj.folder = '94b8c2e8acf3448698d7'
    csonObj.tags = []
    csonObj.isStarred = false
    csonObj.createdAt = "2017-04-17T04:57:32.188Z" //TODO: Set date with moment
    csonObj.updatedAt = "2017-04-17T04:57:45.464Z" //TODO: Set date with moment
    csonObj.title = filename;
    filename = crypto.randomBytes(10).toString('hex');
    writeFile = csonDir + '/' + filename + '.cson';
    csonObj.content = fs.readFileSync(file).toString().trim();
    console.log(`SKIPPING: NEW NOTE: ${writeFile} - NOTE THIS IS BUGGY`);
    //TODO: Adding a txt note will not create id and cleanup. This causes multiple duplicates
    //fs.unlink(file)
    //TODO: Add simplenote without the need to restart program
    console.log(`SKIPPING: NEW NOTE: ${writeFile} - ${csonObj.title}}`);
    console.log(`NOTE: will be created upon restart of this program`);
    }
    }
    }
    @@ -213,14 +198,14 @@ clean = () => {
    csonObj.isStarred = false
    csonObj.createdAt = moment().toISOString()
    csonObj.updatedAt = moment().toISOString()
    csonObj.title = fs.readFileSync(txtDir + '/' + readfile).toString().trim().split('\n')[0] + '\n';
    csonObj.title = fs.readFileSync(txtDir + '/' + readfile).toString().trim().split('\n')[0];
    csonObj.content = fs.readFileSync(txtDir + '/' + readfile).toString().trim();
    filename = crypto.randomBytes(10).toString('hex');
    writeFile = csonDir + '/' + filename + '.cson';
    fs.writeFileSync(writeFile,CSON.stringify(csonObj))
    fs.renameSync(txtDir + '/' + readfile,txtDir + '/' + filename + '.txt');
    //console.log('ORPHAN: ' + txtDir + '/' + readfile);
    console.log(`WROTE: ${writeFile} - ${csonObj.title}`)
    fs.writeFileSync(writeFile, CSON.stringify(csonObj))
    fs.renameSync(txtDir + '/' + readfile, txtDir + '/' + filename + '.txt');
    console.log(`WROTE: ${writeFile} - ${csonObj.title}`);
    console.log(`RENAMED: ${txtDir + '/' + readfile} --> ${txtDir + '/' + filename + '.txt'}`);
    }
    }
    });
    @@ -232,9 +217,7 @@ clean = () => {
    csonObj = CSON.parse(fs.readFileSync(csonDir + '/' + readfile))
    writeFile = txtDir + '/' + filename + '.txt';
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    fs.renameSync(csonDir + '/' + readfile,csonDir + '/' + filename + '.txt');
    //console.log('ORPHAN: ' + csonDir + '/' + readfile);
    console.log(`WROTE:${writeFile} - ${csonObj.title}`)
    console.log(`WROTE: ${writeFile} - ${csonObj.title}`);
    }
    }
    });
    @@ -256,7 +239,6 @@ if (mode == '-h' || mode == undefined) {
    } else if (mode == 'duplicates') {
    duplicates();
    } else if (mode == 'sync') {

    //boost-to-simple
    csonWatcherReady = false;
    //var csonWatcher = chokidar.watch(csonDir).on('all', (event, path) => {
    @@ -315,4 +297,5 @@ if (mode == '-h' || mode == undefined) {
    });
    txtWatcher.on('ready', () => txtWatcherReady = true);
    //end simple-to-boost
    clean();
    }
  7. Soukenka, Eric (ETW - FLEX) revised this gist Apr 26, 2017. 1 changed file with 46 additions and 2 deletions.
    48 changes: 46 additions & 2 deletions sync-notes.js
    Original file line number Diff line number Diff line change
    @@ -191,14 +191,56 @@ noteCounter = () => {
    csonCount++;
    }
    });
    fs.readdirSync(txtDir).forEach(function(readfile) {
    if (path.extname(readfile) == '.txt') {
    fs.readdirSync(txtDir).forEach(function(readfile2) {
    if (path.extname(readfile2) == '.txt') {
    txtCount++;
    }
    });
    console.log(`boost/simple ${csonCount}/${txtCount}`);
    }

    clean = () => {
    noteCounter();
    fs.readdirSync(txtDir).forEach(function(readfile) {
    filename = readfile.split('.').shift()
    extension = readfile.split('.').pop()
    if (extension == 'txt') {
    if (!fs.existsSync(csonDir + '/' + filename + '.cson')) {
    csonObj = {}
    csonObj.type = 'MARKDOWN_NOTE'
    csonObj.folder = '94b8c2e8acf3448698d7'
    csonObj.tags = []
    csonObj.isStarred = false
    csonObj.createdAt = moment().toISOString()
    csonObj.updatedAt = moment().toISOString()
    csonObj.title = fs.readFileSync(txtDir + '/' + readfile).toString().trim().split('\n')[0] + '\n';
    csonObj.content = fs.readFileSync(txtDir + '/' + readfile).toString().trim();
    filename = crypto.randomBytes(10).toString('hex');
    writeFile = csonDir + '/' + filename + '.cson';
    fs.writeFileSync(writeFile,CSON.stringify(csonObj))
    fs.renameSync(txtDir + '/' + readfile,txtDir + '/' + filename + '.txt');
    //console.log('ORPHAN: ' + txtDir + '/' + readfile);
    console.log(`WROTE: ${writeFile} - ${csonObj.title}`)
    }
    }
    });
    fs.readdirSync(csonDir).forEach(function(readfile) {
    filename = readfile.split('.').shift()
    extension = readfile.split('.').pop()
    if (extension == 'cson') {
    if (!fs.existsSync(txtDir + '/' + filename + '.txt')) {
    csonObj = CSON.parse(fs.readFileSync(csonDir + '/' + readfile))
    writeFile = txtDir + '/' + filename + '.txt';
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    fs.renameSync(csonDir + '/' + readfile,csonDir + '/' + filename + '.txt');
    //console.log('ORPHAN: ' + csonDir + '/' + readfile);
    console.log(`WROTE:${writeFile} - ${csonObj.title}`)
    }
    }
    });
    noteCounter();
    }

    var mode = process.argv[2];
    var txtDir = '/Users/esouke/Documents/Notes';
    var csonDir = '/Users/esouke/Boostnote/notes';
    @@ -209,6 +251,8 @@ if (mode == '-h' || mode == undefined) {
    console.log(`node ${process.argv[1]} counter`);
    } else if (mode == 'counter') {
    noteCounter();
    } else if (mode == 'clean') {
    clean();
    } else if (mode == 'duplicates') {
    duplicates();
    } else if (mode == 'sync') {
  8. Soukenka, Eric (ETW - FLEX) revised this gist Apr 26, 2017. 1 changed file with 21 additions and 55 deletions.
    76 changes: 21 additions & 55 deletions sync-notes.js
    Original file line number Diff line number Diff line change
    @@ -2,14 +2,25 @@
    *
    * @TITLE: Simplenote and Boostrap Note Syncronization
    *
    * @DESCRIPTION: Supports two modes one which exports
    * Boostrap notes and exports them to nvAlt .txt files.
    * The other will export nvALT txt files to Boostrap .cson files
    * @DESCRIPTION: Keeps Simplenote and Boostnote insync
    *
    * @INSTRUCTIONS: Change readDir's and writeDir's at the top of
    * both functions appropriately then run with no parameters for
    * insrtructions.
    * @INSTRUCTIONS:
    * Set Resophnotes to save as Plain Text.
    * Change csonDir and txtDir accordingly
    * Run npm install
    *
    * Run in sync mode and make changes and watch output.
    *
    * You can run duplicates mode which will use
    * formulas to determine duplicate Boostnote notes and
    * ask if you want to delete.
    *
    * counter mode just shows how many notes each application has
    *
    *
    * @TODO:
    * Allow adding of new txt notes
    * Remove resophnotes dependency by using Simplenote directly.
    *
    * @AUTHOR: Eric Soukenka
    * @DATE: April 20th 2017
    @@ -158,8 +169,8 @@ processor = (file) => {
    csonObj.folder = '94b8c2e8acf3448698d7'
    csonObj.tags = []
    csonObj.isStarred = false
    csonObj.createdAt = "2017-04-17T04:57:32.188Z"
    csonObj.updatedAt = "2017-04-17T04:57:45.464Z"
    csonObj.createdAt = "2017-04-17T04:57:32.188Z" //TODO: Set date with moment
    csonObj.updatedAt = "2017-04-17T04:57:45.464Z" //TODO: Set date with moment
    csonObj.title = filename;
    filename = crypto.randomBytes(10).toString('hex');
    writeFile = csonDir + '/' + filename + '.cson';
    @@ -193,58 +204,14 @@ var txtDir = '/Users/esouke/Documents/Notes';
    var csonDir = '/Users/esouke/Boostnote/notes';
    if (mode == '-h' || mode == undefined) {
    console.log('This will syncronize Boostrap and Simplenote');
    console.log(`node ${process.argv[1]} simple-to-boost`);
    console.log(`node ${process.argv[1]} boost-to-simple`);
    console.log(`node ${process.argv[1]} sync-both`);
    console.log(`node ${process.argv[1]} sync`);
    console.log(`node ${process.argv[1]} duplicates`);
    console.log(`node ${process.argv[1]} counter`);
    } else if (mode == 'counter') {
    noteCounter();
    } else if (mode == 'duplicates') {
    duplicates();
    } else if (mode == 'simple-to-boost') {
    txtWatcherReady = false;
    var txtWatcher = chokidar.watch(txtDir).on('all', (event, path) => {
    if (txtWatcherReady) {
    similiar(path);
    noteCounter();
    console.log(`EVENT: txt-->cson ${event}`);
    }
    if (event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//, '');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = csonDir + '/' + filename + '.cson'
    if (fs.existsSync(filename)) {
    console.log(`DELETING: ${filename}`);
    fs.unlink(filename);
    }
    }
    });
    txtWatcher.on('ready', () => txtWatcherReady = true);
    } else if (mode == 'boost-to-simple') {
    csonWatcherReady = false;
    var csonWatcher = chokidar.watch(csonDir).on('all', (event, path) => {
    if (csonWatcherReady) {
    console.log(`EVENT: cson-->txt ${event}`);
    noteCounter();
    similiar(path);
    }
    if (event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//, '');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = txtDir + '/' + filename + '.txt'
    if (fs.existsSync(filename)) {
    console.log(`DELETING: ${fs.readFileSync(filename).toString().trim().split('\n')[0]}`);
    fs.unlink(filename);
    }
    }
    });
    csonWatcher.on('ready', () => csonWatcherReady = true);
    } else if (mode == 'sync-both') {
    } else if (mode == 'sync') {

    //boost-to-simple
    csonWatcherReady = false;
    @@ -304,5 +271,4 @@ if (mode == '-h' || mode == undefined) {
    });
    txtWatcher.on('ready', () => txtWatcherReady = true);
    //end simple-to-boost
    //_proc = exec('/Applications/Boostnote.app/Contents/MacOS/Boostnote').unref()
    }
  9. Soukenka, Eric (ETW - FLEX) revised this gist Apr 25, 2017. 2 changed files with 5 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion package.json
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,9 @@
    "sanitize-filename": "^1.6.1",
    "string-similarity": "^1.1.0"
    },
    "devDependencies": {},
    "devDependencies": {
    "moment": "^2.18.1"
    },
    "scripts": {
    "test": "node sync-notes.js sync-both"
    },
    2 changes: 2 additions & 0 deletions sync-notes.js
    Original file line number Diff line number Diff line change
    @@ -27,6 +27,7 @@ var query = require('cli-interact').getYesNo;
    var readlineSync = require('readline-sync');
    var exec = require("child_process").exec
    var spawn = require("child_process").spawn
    var moment = require("moment")


    duplicates = () => {
    @@ -141,6 +142,7 @@ processor = (file) => {
    } else {
    csonObj.content = fs.readFileSync(file).toString().trim()
    csonObj.title = fs.readFileSync(file).toString().trim().split('\n')[0] + '\n';
    csonObj.updatedAt = moment().toISOString()
    if (csonObj.title.substring(0, 1) == '#') {
    csonObj.title = csonObj.title.substring(1)
    }
  10. Soukenka, Eric (ETW - FLEX) revised this gist Apr 25, 2017. 1 changed file with 228 additions and 229 deletions.
    457 changes: 228 additions & 229 deletions sync-notes.js
    Original file line number Diff line number Diff line change
    @@ -30,143 +30,143 @@ var spawn = require("child_process").spawn


    duplicates = () => {
    noteCounter();
    dupCounter = 0;
    answer = '';
    fs.readdirSync(csonDir).forEach(function(csonFile1) {
    if (path.extname(csonFile1) == '.cson') {
    status = 'false';
    try {
    csonObj1 = CSON.parse(fs.readFileSync(csonDir + '/' + csonFile1).toString());
    loop = true;
    fs.readdirSync(csonDir).forEach(function(csonFile2) {
    if(loop) {
    if (path.extname(csonFile2) == '.cson') {
    csonObj2 = CSON.parse(fs.readFileSync(csonDir + '/' + csonFile2).toString());
    x = stringSimilarity.compareTwoStrings(csonObj1.content, csonObj2.content);
    if (x > 0.9) {
    if(status == 'false') {
    status = 'checking';
    } else if(status = 'checking') {
    status = 'duplicate';
    if(answer != 'a') {
    answer = readlineSync.question(`Rating: ${x}\n(1) ${csonObj1.title}\n(2) ${csonObj2.title}\n(3) skip\n(a) all\n(l) log\nChoose 1 | 2 | 3 | a | l\n`);
    }
    if(answer == 1) {
    fs.unlink(`${csonDir}/${csonFile1}`);
    console.log(`DELETING: ${csonDir}/${csonFile1} ${csonObj1.title}`);
    } else if(answer == 2) {
    fs.unlink(`${csonDir}/${csonFile2}`);
    console.log(`DELETING: ${csonDir}/${csonFile2} ${csonObj2.title}`);
    } else if(answer == 3) {
    console.log(`SKIPPING`);
    } else if(answer == 'a') {
    console.log(`DELETING: ${csonDir}/${csonFile2} ${csonObj2.title}`);
    fs.unlink(`${csonDir}/${csonFile2}`);
    } else if(answer == 'l') {
    console.log(`LOGGING: ${csonDir}/${csonFile2} ${csonObj2.title}`);
    }
    loop = false;
    //console.log(`DUP: "${csonObj1.title.trim()}" "${csonObj2.title.trim()}" - ${x}`);
    dupCounter++;
    }
    }
    }
    }
    })
    } catch(e) {
    console.log('ERROR');
    }
    }
    })
    console.log(`Duplicates: ${dupCounter}`)
    noteCounter();
    noteCounter();
    dupCounter = 0;
    answer = '';
    fs.readdirSync(csonDir).forEach(function(csonFile1) {
    if (path.extname(csonFile1) == '.cson') {
    status = 'false';
    try {
    csonObj1 = CSON.parse(fs.readFileSync(csonDir + '/' + csonFile1).toString());
    loop = true;
    fs.readdirSync(csonDir).forEach(function(csonFile2) {
    if (loop) {
    if (path.extname(csonFile2) == '.cson') {
    csonObj2 = CSON.parse(fs.readFileSync(csonDir + '/' + csonFile2).toString());
    x = stringSimilarity.compareTwoStrings(csonObj1.content, csonObj2.content);
    if (x > 0.9) {
    if (status == 'false') {
    status = 'checking';
    } else if (status = 'checking') {
    status = 'duplicate';
    if (answer != 'a') {
    answer = readlineSync.question(`Rating: ${x}\n(1) ${csonObj1.title}\n(2) ${csonObj2.title}\n(3) skip\n(a) all\n(l) log\nChoose 1 | 2 | 3 | a | l\n`);
    }
    if (answer == 1) {
    fs.unlink(`${csonDir}/${csonFile1}`);
    console.log(`DELETING: ${csonDir}/${csonFile1} ${csonObj1.title}`);
    } else if (answer == 2) {
    fs.unlink(`${csonDir}/${csonFile2}`);
    console.log(`DELETING: ${csonDir}/${csonFile2} ${csonObj2.title}`);
    } else if (answer == 3) {
    console.log(`SKIPPING`);
    } else if (answer == 'a') {
    console.log(`DELETING: ${csonDir}/${csonFile2} ${csonObj2.title}`);
    fs.unlink(`${csonDir}/${csonFile2}`);
    } else if (answer == 'l') {
    console.log(`LOGGING: ${csonDir}/${csonFile2} ${csonObj2.title}`);
    }
    loop = false;
    //console.log(`DUP: "${csonObj1.title.trim()}" "${csonObj2.title.trim()}" - ${x}`);
    dupCounter++;
    }
    }
    }
    }
    })
    } catch (e) {
    console.log('ERROR');
    }
    }
    })
    console.log(`Duplicates: ${dupCounter}`)
    noteCounter();
    }

    similiar = (file) => {
    if (path.extname(file) == '.cson' && fs.existsSync(file)) {
    status = 'new';
    csonObj = CSON.parse(fs.readFileSync(file).toString());
    //console.log(`SIMILIARITY: check ${csonObj.title.trim()}`);
    fs.readdirSync(txtDir).forEach(function(txtFile) {
    if (path.extname(txtFile) == '.txt') {
    txtContent = fs.readFileSync(txtDir + '/' + txtFile).toString()
    x = stringSimilarity.compareTwoStrings(csonObj.content, txtContent);
    if (x > 0.9) {
    if(status == 'new') {
    status = 'existing';
    } else if(status= 'existing') {
    console.log(`DUPLICATE: "${csonObj.title.trim()}" "${txtContent.split('\n')[0]}" - ${x}`);
    }
    }
    }
    })
    }
    if (path.extname(file) == '.cson' && fs.existsSync(file)) {
    status = 'new';
    csonObj = CSON.parse(fs.readFileSync(file).toString());
    //console.log(`SIMILIARITY: check ${csonObj.title.trim()}`);
    fs.readdirSync(txtDir).forEach(function(txtFile) {
    if (path.extname(txtFile) == '.txt') {
    txtContent = fs.readFileSync(txtDir + '/' + txtFile).toString()
    x = stringSimilarity.compareTwoStrings(csonObj.content, txtContent);
    if (x > 0.9) {
    if (status == 'new') {
    status = 'existing';
    } else if (status = 'existing') {
    console.log(`DUPLICATE: "${csonObj.title.trim()}" "${txtContent.split('\n')[0]}" - ${x}`);
    }
    }
    }
    })
    }
    }

    processor = (file) => {
    if (path.extname(file) == '.cson') {
    readFile = path.basename(file);
    filename = readFile.replace(/\.[^/.]+$/, "");
    writeFile = txtDir + '/' + filename + '.txt';
    csonObj = CSON.parse(fs.readFileSync(file).toString())
    //if(csonObj.title.substring(0,1) != '#') {
    //csonObj.title = csonObj.title.substring(1)
    //}
    if(fs.existsSync(writeFile)) {
    if(fs.readFileSync(writeFile).toString().trim() != csonObj.content.trim()) {
    if(fs.statSync(writeFile).mtime > fs.statSync(file).mtime) {
    console.log('write > read')
    } else {
    console.log(`MODIFED: cson ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    } else {
    console.log(`UNCHANGED: ${csonObj.title.trim()}`)
    }
    } else {
    console.log(`ADDED NEW FILE ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    }
    if (path.extname(file) == '.txt') {
    readFile = path.basename(file);
    filename = readFile.replace(/\.[^/.]+$/, "");
    writeFile = csonDir + '/' + filename + '.cson';
    if(fs.existsSync(writeFile)) {
    csonObj = CSON.parse(fs.readFileSync(writeFile).toString())
    if(fs.readFileSync(file).toString().trim() != csonObj.content.trim()) {
    if(fs.statSync(writeFile).mtime > fs.statSync(file).mtime) {
    console.log('write > read')
    } else {
    csonObj.content = fs.readFileSync(file).toString().trim()
    csonObj.title = fs.readFileSync(file).toString().trim().split('\n')[0] + '\n';
    if(csonObj.title.substring(0,1) == '#') {
    csonObj.title = csonObj.title.substring(1)
    }
    console.log(`MODIFIED: txt ${fs.readFileSync(file).toString().trim().split('\n')[0]}`);
    fs.writeFileSync(writeFile, CSON.stringify(csonObj));
    }
    } else {
    console.log(`UNCHANGED: ${csonObj.title.trim()}`)
    }
    } else {
    csonObj = {}
    csonObj.type = 'MARKDOWN_NOTE'
    csonObj.folder = '94b8c2e8acf3448698d7'
    csonObj.tags = []
    csonObj.isStarred = false
    csonObj.createdAt = "2017-04-17T04:57:32.188Z"
    csonObj.updatedAt = "2017-04-17T04:57:45.464Z"
    csonObj.title = filename;
    filename = crypto.randomBytes(10).toString('hex');
    writeFile = csonDir + '/' + filename + '.cson';
    csonObj.content = fs.readFileSync(file).toString().trim();
    console.log(`SKIPPING: NEW NOTE: ${writeFile} - NOTE THIS IS BUGGY`);
    //TODO: Adding a txt note will not create id and cleanup. This causes multiple duplicates
    if (path.extname(file) == '.cson') {
    readFile = path.basename(file);
    filename = readFile.replace(/\.[^/.]+$/, "");
    writeFile = txtDir + '/' + filename + '.txt';
    csonObj = CSON.parse(fs.readFileSync(file).toString())
    //if(csonObj.title.substring(0,1) != '#') {
    //csonObj.title = csonObj.title.substring(1)
    //}
    if (fs.existsSync(writeFile)) {
    if (fs.readFileSync(writeFile).toString().trim() != csonObj.content.trim()) {
    if (fs.statSync(writeFile).mtime > fs.statSync(file).mtime) {
    console.log('write > read')
    } else {
    console.log(`MODIFED: cson ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    } else {
    console.log(`UNCHANGED: ${csonObj.title.trim()}`)
    }
    } else {
    console.log(`ADDED NEW FILE ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    }
    if (path.extname(file) == '.txt') {
    readFile = path.basename(file);
    filename = readFile.replace(/\.[^/.]+$/, "");
    writeFile = csonDir + '/' + filename + '.cson';
    if (fs.existsSync(writeFile)) {
    csonObj = CSON.parse(fs.readFileSync(writeFile).toString())
    if (fs.readFileSync(file).toString().trim() != csonObj.content.trim()) {
    if (fs.statSync(writeFile).mtime > fs.statSync(file).mtime) {
    console.log('write > read')
    } else {
    csonObj.content = fs.readFileSync(file).toString().trim()
    csonObj.title = fs.readFileSync(file).toString().trim().split('\n')[0] + '\n';
    if (csonObj.title.substring(0, 1) == '#') {
    csonObj.title = csonObj.title.substring(1)
    }
    console.log(`MODIFIED: txt ${fs.readFileSync(file).toString().trim().split('\n')[0]}`);
    fs.writeFileSync(writeFile, CSON.stringify(csonObj));
    }
    } else {
    console.log(`UNCHANGED: ${csonObj.title.trim()}`)
    }
    } else {
    csonObj = {}
    csonObj.type = 'MARKDOWN_NOTE'
    csonObj.folder = '94b8c2e8acf3448698d7'
    csonObj.tags = []
    csonObj.isStarred = false
    csonObj.createdAt = "2017-04-17T04:57:32.188Z"
    csonObj.updatedAt = "2017-04-17T04:57:45.464Z"
    csonObj.title = filename;
    filename = crypto.randomBytes(10).toString('hex');
    writeFile = csonDir + '/' + filename + '.cson';
    csonObj.content = fs.readFileSync(file).toString().trim();
    console.log(`SKIPPING: NEW NOTE: ${writeFile} - NOTE THIS IS BUGGY`);
    //TODO: Adding a txt note will not create id and cleanup. This causes multiple duplicates
    //fs.unlink(file)
    }
    }
    }
    }
    }

    noteCounter = () => {
    @@ -197,111 +197,110 @@ if (mode == '-h' || mode == undefined) {
    console.log(`node ${process.argv[1]} duplicates`);
    console.log(`node ${process.argv[1]} counter`);
    } else if (mode == 'counter') {
    noteCounter();
    noteCounter();
    } else if (mode == 'duplicates') {
    duplicates();
    duplicates();
    } else if (mode == 'simple-to-boost') {
    txtWatcherReady = false;
    var txtWatcher = chokidar.watch(txtDir).on('all', (event, path) => {
    if(txtWatcherReady) {
    similiar(path);
    noteCounter();
    console.log(`EVENT: txt-->cson ${event}`);
    }
    if(event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//,'');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = csonDir + '/' + filename + '.cson'
    if(fs.existsSync(filename)) {
    console.log(`DELETING: ${filename}`);
    fs.unlink(filename);
    }
    }
    });
    txtWatcherReady = false;
    var txtWatcher = chokidar.watch(txtDir).on('all', (event, path) => {
    if (txtWatcherReady) {
    similiar(path);
    noteCounter();
    console.log(`EVENT: txt-->cson ${event}`);
    }
    if (event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//, '');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = csonDir + '/' + filename + '.cson'
    if (fs.existsSync(filename)) {
    console.log(`DELETING: ${filename}`);
    fs.unlink(filename);
    }
    }
    });
    txtWatcher.on('ready', () => txtWatcherReady = true);
    } else if (mode == 'boost-to-simple') {
    csonWatcherReady = false;
    var csonWatcher = chokidar.watch(csonDir).on('all', (event, path) => {
    if(csonWatcherReady) {
    console.log(`EVENT: cson-->txt ${event}`);
    noteCounter();
    similiar(path);
    }
    if(event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//,'');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = txtDir + '/' + filename + '.txt'
    if(fs.existsSync(filename)) {
    console.log(`DELETING: ${fs.readFileSync(filename).toString().trim().split('\n')[0]}`);
    fs.unlink(filename);
    }
    }
    });
    csonWatcherReady = false;
    var csonWatcher = chokidar.watch(csonDir).on('all', (event, path) => {
    if (csonWatcherReady) {
    console.log(`EVENT: cson-->txt ${event}`);
    noteCounter();
    similiar(path);
    }
    if (event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//, '');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = txtDir + '/' + filename + '.txt'
    if (fs.existsSync(filename)) {
    console.log(`DELETING: ${fs.readFileSync(filename).toString().trim().split('\n')[0]}`);
    fs.unlink(filename);
    }
    }
    });
    csonWatcher.on('ready', () => csonWatcherReady = true);
    } else if (mode == 'sync-both') {

    //boost-to-simple
    csonWatcherReady = false;
    //var csonWatcher = chokidar.watch(csonDir).on('all', (event, path) => {
    var csonWatcher = chokidar.watch(csonDir, {
    alwaysState: true,
    awaitWriteFinish: {
    stabilityThreshold: 5000,
    pollInterval: 100
    },
    }).on('all', (event, path) => {
    if(csonWatcherReady) {
    console.log(`EVENT CSON-->TXT: ${event}`);
    noteCounter();
    similiar(path);
    }
    if(event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//,'');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = txtDir + '/' + filename + '.txt'
    if(fs.existsSync(filename)) {
    console.log(`DELETING: ${fs.readFileSync(filename).toString().trim().split('\n')[0]}`);
    fs.unlink(filename);
    }
    }
    });
    //boost-to-simple
    csonWatcherReady = false;
    //var csonWatcher = chokidar.watch(csonDir).on('all', (event, path) => {
    var csonWatcher = chokidar.watch(csonDir, {
    alwaysState: true,
    awaitWriteFinish: {
    stabilityThreshold: 5000,
    pollInterval: 100
    },
    }).on('all', (event, path) => {
    if (csonWatcherReady) {
    console.log(`EVENT CSON-->TXT: ${event}`);
    noteCounter();
    similiar(path);
    }
    if (event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//, '');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = txtDir + '/' + filename + '.txt'
    if (fs.existsSync(filename)) {
    console.log(`DELETING: ${fs.readFileSync(filename).toString().trim().split('\n')[0]}`);
    fs.unlink(filename);
    }
    }
    });
    csonWatcher.on('ready', () => csonWatcherReady = true);
    //end boost-to-simple

    //simple-to-boost
    txtWatcherReady = false;
    var txtWatcher = chokidar.watch(txtDir, {
    alwaysState: true,
    awaitWriteFinish: {
    stabilityThreshold: 2000,
    pollInterval: 100
    },
    }).on('all', (event, path) => {
    if(txtWatcherReady) {
    similiar(path);
    noteCounter();
    console.log(`EVENT TXT-->CSON: ${event}`);
    }
    if(event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//,'');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = csonDir + '/' + filename + '.cson'
    if(fs.existsSync(filename)) {
    console.log(`DELETING: ${filename}`);
    fs.unlink(filename);
    }
    }
    });
    txtWatcher.on('ready', () => txtWatcherReady = true);
    //end simple-to-boost
    //_proc = exec('/Applications/Boostnote.app/Contents/MacOS/Boostnote').unref()
    }
    //end boost-to-simple

    //simple-to-boost
    txtWatcherReady = false;
    var txtWatcher = chokidar.watch(txtDir, {
    alwaysState: true,
    awaitWriteFinish: {
    stabilityThreshold: 2000,
    pollInterval: 100
    },
    }).on('all', (event, path) => {
    if (txtWatcherReady) {
    similiar(path);
    noteCounter();
    console.log(`EVENT TXT-->CSON: ${event}`);
    }
    if (event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//, '');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = csonDir + '/' + filename + '.cson'
    if (fs.existsSync(filename)) {
    console.log(`DELETING: ${filename}`);
    fs.unlink(filename);
    }
    }
    });
    txtWatcher.on('ready', () => txtWatcherReady = true);
    //end simple-to-boost
    //_proc = exec('/Applications/Boostnote.app/Contents/MacOS/Boostnote').unref()
    }
  11. Soukenka, Eric (ETW - FLEX) revised this gist Apr 25, 2017. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    node_modules
  12. Soukenka, Eric (ETW - FLEX) revised this gist Apr 25, 2017. 1 changed file with 28 additions and 0 deletions.
    28 changes: 28 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,28 @@
    {
    "name": "sync-notes",
    "version": "1.0.0",
    "description": "Syncs Simplenote to boostnote and vice versa",
    "main": "sync-notes.js",
    "dependencies": {
    "cli-interact": "^0.1.9",
    "chokidar": "^1.6.1",
    "cson": "^4.1.0",
    "parse-json": "^2.2.0",
    "sanitize-filename": "^1.6.1",
    "string-similarity": "^1.1.0"
    },
    "devDependencies": {},
    "scripts": {
    "test": "node sync-notes.js sync-both"
    },
    "repository": {
    "type": "git",
    "url": "git+https://gist.github.com/fe0b2b83c4d5faf9ac92c82c224d506d.git"
    },
    "author": "eric soukenka",
    "license": "ISC",
    "bugs": {
    "url": "https://gist.github.com/fe0b2b83c4d5faf9ac92c82c224d506d"
    },
    "homepage": "https://gist.github.com/fe0b2b83c4d5faf9ac92c82c224d506d"
    }
  13. Soukenka, Eric (ETW - FLEX) revised this gist Apr 25, 2017. 2 changed files with 0 additions and 11 deletions.
    10 changes: 0 additions & 10 deletions skeleton.js
    Original file line number Diff line number Diff line change
    @@ -1,10 +0,0 @@
    type: "MARKDOWN_NOTE"
    folder: "94b8c2e8acf3448698d7"
    title: "unknown"
    content: '''
    unknown
    '''
    tags: []
    isStarred: false
    createdAt: "2017-04-17T04:57:32.188Z"
    updatedAt: "2017-04-17T04:57:45.464Z"
    1 change: 0 additions & 1 deletion test.txt
    Original file line number Diff line number Diff line change
    @@ -1 +0,0 @@
    hi
  14. Soukenka, Eric (ETW - FLEX) revised this gist Apr 25, 2017. 3 changed files with 590 additions and 95 deletions.
    196 changes: 101 additions & 95 deletions cleanup-duplicate-boostrap-entries.js
    Original file line number Diff line number Diff line change
    @@ -1,112 +1,118 @@
    /*********************************************************
    *
    * @TITLE: Simplenote and Boostrap Note Syncronization
    *
    * @DESCRIPTION: Supports two modes one which exports
    * Boostrap notes and exports them to nvAlt .txt files.
    * The other will export nvALT txt files to Boostrap .cson files
    *
    * @INSTRUCTIONS: Change readDir's and writeDir's at the top of
    * both functions appropriately then run with no parameters for
    * insrtructions.
    *
    * I recommend changing the folder id in skeleton.js. It may
    * even be required.
    *
    * @TITLE: Boostrap Duplicate Records
    * @DESCRIPTION: Uses String Similiarity to compare note
    * titles and contents to determine similiar records.
    * Upon intelligently determining records which are safe
    * to delete automatically if entries are close it will
    * prompt you per entry if it is safe to delete.
    *
    * @AUTHOR: Eric Soukenka
    * @DATE: April 20th 2017
    *
    * @NOTE: Created due to learning too late I had to restart
    * Boostrap after manually editing .cson files if I was
    * going to start using the application to modify entries.
    *
    * @NOTE: nvALT must have syncronization setting set to Plain
    * Text files.
    *
    * @NOTE: Ensure you restart Boostrap after import to avoid
    * duplicate entries.
    *
    * @NOTE: NOT YET POLISHED meaning it has a lot of my specific
    * requirements and even the code is relatively embarrising :)
    *
    * !!! #################### !!!
    * ####### IMPORTANT ##### !!!
    * !!! Restart Boostrap after import!!!!!
    * @NOTE: NOT YET POLISHED it was wrote during anger of
    * learning I had hundreds of duplicates and regex'ing toe
    * fix was too complicated.
    *
    ********************************************************* */
    ********************************************************* */
    var parseJson = require('parse-json');
    var fs = require('fs');
    var path = require('path');
    var CSON = require('cson');
    var crypto = require('crypto');
    var stringSimilarity = require('string-similarity');
    //var globals = require('globals');
    var _ = require('underscore');
    var query = require('cli-interact').getYesNo;


    var readDir = '/Users/esouke/Boostnote/notes';
    var writeDir = '/Users/esouke/Documents/Notes';
    var separator = '\n=========================================================\n'
    var cleanupFiles = [];
    var maybeCleanupFiles = [];

    // TXT --> CSON
    convertCsonToTxt = () => {
    var skeleton = CSON.parseCSONFile('skeleton.cson');
    var readDir = '/Users/esouke/Boostnote/notes';
    var writeDir = '/Users/esouke/Documents/Notes';
    var separator = '\n=========================================================\n'

    fs.readdirSync(writeDir).forEach(function(file) {
    if (path.extname(file) == '.txt') {
    fs.unlink(writeDir + '/' + file)
    }
    })
    files = fs.readdirSync(readDir);
    filelist = [];
    files.forEach(function(readfile) {
    console.log(readfile)
    if (path.extname(readfile) == '.cson') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var obj = CSON.parse(txt);
    var writeFile = writeDir + '/' + obj.title + '.txt';
    var writeBody = obj.content.replace(obj.title, '').replace(/\s+.*====/, '').replace(obj.title, '').replace(/^\s+|\s+$/g, '');
    fs.writeFileSync(writeFile, obj.title + separator + writeBody);
    }
    })
    console.log("IMPORTANT! Restart Boostrap if it is running!!!");
    files = fs.readdirSync(readDir);
    /*
    files = files.sort(function(a, b) {
    return a < b ? -1 : 1;
    })
    */
    files.forEach(function(readfile) {
    try {
    if (path.extname(readfile) == '.cson') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var obj = CSON.parse(txt);
    if (obj.title) {
    files.forEach(readfile2 => {
    var answer = false;
    var txt2 = fs.readFileSync(readDir + '/' + readfile2).toString();
    var obj2 = CSON.parse(txt + txt2)
    if (obj2.title) {
    x = stringSimilarity.compareTwoStrings(obj.title, obj2.title);
    if (x > 03 && x != 1) {
    y = stringSimilarity.compareTwoStrings(obj.content, obj2.content);
    if (y > 0.9) {
    console.log(`GOING: --------------- ${x} - ${y}`)
    console.log(`OLD: ${obj.title}`);
    console.log(`NEW: ${obj2.title}`);
    console.log(`KEE: ${readDir}/${readfile}`)
    console.log(`DEL: ${readDir}/${readfile2}`)
    cleanupFiles.push(readDir + '/' + readfile2);
    } else {
    if (y > 0.5) {
    console.log(`ASKING: ----------- ${x} - ${y}`)
    console.log(`OLD: ${obj.title}`);
    console.log(`NEW: ${obj2.title}`);
    console.log(`KEE: ${readDir}/${readfile}`)
    console.log(`DEL: ${readDir}/${readfile2}`)
    maybeCleanupFiles.push(readDir + '/' + readfile2);
    } else {
    console.log(`SKIPPING: ${y} ${obj.title} - ${obj2.title} - ${x}`)
    }
    }
    }
    }
    })
    }
    }
    } catch (e) {
    console.log(`ERROR: ${readfile}`);
    }
    })
    for (index = 0; index < cleanupFiles.length; ++index) {
    console.log(`Deleting: ${cleanupFiles[index]}`);
    try {
    fs.unlinkSync(cleanupFiles[index]);
    } catch (e) {
    console.log(`ERROR deleting: ${cleanupFiles[index]}`);
    }
    }

    // CSON --> TXT
    convertTxtToCson = () => {
    var skeleton = CSON.parseCSONFile('skeleton.cson');
    var readDir = '/Users/esouke/Documents/Notes';
    var writeDir = '/Users/esouke/Boostnote/notes';
    var separator = '\n=========================================================\n'

    fs.readdirSync(writeDir).forEach(function(file) {
    if (path.extname(file) == '.cson') {
    fs.unlink(writeDir + '/' + file)
    }
    })
    files = fs.readdirSync(readDir);
    filelist = [];
    files.forEach(function(readfile) {
    if (path.extname(readfile) == '.txt') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var writeFile = writeDir + '/' + crypto.randomBytes(10).toString('hex') + '.cson';
    readfile = readfile.replace(/\.[^/.]+$/, "");

    skeleton.title = readfile;
    var writeBody = txt.replace(readfile, '').replace(/\s+.*====/, '').replace(readfile, '').replace(/^\s+|\s+$/g, '')

    skeleton.content = skeleton.title + separator + writeBody;

    fs.writeFileSync(writeFile, CSON.stringify(skeleton));

    skeleton.title = 'unknown';
    skeleton.content = 'unknown';
    }
    });
    for (index = 0; index < maybeCleanupFiles.length; ++index) {
    console.log("--------------------------------------");
    try {
    txt = fs.readFileSync(maybeCleanupFiles[index]).toString();
    obj = CSON.parse(txt);
    console.log(`Info: ${obj.title}`)
    answer = query('delete');
    if (answer) {
    console.log(`Deleting: ${maybeCleanupFiles[index]}`);
    try {
    fs.unlinkSync(cleanupFiles[index]);
    } catch (e) {
    console.log(`ERROR deleting: ${cleanupFiles[index]}`);
    }
    } else {
    console.log(`Skipping: ${maybeCleanupFiles[index]}`);
    }
    } catch (e) {
    console.log('error');
    }
    }

    var mode = process.argv[2];
    if(mode == '-h' || mode == undefined) {
    console.log('This will syncronize Boostrap and Simplenote');
    console.log(`node ${process.argv[1]} simple-to-boost`);
    console.log(`node ${process.argv[1]} boost-to-simple`);
    } else if (mode == 'simple-to-boost') {
    console.log('Syncing Simplenote to Boostrap');
    convertTxtToCson();
    } else if (mode == 'boost-to-simple') {
    console.log('Syncing Boostrap to Simplenote');
    convertCsonToTxt();
    }
    //export.tsv
    //Querybuilder search for multiple properties
    182 changes: 182 additions & 0 deletions simplenote-boostrap-sync.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,182 @@
    /*********************************************************
    *
    * @TITLE: Simplenote and Boostrap Note Syncronization
    *
    * @DESCRIPTION: Supports two modes one which exports
    * Boostrap notes and exports them to nvAlt .txt files.
    * The other will export nvALT txt files to Boostrap .cson files
    *
    * @INSTRUCTIONS: Change readDir's and writeDir's at the top of
    * both functions appropriately then run with no parameters for
    * insrtructions.
    *
    * I recommend changing the folder id in skeleton.js. It may
    * even be required.
    *
    * @AUTHOR: Eric Soukenka
    * @DATE: April 20th 2017
    *
    * @NOTE: nvALT must have syncronization setting set to Plain
    * Text files.
    *
    * @NOTE: Ensure you restart Boostrap after import to avoid
    * duplicate entries.
    *
    * @NOTE: NOT YET POLISHED meaning it has a lot of my specific
    * requirements and even the code is relatively embarrising :)
    *
    * !!! #################### !!!
    * ####### IMPORTANT ##### !!!
    * !!! Restart Boostrap after import!!!!!
    *
    ********************************************************* */
    var parseJson = require('parse-json');
    var fs = require('fs');
    var path = require('path');
    var CSON = require('cson');
    var crypto = require('crypto');
    var sanitize = require("sanitize-filename");




    noteCounter = () => {
    var csonDir = '/Users/esouke/Boostnote/notes';
    var txtDir= '/Users/esouke/Documents/Notes';
    var csonCount = 0;
    var txtCount = 0;

    fs.readdirSync(csonDir).forEach(function(readfile) {
    if (path.extname(readfile) == '.cson') {
    csonCount++;
    }
    });
    fs.readdirSync(txtDir).forEach(function(readfile) {
    if (path.extname(readfile) == '.txt') {
    txtCount++;
    }
    });
    console.log(`.cson = ${csonCount}`);
    console.log(`.txt = ${txtCount}`);
    }

    // CSON --> TXT
    convertCsonToTxt = () => {
    var skeleton = CSON.parseCSONFile('skeleton.cson');
    var readDir = '/Users/esouke/Boostnote/notes';
    var writeDir = '/Users/esouke/Documents/Notes';
    var separator = '\n=========================================================\n'
    fs.readdirSync(writeDir).forEach(function(file) {
    if (path.extname(file) == '.txt') {
    fs.unlink(writeDir + '/' + file)
    }
    })
    fs.readdirSync(readDir).forEach(function(readfile) {
    if (path.extname(readfile) == '.cson') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var obj = CSON.parse(txt);
    if(obj.title.substring(0,1) == '#') {
    obj.title = obj.title.substr(1);
    }
    if(obj.title.substring(0,1) == ' ') {
    obj.title = obj.title.substr(1);
    }
    if(obj.content.substring(0,1) != '#') {
    obj.content = '# ' + obj.content
    }
    var writeFile = writeDir + '/' + obj.title + '-' + crypto.randomBytes(1).toString('hex') + '.txt';
    //var writeBody = obj.content.replace(obj.title, '').replace(/\s+.*====/, '').replace(obj.title, '').replace(/^\s+|\s+$/g, '');
    //fs.writeFileSync(writeFile, sanitize(obj.title + separator + writeBody));
    fs.writeFileSync(writeFile, obj.content);
    }
    })
    console.log("Finished Export from Boostrap to Simplenote Import (cson->txt)");
    noteCounter();
    }

    // TXT --> CSON
    convertTxtToCson = () => {
    var skeleton = CSON.parseCSONFile('skeleton.cson');
    var readDir = '/Users/esouke/Documents/Notes';
    var writeDir = '/Users/esouke/Boostnote/notes';
    var separator = '\n=========================================================\n'

    fs.readdirSync(writeDir).forEach(function(file) {
    if (path.extname(file) == '.cson') {
    fs.unlink(writeDir + '/' + file)
    }
    })
    fs.readdirSync(readDir).forEach(function(readfile) {
    if (path.extname(readfile) == '.txt') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var writeFile = writeDir + '/' + crypto.randomBytes(10).toString('hex') + '.cson';
    readfile = readfile.replace(/\.[^/.]+$/, "");

    var lines = txt.split('\n');
    intCounter = 0;
    lines.forEach(function(line) {
    if(intCounter == 0) {
    skeleton.title = line.substring(1).trim();
    skeleton.content = line.replace(/#(\s\s)+/,'# ') + '\n';
    } else {
    skeleton.content += line + '\n';
    }
    intCounter++;
    })

    fs.writeFileSync(writeFile,CSON.stringify(skeleton));
    }
    });
    console.log("Finished Export from Simplenote to Boostnote (txt->cson)");
    noteCounter();
    console.log("IMPORTANT! Restart Boostrap if it is running!!!");
    }
    adhoc = () => {
    console.log('adhoc')
    var skeleton = CSON.parseCSONFile('skeleton.cson');
    var readDir = '/Users/esouke/Boostnote/notes';
    var writeDir = '/Users/esouke/Boostnote/notes';
    var separator = '\n=========================================================\n'

    fs.readdirSync(readDir).forEach(function(readfile) {
    if (path.extname(readfile) == '.cson') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var obj = CSON.parse(txt);
    obj.title = obj.title.trim();
    var firstLine = obj.content.split('\n')[0];
    //console.log(obj.title)
    var lines = obj.content.split('\n');
    obj.content = '';
    intCounter = 0;
    lines.forEach(function(line) {
    if(intCounter == 0) {
    //x = '# DTM:SSJS: test'
    //console.log(x.replace(/(\s\s)+/,' ') + '\n');
    obj.title = line.substring(1).trim();
    obj.content = line.replace(/(\s\s)+/,' ') + '\n';
    } else {
    obj.content += line + '\n';
    }
    intCounter++;
    })
    console.log(writeDir + '/' + readfile)
    fs.writeFileSync(writeDir + '/' + readfile,CSON.stringify(obj));
    }
    })
    console.log("IMPORTANT! Restart Boostrap if it is running!!!");
    }
    var mode = process.argv[2];
    if (mode == '-h' || mode == undefined) {
    console.log('This will syncronize Boostrap and Simplenote');
    console.log(`node ${process.argv[1]} simple-to-boost`);
    console.log(`node ${process.argv[1]} boost-to-simple`);
    console.log(`node ${process.argv[1]} count`);
    } else if (mode == 'simple-to-boost') {
    convertTxtToCson();
    } else if (mode == 'boost-to-simple') {
    convertCsonToTxt();
    } else if (mode == 'count') {
    noteCounter();
    } else if (mode == 'adhoc') {
    adhoc();
    }
    307 changes: 307 additions & 0 deletions sync-notes.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,307 @@
    /*********************************************************
    *
    * @TITLE: Simplenote and Boostrap Note Syncronization
    *
    * @DESCRIPTION: Supports two modes one which exports
    * Boostrap notes and exports them to nvAlt .txt files.
    * The other will export nvALT txt files to Boostrap .cson files
    *
    * @INSTRUCTIONS: Change readDir's and writeDir's at the top of
    * both functions appropriately then run with no parameters for
    * insrtructions.
    *
    *
    * @AUTHOR: Eric Soukenka
    * @DATE: April 20th 2017
    *
    ********************************************************* */
    var parseJson = require('parse-json');
    var fs = require('fs');
    var path = require('path');
    var CSON = require('cson');
    var crypto = require('crypto');
    var sanitize = require("sanitize-filename");
    var chokidar = require('chokidar');
    var stringSimilarity = require('string-similarity');
    var query = require('cli-interact').getYesNo;
    var readlineSync = require('readline-sync');
    var exec = require("child_process").exec
    var spawn = require("child_process").spawn


    duplicates = () => {
    noteCounter();
    dupCounter = 0;
    answer = '';
    fs.readdirSync(csonDir).forEach(function(csonFile1) {
    if (path.extname(csonFile1) == '.cson') {
    status = 'false';
    try {
    csonObj1 = CSON.parse(fs.readFileSync(csonDir + '/' + csonFile1).toString());
    loop = true;
    fs.readdirSync(csonDir).forEach(function(csonFile2) {
    if(loop) {
    if (path.extname(csonFile2) == '.cson') {
    csonObj2 = CSON.parse(fs.readFileSync(csonDir + '/' + csonFile2).toString());
    x = stringSimilarity.compareTwoStrings(csonObj1.content, csonObj2.content);
    if (x > 0.9) {
    if(status == 'false') {
    status = 'checking';
    } else if(status = 'checking') {
    status = 'duplicate';
    if(answer != 'a') {
    answer = readlineSync.question(`Rating: ${x}\n(1) ${csonObj1.title}\n(2) ${csonObj2.title}\n(3) skip\n(a) all\n(l) log\nChoose 1 | 2 | 3 | a | l\n`);
    }
    if(answer == 1) {
    fs.unlink(`${csonDir}/${csonFile1}`);
    console.log(`DELETING: ${csonDir}/${csonFile1} ${csonObj1.title}`);
    } else if(answer == 2) {
    fs.unlink(`${csonDir}/${csonFile2}`);
    console.log(`DELETING: ${csonDir}/${csonFile2} ${csonObj2.title}`);
    } else if(answer == 3) {
    console.log(`SKIPPING`);
    } else if(answer == 'a') {
    console.log(`DELETING: ${csonDir}/${csonFile2} ${csonObj2.title}`);
    fs.unlink(`${csonDir}/${csonFile2}`);
    } else if(answer == 'l') {
    console.log(`LOGGING: ${csonDir}/${csonFile2} ${csonObj2.title}`);
    }
    loop = false;
    //console.log(`DUP: "${csonObj1.title.trim()}" "${csonObj2.title.trim()}" - ${x}`);
    dupCounter++;
    }
    }
    }
    }
    })
    } catch(e) {
    console.log('ERROR');
    }
    }
    })
    console.log(`Duplicates: ${dupCounter}`)
    noteCounter();
    }

    similiar = (file) => {
    if (path.extname(file) == '.cson' && fs.existsSync(file)) {
    status = 'new';
    csonObj = CSON.parse(fs.readFileSync(file).toString());
    //console.log(`SIMILIARITY: check ${csonObj.title.trim()}`);
    fs.readdirSync(txtDir).forEach(function(txtFile) {
    if (path.extname(txtFile) == '.txt') {
    txtContent = fs.readFileSync(txtDir + '/' + txtFile).toString()
    x = stringSimilarity.compareTwoStrings(csonObj.content, txtContent);
    if (x > 0.9) {
    if(status == 'new') {
    status = 'existing';
    } else if(status= 'existing') {
    console.log(`DUPLICATE: "${csonObj.title.trim()}" "${txtContent.split('\n')[0]}" - ${x}`);
    }
    }
    }
    })
    }
    }

    processor = (file) => {
    if (path.extname(file) == '.cson') {
    readFile = path.basename(file);
    filename = readFile.replace(/\.[^/.]+$/, "");
    writeFile = txtDir + '/' + filename + '.txt';
    csonObj = CSON.parse(fs.readFileSync(file).toString())
    //if(csonObj.title.substring(0,1) != '#') {
    //csonObj.title = csonObj.title.substring(1)
    //}
    if(fs.existsSync(writeFile)) {
    if(fs.readFileSync(writeFile).toString().trim() != csonObj.content.trim()) {
    if(fs.statSync(writeFile).mtime > fs.statSync(file).mtime) {
    console.log('write > read')
    } else {
    console.log(`MODIFED: cson ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    } else {
    console.log(`UNCHANGED: ${csonObj.title.trim()}`)
    }
    } else {
    console.log(`ADDED NEW FILE ${csonObj.title.trim()}`)
    fs.writeFileSync(writeFile, csonObj.content.trim() + '\n');
    }
    }
    if (path.extname(file) == '.txt') {
    readFile = path.basename(file);
    filename = readFile.replace(/\.[^/.]+$/, "");
    writeFile = csonDir + '/' + filename + '.cson';
    if(fs.existsSync(writeFile)) {
    csonObj = CSON.parse(fs.readFileSync(writeFile).toString())
    if(fs.readFileSync(file).toString().trim() != csonObj.content.trim()) {
    if(fs.statSync(writeFile).mtime > fs.statSync(file).mtime) {
    console.log('write > read')
    } else {
    csonObj.content = fs.readFileSync(file).toString().trim()
    csonObj.title = fs.readFileSync(file).toString().trim().split('\n')[0] + '\n';
    if(csonObj.title.substring(0,1) == '#') {
    csonObj.title = csonObj.title.substring(1)
    }
    console.log(`MODIFIED: txt ${fs.readFileSync(file).toString().trim().split('\n')[0]}`);
    fs.writeFileSync(writeFile, CSON.stringify(csonObj));
    }
    } else {
    console.log(`UNCHANGED: ${csonObj.title.trim()}`)
    }
    } else {
    csonObj = {}
    csonObj.type = 'MARKDOWN_NOTE'
    csonObj.folder = '94b8c2e8acf3448698d7'
    csonObj.tags = []
    csonObj.isStarred = false
    csonObj.createdAt = "2017-04-17T04:57:32.188Z"
    csonObj.updatedAt = "2017-04-17T04:57:45.464Z"
    csonObj.title = filename;
    filename = crypto.randomBytes(10).toString('hex');
    writeFile = csonDir + '/' + filename + '.cson';
    csonObj.content = fs.readFileSync(file).toString().trim();
    console.log(`SKIPPING: NEW NOTE: ${writeFile} - NOTE THIS IS BUGGY`);
    //TODO: Adding a txt note will not create id and cleanup. This causes multiple duplicates
    //fs.unlink(file)
    }
    }
    }

    noteCounter = () => {
    var csonCount = 0;
    var txtCount = 0;

    fs.readdirSync(csonDir).forEach(function(readfile) {
    if (path.extname(readfile) == '.cson') {
    csonCount++;
    }
    });
    fs.readdirSync(txtDir).forEach(function(readfile) {
    if (path.extname(readfile) == '.txt') {
    txtCount++;
    }
    });
    console.log(`boost/simple ${csonCount}/${txtCount}`);
    }

    var mode = process.argv[2];
    var txtDir = '/Users/esouke/Documents/Notes';
    var csonDir = '/Users/esouke/Boostnote/notes';
    if (mode == '-h' || mode == undefined) {
    console.log('This will syncronize Boostrap and Simplenote');
    console.log(`node ${process.argv[1]} simple-to-boost`);
    console.log(`node ${process.argv[1]} boost-to-simple`);
    console.log(`node ${process.argv[1]} sync-both`);
    console.log(`node ${process.argv[1]} duplicates`);
    console.log(`node ${process.argv[1]} counter`);
    } else if (mode == 'counter') {
    noteCounter();
    } else if (mode == 'duplicates') {
    duplicates();
    } else if (mode == 'simple-to-boost') {
    txtWatcherReady = false;
    var txtWatcher = chokidar.watch(txtDir).on('all', (event, path) => {
    if(txtWatcherReady) {
    similiar(path);
    noteCounter();
    console.log(`EVENT: txt-->cson ${event}`);
    }
    if(event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//,'');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = csonDir + '/' + filename + '.cson'
    if(fs.existsSync(filename)) {
    console.log(`DELETING: ${filename}`);
    fs.unlink(filename);
    }
    }
    });
    txtWatcher.on('ready', () => txtWatcherReady = true);
    } else if (mode == 'boost-to-simple') {
    csonWatcherReady = false;
    var csonWatcher = chokidar.watch(csonDir).on('all', (event, path) => {
    if(csonWatcherReady) {
    console.log(`EVENT: cson-->txt ${event}`);
    noteCounter();
    similiar(path);
    }
    if(event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//,'');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = txtDir + '/' + filename + '.txt'
    if(fs.existsSync(filename)) {
    console.log(`DELETING: ${fs.readFileSync(filename).toString().trim().split('\n')[0]}`);
    fs.unlink(filename);
    }
    }
    });
    csonWatcher.on('ready', () => csonWatcherReady = true);
    } else if (mode == 'sync-both') {

    //boost-to-simple
    csonWatcherReady = false;
    //var csonWatcher = chokidar.watch(csonDir).on('all', (event, path) => {
    var csonWatcher = chokidar.watch(csonDir, {
    alwaysState: true,
    awaitWriteFinish: {
    stabilityThreshold: 5000,
    pollInterval: 100
    },
    }).on('all', (event, path) => {
    if(csonWatcherReady) {
    console.log(`EVENT CSON-->TXT: ${event}`);
    noteCounter();
    similiar(path);
    }
    if(event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//,'');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = txtDir + '/' + filename + '.txt'
    if(fs.existsSync(filename)) {
    console.log(`DELETING: ${fs.readFileSync(filename).toString().trim().split('\n')[0]}`);
    fs.unlink(filename);
    }
    }
    });
    csonWatcher.on('ready', () => csonWatcherReady = true);
    //end boost-to-simple

    //simple-to-boost
    txtWatcherReady = false;
    var txtWatcher = chokidar.watch(txtDir, {
    alwaysState: true,
    awaitWriteFinish: {
    stabilityThreshold: 2000,
    pollInterval: 100
    },
    }).on('all', (event, path) => {
    if(txtWatcherReady) {
    similiar(path);
    noteCounter();
    console.log(`EVENT TXT-->CSON: ${event}`);
    }
    if(event != 'unlink') {
    processor(path)
    } else {
    filename = path.replace(/.*\//,'');
    filename = filename.replace(/\.[^/.]+$/, "");
    filename = csonDir + '/' + filename + '.cson'
    if(fs.existsSync(filename)) {
    console.log(`DELETING: ${filename}`);
    fs.unlink(filename);
    }
    }
    });
    txtWatcher.on('ready', () => txtWatcherReady = true);
    //end simple-to-boost
    //_proc = exec('/Applications/Boostnote.app/Contents/MacOS/Boostnote').unref()
    }

  15. Soukenka, Eric (ETW - FLEX) revised this gist Apr 25, 2017. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions test.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    hi
  16. toodooleedoo revised this gist Apr 20, 2017. 3 changed files with 104 additions and 94 deletions.
    6 changes: 5 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -14,4 +14,8 @@ This was created as i learned the hardway Boostrap maintains in memory reference
    notes will cause duplicate entries.

    I was unable to get a smart enough regex done after a good round of note cleanup so i leveraged a [String Similiary library](https://www.npmjs.com/package/string-similarity)
    Which turned out to be REALLY cool and I imagine I will use this for other projects.
    Which turned out to be REALLY cool and I imagine I will use this for other projects.

    # Instructions
    Read the comment block at the top for instructions but as quickstart modify read and write dir's, change id in skeleton.js and
    run. You will have to have nvALT setup as Plain Text Storage.
    182 changes: 89 additions & 93 deletions cleanup-duplicate-boostrap-entries.js
    Original file line number Diff line number Diff line change
    @@ -1,116 +1,112 @@
    /*********************************************************
    *
    * @TITLE: Boostrap Duplicate Records
    * @DESCRIPTION: Uses String Similiarity to compare note
    * titles and contents to determine similiar records.
    * Upon intelligently determining records which are safe
    * to delete automatically if entries are close it will
    * prompt you per entry if it is safe to delete.
    *
    * @INSTRUCTIONS: Change read and write directories and
    * read the code. Do some test runs while commenting
    * out the delete this was never fine tuned and meant
    * as a utility script for me to run once.
    * @TITLE: Simplenote and Boostrap Note Syncronization
    *
    * @DESCRIPTION: Supports two modes one which exports
    * Boostrap notes and exports them to nvAlt .txt files.
    * The other will export nvALT txt files to Boostrap .cson files
    *
    * @INSTRUCTIONS: Change readDir's and writeDir's at the top of
    * both functions appropriately then run with no parameters for
    * insrtructions.
    *
    * I recommend changing the folder id in skeleton.js. It may
    * even be required.
    *
    * @AUTHOR: Eric Soukenka
    * @DATE: April 20th 2017
    *
    * @NOTE: Created due to learning too late I had to restart
    * Boostrap after manually editing .cson files if I was
    * going to start using the application to modify entries.
    *
    * @NOTE: NOT YET POLISHED it was wrote during anger of
    * learning I had hundreds of duplicates and regex'ing toe
    * fix was too complicated.
    * @NOTE: nvALT must have syncronization setting set to Plain
    * Text files.
    *
    * @NOTE: Ensure you restart Boostrap after import to avoid
    * duplicate entries.
    *
    * @NOTE: NOT YET POLISHED meaning it has a lot of my specific
    * requirements and even the code is relatively embarrising :)
    *
    * !!! #################### !!!
    * ####### IMPORTANT ##### !!!
    * !!! Restart Boostrap after import!!!!!
    *
    ********************************************************* */
    var parseJson = require('parse-json');
    var fs = require('fs');
    var path = require('path');
    var CSON = require('cson');
    var crypto = require('crypto');
    var stringSimilarity = require('string-similarity');
    //var globals = require('globals');
    var _ = require('underscore');
    var query = require('cli-interact').getYesNo;


    var readDir = '/Users/esouke/Boostnote/notes';
    var writeDir = '/Users/esouke/Documents/Notes';
    var separator = '\n=========================================================\n'
    var cleanupFiles = [];
    var maybeCleanupFiles = [];

    files = fs.readdirSync(readDir);
    filelist = [];
    files.forEach(readfile => {
    try {
    // TXT --> CSON
    convertCsonToTxt = () => {
    var skeleton = CSON.parseCSONFile('skeleton.cson');
    var readDir = '/Users/esouke/Boostnote/notes';
    var writeDir = '/Users/esouke/Documents/Notes';
    var separator = '\n=========================================================\n'

    fs.readdirSync(writeDir).forEach(function(file) {
    if (path.extname(file) == '.txt') {
    fs.unlink(writeDir + '/' + file)
    }
    })
    files = fs.readdirSync(readDir);
    filelist = [];
    files.forEach(function(readfile) {
    console.log(readfile)
    if (path.extname(readfile) == '.cson') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var obj = CSON.parse(txt);
    if (obj.title) {
    files.forEach(readfile2 => {
    var answer = false;
    var txt2 = fs.readFileSync(readDir + '/' + readfile2).toString();
    var obj2 = CSON.parse(txt + txt2)
    if (obj2.title) {
    x = stringSimilarity.compareTwoStrings(obj.title, obj2.title);
    if (x > 0.6 && x != 1) {
    y = stringSimilarity.compareTwoStrings(obj.content, obj2.content);
    if (y > 0.9) {
    console.log(`GOING: --------------- ${x} - ${y}`)
    console.log(`OLD: ${obj.title}`);
    console.log(`NEW: ${obj2.title}`);
    console.log(`KEE: ${readDir}/${readfile}`)
    console.log(`DEL: ${readDir}/${readfile2}`)
    cleanupFiles.push(readDir + '/' + readfile2);
    } else {
    if (y > 0.5) {
    console.log(`ASKING: ----------- ${x} - ${y}`)
    console.log(`OLD: ${obj.title}`);
    console.log(`NEW: ${obj2.title}`);
    console.log(`KEE: ${readDir}/${readfile}`)
    console.log(`DEL: ${readDir}/${readfile2}`)
    maybeCleanupFiles.push(readDir + '/' + readfile2);
    } else {
    console.log(`SKIPPING: ${y} ${obj.title} - ${obj2.title} - ${x}`)
    }
    }
    }
    }
    })
    }
    var writeFile = writeDir + '/' + obj.title + '.txt';
    var writeBody = obj.content.replace(obj.title, '').replace(/\s+.*====/, '').replace(obj.title, '').replace(/^\s+|\s+$/g, '');
    fs.writeFileSync(writeFile, obj.title + separator + writeBody);
    }
    } catch (e) {
    console.log(`ERROR: ${readfile}`);
    }
    })
    for (index = 0; index < cleanupFiles.length; ++index) {
    console.log(`Deleting: ${cleanupFiles[index]}`);
    try {
    fs.unlinkSync(cleanupFiles[index]);
    } catch (e) {
    console.log(`ERROR deleting: ${cleanupFiles[index]}`);
    }
    })
    console.log("IMPORTANT! Restart Boostrap if it is running!!!");
    }
    for (index = 0; index < maybeCleanupFiles.length; ++index) {
    console.log("--------------------------------------");
    try {
    txt = fs.readFileSync(maybeCleanupFiles[index]).toString();
    obj = CSON.parse(txt);
    console.log(`Info: ${obj.title}`)
    answer = query('delete');
    if (answer) {
    console.log(`Deleting: ${maybeCleanupFiles[index]}`);
    try {
    fs.unlinkSync(cleanupFiles[index]);
    } catch (e) {
    console.log(`ERROR deleting: ${cleanupFiles[index]}`);
    }
    } else {
    console.log(`Skipping: ${maybeCleanupFiles[index]}`);

    // CSON --> TXT
    convertTxtToCson = () => {
    var skeleton = CSON.parseCSONFile('skeleton.cson');
    var readDir = '/Users/esouke/Documents/Notes';
    var writeDir = '/Users/esouke/Boostnote/notes';
    var separator = '\n=========================================================\n'

    fs.readdirSync(writeDir).forEach(function(file) {
    if (path.extname(file) == '.cson') {
    fs.unlink(writeDir + '/' + file)
    }
    })
    files = fs.readdirSync(readDir);
    filelist = [];
    files.forEach(function(readfile) {
    if (path.extname(readfile) == '.txt') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var writeFile = writeDir + '/' + crypto.randomBytes(10).toString('hex') + '.cson';
    readfile = readfile.replace(/\.[^/.]+$/, "");

    skeleton.title = readfile;
    var writeBody = txt.replace(readfile, '').replace(/\s+.*====/, '').replace(readfile, '').replace(/^\s+|\s+$/g, '')

    skeleton.content = skeleton.title + separator + writeBody;

    fs.writeFileSync(writeFile, CSON.stringify(skeleton));

    skeleton.title = 'unknown';
    skeleton.content = 'unknown';
    }
    } catch (e) {
    console.log('error');
    }
    });
    }

    var mode = process.argv[2];
    if(mode == '-h' || mode == undefined) {
    console.log('This will syncronize Boostrap and Simplenote');
    console.log(`node ${process.argv[1]} simple-to-boost`);
    console.log(`node ${process.argv[1]} boost-to-simple`);
    } else if (mode == 'simple-to-boost') {
    console.log('Syncing Simplenote to Boostrap');
    convertTxtToCson();
    } else if (mode == 'boost-to-simple') {
    console.log('Syncing Boostrap to Simplenote');
    convertCsonToTxt();
    }
    10 changes: 10 additions & 0 deletions skeleton.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    type: "MARKDOWN_NOTE"
    folder: "94b8c2e8acf3448698d7"
    title: "unknown"
    content: '''
    unknown
    '''
    tags: []
    isStarred: false
    createdAt: "2017-04-17T04:57:32.188Z"
    updatedAt: "2017-04-17T04:57:45.464Z"
  17. toodooleedoo created this gist Apr 20, 2017.
    17 changes: 17 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    # Boostrap and Simplenote Syncronization tool.
    While wanting to switch from a Simplenote workflow and using nvALT to Boostrap I realized a manually import was going to be too
    complicated so i started a utility script.

    Then i realized I could use this tool to continue parts of my note taking workflow in Simplenote including Cloud Syncronization,
    multiple device editing and there Android app which Boostrap still lacks.

    # Warning
    This was a utility script so it is not yet very polished. It also does not keep tags from either app or modified time. I recommend
    understanding the script a bit and doing some tests. (See next)

    # Boostrap Duplicate cleanup utility script is also included.
    This was created as i learned the hardway Boostrap maintains in memory reference to it's persistence and after migrations editing
    notes will cause duplicate entries.

    I was unable to get a smart enough regex done after a good round of note cleanup so i leveraged a [String Similiary library](https://www.npmjs.com/package/string-similarity)
    Which turned out to be REALLY cool and I imagine I will use this for other projects.
    116 changes: 116 additions & 0 deletions cleanup-duplicate-boostrap-entries.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,116 @@
    /*********************************************************
    *
    * @TITLE: Boostrap Duplicate Records
    * @DESCRIPTION: Uses String Similiarity to compare note
    * titles and contents to determine similiar records.
    * Upon intelligently determining records which are safe
    * to delete automatically if entries are close it will
    * prompt you per entry if it is safe to delete.
    *
    * @INSTRUCTIONS: Change read and write directories and
    * read the code. Do some test runs while commenting
    * out the delete this was never fine tuned and meant
    * as a utility script for me to run once.
    *
    * @AUTHOR: Eric Soukenka
    * @DATE: April 20th 2017
    *
    * @NOTE: Created due to learning too late I had to restart
    * Boostrap after manually editing .cson files if I was
    * going to start using the application to modify entries.
    *
    * @NOTE: NOT YET POLISHED it was wrote during anger of
    * learning I had hundreds of duplicates and regex'ing toe
    * fix was too complicated.
    *
    ********************************************************* */
    var parseJson = require('parse-json');
    var fs = require('fs');
    var path = require('path');
    var CSON = require('cson');
    var crypto = require('crypto');
    var stringSimilarity = require('string-similarity');
    //var globals = require('globals');
    var _ = require('underscore');
    var query = require('cli-interact').getYesNo;


    var readDir = '/Users/esouke/Boostnote/notes';
    var writeDir = '/Users/esouke/Documents/Notes';
    var separator = '\n=========================================================\n'
    var cleanupFiles = [];
    var maybeCleanupFiles = [];

    files = fs.readdirSync(readDir);
    filelist = [];
    files.forEach(readfile => {
    try {
    if (path.extname(readfile) == '.cson') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var obj = CSON.parse(txt);
    if (obj.title) {
    files.forEach(readfile2 => {
    var answer = false;
    var txt2 = fs.readFileSync(readDir + '/' + readfile2).toString();
    var obj2 = CSON.parse(txt + txt2)
    if (obj2.title) {
    x = stringSimilarity.compareTwoStrings(obj.title, obj2.title);
    if (x > 0.6 && x != 1) {
    y = stringSimilarity.compareTwoStrings(obj.content, obj2.content);
    if (y > 0.9) {
    console.log(`GOING: --------------- ${x} - ${y}`)
    console.log(`OLD: ${obj.title}`);
    console.log(`NEW: ${obj2.title}`);
    console.log(`KEE: ${readDir}/${readfile}`)
    console.log(`DEL: ${readDir}/${readfile2}`)
    cleanupFiles.push(readDir + '/' + readfile2);
    } else {
    if (y > 0.5) {
    console.log(`ASKING: ----------- ${x} - ${y}`)
    console.log(`OLD: ${obj.title}`);
    console.log(`NEW: ${obj2.title}`);
    console.log(`KEE: ${readDir}/${readfile}`)
    console.log(`DEL: ${readDir}/${readfile2}`)
    maybeCleanupFiles.push(readDir + '/' + readfile2);
    } else {
    console.log(`SKIPPING: ${y} ${obj.title} - ${obj2.title} - ${x}`)
    }
    }
    }
    }
    })
    }
    }
    } catch (e) {
    console.log(`ERROR: ${readfile}`);
    }
    })
    for (index = 0; index < cleanupFiles.length; ++index) {
    console.log(`Deleting: ${cleanupFiles[index]}`);
    try {
    fs.unlinkSync(cleanupFiles[index]);
    } catch (e) {
    console.log(`ERROR deleting: ${cleanupFiles[index]}`);
    }
    }
    for (index = 0; index < maybeCleanupFiles.length; ++index) {
    console.log("--------------------------------------");
    try {
    txt = fs.readFileSync(maybeCleanupFiles[index]).toString();
    obj = CSON.parse(txt);
    console.log(`Info: ${obj.title}`)
    answer = query('delete');
    if (answer) {
    console.log(`Deleting: ${maybeCleanupFiles[index]}`);
    try {
    fs.unlinkSync(cleanupFiles[index]);
    } catch (e) {
    console.log(`ERROR deleting: ${cleanupFiles[index]}`);
    }
    } else {
    console.log(`Skipping: ${maybeCleanupFiles[index]}`);
    }
    } catch (e) {
    console.log('error');
    }
    }
    109 changes: 109 additions & 0 deletions simple-boostrap-sync.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,109 @@
    /*********************************************************
    *
    * @TITLE: Simplenote and Boostrap Note Syncronization
    *
    * @DESCRIPTION: Supports two modes one which exports
    * Boostrap notes and exports them to nvAlt .txt files.
    * The other will export nvALT txt files to Boostrap .cson files
    *
    * @INSTRUCTIONS: Change readDir's and writeDir's at the top of
    * both functions appropriately then run with no parameters for
    * insrtructions.
    *
    * @AUTHOR: Eric Soukenka
    * @DATE: April 20th 2017
    *
    * @NOTE: nvALT must have syncronization setting set to Plain
    * Text files.
    *
    * @NOTE: Ensure you restart Boostrap after import to avoid
    * duplicate entries.
    *
    * @NOTE: NOT YET POLISHED meaning it has a lot of my specific
    * requirements and even the code is relatively embarrising :)
    *
    * !!! #################### !!!
    * ####### IMPORTANT ##### !!!
    * !!! Restart Boostrap after import!!!!!
    *
    ********************************************************* */
    var parseJson = require('parse-json');
    var fs = require('fs');
    var path = require('path');
    var CSON = require('cson');
    var crypto = require('crypto');



    // TXT --> CSON
    convertCsonToTxt = () => {
    var skeleton = CSON.parseCSONFile('skeleton.cson');
    var readDir = '/Users/esouke/Boostnote/notes';
    var writeDir = '/Users/esouke/Documents/Notes';
    var separator = '\n=========================================================\n'

    fs.readdirSync(writeDir).forEach(function(file) {
    if (path.extname(file) == '.txt') {
    fs.unlink(writeDir + '/' + file)
    }
    })
    files = fs.readdirSync(readDir);
    filelist = [];
    files.forEach(function(readfile) {
    console.log(readfile)
    if (path.extname(readfile) == '.cson') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var obj = CSON.parse(txt);
    var writeFile = writeDir + '/' + obj.title + '.txt';
    var writeBody = obj.content.replace(obj.title, '').replace(/\s+.*====/, '').replace(obj.title, '').replace(/^\s+|\s+$/g, '');
    fs.writeFileSync(writeFile, obj.title + separator + writeBody);
    }
    })
    console.log("IMPORTANT! Restart Boostrap if it is running!!!");
    }

    // CSON --> TXT
    convertTxtToCson = () => {
    var skeleton = CSON.parseCSONFile('skeleton.cson');
    var readDir = '/Users/esouke/Documents/Notes';
    var writeDir = '/Users/esouke/Boostnote/notes';
    var separator = '\n=========================================================\n'

    fs.readdirSync(writeDir).forEach(function(file) {
    if (path.extname(file) == '.cson') {
    fs.unlink(writeDir + '/' + file)
    }
    })
    files = fs.readdirSync(readDir);
    filelist = [];
    files.forEach(function(readfile) {
    if (path.extname(readfile) == '.txt') {
    var txt = fs.readFileSync(readDir + '/' + readfile).toString();
    var writeFile = writeDir + '/' + crypto.randomBytes(10).toString('hex') + '.cson';
    readfile = readfile.replace(/\.[^/.]+$/, "");

    skeleton.title = readfile;
    var writeBody = txt.replace(readfile, '').replace(/\s+.*====/, '').replace(readfile, '').replace(/^\s+|\s+$/g, '')

    skeleton.content = skeleton.title + separator + writeBody;

    fs.writeFileSync(writeFile, CSON.stringify(skeleton));

    skeleton.title = 'unknown';
    skeleton.content = 'unknown';
    }
    });
    }

    var mode = process.argv[2];
    if(mode == '-h' || mode == undefined) {
    console.log('This will syncronize Boostrap and Simplenote');
    console.log(`node ${process.argv[1]} simple-to-boost`);
    console.log(`node ${process.argv[1]} boost-to-simple`);
    } else if (mode == 'simple-to-boost') {
    console.log('Syncing Simplenote to Boostrap');
    convertTxtToCson();
    } else if (mode == 'boost-to-simple') {
    console.log('Syncing Boostrap to Simplenote');
    convertCsonToTxt();
    }