diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..965acab --- /dev/null +++ b/.htaccess @@ -0,0 +1,8 @@ +RewriteEngine on + + +RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC] +RewriteRule ^ /%1 [NC,L,R] + +RewriteCond %{REQUEST_FILENAME}.html -f +RewriteRule ^ %{REQUEST_URI}.html [NC,L] \ No newline at end of file diff --git a/README.md b/README.md index 50d1614..afd737f 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,21 @@ # Plex Wrapped -A website and API for collecting Plex user stats within a set timeframe using Tautulli. - -## Warning -I made this for fun, and I am currently working on perfecting it. All feedback and tips are welcome. - +## Introduction +A website and API for collecting Plex user stats within a set timeframe using [Tautulli](https://github.com/Tautulli/Tautulli). Yes, you need Tautulli to have been running beforehand and currently for this to work. ## Instructions -There are multiple settings you must configure! They are all located in config.json. -

-Tautulli API key
-API key generated by Tautulli. +There are multiple settings you must configure! They will be stored in config/config.json, but can be configured easily at you-domain-or-ip.com/admin. -Tautulli IP
-The IP address of the Tautulli server. -Tautulli Port
-The port for the Tautulli server. Can be left as "". +PHP will have issues with this API based on the results you want. If you have a large time frame for your wrapped period and there is a huge amount of Tautulli entries you can have multiple issues. +In your php.ini file you may have to change: +- max_execution_time=enough seconds for the script to finish +- memory_limit=enough M for the script to handle JSON data +- max_input_time=enough seconds for the script to parse JSON data -SSL
-This is supposed to enable HTTPS support, but it does not function at this time. Leave as false. +The cache is stored at config/cache.json, but can be cleared using the admin menu. -Tautulli Root
-If using reverse proxy with a set root, add it here. Do not add "/" before or after. - -Library ID Movies
-The ID of your movie library in Tautulli. You can find it in the URL when visiting the library on the Tautulli website. - -Library ID Shows
-The ID of your show library in Tautulli. You can find it in the URL when visiting the library on the Tautulli website. - -Wrapped Start
-The beginning of the wrapped time period. Written in Epoch. Conversion can be done here https://www.epochconverter.com/. - -Wrapped End
-The end of the wrapped time period. Written in Epoch. Conversion can be done here https://www.epochconverter.com/. - -Get_... Settings
-Disables or enables different methods in the API. Will probably break the website without reconfiguration. - -Tautulli Length
-The number of items in your Tautulli database. Needed so API knows amount of data to load. - -
- -You may need to give your PHP processing more memory, depending on how much data is in your Tautulli database. +If you visit you-domain-or-ip.com/caching you can do a pre-caching of a set of users. This is very useful if you want to prepare for a lot of traffic. ## Need help? -If you contact me I might have time to help you. Or maybe not. If not, many people on several forums (including /r/plex) might be able to assist you. +If you have any issues feel free to contact me. I am always trying to improve the project. If I can't, many people on several forums (including /r/plex) might be able to assist you. Goodybye. \ No newline at end of file diff --git a/admin.html b/admin.html new file mode 100644 index 0000000..84ac859 --- /dev/null +++ b/admin.html @@ -0,0 +1,94 @@ + + + + + + + + Plex Wrapped + + + + + + + + + + + + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +

Wrapped Setup

