initial commit

This commit is contained in:
quenousimporte 2024-04-10 15:17:04 +02:00
commit 4646cecd92
15 changed files with 622 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
md2imap/mbox
md2imap/*.imap
md2imap/input/*

View File

@ -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 <inputUecdFolder>` or open `web-ui.html` in browser.

View File

@ -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;
}

View File

@ -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;
}
});
}

View File

@ -0,0 +1,19 @@
<html>
<head>
<script src="./cryptee-to-markdown.js"></script>
<script>
function convert()
{
var json = document.getElementById("input").value;
var md =getMarkDown(json);
console.log(md);
document.getElementById("result").innerHTML = "<pre>" + md + "</pre>";
}
</script>
</head>
<body>
<textarea id="input"></textarea>
<button onclick="convert();">Convertir</button>
<div id="result"></div>
</body>
</html>

231
delta2md/delta2md.js Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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()

2
export-wm3/README.md Normal file
View File

@ -0,0 +1,2 @@
# export-wm3
A js script to export your [writemonkey3](https://writemonkey.com/wm3/) documents as flat markdown files.

26
export-wm3/export-wm3.js Normal file
View File

@ -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');
}

View File

@ -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()

12
md2imap/imap-note-header Normal file
View File

@ -0,0 +1,12 @@
From email Wed Apr 10 08:45:21 2024
From: name <email>
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 <email>
X-Uniform-Type-Identifier: com.apple.mail-note
Subject: title
X-Universally-Unique-Identifier: uid
Status: RO

18
md2imap/md2imap.sh Normal file
View File

@ -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

12
md2imap/readme.md Normal file
View File

@ -0,0 +1,12 @@
Tool to create a mbox file from a set of markdown files
Usage:
```bash
md2imap.sh <name> <email>
```
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

1
readme.md Normal file
View File

@ -0,0 +1 @@
A set of scripts to convert markdown notes from/to various other formats