TTK - Twitch To Kick: Multi Stream Auto Switcher

Elegantly switches between Twitch and Kick streams with advanced management features, custom styling, and improved performance

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         TTK - Twitch To Kick: Multi Stream Auto Switcher 
// @namespace    http://tampermonkey.net/
// @version      4.1.0
// @description  Elegantly switches between Twitch and Kick streams with advanced management features, custom styling, and improved performance
// @author       Original: TheWhaleCow, Enhanced: Claude
// @match        https://www.twitch.tv/*
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==

(function() {
  'use strict';

  // =================== CONFIGURATION ===================
  const CONFIG = {
    storageKey: 'ttk-streamer-pairs',
    collapsedKey: 'ttk-collapsed',
    settingsVisibleKey: 'ttk-settings-visible',
    currentModeKey: 'ttk-current-mode',
    autoSwitchKey: 'ttk-auto-switch',
    checkInterval: 2000,
    initDelay: 1500,
    theme: {
      primary: '#9146FF',      // Twitch Purple
      secondary: '#00B140',    // Kick Green
      dark: '#18181B',         // Dark background
      light: '#EFEFF1',        // Light text
      border: '#3A3A3D',       // Border color
      success: '#00B140',      // Success color
      error: '#F43B47',        // Error color
      highlight: '#772CE8',    // Highlight color
    }
  };

  // =================== DATA MANAGEMENT ===================
  const Storage = {
    get: (key, defaultValue = null) => {
      try {
        const data = localStorage.getItem(key);
        return data ? JSON.parse(data) : defaultValue;
      } catch (e) {
        console.error('TTK Storage error:', e);
        return defaultValue;
      }
    },

    set: (key, value) => {
      try {
        localStorage.setItem(key, JSON.stringify(value));
        return true;
      } catch (e) {
        console.error('TTK Storage error:', e);
        return false;
      }
    },

    getPairs: () => Storage.get(CONFIG.storageKey, []),
    savePairs: (pairs) => Storage.set(CONFIG.storageKey, pairs),

    isCollapsed: () => Storage.get(CONFIG.collapsedKey, false),
    setCollapsed: (state) => Storage.set(CONFIG.collapsedKey, state),

    isSettingsVisible: () => Storage.get(CONFIG.settingsVisibleKey, false),
    setSettingsVisible: (state) => Storage.set(CONFIG.settingsVisibleKey, state),

    getCurrentMode: () => Storage.get(CONFIG.currentModeKey, 'auto'),
    setCurrentMode: (mode) => Storage.set(CONFIG.currentModeKey, mode),

    isAutoSwitchEnabled: () => Storage.get(CONFIG.autoSwitchKey, true),
    setAutoSwitchEnabled: (state) => Storage.set(CONFIG.autoSwitchKey, state)
  };

  // =================== STREAM MANAGEMENT ===================
  const StreamManager = {
    getCurrentChannel: () => {
      const match = window.location.pathname.match(/^\/([a-zA-Z0-9_]+)$/);
      return match ? match[1].toLowerCase() : null;
    },

    getPairForCurrentChannel: () => {
      const currentChannel = StreamManager.getCurrentChannel();
      if (!currentChannel) return null;

      const pairs = Storage.getPairs();
      return pairs.find(p => p.twitch?.toLowerCase() === currentChannel);
    },

    isTwitchPlayerOffline: () => {
      // Multiple selectors for better reliability
      return !!(
        document.querySelector('[data-test-selector="offline-channel-video"]') ||
        document.querySelector('.channel-status-info [data-a-target="player-overlay-content-gate"]') ||
        Array.from(document.querySelectorAll('.channel-info-content')).some(el =>
          el.textContent.includes('offline') || el.textContent.includes('not available')
        )
      );
    },

    kickStreamURL: (channel) => `https://player.kick.com/${channel}?muted=false`,
    twitchStreamURL: (channel) => `https://player.twitch.tv/?channel=${channel}&parent=twitch.tv&muted=false`,

    replacePlayerWithStream: (url) => {
      const player = document.querySelector('.video-player__container');
      if (!player) return false;

      // Check if we already have our custom player
      const existingOverlay = document.getElementById('ttk-player-overlay');
      if (existingOverlay) {
        const existingIframe = existingOverlay.querySelector('iframe');
        if (existingIframe && existingIframe.src === url) return false;

        existingOverlay.innerHTML = '';
      } else {
        // Create overlay
        const overlay = document.createElement('div');
        overlay.id = 'ttk-player-overlay';
        overlay.style.cssText = `
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          z-index: 9999;
          background: #000;
        `;
        player.style.position = 'relative';
        player.appendChild(overlay);
      }

      // Try to pause/mute all video and audio elements in the original player
      const videoElements = player.querySelectorAll('video');
      videoElements.forEach(video => {
        if (video) {
          try {
            if (!video.paused) video.pause();
            video.muted = true;
            video.volume = 0;
            // Disconnect any event listeners if possible
            if (video.pause) video.pause = () => {};
            if (video.play) video.play = () => {};
          } catch (e) {
            console.error('Error pausing video:', e);
          }
        }
      });

      // Try to pause the player if it has a React instance
      try {
        const twitchPlayer = document.querySelector('[data-a-player-type="site"]');
        if (twitchPlayer && twitchPlayer._reactInstance && typeof twitchPlayer._reactInstance.pausePlayer === 'function') {
          twitchPlayer._reactInstance.pausePlayer();
        }
      } catch (e) {
        console.error('Error accessing Twitch player:', e);
      }

      // Create iframe in the overlay
      const iframe = document.createElement('iframe');
      iframe.src = url;
      iframe.style.cssText = 'height:100%; width:100%; border:none;';
      iframe.setAttribute('allowfullscreen', 'true');
      document.getElementById('ttk-player-overlay').appendChild(iframe);

      UI.showNotification(`Stream changed to ${url.includes('kick') ? 'Kick' : 'Twitch'}`);
      return true;
    },

    switchToTwitch: () => {
      const current = StreamManager.getCurrentChannel();
      if (!current) return false;

      Storage.setCurrentMode('twitch');
      UI.updateModeIndicator('twitch');
      return StreamManager.replacePlayerWithStream(StreamManager.twitchStreamURL(current));
    },

    switchToKick: () => {
      const pair = StreamManager.getPairForCurrentChannel();
      if (!pair || !pair.kick) return false;

      Storage.setCurrentMode('kick');
      UI.updateModeIndicator('kick');
      return StreamManager.replacePlayerWithStream(StreamManager.kickStreamURL(pair.kick));
    },

    autoSwitch: () => {
      if (!Storage.isAutoSwitchEnabled()) return;

      const currentChannel = StreamManager.getCurrentChannel();
      if (!currentChannel) return;

      const pair = StreamManager.getPairForCurrentChannel();
      if (!pair || !pair.kick) return;

      const currentMode = Storage.getCurrentMode();

      // If mode is already set to kick or twitch, respect that choice
      if (currentMode === 'kick') {
        StreamManager.switchToKick();
        return;
      } else if (currentMode === 'twitch') {
        StreamManager.switchToTwitch();
        return;
      }

      // Auto mode - check if Twitch stream is offline
      if (StreamManager.isTwitchPlayerOffline()) {
        StreamManager.switchToKick();
      } else {
        StreamManager.switchToTwitch();
      }
    }
  };

  // =================== USER INTERFACE ===================
  const UI = {
    styles: `
      .ttk-container {
        position: fixed;
        right: 20px;
        top: 80px;
        display: flex;
        flex-direction: column;
        gap: 8px;
        z-index: 9999;
        font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
        transition: transform 0.3s ease;
      }

      .ttk-collapsed {
        transform: translateX(calc(100% + 10px));
      }

      .ttk-button {
        padding: 8px 12px;
        font-size: 13px;
        font-weight: 600;
        border-radius: 6px;
        color: white;
        border: none;
        cursor: pointer;
        user-select: none;
        transition: all 0.2s ease;
        width: 160px;
        display: flex;
        align-items: center;
        gap: 6px;
        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
      }

      .ttk-button:hover {
        transform: translateY(-2px);
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
      }

      .ttk-button:active {
        transform: translateY(0);
      }

      .ttk-twitch-button {
        background-color: ${CONFIG.theme.primary};
      }

      .ttk-twitch-button:hover {
        background-color: #772CE8;
      }

      .ttk-kick-button {
        background-color: ${CONFIG.theme.secondary};
      }

      .ttk-kick-button:hover {
        background-color: #008A2D;
      }

      .ttk-auto-button {
        background-color: #555555;
      }

      .ttk-auto-button:hover {
        background-color: #666666;
      }

      .ttk-icon {
        font-size: 16px;
        display: inline-flex;
      }

      .ttk-indicator {
        width: 8px;
        height: 8px;
        border-radius: 50%;
        margin-left: auto;
        background-color: #888;
      }

      .ttk-indicator.active {
        background-color: #4ade80;
        box-shadow: 0 0 6px #4ade80;
      }

      .ttk-toggle {
        position: fixed;
        top: 120px;
        right: 20px;
        z-index: 10000;
        background: ${CONFIG.theme.dark};
        color: ${CONFIG.theme.light};
        border: 1px solid ${CONFIG.theme.border};
        border-radius: 50%;
        width: 32px;
        height: 32px;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: all 0.2s ease;
        font-size: 14px;
        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
      }

      .ttk-toggle:hover {
        background: #333;
        transform: scale(1.1);
      }

      .ttk-settings-button {
        position: fixed;
        top: 160px;
        right: 20px;
        z-index: 10000;
        background: ${CONFIG.theme.dark};
        color: ${CONFIG.theme.light};
        border: 1px solid ${CONFIG.theme.border};
        border-radius: 50%;
        width: 32px;
        height: 32px;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: all 0.2s ease;
        font-size: 14px;
        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
      }

      .ttk-settings-button:hover {
        background: #333;
        transform: scale(1.1);
      }

      .ttk-settings-panel {
        position: fixed;
        top: 200px;
        right: 20px;
        width: 320px;
        background: ${CONFIG.theme.dark};
        color: ${CONFIG.theme.light};
        border: 1px solid ${CONFIG.theme.border};
        border-radius: 10px;
        padding: 16px;
        z-index: 10000;
        font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
        display: none;
        max-height: 60vh;
        overflow-y: auto;
      }

      .ttk-settings-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 16px;
        padding-bottom: 8px;
        border-bottom: 1px solid ${CONFIG.theme.border};
      }

      .ttk-settings-title {
        font-size: 16px;
        font-weight: 600;
        margin: 0;
      }

      .ttk-close-button {
        background: none;
        border: none;
        color: ${CONFIG.theme.light};
        cursor: pointer;
        font-size: 18px;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0;
      }

      .ttk-pair {
        background: #252528;
        border-radius: 6px;
        padding: 12px;
        margin-bottom: 12px;
        border: 1px solid ${CONFIG.theme.border};
      }

      .ttk-pair-header {
        display: flex;
        justify-content: space-between;
        margin-bottom: 8px;
      }

      .ttk-pair-number {
        font-weight: 600;
        font-size: 14px;
      }

      .ttk-delete-pair {
        background: none;
        border: none;
        color: #f87171;
        cursor: pointer;
        font-size: 14px;
        padding: 0;
      }

      .ttk-input-group {
        margin-bottom: 8px;
      }

      .ttk-input-label {
        display: block;
        margin-bottom: 4px;
        font-size: 12px;
        color: #a0a0a5;
      }

      .ttk-input {
        width: 100%;
        padding: 8px;
        border-radius: 4px;
        border: 1px solid ${CONFIG.theme.border};
        background: #1a1a1c;
        color: ${CONFIG.theme.light};
        font-size: 13px;
      }

      .ttk-input:focus {
        outline: none;
        border-color: ${CONFIG.theme.highlight};
      }

      .ttk-button-row {
        display: flex;
        gap: 8px;
        margin-top: 16px;
      }

      .ttk-action-button {
        flex: 1;
        padding: 8px 12px;
        border-radius: 4px;
        border: none;
        font-size: 13px;
        font-weight: 500;
        cursor: pointer;
        transition: all 0.2s ease;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 4px;
      }

      .ttk-primary-button {
        background: ${CONFIG.theme.primary};
        color: white;
      }

      .ttk-primary-button:hover {
        background: #772CE8;
      }

      .ttk-secondary-button {
        background: #3A3A3D;
        color: ${CONFIG.theme.light};
      }

      .ttk-secondary-button:hover {
        background: #4A4A4D;
      }

      .ttk-danger-button {
        background: #dc2626;
        color: white;
      }

      .ttk-danger-button:hover {
        background: #b91c1c;
      }

      .ttk-switch-container {
        display: flex;
        align-items: center;
        margin: 16px 0;
        justify-content: space-between;
      }

      .ttk-switch-label {
        font-size: 14px;
      }

      .ttk-switch {
        position: relative;
        display: inline-block;
        width: 46px;
        height: 24px;
      }

      .ttk-switch input {
        opacity: 0;
        width: 0;
        height: 0;
      }

      .ttk-slider {
        position: absolute;
        cursor: pointer;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: #3A3A3D;
        transition: .4s;
        border-radius: 34px;
      }

      .ttk-slider:before {
        position: absolute;
        content: "";
        height: 18px;
        width: 18px;
        left: 3px;
        bottom: 3px;
        background-color: white;
        transition: .4s;
        border-radius: 50%;
      }

      input:checked + .ttk-slider {
        background-color: ${CONFIG.theme.secondary};
      }

      input:focus + .ttk-slider {
        box-shadow: 0 0 1px ${CONFIG.theme.secondary};
      }

      input:checked + .ttk-slider:before {
        transform: translateX(22px);
      }

      .ttk-notification {
        position: fixed;
        bottom: 20px;
        right: 20px;
        background: rgba(0, 0, 0, 0.8);
        color: white;
        padding: 10px 16px;
        border-radius: 6px;
        font-size: 14px;
        z-index: 10001;
        opacity: 0;
        transform: translateY(10px);
        transition: all 0.3s ease;
        font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
      }

      .ttk-notification.show {
        opacity: 1;
        transform: translateY(0);
      }

      #ttk-player-overlay {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 9;
        background: #000;
      }
    `,

    init: () => {
      // Add styles
      if (typeof GM_addStyle !== 'undefined') {
        GM_addStyle(UI.styles);
      } else {
        const style = document.createElement('style');
        style.textContent = UI.styles;
        document.head.appendChild(style);
      }

      UI.createButtons();
      UI.createToggles();
      UI.createSettingsPanel();
    },

    createButtons: () => {
      const container = document.createElement('div');
      container.id = 'ttk-container';
      container.className = 'ttk-container';
      if (Storage.isCollapsed()) container.classList.add('ttk-collapsed');

      // Kick button
      const kickBtn = document.createElement('button');
      kickBtn.className = 'ttk-button ttk-kick-button';
      kickBtn.innerHTML = '<span class="ttk-icon">⚡</span> Switch to Kick <span class="ttk-indicator" id="ttk-kick-indicator"></span>';
      kickBtn.onclick = StreamManager.switchToKick;

      // Twitch button
      const twitchBtn = document.createElement('button');
      twitchBtn.className = 'ttk-button ttk-twitch-button';
      twitchBtn.innerHTML = '<span class="ttk-icon">👾</span> Switch to Twitch <span class="ttk-indicator" id="ttk-twitch-indicator"></span>';
      twitchBtn.onclick = StreamManager.switchToTwitch;

      // Auto button
      const autoBtn = document.createElement('button');
      autoBtn.className = 'ttk-button ttk-auto-button';
      autoBtn.innerHTML = '<span class="ttk-icon">🔄</span> Auto Switch <span class="ttk-indicator" id="ttk-auto-indicator"></span>';
      autoBtn.onclick = () => {
        Storage.setCurrentMode('auto');
        UI.updateModeIndicator('auto');
        StreamManager.autoSwitch();
      };

      container.appendChild(twitchBtn);
      container.appendChild(kickBtn);
      container.appendChild(autoBtn);
      document.body.appendChild(container);

      UI.updateModeIndicator(Storage.getCurrentMode());
    },

    updateModeIndicator: (mode) => {
      const twitchIndicator = document.getElementById('ttk-twitch-indicator');
      const kickIndicator = document.getElementById('ttk-kick-indicator');
      const autoIndicator = document.getElementById('ttk-auto-indicator');

      if (twitchIndicator) twitchIndicator.classList.toggle('active', mode === 'twitch');
      if (kickIndicator) kickIndicator.classList.toggle('active', mode === 'kick');
      if (autoIndicator) autoIndicator.classList.toggle('active', mode === 'auto');
    },

    createToggles: () => {
      // Collapse toggle button
      const toggleBtn = document.createElement('button');
      toggleBtn.className = 'ttk-toggle';
      toggleBtn.id = 'ttk-toggle';
      toggleBtn.innerText = Storage.isCollapsed() ? '❯' : '❮';
      toggleBtn.onclick = () => {
        const container = document.getElementById('ttk-container');
        const isCollapsed = container.classList.contains('ttk-collapsed');
        container.classList.toggle('ttk-collapsed', !isCollapsed);
        toggleBtn.innerText = isCollapsed ? '❮' : '❯';
        Storage.setCollapsed(!isCollapsed);
      };
      document.body.appendChild(toggleBtn);

      // Settings button
      const settingsBtn = document.createElement('button');
      settingsBtn.className = 'ttk-settings-button';
      settingsBtn.innerText = '⚙️';
      settingsBtn.onclick = () => {
        const panel = document.getElementById('ttk-settings-panel');
        const isVisible = panel.style.display === 'block';
        panel.style.display = isVisible ? 'none' : 'block';
        Storage.setSettingsVisible(!isVisible);

        if (!isVisible) {
          UI.refreshPairsList();
        }
      };
      document.body.appendChild(settingsBtn);
    },

    createSettingsPanel: () => {
      const panel = document.createElement('div');
      panel.id = 'ttk-settings-panel';
      panel.className = 'ttk-settings-panel';
      if (Storage.isSettingsVisible()) panel.style.display = 'block';

      // Header
      const headerHTML = `
        <div class="ttk-settings-header">
          <h3 class="ttk-settings-title">TTK Stream Switcher Settings</h3>
          <button class="ttk-close-button" id="ttk-close-settings">×</button>
        </div>
      `;

      // Auto-switch toggle
      const autoSwitchHTML = `
        <div class="ttk-switch-container">
          <span class="ttk-switch-label">Enable auto-switching</span>
          <label class="ttk-switch">
            <input type="checkbox" id="ttk-auto-switch-toggle" ${Storage.isAutoSwitchEnabled() ? 'checked' : ''}>
            <span class="ttk-slider"></span>
          </label>
        </div>
      `;

      // Pairs list container
      const pairsListHTML = `
        <div id="ttk-pairs-container"></div>
      `;

      // Action buttons
      const buttonsHTML = `
        <div class="ttk-button-row">
          <button id="ttk-add-pair" class="ttk-action-button ttk-primary-button">
            <span>+</span> Add Pair
          </button>
          <button id="ttk-save-all" class="ttk-action-button ttk-secondary-button">
            <span>💾</span> Save All
          </button>
        </div>
      `;

      panel.innerHTML = headerHTML + autoSwitchHTML + pairsListHTML + buttonsHTML;
      document.body.appendChild(panel);

      // Event listeners
      document.getElementById('ttk-close-settings').onclick = () => {
        panel.style.display = 'none';
        Storage.setSettingsVisible(false);
      };

      document.getElementById('ttk-auto-switch-toggle').onchange = (e) => {
        Storage.setAutoSwitchEnabled(e.target.checked);
      };

      document.getElementById('ttk-add-pair').onclick = () => {
        const pairs = Storage.getPairs();
        pairs.push({ twitch: '', kick: '' });
        Storage.savePairs(pairs);
        UI.refreshPairsList();
      };

      document.getElementById('ttk-save-all').onclick = () => {
        UI.savePairs();
      };

      UI.refreshPairsList();
    },

    refreshPairsList: () => {
      const container = document.getElementById('ttk-pairs-container');
      if (!container) return;

      container.innerHTML = '';
      const pairs = Storage.getPairs();

      if (pairs.length === 0) {
        container.innerHTML = `
          <div style="text-align: center; padding: 20px; color: #a0a0a5;">
            No streamer pairs added yet. Click "Add Pair" to get started.
          </div>
        `;
        return;
      }

      pairs.forEach((pair, index) => {
        const pairElement = document.createElement('div');
        pairElement.className = 'ttk-pair';
        pairElement.innerHTML = `
          <div class="ttk-pair-header">
            <span class="ttk-pair-number">Pair #${index + 1}</span>
            <button class="ttk-delete-pair" data-index="${index}">Delete</button>
          </div>
          <div class="ttk-input-group">
            <label class="ttk-input-label">Twitch Username</label>
            <input type="text" class="ttk-input ttk-twitch-input" data-index="${index}" value="${pair.twitch || ''}">
          </div>
          <div class="ttk-input-group">
            <label class="ttk-input-label">Kick Username</label>
            <input type="text" class="ttk-input ttk-kick-input" data-index="${index}" value="${pair.kick || ''}">
          </div>
        `;
        container.appendChild(pairElement);
      });

      // Add event listeners to delete buttons
      document.querySelectorAll('.ttk-delete-pair').forEach(btn => {
        btn.onclick = (e) => {
          const index = parseInt(e.target.getAttribute('data-index'));
          const pairs = Storage.getPairs();
          pairs.splice(index, 1);
          Storage.savePairs(pairs);
          UI.refreshPairsList();
        };
      });
    },

    savePairs: () => {
      const twitchInputs = document.querySelectorAll('.ttk-twitch-input');
      const kickInputs = document.querySelectorAll('.ttk-kick-input');
      const pairs = [];

      for (let i = 0; i < twitchInputs.length; i++) {
        const twitch = twitchInputs[i].value.trim();
        const kick = kickInputs[i].value.trim();

        if (twitch || kick) {
          pairs.push({ twitch, kick });
        }
      }

      Storage.savePairs(pairs);
      UI.showNotification('Settings saved successfully!');
    },

    showNotification: (message, duration = 3000) => {
      // Remove any existing notification
      const existingNotification = document.querySelector('.ttk-notification');
      if (existingNotification) {
        existingNotification.remove();
      }

      const notification = document.createElement('div');
      notification.className = 'ttk-notification';
      notification.textContent = message;
      document.body.appendChild(notification);

      // Force reflow before adding the show class
      notification.offsetHeight;
      notification.classList.add('show');

      setTimeout(() => {
        notification.classList.remove('show');
        setTimeout(() => notification.remove(), 300);
      }, duration);
    }
  };

  // =================== INITIALIZATION ===================
  function initialize() {
    UI.init();

    // Set up auto-switch monitoring
    setInterval(() => {
      const currentChannel = StreamManager.getCurrentChannel();
      if (currentChannel) {
        StreamManager.autoSwitch();
      }
    }, CONFIG.checkInterval);

    // Initial check
    setTimeout(() => {
      StreamManager.autoSwitch();
    }, CONFIG.initDelay);
  }

  // Execute when DOM is fully loaded
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initialize);
  } else {
    initialize();
  }
})();