Kick Audio Maximizer

Boosts quiet sounds, compresses loud peaks.

// ==UserScript==
// @name        Kick Audio Maximizer
// @name:tr     Kick Ses Dengeleyici
// @description:tr  Sessiz sesleri yükseltir, yüksek sesleri bastırır.
// @description  Boosts quiet sounds, compresses loud peaks.
// @namespace    http://tampermonkey.net/
// @version      1.0
// @author       baris
// @match        *://*.kick.com/*
// @grant        none
// @license      GNU GPLv3
// ==/UserScript==


(() => {
  /* video bekle */
  const waitVideo = () => new Promise(res => {
    const id = setInterval(() => {
      const v = document.querySelector('video');
      if (v && v.readyState >= 2) { clearInterval(id); res(v); }
    }, 400);
  });

  /* UI: canvas */
  const makeCanvas = () => {
    const wrap = Object.assign(document.createElement('div'), {
      style:`position:fixed;bottom:20px;left:20px;z-index:9999;
             background:rgba(0,0,0,.8);padding:8px;border-radius:10px`
    });
    wrap.innerHTML = `
      <div style="color:#fff;font-family:monospace;margin-bottom:4px">
        🔊 Maximizer by Barış
      </div>`;
    const c = Object.assign(document.createElement('canvas'), {
      width:300,height:20,
      style:'background:#222;border-radius:6px'
    });
    wrap.appendChild(c); document.body.appendChild(wrap);
    return c.getContext('2d');
  };

  /* ana akış */
  (async () => {
    const video = await waitVideo();
    const ctx = new AudioContext();

    /* autoplay engeline takılırsa ilk tıkta devam */
    if (ctx.state === 'suspended') {
      const resume = () => { ctx.resume(); window.removeEventListener('click', resume); };
      window.addEventListener('click', resume);
    }

    const src = ctx.createMediaElementSource(video);

    /* efekt zinciri */
    const comp = ctx.createDynamicsCompressor();
    comp.threshold.value = -50;
    comp.knee.value      = 30;
    comp.ratio.value     = 20;
    comp.attack.value    = 0.002;
    comp.release.value   = 0.10;

    const gain = ctx.createGain();
    gain.gain.value = 2.5;          // boost

    const ana = ctx.createAnalyser();
    ana.fftSize = 512;
    const buf = new Uint8Array(ana.fftSize);

    src.connect(comp);
    comp.connect(gain);
    gain.connect(ana);
    ana.connect(ctx.destination);

    /* canvas çizim */
    const g = makeCanvas(), W = g.canvas.width, H = g.canvas.height;
    let smooth = 0, peak = 0, peakT = 0;

    const lerp = (a,b,f)=>a+(b-a)*f;

    const draw = () => {
      requestAnimationFrame(draw);

      ana.getByteTimeDomainData(buf);
      const rms = Math.sqrt(buf.reduce((s,v)=>s+((v-128)/128)**2,0)/buf.length);
      const level = Math.min(rms * gain.gain.value, 1);   // 0-1 çıkış
      smooth = lerp(smooth, level, 0.18);                 // yumuşatma

      const now = performance.now();
      if (smooth > peak || now - peakT > 2000) { peak = smooth; peakT = now; }
      if (now - peakT > 2000) peak = lerp(peak, smooth, 0.05); // düşür

      /* renk geçişi */
      const hue = lerp(220, 0, smooth);                   // mavi→kırmızı
      g.clearRect(0,0,W,H);
      g.fillStyle = `hsl(${hue} 80% 50%)`;
      g.fillRect(0,0, smooth*W, H);

      /* peak çizgisi */
      g.fillStyle = '#fff';
      g.fillRect(peak*W-1, 0, 2, H);
    };
    draw();
  })();
})();