Added music, more options, fixed logs

Music can now be added as stats.
More options on admin page
More dynamic building of stats with the new options considered
Fixed bug where test connection button malfunctioned because of no log-settings
This commit is contained in:
aunefyren 2021-10-02 01:21:18 +02:00
parent 3d148e8e35
commit 5284af5029
10 changed files with 541 additions and 160 deletions

View file

@ -7,6 +7,7 @@ A website-based platform and API for collecting Plex user stats within a set tim
### Features
- Custom timeframes
- Movies, shows & music
- Caching of results
- Friendly, dynamic display for statistics with nice illustrations
- Email and username search

View file

@ -61,7 +61,7 @@ var first_time = false;
var tautulli_apikey = "";
var tautulli_ip = "";
var tautulli_port = "";
var tautulli_length = 50000;
var tautulli_length = 5000;
var tautulli_root = "";
var ssl = false;
@ -70,6 +70,7 @@ var password = "";
var library_id_movies = "";
var library_id_shows = "";
var library_id_music = "";
var wrapped_start = new Date(0);
wrapped_start.setUTCSeconds(1609455600);
@ -80,7 +81,12 @@ wrapped_end.setUTCSeconds(1640991540);
var get_user_movie_stats = true;
var get_user_show_stats = true;
var get_user_show_buddy = true;
var get_year_stats = true;
var get_user_music_stats = true;
var get_year_stats_movies = true;
var get_year_stats_shows = true;
var get_year_stats_music = true;
var get_year_stats_leaderboard = true;
var use_cache = true;
var cache_age_limit = 7;

View file

