Killing Kick Latency

kick 레이턴시 줄이기

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         Killing Kick Latency
// @namespace    http://tampermonkey.net/
// @version      1.01
// @description  kick 레이턴시 줄이기
// @author       purirun
// @match        https://www.kick.com/*
// @match        https://kick.com/*
// @grant        none
// @run-at       document-idle
// @license MIT
// ==/UserScript==

(function () {
  const VIDEO_SEL = 'video';
  let delayText = null;
  let isCooling = false;
  let chaseInterval = null;

  function getControlBar() {
    const all = document.querySelectorAll('.z-controls');
    // absolute bottom-0 인 컨트롤바
    return [...all].find(el => el.classList.contains('bottom-0'));
  }

  function createSyncBtn() {
    if (document.getElementById('kick-tiny-sync')) return;

    const bar = getControlBar();
    if (!bar) return;

    // index 1 = 오른쪽 버튼 그룹
    const rightGroup = bar.children[1];
    if (!rightGroup) return;

    const syncBtn = document.createElement('div');
    syncBtn.id = 'kick-tiny-sync';
    syncBtn.title = '클릭하면 딜레이가 즉시 동기화됩니다.';
    syncBtn.style.cssText = [
      'display:inline-flex',
      'align-items:center',
      'gap:5px',
      'background:rgba(255,255,255,0.1)',
      'border:1px solid transparent',
      'border-radius:6px',
      'padding:3px 8px',
      'cursor:pointer',
      'user-select:none',
      'transition:all 0.2s',
      'font-family:monospace',
      'height:32px',
      'box-sizing:border-box',
      'flex-shrink:0',
    ].join(';');

    syncBtn.onmouseover = () => {
      syncBtn.style.background = 'rgba(255,255,255,0.2)';
      syncBtn.style.border     = '1px solid #53FC18';
    };
    syncBtn.onmouseout = () => {
      if (!isCooling) {
        syncBtn.style.background = 'rgba(255,255,255,0.1)';
        syncBtn.style.border     = '1px solid transparent';
      }
    };

    const icon = document.createElement('span');
    icon.innerText      = '⚡';
    icon.style.fontSize = '12px';

    delayText = document.createElement('span');
    delayText.innerText     = '-.-s';
    delayText.style.cssText = 'font-size:12px;font-weight:bold;color:#fff;line-height:1;white-space:nowrap;';

    syncBtn.appendChild(icon);
    syncBtn.appendChild(delayText);

    syncBtn.onclick = (e) => {
      e.preventDefault();
      e.stopPropagation();
      if (isCooling) return;

      const vid = document.querySelector(VIDEO_SEL);
      if (!vid) return;

      // 버퍼 끝으로 점프
      if (vid.buffered.length > 0) {
        vid.currentTime = vid.buffered.end(vid.buffered.length - 1) - 0.3;
      } else {
        vid.currentTime = vid.duration;
      }

      // 딜레이 남아있으면 1.3배속으로 추격
      if (chaseInterval) clearInterval(chaseInterval);
      chaseInterval = setInterval(() => {
        const v = document.querySelector(VIDEO_SEL);
        if (!v) { clearInterval(chaseInterval); return; }
        const delay = v.buffered.length > 0
          ? v.buffered.end(v.buffered.length - 1) - v.currentTime
          : 0;
        if (delay > 1) {
          v.playbackRate = 1.3;
        } else {
          v.playbackRate = 1.0;
          clearInterval(chaseInterval);
        }
      }, 200);

      isCooling = true;
      delayText.innerText   = 'OK!';
      delayText.style.color = '#53FC18';
      syncBtn.style.border  = '1px solid #53FC18';

      setTimeout(() => {
        isCooling = false;
        syncBtn.style.border     = '1px solid transparent';
        syncBtn.style.background = 'rgba(255,255,255,0.1)';
      }, 1500);
    };

    // 오른쪽 그룹의 첫 번째 버튼 앞에 삽입
    const firstBtn = rightGroup.querySelector('button');
    if (firstBtn) {
      rightGroup.insertBefore(syncBtn, firstBtn);
    } else {
      rightGroup.appendChild(syncBtn);
    }
  }

  // 딜레이 수치 갱신
  setInterval(() => {
    if (!document.getElementById('kick-tiny-sync')) {
      delayText = null;
      createSyncBtn();
      return;
    }
    if (!delayText || isCooling) return;

    const vid = document.querySelector(VIDEO_SEL);
    if (!vid || vid.paused) {
      delayText.innerText   = '---';
      delayText.style.color = '#888';
      return;
    }

    if (vid.buffered.length > 0) {
      const delay = Math.max(0, vid.buffered.end(vid.buffered.length - 1) - vid.currentTime);
      delayText.innerText   = delay.toFixed(1) + 's';
      delayText.style.color = delay < 1.5 ? '#53FC18' : delay < 3 ? '#FFD700' : '#FF4D4D';
    } else {
      delayText.innerText   = '???';
      delayText.style.color = '#888';
    }
  }, 500);

  // 초기 생성 - 컨트롤바는 hover시에만 나타나므로 계속 재시도
  let attempts = 0;
  const initInterval = setInterval(() => {
    if (document.body) {
      createSyncBtn();
      if (document.getElementById('kick-tiny-sync')) clearInterval(initInterval);
    }
    if (++attempts >= 40) clearInterval(initInterval);
  }, 500);
})();