aboutsummaryrefslogtreecommitdiff
path: root/assets/js/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/main.js')
-rwxr-xr-xassets/js/main.js595
1 files changed, 199 insertions, 396 deletions
diff --git a/assets/js/main.js b/assets/js/main.js
index 42ff881..76b9544 100755
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -1,414 +1,217 @@
/**
- * Clientside Script of the Netflix Stats Generator
+ * Client-side Script of the Netflix Stats Generator
* @author Marvin Borner
- * @copyright Marvin Borner 2018
+ * @copyright Marvin Borner 2019
*/
-$(() => {
- const DebuggingMode = true;
- const CookieInput = $(".CookieInput");
- let NetflixJson;
-
- moment.locale("de");
- moment().utcOffset(0); // offset for unix timestamp
-
- if (!DebuggingMode) {
- CookieInput.keyup(e => {
- if (e.keyCode === 13) {
- $.ajax({
- url: "assets/php/getNetflixJson.php",
- data: {
- Cookie: CookieInput.val()
- },
- type: "POST"
- }).done(response => {
- CookieInput.val("");
- CookieInput.hide();
- $(".Main").fadeIn();
- AnalyzeData(response);
- });
- }
- });
- } else {
- CookieInput.hide();
- $.ajax({
- url: "assets/js/ExampleData.js",
- type: "POST"
- }).done(response => {
- $(".Main").fadeIn();
- AnalyzeData(response);
- });
- }
-
- /**
- * Analyzes the Netflix data JSON response
- * @param {JSON} JsonResponse
- */
- function AnalyzeData(JsonResponse) {
- /**
- * @example response of a series:
- * bookmark: 0
- * country: "DE"
- * date: 1529338765489
- * dateStr: "18.06.18"
- * deviceType: 1481
- * duration: 3302
- * episodeTitle: "Folge 13"
- * estRating: "50"
- * index: 0
- * movieID: 80205354
- * seasonDescriptor: "Teil 1"
- * series: 80192098
- * seriesTitle: "Haus des Geldes"
- * title: "Teil 1: \"Folge 13\""
- * topNodeId: "80192098"
- * videoTitle: "Folge 13"
- *
- * @example response of a movie:
- * bookmark: 7771
- * country: "DE"
- * date: 1476477258019
- * dateStr: "14.10.16"
- * deviceType: 1193
- * duration: 8160
- * estRating: "30"
- * index: 916
- * movieID: 20557937
- * title: "Matrix"
- * topNodeId: "20557937"
- * videoTitle: "Matrix"
- */
- NetflixJson = JSON.parse(JsonResponse);
- console.log(NetflixJson);
- let EveryWatched = [];
- let TitleWatchTime = {}; //how long you watched a series/movies
- let HeatmapDatesAll = [];
- let HeatmapDates = [];
- let IndividualTitles = [];
- let IndividualSeries = [];
- let IndividualMovies = [];
- let AverageWatchTimes = []; // when you watched a series/movie
-
- NetflixJson.forEach((item, pageKey) => {
- item.forEach((eachItem, ItemNumber) => {
- const currentObject = NetflixJson[pageKey][ItemNumber];
- let currentTitle; // will be overriden by 'if series'
-
- if ("seriesTitle" in eachItem) {
- // is series
- currentTitle = currentObject.seriesTitle;
- EveryWatched.push(currentTitle);
- if (
- IndividualSeries.indexOf(currentTitle) === -1 &&
- currentTitle !== undefined
- ) {
- // only if not already crawled -> individualism
- IndividualSeries.push(currentTitle);
- }
- } else {
- // is movie
- currentTitle = currentObject.videoTitle;
- EveryWatched.push(currentTitle);
- if (
- IndividualMovies.indexOf(currentTitle) === -1 &&
- currentTitle !== undefined
- ) {
- // only if not already crawled -> individualism
- IndividualMovies.push(currentTitle);
- }
- }
-
- // individualism check for every title
- if (
- IndividualMovies.indexOf(currentTitle) === -1 &&
- currentTitle !== undefined
- ) {
- if (!(IndividualTitles.includes(currentTitle))) IndividualTitles.push(currentTitle);
-
- // get watch-time in hours (how long you watched a series/movies)
- const watchTimeInHours = currentObject.duration / 60 / 60;
- let watchTime;
- if (currentTitle in TitleWatchTime) {
- // already in object -> add to previous
- const previousTitleWatchTime = TitleWatchTime[currentTitle];
- watchTime = watchTimeInHours + previousTitleWatchTime;
- } else {
- watchTime = watchTimeInHours;
- }
- TitleWatchTime[currentTitle] = watchTime;
- }
-
- // get watch time as date (when you watched a series/movie)
- const DayTimeInHours = Number(moment.unix(currentObject.date).format('HH'));
- AverageWatchTimes.push(DayTimeInHours);
-
- // get dates and push to heatmap date array for later duplicate deletion
- HeatmapDatesAll.push(currentObject.dateStr);
- // HeatmapDates.push({
- // date: moment(currentObject.dateStr, 'DD.MM.YY').toDate(),
- // count: 1
- // });
- });
- });
-
- // calculate count of dates for heatmap chart
- const HeatmapDatesOccurrenceCounter = new Map(
- [...new Set(HeatmapDatesAll)].map(x => [
- x,
- HeatmapDatesAll.filter(y => y === x).length // get length (=> occurrence) of filtered array
- ])
- );
-
- uniqueHeatmapDates = HeatmapDatesAll.filter(function (item, pos) {
- return HeatmapDatesAll.indexOf(item) == pos;
- });
-
- uniqueHeatmapDates.forEach((index, val) => {
- HeatmapDates.push({
- date: moment(uniqueHeatmapDates[val], 'DD.MM.YY').toDate(),
- count: HeatmapDatesOccurrenceCounter.get(uniqueHeatmapDates[val])
- });
- });
-
-
- const TotalSeriesWatched = IndividualSeries.length;
-
- // Calculate watch time occurrence (times in which the user watched sth.)
- let AverageWatchTimeOccurrence = [];
- const WatchTimeOccurrenceCounter = new Map(
- [...new Set(AverageWatchTimes)].map(x => [
- x,
- AverageWatchTimes.filter(y => y === x).length // get length (=> occurrence) of filtered array
- ])
- );
- for (let i = 0; i < 24; i++) {
- AverageWatchTimeOccurrence.push(WatchTimeOccurrenceCounter.get(i));
- }
-
- // Calculate the most watched series/movies
- const UnsortedTitleOccurrenceCounter = EveryWatched.reduce(
- (prev, curr) => ((prev[curr] = ++prev[curr] || 1), prev), {}
- );
- const SortedTitleOccurrenceCounter = sortObject(
- UnsortedTitleOccurrenceCounter
- );
- const TopSeries = Object.keys(SortedTitleOccurrenceCounter)[
- Object.keys(SortedTitleOccurrenceCounter).length - 1
- ];
-
- // log
- console.table(IndividualTitles);
- console.table(IndividualSeries);
- console.table(IndividualMovies);
- console.table(AverageWatchTimeOccurrence);
- console.table(SortedTitleOccurrenceCounter);
- console.table(TitleWatchTime);
-
- // render
- RenderTopSeries(TopSeries);
- RenderDayTimeChart(AverageWatchTimeOccurrence);
- RenderMostWatchedChart(SortedTitleOccurrenceCounter, TitleWatchTime);
- RenderHeatmap(HeatmapDates);
- }
-
- /**
- * Renders the day time chart
- * @param {Array} AverageWatchTimeOccurrenceArray
- */
- function RenderDayTimeChart(AverageWatchTimeOccurrenceArray) {
- var randomColorGenerator = () => {
- return "#" + (Math.random().toString(16) + "0000000").slice(2, 8);
+const cookie = document.querySelector("#cookie");
+const cookieWrap = document.querySelector("#cookie_wrap");
+const loading = document.querySelector("#loading");
+const stats = document.querySelector("#stats");
+const heatMap = document.querySelector("#heatMap");
+
+cookie.addEventListener("keyup", e => {
+ if (e.key === "Enter") {
+ const request = new XMLHttpRequest();
+ request.onreadystatechange = () => {
+ if (request.readyState === 4 && request.status === 200) {
+ analyze(request.responseText);
+ loading.style.display = "none";
+ stats.style.display = "block";
+ } else if (request.readyState === 4 && request.status !== 200)
+ alert("Cookie is not valid!")
};
-
- // Render day time chart
- const WatchTimeChartElement = document
- .getElementById("WatchTimeChart")
- .getContext("2d");
- new Chart(WatchTimeChartElement, {
- type: "line",
- data: {
- labels: [
- "12am",
- "1am",
- "2am",
- "3am",
- "4am",
- "5am",
- "6am",
- "7am",
- "8am",
- "9am",
- "10am",
- "11am",
- "12pm",
- "1pm",
- "2pm",
- "3pm",
- "4pm",
- "5pm",
- "6pm",
- "7pm",
- "8pm",
- "9pm",
- "10pm",
- "11pm"
- ],
- datasets: [{
- label: "Watches at daytime",
- borderColor: "rgb(255, 99, 132)",
- cubicInterpolationMode: "monotone",
- pointRadius: 0,
- pointHitRadius: 15,
- data: AverageWatchTimeOccurrenceArray
- }]
- },
- options: {
- scales: {
- yAxes: [{
- ticks: {
- display: false
- },
- gridLines: {
- zeroLineColor: "transparent",
- zeroLineWidth: 2,
- drawTicks: false,
- drawBorder: false,
- color: "transparent"
- }
- }],
- xAxes: [{
- gridLines: {
- zeroLineColor: "rgba(255, 255, 255, 0.25)",
- display: true,
- drawBorder: false,
- color: "rgba(255, 255, 255, 0.25)"
- }
- }]
- },
- tension: 1
- }
- });
+ 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";
}
-
- /**
- * Renders the "most watched series" doughnut chart
- * @param {Object} TitleOccurrenceCounterObject
- * @param {Object} TitleWatchTimeObject
- */
- function RenderMostWatchedChart(TitleOccurrenceCounterObject, TitleWatchTimeObject) {
- // Render and calculate most watched chart
- const GenerateRandomColorArray = () => {
- let RandomColorArray = [];
- const Generate = () => {
- var letters = "0123456789ABCDEF".split("");
- var color = "#";
- for (var i = 0; i < 6; i++) {
- color += letters[Math.floor(Math.random() * 16)];
- }
- return color;
+});
+
+function analyze(data) {
+ data = JSON.parse(data).flat(1);
+ let totalWatchedSeconds = 0;
+ const hourObject = Array(24).fill(0);
+ const watchCountObject = {};
+
+ data.forEach(element => {
+ let title;
+ const seriesTitle = element.seriesTitle;
+ const movieTitle = element.title;
+ const watchDate = element.date;
+ const duration = element.duration;
+
+ // Generate watch time array (eg. 12am)
+ hourObject[(new Date(watchDate)).getHours()]++;
+
+ if (seriesTitle !== undefined) title = seriesTitle;
+ else title = movieTitle;
+
+ if (watchCountObject[title] !== undefined) {
+ watchCountObject[title].date.push(new Date(watchDate));
+ watchCountObject[title].watchTimeInSeconds += duration;
+ watchCountObject[title].watchTime = secondsToHours(watchCountObject[title].watchTimeInSeconds);
+ watchCountObject[title].count++;
+ totalWatchedSeconds += duration
+ } else {
+ watchCountObject[title] = {
+ date: [new Date(watchDate)],
+ watchTime: secondsToHours(duration),
+ watchTimeInSeconds: duration,
+ count: 1
};
- for (var key in TitleOccurrenceCounterObject) {
- RandomColorArray.push(Generate());
- }
- return RandomColorArray;
- };
-
- const MostWatchedChartElement = document
- .getElementById("MostWatchedChart")
- .getContext("2d");
- var MostWatchedChartData = {
- labels: [],
+ totalWatchedSeconds += duration;
+ }
+ });
+
+ renderTotalSpent(totalWatchedSeconds);
+ renderHourChart(hourObject);
+ renderTopChart(watchCountObject);
+ renderHeatMap(watchCountObject);
+ console.log(watchCountObject);
+}
+
+function renderTotalSpent(total) {
+ document.querySelector("#totalSpent").innerHTML = `
+ Days: ${Math.floor(total / 60 / 60 / 24)},
+ Hours: ${Math.floor(total / 60 / 60)},
+ Minutes: ${Math.round(total / 60)},
+ Seconds: ${total}`
+}
+
+function renderHourChart(hourObject) {
+ const element = document
+ .getElementById("hourChart")
+ .getContext("2d");
+
+ new Chart(element, {
+ type: "line",
+ data: {
+ labels: [
+ "12am",
+ "1am",
+ "2am",
+ "3am",
+ "4am",
+ "5am",
+ "6am",
+ "7am",
+ "8am",
+ "9am",
+ "10am",
+ "11am",
+ "12pm",
+ "1pm",
+ "2pm",
+ "3pm",
+ "4pm",
+ "5pm",
+ "6pm",
+ "7pm",
+ "8pm",
+ "9pm",
+ "10pm",
+ "11pm"
+ ],
datasets: [{
- label: "Most watched",
- backgroundColor: GenerateRandomColorArray(),
- data: []
+ label: "Average watch times",
+ borderColor: "rgb(255, 99, 132)",
+ cubicInterpolationMode: "monotone",
+ pointRadius: 0,
+ pointHitRadius: 15,
+ data: hourObject
}]
- };
- Chart.pluginService.register({
- beforeInit: chart => {
- var data = chart.config.data;
- for (var key in TitleOccurrenceCounterObject) {
- if (TitleOccurrenceCounterObject.hasOwnProperty(key)) {
- if (TitleOccurrenceCounterObject[key] > 1) {
- data.labels.push(`${key} (Time: ${Math.round(TitleWatchTimeObject[key] * 100) / 100} hours)`); // add label with rounded watch time
- data.datasets[0].data.push(TitleOccurrenceCounterObject[key]);
- }
+ },
+ options: {
+ scales: {
+ yAxes: [{
+ ticks: {
+ display: false
}
- }
+ }]
+ },
+ legend: {
+ display: false
}
- });
- new Chart(MostWatchedChartElement, {
- type: "doughnut",
- data: MostWatchedChartData,
- options: {
- animation: {
- animateScale: true,
- animateRotate: true
- },
- legend: {
- display: false
- }
+ }
+ });
+}
+
+function renderTopChart(object) {
+ const sorted = Object.keys(object).sort((a, b) => {
+ return object[b].watchTimeInSeconds - object[a].watchTimeInSeconds
+ });
+ const data = sorted.map(element => object[element].watchTimeInSeconds);
+ const labels = sorted.map(element => {
+ return element + " (" + Math.floor(object[element].watchTimeInSeconds / 60 / 60) + " hours)"
+ });
+ const colorArray = Array.from({length: data.length}, () =>
+ "#" + ((1 << 24) * Math.random() | 0).toString(16));
+
+ const element = document
+ .getElementById("topChart")
+ .getContext("2d");
+
+ new Chart(element, {
+ type: 'doughnut',
+ data: {
+ datasets: [{
+ data: data,
+ backgroundColor: colorArray
+ }],
+ labels: labels,
+ },
+ options: {
+ animation: {
+ animateScale: true,
+ animateRotate: true
+ },
+ legend: {
+ display: false
}
- });
+ }
+ });
+}
+
+function renderHeatMap(object) {
+ const allDates = Object.keys(object).map(element => object[element].date).flat(10)
+ .map(element => element.setHours(0, 0, 0, 0));
+ const watchedPerWeek = [[], [], [], [], [], [], []];
+
+ for (let i = 0; i < 366; i++) {
+ const date = new Date();
+ date.setDate(date.getDate() - i);
+ date.setHours(0, 0, 0, 0);
+ watchedPerWeek[date.getDay()].push(allDates.map(element => element === date.getTime()).filter(Boolean).length);
}
- /**
- * Renders the top series in the DOM
- * @param {String} Title
- */
- function RenderTopSeries(Title) {
- $.ajax({
- url: "assets/php/getInformation.php",
- data: {
- Title: Title
- },
- type: "POST"
- }).done(result => {
- const TopInformation = JSON.parse(result);
- $(".MostWatchedOverview > .MostWatchedPoster").attr(
- "src",
- `https://image.tmdb.org/t/p/w300${TopInformation.poster_path}`
- );
- $(".MostWatchedOverview > .Description").text(
- TopInformation.overview
- );
- console.log(TopInformation);
- });
- }
+ const maxWatchedPerDay = Math.max.apply(Math, watchedPerWeek.flat(2));
- /**
- * Renders a heatmap of all watched days
- * @param {Array} chartData
- */
- function RenderHeatmap(chartData) {
- const Heatmap = calendarHeatmap()
- .data(chartData)
- .selector('#Heatmap')
- .colorRange(['#ffd3d3', '#fc1111'])
- .tooltipEnabled(true)
- .onClick(function (data) {
- console.log('onClick callback. Data:', data);
- });
+ watchedPerWeek.map((element, i) => {
+ watchedPerWeek[i].push(["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][i]);
+ return watchedPerWeek[i].reverse();
+ });
- Heatmap();
- }
+ watchedPerWeek.forEach(element => {
+ const tableRow = document.createElement("tr");
+ element.forEach(count => {
+ const tableData = document.createElement("td");
+ tableData.style.backgroundColor = "rgba(255,13,0," + count / maxWatchedPerDay + ")";
+ if (typeof count !== "number") tableData.appendChild(document.createTextNode(count));
+ tableRow.appendChild(tableData);
- /**
- * Sorts an js object by value {int}
- * @param {Object} list
- */
- function sortObject(list) {
- var sortable = [];
- for (var key in list) {
- sortable.push([key, list[key]]);
- }
- sortable.sort((a, b) => {
- return a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0;
+ tableData.addEventListener("mouseover", () => {
+ document.querySelector("#information").innerText = `You've watched ${count} titles on that day!`;
+ });
});
- var orderedList = {};
- for (var i = 0; i < sortable.length; i++) {
- orderedList[sortable[i][0]] = sortable[i][1];
- }
- return orderedList;
- }
-}); \ No newline at end of file
+
+ heatMap.appendChild(tableRow)
+ })
+}
+
+function secondsToHours(seconds) {
+ const date = new Date(null);
+ date.setSeconds(seconds);
+ return date.toISOString().substr(11, 8)
+}