Skip to content

Instantly share code, notes, and snippets.

@Fluf22
Last active January 5, 2024 08:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Fluf22/1f896f84ac9eb6a319b733189a757de2 to your computer and use it in GitHub Desktop.
Save Fluf22/1f896f84ac9eb6a319b733189a757de2 to your computer and use it in GitHub Desktop.
Transfer notes from unzipped Google Takeout Keep folder to Nextcloud folder
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const fs = require("fs");
const https = require("https");
// How to use this script: execute `node send-notes-to-nextcloud.js` to see this message formatted
const printUsage = () => {
console.log("Usage:\nnode send-notes-to-nextcloud.js </e/ email> <password> [--replace=[true|false] --join-labels=[true|false] | --check=true]");
return;
};
// Get username and password from arguments, and store basic HTTP auth
const username = process.argv[2];
const password = process.argv[3];
const auth = `${username}:${password}`;
const url = `https://ecloud.global/index.php/apps/notes/api/v0.2/notes`; // /e/ Cloud API URL
const currDir = process.cwd(); // Get current directory path
const gkNotes = fs.readdirSync(currDir).filter(gkNote => gkNote.includes(".json")); // Get list of Google Keep notes
const checkOnly = process.argv.length === 5 && process.argv[4].includes("--check") && process.argv[4].split("=")[1] === "true"; // Is check only mode enabled
if (checkOnly) {
// Get all your Nextcloud notes
https.get(url, { auth }, (getResp) => {
let dataGet = "";
// A chunk of data has been recieved.
getResp.on("data", (chunk) => {
dataGet += chunk;
});
// The whole response has been received. Process the result.
getResp.on("end", () => {
// Compare the quantity of notes in your Google Keep folder and in your Nextcloud notes folder in the /e/ Cloud
console.log(`You have ${JSON.parse(dataGet).length} notes in your /e/ Cloud account, and ${gkNotes.length} notes in you Google Keep folder.`);
});
});
} else if (process.argv.length === 5 || process.argv.length === 6) {
const enableReplace = process.argv[4].includes("--replace") && process.argv[4].split("=")[1] === "true"; // Should I replace Notes already in Nextcloud
const joinLabels = process.argv[5].includes("--join-labels") && process.argv[5].split("=")[1] === "true"; // How to deal with multiple Google Keep categories
let failedTransfer = 0; // Track upload failures
// GET all your existing Nextcloud notes
https.get(url, { auth }, (getResp) => {
let dataGet = "";
// A chunk of data has been recieved.
getResp.on("data", (chunk) => {
dataGet += chunk;
});
// The whole response has been received. Process the result.
getResp.on("end", () => {
const ncNotes = JSON.parse(dataGet); // Parse the notes in a JSON format
for (let i = 0; i < gkNotes.length; ++i) {
// Initiate a request every 2 seconds to deal with /e/ Cloud API limitation
setTimeout(() => {
const gkNoteStr = fs.readFileSync(`${currDir}/${gkNotes[i]}`, "utf-8"); // Read the content of a Google Keep note
const gkNote = JSON.parse(gkNoteStr); // Parse it in a JSON format
// Translate the Google Keep note content in markdown to have compatible lists
const newNoteContent = Object.keys(gkNote).includes("textContent") ? gkNote.textContent : gkNote.listContent.map(item => (`- [${item.isChecked ? "x" : " "}] ${item.text}`)).join("\n");
// Create the note title
const newNoteTitle = gkNote.title !== "" ? gkNote.title : newNoteContent.split(" ").slice(0, 3).join(" ");
// Create the new note object
const newNote = {
title: newNoteTitle,
content: newNoteTitle + "\n" + newNoteContent,
category: Object.keys(gkNote).includes("labels") ? (joinLabels ? gkNote.labels.map(item => item.name).join("/") : gkNote.labels[0].name) : "",
favorite: gkNote.isPinned
};
// Store it in a string to be able to send it in a POST request body
const newNoteStr = JSON.stringify(newNote);
// Check if the note already exists in Nextcloud
const existingNcNote = ncNotes.find(ncNote => ncNote.title === newNoteTitle);
// If the --replace option has been set to true, update the note instead of creating a new one
if (enableReplace && existingNcNote !== undefined && existingNcNote.id !== undefined) {
const putReq = https.request(`${url}/${existingNcNote.id}`, {
method: "PUT",
auth,
data: JSON.stringify(newNote),
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(newNoteStr)
}
}, (putResp) => {
let putData = "";
// A chunk of data has been recieved.
putResp.on("data", (chunk) => {
putData += chunk;
});
// The whole response has been received. Process the result.
putResp.on("end", () => {
try {
console.log("Replaced note: ", JSON.parse(putData).title);
} catch {
// Watch for failed transfer
console.log(`Something's fishy (failed transfer count: ${failedTransfer})`);
failedTransfer = failedTransfer + 1;
}
});
}).on("error", (err) => {
console.log("Error during PUT request: " + err.message);
});
putReq.write(newNoteStr);
putReq.end();
} else { // ...otherwise, create a new note on Nextcloud
const postReq = https.request(url, {
method: "POST",
auth,
data: JSON.stringify(newNote),
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(newNoteStr)
}
}, (postResp) => {
let postData = "";
// A chunk of data has been recieved.
postResp.on("data", (chunk) => {
postData += chunk;
});
// The whole response has been received. Process the result.
postResp.on("end", () => {
try {
console.log("Created note: ", JSON.parse(postData).title)
} catch {
// Watch for failed transfer
console.log(`Something's fishy (failed transfer count: ${failedTransfer})`);
failedTransfer = failedTransfer + 1;
}
});
}).on("error", (err) => {
console.log("Error during POST request: " + err.message);
});
postReq.write(newNoteStr);
postReq.end();
}
}, 2000 * i);
}
});
}).on("error", (err) => {
// Watch for request failure
console.log("Error during GET request: " + err.message);
});
} else {
printUsage();
return;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment