Killing Kick Latency

kick 레이턴시 줄이기

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

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

(I already have a user script manager, let me install it!)

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.

(I already have a user style manager, let me install it!)

// ==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);
})();