From c44e6bbb7fb2cbe85e86732ce00d496e82f6761c Mon Sep 17 00:00:00 2001 From: Stefan Bohacek Date: Mon, 9 Oct 2023 10:22:49 -0400 Subject: [PATCH] Added post milestones where supported. --- public/js/modules/getDomain.min.js | 2 + public/js/modules/getDomain.min.js.map | 1 + public/js/modules/handleSignin - Copy.min.js | 2 - .../js/modules/handleSignin - Copy.min.js.map | 1 - public/js/modules/handleUpload.min.js | 39 ++-- public/js/modules/handleUpload.min.js.map | 2 +- public/js/modules/sleep - Copy.min.js | 2 - public/js/modules/sleep - Copy.min.js.map | 1 - public/js/modules/timeSince - Copy.min.js | 2 - public/js/modules/timeSince - Copy.min.js.map | 1 - src/scripts/modules/getDomain.js | 6 + src/scripts/modules/handleUpload.js | 205 ++++++++++++------ views/how-to-export.handlebars | 2 +- 13 files changed, 167 insertions(+), 99 deletions(-) create mode 100644 public/js/modules/getDomain.min.js create mode 100644 public/js/modules/getDomain.min.js.map delete mode 100644 public/js/modules/handleSignin - Copy.min.js delete mode 100644 public/js/modules/handleSignin - Copy.min.js.map delete mode 100644 public/js/modules/sleep - Copy.min.js delete mode 100644 public/js/modules/sleep - Copy.min.js.map delete mode 100644 public/js/modules/timeSince - Copy.min.js delete mode 100644 public/js/modules/timeSince - Copy.min.js.map create mode 100644 src/scripts/modules/getDomain.js diff --git a/public/js/modules/getDomain.min.js b/public/js/modules/getDomain.min.js new file mode 100644 index 0000000..a426cc9 --- /dev/null +++ b/public/js/modules/getDomain.min.js @@ -0,0 +1,2 @@ +const getDomain=e=>{return new URL(e).hostname};export default getDomain; +//# sourceMappingURL=getDomain.min.js.map diff --git a/public/js/modules/getDomain.min.js.map b/public/js/modules/getDomain.min.js.map new file mode 100644 index 0000000..406d6ca --- /dev/null +++ b/public/js/modules/getDomain.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"getDomain.min.js","sources":["modules/getDomain.js"],"sourcesContent":["const getDomain = (url) => {\n let domain = (new URL(url));\n return domain.hostname;\n};\n\nexport default getDomain;\n"],"names":["getDomain","URL","url","hostname"],"mappings":"AAAA,MAAMA,UAAY,IAEd,OADa,IAAKC,IAAIC,CAAI,EACZC,QAClB,iBAEeH"} \ No newline at end of file diff --git a/public/js/modules/handleSignin - Copy.min.js b/public/js/modules/handleSignin - Copy.min.js deleted file mode 100644 index 753e94e..0000000 --- a/public/js/modules/handleSignin - Copy.min.js +++ /dev/null @@ -1,2 +0,0 @@ -import getUrlParams from"/js/modules/getUrlParams.min.js";import Cookie from"/js/cookies/main.min.js";const cookieManager=new Cookie,signinForm=document.getElementById("signin-form"),instance=document.getElementById("instance"),signinButton=document.getElementById("signin-btn"),toggleFormElements=e=>{"true"===e.dataset.enabled?(instance.disabled=!0,signinButton.disabled=!0,signinButton.innerHTML="Loading...",e.dataset.enabled="false"):(instance.disabled=!1,signinButton.disabled=!1,signinButton.innerHTML="Sign in",e.dataset.enabled="true")},handleSignin=()=>{if(signinForm.addEventListener("submit",async e=>{e.preventDefault(),toggleFormElements(signinForm);e=await(await fetch("https://fediverse-info.stefanbohacek.dev/node-info?domain="+instance.value)).json();e&&e.software?window.location.href=`https://auth.stefanbohacek.dev/?method=fediverse&instance=${instance.value}&scope=read:accounts&app=localhost-3000&platform=`+e.software:(alert("This doesn't look like a fediverse instance."),toggleFormElements(signinForm))}),"/"===window.location.pathname){var e=getUrlParams(),n=cookieManager.get("fpusr"),t=document.getElementById("popover-start");if(t&&t.classList.add("show"),!e.logout&&n){const{instance,platform:i,token:a}=JSON.parse(n);instance&&i&&a&&(window.location.href=`/?instance=${instance}&platform=${i}&token=`+a)}}};export default handleSignin; -//# sourceMappingURL=handleSignin - Copy.min.js.map diff --git a/public/js/modules/handleSignin - Copy.min.js.map b/public/js/modules/handleSignin - Copy.min.js.map deleted file mode 100644 index cd07b17..0000000 --- a/public/js/modules/handleSignin - Copy.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"handleSignin - Copy.min.js","sources":["modules/handleSignin - Copy.js"],"sourcesContent":["import getUrlParams from '/js/modules/getUrlParams.min.js';\r\nimport Cookie from '/js/cookies/main.min.js';\r\n\r\nconst cookieManager = new Cookie();\r\nconst signinForm = document.getElementById(\"signin-form\");\r\nconst instance = document.getElementById(\"instance\");\r\nconst signinButton = document.getElementById(\"signin-btn\");\r\n\r\nconst toggleFormElements = (form) => {\r\n if (form.dataset.enabled === 'true'){\r\n instance.disabled = true;\r\n signinButton.disabled = true;\r\n signinButton.innerHTML = 'Loading...';\r\n form.dataset.enabled = 'false';\r\n } else {\r\n instance.disabled = false;\r\n signinButton.disabled = false;\r\n signinButton.innerHTML = 'Sign in';\r\n form.dataset.enabled = 'true';\r\n }\r\n};\r\n\r\nconst handleSignin = () => {\r\n signinForm.addEventListener(\"submit\", async (ev) => {\r\n ev.preventDefault();\r\n toggleFormElements(signinForm);\r\n\r\n const resp = await fetch(`https://fediverse-info.stefanbohacek.dev/node-info?domain=${instance.value}`);\r\n const respJSON = await resp.json();\r\n if (respJSON && respJSON.software){\r\n window.location.href = `https://auth.stefanbohacek.dev/?method=fediverse&instance=${instance.value}&scope=read:accounts&app=localhost-3000&platform=${respJSON.software}`;\r\n } else {\r\n alert(`This doesn't look like a fediverse instance.`);\r\n toggleFormElements(signinForm);\r\n }\r\n });\r\n \r\n if (window.location.pathname === '/'){\r\n const urlParams = getUrlParams();\r\n const userCookie = cookieManager.get('fpusr');\r\n\r\n const startHerePopover = document.getElementById('popover-start');\r\n if (startHerePopover){\r\n startHerePopover.classList.add('show');\r\n }\r\n\r\n if (!urlParams.logout && userCookie){\r\n const {instance, platform, token} = JSON.parse(userCookie);\r\n if (instance && platform && token){\r\n window.location.href = `/?instance=${instance}&platform=${platform}&token=${token}`;\r\n }\r\n }\r\n }\r\n};\r\n\r\nexport default handleSignin;\r\n"],"names":["getUrlParams","Cookie","cookieManager","signinForm","document","getElementById","instance","signinButton","toggleFormElements","form","dataset","enabled","disabled","innerHTML","handleSignin","addEventListener","async","ev","preventDefault","respJSON","await","fetch","value","json","software","window","location","href","alert","pathname","urlParams","userCookie","get","startHerePopover","classList","add","logout","platform","token","JSON","parse"],"mappings":"OAAOA,iBAAkB,yCAClBC,WAAY,0BAEnB,MAAMC,cAAgB,IAAID,OACpBE,WAAaC,SAASC,eAAe,aAAa,EAClDC,SAAWF,SAASC,eAAe,UAAU,EAC7CE,aAAeH,SAASC,eAAe,YAAY,EAEnDG,mBAAqB,IACI,SAAzBC,EAAKC,QAAQC,SACfL,SAASM,SAAW,CAAA,EACpBL,aAAaK,SAAW,CAAA,EACxBL,aAAaM,UAAY,aACzBJ,EAAKC,QAAQC,QAAU,UAEvBL,SAASM,SAAW,CAAA,EACpBL,aAAaK,SAAW,CAAA,EACxBL,aAAaM,UAAY,UACzBJ,EAAKC,QAAQC,QAAU,OAE3B,EAEMG,aAAe,KAenB,GAdAX,WAAWY,iBAAiB,SAAUC,MAAOC,IAC3CA,EAAGC,eAAe,EAClBV,mBAAmBL,UAAU,EAGvBgB,EAAWC,MADJA,MAAMC,MAAM,6DAA6Df,SAASgB,KAAO,GAC1EC,KAAK,EAC7BJ,GAAYA,EAASK,SACvBC,OAAOC,SAASC,kEAAoErB,SAASgB,yDAAyDH,EAASK,UAE/JI,MAAM,8CAA8C,EACpDpB,mBAAmBL,UAAU,EAEjC,CAAC,EAEgC,MAA7BsB,OAAOC,SAASG,SAAiB,CACnC,IAAMC,EAAY9B,aAAa,EACzB+B,EAAa7B,cAAc8B,IAAI,OAAO,EAEtCC,EAAmB7B,SAASC,eAAe,eAAe,EAKhE,GAJI4B,GACFA,EAAiBC,UAAUC,IAAI,MAAM,EAGnC,CAACL,EAAUM,QAAUL,EAAW,CAClC,KAAM,CAACzB,SAAU+B,SAAAA,EAAUC,MAAAA,CAAK,EAAIC,KAAKC,MAAMT,CAAU,EACrDzB,UAAY+B,GAAYC,IAC1Bb,OAAOC,SAASC,mBAAqBrB,qBAAqB+B,WAAkBC,EAEhF,CACF,CACF,iBAEexB"} \ No newline at end of file diff --git a/public/js/modules/handleUpload.min.js b/public/js/modules/handleUpload.min.js index afbe693..e002417 100644 --- a/public/js/modules/handleUpload.min.js +++ b/public/js/modules/handleUpload.min.js @@ -1,4 +1,4 @@ -import sortArrayOfObjects from"/js/modules/sortArrayOfObjects.min.js";import loadEmbedScript from"/js/modules/loadEmbedScript.min.js";import Cookie from"/js/cookies/main.min.js";const cookieManager=new Cookie,fileInput=document.getElementById("file-input"),introElement=document.getElementById("intro"),loadingAnimation=document.getElementById("loading-animation"),loadingText=document.getElementById("loading-text"),resultsElement=document.getElementById("results"),userInfo=document.getElementById("user-info"),userAvatar=document.getElementById("user-avatar"),userDescription=document.getElementById("user-description"),userDataBreakdown=document.getElementById("user-data-breakdown"),chartElement=document.getElementById("chart"),handleUpload=()=>{fileInput&&fileInput.addEventListener("change",async e=>{loadingAnimation.classList.remove("d-none"),loadingText.classList.remove("d-none"),fileInput.disabled=!0;var s=new FormData;s.set("archive",fileInput.files[0]);s=await(await fetch("/extract-data",{method:"POST",body:s})).json();if(console.log(s),s&&s.data){introElement.classList.add("d-none"),resultsElement.classList.remove("d-none");s=s.data;let e="",t="",a=(s.actor?(e+=` +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,fileInput=document.getElementById("file-input"),introElement=document.getElementById("intro"),loadingAnimation=document.getElementById("loading-animation"),loadingText=document.getElementById("loading-text"),resultsElement=document.getElementById("results"),userInfo=document.getElementById("user-info"),userAvatar=document.getElementById("user-avatar"),userDescription=document.getElementById("user-description"),userDataBreakdown=document.getElementById("user-data-breakdown"),chartElement=document.getElementById("chart"),handleUpload=()=>{fileInput&&fileInput.addEventListener("change",async e=>{loadingAnimation.classList.remove("d-none"),loadingText.classList.remove("d-none"),fileInput.disabled=!0;var s=new FormData;s.set("archive",fileInput.files[0]);s=await(await fetch("/extract-data",{method:"POST",body:s})).json();if(s&&s.data){introElement.classList.add("d-none"),resultsElement.classList.remove("d-none");s=s.data;let e="",t="",a=(s.actor?(e+=`

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

