import sortArrayOfObjects from "/js/modules/sortArrayOfObjects.min.js"; import getDomain from "/js/modules/getDomain.min.js"; import loadEmbedScript from "/js/modules/loadEmbedScript.min.js"; import Cookie from "/js/cookies/main.min.js"; const cookieManager = new Cookie(); const fileInput = document.getElementById("file-input"); const introElement = document.getElementById("intro"); const loadingAnimation = document.getElementById("loading-animation"); const loadingText = document.getElementById("loading-text"); const resultsElement = document.getElementById("results"); const userInfo = document.getElementById("user-info"); const userAvatar = document.getElementById("user-avatar"); const userDescription = document.getElementById("user-description"); const userDataBreakdown = document.getElementById("user-data-breakdown"); const chartElement = document.getElementById("chart"); const handleUpload = () => { if (fileInput) { fileInput.addEventListener("change", async (ev) => { loadingAnimation.classList.remove("d-none"); loadingText.classList.remove("d-none"); fileInput.disabled = true; const formData = new FormData(); formData.set("archive", fileInput.files[0]); const resp = await fetch("/extract-data", { method: "POST", body: formData, }); const response = await resp.json(); if (response && response.data) { introElement.classList.add("d-none"); resultsElement.classList.remove("d-none"); const userData = response.data; // let userDomain = getDomain(userData.actor.id); let userDescriptionHTML = ""; let userDataBreakdownHTML = ""; if (userData.actor) { userDescriptionHTML += `

${ userData.actor.name || userData.actor.preferredUsername }

${userData.actor.summary.replaceAll('class="invisible"', "")} `; if (userData.actor.attachment) { userDescriptionHTML += ` `; } userDescription.innerHTML = `
${userDescriptionHTML}
`; if (userData.avatar_url) { userAvatar.innerHTML = ` `; } else if (userData.avatar) { userAvatar.innerHTML = ` `; } } else { userInfo.remove(); userDescription.remove(); } let posts = []; let firstPost; let postCount = 0; if (userData?.outbox?.orderedItems) { posts = userData.outbox.orderedItems; } else if (userData?.outbox) { posts = userData.outbox; } postCount = posts.length; let milestones = []; let counter = { posts: 0, replies: 0, reblogs: 0, total: 0, }; if (postCount) { // posts = sortArrayOfObjects(posts, key, desc) const maxRoot = Math.ceil(Math.pow(posts.length, 1 / 10)); let index = 0; firstPost = posts[0]; posts.forEach((post) => { let isSemiPublic = false; const recipients = [...post.to, ...post.cc]; recipients.forEach((recipient) => { if (recipient.endsWith("/followers")) { isSemiPublic = true; } }); if (isSemiPublic) { index++; if (posts.length >= 10 && index <= maxRoot) { const post = posts[Math.pow(10, index)]; const url = post.id.replace("/activity", ""); let milestone = {}; let isBoost = false; if (!post.object.id) { isBoost = true; } milestone = { label: [`${Math.pow(10, index).toLocaleString()}th post`], url, isBoost, }; milestones.push(milestone); } counter.total++; if (post.type === "Create") { if (post.object.inReplyTo) { counter.replies++; } else { counter.posts++; } } else { try { if ( post.id && post.object && post.id.split("/users/")[0] === post.object.split("/users/")[0] ) { console.log(post); counter.posts++; counter.total++; } else { counter.reblogs++; } } catch (err) { /*noop*/ } } } else { // console.log(post.id.replace("users/", "@").replace("statuses/", "").replace("/activity", ""), recipients); // console.log(recipients); // if (recipients.length === 0){ // console.log(post.id.replace("users/", "@").replace("statuses/", "").replace("/activity", "")); // } } }); // console.log({ counter }); } const options = { weekday: "long", year: "numeric", month: "long", day: "numeric", }; if (userData.actor) { const accountCreationDate = moment(userData.actor.published); const today = moment(); const timeAgo = today.diff(accountCreationDate, "days"); userDataBreakdownHTML += `

You created your account on ${new Date( userData.actor.published ).toLocaleDateString( undefined, options )}, which is ${timeAgo.toLocaleString()} day(s) ago. Since then, you posted ${counter.total.toLocaleString()} times, or about ${Math.round( counter.total / timeAgo ).toLocaleString()} time(s) a day on average.

`; } if (counter.reblogs > 0 || counter.replies > 0) { userDataBreakdownHTML += `

You have reblogged ${counter.reblogs.toLocaleString()} post(s), replied ${counter.replies.toLocaleString()} time(s), and posted ${counter.posts.toLocaleString()} new post(s).

`; } let instanceURL; if (firstPost) { let postURL; let url; if (["firefish", "calckey", "misskey"].includes(userData.format)) { // Export file doesn't contain server name. } else { postURL = firstPost?.uri || firstPost?.object?.id || firstPost?.id; try { url = new URL(postURL); } catch (err) { console.log("error parsing data file", err); } if (url && url.protocol && url.hostname) { instanceURL = `${url.protocol}//${url.hostname}`; } userDataBreakdownHTML += `

Here's your first post!

`; if (userData.format === "mastodon") { userDataBreakdownHTML += ` `; } if (milestones && milestones.length) { userDataBreakdownHTML += `

Here are more of your milestones:

`; } userDataBreakdownHTML += `

And this is what your posting history looks like.

`; } } userDataBreakdown.innerHTML = userDataBreakdownHTML; if (userData.format === "mastodon") { loadEmbedScript(instanceURL); } // chartOptions.options.legend = { // display: false // }; const data = { labels: posts.map((post) => moment(post.published || post.createdAt || post.created) ), datasets: [ { label: "Your posts in time", data: posts.map((post, index) => { return { x: moment(post.published || post.createdAt || post.created), // y: (new Date(post.published || post.createdAt)).getHour() + 1, y: new Date( post.published || post.createdAt || post.created ).getHours(), }; }), backgroundColor: ["#ff6384"], }, ], }; new Chart(chartElement, { type: "scatter", data: data, options: { scales: { x: { type: "time", position: "bottom", ticks: { beginAtZero: false, stepSize: 10, }, }, y: { ticks: { beginAtZero: false, display: false, }, scaleLabel: { display: false, // labelString: chartEl.dataset.axisLabelData // labelString: chartEl.dataset.sourceId ? window.ftfDataviz[parseInt( chartEl.dataset.sourceId )].axis_label_title : '' // labelString: 'Day of the month' }, minorTickInterval: null, }, }, plugins: { tooltip: { callbacks: { // label: (ctx) => ctx.label label: (ctx) => { // console.log(ctx); // console.log(posts[ctx.dataIndex].object.content); return ctx.label; }, }, }, }, }, }); } else { loadingAnimation.classList.add("d-none"); loadingText.classList.add("d-none"); fileInput.disabled = false; } }); } }; export default handleUpload;