commit 4646cecd9266f91e41edacff64414bb668fd66ab Author: quenousimporte Date: Wed Apr 10 15:17:04 2024 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a0623bd --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +md2imap/mbox +md2imap/*.imap +md2imap/input/* diff --git a/cryptee-to-markdown-deprecated/README.md b/cryptee-to-markdown-deprecated/README.md new file mode 100644 index 0000000..92a418a --- /dev/null +++ b/cryptee-to-markdown-deprecated/README.md @@ -0,0 +1,8 @@ +# cryptee-to-markdown +A simple js script to convert your .uecd [Cryptee](https://github.com/cryptee) documents to markdown. + +**Deprecated**: see delta2md instead + +Usage: +* Download .uecd files from the crypt.ee app. +* call `node node-ui.js ` or open `web-ui.html` in browser. diff --git a/cryptee-to-markdown-deprecated/cryptee-to-markdown.js b/cryptee-to-markdown-deprecated/cryptee-to-markdown.js new file mode 100644 index 0000000..4febd54 --- /dev/null +++ b/cryptee-to-markdown-deprecated/cryptee-to-markdown.js @@ -0,0 +1,117 @@ +function getMarkDown(jsonInput) +{ + function startLastWith(text) + { + temp = result.split('\n'); + temp[temp.length - 1] = text + temp[temp.length - 1]; + result = temp.join('\n'); + } + + function dressUp(text, cloth) + { + return cloth + text + cloth; + } + + function createCodeBlocks() + { + temp = result.split('\n'); + var code = false; + for (var i in temp) + { + if (temp[i].startsWith("~~~")) + { + if (!code) + { + code = true; + } + else + { + temp[i] = temp[i].substr(3); + } + } + else if (code) + { + temp[i] += "~~~"; + code = false; + } + } + result = temp.join('\n'); + } + + var data = JSON.parse(jsonInput); + var result = ""; + var code = false; + + for (var i in data.ops) + { + var elt = data.ops[i]; + var text = elt.insert; + + if (text.image) + { + var alt = ""; + if (elt.attributes && elt.attributes.alt) alt = elt.attributes.alt; + text = "![" + alt + "](" + text.image + ")"; + } + if (text.divider) + { + text = '____\n'; + } + + if (elt.attributes) + { + var attr = elt.attributes; + if (attr.tag) + { + text = "#" + text; + } + if (attr.header) + { + startLastWith("#".repeat(attr.header) + " " ); + } + if (attr.list == "bullet") + { + startLastWith("* "); + } + if (attr.list == "ordered") + { + startLastWith("1. "); + } + if (attr.list == "unchecked") + { + startLastWith("- [ ] "); + } + if (attr.list == "checked") + { + startLastWith("- [x] "); + } + if (attr.italic) + { + text = dressUp(text, "*"); + } + if (attr.bold) + { + text = dressUp(text, "**"); + } + if (attr["code-block"]) + { + startLastWith("~~~"); + } + if (attr.blockquote) + { + startLastWith("> "); + } + } + result += text; + } + + // post processing + createCodeBlocks(); + + return result; +} + +if (typeof module !== "undefined") +{ + module.exports.convert = getMarkDown; +} diff --git a/cryptee-to-markdown-deprecated/node-ui.js b/cryptee-to-markdown-deprecated/node-ui.js new file mode 100644 index 0000000..9bcfa0f --- /dev/null +++ b/cryptee-to-markdown-deprecated/node-ui.js @@ -0,0 +1,28 @@ +let getMarkDown = require("./cryptee-to-markdown.js"); + + +var fs = require('fs'); +var path = require('path'); + +const folder = process.argv[2]; +const files = fs.readdirSync(folder); + +for (var i in files) +{ + const file = files[i]; + + if (file.indexOf('uecd') === -1) continue; + console.log(file); + + var data = fs.readFileSync( path.join(folder, file)); + + var md = getMarkDown.convert(data); + + fs.writeFile(path.join(folder, file.replace(".uecd", ".md")), md, function (err) + { + if (err) + { + throw err; + } + }); +} diff --git a/cryptee-to-markdown-deprecated/web-ui.html b/cryptee-to-markdown-deprecated/web-ui.html new file mode 100644 index 0000000..aed37c9 --- /dev/null +++ b/cryptee-to-markdown-deprecated/web-ui.html @@ -0,0 +1,19 @@ + + + + + + + + +
+ + diff --git a/delta2md/delta2md.js b/delta2md/delta2md.js new file mode 100644 index 0000000..06f2426 --- /dev/null +++ b/delta2md/delta2md.js @@ -0,0 +1,231 @@ +var fs = require('fs'); +var path = require('path'); + +// parameters +var inputFolder = "notes"; +var outputFolder = "result"; +var includeheaders = true; + +var files = fs.readdirSync(inputFolder); + +for (var i in files) +{ + var file = files[i]; + if (file.indexOf(".uecd") === -1) + { + fs.copyFileSync(path.join(inputFolder, file), path.join(outputFolder, file)); + } + else + { + + var data = fs.readFileSync(path.join(inputFolder, file), 'utf8'); + var md = mdify(JSON.parse(data), file); + fs.writeFileSync(path.join(outputFolder, file).replace(".uecd", ".md"), md); + } +} + +function mdify(data, file) +{ + var result = ""; + var tags = []; + + for (var i in data.ops) + { + var op = data.ops[i]; + + if (op.insert.image) + { + // inline base64 + //result += "![](" + op.insert.image + ")"; + + //external + var alt = op.attributes && op.attributes.alt ? op.attributes.alt : ""; + if (op.insert.image.indexOf("data:image") !== -1) + { + var buffer = Buffer.from(op.insert.image.replace(/^data:image\/jpeg;base64,/, ""), "base64"); + var imageFileName = file.replace(".uecd", i + ".jpeg"); + fs.writeFileSync(path.join(outputFolder, imageFileName), buffer); + result += "![" + alt + "](" + imageFileName + ")"; + } + else + { + result += "![" + alt + "](" + op.insert.image + ")"; + } + } + else if (!op.attributes) + { + if (op.insert.divider) + { + result += "---\n"; + } + else + { + result += op.insert; + } + } + else if (op.attributes.italic) + { + result += "*" + op.insert + "*"; + } + else if (op.attributes.bold) + { + result += "**" + op.insert + "**"; + } + else if (op.attributes.underline) + { + result += "__" + op.insert + "__"; + } + else if (op.attributes.strike) + { + result += "~~" + op.insert + "~~"; + } + else if (op.attributes.tag) + { + //result += "#" + op.insert; + tags.push(op.insert); + } + else if (op.attributes.header) + { + var result = result.split("\n"); + result[result.length - 1] = "#".repeat(op.attributes.header) + " " + result[result.length - 1]; + result = result.join("\n"); + result += op.insert; + } + else if (op.attributes.link) + { + if (op.insert == op.attributes.link) + { + result += op.insert; + } + else + { + result += "[" + op.insert + "](" + op.attributes.link + ")"; + } + } + else if (op.attributes.code) + { + result += "`" + op.insert + "`"; + } + else if (op.attributes.list == "bullet") + { + var result = result.split("\n"); + result[result.length - 1] = "\t".repeat(op.attributes.indent) + "* " + result[result.length - 1]; + result = result.join("\n"); + result += op.insert; + } + else if (op.attributes.list == "unchecked") + { + var result = result.split("\n"); + result[result.length - 1] = "\t".repeat(op.attributes.indent) + "[ ] " + result[result.length - 1]; + result = result.join("\n"); + result += op.insert; + } + else if (op.attributes.list == "checked") + { + var result = result.split("\n"); + result[result.length - 1] = "\t".repeat(op.attributes.indent) + "[x] " + result[result.length - 1]; + result = result.join("\n"); + result += op.insert; + } + else if (op.attributes.list == "ordered") + { + var result = result.split("\n"); + result[result.length - 1] = "\t".repeat(op.attributes.indent) + "1. " + result[result.length - 1]; + result = result.join("\n"); + result += op.insert; + } + else if (op.attributes.file) + { + result += "[[" + op.attributes.file.filetitle + "]]"; + + // traditional link + //result += "[" + op.attributes.file.filetitle + "](" + op.attributes.file.filetitle + ".md)"; + } + else if (op.attributes["code-block"]) + { + var result = result.split("\n"); + result[result.length - 1] = "```" + result[result.length - 1] + "```"; + result = result.join("\n"); + result += op.insert.replace(/\n\n/g, "\n``````\n");; + } + else if (op.attributes.blockquote) + { + var result = result.split("\n"); + result[result.length - 1] = "> " + result[result.length - 1]; + result = result.join("\n"); + result += op.insert.replace(/\n\n/g, "\n> \n"); + } + else + { + result += op.insert; + } + } + + // Post processing + + // remove nbsp, indent and trailing + result = result.replace(/ /g, " "); + result = result.replace(/\n[ ]*/g, "\n"); + result = result.replace(/[ ]*\n/g, "\n"); + + // insert line endings + result = result.split('\n'); + var blockMarkers = ["* ", "1. ", "> ", "```", "["]; + for (var i = 0; i < result.length; i++) + { + var inBlock = false; + for (var j in blockMarkers) + { + var block = blockMarkers[j]; + if (result[i].replace(/\t/g, "").startsWith(block) && result[i + 1].replace(/\t/g, "").startsWith(block)) + { + inBlock = true; + break; + } + } + if (!inBlock && Boolean(result[i + 1])) + { + result.splice(i + 1, 0, ""); + i++; + } + } + result = result.join("\n"); + + // merge code blocks + result = result.replace(/```\n```/g, "\n"); + result = result.replace(/```/g, "\n```\n"); + + // escape ~ in unix path + result = result.replace(/~\//g, "\\~/"); + + // headers + if (includeheaders) + { + var headers = + { + title: file.replace(".uecd", ""), + tags: tags.join(", ") + }; + + if (/[.|mars|mai|juin|août] 202\d /.test(file)) + { + var index = file.indexOf("202"); + headers.title = headers.title.substring(index + 5); + headers.date = file.substring(0, index + 4); + } + + var headersmd = "---\n"; + for (var i in headers) + { + headersmd += i + ": " + headers[i] + "\n"; + } + headersmd += "---"; + + if (result[0] != "\n") headersmd += "\n"; + if (result[1] != "\n") headersmd += "\n"; + + result = headersmd + result; + } + + return result; +} diff --git a/export-turtl-notes/README.md b/export-turtl-notes/README.md new file mode 100644 index 0000000..8f3fd2a --- /dev/null +++ b/export-turtl-notes/README.md @@ -0,0 +1,12 @@ +# export-turtl-notes +A simple python script to export your [turtl](https://github.com/turtl) notes. + +What the script does: +* Export your notes as markdown files. +* Photos and files are also exported (without the associated text). +* A new folder is created for each board, containg the files. +* Tags are lost. + +Usage: +* Export your turtl profile from the turtl app +* launch `python export-turtl-notes.py` next to turtl-backup.json diff --git a/export-turtl-notes/export-turtl-notes.py b/export-turtl-notes/export-turtl-notes.py new file mode 100644 index 0000000..fc0366d --- /dev/null +++ b/export-turtl-notes/export-turtl-notes.py @@ -0,0 +1,62 @@ +import base64 +import json +import os + +def findboard(id): + for board in data['boards']: + if id == board['id']: + return board['title'] + return '' + +def clean(text): + return "".join(c if c.isalnum() else " " for c in text) + + +f = open('turtl-backup.json', encoding='utf-8') +data = json.load(f) + +if not os.path.isdir('turtl'): + os.mkdir('turtl') + +for folder in data['boards']: + path = os.path.join('turtl', folder['title']) + if not os.path.isdir(path): + os.mkdir(path) + +untitledcounter = 1 + +for note in data['notes']: + + type = note['type'] + title = note['title'] + if title == '': + title = 'untitled' + str(untitledcounter) + untitledcounter += 1 + + print(title) + + if type == 'text': + filename = clean(title) + '.md' + with open(os.path.join('turtl', findboard(note['board_id']), filename), 'wb') as n: + n.write(note['text'].encode('utf-8')) + n.close() + + if type == 'image' or type == 'file': + file = note['file'] + filename = file['name'] + for fileref in data['files']: + if fileref['id'] == note['id']: + b64 = fileref['data'] + with open(os.path.join('turtl', findboard(note['board_id']), filename), 'wb') as n: + n.write(base64.decodebytes(b64.encode('utf-8'))) + n.close() + + if type == 'link': + url = note['url'] + text = url + '\r\n' + note['text'] + filename = clean(title) + '.md' + with open(os.path.join('turtl', findboard(note['board_id']), filename), 'wb') as n: + n.write(text.encode('utf-8')) + n.close() + +f.close() \ No newline at end of file diff --git a/export-wm3/README.md b/export-wm3/README.md new file mode 100644 index 0000000..75b33ee --- /dev/null +++ b/export-wm3/README.md @@ -0,0 +1,2 @@ +# export-wm3 +A js script to export your [writemonkey3](https://writemonkey.com/wm3/) documents as flat markdown files. diff --git a/export-wm3/export-wm3.js b/export-wm3/export-wm3.js new file mode 100644 index 0000000..5f109f4 --- /dev/null +++ b/export-wm3/export-wm3.js @@ -0,0 +1,26 @@ +var fs = require('fs') + +var filePath = process.argv[2]; + +var fileContent = fs.readFileSync(filePath, 'utf8'); +var data = fileContent.split("\n"); +var documents = {}; +for (var i in data) +{ + if (!data[i]) continue; + + var file = JSON.parse(data[i]); + if (file.nam && file.txt && !file.del) + { + if (!documents[file.nam] || documents[file.nam].dtm < file.dtm) + { + documents[file.nam] = file; + } + } +} + +for (var i in documents) +{ + console.log(documents[i].nam); + fs.writeFileSync(documents[i].nam + '.md', documents[i].txt, 'utf8'); +} diff --git a/imap2md/export-imap-notes.py b/imap2md/export-imap-notes.py new file mode 100644 index 0000000..33f6e07 --- /dev/null +++ b/imap2md/export-imap-notes.py @@ -0,0 +1,71 @@ +from markdownify import markdownify +import imaplib +import email +from email.header import decode_header +import os + +username = "" +password = "" +imapserver = "" + +if not os.path.isdir('notes'): + os.mkdir('notes') + +def clean(text): + return "".join(c if c.isalnum() else "_" for c in text) + +# number of top emails to fetch +N = 200 + +imap = imaplib.IMAP4_SSL(imapserver) +imap.login(username, password) + +status, messages = imap.select("Notes") + +messages = int(messages[0]) + +for i in range(messages, messages-N, -1): + res, msg = imap.fetch(str(i), "(RFC822)") + for response in msg: + if isinstance(response, tuple): + msg = email.message_from_bytes(response[1]) + subject, encoding = decode_header(msg["Subject"])[0] + if isinstance(subject, bytes): + subject = subject.decode(encoding) + + From, encoding = decode_header(msg.get("From"))[0] + if isinstance(From, bytes): + From = From.decode(encoding) + + print(subject) + filepath = clean(subject) + '.md' + filepath = os.path.join('notes', filepath) + + if msg.is_multipart(): + for part in msg.walk(): + content_type = part.get_content_type() + content_disposition = str(part.get("Content-Disposition")) + try: + body = part.get_payload(decode=True).decode() + except: + pass + + if content_type == "text/plain" and "attachment" not in content_disposition: + open(filepath, "w").write(body) + elif "attachment" in content_disposition: + print('/!\\ attachment') + else: + content_type = msg.get_content_type() + body = msg.get_payload(decode=True).decode() + if content_type == "text/plain": + open(filepath, "w").write(body) + + if content_type == "text/html": + md = markdownify(body) + if md[:4] == 'html': + md = md[4:] + + open(filepath, "wb").write(md.encode('utf8')) + +imap.close() +imap.logout() diff --git a/md2imap/imap-note-header b/md2imap/imap-note-header new file mode 100644 index 0000000..73428e1 --- /dev/null +++ b/md2imap/imap-note-header @@ -0,0 +1,12 @@ +From email Wed Apr 10 08:45:21 2024 +From: name +MIME-Version: 1.0 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/plain; charset="utf-8" +Date: Wed, 10 Apr 2024 02:45:21 -0400 +Reply-To: name +X-Uniform-Type-Identifier: com.apple.mail-note +Subject: title +X-Universally-Unique-Identifier: uid +Status: RO + diff --git a/md2imap/md2imap.sh b/md2imap/md2imap.sh new file mode 100644 index 0000000..905bdd2 --- /dev/null +++ b/md2imap/md2imap.sh @@ -0,0 +1,18 @@ +rm mbox +for f in input/*.md +do + f=${f##*/} + title=${f%.md} + + uid=$(cat /proc/sys/kernel/random/uuid) + cp imap-note-header "$title".imap + sed -i "s/uid/${uid}/" "$title".imap + sed -i "s/title/${title}/" "$title".imap + sed -i "s/name/$1/" "$title".imap + sed -i "s/email/$2/" "$title".imap + + cat "input/$f" >> "$title".imap + cat "$title".imap >> mbox + printf '\n\n' >> mbox + rm "$title".imap +done diff --git a/md2imap/readme.md b/md2imap/readme.md new file mode 100644 index 0000000..5db3caf --- /dev/null +++ b/md2imap/readme.md @@ -0,0 +1,12 @@ +Tool to create a mbox file from a set of markdown files + +Usage: +```bash +md2imap.sh +``` + +To import the mbox file to an imap server using mutt: +* Open mbox file: `mutt -f mbox` +* `T` then `.` to select all +* `;` then `s` to save to =Notes folder +* `U` then `.` to undelete mbox, if needed diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..fba9a6d --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +A set of scripts to convert markdown notes from/to various other formats \ No newline at end of file