Squashed commit of the following:

commit 03b7ce95646b8b4452bbf56849127d52a0f98474
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Tue Jan 11 14:32:22 2022 +0100

    Custom server-wide section

commit 1dce85dd0a7a7d8ad0a31eb8a11ad7fca2de4988
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Tue Jan 4 15:29:57 2022 +0100

    Link improvements

    - Links are deleted if made on different version
    - Links also carry Wrapperr settings for that link creation
    - Created links are shown on homepage
    - Links can be deleted on home page
    - CSS tweaks

commit 3c6a7eb05e7d1a4afda2239a8a98706827bf1f96
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Mon Jan 3 22:16:56 2022 +0100

    Music is now fully custom

commit edfca775004e43518d6258347a3e4c69c9e089a3
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Mon Jan 3 12:16:53 2022 +0100

    SHow buddy bug fix

commit e5a739631da9c34d8a7c2262bd96430f23d2ea12
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Mon Jan 3 12:05:35 2022 +0100

    Show section is now fully custom

commit 693eaec76951241a9ef0d76d8284169c87c25fdd
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sun Jan 2 19:56:50 2022 +0100

    Fixed movie completion image bug

commit ef2b49969fbbb593e207fabdea42fd2f3f849f42
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sun Jan 2 19:45:10 2022 +0100

    pop up issues on iOs

commit 1515db8c1b56ec95f2455df62a82ecdb45a56fac
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sun Jan 2 18:51:22 2022 +0100

    URL

commit b8add61a1652ae5d4de8527acf422ae2215adef8
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sun Jan 2 18:39:06 2022 +0100

    CSS overhaul for admin-page

commit 40e44fc5b1272d23e4fc6da3a59f9c06a339bcc7
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Thu Dec 30 18:55:47 2021 +0100

    100% custom movie section, sort buttons

commit 7accc2d006088127e80beebace3c8ac8f0c14960
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Thu Dec 23 15:59:04 2021 +0100

    Added sorting by plays

    And custom text for movie completion

commit 3f24b11fd116669e51fa0256e086f352d35c48b0
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Wed Dec 22 14:53:56 2021 +0100

    Application title CSS size

commit a8f19370d2ac5723fe397e1fe106e8cec49cd174
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Wed Dec 22 14:30:32 2021 +0100

    More custom text

    - Lists
    - Server-wide options

commit 847dd60483065516398e1d52fa209b54f240de01
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Tue Dec 21 14:33:27 2021 +0100

    Custom language options

    Change certain words for alternatives, such as plays, days and so on.

commit fe501ba9e3ffa6098d3c1869ef8a1580f10897be
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Tue Dec 21 13:01:15 2021 +0100

    Scrambling for answers

commit f99c2f2dff36a45cbe7ccf79d7a6f5ac39f21011
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Tue Dec 21 12:42:57 2021 +0100

    Cookie settings

commit 5efddfc9d77a69db62d8b979976c42d079c8b4a2
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Tue Dec 21 12:21:05 2021 +0100

    More headers

commit e1c106534cfbd2d0d62492e6c25a1efdb5a70325
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Tue Dec 21 11:52:11 2021 +0100

    Trying to fix CURL origin

commit f7a59ed8d21ad731913ba5f5259997361c8ffdbb
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Tue Dec 21 11:40:56 2021 +0100

    Color bug and headers

commit be604797524de5cb06c66eb593fecd563cbd6592
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Tue Dec 21 11:12:02 2021 +0100

    Admin stuff

    - Added new admin menu
    - Admin login session
    - Separate config categories
    - Added application URL and name
    - Config file builds using file, then adds default for variables not found. Less config deletions.
    - Admin is separate config to prevent stealing unconfigured platforms.
    - Moved caching to admin menu.
    - Caching in API requires admin login.
    - Added robots.txt for web crawlers.
    - New color palette
    - Renamed more stuff to Wrapperr

commit 5b62dbb2ef4f05d33e49f0ce7e12c147e2343f06
Merge: 84caa7b 67dcf77
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Mon Dec 13 12:51:09 2021 +0100

    Merge branch 'main' into develop

commit 84caa7b85f9036c7ca4cf2535f80bdf96aa120f6
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sun Dec 12 17:26:23 2021 +0100

    Disable pre-made links when changing config

    If you disable links in the config, already made links will stop working

commit 4ae03627594a821323fc20c1ad8bf1b8d5f8f1cb
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sun Dec 12 17:08:49 2021 +0100

    Button icons and button disabling

    Displays that a function is working in the background by disabling the button.

commit cc43d00fbc122cc681a008e6a736273540c10b3e
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sun Dec 12 16:43:33 2021 +0100

    Added version control

    - Release now dynamically displayed on pages
    - Configs are tagged with version and deleted when not compatible

commit a18c2515904a978cb0a85edbeecfb5baab81c2b6
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sat Dec 11 13:56:18 2021 +0100

    Option to disable links

commit d8f1b0ab09f5ed1cfbdc9a753be2bebd63c51e2c
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sat Dec 11 12:49:58 2021 +0100

    Plex Auth, shareable links, fancy colors

    v2.1.0 testing
    - Moved to class-system within PHP.
    - All wrapped requests now gathered and validated using Plex Auth #9
    - Session stored as browser cookie
    - Button icons
    - Colors fade between wrapped categories
    - Minutes count added for music above a certain sum #7
    - Ability to create shareable links valid for 7 days #14
    - HTML Input placeholders removed #10
    - Ability to specify Plex libraries #18

commit 23022d0090c267c46e95a818cd57639360e542bc
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sat Dec 4 23:02:16 2021 +0100

    Fixed caching

    Forgot to add global and variable to function

commit b5765f3094206406c8d2f20ffd36b0bad5ea0200
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sat Dec 4 22:58:48 2021 +0100

    Re-added caching mode

    Whops

commit 20ccd23ed9a04fa4b00e2994ab89a931d79f5a78
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sat Dec 4 22:52:38 2021 +0100

    Stats API mostly moved to new class format

commit a594447ffcd917d149078dd5c57d7e3f5a88bf1a
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sat Dec 4 16:17:48 2021 +0100

    Fixed login bug on caching

commit 9d303514ef080e9483f4753b7fc488da314d1b7a
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sat Dec 4 16:06:09 2021 +0100

    Added root option, fixed PHP relative folders

commit 08f21ad4132f92a502cd83521ba51dd9ab9a2dfb
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sat Dec 4 13:57:18 2021 +0100

    FIxed major login issue from last  commit

commit 84d767ac99946016dca6ef92991f12f661de266c
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Sat Dec 4 13:12:42 2021 +0100

    Made PHP classes, added client_id variable

    PHP now uses classes on everything but the main stat API call. This should improve error messages.
    Added new client_id variable for Plex Auth
    Tried to improve caching description
    Tautulli test button now alerts error messages
    New code has comments

commit e14ad8b5ccd937eea639eb6fc8c6c7e93ee9df3a
Author: aunefyren <oystein.sverre@gmail.com>
Date:   Fri Dec 3 17:25:00 2021 +0100

    Changed UI for admin & Trying to alert permission issues
This commit is contained in:
aunefyren 2022-01-11 14:33:30 +01:00
parent 67dcf7714c
commit 589dd44672
44 changed files with 5161 additions and 1375 deletions

3
.gitignore vendored
View file

@ -2,4 +2,5 @@
config/wrapped.log
config/config.json
config/cache.json
config/links
config/links
config/admin.json

2112
admin.js

File diff suppressed because it is too large Load diff

View file

@ -1,61 +1,45 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Plex Wrapped</title>
<head>
<!-- Required meta tags -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<!-- Bootstrap 4 CSS and custom CSS -->
<link rel="stylesheet" type="text/css" href="../assets/css/wrapped.css" />
<link rel="shortcut icon" href="../assets/img/favicons/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="../admin.js"></script>
<script src="../get_config.js"></script>
<script src="../set_config.js"></script>
<title>Wrapperr</title>
<!-- Bootstrap 4 CSS and custom CSS -->
<link rel="stylesheet" type="text/css" href="../assets/css/admin.css" />
<link rel="shortcut icon" href="../assets/img/favicons/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="../functions.js"></script>
<script src="../admin.js"></script>
</head>
</head>
<body>
<div class="content_landing" id="login_content" style="">
<div class="content">
<div class="boks">
<div class="boks3" id="search_input" style="padding: 0 !important;">
<div class="boks2" style="float: none !important; display: block; padding: 0; margin-top: 0em;">
<img src="../assets/img/gift.svg" onclick="window.location.href = '../';" style="width: 15em; cursor: pointer;">
</div>
<div class="boks2" style="float: none !important; display: block; margin-top: 0em; padding-top: 0;">
<div class="status" style="max-width: 100%;">
<h1>Wrapped Setup</h1>
<div id="setup">
</div>
</div>
</div>
<div class="container">
<div class="sub_container">
<h1 id='application_name'>Wrapperr Setup</h1>
</div>
</div>
<div class="container">
<div class="sub_container" id="setup">
</div>
</div>
</div>
<div class="footer" id="footer">
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="../">Wrapped</a> |
<div class="content" id="footer">
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="../">Wrapperr</a> |
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="../admin">Admin</a> |
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="../caching">Caching</a> |
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" id="github_link" href="https://github.com/aunefyren/plex-wrapped" target="_blank">GitHub</a>
</div>
<div class="content" id="search_results">
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" id="github_link" href="https://github.com/aunefyren/wrapperr" target="_blank">GitHub</a>
</div>
<script type="text/javascript">
@ -64,57 +48,129 @@ var root = "../";
var first_time = false;
var plex_wrapped_version = "";
var wrapperr_version = '';
var tautulli_apikey = '';
var tautulli_ip = '';
var tautulli_port = '';
var tautulli_length = '';
var tautulli_root = '';
var tautulli_libraries = '';
var https = '';
var tautulli_apikey = "";
var tautulli_ip = "";
var tautulli_port = "";
var tautulli_length = 5000;
var tautulli_root = "";
var tautulli_libraries = "";
var password = '';
var username = '';
var ssl = false;
var timezone = '';
var use_cache = '';
var use_logs = '';
var stats_intro = '';
var stats_outro = '';
var client_id = '';
var wrapperr_root = '';
var application_name_str = '';
var application_url_str = '';
var password = "";
var username = "";
var wrapped_start = '';
var wrapped_end = '';
var create_share_links = '';
var timezone = "";
var get_user_movie_stats = '';
var get_user_movie_stats_title = '';
var get_user_movie_stats_subtitle = '';
var get_user_movie_stats_subsubtitle = '';
var get_user_movie_stats_subtitle_one = '';
var get_user_movie_stats_subsubtitle_one = '';
var get_user_movie_stats_subtitle_none = '';
var get_user_movie_stats_subsubtitle_none = '';
var get_user_movie_stats_top_movie = '';
var get_user_movie_stats_top_movie_plural = '';
var get_user_movie_stats_movie_completion_title = '';
var get_user_movie_stats_movie_completion_title_plural = '';
var get_user_movie_stats_movie_completion_subtitle = '';
var get_user_movie_stats_pause_title = '';
var get_user_movie_stats_pause_subtitle = '';
var get_user_movie_stats_pause_title_one = '';
var get_user_movie_stats_pause_subtitle_one = '';
var get_user_movie_stats_pause_title_none = '';
var get_user_movie_stats_pause_subtitle_none = '';
var get_user_movie_stats_oldest_title = '';
var get_user_movie_stats_oldest_subtitle = '';
var get_user_movie_stats_oldest_subtitle_pre_1950 = '';
var get_user_movie_stats_oldest_subtitle_pre_1975 = '';
var get_user_movie_stats_oldest_subtitle_pre_2000 = '';
var get_user_movie_stats_spent_title = '';
var wrapped_start = new Date(0);
wrapped_start.setUTCSeconds(1609455600);
var get_user_show_stats = '';
var get_user_show_stats_buddy = '';
var get_user_show_stats_title = '';
var get_user_show_stats_subtitle = '';
var get_user_show_stats_subsubtitle = '';
var get_user_show_stats_subtitle_one = '';
var get_user_show_stats_subsubtitle_one = '';
var get_user_show_stats_subtitle_none = '';
var get_user_show_stats_subsubtitle_none = '';
var get_user_show_stats_top_show = '';
var get_user_show_stats_top_show_plural = '';
var get_user_show_stats_spent_title = '';
var get_user_show_stats_most_played_title = '';
var get_user_show_stats_most_played_subtitle = '';
var get_user_show_stats_buddy_title = '';
var get_user_show_stats_buddy_subtitle = '';
var get_user_show_stats_buddy_title_none = '';
var get_user_show_stats_buddy_subtitle_none = '';
var wrapped_end = new Date(0);
wrapped_end.setUTCSeconds(1640991540);
var get_user_music_stats = '';
var get_user_music_stats_title = '';
var get_user_music_stats_subtitle = '';
var get_user_music_stats_subsubtitle = '';
var get_user_music_stats_subtitle_one = '';
var get_user_music_stats_subsubtitle_one = '';
var get_user_music_stats_subtitle_none = '';
var get_user_music_stats_subsubtitle_none = '';
var get_user_music_stats_top_track = '';
var get_user_music_stats_top_track_plural = '';
var get_user_music_stats_top_album_plural = '';
var get_user_music_stats_top_artist_plural = '';
var get_user_music_stats_spent_title = '';
var get_user_music_stats_spent_subtitle = '';
var get_user_music_stats_oldest_album_title = '';
var get_user_music_stats_oldest_album_subtitle = '';
var create_share_links = true;
var get_year_stats_title = '';
var get_year_stats_subtitle = '';
var get_year_stats_subsubtitle = '';
var get_year_stats_movies = '';
var get_year_stats_movies_title = '';
var get_year_stats_movies_duration_title = '';
var get_year_stats_shows = '';
var get_year_stats_shows_title = '';
var get_year_stats_shows_duration_title = '';
var get_year_stats_music = '';
var get_year_stats_music_title = '';
var get_year_stats_music_duration_title = '';
var get_year_stats_leaderboard = '';
var get_year_stats_leaderboard_title = '';
var get_year_stats_duration_sum_title = '';
var get_user_movie_stats = true;
var get_user_show_stats = true;
var get_user_show_buddy = 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 use_logs = true;
var current_password = "";
var current_username = "";
var stats_intro = "New year, new page of statistics...";
var client_id = "";
var plex_wrapped_root = "";
var wrapperr_and = '';
var wrapperr_play = '';
var wrapperr_play_plural = '';
var wrapperr_day = '';
var wrapperr_day_plural = '';
var wrapperr_hour = '';
var wrapperr_hour_plural = '';
var wrapperr_minute = '';
var wrapperr_minute_plural = '';
var wrapperr_second = '';
var wrapperr_second_plural = '';
var wrapperr_sort_plays = '';
var wrapperr_sort_duration = '';
$(document).ready(function() {
get_plex_wrapped_version();
get_wrapper_version();
get_config_initial("../");
get_admin_state();
});
</script>

61
api/create_admin.php Normal file
View file

@ -0,0 +1,61 @@
<?php
// Required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// Files needed to use objects
require(dirname(__FILE__) . '/objects/log.php');
require(dirname(__FILE__) . '/objects/admin.php');
// Create variables
$admin = new Admin();
$log = new Log();
$data = json_decode(file_get_contents("php://input"));
// If POST data is empty
if(empty($data) || !isset($data->password) || !isset($data->username)) {
// Log use
$log->log_activity('create_admin.php', 'unknown', 'No input provided.');
echo json_encode(array("error" => true, "message" => "No input provided."));
exit(0);
}
// Remove potential harmfull input
$password = htmlspecialchars($data->password);
$username = htmlspecialchars($data->username);
// Check if confgiured
if($admin->is_configured()) {
// Log use
$log->log_activity('create_admin.php', 'unknown', 'Wrapperr admin is already configured.');
echo json_encode(array("error" => true, "message" => "Wrapperr admin is already configured."));
exit(0);
// VSave new admin
} else if($admin->create_admin($username, $password)) {
// Log use
$log->log_activity('create_admin.php', 'unknown', 'Created admin account: ' . $username . ".");
echo json_encode(array("error" => false, "message" => "Admin account created."));
exit(0);
// If creating failed
} else {
// Log use
$log->log_activity('create_admin.php', 'unknown', 'Failed to create Wrapperr admin.');
echo json_encode(array("error" => true, "message" => "Failed to create Wrapperr admin."));
exit(0);
}
?>

View file

