~patrickhaussmann/bpm.app.5ls.de

d1efdb0cb5a104d1da7b63b5963887944ff03be4 — patrickhaussmann 6 months ago
first working version
2 files changed, 148 insertions(+), 0 deletions(-)

A .build.yml
A index.html
A  => .build.yml +14 -0
@@ 1,14 @@
image: alpine/latest
packages:
  - npm
secrets:
  - 3ccf561f-8f40-49dd-9d3f-e2a9e69b5219
environment:
  site: bpm.app.5ls.de
tasks:
  - install: |
      sudo npm install --loglevel=error --global surge

  - publish: |
      . ~/.surgesecrets
      surge $site/ $(echo https://$site | sed -e "s/\./-/g" -e "1 s/$/\.surge\.sh/")

A  => index.html +134 -0
@@ 1,134 @@
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <meta name="apple-mobile-web-app-title" content="BPM" />
    <meta name="msapplication-TileColor" content="#000" />
    <meta name="theme-color" content="#000" />
    <meta name="Description" content="BPM finder" />
    <title>BPM</title>
    <style>
      html,
      body {
        height: 100%;
        margin: 0px;
        padding: 0px;
        touch-action: manipulation;
        -webkit-touch-callout: none;
        /* iOS Safari */
        -webkit-user-select: none;
        /* Safari */
        -khtml-user-select: none;
        /* Konqueror HTML */
        -moz-user-select: none;
        /* Old versions of Firefox */
        -ms-user-select: none;
        /* Internet Explorer/Edge */
        user-select: none;
        /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */
      }

      body {
        background-color: #000;
        position: relative;
        color: #fff;
        fill: #fff;
        text-align: center;
        font-family: monospace, monospace;
      }

      .main {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
      }

      .main > div {
        display: flex;
        flex-direction: column;
      }

      span#bpm {
        font-size: 3.5rem;
        font-weight: 500;
        line-height: 1.2;
      }
    </style>
  </head>

  <body>
    <div class="main">
      <div>
        <h1><span id="bpm">-</span> <span>BPM</span></h1>
      </div>
    </div>

    <script>
      const bpm_div = document.getElementById("bpm");
      const diffs = [];

      function filterOutliers(array) {
        // https://stackoverflow.com/a/20811670
        const values = array.concat();
        values.sort();

        const q1 = values[Math.floor(values.length / 4)];
        const q3 = values[Math.ceil(values.length * (3 / 4))];
        const iqr = q3 - q1; // inter-quartile range

        const maxValue = q3 + iqr * 1.5;
        const minValue = q1 - iqr * 1.5;
        return array.filter((x) => x <= maxValue && x >= minValue);
      }

      function calcBPM() {
        // limit to last 10 clicks
        const lastDiffs = diffs.slice(-10);
        const filteredDiffs = filterOutliers(lastDiffs);
        if (!filteredDiffs) {
          return;
        }

        const avg =
          filteredDiffs.reduce((a, b) => a + b, 0) / filteredDiffs.length;
        const bpm = 60 / avg;

        return Math.round(bpm);
      }

      function displayBPM() {
        const bpm = calcBPM();
        if (!bpm || Number.isNaN(bpm) || bpm == Infinity || bpm == 0) {
          bpm_div.innerText = "-";
        } else {
          bpm_div.innerText = bpm;
        }
      }

      let lastClick;
      document.addEventListener("click", function (e) {
        const now = new Date().getTime() / 1000;

        if (now - lastClick > 10) {
          diffs.length = 0;
          lastClick = null;
        }

        if (lastClick) {
          const diff = now - lastClick;
          diffs.push(diff);
        }

        displayBPM();
        lastClick = now;
      });
    </script>
  </body>
</html>