crappy logviewer is better than no logviewer I guess

This commit is contained in:
Ash Keel 2023-11-04 14:27:25 +01:00
parent a677b3755f
commit 87073a2ce0
No known key found for this signature in database
GPG Key ID: 53A9E9A6035DD109
2 changed files with 127 additions and 175 deletions

View File

@ -1,175 +0,0 @@
{{ define "main" }}
<main class="landing">
<section class="hero maxw">
<div class="hero-copy">
<h1>The streaming companion for power users</h1>
<p>
strimertül is a free and open source tool to add to your Twitch
streams for creating powerful overlays and power-up the viewer
interaction!
</p>
<div id="download">
<noscript>
<a href="https://github.com/strimertul/strimertul/releases/latest">
Check out the latest version on GitHub
</a>
</noscript>
<div class="hidden" id="download-template">
<h2>
Latest stable release:
<a href="https://github.com/strimertul/strimertul/releases/latest"
><span data-field="name"></span> (<time data-field="date"></time
>)</a
>
</h2>
<div class="download-list"><b>Downloads:</b></div>
</div>
</div>
<script>
const platforms = [
{
filter: ".exe",
name: "Windows 64-bit",
},
{
filter: ".dmg",
name: "macOS Universal",
},
{
filter: "linux",
name: "Linux AMD64",
},
];
(async function () {
const releaseblock = document.getElementById("download-template");
const latest = await (
await fetch(
"https://api.github.com/repos/strimertul/strimertul/releases/latest"
)
).json();
// Poor's man angularjs
const data = {
...latest,
date: new Date(latest.published_at).toLocaleDateString(),
};
releaseblock.querySelectorAll("*[data-field]").forEach((el) => {
const { field } = el.dataset;
if (field in data) {
el.innerHTML = data[field];
}
});
// Make those links
const downloadLinks = releaseblock.querySelector(".download-list");
latest.assets
.map((asset) => [
platforms.findIndex(({ filter }) =>
asset.name.includes(filter)
),
asset.browser_download_url,
])
.filter(([index]) => index >= 0)
.sort(([a], [b]) => a - b)
.forEach(([index, url]) => {
const link = document.createElement("a");
link.classList.add("download-link");
link.href = url;
link.appendChild(
document.createTextNode(platforms[index].name)
);
downloadLinks.appendChild(link);
});
releaseblock.classList.remove("hidden");
})();
</script>
</div>
</section>
<section class="features">
<article>
<div class="maxw">
<div class="flex">
<div>
<header>One API for everything</header>
<p>
Build overlays and tooling with easy access to Twitch alerts,
chat messages and more through a single websocket interface. The
API strives for simplicity with a
<a
href="https://github.com/strimertul/kilovolt/blob/main/PROTOCOL.md"
>documented protocol</a
>, but there are also officially supported bindings for popular
languages such as
<a href="https://github.com/strimertul/kilovolt-client-ts"
>Typescript</a
>,
<a href="https://github.com/strimertul/kilovolt-client-go"
>Go</a
>
and
<a href="https://github.com/strimertul/kilovolt-client-python"
>Python</a
>.
</p>
</div>
{{ $image := resources.Get "landing/websocket.svg" }}
<img
class="landing-point"
src="{{ $image.RelPermalink }}"
style="width: 200px; padding-left: 20px"
/>
</div>
</div>
</article>
<article>
<div class="maxw">
<div class="flex">
{{ $image := resources.Get "landing/rewards.png" }}
<img class="landing-point" src="{{ $image.RelPermalink }}" />
<div>
<header>No Twitch Affiliate?</header>
<p>
The built-in loyalty system lets regular viewers accrue points,
claim rewards and contribute towards community goals.
</p>
</div>
</div>
</div>
</article>
<article>
<div class="maxw">
<div class="flex">
<div class="flex-copy">
<header>Keep total control of your tech</header>
<p>
Strimertül runs completely in your computer and has no remote
components.
</p>
</div>
{{ $image := resources.Get "landing/downloads.png" }}
<img class="landing-point" src="{{ $image.RelPermalink }}" />
</div>
</div>
</article>
<article>
<div class="maxw">
<div class="flex">
{{ $image := resources.Get "landing/AGPLv3_Logo.svg" }}
<img class="landing-point" src="{{ $image.RelPermalink }}" />
<div>
<header>Free and won't turn evil</header>
<p>
strimertül is free and open source under the
<a
href="https://github.com/strimertul/strimertul/blob/master/LICENSE"
>AGPLv3</a
>, a strong
<a href="https://en.wikipedia.org/wiki/Copyleft"
>copyleft license</a
>, meaning we couldn't close it down even if we wanted!
</p>
</div>
</div>
</div>
</article>
</section>
</main>
{{ end }}

127
static/logviewer.html Normal file
View File

@ -0,0 +1,127 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Online log viewer</title>
<style>
@import url("https://rsms.me/inter/inter.css");
@import url("https://iosevka-webfonts.github.io/iosevka/iosevka.css");
:root {
--site-bg: #171717;
--white: #ededed;
background-color: var(--site-bg);
color: var(--white);
font-family: "Inter", "Gill Sans", "Gill Sans MT", "Segoe UI",
sans-serif;
}
html,
body {
margin: 0;
}
main {
display: flex;
}
#starting {
height: 100vh;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
code {
display: inline-block;
font-family: "Iosevka", monospace;
background-color: #222;
border-radius: 3px;
padding: 3px 6px;
}
.hidden {
display: none !important;
}
</style>
</head>
<body>
<main id="app">
<section id="starting">
<h1>Online log viewer</h1>
<p>
Drag a <code>strimertul.log</code> in this window to view it (or click
anywhere to open a file dialog).<br />
The contents will not be uploaded anywhere, this webpage is fully
local.
</p>
</section>
<table id="logs" class="hidden">
<thead>
<tr>
<th>Level</th>
<th>Time</th>
<th>Caller</th>
<th>Message</th>
<th>Data</th>
</tr>
</thead>
<tbody></tbody>
</table>
</main>
<script>
// @ts-check
const mainEl = document.getElementById("app");
const startingEl = document.getElementById("starting");
const tableEl = document.getElementById("logs");
// Click handler (open file select)
startingEl?.addEventListener("click", (ev) => {
// Create temporary file input and click it
const fileSelect = document.createElement("input");
fileSelect.type = "file";
fileSelect.accept = ".log";
fileSelect.addEventListener("change", (ev) => {
if (ev.target instanceof HTMLInputElement && ev.target.files) {
const file = ev.target.files[0];
startingEl.innerHTML = "Loading...";
if (file) {
const reader = new FileReader();
reader.addEventListener("load", (ev) => {
const logs =
ev.target?.result
?.toString()
.split("\n")
.map((line) => line.trim())
.filter((line) => line.length > 0)
.map((line) => {
return makeLog(JSON.parse(line));
}) || [];
tableEl?.querySelector("tbody")?.replaceChildren(...logs);
tableEl?.classList.remove("hidden");
startingEl.classList.add("hidden");
});
reader.readAsText(file);
}
}
});
fileSelect.click();
});
function makeLog(log) {
const tr = document.createElement("tr");
const { level, ts, caller, msg, ...data } = log;
tr.appendChild(makeCell(level));
tr.appendChild(makeCell(new Date(ts * 1000).toISOString()));
tr.appendChild(makeCell(caller));
tr.appendChild(makeCell(msg));
tr.appendChild(makeCell(JSON.stringify(data)));
return tr;
}
function makeCell(text) {
const td = document.createElement("td");
td.appendChild(document.createTextNode(text));
return td;
}
</script>
</body>
</html>