@ -34,9 +34,9 @@ if(empty($data)) {
if(!$config->is_configured()) {
// Log use
$log->log_activity('create_link.php', 'unknown', 'Plex-Wrapped is not configured.');
$log->log_activity('create_link.php', 'unknown', 'Wrapperr is not configured.');
echo json_encode(array("error" => true, "message" => "Plex-Wrapped is not configured.", "password" => false, "data" => array()));
echo json_encode(array("error" => true, "message" => "Wrapperr is not configured.", "password" => false, "data" => array()));
exit(0);
}
@ -45,9 +45,9 @@ if(!$config->is_configured()) {
if(!$config->create_share_links) {
// Log use
$log->log_activity('create_link.php', 'unknown', 'Plex-Wrapped does not allow link creation in config.');
$log->log_activity('create_link.php', 'unknown', 'Wrapperr does not allow link creation in config.');
echo json_encode(array("error" => true, "message" => "Plex-Wrapped option for link creation not enabled."));
echo json_encode(array("error" => true, "message" => "Wrapperr option for link creation not enabled."));
exit(0);
}
@ -55,6 +55,7 @@ if(!$config->create_share_links) {
// Remove potential harmfull input
$cookie = htmlspecialchars($data->cookie);
$wrapped_data = $data->data;
$wrapped_functions = $data->functions;
// Get Plex Token
$token_object = json_decode($auth->validate_token($cookie));
@ -63,9 +64,9 @@ $token_object = json_decode($auth->validate_token($cookie));
if(empty($token_object) || !isset($token_object->data->id)) {
// Log use
$log->log_activity('create_link.php', 'unknown', 'Plex Token from cookie not valid.');
$log->log_activity('create_link.php', 'unknown', 'Plex Token from cookie not valid. Could not create link.');
echo json_encode(array("error" => true, "message" => "Login not accepted. Log in again."));
echo json_encode(array("error" => true, "message" => "Login not accepted. Try again."));
exit(0);
}
@ -82,13 +83,13 @@ $random = md5(rand(0,1000));
$url_hash = $id . '-' . $random;
//Create link content
$link_content = array("url_hash" => $url_hash, "id" => $id, "date" => $now->format('Y-m-d'), "data" => $wrapped_data);
$link_content = array("url_hash" => $url_hash, "id" => $id, "date" => $now->format('Y-m-d'), "wrapperr_version" => $config->wrapperr_version, "data" => $wrapped_data, "functions" => $wrapped_functions);
// Save the content to file
$link->save_link($link_content, $id);
// Log use
$log->log_activity('create_link.php', $id, 'Created Wrapped link.');
$log->log_activity('create_link.php', $id, 'Created Wrapperr link.');
// Return URL generated
echo json_encode(array("error" => false, "message" => "Link created.", "url" => "?hash=" . $url_hash));

91
api/delete_link_user.php Normal file
View file

@ -0,0 +1,91 @@
<?php
// Required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// Files needed to use objects
require(dirname(__FILE__) . '/objects/auth.php');
require(dirname(__FILE__) . '/objects/config.php');
require(dirname(__FILE__) . '/objects/log.php');
require(dirname(__FILE__) . '/objects/link.php');
// Create variables
$auth = new Auth();
$config = new Config();
$link = new Link();
$log = new Log();
$data = json_decode(file_get_contents("php://input"));
// If POST data is empty
if(empty($data) || empty($data->cookie)) {
// Log use
$log->log_activity('delete_link_user.php', 'unknown', 'No input provided.');
echo json_encode(array("error" => true, "message" => "No input provided."));
exit(0);
}
// Check if confgiured
if(!$config->is_configured()) {
// Log use
$log->log_activity('delete_link_user.php', 'unknown', 'Wrapperr is not configured. Can\'t delete link.');
echo json_encode(array("error" => true, "message" => "Wrapperr is not configured.", "password" => false, "data" => array()));
exit(0);
}
// Check if link creation is allowed
if(!$config->create_share_links) {
// Log use
$log->log_activity('delete_link_user.php', 'unknown', 'Wrapperr does not allow link creation in config. Won\'t delete link.');
echo json_encode(array("error" => true, "message" => "Wrapperr option for link creation not enabled."));
exit(0);
}
// Remove potential harmfull input
$cookie = htmlspecialchars($data->cookie);
// Get Plex Token
$token_object = json_decode($auth->validate_token($cookie));
// Validate Plex ID
if(empty($token_object) || !isset($token_object->data->id)) {
// Log use
$log->log_activity('delete_link_user.php', 'unknown', 'Plex Token from cookie not valid. Could not create link.');
echo json_encode(array("error" => true, "message" => "Login not accepted. Try again."));
exit(0);
}
// Assign values from Plex Token
$id = $token_object->data->id;
// Delete content
if(!$link->delete_link($id)) {
// Log use
$log->log_activity('delete_link_user.php', $id, 'Failed to delete link. Not found.');
echo json_encode(array("error" => true, "message" => "This Wrapperr link has expired."));
exit(0);
}
// Log use
$log->log_activity('delete_link_user.php', $id, 'Wrapperr link deleted by user.');
echo json_encode(array("error" => false, "message" => "This Wrapperr link deleted."));
exit(0);
?>

29
api/get_admin_state.php Normal file
View file

@ -0,0 +1,29 @@
<?php
// Required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// Files needed to use objects
require(dirname(__FILE__) . '/objects/admin.php');
require(dirname(__FILE__) . '/objects/log.php');
// Create variables
$admin = new Admin();
$log = new Log();
// Log use
$log->log_activity('get_admin_state.php', 'unknown', 'Retrieved Wrapperr admin state.');
// Create JSON from functions
$functions_json = array("wrapperr_admin_configured" => $admin->is_configured(),
"error" => false,
"message" => "Admin configuration state retrieved."
);
// Encode JSON and print it
echo json_encode($functions_json);
exit(0);
?>

View file

@ -9,53 +9,64 @@ header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers
// Files needed to use objects
require(dirname(__FILE__) . '/objects/config.php');
require(dirname(__FILE__) . '/objects/log.php');
require(dirname(__FILE__) . '/objects/admin.php');
// Create variables
$config = new Config();
$admin = new Admin();
$log = new Log();
$data = json_decode(file_get_contents("php://input"));
// If POST data is empty
if(empty($data)) {
if(empty($data) || !isset($data->cookie)) {
// Log use
$log->log_activity('get_config.php', 'unknown', 'No admin login input provided.');
$log->log_activity('get_config.php', 'unknown', 'No admin login cookie provided.');
echo json_encode(array("error" => true, "message" => "No input provided."));
echo json_encode(array("error" => true, "message" => "No cookie provided."));
exit(0);
}
// Remove potential harmfull input
$password = htmlspecialchars($data->password);
$username = htmlspecialchars($data->username);
$cookie = htmlspecialchars($data->cookie);
// Check if confgiured
if(!$config->is_configured()) {
if(!$admin->is_configured()) {
// Log use
$log->log_activity('get_config.php', 'unknown', 'Plex-Wrapped is not configured.');
$log->log_activity('get_config.php', 'unknown', 'Wrapperr admin is not configured.');
echo json_encode(array("error" => true, "message" => "Plex-Wrapped is not configured.", "password" => false, "data" => array()));
echo json_encode(array("error" => true, "message" => "Wrapperr admin is not configured."));
exit(0);
// Verify password and username combination
} else if($config->verify_wrapped_admin($username, $password)) {
} else if(!$config->is_configured()) {
// Log use
$log->log_activity('get_config.php', 'unknown', 'Wrapperr is not configured.');
echo json_encode(array("error" => false, "message" => "Wrapperr is not configured.", "wrapperr_configured" => false, "data" => $config, "admin" => $admin->username));
exit(0);
}
// Decrypt cookie
$cookie_object = json_decode($admin->decrypt_cookie($cookie));
// Validate admin cookie
if(!$admin->validate_cookie($cookie_object)) {
// Log use
$log->log_activity('get_config.php', 'unknown', 'Admin cookie not valid.');
echo json_encode(array("error" => true, "message" => "Admin cookie not accepted. Log in again."));
exit(0);
// Log use
$log->log_activity('get_config.php', 'unknown', 'Retrieved Plex-Wrapped configuraton.');
echo json_encode(array("error" => false, "message" => "Login successful.", "password" => true, "data" => $config));
exit(0);
// If input was given, but is empty
} else {
// Log use
$log->log_activity('get_config.php', 'unknown', 'Wrong admin password/username combination.');
echo json_encode(array("error" => true, "message" => "Username and password combination not accepted.", "password" => true, "data" => array()));
exit(0);
}
// Log use
$log->log_activity('get_config.php', 'admin', 'Retrieved Wrapperr configuration.');
echo json_encode(array("error" => false, "message" => "Config retrieved.", "wrapperr_configured" => true, "data" => $config, "admin" => $admin->username));
exit(0);
?>

View file

@ -16,20 +16,100 @@ $log = new Log();
$data = json_decode(file_get_contents("php://input"));
// Log use
$log->log_activity('get_functions.php', 'unknown', 'Retrieved Plex-Wrapped functions.');
$log->log_activity('get_functions.php', 'unknown', 'Retrieved Wrapperr functions.');
// Create JSON from functions
$functions_json = array("plex_wrapped_version" => $config->plex_wrapped_version,
$functions_json = array("wrapperr_version" => $config->wrapperr_version,
"get_user_movie_stats" => $config->get_user_movie_stats,
"get_user_movie_stats_title" => $config->get_user_movie_stats_title,
"get_user_movie_stats_subtitle" => $config->get_user_movie_stats_subtitle,
"get_user_movie_stats_subsubtitle" => $config->get_user_movie_stats_subsubtitle,
"get_user_movie_stats_subtitle_one" => $config->get_user_movie_stats_subtitle_one,
"get_user_movie_stats_subsubtitle_one" => $config->get_user_movie_stats_subsubtitle_one,
"get_user_movie_stats_subtitle_none" => $config->get_user_movie_stats_subtitle_none,
"get_user_movie_stats_subsubtitle_none" => $config->get_user_movie_stats_subsubtitle_none,
"get_user_movie_stats_top_movie" => $config->get_user_movie_stats_top_movie,
"get_user_movie_stats_top_movie_plural" => $config->get_user_movie_stats_top_movie_plural,
"get_user_movie_stats_movie_completion_title" => $config->get_user_movie_stats_movie_completion_title,
"get_user_movie_stats_movie_completion_title_plural" => $config->get_user_movie_stats_movie_completion_title_plural,
"get_user_movie_stats_movie_completion_subtitle" => $config->get_user_movie_stats_movie_completion_subtitle,
"get_user_movie_stats_pause_title" => $config->get_user_movie_stats_pause_title,
"get_user_movie_stats_pause_subtitle" => $config->get_user_movie_stats_pause_subtitle,
"get_user_movie_stats_pause_title_one" => $config->get_user_movie_stats_pause_title_one,
"get_user_movie_stats_pause_subtitle_one" => $config->get_user_movie_stats_pause_subtitle_one,
"get_user_movie_stats_pause_title_none" => $config->get_user_movie_stats_pause_title_none,
"get_user_movie_stats_pause_subtitle_none" => $config->get_user_movie_stats_pause_subtitle_none,
"get_user_movie_stats_oldest_title" => $config->get_user_movie_stats_oldest_title,
"get_user_movie_stats_oldest_subtitle" => $config->get_user_movie_stats_oldest_subtitle,
"get_user_movie_stats_oldest_subtitle_pre_1950" => $config->get_user_movie_stats_oldest_subtitle_pre_1950,
"get_user_movie_stats_oldest_subtitle_pre_1975" => $config->get_user_movie_stats_oldest_subtitle_pre_1975,
"get_user_movie_stats_oldest_subtitle_pre_2000" => $config->get_user_movie_stats_oldest_subtitle_pre_2000,
"get_user_movie_stats_spent_title" => $config->get_user_movie_stats_spent_title,
"get_user_show_stats" => $config->get_user_show_stats,
"get_user_show_buddy" => $config->get_user_show_buddy,
"get_user_show_stats_buddy" => $config->get_user_show_stats_buddy,
"get_user_show_stats_title" => $config->get_user_show_stats_title,
"get_user_show_stats_subtitle" => $config->get_user_show_stats_subtitle,
"get_user_show_stats_subsubtitle" => $config->get_user_show_stats_subsubtitle,
"get_user_show_stats_subtitle_one" => $config->get_user_show_stats_subtitle_one,
"get_user_show_stats_subsubtitle_one" => $config->get_user_show_stats_subsubtitle_one,
"get_user_show_stats_subtitle_none" => $config->get_user_show_stats_subtitle_none,
"get_user_show_stats_subsubtitle_none" => $config->get_user_show_stats_subsubtitle_none,
"get_user_show_stats_top_show" => $config->get_user_show_stats_top_show,
"get_user_show_stats_top_show_plural" => $config->get_user_show_stats_top_show_plural,
"get_user_show_stats_spent_title" => $config->get_user_show_stats_spent_title,
"get_user_show_stats_most_played_title" => $config->get_user_show_stats_most_played_title,
"get_user_show_stats_most_played_subtitle" => $config->get_user_show_stats_most_played_subtitle,
"get_user_show_stats_buddy_title" => $config->get_user_show_stats_buddy_title,
"get_user_show_stats_buddy_subtitle" => $config->get_user_show_stats_buddy_subtitle,
"get_user_show_stats_buddy_title_none" => $config->get_user_show_stats_buddy_title_none,
"get_user_show_stats_buddy_subtitle_none" => $config->get_user_show_stats_buddy_subtitle_none,
"get_user_music_stats" => $config->get_user_music_stats,
"get_user_music_stats_title" => $config->get_user_music_stats_title,
"get_user_music_stats_subtitle" => $config->get_user_music_stats_subtitle,
"get_user_music_stats_subsubtitle" => $config->get_user_music_stats_subsubtitle,
"get_user_music_stats_subtitle_one" => $config->get_user_music_stats_subtitle_one,
"get_user_music_stats_subsubtitle_one" => $config->get_user_music_stats_subsubtitle_one,
"get_user_music_stats_subtitle_none" => $config->get_user_music_stats_subtitle_none,
"get_user_music_stats_subsubtitle_none" => $config->get_user_music_stats_subsubtitle_none,
"get_user_music_stats_top_track" => $config->get_user_music_stats_top_track,
"get_user_music_stats_top_track_plural" => $config->get_user_music_stats_top_track_plural,
"get_user_music_stats_top_album_plural" => $config->get_user_music_stats_top_album_plural,
"get_user_music_stats_top_artist_plural" => $config->get_user_music_stats_top_artist_plural,
"get_user_music_stats_spent_title" => $config->get_user_music_stats_spent_title,
"get_user_music_stats_spent_subtitle" => $config->get_user_music_stats_spent_subtitle,
"get_user_music_stats_oldest_album_title" => $config->get_user_music_stats_oldest_album_title,
"get_user_music_stats_oldest_album_subtitle" => $config->get_user_music_stats_oldest_album_subtitle,
"get_year_stats_title" => $config->get_year_stats_title,
"get_year_stats_subtitle" => $config->get_year_stats_subtitle,
"get_year_stats_subsubtitle" => $config->get_year_stats_subsubtitle,
"get_year_stats_movies" => $config->get_year_stats_movies,
"get_year_stats_movies_title" => $config->get_year_stats_movies_title,
"get_year_stats_movies_duration_title" => $config->get_year_stats_movies_duration_title,
"get_year_stats_shows" => $config->get_year_stats_shows,
"get_year_stats_shows_title" => $config->get_year_stats_shows_title,
"get_year_stats_shows_duration_title" => $config->get_year_stats_shows_duration_title,
"get_year_stats_music" => $config->get_year_stats_music,
"get_year_stats_music_title" => $config->get_year_stats_music_title,
"get_year_stats_music_duration_title" => $config->get_year_stats_music_duration_title,
"get_year_stats_leaderboard" => $config->get_year_stats_leaderboard,
"get_year_stats_leaderboard_title" => $config->get_year_stats_leaderboard_title,
"get_year_stats_duration_sum_title" => $config->get_year_stats_duration_sum_title,
"stats_intro" => $config->stats_intro,
"create_share_links" => $config->create_share_links
"stats_outro" => $config->stats_outro,
"create_share_links" => $config->create_share_links,
"wrapperr_and" => $config->wrapperr_and,
"wrapperr_play" => $config->wrapperr_play,
"wrapperr_play_plural" => $config->wrapperr_play_plural,
"wrapperr_day" => $config->wrapperr_day,
"wrapperr_day_plural" => $config->wrapperr_day_plural,
"wrapperr_hour" => $config->wrapperr_hour,
"wrapperr_hour_plural" => $config->wrapperr_hour_plural,
"wrapperr_minute" => $config->wrapperr_minute,
"wrapperr_minute_plural" => $config->wrapperr_minute_plural,
"wrapperr_second" => $config->wrapperr_second,
"wrapperr_second_plural" => $config->wrapperr_second_plural,
"wrapperr_sort_plays" => $config->wrapperr_sort_plays,
"wrapperr_sort_duration" => $config->wrapperr_sort_duration
);
// Encode JSON and print it

View file

@ -34,9 +34,9 @@ if(empty($data) || !isset($data->hash)) {
if(!$config->is_configured()) {
// Log use
$log->log_activity('get_link.php', 'unknown', 'Plex-Wrapped is not configured.');
$log->log_activity('get_link.php', 'unknown', 'Wrapperr is not configured.');
echo json_encode(array("error" => true, "message" => "Plex-Wrapped is not configured.", "password" => false, "data" => array()));
echo json_encode(array("error" => true, "message" => "Wrapperr is not configured.", "password" => false, "data" => array()));
exit(0);
}
@ -45,9 +45,9 @@ if(!$config->is_configured()) {
if(!$config->create_share_links) {
// Log use
$log->log_activity('get_link.php', 'unknown', 'Plex-Wrapped does not allow link creation in config.');
$log->log_activity('get_link.php', 'unknown', 'Wrapperr does not allow link creation in config.');
echo json_encode(array("error" => true, "message" => "Plex-Wrapped option for link creation not enabled."));
echo json_encode(array("error" => true, "message" => "Wrapperr option for link creation not enabled."));
exit(0);
}
@ -58,9 +58,9 @@ $hash_input = explode('-', htmlspecialchars($data->hash));
if(count($hash_input) !== 2) {
// Log use
$log->log_activity('get_link.php', 'unknown', 'Failed to get Wrapped link. Can\'t parse input.');
$log->log_activity('get_link.php', 'unknown', 'Failed to get Wrapperr link. Can\'t parse input.');
echo json_encode(array("error" => true, "message" => "Wrapped link is either wrong or expired."));
echo json_encode(array("error" => true, "message" => "Wrapperr link is either wrong or expired."));
exit(0);
}
@ -82,9 +82,9 @@ $content = $link->open_link($id);
if(!$content) {
// Log use
$log->log_activity('get_link.php', 'unknown', 'Failed to get Wrapped link. File not found.');
$log->log_activity('get_link.php', 'unknown', 'Failed to get Wrapperr link. File not found.');
echo json_encode(array("error" => true, "message" => "There was an error fetching this Wrapped page. Could the link have expired?"));
echo json_encode(array("error" => true, "message" => "There was an error fetching this Wrapperr page. Could the link have expired?"));
exit(0);
}
@ -95,9 +95,9 @@ $link_data = json_decode($content);
if($link_data->url_hash !== $data->hash) {
// Log use
$log->log_activity('get_link.php', 'unknown', 'Failed to get Wrapped link. Hash did not match.');
$log->log_activity('get_link.php', 'unknown', 'Failed to get Wrapperr link. Hash did not match.');
echo json_encode(array("error" => true, "message" => "There was an error fetching this Wrapped page. Could the link have expired?"));
echo json_encode(array("error" => true, "message" => "There was an error fetching this Wrapperr page. Could the link have expired?"));
exit(0);
}
@ -109,22 +109,37 @@ $diff = (array) date_diff($now, $then);
if($diff['days'] > 7) {
// Log use
$log->log_activity('get_link.php', 'unknown', 'Failed to get Wrapped link for ID: ' . $id . '. It has expired. Deleting file.');
$log->log_activity('get_link.php', 'unknown', 'Failed to get Wrapperr link for ID: ' . $id . '. It has expired. Deleting file.');
// Delete expired content
if(!$link->delete_link($id)) {
$log->log_activity('get_link.php', 'unknown', 'Failed to delete link for ID: ' . $id . '.');
}
echo json_encode(array("error" => true, "message" => "This Wrapped link has expired."));
echo json_encode(array("error" => true, "message" => "This Wrapperr link has expired."));
exit(0);
}
if($link_data->wrapperr_version !== $config->wrapperr_version) {
// Log use
$log->log_activity('get_link.php', 'unknown', 'Wrapperr link for ID: ' . $id . ' is made for version: ' . $link_data->wrapperr_version . '. Deleting file.');
// Delete expired content
if(!$link->delete_link($id)) {
$log->log_activity('get_link.php', 'unknown', 'Failed to delete link for ID: ' . $id . '.');
}
echo json_encode(array("error" => true, "message" => "This Wrapperr link is made for another Wrapperr version. Create a new link on the current version."));
exit(0);
}
// Log use
$log->log_activity('get_link.php', 'unknown', 'Retrieved Wrapped link for ID: ' . $id . '.');
$log->log_activity('get_link.php', 'unknown', 'Retrieved Wrapperr link for ID: ' . $id . '.');
// Return URL generated
echo json_encode(array("error" => false, "message" => "Link retrieved.", "data" => $link_data->data));
echo json_encode(array("error" => false, "message" => "Link retrieved.", "data" => $link_data->data, "functions" => $link_data->functions));
exit(0);
?>

134
api/get_link_user.php Normal file
View file

@ -0,0 +1,134 @@
<?php
// Required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// Files needed to use objects
require(dirname(__FILE__) . '/objects/auth.php');
require(dirname(__FILE__) . '/objects/config.php');
require(dirname(__FILE__) . '/objects/log.php');
require(dirname(__FILE__) . '/objects/link.php');
// Create variables
$auth = new Auth();
$config = new Config();
$link = new Link();
$log = new Log();
$data = json_decode(file_get_contents("php://input"));
// If POST data is empty
if(empty($data) || !isset($data->cookie)) {
// Log use
$log->log_activity('get_link_user.php', 'unknown', 'No input provided.');
echo json_encode(array("error" => true, "message" => "No input provided."));
exit(0);
}
// Check if confgiured
if(!$config->is_configured()) {
// Log use
$log->log_activity('get_link_user.php', 'unknown', 'Wrapperr is not configured. Can\'t retrieve links.');
echo json_encode(array("error" => true, "message" => "Wrapperr is not configured.", "password" => false, "data" => array()));
exit(0);
}
// Check if link creation is allowed
if(!$config->create_share_links) {
// Log use
$log->log_activity('get_link_user.php', 'unknown', 'Wrapperr does not allow link creation in config. Will not retrieve link.');
echo json_encode(array("error" => true, "message" => "Wrapperr option for link creation not enabled."));
exit(0);
}
// Remove potential harmfull input
$cookie = htmlspecialchars($data->cookie);
// Get the current date
$now = new DateTime('NOW');
// Get Plex Token
$token_object = json_decode($auth->validate_token($cookie));
// Validate Plex ID
if(empty($token_object) || !isset($token_object->data->id)) {
// Log use
$log->log_activity('get_link_user.php', 'unknown', 'Plex Token from cookie not valid. Could not retrieve link.');
echo json_encode(array("error" => true, "message" => "Login not accepted. Try again."));
exit(0);
}
// Assign values from Plex Token
$id = $token_object->data->id;
// Save the content to file
$content = $link->open_link($id);
if(!$content) {
// Log use
$log->log_activity('get_link_user.php', $id, 'User does not have any Wrapperr link file.');
echo json_encode(array("error" => false, "message" => "Wrapperr links retrieved.", "links" => array()));
exit(0);
}
$link_data = json_decode($content);
$then = date_create_from_format('Y-m-d', $link_data->date);
$diff = (array) date_diff($now, $then);
if($diff['days'] > 7) {
// Log use
$log->log_activity('get_link_user.php', $id, 'Wrapperr link has expired. Deleting file.');
// Delete expired content
if(!$link->delete_link($id)) {
$log->log_activity('get_link_user.php', $id, 'Failed to delete link.');
}
echo json_encode(array("error" => false, "message" => "Wrapperr links retrieved.", "links" => array()));
exit(0);
}
if($link_data->wrapperr_version !== $config->wrapperr_version) {
// Log use
$log->log_activity('get_link_user.php', $id, 'Wrapperr link is made for version: ' . $link_data->wrapperr_version . '. Deleting file.');
// Delete expired content
if(!$link->delete_link($id)) {
$log->log_activity('get_link_user.php', $id, 'Failed to delete link.');
}
echo json_encode(array("error" => false, "message" => "Wrapperr links retrieved.", "links" => array()));
exit(0);
}
// Create link dataset
$links = array('url_hash' => $link_data->url_hash, 'date' => $link_data->date);
// Log use
$log->log_activity('get_link_user.php', $id, 'Retrieved Wrapperr link.');
// Return URL generated
echo json_encode(array("error" => false, "message" => "Wrapperr links retrieved.", "links" => array($links)));
exit(0);
?>

View file

@ -0,0 +1,53 @@
<?php
// Required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// Files needed to use objects
require(dirname(__FILE__) . '/objects/admin.php');
require(dirname(__FILE__) . '/objects/log.php');
// Create variables
$admin = new Admin();
$log = new Log();
$data = json_decode(file_get_contents("php://input"));
// If POST data is empty or wrong
if(empty($data) || !isset($data->password) || !isset($data->username)) {
// Log use
$log->log_activity('get_login_admin_cookie.php', 'unknown', 'Input error from user.');
echo json_encode(array("error" => true, "message" => "Input error."));
exit(0);
}
// Remove potential harmfull input
$password = htmlspecialchars($data->password);
$username = htmlspecialchars($data->username);
// Get Plex token
$admin_cookie = $admin->get_login_admin_cookie($username, $password);
// Validate Plex ID
if(!$admin_cookie) {
// Log use
$log->log_activity('get_login_admin_cookie.php', 'unknown', 'Admin login not valid.');
echo json_encode(array("error" => true, "message" => "Login not accepted. Try again."));
exit(0);
}
// Log use
$log->log_activity('get_login_admin_cookie.php', 'admin', 'Admin login accepted. Returned cookie.');
// Print cookie and exit
echo json_encode(array("error" => false, "message" => "Login is valid. Admin cookie created.", "cookie" => $admin_cookie));
exit(0);
?>

View file

@ -34,7 +34,7 @@ $code = htmlspecialchars($data->code);
$cookie = $auth->get_cookie($id, $code);
// Log use
$log->log_activity('get_login_cookie.php', 'unknown', 'Plex-Wrapped login cookie created.');
$log->log_activity('get_login_cookie.php', 'unknown', 'Wrapperr login cookie created.');
// Print cookie and exit
echo json_encode(array("error" => false, "message" => "Cookie created.", "cookie" => $cookie));

View file

@ -21,9 +21,9 @@ $config = new Config();
if(!$config->is_configured()) {
// Log activity
$log->log_activity('get_login_url.php', 'unknown', 'Plex-Wrapped is not confgured..');
$log->log_activity('get_login_url.php', 'unknown', 'Wrapperr is not confgured..');
echo json_encode(array("message" => "Plex-Wrapped is not confgured.", "error" => true));
echo json_encode(array("message" => "Wrapperr is not confgured.", "error" => true));
exit(0);
}
@ -41,6 +41,17 @@ if(empty($data) || !isset($data->home_url)) {
// Get code and pin from Plex
$pin_object = json_decode($auth->get_pin(), true);
if(!isset($pin_object['id']) || !isset($pin_object['code'])) {
// Log URL creation
$log->log_activity('get_login_url.php', 'unknown', 'Failed to get ID or Code from Plex Auth. Exiting.');
// Return URL for login
echo json_encode(array("message" => 'Failed to get ID or Code from Plex Auth.', "error" => true));
exit(0);
}
// Get URL using pin and code
$url = $auth->get_login_url($pin_object['code'], $pin_object['id'], $data->home_url);

View file

@ -9,23 +9,25 @@ header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers
// Files needed to use objects
require(dirname(__FILE__) . '/objects/auth.php');
require(dirname(__FILE__) . '/objects/config.php');
require(dirname(__FILE__) . '/objects/admin.php');
require(dirname(__FILE__) . '/objects/log.php');
require(dirname(__FILE__) . '/objects/cache.php');
// Create variables
$config = new Config();
$admin = new Admin();
$auth = new Auth();
$log = new Log();
$cache = new Cache();
$data = json_decode(file_get_contents("php://input"));
// Check if configured
if(!$config->is_configured()) {
if(!$config->is_configured() || !$admin->is_configured()) {
// Log activity
$log->log_activity('get_stats.php', 'unknown', 'Plex-Wrapped is not confgured..');
$log->log_activity('get_stats.php', 'unknown', 'Wrapperr is not confgured..');
echo json_encode(array("message" => "Plex-Wrapped is not confgured.", "error" => true));
echo json_encode(array("message" => "Wrapperr is not confgured.", "error" => true));
exit(0);
}
@ -33,7 +35,7 @@ if(!$config->is_configured()) {
date_default_timezone_set($config->timezone);
// Set maximum run-time
set_time_limit(300);
set_time_limit(600);
// Base-URL for connections to Tautulli API.
$connection = create_url();
@ -44,6 +46,9 @@ if(!empty($data) && isset($data->cookie)){
} else if(isset($_GET["cookie"])) {
$cookie = htmlspecialchars(trim($_GET["cookie"]));
} else {
// Log activity
$log->log_activity('get_stats.php', 'unknown', 'Invalid cookie input.');
http_response_code(400);
echo json_encode(array("message" => "Input error.", "error" => true));
exit(0);
@ -77,7 +82,7 @@ if($caching) {
// Log activity
$log->log_activity('get_stats.php', 'unknown', 'Starting caching mode.');
caching_mode($cache_limit);
caching_mode($cache_limit, $cookie);
}
@ -124,7 +129,7 @@ if(isset($token_object->data->friendlyName)) {
}
// Log use
$log->log_activity('get_stats.php', $token_object->data->id, 'Plex-Wrapped login cookie accepted.');
$log->log_activity('get_stats.php', $token_object->data->id, 'Wrapperr login cookie accepted.');
// Get user name
$name = tautulli_get_name($id);
@ -236,11 +241,11 @@ if($config->get_user_movie_stats || $config->get_user_show_stats || $config->get
}
// Get show buddy if enabled, shows are not empty, and shows is enabled.
if($config->get_year_stats_shows && $config->get_user_show_buddy && count($user_shows["data"]["shows"]) > 0) {
if($config->get_year_stats_shows && $config->get_user_show_stats_buddy && count($user_shows["data"]["shows_duration"]) > 0) {
// Log show-buddy action
$log->log_activity('get_stats.php', $id, 'Getting show-buddy.');
$user_shows["data"] = $user_shows["data"] + array("show_buddy" => data_get_user_show_buddy($id, $user_shows["data"]["shows"][0]["title"], $tautulli_data));
$user_shows["data"] = $user_shows["data"] + array("show_buddy" => data_get_user_show_buddy($id, $user_shows["data"]["shows_duration"][0]["title"], $tautulli_data));
} else {
// Log show-buddy action
$log->log_activity('get_stats.php', $id, 'Show-buddy disabled.');
@ -299,7 +304,7 @@ function create_url() {
$ip = $config->tautulli_ip;
// SSL means 'https', not means 'http'
if($config->ssl) {
if($config->https) {
$base = "https://";
} else {
$base = "http://";
@ -389,7 +394,7 @@ function tautulli_get_name($id) {
global $arrContextOptions;
$url = $connection . "/api/v2?apikey=" . $config->tautulli_apikey . "&cmd=get_user_ips&user_id=" . $id;
if($config->ssl) {
if($config->https) {
$response = json_decode(file_get_contents($url, false, stream_context_create($arrContextOptions)));
} else {
$response = json_decode(file_get_contents($url));
@ -406,21 +411,39 @@ function tautulli_get_name($id) {
}
}
function caching_mode($cache_limit) {
function caching_mode($cache_limit, $cookie) {
global $config;
global $admin;
global $cache;
global $log;
global $cache_data;
$id = "Caching mode";
// Log caching mode
$log->log_activity('get_stats.php', $id, 'Tautulli connection test was successful.');
$log->log_activity('get_stats.php', $id, 'Caching mode initiated.');
if(!$config->use_cache) {
// Log caching mode
$log->log_activity('get_stats.php', $id, 'Caching is disabled in config. Caching mode can\'t proceed.');
http_response_code(400);
echo json_encode(array("message" => "Caching is disabled.", "error" => true));
echo json_encode(array("message" => "Caching is disabled in configuration.", "error" => true));
exit(0);
}
// Decrypt cookie
$cookie_object = json_decode($admin->decrypt_cookie($cookie));
// Validate admin cookie
if(!$admin->validate_cookie($cookie_object)) {
// Log use
$log->log_activity('get_stats.php', $id, 'Admin cookie not valid. Stopping caching mode.');
echo json_encode(array("error" => true, "message" => "Admin cookie not accepted. Can't proceed."));
exit(0);
}
// Log checking cache
$log->log_activity('get_stats.php', $id, 'Starting cache loop.');
@ -949,9 +972,19 @@ function data_get_user_stats_loop($id, $array) {
$duration = array_column($movies, 'duration');
array_multisort($duration, SORT_DESC, $movies);
// Sort $movies by plays
$movies_plays = $movies;
$plays = array_column($movies_plays, 'plays');
array_multisort($plays, SORT_DESC, $movies_plays);
//Sort $shows by longest duration
$duration = array_column($shows, 'duration');
array_multisort($duration, SORT_DESC, $shows);
//Sort $shows by plays
$shows_plays = $shows;
$plays = array_column($shows_plays, 'plays');
array_multisort($plays, SORT_DESC, $shows_plays);
//Sort episodes by duration and find longest episode duration
$duration = array_column($episodes, 'duration');
@ -1026,30 +1059,65 @@ function data_get_user_stats_loop($id, $array) {
$duration = array_column($tracks, 'duration');
array_multisort($duration, SORT_DESC, $tracks);
// Sort $tracks by plays
$tracks_plays = $tracks;
$plays = array_column($tracks_plays, 'plays');
array_multisort($plays, SORT_DESC, $tracks_plays);
// Sort $albums by longest duration
$duration = array_column($albums, 'duration');
array_multisort($duration, SORT_DESC, $albums);
// Sort $albums by plays
$albums_plays = $albums;
$plays = array_column($albums_plays, 'plays');
array_multisort($plays, SORT_DESC, $albums_plays);
// Sort $artists by longest duration
$duration = array_column($artists, 'duration');
array_multisort($duration, SORT_DESC, $artists);
// Sort $artists by plays
$artists_plays = $artists;
$plays = array_column($artists_plays, 'plays');
array_multisort($plays, SORT_DESC, $artists_plays);
// Sort $year_movies by duration
$duration = array_column($year_movies, 'duration');
array_multisort($duration, SORT_DESC, $year_movies);
// Sort $year_movies by plays
$year_movies_plays = $year_movies;
$plays = array_column($year_movies_plays, 'plays');
array_multisort($plays, SORT_DESC, $year_movies_plays);
// Sort $year_shows by duration
$duration = array_column($year_shows, 'duration');
array_multisort($duration, SORT_DESC, $year_shows);
// Sort $year_show by plays
$year_shows_plays = $year_shows;
$plays = array_column($year_shows_plays, 'plays');
array_multisort($plays, SORT_DESC, $year_shows_plays);
// Sort $year_music by duration
$duration = array_column($year_music, 'duration');
array_multisort($duration, SORT_DESC, $year_music);
// Sort $year_music by plays
$year_music_plays = $year_music;
$plays = array_column($year_music_plays, 'plays');
array_multisort($plays, SORT_DESC, $year_music_plays);
// Sort users by combined duration
$duration = array_column($year_users, 'duration');
array_multisort($duration, SORT_DESC, $year_users);
// Sort users by combined plays
$year_users_plays = $year_users;
$plays = array_column($year_users_plays, 'plays');
array_multisort($plays, SORT_DESC, $year_users_plays);
// Calculate average movie finishing percentage
$sum = 0;
for($i = 0; $i < count($movies_percent_complete); $i++) {
@ -1063,7 +1131,8 @@ function data_get_user_stats_loop($id, $array) {
// Choose return value based on if function is enabled
if($config->get_user_movie_stats) {
$return_movies = array("movies" => array_slice($movies, 0, 10), "user_movie_most_paused" => $movie_most_paused, "user_movie_finishing_percent" => $movie_percent_average, "user_movie_oldest" => $movie_oldest);
// Duration values
$return_movies = array("movies_duration" => array_slice($movies, 0, 10), "movies_plays" => array_slice($movies_plays, 0, 10), "user_movie_most_paused" => $movie_most_paused, "user_movie_finishing_percent" => $movie_percent_average, "user_movie_oldest" => $movie_oldest);
$duration = 0;
for($i = 0; $i < count($movies); $i++) {
$duration += $movies[$i]["duration"];
@ -1076,7 +1145,7 @@ function data_get_user_stats_loop($id, $array) {
// Choose return value based on if function is enabled
if($config->get_user_show_stats) {
$return_shows = array("shows" => array_slice($shows, 0, 10), "episode_duration_longest" => $episode_duration_longest);
$return_shows = array("shows_duration" => array_slice($shows, 0, 10), "shows_plays" => array_slice($shows_plays, 0, 10), "episode_duration_longest" => $episode_duration_longest);
$duration = 0;
for($i = 0; $i < count($shows); $i++) {
$duration += $shows[$i]["duration"];
@ -1089,7 +1158,7 @@ function data_get_user_stats_loop($id, $array) {
// Choose return value based on if function is enabled
if($config->get_user_music_stats) {
$return_music = array("tracks" => array_slice($tracks, 0, 10), "albums" => array_slice($albums, 0, 10), "user_album_oldest" => $album_oldest, "artists" => array_slice($artists, 0, 10));
$return_music = array("tracks_duration" => array_slice($tracks, 0, 10), "tracks_plays" => array_slice($tracks_plays, 0, 10), "albums_duration" => array_slice($albums, 0, 10), "albums_plays" => array_slice($albums_plays, 0, 10), "user_album_oldest" => $album_oldest, "artists_duration" => array_slice($artists, 0, 10), "artists_plays" => array_slice($artists_plays, 0, 10));
$duration = 0;
for($i = 0; $i < count($tracks); $i++) {
$duration += $tracks[$i]["duration"];
@ -1102,7 +1171,8 @@ function data_get_user_stats_loop($id, $array) {
// Choose return value based on if function is enabled
if($config->get_year_stats_movies) {
$return_year_movies["movies"] = array_slice($year_movies, 0, 10);
$return_year_movies["movies_duration"] = array_slice($year_movies, 0, 10);
$return_year_movies["movies_plays"] = array_slice($year_movies_plays, 0, 10);
$duration = 0;
for($i = 0; $i < count($year_movies); $i++) {
$duration += $year_movies[$i]["duration"];
@ -1115,7 +1185,8 @@ function data_get_user_stats_loop($id, $array) {
// Choose return value based on if function is enabled
if($config->get_year_stats_shows) {
$return_year_shows["shows"] = array_slice($year_shows, 0, 10);
$return_year_shows["shows_duration"] = array_slice($year_shows, 0, 10);
$return_year_shows["shows_plays"] = array_slice($year_shows_plays, 0, 10);
$duration = 0;
for($i = 0; $i < count($year_shows); $i++) {
$duration += $year_shows[$i]["duration"];
@ -1128,7 +1199,8 @@ function data_get_user_stats_loop($id, $array) {
// Choose return value based on if function is enabled
if($config->get_year_stats_music) {
$return_year_music["artists"] = array_slice($year_music, 0, 10);
$return_year_music["artists_duration"] = array_slice($year_music, 0, 10);
$return_year_music["artists_plays"] = array_slice($year_music_plays, 0, 10);
$duration = 0;
for($i = 0; $i < count($year_music); $i++) {
$duration += $year_music[$i]["duration"];
@ -1141,9 +1213,11 @@ function data_get_user_stats_loop($id, $array) {
// Choose return value based on if function is enabled
if(($config->get_year_stats_movies || $config->get_year_stats_shows || $config->get_year_stats_music) && $config->get_year_stats_leaderboard) {
$return_year_users = array_slice($year_users, 0, 10);
$return_year_users["users_duration"] = array_slice($year_users, 0, 10);
$return_year_users["users_plays"] = array_slice($year_users_plays, 0, 10);
} else {
$return_year_users = array();
$return_year_users["users_duration"] = array();
$return_year_users["users_plays"] = array();
}
// Calculate and log execution time

View file

@ -15,11 +15,12 @@ $config = new Config();
$log = new Log();
// Log use
$log->log_activity('get_plex_wrapped_version.php', 'unknown', 'Retrieved Plex-Wrapped version.');
$log->log_activity('get_plex_wrapped_version.php', 'unknown', 'Retrieved Wrapperr version.');
// Create JSON from functions
$version_json = array("plex_wrapped_version" => $config->plex_wrapped_version,
"message" => "Retrieved Plex-Wrapped verison.",
$version_json = array( "wrapperr_version" => $config->wrapperr_version,
"application_name" => $config->application_name,
"message" => "Retrieved Wrapperr verison.",
"error" => false
);

167
api/objects/admin.php Normal file
View file

@ -0,0 +1,167 @@
<?php
class Admin {
// Object properties
// Admin path
private $path;
// Admin user
public $password;
public $username;
// Encryption variables
const METHOD = 'aes-256-ctr';
public $token_encrypter;
// Constructor
public function __construct(){
// Declare admin path
$this->path = dirname(__FILE__, 3) . '/config/admin.json';
// Check if config file exists, if not, create it
if(!file_exists($this->path)) {
$create_admin = fopen($this->path, "w");
if(!$create_admin) {
echo json_encode(array("message" => "Failed to create admin.json. Is the 'config' directory writable?", "error" => true));
exit();
}
fclose($create_admin);
}
// Parse JSON from config
$json = json_decode(file_get_contents($this->path));
if(!empty($json)) {
// Assign values from config file
$this->password = $json->password;
$this->username = $json->username;
$this->token_encrypter = $json->token_encrypter;
}
}
public function get_login_admin_cookie($username, $password) {
if(!password_verify($password, $this->password) || $username !== $this->username) {
return false;
}
$nonceSize = openssl_cipher_iv_length(self::METHOD);
$nonce = openssl_random_pseudo_bytes($nonceSize);
// Get the current date
$now = new DateTime('NOW');
$object = json_encode(array("username" => $this->username, "password" => $this->password, "date" => $now->format('Y-m-d')));
$token = openssl_encrypt(
$object,
self::METHOD,
$this->token_encrypter,
OPENSSL_RAW_DATA,
$nonce
);
return base64_encode($nonce.$token);
}
public function is_configured() {
if(!empty(file_get_contents($this->path)) && !empty($this->username) && !empty($this->password)) {
return true;
}
return false;
}
public function create_admin($username, $password) {
// Hash the new password if changed
$hash = password_hash($password, PASSWORD_DEFAULT);
// Save new username if it has changed
if($username === "") {
echo json_encode(array("message" => "Username not valid", "error" => true));
exit();
}
$this->username = $username;
$this->password = $hash;
if($this->save_admin()) {
return true;
} else {
return false;
}
}
public function save_admin() {
$this->token_encrypter = md5(rand(0,1000));
$save = json_encode(array("username" => $this->username, "password" => $this->password, "token_encrypter" => $this->token_encrypter));
if(file_put_contents($this->path, $save)) {
return true;
}
return false;
}
// Validate Plex Token
function decrypt_cookie($cookie) {
try {
// Debase cookie
$cookie_debased = base64_decode($cookie, true);
if ($cookie_debased === false) {
throw new Exception('Encryption failure. Cookie invalid.');
}
// Assign variables
$nonceSize = openssl_cipher_iv_length(self::METHOD);
$nonce = mb_substr($cookie_debased, 0, $nonceSize, '8bit');
$ciphertext = mb_substr($cookie_debased, $nonceSize, null, '8bit');
// Decrypt cookie
$cookie_data = openssl_decrypt(
$ciphertext,
self::METHOD,
$this->token_encrypter,
OPENSSL_RAW_DATA,
$nonce
);
// Decode the JSON response
$cookie_result = json_decode($cookie_data, true);
// Return Plex token
return json_encode(array("message" => 'Login accepted.', "error" => false, "data" => $cookie_result));
// Catch errors
} catch (Exception $e) {
echo json_encode(array("message" => $e->getMessage(), "error" => true, "data" => array()));
exit(0);
}
}
function validate_cookie($cookie_object) {
// Validate admin variables
if(!$cookie_object || empty($cookie_object) || !isset($cookie_object->data->username) || !isset($cookie_object->data->password) || !isset($cookie_object->data->date)) {
return false;
}
$now = new DateTime('NOW');
$then = date_create_from_format('Y-m-d', $cookie_object->data->date);
$diff = (array) date_diff($now, $then);
if($diff['days'] > 2) {
return false;
}
return true;
}
}
?>

View file

@ -6,7 +6,8 @@ class Auth {
private $token_encrypter;
private $strong = true;
private $header = 'application/json';
private $x_plex_product = 'Plex-Wrapped';
private $application_url;
private $x_plex_product = 'Wrapperr';
const METHOD = 'aes-256-ctr';
// Constructor
@ -17,6 +18,7 @@ class Auth {
$config_file = new Config();
$this->client_id = $config_file->client_id;
$this->token_encrypter = $config_file->token_encrypter;
$this->application_url = $config_file->application_url;
}
@ -38,7 +40,18 @@ class Auth {
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Add payload
$payload = array( "strong"=> $this->strong, "X-Plex-Product" => $this->x_plex_product, "X-Plex-Client-Identifier" => $this->client_id );
$payload = array( "strong"=> $this->strong,
"X-Plex-Product" => $this->x_plex_product,
"X-Plex-Client-Identifier" => $this->client_id,
"X-Plex-Version" => "2.0",
"X-Plex-Model" => "Plex OAuth",
"X-Plex-Language" => 'en'
);
if($this->application_url !== '') {
array_push($headers, "Host: $this->application_url");
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
// Add headers
@ -57,13 +70,19 @@ class Auth {
// Closing curl
curl_close($ch);
// Decode the JSON response
return $result;
// Catch errors
} catch (Exception $e) {
// Log error
require_once(dirname(__FILE__) . '/log.php');
$log = new Log();
$log->log_activity('auth.php', 'unknown', 'Error: ' . $e->getMessage());
echo json_encode(array("message" => $e->getMessage(), "error" => true, "data" => array()));
exit(0);
}
@ -97,7 +116,18 @@ class Auth {
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Add payload
$payload = array( "code"=> $code, "X-Plex-Client-Identifier" => $this->client_id );
$payload = array(
"code"=> $code,
"X-Plex-Client-Identifier" => $this->client_id,
"X-Plex-Version" => "2.0",
"X-Plex-Model" => "Plex OAuth",
"X-Plex-Language" => 'en'
);
if($this->application_url !== '') {
array_push($headers, "Host: $this->application_url");
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
@ -145,8 +175,15 @@ class Auth {
// Catch errors
} catch (Exception $e) {
// Log error
require_once(dirname(__FILE__) . '/log.php');
$log = new Log();
$log->log_activity('auth.php', 'unknown', 'Error: ' . $e->getMessage());
echo json_encode(array("message" => $e->getMessage(), "error" => true, "data" => array()));
exit(0);
}
}
@ -162,7 +199,7 @@ class Auth {
// Debase token-cookie
$token_debased = base64_decode($token, true);
if ($token_debased === false) {
throw new Exception('Encryption failure.');
throw new Exception('Encryption failure. Failed to decrypt login cookie.');
}
// Assign variables
@ -188,7 +225,19 @@ class Auth {
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Add payload
$payload = array( "X-Plex-Token"=> $x_plex_token, "X-Plex-Client-Identifier" => $this->client_id, "X-Plex-Product" => $this->x_plex_product );
$payload = array(
"X-Plex-Token"=> $x_plex_token,
"X-Plex-Client-Identifier" => $this->client_id,
"X-Plex-Product" => $this->x_plex_product,
"X-Plex-Version" => "2.0",
"X-Plex-Model" => "Plex OAuth",
"X-Plex-Language" => 'en'
);
if($this->application_url !== '') {
array_push($headers, "Host: $this->application_url");
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
@ -218,8 +267,15 @@ class Auth {
// Catch errors
} catch (Exception $e) {
// Log error
require_once(dirname(__FILE__) . '/log.php');
$log = new Log();
$log->log_activity('auth.php', 'unknown', 'Error: ' . $e->getMessage());
echo json_encode(array("message" => $e->getMessage(), "error" => true, "data" => array()));
exit(0);
}
}

View file

@ -12,38 +12,125 @@ class Config {
public $tautulli_length;
public $tautulli_root;
public $tautulli_libraries;
public $ssl;
public $https;
// Admin user
public $password;
public $username;
// Plex-Wrapped config
public $plex_wrapped_version = 'v2.1.0';
// Wrapperr config
public $wrapperr_version = 'v2.2.0';
public $timezone;
public $application_name;
public $application_url;
public $use_cache;
public $use_logs;
public $client_id;
public $plex_wrapped_root;
public $wrapperr_root;
public $token_encrypter;
public $create_share_links;
// Plex Wrapped custom
// Wrapperr custom
public $wrapped_start;
public $wrapped_end;
public $stats_intro;
public $create_share_links;
// Wrapperr custom movies
public $get_user_movie_stats;
public $get_user_movie_stats_title;
public $get_user_movie_stats_subtitle;
public $get_user_movie_stats_subsubtitle;
public $get_user_movie_stats_subtitle_one;
public $get_user_movie_stats_subsubtitle_one;
public $get_user_movie_stats_subtitle_none;
public $get_user_movie_stats_subsubtitle_none;
public $get_user_movie_stats_top_movie;
public $get_user_movie_stats_top_movie_plural;
public $get_user_movie_stats_movie_completion_title;
public $get_user_movie_stats_movie_completion_title_plural;
public $get_user_movie_stats_movie_completion_subtitle;
public $get_user_movie_stats_pause_title;
public $get_user_movie_stats_pause_subtitle;
public $get_user_movie_stats_pause_title_one;
public $get_user_movie_stats_pause_subtitle_one;
public $get_user_movie_stats_pause_title_none;
public $get_user_movie_stats_pause_subtitle_none;
public $get_user_movie_stats_oldest_title;
public $get_user_movie_stats_oldest_subtitle;
public $get_user_movie_stats_oldest_subtitle_pre_1950;
public $get_user_movie_stats_oldest_subtitle_pre_1975;
public $get_user_movie_stats_oldest_subtitle_pre_2000;
public $get_user_movie_stats_spent_title;
// Wrapperr custom shows
public $get_user_show_stats;
public $get_user_show_buddy;
public $get_user_show_stats_title;
public $get_user_show_stats_subtitle;
public $get_user_show_stats_subsubtitle;
public $get_user_show_stats_subtitle_one;
public $get_user_show_stats_subsubtitle_one;
public $get_user_show_stats_subtitle_none;
public $get_user_show_stats_subsubtitle_none;
public $get_user_show_stats_top_show;
public $get_user_show_stats_top_show_plural;
public $get_user_show_stats_spent_title;
public $get_user_show_stats_most_played_title;
public $get_user_show_stats_most_played_subtitle;
public $get_user_show_stats_buddy_title;
public $get_user_show_stats_buddy_subtitle;
public $get_user_show_stats_buddy_title_none;
public $get_user_show_stats_buddy_subtitle_none;
// Wrapperr custom music
public $get_user_music_stats;
public $get_user_music_stats_title;
public $get_user_music_stats_subtitle;
public $get_user_music_stats_subsubtitle;
public $get_user_music_stats_subtitle_one;
public $get_user_music_stats_subsubtitle_one;
public $get_user_music_stats_subtitle_none;
public $get_user_music_stats_subsubtitle_none;
public $get_user_music_stats_top_track;
public $get_user_music_stats_top_track_plural;
public $get_user_music_stats_top_album_plural;
public $get_user_music_stats_top_artist_plural;
public $get_user_music_stats_spent_title;
public $get_user_music_stats_spent_subtitle;
public $get_user_music_stats_oldest_album_title;
public $get_user_music_stats_oldest_album_subtitle;
// Wrapperr custom server-wide
public $get_year_stats_title;
public $get_year_stats_subtitle;
public $get_year_stats_subsubtitle;
public $get_year_stats_movies;
public $get_year_stats_movies_title;
public $get_year_stats_shows;
public $get_year_stats_shows_title;
public $get_year_stats_music;
public $get_year_stats_music_title;
public $get_year_stats_leaderboard;
public $get_year_stats_leaderboard_title;
public $get_year_stats_movies_duration_title;
public $get_year_stats_shows_duration_title;
public $get_year_stats_music_duration_title;
public $get_year_stats_duration_sum_title;
// Wrapperr language variables
public $wrapperr_and;
public $wrapperr_play;
public $wrapperr_play_plural;
public $wrapperr_day;
public $wrapperr_day_plural;
public $wrapperr_hour;
public $wrapperr_hour_plural;
public $wrapperr_minute;
public $wrapperr_minute_plural;
public $wrapperr_second;
public $wrapperr_second_plural;
public $wrapperr_sort_plays;
public $wrapperr_sort_duration;
// Constructor
public function __construct(){
// Declare config path
$this->path = dirname(__FILE__, 3) . '/config/config.json';
@ -60,51 +147,720 @@ class Config {
// Parse JSON from config
$json = json_decode(file_get_contents($this->path));
if(!empty($json)) {
// Assign values from config file
// Assign values from config file
if(isset($json->tautulli_apikey)) {
$this->tautulli_apikey = $json->tautulli_apikey;
} else {
$this->tautulli_apikey = '';
}
if(isset($json->tautulli_ip)) {
$this->tautulli_ip = $json->tautulli_ip;
$this->tautulli_port = $json->tautulli_port;
$this->tautulli_length = $json->tautulli_length;
$this->tautulli_root = $json->tautulli_root;
$this->tautulli_libraries = $json->tautulli_libraries;
$this->ssl = $json->ssl;
$this->password = $json->password;
$this->username = $json->username;
$this->timezone = $json->timezone;
$this->use_cache = $json->use_cache;
$this->use_logs = $json->use_logs;
$this->client_id = $json->client_id;
$this->token_encrypter = $json->token_encrypter;
$this->plex_wrapped_root = $json->plex_wrapped_root;
$this->wrapped_start = $json->wrapped_start;
$this->wrapped_end = $json->wrapped_end;
$this->stats_intro = $json->stats_intro;
$this->create_share_links = $json->create_share_links;
$this->get_user_movie_stats = $json->get_user_movie_stats;
$this->get_user_show_stats = $json->get_user_show_stats;
$this->get_user_show_buddy = $json->get_user_show_buddy;
$this->get_user_music_stats = $json->get_user_music_stats;
$this->get_year_stats_movies = $json->get_year_stats_movies;
$this->get_year_stats_shows = $json->get_year_stats_shows;
$this->get_year_stats_music = $json->get_year_stats_music;
$this->get_year_stats_leaderboard = $json->get_year_stats_leaderboard;
if($this->plex_wrapped_version !== $json->plex_wrapped_version) {
if(!$this->delete_config()) {
echo json_encode(array(
"message" => "Plex Wrapped configuration is made with version: " . $json->plex_wrapped_version . ", but you are using: " . $this->plex_wrapped_version . ". Delete config.json and re-configure Plex Wrapped again.",
"error" => true));
exit();
}
}
} else {
$this->tautulli_ip = '';
}
// If token encrypter is not set, generate one
if($this->token_encrypter == '') {
if(isset($json->tautulli_port)) {
$this->tautulli_port = $json->tautulli_port;
} else {
$this->tautulli_port = '';
}
if(isset($json->tautulli_length)) {
$this->tautulli_length = $json->tautulli_length;
} else {
$this->tautulli_length = 5000;
}
if(isset($json->tautulli_root)) {
$this->tautulli_root = $json->tautulli_root;
} else {
$this->tautulli_root = '';
}
if(isset($json->tautulli_libraries)) {
$this->tautulli_libraries = $json->tautulli_libraries;
} else {
$this->tautulli_libraries = '';
}
if(isset($json->https)) {
$this->https = $json->https;
} else {
$this->https = false;
}
if(isset($json->timezone)) {
$this->timezone = $json->timezone;
} else {
$this->timezone = '';
}
if(isset($json->use_cache)) {
$this->use_cache = $json->use_cache;
} else {
$this->use_cache = true;
}
if(isset($json->use_logs)) {
$this->use_logs = $json->use_logs;
} else {
$this->use_logs = false;
}
if(isset($json->client_id) && $json->client_id !== '') {
$this->client_id = $json->client_id;
} else {
$this->client_id = md5(rand(0,1000));
}
if(isset($json->token_encrypter) && $json->token_encrypter !== '') {
$this->token_encrypter = $json->token_encrypter;
} else {
$this->token_encrypter = md5(rand(0,1000));
}
if(isset($json->wrapperr_root)) {
$this->wrapperr_root = $json->wrapperr_root;
} else {
$this->wrapperr_root = '';
}
if(isset($json->application_name)) {
$this->application_name = $json->application_name;
} else {
$this->application_name = 'Wrapperr';
}
if(isset($json->application_url)) {
$this->application_url = $json->application_url;
} else {
$this->application_url = '';
}
if(isset($json->wrapped_start)) {
$this->wrapped_start = $json->wrapped_start;
} else {
$this->wrapped_start = 1609455600;
}
if(isset($json->wrapped_end)) {
$this->wrapped_end = $json->wrapped_end;
} else {
$this->wrapped_end = 1640991540;
}
if(isset($json->stats_intro)) {
$this->stats_intro = $json->stats_intro;
} else {
$this->stats_intro = '<h1>Hey there, {user}!</h1><h2>New year, new page of statistics...</h2>';
}
if(isset($json->stats_outro)) {
$this->stats_outro = $json->stats_outro;
} else {
$this->stats_outro = '<h1>Hope you are staying safe!</h1><h2>Goodbye.</h2>';
}
if(isset($json->create_share_links)) {
$this->create_share_links = $json->create_share_links;
} else {
$this->create_share_links = false;
}
// Movie values
if(isset($json->get_user_movie_stats)) {
$this->get_user_movie_stats = $json->get_user_movie_stats;
} else {
$this->get_user_movie_stats = false;
}
// Title
if(isset($json->get_user_movie_stats_title)) {
$this->get_user_movie_stats_title = $json->get_user_movie_stats_title;
} else {
$this->get_user_movie_stats_title = 'Movies!';
}
// Multiple movies subtitle
if(isset($json->get_user_movie_stats_subtitle)) {
$this->get_user_movie_stats_subtitle = $json->get_user_movie_stats_subtitle;
} else {
$this->get_user_movie_stats_subtitle = 'You watched {movie_count} movies. That\'s a lot of movies!';
}
// Multiple movies sub-subtitle
if(isset($json->get_user_movie_stats_subsubtitle)) {
$this->get_user_movie_stats_subsubtitle = $json->get_user_movie_stats_subsubtitle;
} else {
$this->get_user_movie_stats_subsubtitle = '(or not, I am pre-programmed to say that)';
}
// One movie subtitle
if(isset($json->get_user_movie_stats_subtitle_one)) {
$this->get_user_movie_stats_subtitle_one = $json->get_user_movie_stats_subtitle_one;
} else {
$this->get_user_movie_stats_subtitle_one = 'You watched one movie. You know what you like!';
}
// One movie sub-subtitle
if(isset($json->get_user_movie_stats_subsubtitle_one)) {
$this->get_user_movie_stats_subsubtitle_one = $json->get_user_movie_stats_subsubtitle_one;
} else {
$this->get_user_movie_stats_subsubtitle_one = '(at least you tried it out)';
}
// No movies subtitle
if(isset($json->get_user_movie_stats_subtitle_none)) {
$this->get_user_movie_stats_subtitle_none = $json->get_user_movie_stats_subtitle_none;
} else {
$this->get_user_movie_stats_subtitle_none = 'You watched no movies. That\'s impressive in itself!';
}
// No movies sub-subtitle
if(isset($json->get_user_movie_stats_subsubtitle_none)) {
$this->get_user_movie_stats_subsubtitle_none = $json->get_user_movie_stats_subsubtitle_none;
} else {
$this->get_user_movie_stats_subsubtitle_none = '(might wanna try it)';
}
// Top movie title
if(isset($json->get_user_movie_stats_top_movie)) {
$this->get_user_movie_stats_top_movie = $json->get_user_movie_stats_top_movie;
} else {
$this->get_user_movie_stats_top_movie = 'Your movie';
}
// Top movies title
if(isset($json->get_user_movie_stats_top_movie_plural)) {
$this->get_user_movie_stats_top_movie_plural = $json->get_user_movie_stats_top_movie_plural;
} else {
$this->get_user_movie_stats_top_movie_plural = 'Your top movies';
}
// Movie completion title
if(isset($json->get_user_movie_stats_movie_completion_title)) {
$this->get_user_movie_stats_movie_completion_title = $json->get_user_movie_stats_movie_completion_title;
} else {
$this->get_user_movie_stats_movie_completion_title = 'You saw {movie_finish_percent}% of the movie!';
}
// Movie completion title plural
if(isset($json->get_user_movie_stats_movie_completion_title_plural)) {
$this->get_user_movie_stats_movie_completion_title_plural = $json->get_user_movie_stats_movie_completion_title_plural;
} else {
$this->get_user_movie_stats_movie_completion_title_plural = 'Your average movie finishing percentage was {movie_finish_percent}%!';
}
// Movie completion subtitle
if(isset($json->get_user_movie_stats_movie_completion_subtitle)) {
$this->get_user_movie_stats_movie_completion_subtitle = $json->get_user_movie_stats_movie_completion_subtitle;
} else {
$this->get_user_movie_stats_movie_completion_subtitle = 'You\'re not watching the credits like a nerd, are you?';
}
// Movie pause title
if(isset($json->get_user_movie_stats_pause_title)) {
$this->get_user_movie_stats_pause_title = $json->get_user_movie_stats_pause_title;
} else {
$this->get_user_movie_stats_pause_title = 'Your longest movie pause was watching {movie_title}.';
}
// Movie pause subtitle
if(isset($json->get_user_movie_stats_pause_subtitle)) {
$this->get_user_movie_stats_pause_subtitle = $json->get_user_movie_stats_pause_subtitle;
} else {
$this->get_user_movie_stats_pause_subtitle = 'It was paused for {pause_duration}...';
}
// Movie pause title (one movie)
if(isset($json->get_user_movie_stats_pause_title_one)) {
$this->get_user_movie_stats_pause_title_one = $json->get_user_movie_stats_pause_title_one;
} else {
$this->get_user_movie_stats_pause_title_one = 'One movie, but you still had to pause it.';
}
// Movie pause subtitle (one movie)
if(isset($json->get_user_movie_stats_pause_subtitle_one)) {
$this->get_user_movie_stats_pause_subtitle_one = $json->get_user_movie_stats_pause_subtitle_one;
} else {
$this->get_user_movie_stats_pause_subtitle_one = 'It was paused for {pause_duration}...';
}
// Movie pause title (no pausing)
if(isset($json->get_user_movie_stats_pause_title_none)) {
$this->get_user_movie_stats_pause_title_none = $json->get_user_movie_stats_pause_title_none;
} else {
$this->get_user_movie_stats_pause_title_none = 'Bladder of steel!';
}
// Movie pause subtitle (no pausing)
if(isset($json->get_user_movie_stats_pause_subtitle_none)) {
$this->get_user_movie_stats_pause_subtitle_none = $json->get_user_movie_stats_pause_subtitle_none;
} else {
$this->get_user_movie_stats_pause_subtitle_none = 'You never paused a single movie.';
}
// Movie oldest title
if(isset($json->get_user_movie_stats_oldest_title)) {
$this->get_user_movie_stats_oldest_title = $json->get_user_movie_stats_oldest_title;
} else {
$this->get_user_movie_stats_oldest_title = 'The oldest movie you watched was {movie_title}.';
}
// Movie oldest subtitle
if(isset($json->get_user_movie_stats_oldest_subtitle)) {
$this->get_user_movie_stats_oldest_subtitle = $json->get_user_movie_stats_oldest_subtitle;
} else {
$this->get_user_movie_stats_oldest_subtitle = 'Enjoying the classics, huh?';
}
// Movie oldest (from before 1950) subtitle
if(isset($json->get_user_movie_stats_oldest_subtitle_pre_1950)) {
$this->get_user_movie_stats_oldest_subtitle_pre_1950 = $json->get_user_movie_stats_oldest_subtitle_pre_1950;
} else {
$this->get_user_movie_stats_oldest_subtitle_pre_1950 = 'I didn\'t even know they made movies back then...';
}
// Movie oldest (from before 1975) subtitle
if(isset($json->get_user_movie_stats_oldest_subtitle_pre_1975)) {
$this->get_user_movie_stats_oldest_subtitle_pre_1975 = $json->get_user_movie_stats_oldest_subtitle_pre_1975;
} else {
$this->get_user_movie_stats_oldest_subtitle_pre_1975 = 'Did it even have color?';
}
// Movie oldest (from before 2000) subtitle
if(isset($json->get_user_movie_stats_oldest_subtitle_pre_2000)) {
$this->get_user_movie_stats_oldest_subtitle_pre_2000 = $json->get_user_movie_stats_oldest_subtitle_pre_2000;
} else {
$this->get_user_movie_stats_oldest_subtitle_pre_2000 = 'Was it a 4K, UHD, 3D, Dolby Atmos remaster?';
}
// Movie spent title
if(isset($json->get_user_movie_stats_spent_title)) {
$this->get_user_movie_stats_spent_title = $json->get_user_movie_stats_spent_title;
} else {
$this->get_user_movie_stats_spent_title = 'You spent {movie_sum_duration} watching movies.';
}
// Show values
if(isset($json->get_user_show_stats)) {
$this->get_user_show_stats = $json->get_user_show_stats;
} else {
$this->get_user_show_stats = false;
}
// Get show-buddy
if(isset($json->get_user_show_stats_buddy)) {
$this->get_user_show_stats_buddy = $json->get_user_show_stats_buddy;
} else {
$this->get_user_show_stats_buddy = false;
}
// Show title
if(isset($json->get_user_show_stats_title)) {
$this->get_user_show_stats_title = $json->get_user_show_stats_title;
} else {
$this->get_user_show_stats_title = 'Shows!';
}
// Multiple shows subtitle
if(isset($json->get_user_show_stats_subtitle)) {
$this->get_user_show_stats_subtitle = $json->get_user_show_stats_subtitle;
} else {
$this->get_user_show_stats_subtitle = 'You watched {show_count} different shows.';
}
// Multiple shows sub-subtitle
if(isset($json->get_user_show_stats_subsubtitle)) {
$this->get_user_show_stats_subsubtitle = $json->get_user_show_stats_subsubtitle;
} else {
$this->get_user_show_stats_subsubtitle = '(no, watching The Office twice doesn\'t count as two shows)';
}
// One show subtitle
if(isset($json->get_user_show_stats_subtitle_one)) {
$this->get_user_show_stats_subtitle_one = $json->get_user_show_stats_subtitle_one;
} else {
$this->get_user_show_stats_subtitle_one = 'You watched one show.';
}
// One show sub-subtitle
if(isset($json->get_user_show_stats_subsubtitle_one)) {
$this->get_user_show_stats_subsubtitle_one = $json->get_user_show_stats_subsubtitle_one;
} else {
$this->get_user_show_stats_subsubtitle_one = '(better not be that same one again...)';
}
// No shows subtitle
if(isset($json->get_user_show_stats_subtitle_none)) {
$this->get_user_show_stats_subtitle_none = $json->get_user_show_stats_subtitle_none;
} else {
$this->get_user_show_stats_subtitle_none = 'You watched 0 shows. I get it, it\'s not for everyone!';
}
// No shows sub-subtitle
if(isset($json->get_user_show_stats_subsubtitle_none)) {
$this->get_user_show_stats_subsubtitle_none = $json->get_user_show_stats_subsubtitle_none;
} else {
$this->get_user_show_stats_subsubtitle_none = '(might wanna try it)';
}
// Top show title
if(isset($json->get_user_show_stats_top_show)) {
$this->get_user_show_stats_top_show = $json->get_user_show_stats_top_show;
} else {
$this->get_user_show_stats_top_show = 'Your show';
}
// Top shows title
if(isset($json->get_user_show_stats_top_show_plural)) {
$this->get_user_show_stats_top_show_plural = $json->get_user_show_stats_top_show_plural;
} else {
$this->get_user_show_stats_top_show_plural = 'Your top shows';
}
// Time spent on shows
if(isset($json->get_user_show_stats_spent_title)) {
$this->get_user_show_stats_spent_title = $json->get_user_show_stats_spent_title;
} else {
$this->get_user_show_stats_spent_title = 'You spent {show_sum_duration} watching shows.';
}
// Top episode title
if(isset($json->get_user_show_stats_most_played_title)) {
$this->get_user_show_stats_most_played_title = $json->get_user_show_stats_most_played_title;
} else {
$this->get_user_show_stats_most_played_title = 'You really liked the episode {show_episode} from {show_title}.';
}
// Top episode subtitle
if(isset($json->get_user_show_stats_most_played_subtitle)) {
$this->get_user_show_stats_most_played_subtitle = $json->get_user_show_stats_most_played_subtitle;
} else {
$this->get_user_show_stats_most_played_subtitle = 'It recieved {episode_play_sum} and was endured for {episode_duration_sum}.';
}
// Show buddy title
if(isset($json->get_user_show_stats_buddy_title)) {
$this->get_user_show_stats_buddy_title = $json->get_user_show_stats_buddy_title;
} else {
$this->get_user_show_stats_buddy_title = 'Your top show was {top_show_title}. And you\'re not alone! Your {top_show_title}-buddy is {buddy_username}!';
}
// Show buddy subtitle
if(isset($json->get_user_show_stats_buddy_subtitle)) {
$this->get_user_show_stats_buddy_subtitle = $json->get_user_show_stats_buddy_subtitle;
} else {
$this->get_user_show_stats_buddy_subtitle = 'Your combined efforts resulted in {buddy_duration_sum} of {top_show_title}!';
}
// No show buddy title
if(isset($json->get_user_show_stats_buddy_title_none)) {
$this->get_user_show_stats_buddy_title_none = $json->get_user_show_stats_buddy_title_none;
} else {
$this->get_user_show_stats_buddy_title_none = 'Your top show was {top_show_title}.';
}
// No show buddy subtitle
if(isset($json->get_user_show_stats_buddy_subtitle_none)) {
$this->get_user_show_stats_buddy_subtitle_none = $json->get_user_show_stats_buddy_subtitle_none;
} else {
$this->get_user_show_stats_buddy_subtitle_none = 'That means you dared to explore where no one else would, as you are the only viewer of that show. Spread the word!';
}
// Music values
if(isset($json->get_user_music_stats)) {
$this->get_user_music_stats = $json->get_user_music_stats;
} else {
$this->get_user_music_stats = false;
}
// Title
if(isset($json->get_user_music_stats_title)) {
$this->get_user_music_stats_title = $json->get_user_music_stats_title;
} else {
$this->get_user_music_stats_title = 'Music!';
}
// Multiple tracks subtitle
if(isset($json->get_user_music_stats_subtitle)) {
$this->get_user_music_stats_subtitle = $json->get_user_music_stats_subtitle;
} else {
$this->get_user_music_stats_subtitle = 'You listened to {track_count} different tracks.';
}
// Multiple tracks sub-subtitle
if(isset($json->get_user_music_stats_subsubtitle)) {
$this->get_user_music_stats_subsubtitle = $json->get_user_music_stats_subsubtitle;
} else {
$this->get_user_music_stats_subsubtitle = '(if you can call your taste "music"...)';
}
// One track subtitle
if(isset($json->get_user_music_stats_subtitle_one)) {
$this->get_user_music_stats_subtitle_one = $json->get_user_music_stats_subtitle_one;
} else {
$this->get_user_music_stats_subtitle_one = 'You listened to one track.';
}
// One track sub-subtitle
if(isset($json->get_user_music_stats_subsubtitle_one)) {
$this->get_user_music_stats_subsubtitle_one = $json->get_user_music_stats_subsubtitle_one;
} else {
$this->get_user_music_stats_subsubtitle_one = '(whatever floats your boat...)';
}
// No tracks subtitle
if(isset($json->get_user_music_stats_subtitle_none)) {
$this->get_user_music_stats_subtitle_none = $json->get_user_music_stats_subtitle_none;
} else {
$this->get_user_music_stats_subtitle_none = 'You listened to 0 tracks. No speakers, huh?';
}
// No tracks sub-subtitle
if(isset($json->get_user_music_stats_subsubtitle_none)) {
$this->get_user_music_stats_subsubtitle_none = $json->get_user_music_stats_subsubtitle_none;
} else {
$this->get_user_music_stats_subsubtitle_none = '(might wanna try it)';
}
// Top track title
if(isset($json->get_user_music_stats_top_track)) {
$this->get_user_music_stats_top_track = $json->get_user_music_stats_top_track;
} else {
$this->get_user_music_stats_top_track = 'Your track';
}
// Top tracks title
if(isset($json->get_user_music_stats_top_track_plural)) {
$this->get_user_music_stats_top_track_plural = $json->get_user_music_stats_top_track_plural;
} else {
$this->get_user_music_stats_top_track_plural = 'Your top tracks';
}
// Top albums title
if(isset($json->get_user_music_stats_top_album_plural)) {
$this->get_user_music_stats_top_album_plural = $json->get_user_music_stats_top_album_plural;
} else {
$this->get_user_music_stats_top_album_plural = 'Your top albums';
}
// Top artists title
if(isset($json->get_user_music_stats_top_artist_plural)) {
$this->get_user_music_stats_top_artist_plural = $json->get_user_music_stats_top_artist_plural;
} else {
$this->get_user_music_stats_top_artist_plural = 'Your top artists';
}
// Time spent on music title
if(isset($json->get_user_music_stats_spent_title)) {
$this->get_user_music_stats_spent_title = $json->get_user_music_stats_spent_title;
} else {
$this->get_user_music_stats_spent_title = 'You spent {music_sum_duration} listening to music.';
}
// Time spent on music subtitle
if(isset($json->get_user_music_stats_spent_subtitle)) {
$this->get_user_music_stats_spent_subtitle = $json->get_user_music_stats_spent_subtitle;
} else {
$this->get_user_music_stats_spent_subtitle = 'That is {music_sum_minutes}!';
}
// Oldest album title
if(isset($json->get_user_music_stats_oldest_album_title)) {
$this->get_user_music_stats_oldest_album_title = $json->get_user_music_stats_oldest_album_title;
} else {
$this->get_user_music_stats_oldest_album_title = 'The oldest album you listened to was {album_title} by {album_artist}.';
}
// Oldest album subtitle
if(isset($json->get_user_music_stats_oldest_album_subtitle)) {
$this->get_user_music_stats_oldest_album_subtitle = $json->get_user_music_stats_oldest_album_subtitle;
} else {
$this->get_user_music_stats_oldest_album_subtitle = 'How about a copy on vinyl?';
}
// Year stats title
if(isset($json->get_year_stats_title)) {
$this->get_year_stats_title = $json->get_year_stats_title;
} else {
$this->get_year_stats_title = 'Server-wide statistics!';
}
// Year stats subtitle
if(isset($json->get_year_stats_subtitle)) {
$this->get_year_stats_subtitle = $json->get_year_stats_subtitle;
} else {
$this->get_year_stats_subtitle = 'It\'s okay to feel shame if you see yourself on the list.';
}
// Server-wide stats subsubtitle
if(isset($json->get_year_stats_subsubtitle)) {
$this->get_year_stats_subsubtitle = $json->get_year_stats_subsubtitle;
} else {
$this->get_year_stats_subsubtitle = '(or if you don\'t...)';
}
// Get movie stats for server
if(isset($json->get_year_stats_movies)) {
$this->get_year_stats_movies = $json->get_year_stats_movies;
} else {
$this->get_year_stats_movies = false;
}
// Top movie stats for server title
if(isset($json->get_year_stats_movies_title)) {
$this->get_year_stats_movies_title = $json->get_year_stats_movies_title;
} else {
$this->get_year_stats_movies_title = 'Top movies';
}
// Movie stats duration sum for server title
if(isset($json->get_year_stats_movies_duration_title)) {
$this->get_year_stats_movies_duration_title = $json->get_year_stats_movies_duration_title;
} else {
$this->get_year_stats_movies_duration_title = 'All users combined spent {movie_duration_sum} watching movies.';
}
if(isset($json->get_year_stats_shows)) {
$this->get_year_stats_shows = $json->get_year_stats_shows;
} else {
$this->get_year_stats_shows = false;
}
// Top shows stats for server title
if(isset($json->get_year_stats_shows_title)) {
$this->get_year_stats_shows_title = $json->get_year_stats_shows_title;
} else {
$this->get_year_stats_shows_title = 'Top shows';
}
// Shows stats duration sum for server title
if(isset($json->get_year_stats_shows_duration_title)) {
$this->get_year_stats_shows_duration_title = $json->get_year_stats_shows_duration_title;
} else {
$this->get_year_stats_shows_duration_title = 'All users combined spent {show_duration_sum} watching shows.';
}
if(isset($json->get_year_stats_music)) {
$this->get_year_stats_music = $json->get_year_stats_music;
} else {
$this->get_year_stats_music = false;
}
// Top shows stats for server title
if(isset($json->get_year_stats_music_title)) {
$this->get_year_stats_music_title = $json->get_year_stats_music_title;
} else {
$this->get_year_stats_music_title = 'Top artists';
}
// Shows stats duration sum for server title
if(isset($json->get_year_stats_music_duration_title)) {
$this->get_year_stats_music_duration_title = $json->get_year_stats_music_duration_title;
} else {
$this->get_year_stats_music_duration_title = 'All users combined spent {music_duration_sum} listening to music.';
}
if(isset($json->get_year_stats_leaderboard)) {
$this->get_year_stats_leaderboard = $json->get_year_stats_leaderboard;
} else {
$this->get_year_stats_leaderboard = false;
}
// Top users for server title
if(isset($json->get_year_stats_leaderboard_title)) {
$this->get_year_stats_leaderboard_title = $json->get_year_stats_leaderboard_title;
} else {
$this->get_year_stats_leaderboard_title = 'Top users';
}
// Sum of duration for server title
if(isset($json->get_year_stats_duration_sum_title)) {
$this->get_year_stats_duration_sum_title = $json->get_year_stats_duration_sum_title;
} else {
$this->get_year_stats_duration_sum_title = 'That is {all_duration_sum} of content!';
}
// Language settings
if(isset($json->wrapperr_and)) {
$this->wrapperr_and = $json->wrapperr_and;
} else {
$this->wrapperr_and = 'and';
}
if(isset($json->wrapperr_play)) {
$this->wrapperr_play = $json->wrapperr_play;
} else {
$this->wrapperr_play = 'play';
}
if(isset($json->wrapperr_play_plural)) {
$this->wrapperr_play_plural = $json->wrapperr_play_plural;
} else {
$this->wrapperr_play_plural = 'plays';
}
if(isset($json->wrapperr_day)) {
$this->wrapperr_day = $json->wrapperr_day;
} else {
$this->wrapperr_day = 'day';
}
if(isset($json->wrapperr_day_plural)) {
$this->wrapperr_day_plural = $json->wrapperr_day_plural;
} else {
$this->wrapperr_day_plural = 'days';
}
if(isset($json->wrapperr_hour)) {
$this->wrapperr_hour = $json->wrapperr_hour;
} else {
$this->wrapperr_hour = 'hour';
}
if(isset($json->wrapperr_hour_plural)) {
$this->wrapperr_hour_plural = $json->wrapperr_hour_plural;
} else {
$this->wrapperr_hour_plural = 'hours';
}
if(isset($json->wrapperr_minute)) {
$this->wrapperr_minute = $json->wrapperr_minute;
} else {
$this->wrapperr_minute = 'minute';
}
if(isset($json->wrapperr_minute_plural)) {
$this->wrapperr_minute_plural = $json->wrapperr_minute_plural;
} else {
$this->wrapperr_minute_plural = 'minutes';
}
if(isset($json->wrapperr_second)) {
$this->wrapperr_second = $json->wrapperr_second;
} else {
$this->wrapperr_second = 'second';
}
if(isset($json->wrapperr_second_plural)) {
$this->wrapperr_second_plural = $json->wrapperr_second_plural;
} else {
$this->wrapperr_second_plural = 'seconds';
}
if(isset($json->wrapperr_sort_plays)) {
$this->wrapperr_sort_plays = $json->wrapperr_sort_plays;
} else {
$this->wrapperr_sort_plays = 'Sort by plays';
}
if(isset($json->wrapperr_sort_duration)) {
$this->wrapperr_sort_duration = $json->wrapperr_sort_duration;
} else {
$this->wrapperr_sort_duration = 'Sort by duration';
}
}
@ -125,15 +881,22 @@ class Config {
return false;
}
public function verify_wrapped_admin($username, $password) {
return password_verify($password, $this->password) && $username == $this->username;
}
public function is_configured() {
return !empty(file_get_contents($this->path));
// Make sure an admin is created
require_once(dirname(__FILE__) . '/admin.php');
$admin = new Admin();
if(!$admin->is_configured()) {
return false;
}
if($this->tautulli_ip !== '' && $this->tautulli_apikey !== '' && $this->tautulli_length !== '' && $this->timezone !== '' && $this->wrapped_start !== '' && $this->wrapped_end !== '')
return true;
else {
return false;
}
}
public function save_config($data, $clear_cache) {
public function save_config($clear_cache) {
// If clear cache is enabled, clear the cache
if($clear_cache) {
@ -145,51 +908,14 @@ class Config {
exit();
}
}
// Hash the new password if changed
if($data->password !== "") {
$hash = password_hash($data->password, PASSWORD_DEFAULT);
$this->password = $hash;
}
// Save new username if it has changed
if($data->username !== "") {
$this->username = $data->username;
}
// Assign new variables from recieved config
$this->tautulli_apikey = $data->tautulli_apikey;
$this->tautulli_ip = $data->tautulli_ip;
$this->tautulli_port = $data->tautulli_port;
$this->tautulli_length = $data->tautulli_length;
$this->tautulli_root = $data->tautulli_root;
$this->tautulli_libraries = $data->tautulli_libraries;
$this->ssl = $data->ssl;
$this->timezone = $data->timezone;
$this->use_cache = $data->use_cache;
$this->use_logs = $data->use_logs;
$this->client_id = $data->client_id;
$this->plex_wrapped_root = $data->plex_wrapped_root;
$this->wrapped_start = $data->wrapped_start;
$this->wrapped_end = $data->wrapped_end;
$this->stats_intro = $data->stats_intro;
$this->create_share_links = $data->create_share_links;
$this->get_user_movie_stats = $data->get_user_movie_stats;
$this->get_user_show_stats = $data->get_user_show_stats;
$this->get_user_show_buddy = $data->get_user_show_buddy;
$this->get_user_music_stats = $data->get_user_music_stats;
$this->get_year_stats_movies = $data->get_year_stats_movies;
$this->get_year_stats_shows = $data->get_year_stats_shows;
$this->get_year_stats_music = $data->get_year_stats_music;
$this->get_year_stats_leaderboard = $data->get_year_stats_leaderboard;
// Generate new random client ID if empty
if($this->client_id === "") {
if($this->client_id === '') {
$this->client_id = md5(rand(0,1000));
}
// If token encrypter is not set, generate one
if($this->token_encrypter == '') {
if($this->token_encrypter === '') {
$this->token_encrypter = md5(rand(0,1000));
}

View file

@ -21,14 +21,23 @@ class Log {
echo json_encode(array("message" => "Failed to create wrapped.log. Is the 'config' directory writable?", "error" => true));
exit();
}
fwrite($create_log, 'Plex Wrapped');
fwrite($create_log, 'Wrapperr');
fclose($create_log);
}
// Assign use_logs configuration from config
include_once(dirname(__FILE__, 3) . '/api/objects/config.php');
$config = new Config();
$this->use_logs = $config->use_logs;
$fail = false;
try {
// Assign use_logs configuration from config
include_once(dirname(__FILE__, 3) . '/api/objects/config.php');
$config = new Config();
$this->use_logs = $config->use_logs;
} catch (Exception $e) {
$fail = true;
}
if($fail) {
$this->use_logs = false;
}
}
public function log_activity($function, $id, $message) {

79
api/set_admin.php Normal file
View file

@ -0,0 +1,79 @@
<?php
// Required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// Files needed to use objects
require(dirname(__FILE__) . '/objects/log.php');
require(dirname(__FILE__) . '/objects/admin.php');
// Create variables
$admin = new Admin();
$log = new Log();
$data = json_decode(file_get_contents("php://input"));
// If POST data is empty
if(empty($data) || !isset($data->cookie) || !isset($data->password) || !isset($data->username)) {
// Log use
$log->log_activity('set_admin.php', 'unknown', 'No input provided.');
echo json_encode(array("error" => true, "message" => "No input provided."));
exit(0);
}
// Remove potential harmfull input
$cookie = htmlspecialchars($data->cookie);
$password = $data->password;
$username = $data->username;
// Check if confgiured
if(!$admin->is_configured()) {
// Log use
$log->log_activity('set_admin.php', 'unknown', 'Wrapperr admin is not configured. Can\'t update admin configuration.');
echo json_encode(array("error" => true, "message" => "Wrapperr admin is not configured."));
exit(0);
}
// Decrypt cookie
$cookie_object = json_decode($admin->decrypt_cookie($cookie));
// Validate admin cookie
if(!$admin->validate_cookie($cookie_object)) {
// Log use
$log->log_activity('set_admin.php', 'unknown', 'Admin cookie not valid. Can\'t update admin configuration.');
echo json_encode(array("error" => true, "message" => "Admin cookie not accepted. Log in again."));
exit(0);
}
$admin->username = $username;
$admin->password = password_hash($password, PASSWORD_DEFAULT);
if($admin->save_admin()) {
// Log use
$log->log_activity('set_admin.php', 'admin', 'Updated and saved admin configuration.');
echo json_encode(array("error" => false, "message" => "Admin account updated."));
exit(0);
} else {
// Log use
$log->log_activity('set_admin.php', 'admin', 'Could not save admin configuration. Is the \'config\' directory writable?');
echo json_encode(array("error" => true, "message" => "Admin account was not updated. Is the \'config\' directory writable?"));
exit(0);
}
?>

View file

@ -8,66 +8,232 @@ header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers
// Files needed to use objects
require(dirname(__FILE__) . '/objects/config.php');
require(dirname(__FILE__) . '/objects/admin.php');
require(dirname(__FILE__) . '/objects/log.php');
// Create variables
$config = new Config();
$admin = new Admin();
$log = new Log();
$data = json_decode(file_get_contents("php://input"));
// If POST data is empty
if(empty($data)) {
if(empty($data) || !isset($data->cookie) || !isset($data->data_type)) {
// Log use
$log->log_activity('set_config.php', 'unknown', 'No admin login input provided.');
echo json_encode(array("error" => true, "message" => "No input provided."));
echo json_encode(array("error" => true, "message" => "Invalid input provided."));
exit(0);
}
// Remove potential harmfull input
$password = htmlspecialchars($data->password);
$username = htmlspecialchars($data->username);
$cookie = htmlspecialchars($data->cookie);
// Verify password and username combination
if(!$config->is_configured()) {
// Check if confgiured
if(!$admin->is_configured()) {
// Log use
$log->log_activity('set_config.php', 'unknown', 'Not configured before, saving first-time configuration.');
// Call save function
save_config($data->data, $data->clear_cache);
} else if($config->verify_wrapped_admin($username, $password)) {
// Log use
$log->log_activity('set_config.php', 'unknown', 'Admin login verified.');
$log->log_activity('set_config.php', 'unknown', 'Wrapperr admin is not configured.');
// Call save function
save_config($data->data, $data->clear_cache);
echo json_encode(array("error" => true, "message" => "Wrapperr admin is not configured."));
exit(0);
// If input was given, but is empty
}
// Decrypt cookie
$cookie_object = json_decode($admin->decrypt_cookie($cookie));
// Validate admin cookie
if(!$admin->validate_cookie($cookie_object)) {
// Log use
$log->log_activity('set_config.php', 'unknown', 'Admin cookie not valid.');
echo json_encode(array("error" => true, "message" => "Admin cookie not accepted. Log in again."));
exit(0);
} else {
// Log use
$log->log_activity('set_config.php', 'unknown', 'Wrong admin password/username combination.');
echo json_encode(array("error" => true, "message" => "Username and password combination not accepted.", "password" => true, "data" => array()));
exit(0);
// Call save function
save_config($data->data, $data->data_type, $data->clear_cache);
}
// Retrieve data and save it
function save_config($data, $clear_cache) {
function save_config($data, $data_type, $clear_cache) {
global $config;
global $log;
// Call function to save data
if($config->save_config($data, $clear_cache)) {
if($data_type === 'tautulli_settings') {
$fail = false;
try {
$config->tautulli_apikey = $data->tautulli_apikey;
$config->tautulli_ip = $data->tautulli_ip;
$config->tautulli_port = $data->tautulli_port;
$config->tautulli_length = $data->tautulli_length;
$config->tautulli_root = $data->tautulli_root;
$config->tautulli_libraries = $data->tautulli_libraries;
$config->https = $data->https;
} catch (Exception $e) {
$fail = true;
}
if($fail) {
// Log use
$log->log_activity('set_config.php', 'admin', 'Failed to assign variables from data. Data type: ' . $data_type . '.');
echo json_encode(array("error" => true, "message" => "Failed to assign variables from data."));
exit(0);
}
} else if($data_type === 'wrapperr_settings') {
$fail = false;
try {
$config->use_cache = $data->use_cache;
$config->use_logs = $data->use_logs;
$config->wrapperr_root = $data->wrapperr_root;
$config->application_name = $data->application_name;
$config->application_url = $data->application_url;
$config->create_share_links = $data->create_share_links;
$config->timezone = $data->timezone;
} catch (Exception $e) {
$fail = true;
}
if($fail) {
// Log use
$log->log_activity('set_config.php', 'admin', 'Failed to assign variables from data. Data type: ' . $data_type . '.');
echo json_encode(array("error" => true, "message" => "Failed to assign variables from data."));
exit(0);
}
} else if($data_type === 'wrapperr_customization') {
$fail = false;
try {
$config->wrapped_start = $data->wrapped_start;
$config->wrapped_end = $data->wrapped_end;
$config->stats_intro = $data->stats_intro;
$config->stats_outro = $data->stats_outro;
$config->get_user_movie_stats = $data->get_user_movie_stats;
$config->get_user_movie_stats_title = $data->get_user_movie_stats_title;
$config->get_user_movie_stats_subtitle = $data->get_user_movie_stats_subtitle;
$config->get_user_movie_stats_subsubtitle = $data->get_user_movie_stats_subsubtitle;
$config->get_user_movie_stats_subtitle_one = $data->get_user_movie_stats_subtitle_one;
$config->get_user_movie_stats_subsubtitle_one = $data->get_user_movie_stats_subsubtitle_one;
$config->get_user_movie_stats_subtitle_none = $data->get_user_movie_stats_subtitle_none;
$config->get_user_movie_stats_subsubtitle_none = $data->get_user_movie_stats_subsubtitle_none;
$config->get_user_movie_stats_top_movie = $data->get_user_movie_stats_top_movie;
$config->get_user_movie_stats_top_movie_plural = $data->get_user_movie_stats_top_movie_plural;
$config->get_user_movie_stats_movie_completion_title = $data->get_user_movie_stats_movie_completion_title;
$config->get_user_movie_stats_movie_completion_title_plural = $data->get_user_movie_stats_movie_completion_title_plural;
$config->get_user_movie_stats_movie_completion_subtitle = $data->get_user_movie_stats_movie_completion_subtitle;
$config->get_user_movie_stats_pause_title = $data->get_user_movie_stats_pause_title;
$config->get_user_movie_stats_pause_subtitle = $data->get_user_movie_stats_pause_subtitle;
$config->get_user_movie_stats_pause_title_one = $data->get_user_movie_stats_pause_title_one;
$config->get_user_movie_stats_pause_subtitle_one = $data->get_user_movie_stats_pause_subtitle_one;
$config->get_user_movie_stats_pause_title_none = $data->get_user_movie_stats_pause_title_none;
$config->get_user_movie_stats_pause_subtitle_none = $data->get_user_movie_stats_pause_subtitle_none;
$config->get_user_movie_stats_oldest_title = $data->get_user_movie_stats_oldest_title;
$config->get_user_movie_stats_oldest_subtitle = $data->get_user_movie_stats_oldest_subtitle;
$config->get_user_movie_stats_oldest_subtitle_pre_1950 = $data->get_user_movie_stats_oldest_subtitle_pre_1950;
$config->get_user_movie_stats_oldest_subtitle_pre_1975 = $data->get_user_movie_stats_oldest_subtitle_pre_1975;
$config->get_user_movie_stats_oldest_subtitle_pre_2000 = $data->get_user_movie_stats_oldest_subtitle_pre_2000;
$config->get_user_movie_stats_spent_title = $data->get_user_movie_stats_spent_title;
$config->get_user_show_stats = $data->get_user_show_stats;
$config->get_user_show_stats_buddy = $data->get_user_show_stats_buddy;
$config->get_user_show_stats_title = $data->get_user_show_stats_title;
$config->get_user_show_stats_subtitle = $data->get_user_show_stats_subtitle;
$config->get_user_show_stats_subsubtitle = $data->get_user_show_stats_subsubtitle;
$config->get_user_show_stats_subtitle_one = $data->get_user_show_stats_subtitle_one;
$config->get_user_show_stats_subsubtitle_one = $data->get_user_show_stats_subsubtitle_one;
$config->get_user_show_stats_subtitle_none = $data->get_user_show_stats_subtitle_none;
$config->get_user_show_stats_subsubtitle_none = $data->get_user_show_stats_subsubtitle_none;
$config->get_user_show_stats_top_show = $data->get_user_show_stats_top_show;
$config->get_user_show_stats_top_show_plural = $data->get_user_show_stats_top_show_plural;
$config->get_user_show_stats_spent_title = $data->get_user_show_stats_spent_title;
$config->get_user_show_stats_most_played_title = $data->get_user_show_stats_most_played_title;
$config->get_user_show_stats_most_played_subtitle = $data->get_user_show_stats_most_played_subtitle;
$config->get_user_show_stats_buddy_title = $data->get_user_show_stats_buddy_title;
$config->get_user_show_stats_buddy_subtitle = $data->get_user_show_stats_buddy_subtitle;
$config->get_user_show_stats_buddy_title_none = $data->get_user_show_stats_buddy_title_none;
$config->get_user_show_stats_buddy_subtitle_none = $data->get_user_show_stats_buddy_subtitle_none;
$config->get_user_music_stats = $data->get_user_music_stats;
$config->get_user_music_stats_title = $data->get_user_music_stats_title;
$config->get_user_music_stats_subtitle = $data->get_user_music_stats_subtitle;
$config->get_user_music_stats_subsubtitle = $data->get_user_music_stats_subsubtitle;
$config->get_user_music_stats_subtitle_one = $data->get_user_music_stats_subtitle_one;
$config->get_user_music_stats_subsubtitle_one = $data->get_user_music_stats_subsubtitle_one;
$config->get_user_music_stats_subtitle_none = $data->get_user_music_stats_subtitle_none;
$config->get_user_music_stats_subsubtitle_none = $data->get_user_music_stats_subsubtitle_none;
$config->get_user_music_stats_top_track = $data->get_user_music_stats_top_track;
$config->get_user_music_stats_top_track_plural = $data->get_user_music_stats_top_track_plural;
$config->get_user_music_stats_top_album_plural = $data->get_user_music_stats_top_album_plural;
$config->get_user_music_stats_top_artist_plural = $data->get_user_music_stats_top_artist_plural;
$config->get_user_music_stats_spent_title = $data->get_user_music_stats_spent_title;
$config->get_user_music_stats_spent_subtitle = $data->get_user_music_stats_spent_subtitle;
$config->get_user_music_stats_oldest_album_title = $data->get_user_music_stats_oldest_album_title;
$config->get_user_music_stats_oldest_album_subtitle = $data->get_user_music_stats_oldest_album_subtitle;
$config->get_year_stats_title = $data->get_year_stats_title;
$config->get_year_stats_subtitle = $data->get_year_stats_subtitle;
$config->get_year_stats_subsubtitle = $data->get_year_stats_subsubtitle;
$config->get_year_stats_movies = $data->get_year_stats_movies;
$config->get_year_stats_movies_title = $data->get_year_stats_movies_title;
$config->get_year_stats_movies_duration_title = $data->get_year_stats_movies_duration_title;
$config->get_year_stats_shows = $data->get_year_stats_shows;
$config->get_year_stats_shows_title = $data->get_year_stats_shows_title;
$config->get_year_stats_shows_duration_title = $data->get_year_stats_shows_duration_title;
$config->get_year_stats_music = $data->get_year_stats_music;
$config->get_year_stats_music_title = $data->get_year_stats_music_title;
$config->get_year_stats_music_duration_title = $data->get_year_stats_music_duration_title;
$config->get_year_stats_leaderboard = $data->get_year_stats_leaderboard;
$config->get_year_stats_leaderboard_title = $data->get_year_stats_leaderboard_title;
$config->get_year_stats_duration_sum_title = $data->get_year_stats_duration_sum_title;
$config->wrapperr_and = $data->wrapperr_and;
$config->wrapperr_play = $data->wrapperr_play;
$config->wrapperr_play_plural = $data->wrapperr_play_plural;
$config->wrapperr_day = $data->wrapperr_day;
$config->wrapperr_day_plural = $data->wrapperr_day_plural;
$config->wrapperr_hour = $data->wrapperr_hour;
$config->wrapperr_hour_plural = $data->wrapperr_hour_plural;
$config->wrapperr_minute = $data->wrapperr_minute;
$config->wrapperr_minute_plural = $data->wrapperr_minute_plural;
$config->wrapperr_second = $data->wrapperr_second;
$config->wrapperr_second_plural = $data->wrapperr_second_plural;
$config->wrapperr_sort_plays = $data->wrapperr_sort_plays;
$config->wrapperr_sort_duration = $data->wrapperr_sort_duration;
} catch (Exception $e) {
$fail = true;
}
if($fail) {
// Log use
$log->log_activity('set_config.php', 'admin', 'Failed to assign variables from data. Data type: ' . $data_type . '.');
echo json_encode(array("error" => true, "message" => "Failed to assign variables from data."));
exit(0);
}
} else {
// Log use
$log->log_activity('set_config.php', 'unknown', 'New config was saved.');
$log->log_activity('set_config.php', 'admin', 'Invalid data type for saving config. Data type: ' . $data_type . '.');
echo json_encode(array("error" => true, "message" => "Invalid data type for saving config."));
exit(0);
}
// Call function to save data
if($config->save_config($clear_cache)) {
// Log use
$log->log_activity('set_config.php', 'admin', 'New config was saved. Data type: ' . $data_type . '.');
echo json_encode(array("error" => false, "message" => "Changes saved."));
exit(0);
@ -75,7 +241,7 @@ function save_config($data, $clear_cache) {
} else {
// Log use
$log->log_activity('set_config.php', 'unknown', 'New login was not saved.');
$log->log_activity('set_config.php', 'admin', 'Changes were not saved.');
echo json_encode(array("error" => true, "message" => "Changes were not saved. Is the directory 'config' writable?"));
exit(0);

View file

@ -0,0 +1,52 @@
<?php
// Required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// Files needed to use objects
require(dirname(__FILE__) . '/objects/admin.php');
require(dirname(__FILE__) . '/objects/log.php');
// Create variables
$admin = new Admin();
$log = new Log();
$data = json_decode(file_get_contents("php://input"));
// If POST data is empty or wrong
if(empty($data) || !isset($data->cookie)) {
// Log use
$log->log_activity('validate_login_admin_cookie.php', 'unknown', 'Input error from user.');
echo json_encode(array("error" => true, "message" => "Input error."));
exit(0);
}
// Remove potential harmfull input
$cookie = htmlspecialchars($data->cookie);
// Decrypt cookie
$cookie_object = json_decode($admin->decrypt_cookie($cookie));
// Validate admin cookie
if(!$admin->validate_cookie($cookie_object)) {
// Log use
$log->log_activity('validate_login_admin_cookie.php', 'unknown', 'Admin cookie not valid.');
echo json_encode(array("error" => true, "message" => "Admin cookie not accepted. Log in again."));
exit(0);
}
// Log use
$log->log_activity('validate_login_admin_cookie.php', 'admin', 'Admin login cookie accepted.');
// Print cookie and exit
echo json_encode(array("error" => false, "message" => "Cookie is valid."));
exit(0);
?>

View file

@ -44,7 +44,7 @@ if(empty($token_object) || !isset($token_object->data->id)) {
}
// Log use
$log->log_activity('validate_login_cookie.php', $token_object->data->id, 'Plex-Wrapped login cookie accepted.');
$log->log_activity('validate_login_cookie.php', $token_object->data->id, 'Wrapperr login cookie accepted.');
// Print cookie and exit
echo json_encode(array("error" => false, "message" => "Cookie is valid."));

1
assets/about.svg Normal file
View file

@ -0,0 +1 @@
<?xml version="1.0"?><svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="96px" height="96px"> <path d="M 12 2 C 10.343 2 9 3.343 9 5 C 9 6.657 10.343 8 12 8 C 13.657 8 15 6.657 15 5 C 15 3.343 13.657 2 12 2 z M 9 10 A 1.0001 1.0001 0 1 0 9 12 L 10 12 L 10 20 L 9 20 A 1.0001 1.0001 0 1 0 9 22 L 15 22 A 1.0001 1.0001 0 1 0 15 20 L 14 20 L 14 11 C 14 10.448 13.552 10 13 10 L 11 10 L 9 10 z"/></svg>

After

Width:  |  Height:  |  Size: 432 B

261
assets/css/admin.css Normal file
View file

@ -0,0 +1,261 @@
:root {
--red: #F94144;
--orangered: #F3722C;
--orangeyellow: #F8961E;
--mango: #F9844A;
--yellow: #F9C74F;
--pistach: #90BE6D;
--green: #43AA8B;
--cadetblue: #4D908E;
--queenblue: #577590;
--blue: #277DA1;
--white: #f1f1f1;
--black: #181818;;
--charcoal: #414141;
}
html {
height: 100%;
}
body {
margin: 0;
box-sizing: content-box;
padding: 0;
top: 0;
font-family: 'Roboto', serif;
font-weight: normal;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: center;
justify-content: space-between;
align-items: center;
background-color: var(--mango);
height: 100%;
}
.content {
margin: 1em 0.5em;
width: 90%;
background-color: var(--charcoal);
padding: 0.5em;
border-radius: 6px;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.19);
color: var(--white);
}
.container {
display: inline-block;
margin: auto;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: flex-start;
font-size: 1em;
}
.sub_container {
display: inline-block;
}
form {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: flex-start;
justify-content: center;
align-items: center;
}
.form-group {
display: inline-block;
padding: 0.5em 1em;
box-sizing: border-box;
}
.newline {
display: block;
width: 100%;
text-align: center;
}
.form_hidden {
max-height: 2.5em;
overflow: hidden;
opacity: 0.5;
transition: 1s;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: center;
justify-content: flex-start;
align-items: center;
}
.form_shown {
max-height: none;
overflow: visible;
opacity: 1;
transition: 1s;
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-content: flex-start;
justify-content: flex-start;
align-items: center
}
.form_block {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: flex-start;
justify-content: center;
align-items: flex-start;
margin: 0.5em;
border-radius: 6px;
width: auto;
background-color: var(--queenblue);
}
#plural {
background-color: var(--queenblue);
}
#singular {
background-color: var(--blue);
}
#none {
background-color: var(--cadetblue);
}
label {
display: block;
margin: 0.25em 0;
text-align: center;
display: block;
}
textarea {
overflow-x: hidden;
resize: vertical;
min-height: 2em;
font-family: 'Roboto', serif !important;
}
.form-control {
font-size: 1.1em;
padding: 0.5em 0.75em;
display: inline-block;
box-sizing: border-box;
text-align: center;
border-radius: 0.25em;
border: none;
width: 18em;
max-width: 100%;
margin: auto;
}
input[type="text"] {
font-size: 1.1em;
width: 18em;
}
.btn {
background-color: var(--yellow);
border: none;
cursor: pointer;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: center;
max-width: 20em;
margin: auto;
}
.btn_logo {
width: 1em;
height: 1em;
margin: 0;
padding: 0 0.5em 0 0;
}
label {
cursor: pointer;
}
input[type="checkbox" i] {
transform: scale(1.5);
cursor: pointer;
width: auto;
box-sizing: content-box;
display: block;
margin-top: 0.5em;
}
h1 {
margin: 0.25em 0.12em;
text-align: center;
font-size: 3em;
}
h2 {
margin: 0.5em 0.25em;
text-align: center;
}
h3 {
font-size: 1.5em;
margin: 0.5em 0;
}
p{
}
p2 {
font-size: 1.25em;
}
hr {
display: block;
width: 100%;
}
a {
text-align: center;
}
.warning {
padding: 1em;
margin: auto;
background-color: var(--yellow);
border-radius: 25px;
color: var(--black);
font-size: 1em;
max-width: 25em;
text-align: center;
}
#footer {
text-align: center;
background: none;
box-shadow: none;
}
#cache {
width: 100%;
margin: 0 1em;
}
#cache_results {
border: 2px solid grey;
border-radius: 6px;
padding: 0.5em 0.75em;
}

View file

@ -1,3 +1,20 @@
:root {
--red: #F94144;
--orangered: #F3722C;
--orangeyellow: #F8961E;
--mango: #F9844A;
--yellow: #F9C74F;
--pistach: #90BE6D;
--green: #43AA8B;
--cadetblue: #4D908E;
--queenblue: #577590;
--blue: #277DA1;
--white: #f1f1f1;
--black: #181818;;
--charcoal: #414141;
}
html {
height: 100%;
width: 100%;
@ -12,13 +29,13 @@ body {
width: 100%;
font-family: 'Roboto', serif;
font-weight: normal;
background: #a2d1d0;
background-color: var(--mango);
box-sizing: border-box;
}
h1{
font-size: 3em;
color: white;
font-size: 2.5em;
color: var(--white);
text-shadow: 1px 1px 2px #555;
line-height: 110%;
text-align: center;
@ -29,22 +46,24 @@ h1{
h2{
text-shadow: 1px 1px 2px #555;
font-size: 2em;
color: white;
color: var(--white);
line-height: 110%;
text-align: center;
margin: 0;
font-weight: normal;
padding: 0.25em 0;
}
h3{
text-shadow: 1px 1px 2px #555;
color: white;
color: var(--white);
text-shadow: 1px 1px 2px #555;
line-height: 110%;
text-align: center;
font-family: 'Roboto', serif;
font-size: 1.5em;
text-overflow: clip;
margin: 0.5em;
}
h4{
@ -52,20 +71,20 @@ h4{
margin: auto;
text-align: center;
font-weight: normal;
color: white;
color: var(--white);
}
p{
text-shadow: 1px 1px 2px #555;
font-size: 1.25em;
color: #ffffff;
color: var(--white);
text-align: center;
margin: 0;
}
p2{
font-size: 1em;
color: black;
color: var(--black);
text-align: center;
margin: 0;
}
@ -102,17 +121,17 @@ img {
}
.boks {
margin: auto;
width: 100%;
align-items: center;
text-align: center;
box-sizing: border-box;
margin: auto;
width: 100%;
align-items: center;
text-align: center;
box-sizing: border-box;
}
.boks2 {
width: 30em;
max-width: 100%;
margin: auto;
margin: 0;
position: relative;
vertical-align: top;
box-sizing: border-box;
@ -125,8 +144,13 @@ img {
width: 100%;
margin: auto;
position: relative;
display: inline-block;
display: flex;
vertical-align: top;
flex-direction: row;
flex-wrap: wrap;
align-content: center;
justify-content: center;
align-items: flex-start;
}
.load_top_10 {
@ -162,17 +186,13 @@ img {
top: 0;
}
#stats {
width: 22em;
}
.warning {
padding: 0.5em;
margin: 0.5em;
background-color: #ffbd55;
background-color: var(--yellow);
border-radius: 25px;
color: black;
font-size: 0.75em;
color: var(--black);
font-size: 0.75em;
}
.boks-knapp {
@ -183,7 +203,7 @@ img {
}
.server:hover {
background-color: white;
background-color: var(--white);
border-radius: 25px;
}
@ -191,12 +211,12 @@ img {
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: lightslategrey;
background-color: var(--charcoal);
border-radius: 25px;
padding: 0.5em;
width: 100%;
top: 0;
color: white;
color: var(--white);
font-size: 1.25em;
box-sizing: border-box;
max-width: 100%;
@ -219,10 +239,10 @@ img {
margin: 0.5em;
font-family: 'Roboto', serif;
font-size: 1.25em;
background-color: #f9a825;
background-color: var(--yellow);
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;
color: white;
color: var(--white);
padding: 1em;
}
@ -235,8 +255,8 @@ img {
.form_button {
font-family: 'Roboto', serif;
text-align: center;
background-color: #f9a825;
color: white;
background-color: var(--yellow);
color: var(--white);
border: 0;
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);
padding: 0.5em;
@ -256,7 +276,7 @@ img {
}
.item:hover {
background-color: #54606d !important;
background-color: var(--black) !important;
border-radius: 25px;
}
@ -284,7 +304,7 @@ img {
display: inline-block;
margin: 1em;
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: var(--white);
border-radius: 25px;
padding: 0.5em;
text-align: left;
@ -376,7 +396,7 @@ img {
}
.btn {
background-color: #ffbd55;
background-color: var(--yellow);
border: none;
cursor: pointer;
display: flex;
@ -405,7 +425,7 @@ input[type="checkbox" i] {
bottom: 0;
width: 100%;
height: 2em;
color: white;
color: var(--white);
text-align: center;
}
@ -416,7 +436,7 @@ input[type="checkbox" i] {
align-content: center;
justify-content: flex-start;
align-items: center;
background-color: #ffbd55;
background-color: var(--yellow);
border: none;
cursor: pointer;
border-radius: 0.25em;
@ -429,45 +449,91 @@ input[type="checkbox" i] {
width: 1em;
height: 1em;
margin: 0;
padding: 0 0.25em;
padding: 0 0.5em 0 0;
}
/*Snowflakes*/
.snowflake {
color: #fff;
color: var(--white);
font-size: 1em;
font-family: Arial;
text-shadow: 0 0 1px #000;
}
@-webkit-keyframes snowflakes-fall{0%{top:-10%}100%{top:100%}}@-webkit-keyframes snowflakes-shake{0%{-webkit-transform:translateX(0px);transform:translateX(0px)}50%{-webkit-transform:translateX(80px);transform:translateX(80px)}100%{-webkit-transform:translateX(0px);transform:translateX(0px)}}@keyframes snowflakes-fall{0%{top:-10%}100%{top:100%}}@keyframes snowflakes-shake{0%{transform:translateX(0px)}50%{transform:translateX(80px)}100%{transform:translateX(0px)}}.snowflake{position:fixed;top:-10%;z-index:9999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;-webkit-animation-name:snowflakes-fall,snowflakes-shake;-webkit-animation-duration:10s,3s;-webkit-animation-timing-function:linear,ease-in-out;-webkit-animation-iteration-count:infinite,infinite;-webkit-animation-play-state:running,running;animation-name:snowflakes-fall,snowflakes-shake;animation-duration:10s,3s;animation-timing-function:linear,ease-in-out;animation-iteration-count:infinite,infinite;animation-play-state:running,running}.snowflake:nth-of-type(0){left:1%;-webkit-animation-delay:0s,0s;animation-delay:0s,0s}.snowflake:nth-of-type(1){left:10%;-webkit-animation-delay:1s,1s;animation-delay:1s,1s}.snowflake:nth-of-type(2){left:20%;-webkit-animation-delay:6s,.5s;animation-delay:6s,.5s}.snowflake:nth-of-type(3){left:30%;-webkit-animation-delay:4s,2s;animation-delay:4s,2s}.snowflake:nth-of-type(4){left:40%;-webkit-animation-delay:2s,2s;animation-delay:2s,2s}.snowflake:nth-of-type(5){left:50%;-webkit-animation-delay:8s,3s;animation-delay:8s,3s}.snowflake:nth-of-type(6){left:60%;-webkit-animation-delay:6s,2s;animation-delay:6s,2s}.snowflake:nth-of-type(7){left:70%;-webkit-animation-delay:2.5s,1s;animation-delay:2.5s,1s}.snowflake:nth-of-type(8){left:80%;-webkit-animation-delay:1s,0s;animation-delay:1s,0s}.snowflake:nth-of-type(9){left:90%;-webkit-animation-delay:3s,1.5s;animation-delay:3s,1.5s}
.color-purple {
background-color: #B9A3D2;
.color-red {
background-color: var(--red);
transition-duration: 1s;
}
.color-pink {
background-color: #D2A3A4;
.color-orangered {
background-color: var(--orangered);
transition-duration: 1s;
}
.color-green {
background-color: #BBD2A3;
.color-orangeyellow {
background-color: var(--orangeyellow);
transition-duration: 1s;
}
.color-brown {
background-color: #CFA38C;
.color-mango {
background-color: var(--mango);
transition-duration: 1s;
}
.color-blue {
background-color: #a2d1d0;
.color-pistach {
background-color: var(--pistach);
transition-duration: 1s;
}
.color-black {
background-color: #39393A;
.color-charcoal {
background-color: var(--charcoal);
transition-duration: 1s;
}
hr {
margin: 0.5em 0;
}
#share_wrapped_url {
padding: 0.25em;
background: none;
color: var(--black);
border-radius: 0.25em;
overflow: auto;
font-size: 0.8em;
width: 80%;
box-sizing: border-box;
white-space:nowrap;
height: 2.5em;
background-color: var(--white);
display: inline-flex;
align-items: center;
cursor: text;
}
#share_wrapped_delete {
padding: 0 0 0 0.25em;
background: none;
border-radius: 0.25em;
overflow: auto;
font-size: 0.8em;
width: 10%;
box-sizing: border-box;
height: 1.5em;
cursor: pointer;
}
#share_wrapped_copy {
padding: 0 0 0 0.5em;
background: none;
border-radius: 0.25em;
overflow: auto;
font-size: 0.8em;
width: 10%;
box-sizing: border-box;
height: 1.5em;
cursor: pointer;
}

1
assets/download.svg Normal file
View file

@ -0,0 +1 @@
<?xml version="1.0"?><svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="96px" height="96px"> <path d="M19.355,10.036C18.674,6.595,15.641,4,12,4C9.108,4,6.603,5.639,5.352,8.036C2.343,8.36,0,10.906,0,14c0,3.314,2.686,6,6,6 h13c2.761,0,5-2.239,5-5C24,12.36,21.948,10.221,19.355,10.036z M12,18l-4.333-4.333C7.421,13.421,7.595,13,7.943,13H10V9.5 C10,9.224,10.224,9,10.5,9h3C13.776,9,14,9.224,14,9.5V13h2.057c0.348,0,0.522,0.421,0.276,0.667L12,18z"/></svg>

After

Width:  |  Height:  |  Size: 485 B

38
assets/gift_icon.svg Normal file
View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="86.5 52.5 345.5 370" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
<defs>
<filter id="black-and-white-filter-0" color-interpolation-filters="sRGB" x="-500%" y="-500%" width="1000%" height="1000%" bx:preset="black-and-white 1 -0.67">
<feColorMatrix type="saturate" values="0"/>
<feComponentTransfer>
<feFuncR type="discrete" tableValues="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 "/>
<feFuncG type="discrete" tableValues="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 "/>
<feFuncB type="discrete" tableValues="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 "/>
</feComponentTransfer>
</filter>
<style type="text/css">
.st0{fill:#F2F2F2;}
.st1{fill:#FFBD55;}
.st2{fill:#DEDEDE;}
.st3{fill:#F2AB44;}
.st4{fill:#D3D3D3;}
.st5{fill:#FFC878;}
.st6{fill:#FFFFFF;}
.st7{fill:#D4D4D4;}
</style>
</defs>
<g id="OBJECTS" style="filter: url(#black-and-white-filter-0);">
<polygon class="st1" points="401.9,359 222.8,422.5 222.8,258 401.9,194.5 "/>
<polygon class="st0" points="328.9,384.8 295.8,396.6 295.8,232.1 328.9,220.4 "/>
<polygon class="st2" points="401.9,194.5 401.9,217.7 222.7,281.3 222.7,258 "/>
<polygon class="st1" points="432,183.8 222.8,258 222.8,180.2 432,106 "/>
<polygon class="st0" points="346.7,214.1 308,227.8 308,149.9 346.7,136.2 "/>
<polygon class="st3" points="106.2,359 222.8,422.5 222.8,258 106.2,194.5 "/>
<polygon class="st4" points="153.7,384.8 175.2,396.6 175.2,232.1 153.7,220.4 "/>
<polygon class="st2" points="222.7,258 222.7,281.7 106.2,218.2 106.2,194.5 "/>
<polygon class="st3" points="86.5,183.8 222.8,258 222.8,180.2 86.5,106 "/>
<polygon class="st4" points="142.1,214.1 167.2,227.8 167.2,149.9 142.1,136.2 "/>
<polygon class="st5" points="432,106 346.7,136.2 308,149.9 222.8,180.2 167.3,149.9 142,136.2 86.5,106 175.9,78.6 175.9,78.6 210.5,68 261.3,52.5 314.7,69.2 350.5,80.4 "/>
<polygon class="st6" points="346.7,136.2 308,149.9 249.9,118.6 223.8,104.5 175.9,78.6 210.5,68 257.3,91.5 257.3,91.5 285,105.3 "/>
<polygon class="st6" points="350.5,80.4 285,105.3 249.9,118.6 167.3,149.9 142,136.2 223.8,104.5 257.3,91.5 314.7,69.2 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

6
assets/img/pattern.svg Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 -0.001 600 300.002" xmlns="http://www.w3.org/2000/svg">
<rect width="600" height="300" style="stroke: rgb(0, 0, 0); fill: rgb(20, 107, 58); stroke-width: 0px;"/>
<path style="stroke: rgb(0, 0, 0); fill: rgb(187, 37, 40); stroke-width: 0px;" d="M 100 300 L 300 0 L 200 0 C 200 0 0 300.583 0 300 L 100 300 Z"/>
<path style="stroke: rgb(0, 0, 0); stroke-width: 0px; fill: rgb(248, 178, 41);" d="M 400 299.999 L 600 -0.001 L 500 -0.001 C 500 -0.001 300 300.582 300 299.999 L 400 299.999 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 555 B

BIN
assets/img/pixel_weave.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

1
assets/trash.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="96px" height="96px"><path d="M 10 2 L 9 3 L 5 3 C 4.4 3 4 3.4 4 4 C 4 4.6 4.4 5 5 5 L 7 5 L 17 5 L 19 5 C 19.6 5 20 4.6 20 4 C 20 3.4 19.6 3 19 3 L 15 3 L 14 2 L 10 2 z M 5 7 L 5 20 C 5 21.1 5.9 22 7 22 L 17 22 C 18.1 22 19 21.1 19 20 L 19 7 L 5 7 z M 9 9 C 9.6 9 10 9.4 10 10 L 10 19 C 10 19.6 9.6 20 9 20 C 8.4 20 8 19.6 8 19 L 8 10 C 8 9.4 8.4 9 9 9 z M 15 9 C 15.6 9 16 9.4 16 10 L 16 19 C 16 19.6 15.6 20 15 20 C 14.4 20 14 19.6 14 19 L 14 10 C 14 9.4 14.4 9 15 9 z"/></svg>

After

Width:  |  Height:  |  Size: 562 B

1
assets/tweak.svg Normal file
View file

@ -0,0 +1 @@
<?xml version="1.0"?><svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="96px" height="96px"> <path d="M20.869,7.795C20.869,7.795,20.5,6,20,6c-0.375,0-1.871,1.684-2.599,2.528C17.141,8.83,16.766,9,16.368,9 C15.612,9,15,8.388,15,7.632c0-0.398,0.17-0.773,0.472-1.033C16.316,5.871,18,4.375,18,4c0-0.5-1.799-0.878-1.799-0.878 C15.809,3.041,15.404,3,15,3c-3.309,0-6,2.717-6,6.056c0,0.42,0.051,0.845,0.153,1.285l-6.214,6.103 c-1.252,1.269-1.252,3.332,0.001,4.601C3.55,21.66,4.363,22,5.231,22c0.867,0,1.681-0.34,2.28-0.946l6.229-6.12 C14.169,15,14.587,15,15,15c3.364,0,6-2.611,6-5.944C21,8.634,20.956,8.209,20.869,7.795z"/></svg>

After

Width:  |  Height:  |  Size: 655 B

View file

@ -1,228 +0,0 @@
var cached = 0;
var input_array;
function search_box() {
var html = `
<form id='stats_form' class='form' onsubmit='return false' action="" method="post">
<p style="font-size:1em;">
When you configured a wrapped period, it included the amount of days you want to analyze. Each unique day in that period is a new API request to Tautulli.
<br>
<br>
Here you can perform a full caching of all those days, by calling the Plex-Wrapped API in a loop, downloading all the data needed. This makes the site fast to load.
<br>
<br>
Plex-Wrapped uses PHP, which has script run-time limits. The input below allows you to reduce the number of days cached each time the cacher loops, preventing the PHP script from running for more than the allowed runtime (typically 120 seconds).
</p>
<div class='form-group'>
<label for="days" title="">Days to cache:</label>
<input type="number" class='form-control' name="days" id="days" minlenght='1' value='50' autocomplete="off" required />
</div>
<div class='form-group'>
<input type="submit" class='form-control btn' value="Cache" name="cache_button" id="cache_button" required/>
</div>
</form>
`;
document.getElementById('cache').innerHTML = html;
}
$(document).on('submit', '#stats_form', function(){
cache();
});
function cache() {
var days = document.getElementById('days').value;
var html = `
<form id='stats_form' class='form' onsubmit='return false' action="" method="post">
<div class='form-group'>
<img id="loading_icon" src="../assets/loading.gif" style="border-radius: 25px; background-color: white; padding: 1em; width: 4em; height: 4em; display: inline;">
</div>
<h3>Caching log:</h3>
<div id="cache_results">
</div>
</form>
`;
document.getElementById('cache').innerHTML = html;
document.getElementById('cache_results').innerHTML += '<p style="color:white;">' + 'Creating new cache request. Maximum ' + days + ' days.' + '</p>';
get_stats(days);
}
function cache_log(days, result, complete) {
if(result) {
document.getElementById('cache_results').innerHTML += '<p style="color:darkseagreen;">' + 'Completed one caching with a maxmimum of ' + days + ' days.' + '</p>';
} else {
document.getElementById('cache_results').innerHTML += '<p style="color:indianred;"> ' + 'Error caching ' + days + ' days. Stopping.' + '</p>';
document.getElementById('loading_icon').style.display = "none";
}
if(complete) {
document.getElementById('cache_results').innerHTML += '<p style="color:darkseagreen;">' + 'Finished caching loop.' + '</p>';
document.getElementById('loading_icon').style.display = "none";
} else {
document.getElementById('cache_results').innerHTML += '<p style="color:white;">' + 'Creating new cache request. Maximum ' + days + ' days.' + '</p>';
}
}
function get_stats(days) {
stats_form = {
"cookie" : '',
"caching" : true,
"cache_limit" : days
};
var stats_data = JSON.stringify(stats_form);
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
try {
var result = JSON.parse(this.responseText);
if(result.error) {
cache_log(days, false, true);
} else {
if(!result.caching_complete) {
cache_log(days, true, result.caching_complete);
get_stats(days);
} else {
cache_log(days, true, result.caching_complete);
}
}
} catch(error) {
cache_log(days, false, true);
console.log('Error: ' + error);
console.log(this.responseText);
}
}
};
xhttp.withCredentials = true;
xhttp.open("post", root + "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" : "",
"username" : "",
};
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", root + "api/get_config.php");
xhttp.send(config_data);
}
function get_config() {
current_password = document.getElementById('password').value;
current_username = document.getElementById('username').value;
config_form = {
"password" : current_password,
"username" : current_username
};
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", root + "api/get_config.php");
xhttp.send(config_data);
}
function login_menu() {
topFunction();
var html = '<form id="password_login_form" onsubmit="get_config();return false">'
html += '<div class="form-group">';
html += '<label for="username" title="The administrator username chosen during first-time setup.">Username:</label>';
html += '<input type="text" class="form-control" id="username" value="" autocomplete="on" minlength=4 required />';
html += '</div>';
html += '<div class="form-group">';
html += '<label for="password" title="The password chosen for the administrator during first-time setup.">Password:</label>';
html += '<input type="password" class="form-control" id="password" value="" autocomplete="off" required />';
html += '</div>';
html += '<div class="form-group">';
html += '<input type="submit" class="form-control btn" id="password_button" value="Log in" required />';
html += '</div>';
html += '</form>';
document.getElementById("cache").innerHTML = html;
}
function get_plex_wrapped_version() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
try {
var result= JSON.parse(this.responseText);
} catch(error) {
console.log('Failed to parse Plex-Wrapped version. Response: ' + this.responseText)
}
if(!result.error) {
document.getElementById('github_link').innerHTML = 'GitHub (' + result.plex_wrapped_version + ')';
}
}
};
xhttp.withCredentials = true;
xhttp.open("post", "../api/get_plex_wrapped_version.php");
xhttp.send();
return;
}

View file

@ -1,83 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Plex Wrapped</title>
<!-- Bootstrap 4 CSS and custom CSS -->
<link rel="stylesheet" type="text/css" href="../assets/css/wrapped.css" />
<link rel="shortcut icon" href="../assets/img/favicons/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="../caching.js"></script>
</head>
<body>
<div class="content" id="login_content" style="">
<div class="boks">
<div class="boks3" id="search_input" style="padding: 0 !important;">
<div class="boks2" style="float: none !important; display: block; padding: 0; margin-top: 0em;">
<img src="../assets/img/gift.svg" onclick="window.location.href = '../';" style="width: 15em; cursor: pointer;">
</div>
<div class="boks2" style="float: none !important; display: block; margin-top: 0em; padding-top: 0;">
<div class="stats_tekst" style="height: auto;">
<p>
Caching decreases loadtime for users and reduces PHP induced errors.
<br><br><a href="../admin">Remember to configure the system first.</a>
</p>
</div>
<br>
<div class="status" id="stats" style="">
<h1>Wrapped Caching</h1>
<div class="search" id="cache">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="content" id="search_results">
</div>
<div class="footer" id="footer">
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="../">Wrapped</a> |
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="../admin">Admin</a> |
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="../caching">Caching</a> |
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="https://github.com/aunefyren/plex-wrapped" target="_blank">GitHub (v2.1.0)</a>
</div>
<script type="text/javascript">
var root = "../";
var cookie;
$(document).ready(function() {
get_plex_wrapped_version();
get_config_cache();
});
</script>
</body>
</html>

View file

@ -1,6 +1,7 @@
FROM php:7.4-apache
LABEL maintainer="Wrapperr https://github.com/aunefyren/wrapperr"
RUN apt-get update && apt-get install -y \
git
RUN rm -d -r /var/www/html
RUN git clone https://github.com/aunefyren/plex-wrapped --branch v2.1.0 /var/www/html
RUN git clone https://github.com/aunefyren/wrapper --branch v2.2.0 /var/www/html
RUN chmod -R 0777 /var/www/html/config

195
functions.js Normal file
View file

@ -0,0 +1,195 @@
function set_cookie(cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
var expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/;SameSite=None;secure";
}
function get_cookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' '){
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
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 seconds_to_days(seconds, comma, function_setting) {
var day = Math.floor(seconds / seconds_in_day);
var rest = Math.floor(seconds % seconds_in_day);
var hour = Math.floor(rest / seconds_in_hour);
rest = Math.floor(rest % seconds_in_hour);
var minute = Math.floor(rest / seconds_in_minute);
rest = Math.floor(rest % seconds_in_minute);
var day_string = '';
var hour_string = '';
var minute_string = '';
if(day == 1) {
day_string += day + ' ' + function_setting.wrapperr_day;
} else {
day_string += day + ' ' + function_setting.wrapperr_day_plural;
}
if(hour == 1) {
hour_string += hour + ' ' + function_setting.wrapperr_hour;
} else {
hour_string += hour + ' ' + function_setting.wrapperr_hour_plural;
}
if(minute == 1) {
minute_string += minute + ' ' + function_setting.wrapperr_minute;
} else {
minute_string += minute + ' ' + function_setting.wrapperr_minute_plural;;
}
if(hour >= 1) {
if(minute >= 1) {
if(comma) {
return day_string + ', ' + hour_string + ', ' + minute_string;
} else {
return day_string + ', ' + hour_string + ' ' + function_setting.wrapperr_and + ' ' + minute_string;
}
} else {
if(comma) {
return day_string + ', ' + hour_string;
} else {
return day_string + ' ' + function_setting.wrapperr_and + ' ' + hour_string;
}
}
} else {
return day_string;
}
}
function seconds_to_hours(seconds, comma, function_setting) {
var hour = Math.floor(seconds / seconds_in_hour);
var rest = Math.floor(seconds % seconds_in_hour);
var minute = Math.floor(rest / seconds_in_minute);
rest = Math.floor(rest % seconds_in_minute);
var hour_string = '';
var minute_string = '';
if(hour == 1) {
hour_string += hour + ' ' + function_setting.wrapperr_hour;
} else {
hour_string += hour + ' ' + function_setting.wrapperr_hour_plural;
}
if(minute == 1) {
minute_string += minute + ' ' + function_setting.wrapperr_minute;
} else {
minute_string += minute + ' ' + function_setting.wrapperr_minute_plural;
}
if(minute >= 1) {
if(comma) {
return hour_string + ', ' + minute_string;
} else {
return hour_string + ' ' + function_setting.wrapperr_and + ' ' + minute_string;
}
} else {
return hour_string;
}
}
function seconds_to_minutes(seconds, comma, function_setting) {
seconds = parseInt(seconds);
var minute = Math.floor(seconds / seconds_in_minute);
var rest = Math.floor(seconds % seconds_in_minute);
var minute_string = '';
var second_string = '';
if(minute == 1) {
minute_string += minute + ' ' + function_setting.wrapperr_minute;
} else {
minute_string += minute + ' ' + function_setting.wrapperr_minute_plural;
}
if(seconds == 1) {
second_string += rest + ' ' + function_setting.wrapperr_second;
} else {
second_string += rest + ' ' + function_setting.wrapperr_second_plural;
}
if(rest >= 1) {
if(comma) {
return minute_string + ', ' + second_string;
} else {
return minute_string + ' ' + function_setting.wrapperr_and + ' ' + second_string;
}
} else {
return minute_string;
}
}
function seconds_to_seconds(seconds, function_setting) {
var second_string = '';
if(seconds == 1) {
second_string += number_with_spaces(seconds) + ' ' + function_setting.wrapperr_second;
} else {
second_string += number_with_spaces(seconds) + ' ' + function_setting.wrapperr_second_plural;
}
return second_string;
}
function number_with_spaces(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
}
function play_plays(plays) {
plays = parseInt(plays);
if(plays == 1) {
var play_string = number_with_spaces(plays) + ' ' + functions.wrapperr_play;
} else {
var play_string = number_with_spaces(plays) + ' ' + functions.wrapperr_play_plural;
}
return play_string;
}

View file

@ -1,96 +0,0 @@
function get_config_initial() {
config_form = {
"password" : "",
"username" : "",
};
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) {
if(!result.password) {
first_time = true;
set_password();
} else {
login_menu();
}
}
}
};
xhttp.withCredentials = true;
xhttp.open("post", root + "api/get_config.php");
xhttp.send(config_data);
}
function get_config() {
current_password = document.getElementById('password').value;
current_username = document.getElementById('username').value;
config_form = {
"password" : current_password,
"username" : current_username,
};
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);
document.getElementById('password').value = '';
} 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;
tautulli_libraries = result.data.tautulli_libraries;
ssl = result.data.ssl;
username = result.data.username;
password = "";
timezone = result.data.timezone;
wrapped_start = new Date(0);
wrapped_start.setUTCSeconds(result.data.wrapped_start);
wrapped_end = new Date(0);
wrapped_end.setUTCSeconds(result.data.wrapped_end);
stats_intro = result.data.stats_intro;
create_share_links = result.data.create_share_links;
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_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;
clientID = result.data.clientID;
plex_wrapped_root = result.data.plex_wrapped_root;
set_tautulli(true);
}
}
};
xhttp.withCredentials = true;
xhttp.open("post", root + "api/get_config.php");
xhttp.send(config_data);
}

View file

@ -16,11 +16,8 @@ function get_functions() {
document.getElementById('results_error').innerHTML = result.message;
} else {
functions = result;
if(!link_mode) {
get_stats();
} else {
load_page(results);
}
get_stats();
}
}
};

File diff suppressed because it is too large Load diff

View file

@ -5,13 +5,14 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Plex Wrapped</title>
<title>Wrapperr</title>
<!-- Bootstrap 4 CSS and custom CSS -->
<link rel="stylesheet" type="text/css" href="assets/css/wrapped.css" />
<link rel="shortcut icon" href="assets/img/favicons/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="./functions.js"></script>
<script src="./index.js"></script>
<script src="./get_stats.js"></script>
<script src="./get_functions.js"></script>
@ -23,11 +24,15 @@
<div class="boks">
<div class="boks3" id="search_input" style="padding: 0 !important;">
<div class="boks3" id="" style="padding: 0 !important;">
<div class="boks2" style="float: none !important; display: block; padding: 0; margin-top: 0em;">
<img src="assets/img/gift.svg" onclick="window.location.href = './';" style="width: 15em; cursor: pointer;">
</div>
</div>
<div class="boks3" id="search_input" style="padding: 0 !important;">
<div class="boks2" style="float: none !important; display: block; margin-top: 0em; padding-top: 0;">
@ -42,7 +47,7 @@
<div class="status" id="stats" style="">
<h1>Plex Wrapped</h1>
<h1 id='application_name'>Wrapperr</h1>
<div class="search">
@ -62,30 +67,51 @@
<div class="form-group" id='search_wrapped_div'>
<button class='form-control btn' name="search_wrapped_button" id="search_wrapped_button" style='opacity: 0.5;' disabled>
<img src='assets/done.svg' class='btn_logo'>
<p2 id='plex_login_button_text'>Plex Wrapped</p2>
<p2 id='search_wrapped_button_text'>Unwrap</p2>
</button>
</div>
<div class="form-group" id='sign_out_div' style='display: none;'>
<button class='form-control btn' name="plex_signout_button" id="plex_signout_button" onclick='sign_out()'>
<img src='assets/close.svg' class='btn_logo'>
<p2 id='plex_signout_button_text'>Sign Out</p2>
</button>
</div>
</form>
<div class="form-group" id='sign_out_div' style='display: none;'>
<button class='form-control btn' name="plex_signout_button" id="plex_signout_button" onclick='sign_out()'>
<img src='assets/close.svg' class='btn_logo'>
<p2 id='plex_signout_button_text'>Sign Out</p2>
</button>
</div>
</div>
<img id="loading_icon" src="assets/loading.gif" style="border-radius: 25px; background-color: white; padding: 1em;width: 4em; height: 4em; display:none; margin: 1em 0 0 0;">
<img id="loading_icon" src="assets/loading.gif" style="border-radius: 25px; background-color: var(--white); padding: 1em;width: 4em; height: 4em; display:none; margin: 1em 0 0 0;">
<div id="results">
</div>
<div class="form-group" id='results_error_div'>
<div id="results_error" style="color: var(--red) !important;"></div>
</div>
<div class="form-group" id='share_wrapped_title_div' style='margin: 0; display: none;'>
<h3 style='margin: 0'>Shareable link:</h3>
</div>
<div id="results_error" style="padding:0.5em; bottom:0; color: #ffbd55 !important;"></div>
<div class="form-group" id='share_wrapped_div' style=' display: none;
flex-direction: row;
flex-wrap: wrap;
align-content: flex-start;
justify-content: center;
align-items: flex-start;
border-radius: 6px;
margin: 0 0 0.5em 0;
padding: 0.5em;
'>
<div class='form-control btn' id="share_wrapped_delete_button" style='background-color: var(--white); cursor: default;'>
<span id='share_wrapped_url' style=''></span>
<img id='share_wrapped_copy' src='assets/external-link.svg' style='' onclick='copy_link_user();'>
<img id='share_wrapped_delete' src='assets/trash.svg' style='' onclick='delete_link_user();'>
</div>
</div>
</div>
@ -123,16 +149,16 @@
<div class="snowflake">
</div>
</div>
</div>
</div>
<div class="footer" id="footer">
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="./">Wrapped</a> |
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="./">Wrapperr</a> |
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="./admin">Admin</a> |
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" href="./caching">Caching</a> |
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" id="github_link" href="https://github.com/aunefyren/plex-wrapped" target="_blank">GitHub</a>
<a style="color: white; font-weight: normal; font-size: 0.75em; text-decoration: none;" id="github_link" href="https://github.com/aunefyren/wrapperr" target="_blank">GitHub</a>
</div>
</div>
@ -153,7 +179,7 @@
var hash = url.searchParams.get("hash");
var close_me = url.searchParams.get("close_me");
get_plex_wrapped_version();
get_wrapper_version();
if(close_me !== null) {
window.close();

144
index.js
View file

@ -1,12 +1,12 @@
function cookie_login_actions() {
cookie = get_cookie('plex-wrapped');
cookie = get_cookie('wrapperr-user');
if(cookie) {
document.getElementById('search_wrapped_form').style.display = 'block';
document.getElementById('plex_login_form').style.display = 'none';
document.getElementById('sign_out_div').style.display = 'block';
validate_cookie(cookie);
validate_cookie_user(cookie);
}
}
@ -32,7 +32,8 @@ function wrapped_link_actions(hash) {
document.getElementById('stats').innerHTML = '<p>' + result.message + '</p><img id="bored_image" src="assets/img/bored.svg" style="width: 10em; height: 10em; display:block; margin: 1em auto;">';
} else {
results = result.data;
get_functions();
functions = result.functions;
load_page();
}
}
};
@ -42,7 +43,7 @@ function wrapped_link_actions(hash) {
}
function sign_out() {
set_cookie("plex-wrapped", "", 1);
set_cookie("wrapperr-user", "", 1);
document.getElementById('search_wrapped_form').style.display = 'none';
document.getElementById('plex_login_form').style.display = 'block';
document.getElementById("plex_login_button").disabled = false;
@ -67,7 +68,9 @@ $(document).on('submit', '#plex_login_form', function(){
window_url = window.location.href.split('?')[0];
auth_form = {"home_url" : window_url};
auth_form = {
"home_url" : window_url
};
var auth_data = JSON.stringify(auth_form);
@ -80,6 +83,9 @@ $(document).on('submit', '#plex_login_form', function(){
} catch(error) {
document.getElementById('results_error').innerHTML = "API response can't be parsed.";
}
//console.log(result);
if(result.error) {
document.getElementById('results_error').innerHTML = result.message;
@ -103,9 +109,14 @@ function pop_up_login(url, code, id) {
const openedWindow = window.open(
url,
"Plex Login",
"width=500,height=750,resizable,scrollbars"
"width=500,height=750,resizable,scrollbars,popup=yes"
);
if (openedWindow == null || typeof(openedWindow)=='undefined') {
alert("Failed to open login window. Your browser might be blocking pop-up windows.");
return;
}
var timer = setInterval(function() {
if(openedWindow.closed) {
@ -134,13 +145,16 @@ function check_token(code, id) {
var result= JSON.parse(this.responseText);
} catch(error) {
document.getElementById('results_error').innerHTML = "API response can't be parsed.";
console.log('API response can\'t be parsed. Error: ' + this.responseText)
reset_button();
}
//console.log(result);
if(result.error) {
reset_button();
} else {
set_cookie("plex-wrapped", result.cookie, 1);
set_cookie("wrapperr-user", result.cookie, 1);
location.reload();
}
}
@ -157,31 +171,7 @@ function reset_button() {
document.getElementById("plex_login_button").style.opacity = '1';
}
function set_cookie(cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
var expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
function get_cookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' '){
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
function validate_cookie(cookie) {
function validate_cookie_user(cookie) {
var json_cookie = JSON.stringify({"cookie": cookie});
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
@ -194,8 +184,10 @@ function validate_cookie(cookie) {
reset_button();
}
//console.log(result);
if(result.error) {
set_cookie("plex-wrapped", "", 1);
set_cookie("wrapperr-user", "", 1);
document.getElementById('search_wrapped_form').style.display = 'none';
document.getElementById('sign_out_div').style.display = 'none';
document.getElementById('plex_login_form').style.display = 'block';
@ -204,6 +196,7 @@ function validate_cookie(cookie) {
document.getElementById("plex_login_button").style.opacity = '0.5';
document.getElementById("search_wrapped_button").disabled = false;
document.getElementById("search_wrapped_button").style.opacity = '1';
get_user_links(cookie);
}
}
@ -214,7 +207,12 @@ function validate_cookie(cookie) {
return;
}
function get_plex_wrapped_version() {
function get_user_links(cookie) {
cookie_form = {
"cookie" : cookie
};
var cookie_data = JSON.stringify(cookie_form);
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
@ -222,17 +220,89 @@ function get_plex_wrapped_version() {
try {
var result= JSON.parse(this.responseText);
} catch(error) {
console.log('Failed to parse Plex-Wrapped version. Response: ' + this.responseText)
console.log('Failed to parse Wrapperr links. Response: ' + this.responseText)
}
if(!result.error) {
document.getElementById('github_link').innerHTML = 'GitHub (' + result.plex_wrapped_version + ')';
for(var i = 0; i < result.links.length; i++) {
document.getElementById('share_wrapped_url').innerHTML = window.location.href.split('?')[0] + '?hash=' + result.links[i].url_hash;
document.getElementById('share_wrapped_title_div').style.display = 'block';
document.getElementById('share_wrapped_div').style.display = 'flex';
}
}
}
};
xhttp.withCredentials = true;
xhttp.open("post", "api/get_plex_wrapped_version.php");
xhttp.open("post", "api/get_link_user.php");
xhttp.send(cookie_data);
return;
}
function get_wrapper_version() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
try {
var result= JSON.parse(this.responseText);
} catch(error) {
console.log('Failed to parse Wrapperr version. Response: ' + this.responseText)
}
if(!result.error) {
document.getElementById('github_link').innerHTML = 'GitHub (' + result.wrapperr_version + ')';
if(result.application_name && result.application_name !== '' && !link_mode) {
document.getElementById('application_name').innerHTML = result.application_name;
document.title = result.application_name;
}
}
}
};
xhttp.withCredentials = true;
xhttp.open("post", "api/get_wrapperr_version.php");
xhttp.send();
return;
}
function copy_link_user() {
window.open(document.getElementById('share_wrapped_url').innerHTML, '_blank').focus();
}
function delete_link_user() {
if(!confirm('Are you sure you want to delete this link?')) {
return;
}
cookie_form = {
"cookie" : cookie
};
var cookie_data = JSON.stringify(cookie_form);
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
try {
var result= JSON.parse(this.responseText);
} catch(error) {
console.log('Failed to parse Wrapperr response. Response: ' + this.responseText)
}
if(!result.error) {
document.getElementById('share_wrapped_title_div').style.display = 'none';
document.getElementById('share_wrapped_div').style.display = 'none';
} else {
console.log(result.message);
}
}
};
xhttp.withCredentials = true;
xhttp.open("post", "api/delete_link_user.php");
xhttp.send(cookie_data);
return;
}

11
robots.txt Normal file
View file

@ -0,0 +1,11 @@
# Folders
User-agent: *
Disallow: /api/
Disallow: /assets/
Disallow: /config/
Disallow: /docker/
# File types
Disallow: /*.json
Disallow: /*.php
Disallow: /*.js
Disallow: /*.md

View file

@ -1,56 +0,0 @@
function set_config() {
var clear_cache = document.getElementById('clear_cache').checked;
config_form = {
"password" : current_password,
"username" : current_username,
"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,
"tautulli_libraries" : tautulli_libraries,
"ssl" : ssl,
"password" : password,
"username" : username,
"timezone" : timezone,
"wrapped_start" : Math.round(wrapped_start.getTime() / 1000),
"wrapped_end" : Math.round(wrapped_end.getTime() / 1000),
"stats_intro" : stats_intro,
"create_share_links" : create_share_links,
"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_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,
"client_id" : client_id,
"plex_wrapped_root" : plex_wrapped_root
}
};
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", root + "api/set_config.php");
xhttp.send(config_data);
}