@@ -13,27 +13,34 @@ import sortArrayOfObjects from"/js/modules/sortArrayOfObjects.min.js";import loa `:s.avatar&&(userAvatar.innerHTML=` - `)):(userInfo.remove(),userDescription.remove()),[]),o,n=0;s?.outbox?.orderedItems?a=s.outbox.orderedItems:s?.outbox&&(a=s.outbox),(n=a.length)&&(o=a[0]);var i={weekday:"long",year:"numeric",month:"long",day:"numeric"};s.actor&&(l=moment(s.actor.published),l=moment().diff(l,"days"),t+=` + `)):(userInfo.remove(),userDescription.remove()),[]),o,r=0;s?.outbox?.orderedItems?a=s.outbox.orderedItems:s?.outbox&&(a=s.outbox);var i=[];if(r=a.length){var l=Math.ceil(Math.pow(a.length,.1));if(o=a[0],10<=a.length)for(let t=1;t<=l;t++){var d=a[Math.pow(10,t)],m=d.id.replace("/activity","");let e=!1;d.object.id||(e=!0),d={label:[Math.pow(10,t).toLocaleString()+"th post"],url:m,isBoost:e},i.push(d)}}var c={weekday:"long",year:"numeric",month:"long",day:"numeric"};s.actor&&(u=moment(s.actor.published),u=moment().diff(u,"days"),t+=`

