Source code:
<!DOCTYPE html>
<html>
<head>
<meta name="robots" content="noindex,nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="water.css">
<script src="chart.js"></script>
<script src="chartjs-plugin-annotation.min.js"></script>
<link rel="icon" type="image/png" href="../speed.png" />
<meta property="og:title" content="TheSauna Speedtest">
<meta property="og:description" content="TheSauna Speedtest is a simple download speed test.">
<meta property="og:image" content="https://the-sauna.icu/speed.png">
<meta property="og:url" content="https://the-sauna.icu/speed/">
<meta property="og:type" content="website">
<meta property="og:site_name" content="TheSauna Speedtest">
<meta property="og:locale" content="en_US">
<title>Sauna Speedtest</title>
<style>
:root {
--text-main: #BDBDC1;
--focus: #FF7800;
--border: #FF7800;
--text-bright: #FFFFF;
--code: #FF7800;
--background: #0F0F0F;
--background-alt: #181717;
--background-body: #1E1E20;
--links: #FF7B00;
}
#raw-equation,
#weighted-equation {
/* center horizontally */
display: flex;
justify-content: center;
/* resize font to fit on screen */
font-size: 0.8em;
}
#weight-explanation {
background-image: linear-gradient(45deg, #181717 25%, transparent 25%, transparent 75%, #181717 75%, #181717), linear-gradient(45deg, #181717 25%, transparent 25%, transparent 75%, #181717 75%, #181717);
background-size: 20px 20px !important;
background-position: 0 0, 10px 10px !important;
color: #BDBDC1;
border-radius: 5px;
padding: 10px;
}
#cookiebanner {
position: fixed;
bottom: 0;
right: 0;
margin: 10px;
padding: 10px;
background-color: #f6cb72;
border-radius: 5px;
color: #1E1E20;
z-index: 100;
}
</style>
</head>
<body>
<div class="container">
<span>
</span>
<div class="header">
<img src="../speed.png" alt="Speedtest" width="128" height="128">
<div id="titlez">
<h1>Sauna Speedtest</h1>
</div>
</div>
<noscript>
<p>This site requires JS to function</p>
<details>
<summary>Source code:</summary>
/s", "", $file);
echo "<pre>";
echo htmlspecialchars($file);
echo "</pre>";
?>
</details>
</noscript>
<div class="content">
<div class="speedtest" style="display: none;">
<button id="start-button" onclick="startProgress()">Start Speedtest</button>
<div id="whenuserclicks" style="display: none;">
<p><span id="tests">Test 0 of 20 complete</span></p>
<p><span id="download-speed"></span></p>
<p><span id="raw-dl"></span></span>​<span id="weighted-dl">​</span></p>
<p><span id="ping"></span></p>
<canvas id="pingchart"></canvas>
<canvas id="chart"></canvas>
<p><span id="rawdata"></span></p>
<div id="weight-explanation">
<p>
I'd like to mention that this is not supposed to be a max ISP speed test <br>
but rather a a <i>- 'real life' -</i> estimate of the speed you should get.
<br><i>* This is the weighted average speed of all the tests.</i>
</p>
</div>
<p><span id="equation" style="display: none;"></span></p>
<br>
<p><span id="raw-equation" style="display: none;">"</span></p>
<p><span id="weighted-equation" style="display: none;"></span></p>
<script>
// a button to get the equations to clipboard (copies the contents of equation, raw-equation, and weighted-equation)
var copyButton = document.createElement("button");
copyButton.innerHTML = "Copy equations to clipboard";
copyButton.onclick = function() {
var equation = document.getElementById("equation").innerText;
var rawEquation = document.getElementById("raw-equation").innerText;
var weightedEquation = document.getElementById("weighted-equation").innerText;
var text = equation + " " + rawEquation + " " + weightedEquation;
navigator.clipboard.writeText(text);
}
document.getElementById("tests").addEventListener("DOMSubtreeModified", function() {
if (document.getElementById("tests").innerText == "Test 20 of 20 complete") {
var center = document.createElement("center");
center.appendChild(copyButton);
document.getElementById("whenuserclicks").appendChild(center);
}
});
</script>
</div>
<details>
<summary>Last 5 tests</summary>
<div id="last5"></div>
</details>
<details>
<summary>IP + Headers</summary>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
</details>
</div>
</div>
<!-- cookie banner div -->
<!-- <div class="cookiebanner" id="cookiebanner">
<p>The-Sauna uses cookies to improve your experience. </p>
<p>By using this site, you agree to our use of cookies.</p>
<pre>If you want to learn how to clear cookies on <span id="dynid"></span> click <a href="https://duckduckgo.com/?q=how+to+clear+cookies">here</a></pre>
<p>Read more about how we use cookies in our <a href="https://cloud.the-sauna.icu/notice.html">privacy notice</a>.</p>
<button onclick="cookiebanner()">I understand</button>
</div> -->
<br>
<h5> a work in progress project by <a href="https://the-sauna.icu/">TheSauna</h5>
<br>
<script>
function updatelast5() {
var table = document.getElementById("last5table");
if (table == null) {
document.getElementById("last5").innerHTML = "<h3>Last 5 results</h3>";
var table = document.createElement("table");
table.setAttribute("id", "last5table");
var tr = table.insertRow(-1);
var th = document.createElement("th");
th.innerHTML = "Test";
// speed
var th2 = document.createElement("th");
th2.innerHTML = "Speed";
tr.appendChild(th);
tr.appendChild(th2);
last5 = [];
// parse last5 from localstorage
var last5str = localStorage.getItem("last5");
console.log("last5str: " + last5str);
// if there are more than 5 tests in localstorage then remove the oldest one
if (last5str != null) {
last5 = JSON.parse(last5str);
if (last5.length > 5) {
last5.shift();
// update localstorage
localStorage.setItem("last5", JSON.stringify(last5));
console.log("removed oldest test");
}
}
if (last5str != null) {
last5 = JSON.parse(last5str);
} else {
// we return "no tests yet" if there are no tests
document.getElementById("last5").innerHTML = "<h3>No tests yet</h3>";
return;
}
for (var i = 0; i < last5.length; i++) {
tr = table.insertRow(-1);
var tabCell = tr.insertCell(-1);
tabCell.innerHTML = "Test #" + (i + 1);
var tabCell2 = tr.insertCell(-1);
tabCell2.innerHTML = last5[i];
}
var divContainer = document.getElementById("last5");
divContainer.innerHTML = "";
divContainer.appendChild(table);
} else {
last5 = [];
// parse last5 from localstorage
var last5str = localStorage.getItem("last5");
if (last5str != null) {
last5 = JSON.parse(last5str);
}
for (var i = 0; i < last5.length; i++) {
//var tabCell = table.rows[i + 1].cells[1];
//tabCell2.innerHTML = last5[i].toFixed(2) + " Mbps";
tabCell.innerHTML = last5[i] + " ~Mbps";
}
}
}
window.onload = function() {
// set speedtest visible
document.getElementsByClassName("speedtest")[0].style.display = "block";
// get our browsers name (chrome, firefox, etc)
var browser = navigator.userAgent.split(' ')[0];
// replace dynid with the cleaned up browser name
//document.getElementById("dynid").innerHTML = browser;
// NOT USED AON
}
try {
updatelast5();
console.log("Last 5 tests drawn.");
} catch (err) {
console.log("error updating last 5: " + err + " [Last5.localstorage probably just does not exist]");
}
</script>
</body>
<script>
var ctx = document.getElementById('chart').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Speed in Mbps',
data: null,
backgroundColor: [
'rgba(255, 99, 132, 1)',
],
borderColor: [
'rgba(255, 99, 132, 1)',
],
borderWidth: 1,
fill: true,
lineTension: 0.4,
pointRadius: 2,
pointHitRadius: 4,
pointHoverRadius: 7,
pointHoverBackgroundColor: 'rgba(255, 99, 132, 1)',
pointHoverBorderColor: 'rgba(255, 99, 132, 1)',
pointHoverBorderWidth: 4,
pointBackgroundColor: 'rgba(255, 99, 132, 1)',
pointBorderColor: 'rgba(180, 60, 100, 1)',
pointBorderWidth: 0.5,
}]
},
options: {
scales: {
y: {
beginAtZero: false
}
},
animation: {
duration: 3000,
easing: 'easeOutQuart'
},
elements: {
line: {
tension: 0.3,
}
},
plugins: {
legend: {
display: false
},
title: {
display: true,
text: 'Speed in Mbps'
}
}
}
});
var pingctx = document.getElementById('pingchart').getContext('2d');
var pingchart = new Chart(pingctx, {
type: 'line',
data: {
datasets: [{
label: 'Ping in ms',
data: null,
backgroundColor: [
'rgba(126, 152, 73)',
],
borderColor: [
'rgba(126, 152, 73))',
],
borderWidth: 1,
fill: true,
lineTension: 0.4,
pointRadius: 2,
pointHitRadius: 4,
pointHoverRadius: 7,
pointHoverBackgroundColor: 'rgba(126, 152, 73)',
pointHoverBorderColor: 'rgba(126, 152, 73)',
pointHoverBorderWidth: 4,
pointBackgroundColor: 'rgba(126, 152, 73)',
pointBorderColor: 'rgba(80, 100, 30, 1)',
pointBorderWidth: 0.5,
}]
},
options: {
scales: {
y: {
beginAtZero: false
}
},
animation: {
duration: 1000,
easing: 'easeOutQuart'
},
elements: {
line: {
tension: 0.6,
}
},
plugins: {
legend: {
display: false
},
title: {
display: true,
text: 'Ping in MS'
}
}
}
});
var done = 0;
var ping = 0;
var urls = ["https://the-sauna.icu/speed/5.mb", "https://the-sauna.icu/speed/10.mb", "https://the-sauna.icu/speed/20.mb"]
// temporarily set urlbase to
urlBase = "the-sauna.icu"
var pingurls = ["https://the-sauna.icu/speed/ping.php"]
var pingurl = pingurls[Math.floor(Math.random() * pingurls.length)];
var pingurlBase = pingurl.split("/")[2];
console.log(pingurlBase);
if (urlBase != pingurlBase) {
pingurl = pingurls.filter(function(item) {
return item !== pingurl
})[0];
}
function simplespeed() {
console.log("starting speedtest...");
var xhr = new XMLHttpRequest();
var startTime = new Date().getTime();
var delay = 2000;
var testCount = 20;
var testResults = [];
var testResult = 0;
var lastresulttook = 0;
var sum = 0;
console.log("testing " + urlBase);
document.getElementById("titlez").innerHTML = "<h1>Sauna Speedtest</h1> <h3>Testing from: <code>" + urlBase + "</code></h3>";
var test = function() {
// if testResult.length is below 10, we use urls[0] (1mb)
// if testResult.length is below 20, we use urls[1] (5mb)
// if testResult.length is below 30, we use urls[2] (10mb)
// print all urls
console.log(urls)
console.log(testResults.length)
if (testResults.length < 10) {
url = urls[0];
} else if (testResults.length < 17 && testResults.length > 10) {
url = urls[1];
} else if (testResults.length < 20 && testResults.length > 17) {
url = urls[2];
}
console.log("url: " + url);
xhr.open("GET", url + "?=" + Math.random(), true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('Access-Control-Allow-Origin', '*');
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("Pragma", "no-cache");
xhr.setRequestHeader("Expires", "0");
xhr.setRequestHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
xhr.setRequestHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
xhr.setRequestHeader("Access-Control-Allow-Credentials", "true");
xhr.open("GET", url + "?=" + Math.random(), true);
xhr.responseType = 'arraybuffer';
var startTime = new Date().getTime();
xhr.onload = function(e) {
var starttest = new Date().getTime();
var endTime = new Date().getTime();
var duration = (endTime - startTime) / 1000;
var speedMbps = (xhr.response.byteLength * 8 / 1024 / 1024 / duration).toFixed(2);
if (speedMbps > 1000) {
test();
}
console.log("speed: " + speedMbps + " Mbps");
testResults.push(speedMbps);
// get the chart we've made and update it
if (testResults.length < testCount) {
console.log("test " + testResults.length + " of " + testCount + " complete");
xhr = new XMLHttpRequest();
document.getElementById("tests").innerHTML = "Test " + testResults.length + " of " + testCount + " complete <div id=timeleft></div>";
var sum = 0;
for (var i = 0; i < testResults.length; i++) {
sum += parseInt(testResults[i], 10);
}
var avg = sum / testResults.length;
console.log("current average is: " + avg);
document.getElementById("raw-dl").innerHTML = "Current average is: " + avg.toFixed(2);
setTimeout(test, delay);
} else {
console.log("all tests complete");
document.getElementById("tests").style.display = "none";
var sum = 0;
for (var i = 0; i < testResults.length; i++) {
sum += parseInt(testResults[i], 10);
console.log("test " + i + " is: " + testResults[i]);
}
var avg = sum / testResults.length;
console.log("actual average is: " + avg);
if (avg > 1000) {
document.getElementById("raw-dl").innerHTML = "Average is: <h1>Holy shit.</h1>";
} else {
document.getElementById("raw-dl").innerHTML = "Average is: " + avg.toFixed(2);
}
// save this to a cookie and display last 5 tests averages on the page
var last5 = [];
if (localStorage.getItem("last5") === null) {
last5 = [];
} else {
last5 = JSON.parse(localStorage.getItem("last5"));
}
last5.push(avg);
localStorage.setItem("last5", JSON.stringify(last5));
console.log(last5);
var last5sum = 0;
// remove the first item in the array if it's over 5 items
for (var i = 0; i < last5.length; i++) {
last5sum += parseInt(last5[i], 10);
}
var last5avg = last5sum / last5.length;
console.log("last 5 average is: " + last5avg);
updatelast5();
done = 1;
// add rawdata table to page
var rawdata = "<table><tr><th>Test</th><th>Speed</th></tr>";
for (var i = 0; i < testResults.length; i++) {
rawdata += "<tr><td>" + (i + 1) + "</td><td>" + testResults[i] + "</td></tr>";
}
rawdata += "</table>";
document.getElementById("rawdata").innerHTML = rawdata;
// add last 5 avgs
var equation = "r = ";
var sum = 0;
for (var i = 0; i < testResults.length; i++) {
if (i == 0) {
sum += parseInt(testResults[i], 10);
equation += testResults[i];
} else {
sum += parseInt(testResults[i], 10);
equation += " + " + testResults[i];
}
}
var avg = sum / testResults.length;
equation += " / " + testResults.length + " = " + avg;
document.getElementById("raw-equation").innerHTML = "<pre>" + equation + "</pre>";
document.getElementById("download-speed").style.display = "none";
}
var ctx = document.getElementById('chart').getContext('2d');
var myChart = chart;
myChart.data.datasets[0].data = testResults;
myChart.data.labels.push("Test #" + testResults.length);
myChart.update();
// this is dum
// formula for weighted average:
// weightedAverage = (value1 * weight1 + value2 * weight2 + ... + valueN * weightN) / (weight1 + weight2 + ... + weightN)
// weight = 1 / (test number)
// value = speed
var weightedSum = 0;
var weightSum = 0;
for (var i = 0; i < testResults.length; i++) {
weightedSum += testResults[i] * (1 / (i + 1));
weightSum += 1 / (i + 1);
}
var weightedAvg = weightedSum / weightSum;
document.getElementById("weighted-dl").innerHTML = " <sup>(" + weightedAvg.toFixed(2) + ")* </sup> ~ Mbps";
var weightedEquation = "r = ";
var weightedSum = 0;
var weightSum = 0;
for (var i = 0; i < testResults.length; i++) {
if (i == 0) {
weightedSum += testResults[i] * (1 / (i + 1));
weightSum += 1 / (i + 1);
weightedEquation += "(" + testResults[i] + " * " + (1 / (i + 1)) + ")";
} else {
weightedSum += testResults[i] * (1 / (i + 1));
weightSum += 1 / (i + 1);
weightedEquation += " + (" + testResults[i] + " * " + (1 / (i + 1)) + ")";
}
}
var weightedAvg = weightedSum / weightSum;
weightedEquation += " / (" + weightSum + ") = " + weightedAvg;
document.getElementById("weighted-equation").innerHTML = "<pre>" + weightedEquation + "</pre>";
// this is dum
try {
var timeleft = duration * (testCount - testResults.length);
timeleft += 2; // compensation
var minutes = Math.floor(timeleft / 60);
var seconds = Math.floor(timeleft - minutes * 60);
if (minutes < 10) {
minutes = "0" + minutes;
}
if (seconds < 10) {
seconds = "0" + seconds;
}
document.getElementById("timeleft").innerHTML = "Estimated time left: " + minutes + ":" + seconds;
} catch (err) {
console.log("cant estimate: " + err)
}
};
xhr.send();
};
test();
}
pings = [];
ping_amount = 51;
pd = 100;
// super simple ping test in js in under 20 lines of code
function pingtest() {
var startTime = new Date().getTime();
var xhr = new XMLHttpRequest();
xhr.open("GET", pingurl, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('Access-Control-Allow-Origin', '*');
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("Pragma", "no-cache");
xhr.setRequestHeader("Expires", "0");
xhr.onload = function(e) {
var endTime = new Date().getTime();
var duration = (endTime - startTime);
pings.push(duration);
if (pings.length < ping_amount) {
// add this to the pingchart chart we made earlier and update it
console.log("ping " + pings.length + " of " + ping_amount + " complete");
setTimeout(pingtest, pd);
} else {
console.log("all pings complete");
var sum = 0;
for (var i = 0; i < pings.length; i++) {
sum += parseInt(pings[i], 10);
}
var avg = sum / pings.length;
console.log("actual average is: " + avg);
document.getElementById("ping").innerHTML = "Your ping is: " + avg.toFixed(2) + "~ ms";
}
var ctx = document.getElementById('pingchart').getContext('2d');
var myChart = pingchart;
myChart.data.datasets[0].data = pings;
// add a label to the beginning of the chart for this test number as "Ping #testnumber"
myChart.data.labels.push("Ping #" + pings.length);
myChart.update();
};
xhr.send();
}
function startProgress() {
pingtest();
document.getElementById('whenuserclicks').style.display = 'block';
document.getElementById('start-button').style.display = 'none';
document.getElementById('download-speed').innerHTML = "Testing";
var dots = window.setInterval(function() {
var wait = document.getElementById("download-speed");
// change the hue of the dots based on time so it looks like it's loading
var hue = Math.floor((new Date().getTime() / 100) % 360);
if (done) {
window.clearInterval(dots);
}
// change the dots to a loading animation
if (wait.innerHTML.length > 128) {
wait.innerHTML = "Testing";
} else {
wait.innerHTML += "<span id='dot' style='color: hsl(" + hue + ", 100%, 50%);'>.</span>";
}
}, 300);
// wait for pingtest to finish by checking if pings is under 9
var wait = window.setInterval(function() {
if (pings.length > 49) {
window.clearInterval(wait);
simplespeed();
}
}, 1000);
}
</script>
</html>