plexpy/data/interfaces/default/welcome.html
2018-07-17 09:44:00 -07:00

517 lines
25 KiB
HTML

<%
import plexpy
from plexpy import common, helpers
%>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tautulli - ${title} | ${server_name}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link href="${http_root}css/bootstrap3/bootstrap.css" rel="stylesheet">
<link href="${http_root}css/bootstrap-wizard.css" rel="stylesheet">
<link href="${http_root}css/tautulli.css${cache_param}" rel="stylesheet">
<link href="${http_root}css/selectize.bootstrap3.css" rel="stylesheet">
<link href="${http_root}css/opensans.min.css" rel="stylesheet">
<link href="${http_root}css/font-awesome.all.min.css" rel="stylesheet">
<link href="${http_root}css/font-awesome.v4-shims.min.css" rel="stylesheet">
<!-- Favicons -->
<link rel="icon" type="image/png" sizes="32x32" href="${http_root}images/favicon/favicon-32x32.png?v=2.0.0">
<link rel="icon" type="image/png" sizes="16x16" href="${http_root}images/favicon/favicon-16x16.png?v=2.0.0">
<link rel="shortcut icon" href="${http_root}images/favicon/favicon.ico?v=2.0.0">
<!-- ICONS -->
<!-- Android >M39 icon -->
<link rel="icon" type="image/png" sizes="192x192" href="${http_root}images/favicon/android-chrome-192x192.png?v=2.0.0">
<link rel="manifest" href="${http_root}json/Android-manifest.json?v=2.0.0">
<meta name="theme-color" content="#1f1f1f">
<!-- Apple -->
<link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.0.0">
<link rel="mask-icon" href="${http_root}images/favicon/safari-pinned-tab.svg?v=2.0.0" color="#1f1f1f">
<meta name="apple-mobile-web-app-title" content="Tautulli">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="viewport" content="initial-scale=1">
<meta name="format-detection" content="telephone=no">
<!-- IE10 icon -->
<meta name="application-name" content="Tautulli">
<meta name="msapplication-TileColor" content="#1f1f1f">
<meta name="msapplication-TileImage" content="${http_root}images/favicon/mstile-144x144.png?v=2.0.0">
<meta name="msapplication-config" content="${http_root}xml/IEconfig.xml?v=2.0.0" />
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="wizard" id="setup-wizard" data-title="Tautulli Setup Wizard">
<form>
<div class="wizard-card" data-cardname="card1">
<div style="float: right;">
<img src="${http_root}images/logo-tautulli-45.png" height="45" alt="Tautulli">
</div>
<h3 style="line-height: 50px;">Welcome!</h3>
<div class="wizard-input-section">
<p class="welcome-message">
Thanks for taking the time to try out Tautulli. Hope you find it useful.
</p>
<p class="welcome-message">
Tautulli requires a permanent internet connection to ensure a reliable experience.
</p>
<p class="welcome-message">
This wizard will help you get set up, to continue press Next.
</p>
</div>
</div>
<div class="wizard-card" data-cardname="card2">
<h3>Plex Authentication</h3>
<div class="wizard-input-section">
<p class="help-block">
Tautulli requires a Plex.tv account. Click the button below to sign in on Plex.tv. You may need to allow popups in your browser.
</p>
</div>
<input type="hidden" class="form-control" name="pms_token" id="pms_token" value="" data-validate="validatePMStoken">
<a class="btn btn-dark" id="sign-in-plex" href="#" role="button">Sign In with Plex</a>
<span style="margin-left: 10px; display: none;" id="pms-token-status"></span>
</div>
<div class="wizard-card" data-cardname="card3">
<h3>Plex Media Server</h3>
<div class="wizard-input-section">
<p class="help-block">
Select your Plex Media Server from the dropdown menu or enter an IP address or hostname.
</p>
</div>
<div class="wizard-input-section">
<label for="pms_ip_selectize">Plex IP Address or Hostname</label>
<div class="row">
<div class="col-xs-12">
<select class="form-control pms-settings selectize-pms-ip" id="pms_ip_selectize">
<option value="${config['pms_ip']}:${config['pms_port']}"
data-identifier="${config['pms_identifier']}"
data-ip="${config['pms_ip']}"
data-port="${config['pms_port']}"
data-local="${int(not int(config['pms_is_remote']))}"
data-ssl="${config['pms_ssl']}"
data-is_cloud="${config['pms_is_cloud']}"
data-label="${config['pms_name'] or 'Local'}"
selected>${config['pms_ip']}</option>
</select>
</div>
</div>
</div>
<div class="wizard-input-section">
<label for="pms_port">Plex Port</label>
<div class="row">
<div class="col-xs-3">
<input type="text" class="form-control pms-settings" name="pms_port" id="pms_port" placeholder="32400" value="${config['pms_port']}" required>
</div>
<div class="col-xs-4">
<div class="checkbox">
<label>
<input type="checkbox" id="pms_ssl_checkbox" class="checkbox-toggle pms-settings" data-id="pms_ssl" value="1" ${helpers.checked(config['pms_ssl'])}> Use SSL
<input type="hidden" id="pms_ssl" name="pms_ssl" value="${config['pms_ssl']}">
</label>
</div>
</div>
<div class="col-xs-4">
<div class="checkbox">
<label>
<input type="checkbox" id="pms_is_remote_checkbox" class="checkbox-toggle pms-settings" data-id="pms_is_remote" value="1" ${helpers.checked(config['pms_is_remote'])}> Remote Server
<input type="hidden" id="pms_is_remote" name="pms_is_remote" value="${config['pms_is_remote']}">
</label>
</div>
</div>
</div>
</div>
<input type="hidden" id="pms_valid" data-validate="validatePMSip" value="">
<input type="hidden" id="pms_ip" name="pms_ip" value="${config['pms_ip']}">
<input type="hidden" id="pms_is_cloud" name="pms_is_cloud" value="${config['pms_is_cloud']}">
<input type="hidden" id="pms_identifier" name="pms_identifier" value="${config['pms_identifier']}">
<a class="btn btn-dark" id="verify-plex-server" href="#" role="button">Verify</a>
<span style="margin-left: 10px; display: none;" id="pms-verify-status"></span>
</div>
<div class="wizard-card" data-cardname="card4">
<h3>Activity Logging</h3>
<div class="wizard-input-section">
<p class="help-block">
Tautulli will keep a history of all streaming activity on your Plex server.
</p>
</div>
<div class="wizard-input-section">
<label for="logging_ignore_interval">Ignore Interval</label>
<div class="row">
<div class="col-xs-4">
<input type="text" class="form-control pms-monitoring" id="logging_ignore_interval" name="logging_ignore_interval" placeholder="120" value="${config['logging_ignore_interval']}" data-validate="validateIgnoreInterval" required>
</div>
<span style="margin-left: 10px; line-height: 35px; display: none;" id="ignore-int-status"></span>
</div>
<p class="help-block">The interval (in seconds) an item must be in a playing state before logging it. 0 to disable.</p>
</div>
<div class="wizard-input-section">
<p class="help-block">
Additional options to disable history logging for certain libraries or users can be found by editing them
on the <strong>Libraries</strong> or <strong>Users</strong> pages.
</p>
</div>
</div>
<div class="wizard-card" data-cardname="card4">
<h3>Notifications</h3>
<div class="wizard-input-section">
<p class="help-block">
Tautulli can send a wide variety of notifications to alert you of activity on your Plex server.
</p>
<p class="help-block">
To set up a notification agent, navigate to the <strong>Settings</strong> page
and to the <strong>Notification Agents</strong> tab after you have completed this setup wizard.
</p>
</div>
</div>
<div class="wizard-card" data-cardname="card5">
<h3>Database Import</h3>
<div class="wizard-input-section">
<p class="help-block">
If you have an existing PlexWatch/Plexivity database, you can import the data into Tautulli.
</p>
<p class="help-block">
To import a database, navigate to the <strong>Settings</strong> page
and to the <strong>Import & Backups</strong> tab after you have completed this setup wizard.
</p>
</div>
<!-- Required fields but hidden -->
<div style="display: none;">
<input type="checkbox" name="first_run" id="first_run" value="1" checked>
<input type="checkbox" name="group_history_tables" id="group_history_tables" value="1" checked>
<input type="checkbox" name="history_table_activity" id="history_table_activity" value="1" checked>
<input type="checkbox" name="launch_browser" id="launch_browser" value="1" checked>
<input type="checkbox" name="api_enabled" id="api_enabled" value="1" checked>
<input type="checkbox" name="refresh_users_on_startup" id="refresh_users_on_startup" value="1" checked>
<input type="checkbox" name="refresh_libraries_on_startup" id="refresh_libraries_on_startup" value="1" checked>
<input type="checkbox" name="check_github" id="check_github" value="1" checked>
<input type="checkbox" name="log_blacklist" id="log_blacklist" value="1" checked>
<input type="checkbox" name="cache_images" id="cache_images" value="1" checked>
<input type="checkbox" name="server_changed" id="server_changed" value="1" checked>
<input type="checkbox" name="first_run_complete" id="first_run_complete" value="1" checked>
<input type="text" name="home_stats_cards" id="home_stats_cards" value="first_run_wizard">
<input type="text" name="home_library_cards" id="home_library_cards" value="first_run_wizard">
</div>
</div>
</form>
<div class="wizard-success">
<h3>Setup Complete!</h3>
<br/>
<p>Setup is now complete. For more configuration options please visit the Settings menu on the home page.</p>
<br/>
<i class="fa fa-refresh fa-spin"></i>&nbspWaiting <span class="countdown">5</span> seconds to ensure authentication token is registered...
</div>
</div>
</div>
</div>
<script src="${http_root}js/jquery-2.1.4.min.js"></script>
<script src="${http_root}js/bootstrap.min.js"></script>
<script src="${http_root}js/selectize.min.js"></script>
<script src="${http_root}js/platform.min.js"></script>
<script src="${http_root}js/script.js${cache_param}"></script>
<script src="${http_root}js/bootstrap-wizard.min.js"></script>
<script>
function validatePMSip(el) {
var valid_pms_ip = el.val();
var retValue = {};
if (valid_pms_ip == "") {
retValue.status = false;
retValue.msg = "Please verify your server.";
$("#pms-verify-status").html('<i class="fa fa-exclamation-circle"></i> Please verify your server.');
$('#pms-verify-status').fadeIn('fast').delay(2000).fadeOut('fast');
} else {
retValue.status = true;
}
return retValue;
}
function validatePMStoken(el) {
var valid_pms_token = el.val();
var retValue = {};
if (valid_pms_token == "") {
retValue.status = false;
retValue.msg = "Please authenticate.";
$("#pms-token-status").html('<i class="fa fa-exclamation-circle"></i> Please authenticate.');
$('#pms-token-status').fadeIn('fast').delay(2000).fadeOut('fast');
} else {
retValue.status = true;
}
return retValue;
}
function validateIgnoreInterval(el) {
var valid_ignore_int = el.val();
var retValue = {};
if (!isPositiveInt(valid_ignore_int)) {
retValue.status = false;
retValue.msg = "Please enter a valid integer.";
$("#ignore-int-status").html('<i class="fa fa-exclamation-circle"></i> Please enter a valid ignore interval.');
$('#ignore-int-status').fadeIn('fast').delay(2000).fadeOut('fast');
} else {
retValue.status = true;
}
return retValue;
}
function isPositiveInt(n) {
return $.isNumeric(n) && (Math.floor(n) == n) && (n >= 0)
}
$(document).ready(function() {
$.fn.wizard.logging = false;
var options = {
keyboard : false,
contentHeight : 400,
contentWidth : 700,
backdrop: 'static',
buttons: {submitText: 'Finish'},
submitUrl: "configUpdate"
};
var wizard = $("#setup-wizard").wizard(options);
wizard.show();
// Change button classes
wizard.find('.wizard-back').addClass('btn-dark');
wizard.on('incrementCard', function(wizard) {
wizard.find('.wizard-next.btn-success').removeClass('btn-success').addClass('btn-bright');
});
wizard.on('decrementCard', function(wizard) {
wizard.find('.wizard-next').removeClass('btn-bright').text('Next');
});
wizard.on("submit", function(wizard) {
// Probably should not success before we know, but hopefully validation is good enough.
wizard.submitSuccess();
$.ajax({
type: "POST",
url: wizard.args.submitUrl,
data: wizard.serialize(),
dataType: "json",
complete: function (data) {
$(".countdown").countdown(function () { location.reload(); }, 5, "");
}
})
});
$('.checkbox-toggle').click(function () {
var configToggle = $(this).data('id');
if ($(this).is(':checked')) {
$('#'+configToggle).val(1);
} else {
$('#'+configToggle).val(0);
}
});
var $select_pms = $('#pms_ip_selectize').selectize({
createOnBlur: true,
openOnFocus: true,
maxItems: 1,
closeAfterSelect: true,
sortField: 'label',
searchField: ['label', 'value'],
inputClass: 'form-control selectize-input',
render: {
item: function (item, escape) {
if (!item.label) {
$.extend(item,
$(this.revertSettings.$children)
.filter('[value=' + item.value + ']').data()
);
}
var label = item.label || item.value;
var caption = item.label ? item.ip : null;
return '<div data-identifier="' + item.clientIdentifier +
'" data-ip="' + item.ip +
'" data-port="' + item.port +
'" data-local="' + item.local +
'" data-ssl="' + item.httpsRequired +
'" data-is_cloud="' + item.is_cloud +
'" data-label="' + item.label + '">' +
'<span class="item-text">' + escape(label) + '</span>' +
(caption ? '<span class="item-value">' + escape(caption) + '</span>' : '') +
'</div>';
},
option: function (item, escape) {
var label = item.label || item.value;
var caption = item.label ? item.value : null;
return '<div data-identifier="' + item.clientIdentifier +
'" data-ip="' + item.ip +
'" data-port="' + item.port +
'" data-local="' + item.local +
'" data-ssl="' + item.httpsRequired +
'" data-is_cloud="' + item.is_cloud +
'" data-label="' + item.label + '">' +
escape(label) +
(caption ? '<span class="caption">' + escape(caption) + '</span>' : '') +
'</div>';
}
},
create: function(input) {
return {label: '', value: input};
},
onInitialize: function () {
var s = this;
this.revertSettings.$children.each(function () {
$.extend(s.options[this.value], $(this).data());
});
},
onChange: function (item) {
var pms_ip_selected = this.getItem(item)[0];
var identifier = $(pms_ip_selected).data('identifier');
var ip = $(pms_ip_selected).data('ip');
var port = $(pms_ip_selected).data('port');
var local = $(pms_ip_selected).data('local');
var ssl = $(pms_ip_selected).data('ssl');
var is_cloud = $(pms_ip_selected).data('is_cloud');
var value = $(pms_ip_selected).data('value');
$("#pms_valid").val(identifier !== 'undefined' ? 'valid' : '');
$("#pms-verify-status").html(identifier !== 'undefined' ? '<i class="fa fa-check"></i>&nbsp; Server found!' : '').fadeIn('fast');
$("#pms_identifier").val(identifier !== 'undefined' ? identifier : '');
$('#pms_ip').val(ip !== 'undefined' ? ip : value);
$('#pms_port').val(port !== 'undefined' ? port : 32400);
$('#pms_is_remote_checkbox').prop('checked', (local !== 'undefined' && local === 0));
$('#pms_is_remote').val(local !== 'undefined' && local === 0 ? 1 : 0);
$('#pms_ssl_checkbox').prop('checked', (ssl !== 'undefined' && ssl === 1));
$('#pms_ssl').val(ssl !== 'undefined' && ssl === 1 ? 1 : 0);
$('#pms_is_cloud').val(is_cloud !== 'undefined' && is_cloud === true ? 1 : 0);
if (is_cloud === true) {
$('#pms_port').prop('readonly', true);
$('#pms_is_remote_checkbox').prop('disabled', true);
$('#pms_ssl_checkbox').prop('disabled', true);
} else {
$('#pms_port').prop('readonly', false);
$('#pms_is_remote_checkbox').prop('disabled', false);
$('#pms_ssl_checkbox').prop('disabled', false);
}
},
onDropdownOpen: function() {
this.clear();
}
});
var select_pms = $select_pms[0].selectize;
function getServerOptions(token) {
/* Set token and returns server options */
$.ajax({
url: 'discover',
data: {
token: token
},
success: function (result) {
if (result) {
var existing_ip = $('#pms_ip').val();
var existing_port = $('#pms_port').val();
result.forEach(function (item) {
if (item.ip === existing_ip && item.port === existing_port) {
select_pms.updateOption(item.value, item);
} else {
select_pms.addOption(item);
}
});
}
}
})
}
var pms_verified = false;
var authenticated = false;
$("#verify-plex-server").click(function () {
if (!(pms_verified)) {
var pms_ip = $("#pms_ip").val().trim();
var pms_port = $("#pms_port").val().trim();
var pms_identifier = $("#pms_identifier").val();
var pms_ssl = $("#pms_ssl").val();
var pms_is_remote = $("#pms_is_remote").val();
if ((pms_ip !== '') || (pms_port !== '')) {
$("#pms-verify-status").html('<i class="fa fa-refresh fa-spin"></i>&nbsp; Validating server...');
$('#pms-verify-status').fadeIn('fast');
$.ajax({
url: 'get_server_id',
data: {
hostname: pms_ip,
port: pms_port,
identifier: pms_identifier,
ssl: pms_ssl,
remote: pms_is_remote
},
cache: true,
async: true,
timeout: 5000,
error: function (jqXHR, textStatus, errorThrown) {
$("#pms-verify-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; This is not a Plex Server!');
$('#pms-verify-status').fadeIn('fast');
},
success: function(xhr, status) {
var result = xhr;
var identifier = result.identifier;
if (identifier) {
$("#pms_identifier").val(identifier);
$("#pms-verify-status").html('<i class="fa fa-check"></i>&nbsp; Server found!');
$('#pms-verify-status').fadeIn('fast');
pms_verified = true;
$("#pms_valid").val("valid");
} else {
$("#pms-verify-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; This is not a Plex Server!');
$('#pms-verify-status').fadeIn('fast');
}
}
});
} else {
$("#pms-verify-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; Please enter both fields.');
$('#pms-verify-status').fadeIn('fast');
}
}
});
$( ".pms-settings" ).change(function() {
pms_verified = false;
$("#pms_valid").val("");
$("#pms-verify-status").html("");
});
function OAuthPreFunction() {
$("#pms_token").val('');
$("#pms-token-status").html('<i class="fa fa-refresh fa-spin"></i>&nbsp; Waiting for authentication...').fadeIn('fast');
}
function OAuthSuccessCallback(authToken) {
$("#pms_token").val(authToken);
$("#pms-token-status").html('<i class="fa fa-check"></i>&nbsp; Authentication successful.').fadeIn('fast');
authenticated = true;
getServerOptions(authToken);
}
function OAuthErrorCallback() {
$("#pms-token-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; Error communicating with Plex.tv.').fadeIn('fast');
}
$('#sign-in-plex').click(function() {
PlexOAuth(OAuthSuccessCallback, OAuthErrorCallback, OAuthPreFunction);
});
});
</script>
</body>
</html>