- You created your account on ${new Date(s.actor.published).toLocaleDateString(void 0,i)}, which is ${l.toLocaleString()} day(s) ago. Since then, you posted ${n.toLocaleString()} times, or about ${Math.round(n/l).toLocaleString()} time(s) a day on average. + You created your account on ${new Date(s.actor.published).toLocaleDateString(void 0,c)}, which is ${u.toLocaleString()} day(s) ago. Since then, you posted ${r.toLocaleString()} times, or about ${Math.round(r/u).toLocaleString()} time(s) a day on average.

- `);let r;"mastodon"===s.format?(o&&(i=o?.object?.id||o?.id,l=new URL(i),r=l.protocol+"//"+l.hostname,t=t+` + `);let n;if(o){let e;if(!["firefish","calckey","misskey"].includes(s.format)){c=o?.uri||o?.object?.id||o?.id;try{e=new URL(c)}catch(e){console.log("error parsing data file",e)}e&&e.protocol&&e.hostname&&(n=e.protocol+"//"+e.hostname),t+=`

- Here's your first post! + Here's your first post!

- `+` + `,"mastodon"===s.format&&(t+=` - `),t+=` -

- And this is what your posting history looks like. -

- `):t+=` -

- Here's what your posting history looks like. -

- `,userDataBreakdown.innerHTML=t,"mastodon"===s.format&&loadEmbedScript(r);var l={labels:a.map(e=>moment(e.published||e.createdAt||e.created)),datasets:[{label:"Your posts in time",data:a.map((e,t)=>({x:moment(e.published||e.createdAt||e.created),y:new Date(e.published||e.createdAt||e.created).getHours()})),backgroundColor:["#ff6384"]}]};new Chart(chartElement,{type:"scatter",data:l,options:{scales:{x:{type:"time",position:"bottom",ticks:{beginAtZero:!1,stepSize:10}},y:{ticks:{beginAtZero:!1,display:!1},scaleLabel:{display:!1},minorTickInterval:null}},plugins:{tooltip:{callbacks:{label:e=>e.label}}}}})}else loadingAnimation.classList.add("d-none"),loadingText.classList.add("d-none"),fileInput.disabled=!1})};export default handleUpload; + `),i&&i.length&&(t+=` +

+ Here are more of your milestones: +

+ + `),t+=` +

+ And this is what your posting history looks like. +

+ `}}userDataBreakdown.innerHTML=t,"mastodon"===s.format&&loadEmbedScript(n);var u={labels:a.map(e=>moment(e.published||e.createdAt||e.created)),datasets:[{label:"Your posts in time",data:a.map((e,t)=>({x:moment(e.published||e.createdAt||e.created),y:new Date(e.published||e.createdAt||e.created).getHours()})),backgroundColor:["#ff6384"]}]};new Chart(chartElement,{type:"scatter",data:u,options:{scales:{x:{type:"time",position:"bottom",ticks:{beginAtZero:!1,stepSize:10}},y:{ticks:{beginAtZero:!1,display:!1},scaleLabel:{display:!1},minorTickInterval:null}},plugins:{tooltip:{callbacks:{label:e=>e.label}}}}})}else loadingAnimation.classList.add("d-none"),loadingText.classList.add("d-none"),fileInput.disabled=!1})};export default handleUpload; //# sourceMappingURL=handleUpload.min.js.map diff --git a/public/js/modules/handleUpload.min.js.map b/public/js/modules/handleUpload.min.js.map index 4ffcd9c..bbee363 100644 --- a/public/js/modules/handleUpload.min.js.map +++ b/public/js/modules/handleUpload.min.js.map @@ -1 +1 @@ -{"version":3,"file":"handleUpload.min.js","sources":["modules/handleUpload.js"],"sourcesContent":["import sortArrayOfObjects from \"/js/modules/sortArrayOfObjects.min.js\";\r\nimport loadEmbedScript from \"/js/modules/loadEmbedScript.min.js\";\r\nimport Cookie from \"/js/cookies/main.min.js\";\r\n\r\nconst cookieManager = new Cookie();\r\nconst fileInput = document.getElementById(\"file-input\");\r\nconst introElement = document.getElementById(\"intro\");\r\nconst loadingAnimation = document.getElementById(\"loading-animation\");\r\nconst loadingText = document.getElementById(\"loading-text\");\r\nconst resultsElement = document.getElementById(\"results\");\r\nconst userInfo = document.getElementById(\"user-info\");\r\nconst userAvatar = document.getElementById(\"user-avatar\");\r\nconst userDescription = document.getElementById(\"user-description\");\r\nconst userDataBreakdown = document.getElementById(\"user-data-breakdown\");\r\nconst chartElement = document.getElementById(\"chart\");\r\n\r\nconst handleUpload = () => {\r\n if (fileInput) {\r\n fileInput.addEventListener(\"change\", async (ev) => {\r\n loadingAnimation.classList.remove('d-none');\r\n loadingText.classList.remove('d-none');\r\n fileInput.disabled = true;\r\n const formData = new FormData();\r\n formData.set(\"archive\", fileInput.files[0]);\r\n\r\n const resp = await fetch(\"/extract-data\", {\r\n method: \"POST\",\r\n body: formData,\r\n });\r\n\r\n const response = await resp.json();\r\n console.log(response);\r\n\r\n if (response && response.data) {\r\n introElement.classList.add(\"d-none\");\r\n resultsElement.classList.remove(\"d-none\");\r\n const userData = response.data;\r\n\r\n let userDescriptionHTML = '';\r\n let userDataBreakdownHTML = '';\r\n\r\n if (userData.actor){\r\n userDescriptionHTML += `\r\n

