stevekrouse-slack_cleaner.web.val.run
Readme

Paste messages from Slack, get clean markdown

This little webapp is intended to make it easier to copy messages from Slack into other places for sharing or archival, with cleaned-up, readable formatting. I hacked it together on valtown with copious help from an LLM over a weekend; please propose changes or edits, as I'm sure I missed many use-cases and edge-cases. This app runs entirely in your browser and does not send your data anywhere.

Screenshot 2024-06-24 at 08.49.45@2x.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
export function slackHTMLToMarkdown(html) {
removeAbsolutePositioning();
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
let lastSender = "";
let lastTimestamp = "";
let markdown = "";
function convertMessage(messageElement) {
function safeGetAttribute(selector, attribute) {
const element = messageElement.querySelector(selector);
return element ? element.getAttribute(attribute) : "";
}
const senderElement = messageElement.querySelector(`[data-qa="message_sender_name"]`);
const sender = senderElement ? senderElement.textContent.trim() : lastSender;
const ariaLabel = safeGetAttribute(".c-timestamp", "aria-label") || "";
const contentElements = messageElement.querySelectorAll(`.c-message_kit__blocks, [data-qa="file_name"]`);
const date = parseTimestamp(ariaLabel);
const isoDate = date.toISOString().split("T")[0];
const formattedTime = date.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: true });
const formattedTimestamp = `${isoDate} ${formattedTime} EST`;
let messageMarkdown = "";
function processNode(node) {
if (node.nodeType === Node.TEXT_NODE) {
return node.textContent;
} else if (node.nodeName === "CODE") {
const codeContent = node.textContent;
if (node.parentNode.nodeName === "PRE") {
const language = node.className.replace("language-", "").split(" ")[0] || "";
return `\n\`\`\`${language}\n${codeContent}\n\`\`\`\n`;
} else {
return "`" + codeContent + "`";
}
} else if (node.nodeName === "PRE") {
const codeElement = node.querySelector("code");
if (codeElement) {
return processNode(codeElement);
} else {
return `\n\`\`\`\n${node.textContent}\n\`\`\`\n`;
}
} else if (node.nodeName === "OL" || node.nodeName === "UL") {
const listType = node.nodeName === "OL" ? "ordered" : "unordered";
const indent = parseInt(node.getAttribute("data-indent") || "0");
const listItems = Array.from(node.querySelectorAll("li")).map((item, index) => {
const indentation = " ".repeat(indent);
const bullet = listType === "ordered" ? `${index + 1}.` : "-";
return `${indentation}${bullet} ${processNode(item).trim()}`;
}).join("\n");
return `\n${listItems}\n`;
} else {
return Array.from(node.childNodes).map(processNode).join("");
}
}
if (contentElements.length > 0) {
messageMarkdown = Array.from(contentElements).map(processNode).join("\n");
}
if (messageMarkdown.trim()) {
if (sender !== lastSender || formattedTimestamp !== lastTimestamp) {
messageMarkdown = `__${sender}__ [${formattedTimestamp}]:\n${messageMarkdown}`;
lastSender = sender;
lastTimestamp = formattedTimestamp;
}
// Split the content by newlines and add blockquotes, except for code blocks
const lines = messageMarkdown.replaceAll(/\n\n+/g, "\n\n").split("\n");
let inCodeBlock = false;
let inList = false;
messageMarkdown = lines.map(line => {
if (line.startsWith("```")) {
inCodeBlock = !inCodeBlock;
return line;
} else if (inCodeBlock || line.startsWith("__")) {
inList = false;
return line;
} else if (line.match(/^\s*(\d+\.|-)\s/)) {
console.log("inlist");
if (inList) return `> ${line}`;
inList = true;
return `>\n> ${line}`;
} else if (line.trim() === "") {
if (inList) return null; // strip extra newlines
return line;
} else {
if (inList) return `>\n> ${line}`;
inList = false;
return `> ${line}`;
}
}).filter(x => x != null).join("\n");
messageMarkdown += "\n\n";
}
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Comments
Nobody has commented on this val yet: be the first!
June 24, 2024