Skip to content

Instantly share code, notes, and snippets.

@fabiomadge
Last active June 24, 2020 16:47
Show Gist options
  • Save fabiomadge/817bbc01b46b2c4d2c2d1fcd8c10c72f to your computer and use it in GitHub Desktop.
Save fabiomadge/817bbc01b46b2c4d2c2d1fcd8c10c72f to your computer and use it in GitHub Desktop.
HTML View of Signal database dump of a single conversation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Chat</title>
<style>
body {
background-color: #121212;
font-family: -apple-system, BlinkMacSystemFont, Inter, "Helvetica Neue", sans-serif;
}
hr {
margin-bottom: 2px;
margin-left: 12px;
margin-right: 12px;
border-color: rgba(255, 255, 255, 0.8);
}
.day {
text-align: center;
color: rgba(255, 255, 255, 0.8);
}
.row {
position: relative;
}
.outgoing, .incoming {
max-width: 70%;
width: fit-content;
padding-left: 12pt;
padding-right: 12pt;
padding-top: 10pt;
padding-bottom: 10pt;
margin-top: 8pt;
margin-bottom: 8pt;
word-wrap: break-word;
border-radius: 16px;
}
.outgoing {
margin-left:auto;
margin-right:0;
background-color: #2c6bed;
color: rgba(255, 255, 255, 0.9);
}
.outgoing .timestamp {
color: rgba(255, 255, 255, 0.8);
text-align: right;
}
.outgoing .quote {
background-color: #1851b4;
}
.incoming {
color: rgb(233, 233, 233);
background-color: #3b3b3b;
}
.incoming .timestamp {
color: rgb(185, 185, 185);
}
.incoming .quote {
background-color: #5a5a63;
}
.timestamp {
margin-top: 3px;
margin-bottom: -3px;
font-size: .8rem;
}
.quote {
padding-right: 8px;
padding-left: 8px;
padding-top: 7px;
padding-bottom: 7px;
margin-top: -4px;
margin-bottom: 5px;
margin-left: -6px;
margin-right: -6px;
border-left-width: 4px;
border-left-style: solid;
border-color: black;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
</style>
<script>
function loadTexts() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var records = parseCSV(this.responseText);
var texts = document.createElement("DIV");
texts.setAttribute("id", "texts");
var date = new Date(0);
records.forEach(element => {
var day = new Date(parseInt(element.getAttribute("sent_at")));
day.setHours(0,0,0,0);
if (day.getTime() !== date.getTime()){
texts.appendChild(document.createElement("HR"));
var d = document.createElement("DIV");
d.classList.add("day");
d.innerText = day.toDateString();
date = day;
texts.appendChild(d);
}
var row = document.createElement("DIV");
row.classList.add("row");
row.appendChild(element);
texts.appendChild(row);
});
document.body.appendChild(texts);
if (window.location.hash !== "") window.location = window.location;
}
};
xmlhttp.open("GET", "messages.csv", true);
xmlhttp.send();
}
function parseCSV(csv){
var lines = csv.match(/(?:"[^"]*"|[^\n])+/g);
var jsonIndex = lines[0].match(/(?:"[^"]*"|[^,])+/g).indexOf("json");
var records = lines.slice(1);
return records.map(r => parseJSON(r.match(/(?:"[^"]*"|[^,])+/g)[jsonIndex]));
}
function parseJSON(json){
var msg = JSON.parse(json.slice(1,-1).replace(/\"\"/g, "\""));
var div = document.createElement("div");
div.classList.add(msg.type);
div.setAttribute("id", msg.id);
div.setAttribute("timestamp", msg.timestamp);
div.setAttribute("sent_at", msg.sent_at);
div.addEventListener("click", function() {window.location.hash = "#" + msg.id;});
if (msg.quote !== null && msg.quote !== undefined){
var quote = document.createElement("div");
quote.classList.add("quote");
quote.onclick = function() {
var id = findIdWithTimestamp(msg.quote.id);
if (id !== null) document.getElementById(id).scrollIntoView();
event.stopPropagation();
};
quote.innerText = msg.quote.text;
div.appendChild(quote);
}
var text = document.createElement("div");
text.innerText = msg.body;
div.appendChild(text);
var timestamp = document.createElement("div");
timestamp.classList.add("timestamp");
var d = new Date(msg.sent_at);
var mins = d.getMinutes()
timestamp.innerText = d.getHours() + ":" + (mins < 10 ? "0" : "") + mins;
div.appendChild(timestamp);
return div;
}
function findIdWithTimestamp(timestamp){
var classes = ["outgoing", "incoming"];
for (var i = 0, n = classes.length; i < n; i++){
var allElements = document.getElementsByClassName(classes[i]);
for (var j = 0, m = allElements.length; j < m; j++){
if (parseInt(allElements[j].getAttribute("sent_at")) === timestamp){
return allElements[j].getAttribute("id");
}
}
}
return null;
}
</script>
</head>
<body onload="loadTexts()">
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment