Skip to content

Instantly share code, notes, and snippets.

@Archetrix
Created September 20, 2019 13:48
Show Gist options
  • Save Archetrix/c43f25ba59203a8fb1d9342c6848ac08 to your computer and use it in GitHub Desktop.
Save Archetrix/c43f25ba59203a8fb1d9342c6848ac08 to your computer and use it in GitHub Desktop.
Skype export parser including files from media-folder and links to other referenced files.
<!DOCTYPE html><html><head>
<!-- Copyright © Microsoft. All rights reserved. -->
<!--
Extended Version by A.Geesen (2019)
Fixed Code errors
Removed protection
Added auto-link to media/ files.
Added link to external references.
Unfolded the one-lined mess :)
-->
<title>Archived conversations</title><meta charset="utf-8">
<style>
@font-face {
font-family: "Segoe UI Local";
font-weight: 200;
src: local("Segoe UI Light")
}
@font-face {
font-family: "Segoe UI Local";
font-weight: 400;
src: local("Segoe UI")
}
@font-face {
font-family: "Segoe UI Local";
font-weight: 600;
src: local("Segoe UI Semibold")
}
body,html {
height: 100%
}
body {
background-color: #f2f2f2;
font: 1em "Segoe UI Local","Segoe WP","Segoe UI Web",Tahoma,"Helvetica Neue",Helvetica,"Meiryo UI",Meiryo,Arial Unicode MS,sans-serif;
width: 100%;
margin: 0 auto
}
body.conversation {
overflow-x: hidden
}
.left {
display: block;
position: absolute;
left: 0;
top: 0;
width: 30%;
height: 100%;
margin: 0;
overflow: hidden
}
.right {
display: block;
position: absolute;
right: 0;
top: 0;
width: 70%;
height: 100%;
overflow: hidden
}
div#selected-conversation-placeholder {
display: block;
width: 100%;
top: 120px;
bottom: 0;
position: absolute;
overflow: auto
}
.object {
width: 100%;
height: 98%;
overflow-x: hidden;
overflow-x: hidden
}
body.index {
overflow: hidden
}
div.header {
position: fixed;
top: 0;
left: 1rem;
width: 100%;
background-color: #f2f2f2;
margin-bottom: 1rem;
padding-bottom: 1rem
}
h1 {
color: #0b0b10;
font-size: 1.5em;
top: 0;
left: 1rem;
padding-left: 1rem;
padding-top: 1rem;
padding-bottom: 1rem;
margin-top: 0;
margin-bottom: 1rem;
width: 100%;
background-color: #f2f2f2
}
h1.conversations {
position: static;
margin-bottom: 0;
padding-left: 7rem;
background: url(skype.svg) 1rem 1rem no-repeat;
margin-bottom: 0
}
div.author {
color: #626f82;
padding-bottom: .5rem
}
div.quote:before {
display: block;
height: 0;
content: "“";
margin-left: -1.5rem;
font: italic 50px/1 Georgia,serif;
color: #999
}
div.quote {
font-style: italic;
margin-left: 1.5rem;
margin-bottom: .5rem
}
span.author {
color: #626f82
}
span.timestamp {
color: #626f82;
padding-left: .5rem;
font-size: small
}
span.timestamp-conv {
color: #626f82;
padding-left: .5rem;
font-size: small
}
span.messageCount {
color: #626f82;
font-size: small
}
span.at:before {
content: "@"
}
span.at {
font-style: italic;
color: #626f82
}
ul {
list-style-type: none;
padding-left: 1rem;
padding-right: 1rem;
padding-top: 1rem;
margin-top: 1rem;
margin-bottom: 2rem;
padding-bottom: 2rem
}
ul.conversations {
position: absolute;
top: 8rem;
bottom: 0;
width: 90%;
overflow-y: scroll
}
li.message {
border-radius: 5px;
background-color: #fff;
color: #0b0b10;
padding-left: 1rem;
padding-top: .5rem;
padding-bottom: .5rem;
margin: .5rem auto
}
li.conversations {
background-color: #f2f2f2;
color: #0b0b10;
padding-left: .25rem;
padding-top: .5rem;
padding-bottom: .5rem;
margin: 0 auto;
word-wrap: break-word;
border-bottom-style: solid;
border-bottom-width: thin;
border-bottom-color: #626f82
}
li.conversations-sel {
background-color: #c7edfc;
color: #0b0b10;
padding-left: .25rem;
padding-top: .5rem;
padding-bottom: .5rem;
margin: 0 auto;
word-wrap: break-word;
border-bottom-style: solid;
border-bottom-width: thin;
border-bottom-color: #626f82
}
.form {
position: absolute;
display: block;
top: 100px;
left: 50px;
right: 50px;
text-align: left
}
.form fieldset {
border-radius: 5px;
border-color: #626f82;
background-color: #c7edfc
}
.primaryCta:hover,.promo a:hover .promo-link {
color: #fff;
background-color: #0b64a4
}
.btn {
box-sizing: border-box;
border: 1px solid transparent;
border-radius: 100px;
cursor: pointer;
display: inline-block;
font-size: 16px;
font-weight: 600;
line-height: 24px;
position: relative;
text-align: center;
text-decoration: none!important;
word-wrap: break-word;
padding: 12px 30px
}
.primaryCta {
color: #fff;
background-color: #0078ca
}
#progress {
display: none
}
pre {
display: inline
}
ul.details {
list-style-type: circle;
padding-left: 1rem;
padding-right: 1rem;
padding-top: 0;
margin-top: 0;
margin-bottom: 10px;
padding-bottom: 10px
}
#selected-conversation-header {
margin-top: 50px
}
.step-1,.step-2 {
display: none
}
.message-body img {
max-width: 95%;
}
</style>
</head>
<body>
<div class="left step-2">
<div class="header">
<h1 class="conversations">
Archived conversations
</h1>
<table class="step-2">
<tbody>
<tr>
<th>
User
</th>
<td id="hdr-user"></td>
</tr>
<tr>
<th>
Exported
</th>
<td id="hdr-exported"></td>
</tr>
<tr>
<th>
Total
</th>
<td id="hdr-stats"></td>
</tr>
</tbody>
</table>
</div>
<ul class="conversations step-2" id="conversations"></ul>
</div>
<div id="selected-conversation" class="right step-2">
<h1 class="conversation step-2" id="selected-conversation-header"></h1>
<div id="selected-conversation-placeholder" class="step-2">
<ul class="messages" id="messages"></ul>
</div>
</div>
<div class="step-1 form">
<form id="jsonFile" name="jsonFile" enctype="multipart/form-data" method="post">
<fieldset>
<h3>
View your Skype conversation history export
</h3>
<ol>
<li>Request an <a href="https://go.skype.com/export" target="_blank">export of your Skype conversations</a>
</li>
<li>Once available, <a href="https://go.skype.com/export" target="_blank">download the exported file</a>
</li>
<li>Unpack the TAR file
<ul class="details">
<li>On Windows, you can use the free <a href="https://www.7-zip.org/" target="_blank">7-zip</a> or similar tool
</li>
<li>On Mac, you can double-click the file to extract it
</li>
</ul>
</li>
<li>
<strong>Select the&nbsp;</strong>
<pre>messages.json</pre><strong>&nbsp;file from the export:&nbsp;</strong><input type="file" accept=".json" id="fileinput">
</li>
<li>
<strong>Click the&nbsp;</strong><input type="button" id="btnLoad" value="Load" class="btn primaryCta">
</li>
</ol><br>
<div id="progress">
Processing...
</div>
</fieldset>
</form>
</div>
<script type = "text/javascript">
!function () {
"use strict";
function c(e) {
return e.displayName ? u(e.displayName) : p(e.id);
}
function lk() {
var rp = new RegExp(/&lt;URIObject.*uri="https:\/\/api\.asm\.skype\.com\/v1\/objects\/([^"]+)"[^;]+[^O]+OriginalName v="[^"]+(\..{3,4})".*&lt;\/URIObject&gt;/, 'gm'),
rf = new RegExp(/&lt;URIObject.*href="([^"]+)"[^;]+[^O]+OriginalName v="([^"]+)".*&lt;\/URIObject&gt;/, 'gm');
Array.prototype.filter.call(document.getElementsByClassName('message-body'), function (t) {
return t.innerHTML.substring(0, 13) === '&lt;URIObject';
}).forEach(function (w, i, a) {
var t = w.innerHTML,c = 0;
if (t.match(/type="photo"/)) {
w.innerHTML = t.replace(rp, function (m, p1, p2) {
return "<img src='media/" + p1 + "." + ++c + p2 + "'>";
});
} else if (t.match(/type="File/) || t.match(/type="Video/)) {
w.innerHTML = t.replace(rf, function (m, p1, p2) {
return "<a href='" + p1 + "'>" + p2 + "</a>";
});
}
});
}
function m(e) {
e.preventDefault();
var t = parseInt(e.target.getAttribute("data-conv"), 10),
n = document.getElementById("messages");
n.innerHtml = "", n.textContent = "", document.getElementById("selected-conversation-header").textContent = c(window.Skype.conversations[t]);
for (var a = window.Skype.conversations[t] && window.Skype.conversations[t].MessageList ? window.Skype.conversations[t].MessageList : [], s = 0; s < a.length; s++)
if ("" !== a[s].content) {
var r = document.createElement("li");
r.className = "message", r.setAttribute("id", a[s].id);
var o = document.createElement("div");
r.appendChild(o);
var i = document.createElement("span");
i.className = "author", i.textContent = p(a[s].from), o.appendChild(i);
var l = document.createElement("span");
l.className = "timestamp", l.textContent = new Date(a[s].originalarrivaltime).toLocaleString(), o.appendChild(l);
var d = document.createElement("div");
d.className = "message-body", d.innerText = u(a[s].content), r.appendChild(d), n.appendChild(r);
}
lk();
}
function a(e, t) {
document.getElementById(e).textContent = t;
}
function p(e) {
return e.replace(/^8:/, "");
}
function u(e) {
return e.replace(/&apos;/g, "'").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">");
}
function s(e, t) {
for (var n = document.getElementsByClassName(e), a = 0; a < n.length; a++)
n[a].style.display = t ? "block" : "none";
}
document.getElementById("btnLoad").addEventListener("click", function () {
var e, t, n;
"function" == typeof window.FileReader ? (e = document.getElementById("fileinput")) && e.files ? e.files[0] ? (document.getElementById("progress").style.display = "block", t = e.files[0], (n = new FileReader).onload = function (e) {
var t = e.target.result;
!function (e) {
if (e && e.userId && e.conversations && e.exportDate) {
var t = new Date(e.exportDate),
n = e.conversations.filter(function (e) {
return e.id && "ALL" !== e.id && !/@cast\.skype$/.test(e.id) && e.MessageList && e.MessageList.length;
});
a("hdr-user", p(e.userId)), a("hdr-exported", t.toLocaleString()), a("hdr-stats", n.length + " conversations"),
function (e) {
for (var t = document.getElementById("conversations"), n = 0; n < e.length; n++) {
var a = document.createElement("li");
a.className = "conversations";
var s = document.createElement("a");
s.setAttribute("href", "#"), s.setAttribute("data-conv", n), s.className = "conv-link", s.textContent = c(e[n]), a.appendChild(s);
var r = document.createElement("div");
a.appendChild(r);
var o = document.createElement("span");
o.className = "messageCount", o.textContent = e[n].MessageList.length + " messages", r.appendChild(o);
var i = e[n].properties && e[n].properties.lastimreceivedtime ? e[n].properties.lastimreceivedtime : null;
if (i) {
var l = document.createElement("span");
l.className = "timestamp-conv", l.textContent = "Last from: " + new Date(i).toLocaleString(), r.appendChild(l);
}
t.appendChild(a);
}
for (var d = document.getElementsByClassName("conv-link"), n = 0; n < d.length; n++)
d[n].addEventListener("click", m);
}(n), window.Skype = {}, window.Skype.conversations = n, s("step-1", !1), s("step-2", !0);
} else
alert("Sorry, we are unable to load this file");
}(JSON.parse(t));
}, n.readAsText(t, "utf8")) : alert("Please select a file before clicking 'Load'") : alert("This browser doesn't seem to support the 'files' property of file inputs.") : alert("The file API isn't supported on this browser. Please use a more modern browser.");
}), s("step-2", !1), s("step-1", !0);
}();
</script>
</body></html>
@Archetrix
Copy link
Author

Put this into the folder of the message.json with the media/ folder next to it. Just like you've extracted it from the download.
Targets all URIObject entry types i could find so far. If you have more types let me know or adapt accordingly.

@tommycrattyjr
Copy link

what the hell bobby? I dont know how to do this shit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment