mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2025-10-05 16:26:50 +08:00

Implemented a dark mode feature for the website, including a toggle button in the navigation bar that allows users to switch between light and dark themes. To support this feature, centralized common CSS styles (such as body, table, and button stylings) into main.js to ensure consistent application across all HTML pages. This change improves user experience by providing a visually comfortable alternative for low-light environments and centralizes styling rules for easier maintenance. - Added dark mode styles for body, table, buttons, and navigation elements in main.js. - Introduced a toggle mechanism in the navigation bar to switch between light and dark modes. - Utilized JavaScript to detect system theme preference (`prefers-color-scheme`) and persist user's theme choice using localStorage. - Removed duplicate and scattered CSS rules from individual HTML files (add.html, index.html, links.html, log.html) and centralized them in main.js to reduce redundancy and facilitate easier updates in the future. This update enhances accessibility and user preference compliance by allowing users to select their desired theme while simplifying CSS management across the website.
309 lines
9.8 KiB
HTML
309 lines
9.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>Add Stream</title>
|
|
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1">
|
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
html, body {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.module {
|
|
display: none;
|
|
padding: 10px;
|
|
}
|
|
|
|
|
|
table tbody td {
|
|
font-size: 13px;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<script src="main.js"></script>
|
|
<script>
|
|
function drawTable(table, data) {
|
|
const cols = ['id', 'name', 'info', 'url', 'location'];
|
|
const th = (row) => cols.reduce((html, k) => k in row ? `${html}<th>${k}</th>` : html, '<tr>') + '</tr>';
|
|
const td = (row) => cols.reduce((html, k) => k in row ? `${html}<td>${row[k]}</td>` : html, '<tr>') + '</tr>';
|
|
|
|
const thead = th(data.sources[0]);
|
|
const tbody = data.sources.reduce((html, source) => `${html}${td(source)}`, '');
|
|
|
|
table.innerHTML = `<thead>${thead}</thead><tbody>${tbody}</tbody>`;
|
|
}
|
|
|
|
async function getSources(tableID, url) {
|
|
const table = document.getElementById(tableID);
|
|
table.innerText = 'loading...';
|
|
|
|
const r = typeof url === 'string' ? await fetch(url, {cache: 'no-cache'}) : url;
|
|
if (!r.ok) {
|
|
table.innerText = await r.text();
|
|
return;
|
|
}
|
|
|
|
drawTable(table, await r.json());
|
|
}
|
|
</script>
|
|
|
|
|
|
<button id="stream">Temporary stream</button>
|
|
<div class="module">
|
|
<form id="stream-form" style="padding: 10px">
|
|
<input type="text" name="name" placeholder="name">
|
|
<input type="text" name="src" placeholder="url">
|
|
<input type="submit" value="add">
|
|
</form>
|
|
</div>
|
|
<script>
|
|
document.getElementById('stream').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
});
|
|
|
|
document.getElementById('stream-form').addEventListener('submit', async ev => {
|
|
ev.preventDefault();
|
|
|
|
const url = new URL('api/streams', location.href);
|
|
url.searchParams.set('name', ev.target.elements['name'].value);
|
|
url.searchParams.set('src', ev.target.elements['src'].value);
|
|
|
|
const r = await fetch(url, {method: 'PUT'});
|
|
alert(r.ok ? 'OK' : 'ERROR: ' + await r.text());
|
|
});
|
|
</script>
|
|
|
|
|
|
<button id="homekit">Apple HomeKit</button>
|
|
<div class="module">
|
|
<form id="homekit-pair" style="margin-bottom: 10px">
|
|
<input type="text" name="id" placeholder="stream id" size="20">
|
|
<input type="text" name="url" placeholder="url" size="40">
|
|
<input type="text" name="pin" placeholder="pin" size="10">
|
|
<input type="submit" value="Pair">
|
|
</form>
|
|
<form id="homekit-unpair" style="margin-bottom: 10px">
|
|
<input type="text" name="id" placeholder="stream id" size="20">
|
|
<input type="submit" value="Unpair">
|
|
</form>
|
|
<table id="homekit-table"></table>
|
|
</div>
|
|
<script>
|
|
async function reloadHomeKit() {
|
|
await getSources('homekit-table', 'api/homekit');
|
|
|
|
const rows = document.querySelectorAll('#homekit-table tr');
|
|
rows.forEach((row, i) => {
|
|
let commands = '';
|
|
if (row.children[2].innerText.indexOf('status=1') > 0) {
|
|
commands += '<a href="#">pair</a>';
|
|
} else if (i > 0 && row.children[3].innerText) {
|
|
commands += '<a href="#">unpair</a>';
|
|
}
|
|
row.innerHTML += `<td>${commands}</td>`;
|
|
});
|
|
}
|
|
|
|
document.getElementById('homekit').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
await reloadHomeKit();
|
|
});
|
|
|
|
document.getElementById('homekit-table').addEventListener('click', ev => {
|
|
if (ev.target.innerText === 'pair') {
|
|
const form = document.querySelector('#homekit-pair');
|
|
const row = ev.target.closest('tr');
|
|
form.children[0].value = row.children[0].innerText;
|
|
form.children[1].value = row.children[2].innerText;
|
|
} else if (ev.target.innerText === 'unpair') {
|
|
const form = document.querySelector('#homekit-unpair');
|
|
const row = ev.target.closest('tr');
|
|
form.children[0].value = row.children[3].innerText;
|
|
}
|
|
});
|
|
|
|
document.getElementById('homekit-pair').addEventListener('submit', async ev => {
|
|
ev.preventDefault();
|
|
|
|
const body = new FormData(ev.target);
|
|
body.set('url', body.get('url') + '&pin=' + body.get('pin'));
|
|
body.delete('pin');
|
|
|
|
const r = await fetch('api/homekit', {method: 'POST', body: body});
|
|
alert(r.ok ? 'OK' : 'ERROR: ' + await r.text());
|
|
|
|
await reloadHomeKit();
|
|
});
|
|
|
|
document.getElementById('homekit-unpair').addEventListener('submit', async ev => {
|
|
ev.preventDefault();
|
|
const r = await fetch('api/homekit', {method: 'DELETE', body: new FormData(ev.target)});
|
|
alert(r.ok ? 'OK' : 'ERROR: ' + await r.text());
|
|
|
|
await reloadHomeKit();
|
|
});
|
|
</script>
|
|
|
|
|
|
<button id="dvrip">DVRIP</button>
|
|
<div class="module">
|
|
<table id="dvrip-table"></table>
|
|
</div>
|
|
<script>
|
|
document.getElementById('dvrip').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
await getSources('dvrip-table', 'api/dvrip');
|
|
});
|
|
</script>
|
|
|
|
|
|
<button id="devices">FFmpeg Devices (USB)</button>
|
|
<div class="module">
|
|
<table id="devices-table"></table>
|
|
</div>
|
|
<script>
|
|
document.getElementById('devices').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
await getSources('devices-table', 'api/ffmpeg/devices');
|
|
});
|
|
</script>
|
|
|
|
|
|
<button id="hardware">FFmpeg Hardware</button>
|
|
<div class="module">
|
|
<table id="hardware-table"></table>
|
|
</div>
|
|
<script>
|
|
document.getElementById('hardware').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
await getSources('hardware-table', 'api/ffmpeg/hardware');
|
|
});
|
|
</script>
|
|
|
|
|
|
<button id="nest">Google Nest</button>
|
|
<div class="module">
|
|
<form id="nest-form" style="margin-bottom: 10px">
|
|
<input type="text" name="client_id" placeholder="client_id">
|
|
<input type="text" name="client_secret" placeholder="client_secret">
|
|
<input type="text" name="refresh_token" placeholder="refresh_token">
|
|
<input type="text" name="project_id" placeholder="project_id">
|
|
<input type="submit" value="Login">
|
|
</form>
|
|
<table id="nest-table"></table>
|
|
</div>
|
|
<script>
|
|
document.getElementById('nest').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
});
|
|
|
|
document.getElementById('nest-form').addEventListener('submit', async ev => {
|
|
ev.preventDefault();
|
|
|
|
const query = new URLSearchParams(new FormData(ev.target));
|
|
const url = new URL('api/nest?' + query.toString(), location.href);
|
|
|
|
const r = await fetch(url, {cache: 'no-cache'});
|
|
await getSources('nest-table', r);
|
|
});
|
|
</script>
|
|
|
|
|
|
<button id="gopro">GoPro</button>
|
|
<div class="module">
|
|
<table id="gopro-table"></table>
|
|
</div>
|
|
<script>
|
|
document.getElementById('gopro').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
await getSources('gopro-table', 'api/gopro');
|
|
});
|
|
</script>
|
|
|
|
|
|
<button id="hass">Home Assistant</button>
|
|
<div class="module">
|
|
<table id="hass-table"></table>
|
|
</div>
|
|
<script>
|
|
document.getElementById('hass').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
await getSources('hass-table', 'api/hass');
|
|
});
|
|
</script>
|
|
|
|
|
|
<button id="onvif">ONVIF</button>
|
|
<div class="module">
|
|
<form id="onvif-form" style="padding: 10px">
|
|
<input type="text" name="src" placeholder="onvif://user:pass@192.168.1.123:80" size="50">
|
|
<input type="submit" value="test">
|
|
</form>
|
|
<table id="onvif-table"></table>
|
|
</div>
|
|
<script>
|
|
document.getElementById('onvif').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
await getSources('onvif-table', 'api/onvif');
|
|
});
|
|
|
|
document.getElementById('onvif-form').addEventListener('submit', async ev => {
|
|
ev.preventDefault();
|
|
|
|
const url = new URL('api/onvif', location.href);
|
|
url.searchParams.set('src', ev.target.elements['src'].value);
|
|
|
|
await getSources('onvif-table', url.toString());
|
|
});
|
|
</script>
|
|
|
|
|
|
<button id="roborock">Roborock</button>
|
|
<div class="module">
|
|
<form id="roborock-form" style="margin-bottom: 10px">
|
|
<input type="text" name="username" placeholder="username">
|
|
<input type="password" name="password" placeholder="password">
|
|
<input type="submit" value="Login">
|
|
</form>
|
|
<table id="roborock-table">
|
|
</table>
|
|
</div>
|
|
<script>
|
|
document.getElementById('roborock').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
await getSources('roborock-table', 'api/roborock');
|
|
});
|
|
|
|
document.getElementById('roborock-form').addEventListener('submit', async ev => {
|
|
ev.preventDefault();
|
|
const r = await fetch('api/roborock', {method: 'POST', body: new FormData(ev.target)});
|
|
await getSources('roborock-table', r);
|
|
});
|
|
</script>
|
|
|
|
|
|
<button id="webtorrent">WebTorrent Shares</button>
|
|
<div class="module">
|
|
<table id="webtorrent-table"></table>
|
|
</div>
|
|
<script>
|
|
document.getElementById('webtorrent').addEventListener('click', async ev => {
|
|
ev.target.nextElementSibling.style.display = 'block';
|
|
await getSources('webtorrent-table', 'api/webtorrent');
|
|
});
|
|
</script>
|
|
|
|
|
|
</body>
|
|
</html>
|