Feedback needed for a Music Player App

  1. Maybe making the URL less readable bu using some base64 coding/decoding strategy?
var encodedURL = "aHR0cHM6Ly9leGFtcGxlLmNvbS9zb25nLm1wMw=="; // Base64 encoded link
var decodedURL = atob(encodedURL); // Decodes the link
var audio = new Audio(decodedURL);
audio.play();

URL-MASKING or something in this direction.

  1. Or maybe stream it somehow. Once i was working on an own server → STREAMING was an option i think for such use-cases, not sure.

Without beeing sure, but maybe you could try to get this to work…

Streaming the Song Through a Custom Endpoint

In your Wix app, you can create a custom API endpoint using Wix HTTP Functions to serve the song dynamically. This means the song will be streamed from your server (or Wix’s backend) and the URL will not be exposed to the client.

Example:

  1. Create an HTTP Function that streams the audio from your server.

Backend Code (Velo HTTP Function):

import { ok, notFound } from 'wix-http-functions';

export function get_song(request) {
    const songPath = '/path/to/song.mp3';  // Location on Wix Media
    const songFile = wixMedia.getFileUrl(songPath);

    if (songFile) {
        return ok(songFile); // Send the song file URL to the client.
    } else {
        return notFound();
    }
}
  1. Frontend Code: In your Wix Block, request the song through this custom endpoint, and then play it.

Frontend Code:

$w.onReady(function () {
    fetch('/_functions/get_song')
        .then(response => response.text())
        .then(url => {
            const audio = new Audio(url);
            audio.play();
        })
        .catch(err => console.log('Error fetching song:', err));
});

Here, the song URL is abstracted through the HTTP function, and it’s not easily visible in the front-end code.

And maybe you want to use my generated VOLUME-KNOB (present) :laughing:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Volume Knob with Corrected Scale</title>
  <style>
    body {
      background: #111;
      color: #fff;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
    }

    .tick {
      position: absolute;
      width: 2px;
      height: 10px;
      background: #ccc;
      top: 60px;
      left: 50%;
      transform-origin: bottom center;
    }

    .tick-label {
      position: absolute;
      color: #aaa;
      font-size: 9px;
      transform: translate(-50%, -50%);
      pointer-events: none;
    }
  </style>
