Files
JellyPy/data/interfaces/default/welcome.html
2021-02-06 18:41:24 +01:00

566 lines
28 KiB
HTML

<%
import jellypy
from jellypy 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.min.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.6.0">
<link rel="icon" type="image/png" sizes="16x16" href="${http_root}images/favicon/favicon-16x16.png?v=2.6.0">
<link rel="shortcut icon" href="${http_root}images/favicon/favicon.ico?v=2.6.0">
<!-- ICONS -->
<!-- Android -->
<link rel="manifest" href="${http_root}images/favicon/manifest.json?v=2.6.0" crossorigin="use-credentials">
<meta name="theme-color" content="#282a2d">
<!-- Apple -->
<link rel="apple-touch-icon" sizes="180x180" href="${http_root}images/favicon/apple-touch-icon.png?v=2.6.0">
<link rel="mask-icon" href="${http_root}images/favicon/safari-pinned-tab.svg?v=2.6.0" color="#282a2d">
<meta name="apple-mobile-web-app-title" content="Tautulli">
<!-- Microsoft -->
<meta name="application-name" content="Tautulli">
<meta name="msapplication-config" content="${http_root}images/favicon/browserconfig.xml?v=2.6.0">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="wizard" id="setup-wizard" data-title="JellyPy 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 JellyPy. Hope you find it useful.
</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>Authentication</h3>
<div class="wizard-input-section">
<p class="help-block">
Please setup an admin username and password for JellyPy.
</p>
</div>
<div class="wizard-input-section">
<label for="http_username">Username</label>
<div class="row">
<div class="col-xs-8">
<input type="text" class="form-control auth-settings" id="http_username"
name="http_username" value="" size="30">
</div>
</div>
</div>
<div class="wizard-input-section">
<label for="http_password">Password</label>
<div class="row">
<div class="col-xs-8">
<input type="password" class="form-control auth-settings" id="http_password"
name="http_password" value="" size="30" autocomplete="new-password">
</div>
</div>
</div>
<input type="hidden" class="form-control" name="http_hash_password" id="http_hash_password"
value="1">
<input type="hidden" class="form-control" name="http_plex_admin" id="http_plex_admin" value="1">
<input type="hidden" id="authentication_valid" data-validate="validateAuthentication" value="">
<span style="display: none;" id="authentication-status"></span>
</div>
<div class="wizard-card" data-cardname="card3">
<h3>Jellyfin Server</h3>
<div class="wizard-input-section">
<p class="help-block">
Select your Jellyfin Server from the dropdown menu or enter an IP address or hostname.
</p>
</div>
<div class="wizard-input-section">
<label for="jellyfin_ip_selectize">Jellyfin IP Address or Hostname</label>
<div class="row">
<div class="col-xs-12">
<select class="form-control jellyfin-settings selectize-jellyfin-ip" id="jellyfin_ip_selectize">
% if config['jellyfin_identifier']:
<option value="${config['jellyfin_ip']}:${config['jellyfin_port']}"
data-identifier="${config['jellyfin_identifier']}"
data-ip="${config['jellyfin_ip']}"
data-port="${config['jellyfin_port']}"
data-local="${int(not int(config['jellyfin_is_remote']))}"
data-ssl="${config['jellyfin_ssl']}"
data-is_cloud="${config['jellyfin_is_cloud']}"
data-label="${config['jellyfin_name'] or 'Local'}"
selected>${config['jellyfin_ip']}
</option>
% endif
</select>
</div>
</div>
</div>
<div class="wizard-input-section">
<label for="jellyfin_port">Jellyfin Port</label>
<div class="row">
<div class="col-xs-3">
<input type="text" class="form-control jellyfin-settings" name="jellyfin_port" id="jellyfin_port"
placeholder="8096" value="${config['jellyfin_port']}" required>
</div>
<div class="col-xs-4">
<div class="checkbox">
<label>
<input type="checkbox" id="jellyfin_ssl_checkbox"
class="checkbox-toggle jellyfin-settings" data-id="jellyfin_ssl" value="1"
${helpers.checked(config['jellyfin_ssl'])}> Use SSL
<input type="hidden" id="jellyfin_ssl" name="jellyfin_ssl" value="${config['jellyfin_ssl']}">
</label>
</div>
</div>
<div class="col-xs-4">
<div class="checkbox">
<label>
<input type="checkbox" id="jellyfin_is_remote_checkbox"
class="checkbox-toggle jellyfin-settings" data-id="jellyfin_is_remote" value="1"
${helpers.checked(config['jellyfin_is_remote'])}> Remote Server
<input type="hidden" id="jellyfin_is_remote" name="jellyfin_is_remote"
value="${config['jellyfin_is_remote']}">
</label>
</div>
</div>
</div>
</div>
<input type="hidden" id="jellyfin_ip" name="jellyfin_ip" value="${config['jellyfin_ip']}">
</div>
<div class="wizard-card" data-cardname="card4">
<h3>Jellyfin Auth</h3>
<div class="wizard-input-section">
<p class="help-block">
Authentificate with your Jellyfin instance.
</p>
</div>
<div class="wizard-input-section">
<label for="jellyfin_user">Jellyfin Username</label>
<div class="row">
<div class="col-xs-4">
<input type="text" class="form-control jellyfin-settings" name="jellyfin_user"
id="jellyfin_user" value="" required>
</div>
</div>
</div>
<div class="wizard-input-section">
<label for="jellyfin_password">Jellyfin Password</label>
<div class="row">
<div class="col-xs-4">
<input type="password" class="form-control jellyfin-settings" name="jellyfin_password"
id="jellyfin_password" value="" required>
</div>
</div>
</div>
<a class="btn btn-dark" id="verify-jellyfin-server" href="#" role="button">Verify</a>
<span style="margin-left: 10px; display: none;" id="jellyfin-verify-status"></span>
</div>
<div class="wizard-card" data-cardname="card5">
<h3>Activity Logging</h3>
<div class="wizard-input-section">
<p class="help-block">
JellyPy will keep a history of all streaming activity on your Jellyfin 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 jellyfin-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="card6">
<h3>Notifications</h3>
<div class="wizard-input-section">
<p class="help-block">
JellyPy can send a wide variety of notifications to alert you of activity on your Jellyfin
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>
<!-- 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="sys_tray_icon" id="sys_tray_icon" value="1" checked>
<input type="checkbox" name="launch_startup" id="launch_startup" 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="notify_group_recently_added_grandparent"
id="notify_group_recently_added_grandparent" value="1" checked>
<input type="checkbox" name="notify_group_recently_added_parent"
id="notify_group_recently_added_parent" 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-3.5.1.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 validateAuthentication(el) {
var http_username = $("#http_username").val();
var http_password = $("#http_password").val();
var retValue = {};
if (http_username === "" || http_password === "") {
retValue.status = false;
retValue.msg = "Please enter a username and password.";
$("#authentication-status").html('<i class="fa fa-exclamation-circle"></i> Please enter a username and password.');
$('#authentication-status').fadeIn('fast').delay(2000).fadeOut('fast');
} else {
retValue.status = true;
}
return retValue;
}
function validateJellyfinIp(el) {
var valid_jellyfin_ip = el.val();
var retValue = {};
if (valid_jellyfin_ip === "") {
retValue.status = false;
retValue.msg = "Please verify your server.";
$("#jellyfin-verify-status").html('<i class="fa fa-exclamation-circle"></i> Please verify your server.');
$('#jellyfin-verify-status').fadeIn('fast').delay(2000).fadeOut('fast');
} else {
retValue.status = true;
}
return retValue;
}
function validateJellyfinToken(el) {
var valid_jellyfin_token = el.val();
var retValue = {};
if (valid_jellyfin_token === "") {
retValue.status = false;
retValue.msg = "Please authenticate.";
$("#jellyfin-token-status").html('<i class="fa fa-exclamation-circle"></i> Please authenticate.');
$('#jellyfin-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: 450,
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_jellyfin = $('#jellyfin_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 jellyfin_ip_selected = this.getItem(item)[0];
var identifier = $(jellyfin_ip_selected).data('identifier');
var ip = $(jellyfin_ip_selected).data('ip');
var port = $(jellyfin_ip_selected).data('port');
var local = $(jellyfin_ip_selected).data('local');
var ssl = $(jellyfin_ip_selected).data('ssl');
var value = $(jellyfin_ip_selected).data('value');
$("#jellyfin_valid").val(identifier !== 'undefined' ? 'valid' : '');
$("#jellyfin-verify-status").html(identifier !== 'undefined' ? '<i class="fa fa-check"></i>&nbsp; Server found!' : '').fadeIn('fast');
$("#jellyfin_identifier").val(identifier !== 'undefined' ? identifier : '');
$('#jellyfin_ip').val(ip !== 'undefined' ? ip : value);
$('#jellyfin_port').val(port !== 'undefined' ? port : 8096);
$('#jellyfin_is_remote_checkbox').prop('checked', (local !== 'undefined' && local === 0));
$('#jellyfin_is_remote').val(local !== 'undefined' && local === 0 ? 1 : 0);
$('#jellyfin_ssl_checkbox').prop('checked', (ssl !== 'undefined' && ssl === 1));
$('#jellyfin_ssl').val(ssl !== 'undefined' && ssl === 1 ? 1 : 0);
$('#jellyfin_port').prop('readonly', false);
$('#jellyfin_is_remote_checkbox').prop('disabled', false);
$('#jellyfin_ssl_checkbox').prop('disabled', false);
},
onDropdownOpen: function () {
this.clear();
}
});
var select_jellyfin = $select_jellyfin[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 = $('#jellyfin_ip').val();
var existing_port = $('#jellyfin_port').val();
result.forEach(function (item) {
if (item.ip === existing_ip && item.port === existing_port) {
select_jellyfin.updateOption(item.value, item);
} else {
select_jellyfin.addOption(item);
}
});
}
}
})
}
var jellyfin_verified = false;
var authenticated = false;
$("#verify-jellyfin-server").click(function () {
if (!(jellyfin_verified)) {
var jellyfin_ip = $("#jellyfin_ip").val().trim();
var jellyfin_port = $("#jellyfin_port").val().trim();
var jellyfin_ssl = $("#jellyfin_ssl").val();
var jellyfin_is_remote = $("#jellyfin_is_remote").val();
var jellyfin_user = $("#jellyfin_user").val().trim();
var jellyfin_password = $("#jellyfin_password").val();
if ((jellyfin_ip !== '') || (jellyfin_port !== '')) {
$("#jellyfin-verify-status").html('<i class="fa fa-refresh fa-spin"></i>&nbsp; Verifying server...');
$('#jellyfin-verify-status').fadeIn('fast');
$.ajax({
url: 'check_login',
data: {
hostname: jellyfin_ip,
port: jellyfin_port,
ssl: jellyfin_ssl,
remote: jellyfin_is_remote,
user: jellyfin_user,
password: jellyfin_password
},
cache: true,
async: true,
timeout: 5000,
error: function (jqXHR, textStatus, errorThrown) {
$("#jellyfin-verify-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; Error verifying server: ' + textStatus);
$('#jellyfin-verify-status').fadeIn('fast');
},
success: function (xhr, status) {
var result = xhr;
var identifier = result.identifier;
if (identifier) {
$("#jellyfin_identifier").val(identifier);
$("#jellyfin-verify-status").html('<i class="fa fa-check"></i>&nbsp; Login successfull!');
$('#jellyfin-verify-status').fadeIn('fast');
jellyfin_verified = true;
$("#jellyfin_valid").val("valid");
} else {
$("#jellyfin-verify-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; This is not a Jellyfin Server!');
$('#jellyfin-verify-status').fadeIn('fast');
}
}
});
} else {
$("#jellyfin-verify-status").html('<i class="fa fa-exclamation-circle"></i>&nbsp; Please enter both fields.');
$('#jellyfin-verify-status').fadeIn('fast');
}
}
});
$(".jellyfin-settings").change(function () {
jellyfin_verified = false;
$("#jellyfin_valid").val("");
$("#jellyfin-verify-status").html("");
});
});
</script>
</body>
</html>