+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
+ + + + + + diff --git a/admin.js b/admin.js new file mode 100644 index 0000000..5d10f54 --- /dev/null +++ b/admin.js @@ -0,0 +1,311 @@ +function time_days(seconds_input) { + var seconds = Number(seconds_input); + var days = seconds * 1.15741E-5; + + var hours = String(days).split("."); + var hours_str = "0." + hours[1]; + var hours_int = Number(hours_str) * 24.0; + + var minutes = String(hours_int).split("."); + var minutes_str = "0." + minutes[1]; + var minutes_int = Number(minutes_str) * 60.0; + + var days_form = String(days).split("."); + var hours_form = String(hours_int).split("."); + var minutes_form = String(minutes_int).split("."); + + var final = [Number(days_form[0]), Number(hours_form[0]), Number(minutes_form[0])]; + return final; +} + +function time_hours(seconds_input) { + var seconds = Number(seconds_input); + var hours_int = Number(seconds) * 0.0002777778; + + var minutes = String(hours_int).split("."); + var minutes_str = "0." + minutes[1]; + var minutes_int = Number(minutes_str) * 60.0; + + var hours_form = String(hours_int).split("."); + var minutes_form = String(minutes_int).split("."); + + var final = [Number(hours_form[0]), Number(minutes_form[0])]; + return final; +} + +function makeRequest (method, url, data) { + return new Promise(function (resolve, reject) { + var xhr = new XMLHttpRequest(); + xhr.open(method, url); + xhr.onload = function () { + if (this.status >= 200 && this.status < 300) { + resolve(xhr.response); + } else { + reject({ + status: this.status, + statusText: xhr.statusText + }); + } + }; + xhr.onerror = function () { + reject({ + status: this.status, + statusText: xhr.statusText + }); + }; + if(method=="POST" && data){ + xhr.send(data); + }else{ + xhr.send(); + } + }); +} + +function topFunction() { + document.body.scrollTop = 0; // For Safari + document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera +} + +function login_menu() { + topFunction(); + var html = '
' + + html += '
'; + html += ''; + html += ''; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + + html += '
'; + document.getElementById("setup").innerHTML = html; +} + +function set_password(back) { + topFunction(); + var html = '
' + + html += '
'; + html += ''; + html += ''; + html += '
'; + + html += '
'; + html += ''; + html += ''; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + + html += '
'; + document.getElementById("setup").innerHTML = html; +} + +function set_tautulli(back) { + topFunction(); + if(!back) { + if(document.getElementById('password').value == document.getElementById('password_2').value) { + password = document.getElementById('password').value; + } else { + alert("The passwords must match."); + return false; + } + } + + var html = '
'; + html += ''; + html += '
'; + + html += '
' + + html += '
'; + html += ''; + html += '
'; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + + html += '
'; + + document.getElementById("setup").innerHTML = html; +} + +function set_tautulli_details(back) { + topFunction(); + if(!back) { + tautulli_apikey = document.getElementById('tautulli_apikey').value; + tautulli_ip = document.getElementById('tautulli_ip').value; + tautulli_port = document.getElementById('tautulli_port').value; + tautulli_length = document.getElementById('tautulli_length').value; + tautulli_root = document.getElementById('tautulli_root').value; + ssl = document.getElementById('ssl').checked; + library_id_movies = document.getElementById('library_id_movies').value; + library_id_shows = document.getElementById('library_id_shows').value; + } + var html = '
'; + html += ''; + html += '
'; + + html += '
' + + var temp_date = wrapped_start.toLocaleDateString("en-GB", { // you can skip the first argument + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + timezone: "Europe/London", + }); + var temp_date = temp_date.split(','); + var temp_date_first = temp_date[0].split('/'); + var temp_date_second = temp_date[1].split(':'); + html += '
'; + html += ''; + html += '
'; + html += '
'; + + var temp_date = wrapped_end.toLocaleDateString("en-GB", { // you can skip the first argument + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + timezone: "Europe/London", + }); + var temp_date = temp_date.split(','); + var temp_date_first = temp_date[0].split('/'); + var temp_date_second = temp_date[1].split(':'); + html += '
'; + html += ''; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + + html += '
'; + document.getElementById("setup").innerHTML = html; +} + +function set_tautulli_last(back) { + if(!back) { + wrapped_start = new Date(document.getElementById('wrapped_start').value); + wrapped_end = new Date(document.getElementById('wrapped_end').value); + if(wrapped_end < wrapped_start) { + alert("The wrapped end period must be later than the wrapped start period."); + return; + } + + get_user_movie_stats = document.getElementById('get_user_movie_stats').checked; + get_user_show_stats = document.getElementById('get_user_show_stats').checked; + get_user_show_buddy = document.getElementById('get_user_show_buddy').checked; + get_year_stats = document.getElementById('get_year_stats').checked; + use_cache = document.getElementById('use_cache').checked; + cache_age_limit = document.getElementById('cache_age_limit').value; + + set_config(); + } +} \ No newline at end of file diff --git a/api/get_config.php b/api/get_config.php new file mode 100644 index 0000000..118d92d --- /dev/null +++ b/api/get_config.php @@ -0,0 +1,24 @@ + true, "message" => "No input provided.")); + exit(0); +} + +if(empty($config->password)) { + echo json_encode(array("error" => false, "message" => "No password set.", "password" => false, "data" => array())); + exit(0); +} + +$password = htmlspecialchars($data->password); + +if(password_verify($password, $config->password)) { + echo json_encode(array("error" => false, "message" => "Login successful.", "password" => true, "data" => $config)); + exit(0); +} else { + echo json_encode(array("error" => true, "message" => "Password not accepted.", "password" => true, "data" => array())); + exit(0); +} +?> \ No newline at end of file diff --git a/api/get_functions.php b/api/get_functions.php new file mode 100644 index 0000000..f38b47f --- /dev/null +++ b/api/get_functions.php @@ -0,0 +1,17 @@ + "Config not configured.", "error" => true)); + exit(0); +} + +$functions = array("get_user_movie_stats" => $config->get_user_movie_stats, + "get_user_show_stats" => $config->get_user_show_stats, + "get_user_show_buddy" => $config->get_user_show_buddy, + "get_year_stats" => $config->get_year_stats + ); +echo json_encode($functions); +exit(0); +?> \ No newline at end of file diff --git a/api/get_stats.php b/api/get_stats.php index 96738c6..d9f0a6c 100644 --- a/api/get_stats.php +++ b/api/get_stats.php @@ -1,6 +1,18 @@ [ + 'verify_peer'=> false, + 'verify_peer_name'=> false, + ], +]; + +if (empty($config)) { + echo json_encode(array("message" => "Config not configured.", "error" => true)); + exit(0); +} // Libraries for movies and shows $library_id_movies = $config->library_id_movies; @@ -10,19 +22,36 @@ $library_id_shows = $config->library_id_shows; $connection = create_url(); //Declare given email -if($data){ - $p_email = htmlspecialchars($data->p_email); +if(!empty($data)){ + $p_identity = htmlspecialchars($data->p_identity); +} else if(isset($_GET["p_identity"])) { + $p_identity = htmlspecialchars($_GET["p_identity"]); } else { - $p_email = htmlspecialchars($_GET["email"]); + echo json_encode(array("message" => "No input provided.", "error" => true)); + exit(0); } // Get user ID -$id = tautulli_get_user($p_email); +$id = tautulli_get_user($p_identity); if (!$id) { - echo json_encode(array("message" => "No user found with that email.", "error" => "true")); + echo json_encode(array("message" => "No user found with that email.", "error" => true)); exit(0); } +// Use cache +if($config->use_cache) { + if($cache = check_cache()) { + $now = new DateTime('NOW'); + $then = new DateTime($cache->date); + $diff = $now->diff($then); + + if($diff->format('%D') < $config->cache_age_limit) { + echo json_encode($cache); + exit(0); + } + } +} + // Get user name $name = tautulli_get_name($id); if(!$name) { @@ -42,7 +71,7 @@ if($config->get_user_show_stats) { $user_shows = array("error" => True, "message" => "Disabled in config.", "data" => array()); } -if($config->get_user_show_buddy && $config->get_user_show_stats) { +if($config->get_user_show_buddy && $config->get_user_show_stats && !empty($user_shows["data"])) { $user_shows["data"] = $user_shows["data"] + array("show_buddy" => array("user" => tautulli_get_user_show_buddy($id, $user_shows["data"]["shows"]), "error" => False, "Message" => "Buddy is loaded.")); } else { $user_shows["data"] = $user_shows["data"] + array("show_buddy" => array("message" => "Disabled in config.", "error" => True)); @@ -54,16 +83,26 @@ if($config->get_year_stats) { $year_stats = array("data" => array(), "message" => "Disabled in config.", "error" => True); } +$now = new DateTime('NOW'); + // Print results -echo json_encode(array( "error" => False, - "message" => "Data processed.", - "user" => array("name" => $name, - "id" => $id, - "user_movies" => $user_movies, - "user_shows" => $user_shows - ), - "year_stats" => $year_stats, - )); +$result = json_encode(array("error" => False, + "date" => $now->format('Y-m-d'), + "message" => "Data processed.", + "user" => array("name" => $name, + "id" => $id, + "user_movies" => $user_movies, + "user_shows" => $user_shows + ), + "year_stats" => $year_stats, + )); + +if($config->use_cache) { + update_cache($result); +} + +echo $result; +exit(0); function create_url() { global $config; @@ -92,14 +131,20 @@ function create_url() { return $base . $ip . $port . $root; } -function tautulli_get_user($email) { +function tautulli_get_user($input) { global $connection; global $config; + global $arrContextOptions; $url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_users"; - $response = json_decode(file_get_contents($url)); + + if($config->ssl) { + $response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions))); + } else { + $response = json_decode(file_get_contents($url)); + } for ($i = 0; $i < count($response->response->data); $i++) { - if ($response->response->data[$i]->email == $email) { + if ($response->response->data[$i]->email == $input || $response->response->data[$i]->username == $input) { return $response->response->data[$i]->user_id; } } @@ -109,8 +154,15 @@ function tautulli_get_user($email) { function tautulli_get_name($id) { global $connection; global $config; + global $arrContextOptions; $url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_user_ips&user_id=" . $id; - $response = json_decode(file_get_contents($url)); + + if($config->ssl) { + $response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions))); + } else { + $response = json_decode(file_get_contents($url)); + } + $name = $response->response->data->data[0]->friendly_name; if($name != "" && $name != Null) { return $name; @@ -119,12 +171,63 @@ function tautulli_get_name($id) { } } +function check_cache() { + global $config; + global $id; + $cache = json_decode(file_get_contents("../config/cache.json")); + + if(!empty($cache)) { + for($i = 0; $i < count($cache); $i++) { + if($cache[$i]->user->id == $id) { + return $cache[$i]; + } + } + } + + return False; +} + +function update_cache($result) { + global $config; + $cache = json_decode(file_get_contents("../config/cache.json")); + $decode_result = json_decode($result); + $found = False; + + if(!empty($cache)) { + for($i = 0; $i < count($cache); $i++) { + if($cache[$i]->user->id == $decode_result->user->id && !$found) { + $cache[$i] = $decode_result; + $found = True; + break; + } + } + } else { + $cache = array(); + } + + if(!$found) { + array_push($cache, $decode_result); + } + + $save = json_encode($cache); + file_put_contents("../config/cache.json", $save); + return True; +} + function tautulli_get_user_movies($id) { global $connection; global $config; global $library_id_movies; + global $arrContextOptions; + $url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_history&user_id=" . $id . "§ion_id=" . $library_id_movies . "&order_column=date&order_dir=desc&include_activity=0&length=" . $config->tautulli_length . ""; - $response = json_decode(file_get_contents($url)); + + if($config->ssl) { + $response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions))); + } else { + $response = json_decode(file_get_contents($url)); + } + $array = $response->response->data->data; $movies = array(); $movies_percent_complete = array(); @@ -205,8 +308,16 @@ function tautulli_get_user_shows($id) { global $connection; global $config; global $library_id_shows; + global $arrContextOptions; + $url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_history&user_id=" . $id . "§ion_id=" . $library_id_shows . "&order_column=date&order_dir=desc&include_activity=0&length=" . $config->tautulli_length . ""; - $response = json_decode(file_get_contents($url)); + + if($config->ssl) { + $response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions))); + } else { + $response = json_decode(file_get_contents($url)); + } + $array = $response->response->data->data; $shows = array(); @@ -248,9 +359,20 @@ function tautulli_get_user_show_buddy($id, $shows) { global $config; global $library_id_shows; global $name; + global $arrContextOptions; + $url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_history§ion_id=" . $library_id_shows . "&order_column=date&include_activity=0&media_type=episode&order_dir=desc&length=" . $config->tautulli_length . "&search=" . urlencode($shows[0]["title"]); - $response = json_decode(file_get_contents($url)); + + if($config->ssl) { + $response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions))); + } else { + $response = json_decode(file_get_contents($url)); + } + $array = $response->response->data->data; + if(empty($array)) { + $array = array(); + } $top_show_users = array(); for ($i = 0; $i < count($array); $i++) { @@ -298,7 +420,7 @@ function tautulli_get_user_show_buddy($id, $shows) { } } else { - $buddy = array("user" => False, "duration" => 0, found => False, "watched_relative_to_you" => False); + $buddy = array("user" => False, "duration" => 0, "found" => False, "watched_relative_to_you" => False); } return $buddy; @@ -309,8 +431,16 @@ function tautulli_get_year_stats($id) { global $config; global $library_id_shows; global $name; + global $arrContextOptions; + $url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_history&media_type=movie&include_activity=0&order_column=date&order_dir=desc&length=" . $config->tautulli_length; - $response = json_decode(file_get_contents($url)); + + if($config->ssl) { + $response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions))); + } else { + $response = json_decode(file_get_contents($url)); + } + $array = $response->response->data->data; $users = array(); $movies = array(); @@ -361,7 +491,13 @@ function tautulli_get_year_stats($id) { } $url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_history&media_type=episode&include_activity=0&order_column=date&order_dir=desc&length=" . $config->tautulli_length; - $response = json_decode(file_get_contents($url)); + + if($config->ssl) { + $response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions))); + } else { + $response = json_decode(file_get_contents($url)); + } + $array = $response->response->data->data; for ($i = 0; $i < count($array); $i++) { diff --git a/api/set_config.php b/api/set_config.php new file mode 100644 index 0000000..6e9e15a --- /dev/null +++ b/api/set_config.php @@ -0,0 +1,56 @@ +data; +} else { + echo json_encode(array("error" => true, "message" => "No input provided.")); + exit(0); +} +$password = htmlspecialchars($data->password); + +if(empty($config->password)) { + save_config(); + exit(0); +} + +if(password_verify($password, $config->password)) { + save_config(); + exit(0); +} else { + echo json_encode(array("error" => true, "message" => "Password not accepted.", "password" => true)); + exit(0); +} + +function save_config() { + global $data; + global $config_data; + global $config; + global $path; + global $path2; + + if(!empty($config_data->password)) { + $hash = password_hash($config_data->password, PASSWORD_DEFAULT); + $config_data->password = $hash; + } else { + $config_data->password = $config->password; + } + + if(file_put_contents($path, json_encode($config_data))) { + + if($data->clear_cache) { + file_put_contents($path2, ""); + } + + echo json_encode(array("error" => false, "message" => "Changes saved.")); + exit(0); + + } else { + echo json_encode(array("error" => true, "message" => "Changes were not saved.")); + exit(0); + } +} +?> \ No newline at end of file diff --git a/assets/css/wrapped.css b/assets/css/wrapped.css index f03e15a..317bfc3 100644 --- a/assets/css/wrapped.css +++ b/assets/css/wrapped.css @@ -4,48 +4,58 @@ body { margin: auto; font-family: 'Roboto', serif; font-weight: normal; + background: #a2d1d0; + box-sizing: border-box; } h1{ - font-size: 3em; - color: #f9a825; - text-shadow: 1px 1px 2px #555; - line-height: 110%; - text-align: center; - padding: 0; - margin: 0; - text-overflow: clip; - overflow: hidden; + font-size: 3em; + color: white; + text-shadow: 1px 1px 2px #555; + line-height: 110%; + text-align: center; + padding: 0; + margin: 0; } h2{ - font-size: 2em; - color: black; - line-height: 110%; - text-align: center; - margin: 0; + text-shadow: 1px 1px 2px #555; + font-size: 2em; + color: white; + line-height: 110%; + text-align: center; + margin: 0; + font-weight: normal; } h3{ - color: white; - text-shadow: 1px 1px 2px #555; - line-height: 110%; - text-align: center; - font-family: 'Roboto', serif; - font-size: 1.5em; - text-overflow: clip; + text-shadow: 1px 1px 2px #555; + color: white; + text-shadow: 1px 1px 2px #555; + line-height: 110%; + text-align: center; + font-family: 'Roboto', serif; + font-size: 1.5em; + text-overflow: clip; } h4{ - margin: auto; - text-align: center; - text-shadow: 0; + font-size: 1.5em; + margin: auto; + text-align: center; + font-weight: normal; + color: white; } p{ - font-size: 1em; - color: black; - text-align: center; + text-shadow: 1px 1px 2px #555; + font-size: 1.25em; + color: #ffffff; + text-align: center; +} + +img { + max-width: 100%; } .tittel { @@ -60,14 +70,16 @@ p{ width: 100%; margin: 0; padding: 0; + box-sizing: border-box; } .boks { margin: auto; - height: 100%; + min-height: 50em; width: 100%; align-items: center; text-align: center; + box-sizing: border-box; } .boks2 { @@ -75,18 +87,21 @@ p{ max-width: 100%; float: left; margin: auto; - margin-bottom: 2.5em; - margin-top: 2.5em; position: relative; vertical-align: top; + box-sizing: border-box; + padding: 2em; + display: inline-block; } .boks3 { - width: 60em; + width: 70em; + box-sizing: border-box; max-width: 100%; display: inline-block; margin: auto; position: relative; + display: inline-block; vertical-align: top; } @@ -143,16 +158,34 @@ p{ display: inline-block; margin: auto; box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.19); - background-color: #f2f2f2; + background-color: lightslategrey; border-radius: 25px; padding: 0.5em; - max-width: 25em; + width: 100%; top: 0; + color: white; + font-size: 1.25em; + box-sizing: border-box; + max-width: 100%; } -#search_get { - padding: 0.25em; +.stats-list { + max-height: 55em; + overflow-x: hidden; + overflow-y: auto; + scrollbar-width: thin; +} + +.status-title { + font-size: 1.25em; + padding: 0.5em; +} + +.button { + padding: 0.5em; + margin: 0.5em; font-family: 'Roboto', serif; + font-size: 1.25em; background-color: #f9a825; box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2); align-self: center; @@ -184,15 +217,34 @@ p{ width: 90%; margin: 0.5em; text-align: center; + border-radius: 25px; + border: none; + height: 2em; } .item:hover { - background-color: white !important; + background-color: #54606d !important; border-radius: 25px; } .item { - padding: 0.25em; + padding: 0.5em; + display: flex; +} + +.gold { + background-color: #d4af37; + border-radius: 25px; +} + +.silver { + background-color: #C0C0C0 ; + border-radius: 25px; +} + +.bronze { + background-color: #cd7f32; + border-radius: 25px; } .list { @@ -214,8 +266,9 @@ p{ text-align: right; margin: 0.1em; display: inline-block; - width: 1em; + width: 10%; vertical-align: top; + float: left; } .info { @@ -230,12 +283,16 @@ p{ text-align: right; margin: 0.1em; display: inline-block; - width: 8em; + width: 90%; vertical: center; text-overflow: ellipsis; vertical-align: top; } +.you { + text-decoration: underline; +} + .movie_name { width: 90%; text-align: right; @@ -263,3 +320,36 @@ p{ text-align: left; padding: 0.5em; } + +form { + padding: 0; +} + +.form-control { + font-size: 1em; + padding: 0.5em; + margin: auto; + width: 100%; + display: inline-block; + box-sizing: border-box; + text-align: center; + border-radius: 0.25em; + border: none; +} + +.form-group { + display: inline-block; + margin: auto; + float: left; + padding: 1em; + width: 100%; + box-sizing: border-box; +} + +.btn { + background-color: #ffbd55; + border: none; +} +input[type="checkbox" i] { + transform: scale(1.5); +} \ No newline at end of file diff --git a/assets/img/achievement.png b/assets/img/achievement.png new file mode 100644 index 0000000..18f799d Binary files /dev/null and b/assets/img/achievement.png differ diff --git a/assets/img/awards.svg b/assets/img/awards.svg new file mode 100644 index 0000000..ef42d8a --- /dev/null +++ b/assets/img/awards.svg @@ -0,0 +1,362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/banner.png b/assets/img/banner.png new file mode 100644 index 0000000..6f4c434 Binary files /dev/null and b/assets/img/banner.png differ diff --git a/assets/img/bored.svg b/assets/img/bored.svg new file mode 100644 index 0000000..61cac0a --- /dev/null +++ b/assets/img/bored.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/champion.svg b/assets/img/champion.svg new file mode 100644 index 0000000..8dad38a --- /dev/null +++ b/assets/img/champion.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/chef.jpg b/assets/img/chef.jpg new file mode 100644 index 0000000..437e020 Binary files /dev/null and b/assets/img/chef.jpg differ diff --git a/assets/img/finished-illustration.svg b/assets/img/finished-illustration.svg new file mode 100644 index 0000000..e497530 --- /dev/null +++ b/assets/img/finished-illustration.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/gift.svg b/assets/img/gift.svg new file mode 100644 index 0000000..e4063c9 --- /dev/null +++ b/assets/img/gift.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/home.svg b/assets/img/home.svg new file mode 100644 index 0000000..42706f4 --- /dev/null +++ b/assets/img/home.svg @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/logo_black.png b/assets/img/logo_black.png new file mode 100644 index 0000000..c1d6d2b Binary files /dev/null and b/assets/img/logo_black.png differ diff --git a/assets/img/logo_white.png b/assets/img/logo_white.png new file mode 100644 index 0000000..a202368 Binary files /dev/null and b/assets/img/logo_white.png differ diff --git a/assets/img/logo_white_shadow.png b/assets/img/logo_white_shadow.png new file mode 100644 index 0000000..0c05157 Binary files /dev/null and b/assets/img/logo_white_shadow.png differ diff --git a/assets/img/new-years.svg b/assets/img/new-years.svg new file mode 100644 index 0000000..7afe1f0 --- /dev/null +++ b/assets/img/new-years.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/old-man.svg b/assets/img/old-man.svg new file mode 100644 index 0000000..315876e --- /dev/null +++ b/assets/img/old-man.svg @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/plex_logo.png b/assets/img/plex_logo.png new file mode 100644 index 0000000..d70dff8 Binary files /dev/null and b/assets/img/plex_logo.png differ diff --git a/assets/img/quest.svg b/assets/img/quest.svg new file mode 100644 index 0000000..0cf2948 --- /dev/null +++ b/assets/img/quest.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/social-event.svg b/assets/img/social-event.svg new file mode 100644 index 0000000..2b0982f --- /dev/null +++ b/assets/img/social-event.svg @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/streaming.jpg b/assets/img/streaming.jpg new file mode 100644 index 0000000..01fcdf1 Binary files /dev/null and b/assets/img/streaming.jpg differ diff --git a/assets/img/watching-tv.svg b/assets/img/watching-tv.svg new file mode 100644 index 0000000..0eab5f5 --- /dev/null +++ b/assets/img/watching-tv.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/caching.html b/caching.html new file mode 100644 index 0000000..a0c43cb --- /dev/null +++ b/caching.html @@ -0,0 +1,71 @@ + + + + + + + + Plex Wrapped + + + + + + + + + + + +
+ +
+ +
+ +
+ +
+ +
+ +
+

+ If you want to decrease loadtime for your users you can pre-cache their results. +

Remember to configure the system first. +

+
+ +
+ +
+ +

Wrapped Caching

+ + + +
+
+ +
+
+
+
+ + + + + + diff --git a/caching.js b/caching.js new file mode 100644 index 0000000..d4ecb30 --- /dev/null +++ b/caching.js @@ -0,0 +1,191 @@ +var cached = 0; +var input_array; + +function search_box() { + var html = ` +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + +
+ +
+ `; + + document.getElementById('cache').innerHTML = html; +} + +$(document).on('submit', '#stats_form', function(){ + + cache(); + +}); + +function cache() { + var timeout_input = document.getElementById('timeout').value * 1000; + var input = document.getElementById('p_identity_multiple').value; + input_array = input.split(','); + + var html = ` +
+ +
+ +
+ +

Caching results

+ +
+
+ + +
+ `; + + document.getElementById('cache').innerHTML = html; + + call_stats(0, timeout_input); +} +function call_stats(i, timeout_input) { + get_stats(input_array[i].trim()); + + if(i < input_array.length-1) { + setTimeout(function(){ + i += 1; + call_stats(i, timeout_input); + }, timeout_input); + } + + +} + +function cache_log(p_identity, result) { + if(result) { + document.getElementById('cache_results').innerHTML += '

' + p_identity + '

'; + } else { + document.getElementById('cache_results').innerHTML += '

' + p_identity + '

'; + } + + cached += 1; + + if(cached == input_array.length) { + document.getElementById('loading_icon').style.display = "none"; + } +} + +function get_stats(p_identity) { + + stats_form = { + "p_identity" : p_identity + }; + + var stats_data = JSON.stringify(stats_form); + + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + var result = JSON.parse(this.responseText); + + if(result.error) { + cache_log(p_identity, false); + } else { + cache_log(p_identity, true); + } + } + }; + xhttp.withCredentials = true; + xhttp.open("post", "api/get_stats.php", ); + xhttp.send(stats_data); + return; +} + +function topFunction() { + document.body.scrollTop = 0; // For Safari + document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera +} + +function get_config_cache() { + + config_form = { + "password" : "" + }; + + var config_data = JSON.stringify(config_form); + + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + var result = JSON.parse(this.responseText); + if(result.password) { + login_menu(); + } else { + alert(result.message); + } + } + }; + xhttp.withCredentials = true; + xhttp.open("post", "api/get_config.php"); + xhttp.send(config_data); +} + +function get_config() { + + current_password = document.getElementById('password').value; + + config_form = { + "password" : current_password + }; + + var config_data = JSON.stringify(config_form); + + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + var result = JSON.parse(this.responseText); + if(result.error) { + alert(result.message); + } else { + if(!result.data.use_cache) { + alert("You have disabled cache in the configuration!"); + } + search_box(); + } + } + }; + xhttp.withCredentials = true; + xhttp.open("post", "api/get_config.php"); + xhttp.send(config_data); +} + +function login_menu() { + topFunction(); + var html = '
' + + html += '
'; + html += ''; + html += ''; + html += '
'; + + html += '
'; + html += ''; + html += '
'; + + html += '
'; + document.getElementById("cache").innerHTML = html; +} \ No newline at end of file diff --git a/config/.htaccess b/config/.htaccess new file mode 100644 index 0000000..f239fe8 --- /dev/null +++ b/config/.htaccess @@ -0,0 +1,2 @@ +order deny,allow +deny from all \ No newline at end of file diff --git a/get_config.js b/get_config.js new file mode 100644 index 0000000..48351f0 --- /dev/null +++ b/get_config.js @@ -0,0 +1,78 @@ +function get_config_initial() { + + config_form = { + "password" : "" + }; + + var config_data = JSON.stringify(config_form); + + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + var result = JSON.parse(this.responseText); + if(result.password) { + login_menu(); + } else { + first_time = true; + + set_password(); + } + } + }; + xhttp.withCredentials = true; + xhttp.open("post", "api/get_config.php"); + xhttp.send(config_data); +} + +function get_config() { + + current_password = document.getElementById('password').value; + + config_form = { + "password" : current_password + }; + + var config_data = JSON.stringify(config_form); + + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + var result = JSON.parse(this.responseText); + if(result.error) { + alert(result.message); + } else { + tautulli_apikey = result.data.tautulli_apikey; + tautulli_ip = result.data.tautulli_ip; + tautulli_port = result.data.tautulli_port; + tautulli_length = result.data.tautulli_length; + tautulli_root = result.data.tautulli_root; + + ssl = result.data.ssl; + + password = ""; + + library_id_movies = result.data.library_id_movies; + library_id_shows = result.data.library_id_shows; + + wrapped_start = new Date(0); + wrapped_start.setUTCSeconds(result.data.wrapped_start); + + wrapped_end = new Date(0); + wrapped_end.setUTCSeconds(result.data.wrapped_end); + + get_user_movie_stats = result.data.get_user_movie_stats; + get_user_show_stats = result.data.get_user_show_stats; + get_user_show_buddy = result.data.get_user_show_buddy; + get_year_stats = result.data.get_year_stats; + + use_cache = result.data.use_cache; + cache_age_limit = result.data.cache_age_limit; + + set_tautulli(true); + } + } + }; + xhttp.withCredentials = true; + xhttp.open("post", "api/get_config.php"); + xhttp.send(config_data); +} \ No newline at end of file diff --git a/get_functions.js b/get_functions.js new file mode 100644 index 0000000..9b960d7 --- /dev/null +++ b/get_functions.js @@ -0,0 +1,22 @@ +function get_functions() { + + config_form = {}; + + var config_data = JSON.stringify(config_form); + + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + var result = JSON.parse(this.responseText); + if(result.error) { + document.getElementById('results_error').innerHTML = '

' + result.message + '

'; + } else { + functions = result; + get_stats(); + } + } + }; + xhttp.withCredentials = true; + xhttp.open("post", "api/get_functions.php"); + xhttp.send(config_data); +} \ No newline at end of file diff --git a/get_stats.js b/get_stats.js index 64a8daf..86edb91 100644 --- a/get_stats.js +++ b/get_stats.js @@ -1,32 +1,43 @@ -var results; -var loading_icon = document.getElementById("loading_icon"); +function get_stats() { + var results; + var functions; + var loading_icon = document.getElementById("loading_icon"); -var p_email = document.getElementById("p_email").value; + var p_identity = document.getElementById("p_identity").value; -var p_email = p_email.replace(/[&\/\\#,+()$~%:*?<>{}]/g, ''); + //var p_identity = p_identity.replace(/[&\/\\#,+()$~%:*?<>{}]/g, ''); -stats_form = { - "p_email" : p_email - }; + stats_form = { + "p_identity" : p_identity + }; -var stats_data = JSON.stringify(stats_form); + var stats_data = JSON.stringify(stats_form); -var xhttp = new XMLHttpRequest(); -xhttp.onreadystatechange = function() { - if (this.readyState == 4 && this.status == 200) { - load_page(this.responseText); - } -}; -xhttp.withCredentials = true; -xhttp.open("post", "api/get_stats.php"); -xhttp.send(stats_data); + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + var result = JSON.parse(this.responseText); + if(result.error) { + loading_icon.style.display = "none"; + search_button("SEARCH"); + document.getElementById('results_error').innerHTML = '

' + result.message + '

'; -loading_icon.style.display = "inline"; + } else { + load_page(this.responseText); + } + } + }; + xhttp.withCredentials = true; + xhttp.open("post", "api/get_stats.php"); + xhttp.send(stats_data); + + loading_icon.style.display = "inline"; +} function load_page(data){ results = JSON.parse(data); - if(results.error == "true") { + if(results.error) { $('#results_error').html(results.message); loading_icon.style.display = "none"; search_button("SEARCH"); @@ -34,162 +45,405 @@ function load_page(data){ } var search_box = document.getElementById("search_input"); + var login_content = document.getElementById("login_content"); search_box.style.display = "none"; + login_content.style.display = "none"; + load_introduction(); + + if(!results.user.user_movies.error && functions.get_user_movie_stats) { + load_movies(); + } + if(!results.user.user_shows.error && functions.get_user_show_stats) { + load_shows(); + } + + if(!results.year_stats.error && functions.get_year_stats) { + load_users(); + } + + + load_outro(); +} +//INTRODUCTION +function load_introduction() { var text = ""; - - //INTRODUCTION - text += "
"; - text += "

Hey there, " + results.user.name + "!

"; - text += "

2020 kinda sucked, but hopefully you watched some cool stuff...

" - text += "

"; - - //MOVIES - text += "
"; - text += "

Let's look at some movies."; - text += "


You watched " + results.user.user_movies.data.movies.length + " movies. That's a lot of movies!


(or not, I am pre-programmed to say that)" - text += "

"; + text += "
"; text += "
"; - text += "
"; - text += "
"; - text += "
"; - text += "

Your top 10 movies in 2020

"; - for(i = 0; (i < results.user.user_movies.data.movies.length && i < 10); i++) { - text += "
"; - text += "
"; - text += i+1 + ". "; - text += "
"; - text += "
"; - text += results.user.user_movies.data.movies[i].title; - var movie_hour = time_hours(results.user.user_movies.data.movies[i].duration) - text += " (" + results.user.user_movies.data.movies[i].year + ")
" + movie_hour[0] + " hours, " + movie_hour[1] + " minutes
" + results.user.user_movies.data.movies[i].plays + " plays"; - text += "
"; - text += "
"; - } - text += "
"; - text += "
"; + text += "
"; + text += ''; text += "
"; text += "
"; - text += "
"; - text += "
"; - var str = JSON.stringify(results.user.user_movies.data.user_movie_finishing_percent); - var percent = str.split('.'); - text += "

Your average movie finishing percentage in 2020 was " + percent[0] + "%

"; - text += "
You're not watching the credits like a nerd, are you?"; - text += "
"; - text += "
"; - text += "
"; - - text += "
"; - text += "
"; - text += "
"; - text += "Your longest movie pause was watching

" + results.user.user_movies.data.user_movie_most_paused.title + " (" + results.user.user_movies.data.user_movie_most_paused.year + ")

"; - var str = JSON.stringify(results.user.user_movies.data.user_movie_most_paused.paused_counter / 60); - var minutes = str.split('.'); - text += "
It was paused for " + minutes[0] + " minutes..."; - text += "
"; - text += "
"; - text += "
"; - - text += "
"; - text += "
"; - text += "
"; - text += "The oldest movie you watched was

" + results.user.user_movies.data.user_movie_oldest.title + " (" + results.user.user_movies.data.user_movie_oldest.year + ")

"; - text += "
Enjoying the classics, huh?"; - text += "
"; - text += "
"; - text += "
"; - - var sum = 0; - for(i = 0; (i < results.user.user_movies.data.movies.length); i++) { - sum += results.user.user_movies.data.movies[i].duration; - } - var sum_split = time_hours(sum); - text += "
"; - text += "
"; - text += "
"; - text += "You spent

" + sum_split[0] + " hours and " + sum_split[1] + " minutes

"; - text += " watching movies"; - text += "
"; - text += "
"; + text += "
"; + text += "

Hey there, " + results.user.name + "!

"; + text += "



"; + text += "

New year, new page of statistics...

"; text += "
"; text += "
"; + text += "
"; - //SHOWS - text += "
"; - text += "

Now, let's have a look at some shows!"; - text += "


You watched " + results.user.user_shows.data.shows.length + " different shows.


(No, watching The Office twice in a year doesn't count as two shows)" - text += "

"; + document.getElementById("search_results").innerHTML += text; +} - text += "
"; - text += "
"; - text += "
"; - text += "
"; - text += "

Your top 10 shows in 2020

"; - for(i = 0; (i < results.user.user_shows.data.shows.length && i < 10); i++) { - text += "
"; - text += "
"; - text += i+1 + ". "; - text += "
"; +//MOVIES +function load_movies() { + var text = ""; - text += "
"; - text += results.user.user_shows.data.shows[i].title; - var show_hour = time_hours(results.user.user_shows.data.shows[i].duration) - text += "
" + show_hour[0] + " hours, " + show_hour[1] + " minutes
" + results.user.user_shows.data.shows[i].plays + " plays"; - text += "
"; + if(results.user.user_movies.data.movies.length > 1) { + + text += "
"; + + text += "
"; + text += "

Let's look at some movies.

"; + text += "


"; + text += "

You watched " + results.user.user_movies.data.movies.length + " movies. That's a lot of movies!

(or not, I am pre-programmed to say that)

" + + text += "

"; + text += "
"; + + text += "
"; + text += "
"; + text += "
"; + text += "
"; + text += "
Your top movies
"; + text += "
"; + for(i = 0; (i < results.user.user_movies.data.movies.length && i < 10); i++) { + text += "
"; + text += "
"; + text += i+1 + ". "; + text += "
"; + + text += "
"; + text += results.user.user_movies.data.movies[i].title; + var movie_hour = time_hours(results.user.user_movies.data.movies[i].duration) + text += " (" + results.user.user_movies.data.movies[i].year + ")
" + movie_hour[0] + " hours, " + movie_hour[1] + " minutes
" + results.user.user_movies.data.movies[i].plays + " plays"; + text += "
"; + text += "
"; + } + text += "
"; + text += "
"; + text += "
"; + text += "
"; + + text += "
"; + text += "
"; + text += "
"; + var str = JSON.stringify(results.user.user_movies.data.user_movie_finishing_percent); + var percent = str.split('.'); + text += "Your average movie finishing percentage was " + percent[0] + "%"; + if(percent[0] > 89) { + text += '

'; + } + text += "

You're not watching the credits like a nerd, are you?"; + text += "
"; + text += "
"; + text += "
"; + + text += "
"; + text += "
"; + + var str = JSON.stringify(results.user.user_movies.data.user_movie_most_paused.paused_counter / 60); + var minutes = str.split('.'); + + if(minutes[0] > 0) { + text += "
"; + text += "Your longest movie pause was watching
" + results.user.user_movies.data.user_movie_most_paused.title + " (" + results.user.user_movies.data.user_movie_most_paused.year + ")"; + + text += "

It was paused for " + minutes[0] + " minutes..."; + text += "
"; + } else { + text += "
"; + text += "Bladder of steel"; + text += '

'; + text += "
You never paused a single movie."; text += "
"; } text += "
"; text += "
"; - text += "
"; - if(results.user.user_shows.data.shows.length > 0) { text += "
"; text += "
"; text += "
"; - text += "

Your top show was " + results.user.user_shows.data.shows[0].title + "


"; - var buddy_error = JSON.stringify(results.user.user_shows.data.show_buddy.error); - if(buddy_error == "true") { - text += "
That means you're a hipster, because you're the only viewer of that show in 2020 😎"; + text += "The oldest movie you watched was
" + results.user.user_movies.data.user_movie_oldest.title + " (" + results.user.user_movies.data.user_movie_oldest.year + ")
"; + if(results.user.user_movies.data.user_movie_oldest.year < 1950) { + text += "
I didn't even know they made movies back then."; + text += '

'; + } else if(results.user.user_movies.data.user_movie_oldest.year < 1975) { + text += "
Did it even have color?"; + text += '

'; + } else if(results.user.user_movies.data.user_movie_oldest.year < 2000) { + text += "
Was it a 4K, UHD, 3D, Dolby Atmos remaster?"; } else { - text += "And you're not alone! Your " + results.user.user_shows.data.shows[0].title + "-buddy is "; - text += "" + results.user.user_shows.data.show_buddy.user.user + "!

"; - var combined = results.user.user_shows.data.show_buddy.user.duration + parseInt(results.user.user_shows.data.shows[0].duration); - var combined_2 = time_hours(combined); - text += "Your combined efforts resulted in " + combined_2[0] + " hours and " + combined_2[1] + " minutes of " + results.user.user_shows.data.shows[0].title + "!

😎"; + text += "
Enjoying the classics, huh?"; } text += "
"; text += "
"; text += "
"; - } - var sum = 0; - for(i = 0; (i < results.user.user_shows.data.shows.length); i++) { - sum += results.user.user_shows.data.shows[i].duration; - } - var sum_split = time_hours(sum); - text += "
"; - text += "
"; - text += "
"; - text += "You spent

" + sum_split[0] + " hours and " + sum_split[1] + " minutes

"; - text += " watching shows"; + var sum = 0; + for(i = 0; (i < results.user.user_movies.data.movies.length); i++) { + sum += results.user.user_movies.data.movies[i].duration; + } + var sum_split = time_hours(sum); + text += "
"; + text += "
"; + text += "
"; + text += "You spent " + sum_split[0] + " hours and " + sum_split[1] + " minutes"; + text += " watching movies"; + text += '
'; + text += "
"; text += "
"; text += "
"; + + text += "
"; + text += "
"; + + } else if(results.user.user_movies.data.movies.length == 1) { + + text += "
"; + + text += "
"; + text += "

Let's look at some movies.

"; + text += "


"; + text += "

You watched " + results.user.user_movies.data.movies.length + " movie. You know what you like!

(at least you tried it out)

"; + text += "

"; + text += "
"; + + text += "
"; + text += "
"; + text += "
"; + text += "
"; + text += "
Your movie
"; + text += "
"; + for(i = 0; (i < results.user.user_movies.data.movies.length && i < 10); i++) { + text += "
"; + text += "
"; + text += i+1 + ". "; + text += "
"; + + text += "
"; + text += results.user.user_movies.data.movies[i].title; + var movie_hour = time_hours(results.user.user_movies.data.movies[i].duration) + text += " (" + results.user.user_movies.data.movies[i].year + ")
" + movie_hour[0] + " hours, " + movie_hour[1] + " minutes
" + results.user.user_movies.data.movies[i].plays + " plays"; + text += "
"; + text += "
"; + } + text += "
"; + text += "
"; + text += "
"; + text += "
"; + + text += "
"; + text += "
"; + text += "
"; + var str = JSON.stringify(results.user.user_movies.data.user_movie_finishing_percent); + var percent = str.split('.'); + text += "Your saw " + percent[0] + "%"; + if(percent[0] > 89) { + text += '

'; + } + text += "

You're not watching the credits like a nerd, are you?"; + text += "
"; + text += "
"; + text += "
"; + + text += "
"; + text += "
"; + + var str = JSON.stringify(results.user.user_movies.data.user_movie_most_paused.paused_counter / 60); + var minutes = str.split('.'); + + if(minutes[0] > 0) { + text += "
"; + text += "Your longest movie pause was watching
" + results.user.user_movies.data.user_movie_most_paused.title + " (" + results.user.user_movies.data.user_movie_most_paused.year + ")"; + + text += "

It was paused for " + minutes[0] + " minutes..."; + text += "
"; + } else { + text += "
"; + text += "Bladder of steel"; + text += '

'; + text += "
You never paused the movie."; + text += "
"; + } + text += "
"; + text += "
"; + + text += "
"; + text += "
"; + + } else { + + text += "
"; + + text += "
"; + text += "
"; + text += "

Let's look at some movies.

"; + text += "


"; + text += "

You watched " + results.user.user_movies.data.movies.length + " movies. That's impressive in itself!

(might wanna try it out)

" + text += ''; + text += "
"; text += "
"; + text += "
"; + } + document.getElementById("search_results").innerHTML += text; +} + +//SHOWS +function load_shows() { + var text = ""; + + if(results.user.user_shows.data.shows.length > 1) { + text += "
"; + text += "

Now, let's have a look at some shows!

"; + text += "


You watched " + results.user.user_shows.data.shows.length + " different shows.

(No, watching The Office twice in a year doesn't count as two shows)

" + text += "

"; + + text += "
"; + text += "
"; + text += "
"; + text += "
"; + text += "
Your top shows
"; + text += "
"; + for(i = 0; (i < results.user.user_shows.data.shows.length && i < 10); i++) { + text += "
"; + text += "
"; + text += i+1 + ". "; + text += "
"; + + text += "
"; + text += results.user.user_shows.data.shows[i].title; + var show_hour = time_hours(results.user.user_shows.data.shows[i].duration) + text += "
" + show_hour[0] + " hours, " + show_hour[1] + " minutes
" + results.user.user_shows.data.shows[i].plays + " plays"; + text += "
"; + text += "
"; + } + text += "
"; + text += "
"; + text += "
"; + text += "
"; + + if(results.user.user_shows.data.shows.length > 0 && !results.year_stats.error && functions.get_user_show_buddy) { + text += "
"; + text += load_showbuddy(); + text += "
"; + } + + var sum = 0; + for(i = 0; (i < results.user.user_shows.data.shows.length); i++) { + sum += results.user.user_shows.data.shows[i].duration; + } + var sum_split = time_hours(sum); + text += "
"; + text += "
"; + text += "
"; + text += "You spent " + sum_split[0] + " hours and " + sum_split[1] + " minutes"; + text += " watching shows"; + text += '
'; + text += "
"; + text += "
"; + text += "
"; + + text += "
"; text += "
"; - text += "
"; + } else if(results.user.user_shows.data.shows.length == 1) { - //TOP USERS - text += "
"; - text += "

Finally, let's look at the top users, movies and shows in 2020!"; - text += "



It's okay to feel shame if you are on the list.

(or missing from it...)" + text += "
"; + text += "

Now, let's have a look at some shows!

"; + text += "


You watched " + results.user.user_shows.data.shows.length + " show.

(Better not be that same one again...)

" + text += "

"; + + text += "
"; + text += "
"; + text += "
"; + text += "
"; + text += "
Your show
"; + text += "
"; + for(i = 0; (i < results.user.user_shows.data.shows.length && i < 10); i++) { + text += "
"; + text += "
"; + text += i+1 + ". "; + text += "
"; + + text += "
"; + text += results.user.user_shows.data.shows[i].title; + var show_hour = time_hours(results.user.user_shows.data.shows[i].duration) + text += "
" + show_hour[0] + " hours, " + show_hour[1] + " minutes
" + results.user.user_shows.data.shows[i].plays + " plays"; + text += "
"; + text += "
"; + } + text += "
"; + text += "
"; + text += "
"; + text += "
"; + + if(results.user.user_shows.data.shows.length > 0) { + text += "
"; + + text += load_showbuddy(); + + text += "
"; + } + + text += "
"; + text += "
"; + + } else { + + text += "
"; + + text += "
"; + text += "
"; + text += "

Now, let's have a look at some shows!

"; + text += "


"; + text += "

You watched " + results.user.user_shows.data.shows.length + " shows. I get it, it's not for everyone!

(might wanna try it out)

" + text += ''; + text += "
"; + text += "
"; + + text += "
"; + } + + document.getElementById("search_results").innerHTML += text; +} + +function load_showbuddy() { + var html = ""; + html += "
"; + html += "
"; + html += "Your show was " + results.user.user_shows.data.shows[0].title + "
"; + if(!results.user.user_shows.data.show_buddy.error) { + if(!results.user.user_shows.data.show_buddy.user.found) { + html += '
'; + html += "
That means you dared to explore where no one else would, because you're the only viewer of that show"; + } else { + html += "And you're not alone! Your " + results.user.user_shows.data.shows[0].title + "-buddy is "; + html += "" + results.user.user_shows.data.show_buddy.user.user + "!

"; + var combined = results.user.user_shows.data.show_buddy.user.duration + parseInt(results.user.user_shows.data.shows[0].duration); + var combined_2 = time_hours(combined); + html += ''; + html += "
Your combined efforts resulted in " + combined_2[0] + " hours and " + combined_2[1] + " minutes of " + results.user.user_shows.data.shows[0].title + "!"; + } + } + html += "
"; + html += "
"; + return html; +} + +//TOP USERS +function load_users() { + var text = ""; + + text += "
"; + text += "

Finally, let's look at the top users, movies and shows!

"; + text += "



It's okay to feel shame if you are on the list.

(or missing from it...)

" text += "

"; text += "
"; @@ -197,18 +451,34 @@ function load_page(data){ text += "
"; text += "
"; text += "
"; - text += "

Top users from the past year

"; + text += "
Top users
"; + text += "
"; for(i = 0; i < 10 && i < results.year_stats.data.users.length; i++) { - text += "
"; + if(i == 0) { + text += "
"; + } else if(i == 1) { + text += "
"; + } else if(i == 2) { + text += "
"; + } else { + text += "
"; + } text += "
"; text += i+1 + ". "; text += "
"; - text += "
"; - text += results.year_stats.data.users[i].user; - text += "
"; + if(results.year_stats.data.users[i].user == results.user.name) { + text += "
"; + text += results.year_stats.data.users[i].user; + text += "
"; + }else { + text += "
"; + text += results.year_stats.data.users[i].user; + text += "
"; + } text += "
"; } + text += "
"; text += "
"; text += "
"; text += "
"; @@ -227,11 +497,12 @@ function load_page(data){ text += "
"; text += "
"; text += "
"; - text += "The users spent

" + sum_movies_split[0] + " days and " + sum_movies_split[1] + " hours

"; - text += " watching movies"; - text += "

And, the users spent

" + sum_shows_split[0] + " days and " + sum_shows_split[1] + " hours

"; - text += " watching shows"; - text += "

That is

" + Number(sum_shows_split[0] + sum_movies_split[0]) + " days and " + Number(sum_shows_split[1] + sum_movies_split[1]) + " hours

of content!"; + text += "All the different users combined spent " + sum_movies_split[0] + " days and " + sum_movies_split[1] + " hours"; + text += " watching movies."; + text += "

And, the users spent " + sum_shows_split[0] + " days and " + sum_shows_split[1] + " hours"; + text += " watching shows."; + text += "

That is " + Number(sum_shows_split[0] + sum_movies_split[0]) + " days and " + Number(sum_shows_split[1] + sum_movies_split[1]) + " hours
of content!"; + text += ''; text += "
"; text += "
"; text += "
"; @@ -242,7 +513,8 @@ function load_page(data){ text += "
"; text += "
"; text += "
"; - text += "

Top movies from the past year

"; + text += "
Top movies
"; + text += "
"; for(i = 0; i < 10 && i < results.year_stats.data.top_movies.length; i++) { text += "
"; text += "
"; @@ -256,6 +528,7 @@ function load_page(data){ text += "
"; text += "
"; } + text += '
'; text += "
"; text += "
"; text += "
"; @@ -263,7 +536,8 @@ function load_page(data){ text += "
"; text += "
"; text += "
"; - text += "

Top shows from the past year

"; + text += "
Top shows
"; + text += "
"; for(i = 0; i < 10 && i < results.year_stats.data.top_shows.length; i++) { text += "
"; text += "
"; @@ -277,6 +551,7 @@ function load_page(data){ text += "
"; text += "
"; } + text += '
'; text += "
"; text += "
"; text += "
"; @@ -284,12 +559,23 @@ function load_page(data){ text += "
"; text += "
"; + document.getElementById("search_results").innerHTML += text; +} - //Goobye - text += "
"; - text += "

Hope you are staying safe!



Goodybye.

"; +//Outro +function load_outro() { + var text = ""; + + text += "
"; + text += "
"; + text += "
"; + text += ''; + text += "
"; + text += "
"; + text += "

Hope you are staying safe!



Goodybye.

"; + text += "
"; + text += "
"; text += "
"; - $('#search_results').html(text); - + document.getElementById("search_results").innerHTML += text; } \ No newline at end of file diff --git a/index.html b/index.html index c05ad7e..966e35b 100644 --- a/index.html +++ b/index.html @@ -12,27 +12,37 @@ + + + -
+
-
+ +
+ +
+ +
+
-

Your year on Plex

-

- Did you get that thing from Spotify and wondered what your Plex statistics were? -

Well, have a look... -

+

+ Did you get that thing from Spotify and wondered what your Plex statistics looked like? +

Well, have a look... +


-
+
+ +

Plex Wrapped

-
+
@@ -77,8 +88,7 @@ $(document).ready(function() { - $.getScript("index.js", function(){ - }); + }); diff --git a/index.js b/index.js index 44d44d7..877b18f 100644 --- a/index.js +++ b/index.js @@ -69,7 +69,6 @@ $(document).on('submit', '#stats_form', function(){ search_button("SEARCHING..."); - $.getScript("get_stats.js", function(){ - }); + get_functions(); }); diff --git a/set_config.js b/set_config.js new file mode 100644 index 0000000..dc70a4a --- /dev/null +++ b/set_config.js @@ -0,0 +1,46 @@ +function set_config() { + + var clear_cache = document.getElementById('clear_cache').checked; + + config_form = { + "password" : current_password, + "clear_cache" : clear_cache, + "data" : { + "tautulli_apikey" : tautulli_apikey, + "tautulli_ip" : tautulli_ip, + "tautulli_port" : tautulli_port, + "tautulli_length" : tautulli_length, + "tautulli_root" : tautulli_root, + "ssl" : ssl, + "password" : password, + "library_id_movies" : library_id_movies, + "library_id_shows" : library_id_shows, + "wrapped_start" : Math.round(wrapped_start.getTime() / 1000), + "wrapped_end" : Math.round(wrapped_end.getTime() / 1000), + "get_user_movie_stats" : get_user_movie_stats, + "get_user_show_stats" : get_user_show_stats, + "get_user_show_buddy" : get_user_show_buddy, + "get_year_stats" : get_year_stats, + "use_cache" : use_cache, + "cache_age_limit" : cache_age_limit + } + }; + + var config_data = JSON.stringify(config_form); + + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + var result = JSON.parse(this.responseText); + if(result.error) { + alert(result.message); + } else { + alert(result.message); + window.location.href = "./"; + } + } + }; + xhttp.withCredentials = true; + xhttp.open("post", "api/set_config.php"); + xhttp.send(config_data); +} \ No newline at end of file