</head>
<body>
  <script>
    function createVolumeKnob({ initialVolume = 0.5, onChange = () => {} } = {}) {
      const container = document.createElement("div");
      const scale = document.createElement("div");
      const knob = document.createElement("div");
      const indicator = document.createElement("div");
      const shine = document.createElement("div");

      container.style.position = "relative";
      container.style.width = "140px";
      container.style.height = "140px";
      scale.style.position = "absolute";
      scale.style.top = "0";
      scale.style.left = "0";
      scale.style.width = "100%";
      scale.style.height = "100%";
      scale.style.zIndex = "1";

      knob.style.position = "absolute";
      knob.style.top = "20px";
      knob.style.left = "20px";
      knob.style.width = "100px";
      knob.style.height = "100px";
      knob.style.borderRadius = "50%";
      knob.style.background = `
        radial-gradient(circle at 30% 30%, rgba(255,255,255,0.3), transparent 60%),
        repeating-linear-gradient(90deg, #444 0px, #333 1px, #222 2px),
        linear-gradient(145deg, #666, #111)
      `;
      knob.style.backgroundBlendMode = "overlay";
      knob.style.border = "2px solid #888";
      knob.style.cursor = "pointer";
      knob.style.transition = "box-shadow 0.1s linear, background 0.3s ease";
      knob.style.boxShadow = `
        inset -3px -3px 8px rgba(255,255,255,0.15),
        inset 3px 3px 10px rgba(0,0,0,0.5),
        0 0 20px rgba(0,0,0,0.6)
      `;
      knob.style.zIndex = "2";

      Object.assign(indicator.style, {
        width: "4px",
        height: "40px",
        background: "grey",
        position: "absolute",
        top: "10px",
        left: "50%",
        transformOrigin: "bottom center",
        transform: "translateX(-50%) rotate(0deg)",
        borderRadius: "25%",
      });

      Object.assign(shine.style, {
        position: "absolute",
        top: "5px",
        left: "5px",
        width: "90px",
        height: "90px",
        borderRadius: "50%",
        background: "radial-gradient(circle at 30% 30%, rgba(255,255,255,0.2), transparent 60%)",
        pointerEvents: "none"
      });

      knob.appendChild(indicator);
      knob.appendChild(shine);
      container.appendChild(scale);
      container.appendChild(knob);

      // --- Generate 10 scale ticks and labels from 0% to 100%
      const ticks = 10;
      for (let i = 0; i <= ticks; i++) {
        let percent = i / ticks;
        let angle = percent * 270 - 135; // Distribute over 270 degrees

        const tick = document.createElement("div");
        tick.className = "tick";
        tick.style.transform = `rotate(${angle}deg) translateY(-50px)`;
        scale.appendChild(tick);

        const label = document.createElement("div");
        label.className = "tick-label";
        label.innerText = `${i * 10}%`;

        const radians = (angle - 90) * (Math.PI / 180);
        const radius = 72;
        const cx = 70 + radius * Math.cos(radians);
        const cy = 70 + radius * Math.sin(radians);
        label.style.left = `${cx}px`;
        label.style.top = `${cy}px`;

        scale.appendChild(label);
      }

      let volume = initialVolume;
      let angle = volumeToAngle(volume);
      updateKnob(angle);

      function volumeToAngle(v) {
        return v * 270 - 135;
      }

      function angleToVolume(a) {
        return Math.max(0, Math.min(1, (a + 135) / 270));
      }

      function getRGBFromVolume(vol) {
        let r = Math.min(255, Math.floor(510 * vol));
        let g = Math.min(255, Math.floor(510 * (1 - vol)));
        return `rgb(${r},${g},0)`;
      }

      function updateKnob(deg) {
        indicator.style.transform = `translateX(-50%) rotate(${deg}deg)`;
        volume = angleToVolume(deg);
        const glowColor = getRGBFromVolume(volume);
        knob.style.boxShadow = `
          0 0 20px ${glowColor},
          inset -3px -3px 8px rgba(255,255,255,0.15),
          inset 3px 3px 10px rgba(0,0,0,0.5),
          0 0 10px ${glowColor}
        `;
        onChange(volume);
      }

      // --- Interaction
      let isDragging = false;
      knob.addEventListener("mousedown", () => { isDragging = true; });
      document.addEventListener("mouseup", () => { isDragging = false; });
      document.addEventListener("mousemove", (e) => {
        if (!isDragging) return;
        const rect = knob.getBoundingClientRect();
        const x = e.clientX - rect.left - rect.width / 2;
        const y = e.clientY - rect.top - rect.height / 2;
        let deg = Math.atan2(y, x) * (180 / Math.PI);
        deg = Math.max(-135, Math.min(135, deg));
        angle = deg;
        updateKnob(deg);
      });

      knob.addEventListener("wheel", (e) => {
        e.preventDefault();
        const delta = -e.deltaY || e.wheelDelta;
        angle += (delta > 0 ? 10 : -10);
        angle = Math.max(-135, Math.min(135, angle));
        updateKnob(angle);
      });

      return {
        element: container,
        getVolume: () => volume,
        setVolume: (v) => {
          angle = volumeToAngle(v);
          updateKnob(angle);
        },
      };
    }

    // --- Example usage
    const audioElement = new Audio();
    audioElement.volume = 0.5;

    const knob = createVolumeKnob({
      initialVolume: 0.5,
      onChange: (v) => {
        console.log("Volume:", v.toFixed(2));
        audioElement.volume = v;
      }
    });

    document.body.appendChild(knob.element);
  </script>
</body>
</html>

I tried to code it as simple as possible and as self-enclosed as possible, so it is reusable.

Paste the code into JS-FIDDLE (HTML-Section), but i think you will know what and how to do…

And some other ideas…

  1. Sound-equalizer:
    a) Balance-regulation
    b) Bass-regulation
    c) Switching to Mono/Stereo/Doulby mode
    d) and so on, could be your further steps.

P.S.: You can use the mouse-scroll on the knob to set your desired volume-power.

And maybe you take a look here…

Take a look onto the desired features people are searching for, to make your player unique in it’s functionality, features and functions.

Good luck!

And do not forget to show me your end-result!