\r\n ${\r\n userData.actor.name || userData.actor.preferredUsername\r\n }\r\n

\r\n ${userData.actor.summary.replaceAll('class=\"invisible\"', \"\")}\r\n `;\r\n \r\n if (userData.actor.attachment) {\r\n userDescriptionHTML += `\r\n \r\n `;\r\n }\r\n \r\n userDescription.innerHTML = `
${userDescriptionHTML}
`;\r\n\r\n if (userData.avatar_url){\r\n userAvatar.innerHTML = `\r\n \r\n `;\r\n } else if (userData.avatar){\r\n userAvatar.innerHTML = `\r\n \r\n `;\r\n }\r\n } else {\r\n userInfo.remove();\r\n userDescription.remove();\r\n }\r\n\r\n let posts = [],\r\n firstPost,\r\n postCount = 0;\r\n\r\n if (userData?.outbox?.orderedItems) {\r\n posts = userData.outbox.orderedItems;\r\n } else if (userData?.outbox){\r\n posts = userData.outbox; \r\n }\r\n \r\n postCount = posts.length;\r\n if (postCount) {\r\n // posts = sortArrayOfObjects(posts, key, desc)\r\n firstPost = posts[0];\r\n }\r\n const options = {\r\n weekday: \"long\",\r\n year: \"numeric\",\r\n month: \"long\",\r\n day: \"numeric\",\r\n };\r\n\r\n if (userData.actor){\r\n const accountCreationDate = moment(userData.actor.published);\r\n const today = moment();\r\n const timeAgo = today.diff(accountCreationDate, 'days');\r\n \r\n \r\n userDataBreakdownHTML += `\r\n

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

\r\n `;\r\n }\r\n\r\n let instanceURL;\r\n\r\n if (userData.format === 'mastodon'){\r\n if (firstPost) {\r\n const postURL = firstPost?.object?.id || firstPost?.id;\r\n const url = new URL(postURL);\r\n instanceURL = `${url.protocol}//${url.hostname}`;\r\n\r\n\r\n userDataBreakdownHTML += `\r\n

\r\n Here's your first post!\r\n

\r\n `;\r\n\r\n userDataBreakdownHTML += `\r\n \r\n `;\r\n }\r\n\r\n userDataBreakdownHTML += `\r\n

\r\n And this is what your posting history looks like.\r\n

\r\n `;\r\n } else {\r\n userDataBreakdownHTML += `\r\n

\r\n Here's what your posting history looks like.\r\n

\r\n `;\r\n }\r\n \r\n userDataBreakdown.innerHTML = userDataBreakdownHTML;\r\n\r\n if (userData.format === 'mastodon'){\r\n loadEmbedScript(instanceURL);\r\n }\r\n\r\n // chartOptions.options.legend = {\r\n // display: false\r\n // };\r\n\r\n const data = {\r\n labels: posts.map((post) => moment(post.published || post.createdAt || post.created)),\r\n datasets: [\r\n {\r\n label: \"Your posts in time\",\r\n data: posts.map((post, index) => {\r\n return {\r\n x: moment(post.published || post.createdAt || post.created),\r\n // y: (new Date(post.published || post.createdAt)).getHour() + 1,\r\n y: (new Date(post.published || post.createdAt || post.created)).getHours(),\r\n };\r\n }),\r\n backgroundColor: ['#ff6384']\r\n },\r\n ],\r\n };\r\n\r\n new Chart(chartElement, {\r\n type: \"scatter\",\r\n data : data,\r\n options: {\r\n scales: {\r\n x: \r\n {\r\n type: \"time\",\r\n position: \"bottom\",\r\n ticks: {\r\n beginAtZero: false,\r\n stepSize: 10,\r\n },\r\n },\r\n y: \r\n {\r\n ticks: {\r\n beginAtZero: false,\r\n display: false,\r\n },\r\n scaleLabel: {\r\n display: false,\r\n // labelString: chartEl.dataset.axisLabelData\r\n // labelString: chartEl.dataset.sourceId ? window.ftfDataviz[parseInt( chartEl.dataset.sourceId )].axis_label_title : ''\r\n // labelString: 'Day of the month'\r\n },\r\n minorTickInterval: null,\r\n },\r\n },\r\n plugins: {\r\n tooltip: {\r\n callbacks: {\r\n // label: (ctx) => ctx.label \r\n label: (ctx) => {\r\n // console.log(ctx);\r\n // console.log(posts[ctx.dataIndex].object.content);\r\n return ctx.label\r\n }\r\n }\r\n }\r\n }\r\n },\r\n });\r\n } else {\r\n loadingAnimation.classList.add('d-none');\r\n loadingText.classList.add('d-none');\r\n fileInput.disabled = false;\r\n }\r\n });\r\n }\r\n};\r\n\r\nexport default handleUpload;\r\n"],"names":["sortArrayOfObjects","loadEmbedScript","Cookie","cookieManager","fileInput","document","getElementById","introElement","loadingAnimation","loadingText","resultsElement","userInfo","userAvatar","userDescription","userDataBreakdown","chartElement","handleUpload","addEventListener","async","ev","classList","remove","disabled","formData","FormData","set","files","response","await","fetch","method","body","json","console","log","data","add","userData","let","userDescriptionHTML","userDataBreakdownHTML","posts","actor","name","preferredUsername","summary","replaceAll","attachment","map","value","replace","join","innerHTML","avatar_url","avatar","firstPost","postCount","outbox","orderedItems","length","options","weekday","year","month","day","accountCreationDate","moment","published","timeAgo","diff","Date","toLocaleDateString","undefined","toLocaleString","Math","round","instanceURL","format","postURL","object","id","url","URL","protocol","hostname","labels","post","createdAt","created","datasets","label","index","x","y","getHours","backgroundColor","Chart","type","scales","position","ticks","beginAtZero","stepSize","display","scaleLabel","minorTickInterval","plugins","tooltip","callbacks","ctx"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"handleUpload.min.js","sources":["modules/handleUpload.js"],"sourcesContent":["import sortArrayOfObjects from \"/js/modules/sortArrayOfObjects.min.js\";\r\nimport getDomain from \"/js/modules/getDomain.min.js\";\r\nimport loadEmbedScript from \"/js/modules/loadEmbedScript.min.js\";\r\nimport Cookie from \"/js/cookies/main.min.js\";\r\n\r\nconst cookieManager = new Cookie();\r\nconst fileInput = document.getElementById(\"file-input\");\r\nconst introElement = document.getElementById(\"intro\");\r\nconst loadingAnimation = document.getElementById(\"loading-animation\");\r\nconst loadingText = document.getElementById(\"loading-text\");\r\nconst resultsElement = document.getElementById(\"results\");\r\nconst userInfo = document.getElementById(\"user-info\");\r\nconst userAvatar = document.getElementById(\"user-avatar\");\r\nconst userDescription = document.getElementById(\"user-description\");\r\nconst userDataBreakdown = document.getElementById(\"user-data-breakdown\");\r\nconst chartElement = document.getElementById(\"chart\");\r\n\r\nconst handleUpload = () => {\r\n if (fileInput) {\r\n fileInput.addEventListener(\"change\", async (ev) => {\r\n loadingAnimation.classList.remove(\"d-none\");\r\n loadingText.classList.remove(\"d-none\");\r\n fileInput.disabled = true;\r\n const formData = new FormData();\r\n formData.set(\"archive\", fileInput.files[0]);\r\n\r\n const resp = await fetch(\"/extract-data\", {\r\n method: \"POST\",\r\n body: formData,\r\n });\r\n\r\n const response = await resp.json();\r\n\r\n if (response && response.data) {\r\n introElement.classList.add(\"d-none\");\r\n resultsElement.classList.remove(\"d-none\");\r\n const userData = response.data;\r\n\r\n // let userDomain = getDomain(userData.actor.id);\r\n let userDescriptionHTML = \"\";\r\n let userDataBreakdownHTML = \"\";\r\n\r\n if (userData.actor) {\r\n userDescriptionHTML += `\r\n

\r\n ${\r\n userData.actor.name || userData.actor.preferredUsername\r\n }\r\n

\r\n ${userData.actor.summary.replaceAll('class=\"invisible\"', \"\")}\r\n `;\r\n\r\n if (userData.actor.attachment) {\r\n userDescriptionHTML += `\r\n \r\n `;\r\n }\r\n\r\n userDescription.innerHTML = `
${userDescriptionHTML}
`;\r\n\r\n if (userData.avatar_url) {\r\n userAvatar.innerHTML = `\r\n \r\n `;\r\n } else if (userData.avatar) {\r\n userAvatar.innerHTML = `\r\n \r\n `;\r\n }\r\n } else {\r\n userInfo.remove();\r\n userDescription.remove();\r\n }\r\n\r\n let posts = [],\r\n firstPost,\r\n postCount = 0;\r\n\r\n if (userData?.outbox?.orderedItems) {\r\n posts = userData.outbox.orderedItems;\r\n } else if (userData?.outbox) {\r\n posts = userData.outbox;\r\n }\r\n\r\n postCount = posts.length;\r\n let milestones = [];\r\n\r\n if (postCount) {\r\n // posts = sortArrayOfObjects(posts, key, desc)\r\n const maxRoot = Math.ceil(Math.pow(posts.length, 1 / 10));\r\n firstPost = posts[0];\r\n\r\n if (posts.length >= 10) {\r\n for (let i = 1; i <= maxRoot; i++) {\r\n const post = posts[Math.pow(10, i)];\r\n const url = post.id.replace(\"/activity\", \"\");\r\n\r\n let milestone = {};\r\n let isBoost = false;\r\n\r\n if (!post.object.id) {\r\n isBoost = true;\r\n }\r\n\r\n milestone = {\r\n label: [`${Math.pow(10, i).toLocaleString()}th post`],\r\n url,\r\n isBoost,\r\n };\r\n\r\n milestones.push(milestone);\r\n }\r\n }\r\n }\r\n\r\n const options = {\r\n weekday: \"long\",\r\n year: \"numeric\",\r\n month: \"long\",\r\n day: \"numeric\",\r\n };\r\n\r\n if (userData.actor) {\r\n const accountCreationDate = moment(userData.actor.published);\r\n const today = moment();\r\n const timeAgo = today.diff(accountCreationDate, \"days\");\r\n\r\n userDataBreakdownHTML += `\r\n

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

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

\r\n Here's your first post!\r\n

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

\r\n Here are more of your milestones:\r\n

\r\n
    \r\n ${milestones\r\n .map(\r\n (milestone) => `\r\n
  • \r\n ${\r\n milestone.label\r\n }${milestone.isBoost ? ` (boost)` : \"\"}\r\n
  • \r\n `\r\n )\r\n .join(\"\")}\r\n
\r\n `;\r\n }\r\n\r\n userDataBreakdownHTML += `\r\n

\r\n And this is what your posting history looks like.\r\n

\r\n `;\r\n }\r\n }\r\n\r\n userDataBreakdown.innerHTML = userDataBreakdownHTML;\r\n\r\n if (userData.format === \"mastodon\") {\r\n loadEmbedScript(instanceURL);\r\n }\r\n\r\n // chartOptions.options.legend = {\r\n // display: false\r\n // };\r\n\r\n const data = {\r\n labels: posts.map((post) =>\r\n moment(post.published || post.createdAt || post.created)\r\n ),\r\n datasets: [\r\n {\r\n label: \"Your posts in time\",\r\n data: posts.map((post, index) => {\r\n return {\r\n x: moment(post.published || post.createdAt || post.created),\r\n // y: (new Date(post.published || post.createdAt)).getHour() + 1,\r\n y: new Date(\r\n post.published || post.createdAt || post.created\r\n ).getHours(),\r\n };\r\n }),\r\n backgroundColor: [\"#ff6384\"],\r\n },\r\n ],\r\n };\r\n\r\n new Chart(chartElement, {\r\n type: \"scatter\",\r\n data: data,\r\n options: {\r\n scales: {\r\n x: {\r\n type: \"time\",\r\n position: \"bottom\",\r\n ticks: {\r\n beginAtZero: false,\r\n stepSize: 10,\r\n },\r\n },\r\n y: {\r\n ticks: {\r\n beginAtZero: false,\r\n display: false,\r\n },\r\n scaleLabel: {\r\n display: false,\r\n // labelString: chartEl.dataset.axisLabelData\r\n // labelString: chartEl.dataset.sourceId ? window.ftfDataviz[parseInt( chartEl.dataset.sourceId )].axis_label_title : ''\r\n // labelString: 'Day of the month'\r\n },\r\n minorTickInterval: null,\r\n },\r\n },\r\n plugins: {\r\n tooltip: {\r\n callbacks: {\r\n // label: (ctx) => ctx.label\r\n label: (ctx) => {\r\n // console.log(ctx);\r\n // console.log(posts[ctx.dataIndex].object.content);\r\n return ctx.label;\r\n },\r\n },\r\n },\r\n },\r\n },\r\n });\r\n } else {\r\n loadingAnimation.classList.add(\"d-none\");\r\n loadingText.classList.add(\"d-none\");\r\n fileInput.disabled = false;\r\n }\r\n });\r\n }\r\n};\r\n\r\nexport default handleUpload;\r\n"],"names":["sortArrayOfObjects","getDomain","loadEmbedScript","Cookie","cookieManager","fileInput","document","getElementById","introElement","loadingAnimation","loadingText","resultsElement","userInfo","userAvatar","userDescription","userDataBreakdown","chartElement","handleUpload","addEventListener","async","ev","classList","remove","disabled","formData","FormData","set","files","response","await","fetch","method","body","json","data","add","userData","let","userDescriptionHTML","userDataBreakdownHTML","posts","actor","name","preferredUsername","summary","replaceAll","attachment","map","value","replace","join","innerHTML","avatar_url","avatar","firstPost","postCount","outbox","orderedItems","milestones","length","maxRoot","Math","ceil","pow","i","post","url","id","isBoost","object","milestone","label","toLocaleString","push","options","weekday","year","month","day","accountCreationDate","moment","published","timeAgo","diff","Date","toLocaleDateString","undefined","round","instanceURL","includes","format","postURL","uri","URL","err","console","log","protocol","hostname","labels","createdAt","created","datasets","index","x","y","getHours","backgroundColor","Chart","type","scales","position","ticks","beginAtZero","stepSize","display","scaleLabel","minorTickInterval","plugins","tooltip","callbacks","ctx"],"mappings":"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"} \ No newline at end of file diff --git a/public/js/modules/sleep - Copy.min.js b/public/js/modules/sleep - Copy.min.js deleted file mode 100644 index 2ca9e15..0000000 --- a/public/js/modules/sleep - Copy.min.js +++ /dev/null @@ -1,2 +0,0 @@ -const sleep=s=>new Promise(e=>setTimeout(e,s));export default sleep; -//# sourceMappingURL=sleep - Copy.min.js.map diff --git a/public/js/modules/sleep - Copy.min.js.map b/public/js/modules/sleep - Copy.min.js.map deleted file mode 100644 index 11eccd3..0000000 --- a/public/js/modules/sleep - Copy.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"sleep - Copy.min.js","sources":["modules/sleep - Copy.js"],"sourcesContent":["const sleep = (ms) => {\n return new Promise(resolve => setTimeout(resolve, ms));\n};\n\nexport default sleep;\n"],"names":["sleep","Promise","resolve","setTimeout","ms"],"mappings":"AAAA,MAAMA,MAAQ,GACL,IAAIC,QAAQC,GAAWC,WAAWD,EAASE,CAAE,CAAC,iBAGxCJ"} \ No newline at end of file diff --git a/public/js/modules/timeSince - Copy.min.js b/public/js/modules/timeSince - Copy.min.js deleted file mode 100644 index c620ae6..0000000 --- a/public/js/modules/timeSince - Copy.min.js +++ /dev/null @@ -1,2 +0,0 @@ -const timeSince=o=>{var o=Math.floor((new Date-o)/1e3),t=Math.floor(o/31536e3);return 1 {\r\n let seconds = Math.floor((new Date() - date) / 1000);\r\n let interval = Math.floor(seconds / 31536000);\r\n \r\n if (interval > 1) {\r\n return interval + \" years\";\r\n }\r\n\r\n interval = Math.floor(seconds / 2592000);\r\n\r\n if (interval > 1) {\r\n return interval + \" months\";\r\n }\r\n\r\n interval = Math.floor(seconds / 86400);\r\n\r\n if (interval > 1) {\r\n return interval + \" days\";\r\n }\r\n\r\n interval = Math.floor(seconds / 3600);\r\n\r\n if (interval > 1) {\r\n return interval + \" hours\";\r\n }\r\n\r\n interval = Math.floor(seconds / 60);\r\n\r\n if (interval > 1) {\r\n return interval + \" minutes\";\r\n }\r\n\r\n return Math.floor(seconds) + \" seconds\";\r\n};\r\n\r\nexport default timeSince;"],"names":["timeSince","let","seconds","Math","floor","Date","date","interval"],"mappings":"AAAA,MAAMA,UAAY,IACdC,IAAIC,EAAUC,KAAKC,OAAO,IAAIC,KAASC,GAAQ,GAAI,EAC/CC,EAAWJ,KAAKC,MAAMF,EAAU,OAAQ,EAE5C,OAAe,EAAXK,EACOA,EAAW,SAKP,GAFfA,EAAWJ,KAAKC,MAAMF,EAAU,MAAO,GAG5BK,EAAW,UAKP,GAFfA,EAAWJ,KAAKC,MAAMF,EAAU,KAAK,GAG1BK,EAAW,QAKP,GAFfA,EAAWJ,KAAKC,MAAMF,EAAU,IAAI,GAGzBK,EAAW,SAKP,GAFfA,EAAWJ,KAAKC,MAAMF,EAAU,EAAE,GAGvBK,EAAW,WAGfJ,KAAKC,MAAMF,CAAO,EAAI,UACjC,iBAEeF"} \ No newline at end of file diff --git a/src/scripts/modules/getDomain.js b/src/scripts/modules/getDomain.js new file mode 100644 index 0000000..a06f7de --- /dev/null +++ b/src/scripts/modules/getDomain.js @@ -0,0 +1,6 @@ +const getDomain = (url) => { + let domain = (new URL(url)); + return domain.hostname; +}; + +export default getDomain; diff --git a/src/scripts/modules/handleUpload.js b/src/scripts/modules/handleUpload.js index 3d178c3..e5dd97b 100644 --- a/src/scripts/modules/handleUpload.js +++ b/src/scripts/modules/handleUpload.js @@ -1,4 +1,5 @@ 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"; @@ -17,8 +18,8 @@ const chartElement = document.getElementById("chart"); const handleUpload = () => { if (fileInput) { fileInput.addEventListener("change", async (ev) => { - loadingAnimation.classList.remove('d-none'); - loadingText.classList.remove('d-none'); + loadingAnimation.classList.remove("d-none"); + loadingText.classList.remove("d-none"); fileInput.disabled = true; const formData = new FormData(); formData.set("archive", fileInput.files[0]); @@ -29,17 +30,17 @@ const handleUpload = () => { }); const response = await resp.json(); - console.log(response); if (response && response.data) { introElement.classList.add("d-none"); resultsElement.classList.remove("d-none"); const userData = response.data; - let userDescriptionHTML = ''; - let userDataBreakdownHTML = ''; + // let userDomain = getDomain(userData.actor.id); + let userDescriptionHTML = ""; + let userDataBreakdownHTML = ""; - if (userData.actor){ + if (userData.actor) { userDescriptionHTML += `

${ @@ -48,7 +49,7 @@ const handleUpload = () => {

${userData.actor.summary.replaceAll('class="invisible"', "")} `; - + if (userData.actor.attachment) { userDescriptionHTML += `
    @@ -64,14 +65,14 @@ const handleUpload = () => {
`; } - + userDescription.innerHTML = `
${userDescriptionHTML}
`; - if (userData.avatar_url){ + if (userData.avatar_url) { userAvatar.innerHTML = ` `; - } else if (userData.avatar){ + } else if (userData.avatar) { userAvatar.innerHTML = ` `; @@ -87,15 +88,41 @@ const handleUpload = () => { if (userData?.outbox?.orderedItems) { posts = userData.outbox.orderedItems; - } else if (userData?.outbox){ - posts = userData.outbox; + } else if (userData?.outbox) { + posts = userData.outbox; } - + postCount = posts.length; + let milestones = []; + if (postCount) { // posts = sortArrayOfObjects(posts, key, desc) + const maxRoot = Math.ceil(Math.pow(posts.length, 1 / 10)); firstPost = posts[0]; + + if (posts.length >= 10) { + for (let i = 1; i <= maxRoot; i++) { + const post = posts[Math.pow(10, i)]; + const url = post.id.replace("/activity", ""); + + let milestone = {}; + let isBoost = false; + + if (!post.object.id) { + isBoost = true; + } + + milestone = { + label: [`${Math.pow(10, i).toLocaleString()}th post`], + url, + isBoost, + }; + + milestones.push(milestone); + } + } } + const options = { weekday: "long", year: "numeric", @@ -103,30 +130,45 @@ const handleUpload = () => { day: "numeric", }; - if (userData.actor){ + if (userData.actor) { const accountCreationDate = moment(userData.actor.published); const today = moment(); - const timeAgo = today.diff(accountCreationDate, 'days'); - - + const timeAgo = today.diff(accountCreationDate, "days"); + userDataBreakdownHTML += `

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

`; } let instanceURL; - if (userData.format === 'mastodon'){ - if (firstPost) { - const postURL = firstPost?.object?.id || firstPost?.id; - const url = new URL(postURL); - instanceURL = `${url.protocol}//${url.hostname}`; + 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 += `

@@ -134,31 +176,48 @@ const handleUpload = () => {

`; - userDataBreakdownHTML += ` + if (userData.format === "mastodon") { + userDataBreakdownHTML += ` `; - } + } - userDataBreakdownHTML += ` -

- And this is what your posting history looks like. -

- `; - } else { - userDataBreakdownHTML += ` -

- Here's what your posting history looks like. -

- `; + if (milestones && milestones.length) { + userDataBreakdownHTML += ` +

+ Here are more of your milestones: +

+
    + ${milestones + .map( + (milestone) => ` +
  • + ${ + milestone.label + }${milestone.isBoost ? ` (boost)` : ""} +
  • + ` + ) + .join("")} +
+ `; + } + + userDataBreakdownHTML += ` +

+ And this is what your posting history looks like. +

+ `; + } } - + userDataBreakdown.innerHTML = userDataBreakdownHTML; - if (userData.format === 'mastodon'){ + if (userData.format === "mastodon") { loadEmbedScript(instanceURL); } @@ -167,7 +226,9 @@ const handleUpload = () => { // }; const data = { - labels: posts.map((post) => moment(post.published || post.createdAt || post.created)), + labels: posts.map((post) => + moment(post.published || post.createdAt || post.created) + ), datasets: [ { label: "Your posts in time", @@ -175,60 +236,60 @@ const handleUpload = () => { 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(), + y: new Date( + post.published || post.createdAt || post.created + ).getHours(), }; }), - backgroundColor: ['#ff6384'] + backgroundColor: ["#ff6384"], }, ], }; new Chart(chartElement, { type: "scatter", - data : data, + data: data, options: { scales: { - x: - { - type: "time", - position: "bottom", - ticks: { - beginAtZero: false, - stepSize: 10, - }, + 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, + }, + 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) => ctx.label label: (ctx) => { // console.log(ctx); // console.log(posts[ctx.dataIndex].object.content); - return ctx.label - } - } - } - } + return ctx.label; + }, + }, + }, + }, }, }); } else { - loadingAnimation.classList.add('d-none'); - loadingText.classList.add('d-none'); + loadingAnimation.classList.add("d-none"); + loadingText.classList.add("d-none"); fileInput.disabled = false; } }); diff --git a/views/how-to-export.handlebars b/views/how-to-export.handlebars index 3a4a644..3db30ed 100644 --- a/views/how-to-export.handlebars +++ b/views/how-to-export.handlebars @@ -33,7 +33,7 @@ Click the "Export" button under "All posts".
  • - Your exported file will be available in your Drive. (Link is under "Settings".) + Your exported file will be available in your Drive. (Link is under "More" in the sidebar.)