@ -149,7 +149,7 @@ function set_tautulli(back) {
html += '</div>';
html += '<div class="form-group">';
html += '<label for="ssl" title="Enable if your connection uses HTTPS.">Use SSL (optional)</label>';
html += '<label for="ssl" title="Enable if your connection uses HTTPS.">Use SSL</label>';
html += '<input type="checkbox" class="form-control" id="ssl" ';
if(ssl) {
html += 'checked="' + ssl + '" ';
@ -158,13 +158,18 @@ function set_tautulli(back) {
html += '</div>';
html += '<div class="form-group">';
html += '<label for="library_id_movies" title="The ID for your chosen movie library in Tautulli. Can be found by going to Tautulli->Libraries->Your library. The ID is the URL as section_id.">ID for movie-library in Tautulli</label>';
html += '<input type="number" min="0" class="form-control" id="library_id_movies" value="' + library_id_movies + '" autocomplete="off" required placeholder="1" /><br>';
html += '<label for="library_id_movies" title="The ID for your chosen movie library in Tautulli. Can be found by going to Tautulli->Libraries->Your library. The ID is the URL as section_id.">ID for movie-library in Tautulli (optional)</label>';
html += '<input type="number" min="0" class="form-control" id="library_id_movies" value="' + library_id_movies + '" autocomplete="off" placeholder="1" /><br>';
html += '</div>';
html += '<div class="form-group">';
html += '<label for="library_id_shows" title="The ID for your chosen show library in Tautulli. Can be found by going to Tautulli->Libraries->Your library. The ID is the URL as section_id.">ID for show-library in Tautulli</label>';
html += '<input type="number" min="0" class="form-control" id="library_id_shows" value="' + library_id_shows + '" autocomplete="off" required placeholder="2" /><br> ';
html += '<label for="library_id_shows" title="The ID for your chosen show library in Tautulli. Can be found by going to Tautulli->Libraries->Your library. The ID is the URL as section_id.">ID for show-library in Tautulli (optional)</label>';
html += '<input type="number" min="0" class="form-control" id="library_id_shows" value="' + library_id_shows + '" autocomplete="off" placeholder="2" /><br> ';
html += '</div>';
html += '<div class="form-group">';
html += '<label for="library_id_music" title="The ID for your chosen music library in Tautulli. Can be found by going to Tautulli->Libraries->Your library. The ID is the URL as section_id.">ID for music-library in Tautulli (optional)</label>';
html += '<input type="number" min="0" class="form-control" id="library_id_music" value="' + library_id_music + '" autocomplete="off" placeholder="3" /><br> ';
html += '</div>';
html += '<div class="form-group">';
@ -191,6 +196,7 @@ function set_tautulli_details(back) {
ssl = document.getElementById('ssl').checked;
library_id_movies = document.getElementById('library_id_movies').value;
library_id_shows = document.getElementById('library_id_shows').value;
library_id_music = document.getElementById('library_id_music').value;
}
var html = '<div class="form-group">';
html += '<button class="form-control btn" onclick="set_tautulli(true, false)">Tautulli settings</button>';
@ -233,7 +239,7 @@ function set_tautulli_details(back) {
html += '</div>';
html += '<div class="form-group">';
html += '<label for="get_user_movie_stats" title="Includes movie statistics in your wrapped period.">Get users movie statistics (optional)<br>';
html += '<label for="get_user_movie_stats" title="Includes movie statistics in your wrapped period.">Get users movie statistics<br>';
html += '<input type="checkbox" class="form-control" id="get_user_movie_stats" ';
if(get_user_movie_stats) {
html += 'checked="' + get_user_movie_stats + '" ';
@ -242,7 +248,7 @@ function set_tautulli_details(back) {
html += '</div>';
html += '<div class="form-group">';
html += '<label for="get_user_show_stats" title="Includes show statistics in your wrapped period.">Get users show statistics (optional)<br>';
html += '<label for="get_user_show_stats" title="Includes show statistics in your wrapped period.">Get users show statistics<br>';
html += '<input type="checkbox" class="form-control" id="get_user_show_stats" ';
if(get_user_show_stats) {
html += 'checked="' + get_user_show_stats + '" ';
@ -251,7 +257,7 @@ function set_tautulli_details(back) {
html += '</div>';
html += '<div class="form-group">';
html += '<label for="get_user_show_buddy" title="Includes the users top show-buddy in your wrapped period. Requires show stats.">Get users show-buddy (optional)<br>';
html += '<label for="get_user_show_buddy" title="Includes the users top show-buddy in your wrapped period. Requires show stats.">Get users show-buddy<br>';
html += '<input type="checkbox" class="form-control" id="get_user_show_buddy" ';
if(get_user_show_buddy) {
html += 'checked="' + get_user_show_buddy + '" ';
@ -260,16 +266,52 @@ function set_tautulli_details(back) {
html += '</div>';
html += '<div class="form-group">';
html += '<label for="get_year_stats" title="Includes server-wide statistics in your wrapped period.">Get server-wide statistics (optional)<br>';
html += '<input type="checkbox" class="form-control" id="get_year_stats" ';
if(get_year_stats) {
html += 'checked="' + get_year_stats + '" ';
html += '<label for="get_user_music_stats" title="Includes music statistics in your wrapped period.">Get users music statistics<br>';
html += '<input type="checkbox" class="form-control" id="get_user_music_stats" ';
if(get_user_music_stats) {
html += 'checked="' + get_user_music_stats + '" ';
}
html += '/><br>';
html += '</div>';
html += '<div class="form-group">';
html += '<label for="get_year_stats_movies" title="Includes server-wide movie statistics in your wrapped period.">Get server-wide movie statistics<br>';
html += '<input type="checkbox" class="form-control" id="get_year_stats_movies" ';
if(get_year_stats_movies) {
html += 'checked="' + get_year_stats_movies + '" ';
}
html += '/><br>';
html += '</div>';
html += '<div class="form-group">';
html += '<label for="get_year_stats_shows" title="Includes server-wide show statistics in your wrapped period.">Get server-wide show statistics<br>';
html += '<input type="checkbox" class="form-control" id="get_year_stats_shows" ';
if(get_year_stats_shows) {
html += 'checked="' + get_year_stats_shows + '" ';
}
html += '/><br>';
html += '</div>';
html += '<div class="form-group">';
html += '<label for="get_year_stats_music" title="Includes server-wide music statistics in your wrapped period.">Get server-wide music statistics<br>';
html += '<input type="checkbox" class="form-control" id="get_year_stats_music" ';
if(get_year_stats_music) {
html += 'checked="' + get_year_stats_music + '" ';
}
html += '/><br>';
html += '</div>';
html += '<div class="form-group">';
html += '<label for="get_year_stats_leaderboard" title="Creates a user leaderboard based on the server-wide statistics in your wrapped period.">Get server-wide leaderboard rankings<br>';
html += '<input type="checkbox" class="form-control" id="get_year_stats_leaderboard" ';
if(get_year_stats_leaderboard) {
html += 'checked="' + get_year_stats_leaderboard + '" ';
}
html += '/><br>';
html += '</div>';
html += '<div class="form-group">';
html += '<label for="use_logs" title="Logs every API request into a log-file in the config folder. ID for Wrapped request included.">Log API calls (optional)<br>';
html += '<label for="use_logs" title="Logs every API request into a log-file in the config folder. ID for Wrapped request included.">Log API calls<br>';
html += '<input type="checkbox" class="form-control" id="use_logs" ';
if(use_logs) {
html += 'checked="' + use_logs + '" ';
@ -278,7 +320,7 @@ function set_tautulli_details(back) {
html += '</div>';
html += '<div class="form-group">';
html += '<label for="use_cache" title="Caches your results in cache.json for later use.">Cache results for later use (optional)<br>';
html += '<label for="use_cache" title="Caches your results in cache.json for later use.">Cache results for later use<br>';
html += '<input type="checkbox" class="form-control" id="use_cache" ';
if(use_cache) {
html += 'checked="' + use_cache + '" ';
@ -292,7 +334,7 @@ function set_tautulli_details(back) {
html += '</div>';
html += '<div class="form-group" title="Clear the cache now to include the newest settings.">';
html += '<label for="clear_cache">Clear cache now (optional)<br>';
html += '<label for="clear_cache">Clear cache now<br>';
html += '<input type="checkbox" class="form-control" id="clear_cache" checked /></label>';
html += '</div>';
@ -364,7 +406,11 @@ function set_tautulli_last(back) {
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;
get_user_music_stats = document.getElementById('get_user_music_stats').checked;
get_year_stats_movies = document.getElementById('get_year_stats_movies').checked;
get_year_stats_shows = document.getElementById('get_year_stats_shows').checked;
get_year_stats_music = document.getElementById('get_year_stats_music').checked;
get_year_stats_leaderboard = document.getElementById('get_year_stats_leaderboard').checked;
use_cache = document.getElementById('use_cache').checked;
use_logs = document.getElementById('use_logs').checked;
cache_age_limit = document.getElementById('cache_age_limit').value;

View file

@ -8,7 +8,7 @@ if(empty($data)) {
}
// Log API request if enabled
if($config->use_logs) {
if(empty($config) || $config->use_logs) {
if(!log_activity()) {
echo json_encode(array("message" => "Failed to log event.", "error" => true));
exit(0);

View file

@ -15,7 +15,11 @@ if (empty($config)) {
$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
"get_user_music_stats" => $config->get_user_music_stats,
"get_year_stats_movies" => $config->get_year_stats_movies,
"get_year_stats_shows" => $config->get_year_stats_shows,
"get_year_stats_music" => $config->get_year_stats_music,
"get_year_stats_leaderboard" => $config->get_year_stats_leaderboard
);
// Log API request if enabled

View file

@ -22,6 +22,7 @@ if (empty($config)) {
// Libraries for movies and shows
$library_id_movies = $config->library_id_movies;
$library_id_shows = $config->library_id_shows;
$library_id_music = $config->library_id_music;
//Base-URL for connections
$connection = create_url();
@ -90,7 +91,13 @@ if($config->get_user_show_buddy && $config->get_user_show_stats && !empty($user_
$user_shows["data"] = $user_shows["data"] + array("show_buddy" => array("message" => "Disabled in config.", "error" => True));
}
if($config->get_year_stats) {
if($config->get_user_music_stats) {
$user_music = array("data" => tautulli_get_user_music($id), "message" => "Success. User music-stats are loaded.", "error" => False);
} else {
$user_music = array("error" => True, "message" => "Disabled in config.");
}
if($config->get_year_stats_movies || $config->get_year_stats_shows || $config->get_year_stats_music) {
if($config->use_cache) {
$year_stats = array("data" => tautulli_get_year_stats_cache($id), "error" => False, "message" => "Year stats are loaded.");
} else {
@ -109,7 +116,8 @@ $result = json_encode(array("error" => False,
"user" => array("name" => $name,
"id" => $id,
"user_movies" => $user_movies,
"user_shows" => $user_shows
"user_shows" => $user_shows,
"user_music" => $user_music
),
"year_stats" => $year_stats,
));
@ -269,6 +277,56 @@ function log_activity($id) {
return False;
}
function tautulli_get_user_music($id) {
global $connection;
global $config;
global $library_id_music;
global $arrContextOptions;
$url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_history&user_id=" . $id . '&section_id=' . $library_id_music . "&media_type=track&order_column=date&order_dir=desc&include_activity=0&length=" . $config->tautulli_length . "";
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;
$tracks = array();
for ($i = 0; $i < count($array); $i++) {
if($array[$i]->date > $config->wrapped_end) {
continue;
} else if ($array[$i]->date < $config->wrapped_start) {
break;
}
if($array[$i]->title == "" || $array[$i]->grandparent_title == "" || $array[$i]->parent_title == "") {
continue;
}
$found = False;
for ($j = 0; $j < count($tracks); $j++) {
if($array[$i]->title == $tracks[$j]["title"] && $array[$i]->parent_title == $tracks[$j]["parent_title"] && $array[$i]->grandparent_title == $tracks[$j]["grandparent_title"]) {
$tracks[$j]["plays"] = intval($tracks[$j]["plays"]) + 1;
$tracks[$j]["duration"] = intval($tracks[$j]["duration"]) + $array[$i]->duration;
break;
}
}
if(!$found) {
array_push($tracks, array("title" => $array[$i]->title, "parent_title" => $array[$i]->parent_title, "grandparent_title" => $array[$i]->grandparent_title, "plays" => 1, "duration" => $array[$i]->duration, "year" => $array[$i]->year, "rating_key" => $array[$i]->rating_key, "parent_rating_key" => $array[$i]->parent_rating_key, "grandparent_rating_key" => $array[$i]->grandparent_rating_key));
}
}
// Sort $tracks for longest pause
$duration = array_column($tracks, 'duration');
array_multisort($duration, SORT_DESC, $tracks);
return array("music" => $tracks);
}
function tautulli_get_user_movies($id) {
global $connection;
global $config;
@ -503,128 +561,223 @@ function tautulli_get_year_stats_cache($id) {
function tautulli_get_year_stats($id) {
global $connection;
global $config;
global $library_id_shows;
global $library_id_movies;
global $library_id_shows;
global $library_id_music;
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;
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();
$users = array();
$movies = array();
$shows = array();
$tracks = array();
for ($i = 0; $i < count($array); $i++) {
if(intval($array[$i]->date) > $config->wrapped_end) {
continue;
} else if(intval($array[$i]->date) < $config->wrapped_start) {
break;
$earliest_date_movies = 999999999999;
$earliest_date_shows = 999999999999;
$earliest_date_tracks = 999999999999;
if($config->get_year_stats_movies) {
//GET MOVIES
$url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_history&section_id=" . $library_id_movies . "&media_type=movie&include_activity=0&order_column=date&order_dir=desc&length=" . $config->tautulli_length;
if($config->ssl) {
$response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions)));
} else {
$response = json_decode(file_get_contents($url));
}
$title = $array[$i]->full_title;
$duration = $array[$i]->duration;
$user = $array[$i]->friendly_name;
$user_id = $array[$i]->user_id;
$year = $array[$i]->year;
$array = $response->response->data->data;
$user_found = False;
$movie_found = False;
for ($j = 0; $j < count($users); $j++) {
if($users[$j]["id"] == $user_id) {
$users[$j]["duration_movies"] = intval($users[$j]["duration_movies"]) + intval($duration);
$users[$j]["duration"] = intval($users[$j]["duration"]) + intval($duration);
$users[$j]["plays"] = intval($users[$j]["plays"]) + 1;
$user_found = True;
for ($i = 0; $i < count($array); $i++) {
if(intval($array[$i]->date) > $config->wrapped_end) {
continue;
} else if(intval($array[$i]->date) < $config->wrapped_start) {
break;
}
$title = $array[$i]->full_title;
$duration = $array[$i]->duration;
$user = $array[$i]->friendly_name;
$user_id = $array[$i]->user_id;
$year = $array[$i]->year;
$user_found = False;
$movie_found = False;
if($array[$i]->date < $earliest_date_movies) {
$earliest_date_movies = $array[$i]->date;
}
for ($j = 0; $j < count($users); $j++) {
if($users[$j]["id"] == $user_id) {
$users[$j]["duration"] = intval($users[$j]["duration"]) + intval($duration);
$users[$j]["duration_movies"] = intval($users[$j]["duration_movies"]) + intval($duration);
$users[$j]["plays"] = intval($users[$j]["plays"]) + 1;
$user_found = True;
break;
}
}
if(!$user_found) {
array_push($users, array("user" => $user, "id" => $user_id, "duration" => $duration, "duration_movies" => $duration, "duration_shows" => 0, "duration_artists" => 0, "plays" => 1));
}
for ($j = 0; $j < count($movies); $j++) {
if($movies[$j]["title"] == $title && $movies[$j]["year"] == $year) {
$movies[$j]["duration"] = intval($movies[$j]["duration"]) + intval($duration);
$movies[$j]["plays"] = intval($movies[$j]["plays"]) + 1;
$movie_found = True;
break;
}
}
if(!$movie_found) {
array_push($movies, array("title" => $title, "year" => $year, "duration" => $duration, "plays" => 1));
}
}
if(!$user_found) {
array_push($users, array("user" => $user, "id" => $user_id, "duration" => $duration, "duration_movies" => $duration, "duration_shows" => 0, "plays" => 1));
}
// Sort movies by duration
$duration = array_column($movies, 'duration');
array_multisort($duration, SORT_DESC, $movies);
for ($j = 0; $j < count($movies); $j++) {
if($movies[$j]["title"] == $title && $movies[$j]["year"] == $year) {
$movies[$j]["duration"] = intval($movies[$j]["duration"]) + intval($duration);
$movies[$j]["plays"] = intval($movies[$j]["plays"]) + 1;
$movie_found = True;
break;
}
}
if(!$movie_found) {
array_push($movies, array("title" => $title, "year" => $year, "duration" => $duration, "plays" => 1));
}
}
$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;
if($config->ssl) {
$response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions)));
} else {
$response = json_decode(file_get_contents($url));
$movies = array("message" => "Disabled in config.", "error" => True);
}
$array = $response->response->data->data;
if($config->get_year_stats_shows) {
//GET EPISODES
$url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_history&section_id=" . $library_id_shows . "&media_type=episode&include_activity=0&order_column=date&order_dir=desc&length=" . $config->tautulli_length;
for ($i = 0; $i < count($array); $i++) {
if(intval($array[$i]->date) > $config->wrapped_end) {
continue;
} else if(intval($array[$i]->date) < $config->wrapped_start) {
break;
if($config->ssl) {
$response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions)));
} else {
$response = json_decode(file_get_contents($url));
}
$title = $array[$i]->grandparent_title;
$duration = $array[$i]->duration;
$user = $array[$i]->friendly_name;
$user_id = $array[$i]->user_id;
$year = $array[$i]->year;
$array = $response->response->data->data;
$user_found = False;
$show_found = False;
for ($j = 0; $j < count($users); $j++) {
if($users[$j]["id"] == $user_id) {
$users[$j]["duration_shows"] = intval($users[$j]["duration_shows"]) + intval($duration);
$users[$j]["duration"] = intval($users[$j]["duration"]) + intval($duration);
$users[$j]["plays"] = intval($users[$j]["plays"]) + 1;
$user_found = True;
for ($i = 0; $i < count($array); $i++) {
if(intval($array[$i]->date) > $config->wrapped_end) {
continue;
} else if(intval($array[$i]->date) < $config->wrapped_start) {
break;
}
$title = $array[$i]->grandparent_title;
$duration = $array[$i]->duration;
$user = $array[$i]->friendly_name;
$user_id = $array[$i]->user_id;
$year = $array[$i]->year;
$user_found = False;
$show_found = False;
if($array[$i]->date < $earliest_date_shows) {
$earliest_date_shows = $array[$i]->date;
}
for ($j = 0; $j < count($users); $j++) {
if($users[$j]["id"] == $user_id) {
$users[$j]["duration"] = intval($users[$j]["duration"]) + intval($duration);
$users[$j]["duration_shows"] = intval($users[$j]["duration_shows"]) + intval($duration);
$users[$j]["plays"] = intval($users[$j]["plays"]) + 1;
$user_found = True;
break;
}
}
if(!$user_found) {
array_push($users, array("user" => $user, "id" => $user_id, "duration" => $duration, "duration_movies" => 0, "duration_shows" => $duration, "duration_artists" => 0, "plays" => 1));
}
for ($j = 0; $j < count($shows); $j++) {
if($shows[$j]["title"] == $title) {
$shows[$j]["duration"] = intval($shows[$j]["duration"]) + intval($duration);
$shows[$j]["plays"] = intval($shows[$j]["plays"]) + 1;
$show_found = True;
break;
}
}
if(!$show_found) {
array_push($shows, array("title" => $title, "year" => $year, "duration" => $duration, "plays" => 1));
}
}
if(!$user_found) {
array_push($users, array("user" => $user, "id" => $user_id, "duration" => $duration, "duration_movies" => 0, "duration_shows" => $duration, "plays" => 1));
}
// Sort shows by duration
$duration = array_column($shows, 'duration');
array_multisort($duration, SORT_DESC, $shows);
for ($j = 0; $j < count($shows); $j++) {
if($shows[$j]["title"] == $title) {
$shows[$j]["duration"] = intval($shows[$j]["duration"]) + intval($duration);
$shows[$j]["plays"] = intval($shows[$j]["plays"]) + 1;
$show_found = True;
break;
}
}
if(!$show_found) {
array_push($shows, array("title" => $title, "duration" => $duration, "plays" => 1));
}
} else {
$shows = array("message" => "Disabled in config.", "error" => True);
}
// Sort movies by duration
$duration = array_column($movies, 'duration');
array_multisort($duration, SORT_DESC, $movies);
if($config->get_year_stats_shows) {
//GET TRACKS
$url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_history&section_id=" . $library_id_music . "&media_type=track&include_activity=0&order_column=date&order_dir=desc&length=" . $config->tautulli_length;
// Sort movies by duration
$duration = array_column($shows, 'duration');
array_multisort($duration, SORT_DESC, $shows);
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++) {
if($array[$i]->date > $config->wrapped_end) {
continue;
} else if ($array[$i]->date < $config->wrapped_start) {
break;
}
if($array[$i]->title == "" || $array[$i]->grandparent_title == "" || $array[$i]->parent_title == "") {
continue;
}
$user_found = False;
$artist_found = False;
if($array[$i]->date < $earliest_date_tracks) {
$earliest_date_tracks = $array[$i]->date;
}
for ($j = 0; $j < count($users); $j++) {
if($users[$j]["id"] == $array[$i]->user_id) {
$users[$j]["duration"] = intval($users[$j]["duration"]) + $array[$i]->duration;
$users[$j]["duration_artists"] = intval($users[$j]["duration_artists"]) + $array[$i]->duration;
$users[$j]["plays"] = intval($users[$j]["plays"]) + 1;
$user_found = True;
break;
}
}
if(!$user_found) {
array_push($users, array("user" => $$array[$i]->friendly_name, "id" => $array[$i]->user_id, "duration" => $array[$i]->duration, "duration_movies" => 0, "duration_shows" => 0, "duration_artists" => $array[$i]->duration, "plays" => 1));
}
for ($j = 0; $j < count($tracks); $j++) {
if($array[$i]->title == $tracks[$j]["title"] && $array[$i]->parent_title == $tracks[$j]["parent_title"] && $array[$i]->grandparent_title == $tracks[$j]["grandparent_title"]) {
$tracks[$j]["plays"] = intval($tracks[$j]["plays"]) + 1;
$tracks[$j]["duration"] = intval($tracks[$j]["duration"]) + $array[$i]->duration;
break;
}
}
if(!$artist_found) {
array_push($tracks, array("title" => $array[$i]->title, "parent_title" => $array[$i]->parent_title, "grandparent_title" => $array[$i]->grandparent_title, "plays" => 1, "duration" => $array[$i]->duration, "year" => $array[$i]->year, "rating_key" => $array[$i]->rating_key, "parent_rating_key" => $array[$i]->parent_rating_key, "grandparent_rating_key" => $array[$i]->grandparent_rating_key));
}
}
// Sort tracks by duration
$duration = array_column($tracks, 'duration');
array_multisort($duration, SORT_DESC, $tracks);
} else {
$tracks = array("message" => "Disabled in config.", "error" => True);
}
// Sort users by combined duration
$duration = array_column($users, 'duration');
@ -632,6 +785,6 @@ function tautulli_get_year_stats($id) {
$now = new DateTime('NOW');
return array("origin_date" => $now->format('Y-m-d'), "top_movies" => $movies, "users" => $users, "top_shows" => $shows);
return array("origin_date" => $now->format('Y-m-d'), "top_movies" => $movies, "top_movies_earliest" => $earliest_date_movies, "users" => $users, "top_shows" => $shows, "top_show_earliest" => $earliest_date_shows, "top_artists" => $tracks, "top_artists_earliest" => $earliest_date_tracks);
}
?>

View file

@ -182,7 +182,7 @@ img {
}
.stats-list {
max-height: 60em;
max-height: 75em;
overflow-x: hidden;
overflow-y: auto;
scrollbar-width: thin;

View file

@ -55,6 +55,7 @@ function get_config() {
library_id_movies = result.data.library_id_movies;
library_id_shows = result.data.library_id_shows;
library_id_music = result.data.library_id_music;
wrapped_start = new Date(0);
wrapped_start.setUTCSeconds(result.data.wrapped_start);
@ -65,7 +66,12 @@ function get_config() {
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;
get_user_music_stats = result.data.get_user_music_stats;
get_year_stats_movies = result.data.get_year_stats_movies;
get_year_stats_shows = result.data.get_year_stats_shows;
get_year_stats_music = result.data.get_year_stats_music;
get_year_stats_leaderboard = result.data.get_year_stats_leaderboard;
use_cache = result.data.use_cache;
use_logs = result.data.use_logs;

View file

@ -56,11 +56,16 @@ function load_page(data){
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.user.user_music.error && functions.get_user_music_stats) {
load_music();
}
if(!results.year_stats.error && functions.get_year_stats) {
if(!results.year_stats.error && (functions.get_year_stats_movies || functions.get_year_stats_shows || functions.get_year_stats_music)) {
load_users();
}
@ -110,7 +115,7 @@ function load_movies() {
text += "<div class='boks3'>";
text += "<div class='boks2'>";
text += top_list(results.user.user_movies.data.movies, "Your top movies");
text += top_list(results.user.user_movies.data.movies, "Your top movies", false, true);
text += "</div>";
text += "<div class='boks2' style='padding: 0;'>";
@ -155,7 +160,7 @@ function load_movies() {
text += "<div class='boks3'>";
text += "<div class='boks2'>";
text += top_list(results.user.user_movies.data.movies, "Your movie");
text += top_list(results.user.user_movies.data.movies, "Your movie", false, true);
text += "</div>";
text += "<div class='boks2' style='padding: 0;'>";
@ -206,7 +211,7 @@ function load_shows() {
text += "<div class='boks3'>";
text += "<div class='boks2'>";
text += top_list(results.user.user_shows.data.shows, "Your top shows");
text += top_list(results.user.user_shows.data.shows, "Your top shows", false, true);
text += "</div>";
text += "<div class='boks2' style='padding: 0;'>";
@ -243,7 +248,7 @@ function load_shows() {
text += "<div class='boks3'>";
text += "<div class='boks2'>";
text += top_list(results.user.user_shows.data.shows, "Your show");
text += top_list(results.user.user_shows.data.shows, "Your show", false, true);
text += "</div>";
if(results.user.user_shows.data.shows.length > 0 && !results.user.user_shows.data.show_buddy.error && functions.get_user_show_buddy) {
@ -274,6 +279,85 @@ function load_shows() {
document.getElementById("search_results").innerHTML += text;
}
//MUSIC
function load_music() {
var text = "";
var albums = [];
var artists = [];
for(var i = 0; i < results.user.user_music.data.music.length; i++) {
var found = false;
for(var j = 0; j < albums.length; j++) {
if(albums[j].title == results.user.user_music.data.music[i].parent_title && albums[j].grandparent_title == results.user.user_music.data.music[i].grandparent_title) {
albums[j]["plays"] = albums[j].plays + 1;
albums[j]["duration"] = results.user.user_music.data.music[i].duration + albums[j].duration;
found = true;
break;
}
}
if(!found && results.user.user_music.data.music[i].parent_title != "" && results.user.user_music.data.music[i].grandparent_title != "") {
albums.push({"title" : results.user.user_music.data.music[i].parent_title, "parent_rating_key" : results.user.user_music.data.music[i].parent_rating_key,"grandparent_title" : results.user.user_music.data.music[i].grandparent_title, "plays" : 1, "duration" : results.user.user_music.data.music[i].duration});
}
}
albums.sort(function(a, b) {
return parseFloat(b.duration) - parseFloat(a.duration);
});
for(var i = 0; i < results.user.user_music.data.music.length; i++) {
var found = false;
for(var j = 0; j < artists.length; j++) {
if(artists[j].title == results.user.user_music.data.music[i].grandparent_title) {
artists[j]["plays"] = artists[j].plays + 1;
artists[j]["duration"] = results.user.user_music.data.music[i].duration + artists[j].duration;
found = true;
break;
}
}
if(!found && results.user.user_music.data.music[i].grandparent_title != "") {
artists.push({"title" : results.user.user_music.data.music[i].grandparent_title, "grandparent_rating_key" : results.user.user_music.data.music[i].grandparent_rating_key, "plays" : 1, "duration" : results.user.user_music.data.music[i].duration});
}
}
artists.sort(function(a, b) {
return parseFloat(b.duration) - parseFloat(a.duration);
});
if(results.user.user_music.data.music.length > 1) {
text += "<div class='boks' style='height: auto !important; width: 100%; padding-bottom: 25em; padding-top: 25em; height:10em; background-color:#CFA38C;'>";
text += "<div class='boks3'>";
text += "<h1>Music!</h1>";
text += "<br><br><br><h2>You listened to " + results.user.user_music.data.music.length + ' different tracks.</h2><p>(If you can call your taste "music"...)</p>'
text += "</div>";
text += "<div class='boks3'>";
text += "<div class='boks2'>";
text += top_list(results.user.user_music.data.music, "Your top tracks", true, false);
text += "</div>";
text += "<div class='boks2'>";
text += top_list(albums, "Your top albums", true, false);
text += "</div>";
text += "<div class='boks2'>";
text += top_list(artists, "Your top artists", false, false);
text += "</div>";
text += "</div>";
text += "</div>";
}
document.getElementById("search_results").innerHTML += text;
}
function oldest_movie(array) {
var html = "";
@ -388,9 +472,9 @@ function you_spent(time, category) {
return html;
}
function top_list(array, title) {
function top_list(array, title, music, year) {
var html = "";
html += "<div class='status' id='list3'>";
html += "<div class='stats'>";
html += "<div class='status-title'>" + title + "</div>";
@ -401,12 +485,18 @@ function top_list(array, title) {
html += i+1 + ". ";
html += "</div>";
html += "<div class='movie_name'><b>";
html += array[i].title;
html += "<div class='movie_name'>";
if(music) {
html+= array[i].grandparent_title + "<br>";
}
html += "<b>";
html += array[i].title;
html += "</b>";
var movie_hour = seconds_to_time(array[i].duration, true);
if(typeof(array[i].year) != "undefined") {
if(typeof(array[i].year) != "undefined" && year) {
html += " (" + array[i].year + ")";
}
@ -471,47 +561,117 @@ function load_users() {
text += "<div class='boks3'>";
text += "<div class='boks2'>";
text += top_list_names(results.year_stats.data.users, 'Top users');
text += "</div>";
if(functions.get_year_stats_leaderboard) {
var sum_movies = 0;
for(i = 0; (i < results.year_stats.data.top_movies.length); i++) {
sum_movies += results.year_stats.data.top_movies[i].duration;
}
text += "<div class='boks2'>";
text += top_list_names(results.year_stats.data.users, 'Top users');
text += "</div>";
var sum_shows = 0;
for(i = 0; (i < results.year_stats.data.top_shows.length); i++) {
sum_shows += results.year_stats.data.top_shows[i].duration;
}
var sum_movies = 0;
var sum_shows = 0;
var sum_artists = 0;
var time_movies = seconds_to_time(sum_movies, false);
var time_shows = seconds_to_time(sum_shows, false);
var time_all = seconds_to_time(Math.floor(sum_movies + sum_shows), false);
if(functions.get_year_stats_movies) {
for(i = 0; (i < results.year_stats.data.top_movies.length); i++) {
sum_movies += results.year_stats.data.top_movies[i].duration;
}
}
text += "<div class='boks2'>";
text += "<div class='status' id='list3' style='padding:1em;min-width:15em;'>";
text += "<div class='stats'>";
text += "All the different users combined spent <b>" + time_movies + "</b>";
text += " watching movies.";
text += "<br><br>And, the users spent <b>" + time_shows + "</b>";
text += " watching shows.";
text += "<br><br>That is <b>" + time_all + "</b><br>of content!";
text += '<img src="assets/img/home.svg" style="margin: auto; display: block; width: 15em;">';
if(functions.get_year_stats_shows) {
for(i = 0; (i < results.year_stats.data.top_shows.length); i++) {
sum_shows += results.year_stats.data.top_shows[i].duration;
}
}
if(functions.get_year_stats_music) {
for(i = 0; (i < results.year_stats.data.top_artists.length); i++) {
sum_artists += results.year_stats.data.top_artists[i].duration;
}
}
var time_movies = seconds_to_time(sum_movies, false);
var time_shows = seconds_to_time(sum_shows, false);
var time_artists = seconds_to_time(sum_artists, false);
var time_all = seconds_to_time(Math.floor(sum_movies + sum_shows + sum_artists), false);
text += "<div class='boks2'>";
text += "<div class='status' id='list3' style='padding:1em;min-width:15em;'>";
text += "<div class='stats'>";
if(functions.get_year_stats_movies) {
text += "All the different users combined spent <b>" + time_movies + "</b>";
text += " watching movies.";
text += "<br><br>";
}
if(functions.get_year_stats_shows) {
text += "All the different users combined spent <b>" + time_shows + "</b>";
text += " watching shows.";
text += "<br><br>";
}
if(functions.get_year_stats_music) {
text += "All the different users combined spent <b>" + time_artists + "</b>";
text += " listening to artists.";
text += "<br><br>";
}
if(functions.get_year_stats_movies && (functions.get_year_stats_shows || functions.get_year_stats_music) || (functions.get_year_stats_shows && functions.get_year_stats_music)) {
text += "That is <b>" + time_all + "</b><br>of content!";
}
text += '<img src="assets/img/home.svg" style="margin: auto; display: block; width: 15em;">';
text += "</div>";
text += "</div>";
text += "</div>";
text += "</div>";
}
text += "</div>";
text += "<div class='boks3'>";
text += "<div class='boks2'>";
text += top_list(results.year_stats.data.top_movies, "Top movies");
text += "</div>";
if(functions.get_year_stats_movies) {
text += "<div class='boks2'>";
text += top_list(results.year_stats.data.top_movies, "Top movies", false, true);
text += "</div>";
}
text += "<div class='boks2'>";
text += top_list(results.year_stats.data.top_shows, "Top shows");
text += "</div>";
if(functions.get_year_stats_shows) {
text += "<div class='boks2'>";
text += top_list(results.year_stats.data.top_shows, "Top shows", false, true);
text += "</div>";
}
if(functions.get_year_stats_music) {
var artists = [];
for(var i = 0; i < results.year_stats.data.top_artists.length; i++) {
var found = false;
for(var j = 0; j < artists.length; j++) {
if(artists[j].title == results.year_stats.data.top_artists[i].grandparent_title) {
artists[j]["plays"] = artists[j].plays + 1;
artists[j]["duration"] = results.year_stats.data.top_artists[i].duration + artists[j].duration;
found = true;
break;
}
}
if(!found && results.year_stats.data.top_artists[i].grandparent_title != "") {
artists.push({"title" : results.year_stats.data.top_artists[i].grandparent_title, "grandparent_rating_key" : results.year_stats.data.top_artists[i].grandparent_rating_key, "plays" : 1, "duration" : results.year_stats.data.top_artists[i].duration});
}
}
artists.sort(function(a, b) {
return parseFloat(b.duration) - parseFloat(a.duration);
});
text += "<div class='boks2'>";
text += top_list(artists, "Top artists", false, false);
text += "</div>";
}
text += "</div>";
text += "</div>";

View file

@ -15,12 +15,17 @@ function set_config() {
"password" : password,
"library_id_movies" : library_id_movies,
"library_id_shows" : library_id_shows,
"library_id_music" : library_id_music,
"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,
"get_user_music_stats" : get_user_music_stats,
"get_year_stats_movies" : get_year_stats_movies,
"get_year_stats_shows" : get_year_stats_shows,
"get_year_stats_music" : get_year_stats_music,
"get_year_stats_leaderboard" : get_year_stats_leaderboard,
"use_cache" : use_cache,
"use_logs" : use_logs,
"cache_age_limit" : cache_age_limit