/** * Client-side Script of the Netflix Stats Generator * @author Marvin Borner * @copyright Marvin Borner 2019 */ const cookie = document.querySelector("#cookie"); const cookieWrap = document.querySelector("#cookie_wrap"); const loading = document.querySelector("#loading"); const stats = document.querySelector("#stats"); const toggle = document.querySelector("#toggle"); cookie.addEventListener("keyup", (e) => { if (e.key === "Enter") { const request = new XMLHttpRequest(); request.onreadystatechange = () => { if (request.readyState === 4 && request.status === 200) { loading.style.display = "none"; stats.style.display = "block"; analyze(request.responseText); } else if (request.readyState === 4 && request.status !== 200) alert("Cookie is not valid!"); }; request.open("POST", "assets/php/getData.php", true); request.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" ); request.send("cookie=" + cookie.value); loading.style.display = "block"; cookieWrap.style.display = "none"; } }); function analyze(data) { const filtered = {}; data = JSON.parse(data).flat(1); // Push all titles with empty fields data.forEach( (node) => (filtered[node["seriesTitle"] || node["videoTitle"]] = { duration: 0, dates: [], count: 0, }) ); // Push duration, date and count data.forEach((node) => { const obj = filtered[node["seriesTitle"] || node["videoTitle"]]; obj.duration += node["duration"] / 60 / 60; // hours obj.dates.push(new Date(node["date"])); obj.count++; }); setSizes(); drawTotalSpent(filtered); drawTimeline(filtered); drawTopTitles(filtered); toggle.onclick = () => drawTopTitles(filtered); console.log(filtered); } function setSizes() { const elements = document.getElementsByTagName("canvas"); for (const elem of elements) { elem.setAttribute( "width", document.querySelector(".stats div").offsetWidth ); elem.setAttribute("height", window.innerHeight / 2 + 200); } } function drawTotalSpent(data) { const totalHours = Object.keys(data) .map((key) => data[key].duration) .reduce((a, b) => a + b); document.querySelector("#totalSpent").innerHTML = ` Days: ${Math.floor(totalHours / 24)}; Hours: ${Math.floor(totalHours)}; Minutes: ${Math.round(totalHours * 60)}; Seconds: ${Math.round(totalHours * 60 * 60)}`; } function drawTimeline(data) { const hours = Object.keys(data) .map((key) => data[key].dates.map((date) => date.getHours())) .flat(1); const occurrence = new Array(24).fill(0); hours.forEach((hour) => occurrence[hour] ? occurrence[hour]++ : (occurrence[hour] = 1) ); const ctx = document.getElementById("hourChart"); new Chart(ctx, { type: "line", data: { labels: [...Array(24).keys()], datasets: [ { data: occurrence, borderColor: "#e50914", }, ], }, options: { responsive: false, maintainAspectRatio: true, legend: { display: false, }, scales: { xAxes: [ { gridLines: { color: "#424242", }, }, ], yAxes: [ { gridLines: { color: "#424242", }, }, ], }, }, }); console.log(occurrence); } let previous; function drawTopTitles(data) { // Toggle layout toggle.setAttribute( "data-current", toggle.getAttribute("data-current") === "bar" ? "pie" : "bar" ); if (previous) previous.destroy(); const ctx = document.getElementById("topChart"); previous = new Chart(ctx, { type: toggle.getAttribute("data-current"), data: { labels: Object.keys(data).sort( (a, b) => data[b].duration - data[a].duration ), datasets: [ { data: Object.keys(data) .map((key) => +data[key].duration.toFixed(2)) .sort((a, b) => b - a), borderColor: "#424242", backgroundColor: Array.from( { length: Object.keys(data).length }, () => "#" + ( "00000" + ((Math.random() * (1 << 24)) | 0).toString(16) ).slice(-6) ), }, ], }, options: { responsive: false, maintainAspectRatio: true, animation: { animateScale: true, animateRotate: true, }, legend: { display: false, }, scales: { xAxes: [ { gridLines: { display: toggle.getAttribute("data-current") === "bar", color: "#424242", }, ticks: { display: toggle.getAttribute("data-current") === "bar", }, }, ], yAxes: [ { gridLines: { display: toggle.getAttribute("data-current") === "bar", color: "#424242", }, ticks: { display: toggle.getAttribute("data-current") === "bar", }, }, ], }, }, }); }