1
0
mirror of https://github.com/KubaPro010/fm-dx-webserver.git synced 2026-02-26 14:11:59 +01:00
Files
fm-dx-webserver/web/setup.ejs
2025-07-07 22:32:04 +10:00

604 lines
40 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<title>Setup - FM-DX Webserver</title>
<link href="css/entry.css" type="text/css" rel="stylesheet">
<link href="css/flags.min.css" type="text/css" rel="stylesheet">
<link href="css/libs/fontawesome.css" type="text/css" rel="stylesheet">
<script src="js/libs/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" type="text/css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
<link rel="icon" type="image/png" href="favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="toast-container"></div>
<div class="wrapper-outer wrapper-full wrapper-outer-static">
<div id="navigation" class="sidenav flex-container flex-phone">
<div class="sidenav-content">
<h1 class="top-25">Settings</h1>
<ul class="nav" role="tablist" style="border-radius: 15px 15px 0 0;">
<li role="tab" data-panel="dashboard" aria-selected="true" tabindex="0">
<a href="#" role="tab" aria-controls="dashboard"><i class="fa-solid fa-fw fa-chart-line"></i> Dashboard</a>
</li>
<li role="tab" data-panel="tuner" tabindex="0">
<a href="#" role="tab" tabindex="-1" aria-controls="tuner"><i class="fa-solid fa-fw fa-radio"></i> Tuner</a>
</li>
<li role="tab" data-panel="audio" tabindex="0">
<a href="#" role="tab" tabindex="-1" aria-controls="audio"><i class="fa-solid fa-fw fa-volume-high"></i> Audio</a>
</li>
<li role="tab" data-panel="webserver" tabindex="0">
<a href="#" role="tab" tabindex="-1" aria-controls="webserver"><i class="fa-solid fa-fw fa-server"></i> Webserver</a>
</li>
<li role="tab" data-panel="identification" tabindex="0">
<a href="#" role="tab" tabindex="-1" aria-controls="identification"><i class="fa-solid fa-fw fa-circle-info"></i> Identification & Map</a>
</li>
<li role="tab" data-panel="plugins-tab" tabindex="0">
<a href="#" role="tab" tabindex="-1" aria-controls="plugins-tab"><i class="fa-solid fa-fw fa-puzzle-piece"></i> Plugins</a>
</li>
<li role="tab" data-panel="users" tabindex="0">
<a href="#" role="tab" tabindex="-1" aria-controls="users"><i class="fa-solid fa-fw fa-user"></i> User management</a>
</li>
<li role="tab" data-panel="extras" tabindex="0">
<a href="#" role="tab" tabindex="-1" aria-controls="extras"><i class="fa-solid fa-fw fa-star"></i> Extras</a>
</li>
<div class="admin-quick-dashboard top-25">
<div class="icon tooltip" role="button" aria-label="Go back to the main screen" tabindex="0" data-tooltip="Go back to the main screen" onclick="document.location.href='./'">
<i class="fa-solid fa-arrow-left"></i>
</div>
<div class="icon tooltip" id="submit-config" role="button" aria-label="Save settings" tabindex="0" data-tooltip="Save settings" onclick="submitConfig()">
<i class="fa-solid fa-save"></i>
</div>
<div class="icon tooltip logout-link" role="button" aria-label="Sign out" tabindex="0" data-tooltip="Sign out">
<i class="fa-solid fa-sign-out"></i>
</div>
</div>
<hr>
<div class="panel-100-real m-0 p-10 no-bg">
<p class="color-4">Feel free to contact us on <a href="https://discord.gg/ZAVNdS74mC" target="_blank"><strong class="color-5"><i class="fa-brands fa-discord"></i> Discord</strong></a> for community support.</p>
<a href="https://github.com/noobishsvk/fm-dx-webserver" target="_blank" class="text-small">Version: <span class="version-string color-4"></span></a>
</div>
</ul>
</div>
<div class="sidenav-close text-medium-big hover-brighten flex-center color-4 modal-panel-sidebar" role="button" onclick="toggleNav()" aria-label="Toggle navigation" tabindex="0"><i class="fa-solid fa-chevron-left"></i></div>
</div>
<div id="wrapper" class="setup-wrapper admin-wrapper panel-full">
<div class="panel-full" style="margin-top: -20px; border-radius: 0; padding-left: 20px;padding-right: 20px;">
<div class="panel-full tab-content no-bg m-0" id="dashboard" role="tabpanel">
<h2>Dashboard</h2>
<div class="flex-container">
<div class="panel-33 p-20">
<span class="text-medium-big color-5"><%= onlineUsers %></span>
<p>Online users</p>
</div>
<div class="panel-33 p-20">
<span class="text-medium-big color-5"><%= memoryUsage %></span>
<span class="text-small color-4" style="display: block; font-size: 1em; line-height: 0;">(<%= memoryHeap %> heap)</span>
<p>Memory usage</p>
</div>
<div class="panel-33 p-20">
<span class="text-medium-big color-5"><%= processUptime %></span>
<p >Uptime</p>
</div>
</div>
<div class="flex-container">
<div class="panel-100-real p-bottom-20" style="overflow-x: auto;">
<h3>Current users</h3>
<table class="table-big">
<thead>
<tr>
<th>IP Address</th>
<th>Location</th>
<th>Online since</th>
<th></th>
</tr>
</thead>
<tbody>
<% if (connectedUsers.length > 0) { %>
<% connectedUsers.forEach(user => { %>
<tr>
<td>
<a href="https://dnschecker.org/ip-location.php?ip=<%= user.ip.replace('::ffff:', '') %>" target="_blank">
<%= user.ip.replace('::ffff:', '') %>
</a>
</td>
<td><%= user.location %></td>
<td><%= user.time %></td>
<td><a href="./kick?ip=<%= user.ip %>">Kick</a></td>
</tr>
<% }); %>
<% } else { %>
<tr>
<td colspan="4" style="text-align: center">No users online</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
<div class="flex-container">
<div class="panel-100-real p-bottom-20">
<h3>Quick settings</h3>
<div class="flex-container flex-center" style="margin: 30px;">
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Public Tuner', id: 'publicTuner'}) %>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Admin lock', id: 'lockToAdmin'}) %><br>
</div>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Tune password', id: 'password-tunePass', password: true}) %>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Admin password', id: 'password-adminPass', password: true}) %><br>
</div>
</div>
<div class="flex-container">
<div class="panel-100-real p-bottom-20 bottom-20">
<h3>Console</h3>
<% if (consoleOutput && consoleOutput.length > 0) { %>
<div class="panel-100 auto br-5 p-10 text-small text-left top-10" id="console-output">
<% consoleOutput.forEach(function(log) { %>
<pre class="m-0" style="white-space:pre-wrap;"><%= log %></pre>
<% }); %>
</div>
<% } else { %>
<p>No console output available.</p>
<% } %>
</div>
</div>
</div>
<div class="panel-full tab-content no-bg m-0" id="audio" role="tabpanel">
<h2>Audio settings</h2>
<div class="flex-container contains-dropdown">
<div class="panel-33 p-bottom-20">
<h3>Device</h3>
<p>Your audio device port.<br>
<span class="text-gray">This is where your tuner is plugged in.</span>
</p>
<%- include('_components', {
component: 'dropdown',
id: 'audioList',
inputId: 'audio-audioDevice',
label: 'Audio device',
cssClass: '',
placeholder: 'Choose your audio device',
options: [
...videoDevices.map(device => ({
value: device.name,
label: `${device.name}`
})),
...audioDevices.map(device => ({
value: device.name,
label: `${device.name}`
}))
]
}) %>
</div>
<div class="panel-33 p-bottom-20">
<h3>Channels</h3>
<p>Audio channel count.<br>
<span class="text-gray">Choose between Mono / Stereo.</span>
</p>
<%- include('_components', { component: 'dropdown', id: 'audio-channels-dropdown', inputId: 'audio-audioChannels', label: 'Audio channels', cssClass: '', placeholder: 'Stereo',
options: [
{ value: '2', label: 'Stereo' },
{ value: '1', label: 'Mono' }
]
}) %><br>
</div>
<div class="panel-33 p-bottom-20">
<h3>Bitrate</h3>
<p>The bitrate of the mp3 audio.<br>
<span class="text-gray">Minimum: 64 Kbps • Maximum: 320 Kbps</span>
</p>
<%- include('_components', { component: 'dropdown', id: 'audio-quality-dropdown', inputId: 'audio-audioBitrate', label: 'Audio quality', cssClass: '', placeholder: '128kbps (standard)',
options: [
{ value: '64k', label: '64kbps (lowest quality)' },
{ value: '96k', label: '96kbps (low quality)' },
{ value: '128k', label: '128kbps (standard)' },
{ value: '192k', label: '192kbps (high quality)' },
{ value: '256k', label: '256kbps (very high quality)' },
{ value: '320k', label: '320kbps (ultra quality)' }
]
}) %><br>
</div>
</div>
<div class="flex-container">
<div class="panel-50 p-bottom-20">
<h3>Volume</h3>
<p>This option will boost the audio volume globally, recommended for the Headless TEF.</p>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Audio Boost', id: 'audio-audioBoost'}) %>
</div>
<div class="panel-50 p-bottom-20">
<h3>Experimental</h3>
<p>If you use an USB audio card on Linux, enabling this option might fix your audio issues.</p>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'ALSA Software mode', id: 'audio-softwareMode'}) %>
</div>
</div>
<div class="flex-container">
<div class="panel-50 p-bottom-20">
<h3>FFmpeg</h3>
<p>Legacy option for Linux / macOS that could resolve audio issues, but will consume additional CPU and RAM usage.</p>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Additional FFmpeg', id: 'audio-ffmpeg'}) %>
</div>
<div class="panel-50 p-botom-20">
<h3>Sample rate Offset</h3>
<p>Using a negative value could eliminate audio buffering issues during long periods of listening. <br>
However, a value thats too low might increase the buffer over time.</p>
<p><input class="panel-33 input-text w-100 auto" type="number" style="min-height: 40px; color: var(--color-text); padding: 10px; padding-left: 10px; box-sizing: border-box; border: 2px solid transparent; font-family: 'Titillium Web', sans-serif;" id="audio-samplerateOffset" min="-10" max="10" step="1" value="0" aria-label="Samplerate offset"></p>
</div>
</div>
</div>
<div class="panel-full m-0 tab-content no-bg" id="webserver" role="tabpanel">
<h2>Webserver settings</h2>
<div class="flex-container contains-dropdown">
<div class="panel-50 p-bottom-20" style="padding-left: 20px; padding-right: 20px;">
<h3>Connection</h3>
<p class="text-gray">Leave the IP at 0.0.0.0 unless you explicitly know you have to change it.<br>Don't enter your public IP here.</p>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '0.0.0.0', label: 'Webserver IP', id: 'webserver-webserverIp'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '8080', label: 'Webserver port', id: 'webserver-webserverPort'}) %><br>
</div>
<div class="panel-50 p-bottom-20">
<h3>Design</h3>
<h4>Background image</h4>
<%- include('_components', {component: 'text', cssClass: 'br-15', placeholder: 'Direct image link', label: 'Image link', id: 'webserver-bgImage'}) %><br>
<h4 class="top-25">Themes</h4>
<%- include('_components', { component: 'dropdown', id: 'server-theme-selector', inputId: 'webserver-defaultTheme', label: 'Default server theme', cssClass: '', placeholder: 'Default',
options: [
{ value: 'theme1', label: 'Mint' },
{ value: 'theme2', label: 'Cappuccino' },
{ value: 'theme3', label: 'Nature' },
{ value: 'theme4', label: 'Ocean' },
{ value: 'theme5', label: 'Terminal' },
{ value: 'theme6', label: 'Nightlife' },
{ value: 'theme7', label: 'Blurple' },
{ value: 'theme8', label: 'Construction' },
{ value: 'theme9', label: 'Amoled' },
]
}) %><br>
</div>
</div>
<div class="flex-container">
<div class="panel-100-real p-bottom-20">
<h3>Antennas</h3>
<%- include('_components', {component: 'checkbox', cssClass: 'bottom-20', label: 'Antenna switch', id: 'antennas-enabled'}) %><br>
<div class="flex-container flex-center p-20">
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 1', id: 'antennas-ant1-enabled'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant A', label: 'Antenna 1 name', id: 'antennas-ant1-name'}) %><br>
</div>
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
<%- include('_components', {component: 'checkbox', cssClass: 'top-25', label: 'Antenna 2', id: 'antennas-ant2-enabled'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant B', label: 'Antenna 2 name', id: 'antennas-ant2-name'}) %><br>
</div>
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 3', id: 'antennas-ant3-enabled'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant C', label: 'Antenna 3 name', id: 'antennas-ant3-name'}) %><br>
</div>
<div class="flex-container flex-phone flex-column bottom-20" style="margin-left: 15px; margin-right: 15px;">
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Antenna 4', id: 'antennas-ant4-enabled'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'Ant D', label: 'Antenna 4 name', id: 'antennas-ant4-name'}) %><br>
</div>
</div>
</div>
</div>
<div class="flex-container">
<div class="panel-50" style="padding-left: 20px; padding-right: 20px;">
<h3>Tuning options</h3>
<p>If you want to limit which frequencies the users can tune to,<br>you can set the lower and upper limit here.<br>
<span class="text-gray">Enter frequencies in MHz.</span>
</p>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Limit tuning', id: 'webserver-tuningLimit'}) %><br>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '0', label: 'Lower limit', id: 'webserver-tuningLowerLimit'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '108', label: 'Upper limit', id: 'webserver-tuningUpperLimit'}) %>
</div>
<div class="panel-50 p-bottom-20">
<h3>Presets</h3>
<p>You can set up to 4 presets.<br>These presets are accessible with the F1-F4 buttons.<br>
<span class="text-gray">Enter frequencies in MHz.</span></p>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '87.5', label: 'Preset 1', id: 'webserver-presets-1'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '87.5', label: 'Preset 2', id: 'webserver-presets-2'}) %>
<br>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '87.5', label: 'Preset 3', id: 'webserver-presets-3'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '87.5', label: 'Preset 4', id: 'webserver-presets-4'}) %>
</div>
</div>
<div class="flex-container p-bottom-20">
<div class="panel-50 p-bottom-20" style="padding-left: 20px; padding-right: 20px;">
<h3>RDS Mode</h3>
<p>You can switch between American (RBDS) / Global (RDS) mode here.</p>
<%- include('_components', {component: 'checkbox', cssClass: 'bottom-20', iconClass: '', label: 'American RDS mode (RBDS)', id: 'webserver-rdsMode'}) %>
<h3>RDS Timeout</h3>
<p>If no data is received, RDS will be automatically cleared after a timeout.<br>
<span class="text-gray">Enter timeout in seconds or 0 to disable.</span><br></p>
<%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: '0', label: 'RDS Timeout', id: 'webserver-rdsTimeout'}) %>
</div>
<div class="panel-50 p-bottom-20" style="padding-left: 20px; padding-right: 20px;">
<h3>Transmitter Search Algorithm</h3>
<p>Different modes may help with more accurate transmitter identification depending on your region.</p>
<%- include('_components', { component: 'dropdown', id: 'server-tx-id-algo', inputId: 'webserver-txIdAlgorithm', label: 'Transmitter ID Algorithm', cssClass: '', placeholder: 'Algorithm 1',
options: [
{ value: '0', label: 'Algorithm 1' },
{ value: '1', label: 'Algorithm 2' },
{ value: '2', label: 'Algorithm 3' },
]
}) %>
</div>
</div>
</div>
<div class="panel-full m-0 tab-content no-bg" id="tuner" role="tabpanel">
<h2>Tuner settings</h2>
<div class="flex-container contains-dropdown">
<div class="panel-33 p-bottom-20">
<h3>Device type</h3>
<%- include('_components', { component: 'dropdown', id: 'device-selector', inputId: 'device', label: 'Device', cssClass: '', placeholder: 'TEF668x / TEA685x',
options: [
{ value: 'tef', label: 'TEF668x / TEA685x' },
{ value: 'xdr', label: 'XDR (F1HD / S10HDiP)' },
{ value: 'sdr', label: 'SDR (RTL-SDR / AirSpy)' },
{ value: 'other', label: 'Other' }
]
}) %><br>
</div>
<div class="panel-33 p-bottom-20" style="padding-right: 20px; padding-left: 20px;">
<h3>Connection type</h3>
<p class="text-gray">If you want to choose the COM port directly, choose "Direct".<br>If you use xdrd or your receiver is connected via Wi-Fi, choose TCP/IP.</p>
<div class="auto top-10">
<label class="toggleSwitch nolabel" onclick="">
<input id="xdrd-wirelessConnection" type="checkbox" tabindex="0" aria-label="Connection type"/>
<a></a>
<span>
<span class="left-span">Direct</span>
<span class="right-span">TCP/IP</span>
</span>
</label>
</div>
</div>
<div class="panel-33 p-bottom-20">
<h3>Device / Server</h3>
<div id="tuner-usb">
<p class="text-gray">Choose your desired <strong>COM port</strong><br>&nbsp;</p>
<%- include('_components', {
component: 'dropdown',
id: 'deviceList',
inputId: 'xdrd-comPort',
label: 'USB Device',
cssClass: '',
placeholder: 'Choose your USB device',
options: serialPorts.map(serialPort => ({
value: serialPort.path,
label: `${serialPort.path} - ${serialPort.friendlyName}`
}))
}) %>
</div>
<div id="tuner-wireless">
<p class="text-gray">If you are connecting your tuner <strong>wirelessly</strong>, enter the tuner IP. <br> If you use <strong>xdrd</strong>, use 127.0.0.1 as your IP.</p>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', label: 'xdrd IP address', id: 'xdrd-xdrdIp'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', label: 'xdrd port', id: 'xdrd-xdrdPort'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', label: 'xdrd password', id: 'xdrd-xdrdPassword', password: true}) %>
</div>
</div>
</div>
<div class="flex-container">
<div class="panel-50 p-bottom-20">
<h3>Startup</h3>
<h4>Startup volume</h4>
<div class="panel-75 auto" style="height: 48px;">
<input type="range" id="audio-startupVolume" min="0" max="1" step="0.01" value="1" aria-label="Startup Volume slider">
</div>
<h4 class="top-10 text-gray" id="volume-percentage-value"></h4>
<hr>
<h4 class="bottom-20">Default frequency</h4>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Default frequency for first client', id: 'enableDefaultFreq'}) %><br>
<%- include('_components', {component: 'text', cssClass: 'w-100', placeholder: '87.5', label: 'Default frequency', id: 'defaultFreq'}) %>
</div>
<div class="panel-50 p-bottom-20">
<h3>Miscellaneous</h3>
<div class="flex-container">
<div class="panel-50 no-bg">
<h4>Bandwidth switch</h4>
<p>Bandwidth switch allows the user to set the bandwidth manually.</p>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Bandwidth switch', id: 'bwSwitch'}) %><br>
</div>
<div class="panel-50 no-bg">
<h4>Automatic shutdown</h4>
<p>Toggling this option will put the tuner to sleep when no clients are connected.</p>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Auto-shutdown', id: 'autoShutdown'}) %><br>
</div>
</div>
</div>
</div>
</div>
<div class="panel-full m-0 tab-content no-bg" id="plugins-tab" role="tabpanel">
<h2>Plugins</h2>
<div class="panel-100 p-bottom-20">
<h3>Plugin list</h3>
<p>Any compatible <strong>.js</strong> plugin, which is in the "plugins" folder, will be listed here.<br>
Click on the individual plugins to enable/disable them.</p>
<select id="plugins" class="multiselect" multiple>
<% plugins.forEach(function(plugin) { %>
<option data-name="<%= plugin.frontEndPath %>" title="<%= plugin.name %> by <%= plugin.author %> [v<%= plugin.version %>]">
<%= plugin.name %> by <%= plugin.author %> [v<%= plugin.version %>]
</option>
<% }); %>
</select><br><br>
<a href="https://github.com/NoobishSVK/fm-dx-webserver/wiki/Plugin-List" target="_blank">Download new plugins here!</a>
</div>
<div class="panel-100 p-bottom-20">
<h3>Plugin settings</h3>
<div id="plugin-settings">No plugin settings are available.</div>
</div>
</div>
<div class="panel-full m-0 tab-content no-bg" id="identification" role="tabpanel">
<h2>Identification & Map</h2>
<div class="flex-container">
<div class="panel-50 p-bottom-20">
<h3>Basic info</h3>
<p>Set your tuner name and description here.<br>This info will be visible to anyone who tunes in. </p>
<div class="panel-full no-bg" style="padding-left: 20px; padding-right: 20px;">
<label for="identification-tunerName" style="width: 100%;max-width: 768px; margin:auto;">Webserver name:</label>
<input style="width: 100%; max-width: 768px;" class="input-text br-15" type="text" name="identification-tunerName" id="identification-tunerName" placeholder="Fill your server name here." maxlength="32">
<br>
<label for="identification-tunerDesc" style="width: 100%;max-width: 768px; margin: auto;">Webserver description:</label>
<textarea id="identification-tunerDesc" class="br-15" name="webserver-desc" placeholder="Fill the server description here. You can put useful info here such as your antenna setup. You can use simple markdown." maxlength="255"></textarea>
</div>
</div>
<div class="panel-50">
<h3>Online map</h3>
<p>If your location information is filled,<br>you can add your tuner to a public list.</p>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Broadcast to map', id: 'identification-broadcastTuner'}) %><br>
<%- include('_components', {component: 'text', cssClass: 'br-15', placeholder: 'Your e-mail or Discord...', label: 'Owner contact', id: 'identification-contact'}) %>
<%- include('_components', {component: 'text', cssClass: 'br-15', label: 'Broadcast address (if using a proxy)', id: 'identification-proxyIp'}) %>
<p>Check your tuner at <strong><a href="https://servers.fmdx.org" target="_blank" class="color-4">servers.fmdx.org</a></strong>.</p>
<p class="text-small text-gray">By activating the <strong>Broadcast to map</strong> option,<br>you agree to the <a href="https://fmdx.org/projects/webserver.php#rules" target="_blank">Terms of Service</a>.</p>
</div>
</div>
<div class="panel-100">
<h3>Location</h3>
<p class="text-gray">Location info is useful for automatic identification of stations using RDS.</p>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Latitude', id: 'identification-lat'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Longitude', id: 'identification-lon'}) %>
<div id="map"></div>
<br>
</div>
</div>
<div class="panel-full m-0 tab-content no-bg" id="users" role="tabpanel">
<h2>User management</h2>
<div class="panel-100">
<h3>Chat options</h3>
<%- include('_components', {component: 'checkbox', cssClass: '', label: 'Chat', id: 'webserver-chatEnabled'}) %>
</div>
<div class="panel-100 p-bottom-20">
<h3>Banlist</h3>
<p>If you have users that don't behave on your server, you can choose to ban them by their IP address.<br>
<span class="text-gray">You can see their IP address by hovering over their nickname. One IP per row.</span></p>
<table class="table-big">
<thead>
<tr>
<th>IP Address</th>
<th>Location</th>
<th>Ban date</th>
<th>Reason</th>
<th class="color-5"></th>
</tr>
</thead>
<tbody>
<tr>
<td><%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: 'IP address', label: '', id: 'banlist-add-ip'}) %></td>
<td></td>
<td></td>
<td><%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: 'Ban reason (note)', label: '', id: 'banlist-add-reason'}) %></td>
<td class="color-5">
<a href="#" id="banlist-add-link"><i class="fa-solid fa-plus-circle banlist-add"></i></a>
</td>
</tr>
<% if (banlist.length > 0) { %>
<% banlist.forEach(bannedUser => { %>
<tr>
<% if (Array.isArray(bannedUser)) { %>
<!-- If it's an array, use its values -->
<td style="text-align: center !important;"><a href="https://dnschecker.org/ip-location.php?ip=<%= bannedUser[0] %>" target="_blank"><%= bannedUser[0] %></a></td>
<td><%= bannedUser[1] %></td>
<td class="text-bold"><%= new Date(parseInt(bannedUser[2])).toLocaleString() %></td> <!-- Assuming the ban date is a timestamp in seconds -->
<td><%= bannedUser[3] %></td>
<% } else { %>
<!-- If it's just an IP address without additional data, show it as is -->
<td style="text-align: center !important;"><a href="https://dnschecker.org/ip-location.php?ip=<%= bannedUser %>" target="_blank"><%= bannedUser %></a></td>
<td>Unknown</td>
<td class="text-bold">Unknown</td>
<td>Unknown</td>
<% } %>
<td><a href="#" class="banlist-remove"><i class="fa-solid fa-lock-open text-gray"></i></a></td>
</tr>
<% }); %>
<% } else { %>
<tr>
<td colspan="5" style="text-align: center">The banlist is empty.</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
<div class="panel-full m-0 tab-content no-bg" id="extras" role="tabpanel">
<h2>Extras</h2>
<div class="panel-100 p-bottom-20">
<h3>FMLIST Integration</h3>
<p>FMLIST integration allows you to get potential DXes logged on the <a href="http://fmlist.org/fm_logmap.php?hours=900" target="_blank" class="text-bold color-4">FMLIST Visual Logbook</a>.<br>
Your server also needs to have a valid UUID, which is obtained by registering on maps in the <strong>Identification & Map</strong> tab.</p>
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'FMLIST integration', id: 'extras-fmlistIntegration'}) %><br>
<p>If you don't feel comfortable with the general public logging on your server, you can make this feature available only for people with a password</p>
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Admin-only logging', id: 'extras-fmlistAdminOnly'}) %><br>
<p>You can also fill in your OMID from FMLIST.org, if you want the logs to be saved to your account.</p>
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '', label: 'OMID', id: 'extras-fmlistOmid'}) %>
</div>
<div class="panel-100 p-bottom-20">
<h3>Tunnel</h3>
<p>When you become an <a href="https://buymeacoffee.com/fmdx" target="_blank"><strong>FMDX.org supporter</strong></a>, you can host your webserver without the need of a public IP address & port forwarding.<br>
When you become a supporter, you can message the Founders on Discord for your login details.</p>
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Enable tunnel', id: 'tunnel-enabled'}) %><br>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Username', id: 'tunnel-username'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-250 br-15', password: true, placeholder: '', label: 'Token', id: 'tunnel-token'}) %>
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '', label: 'Subdomain name', id: 'tunnel-subdomain'}) %>.fmtuner.org
<p>Enabling low latency mode may provide better experience, however it will also use more bandwidth.</p>
<%- include('_components', {component: 'checkbox', cssClass: 'm-right-10', label: 'Low latency mode', id: 'tunnel-lowLatencyMode'}) %><br>
</div>
</div>
</div>
</div>
</div>
<script src="js/init.js"></script>
<script src="js/toast.js"></script>
<script src="js/settings.js"></script>
<script src="js/dropdown.js"></script>
<script src="js/setup.js"></script>
<script src="js/confighandler.js"></script>
<% enabledPlugins?.forEach(function(plugin) { %>
<script src="js/plugins/<%= plugin %>"></script>
<% }); %>
</body>
</html>