Greasy Fork 支持简体中文。

Kick ↔ MultiKick Enhancer

Adds a “➕” on Kick.com to append streams, and on MultiKick.com preserves & appends streams in a single, re‑used tab.

目前為 2025-04-19 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Kick ↔ MultiKick Enhancer
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Adds a “➕” on Kick.com to append streams, and on MultiKick.com preserves & appends streams in a single, re‑used tab.
// @match        https://kick.com/*
// @match        https://www.kick.com/*
// @match        https://multikick.com/*
// @match        https://www.multikick.com/*
// @grant        none
// @run-at       document-end
// @license MIT
// ==/UserScript==

(function() {
  'use strict';
  const host        = location.hostname.replace(/^www\./, '');
  const WINDOW_NAME = 'multikick-window';

  // ─── Kick.com side ─────────────────────────────────────────────────────
  if (host === 'kick.com') {
    function addButtons() {
      document
        .querySelectorAll('a[data-state][href^="/"] > img.rounded-full')
        .forEach(img => {
          const a = img.parentElement;
          if (a.dataset.mkDone) return;
          a.dataset.mkDone = '1';

          const slug = a.getAttribute('href').slice(1);  // remove leading '/'
          const btn  = document.createElement('a');
          btn.textContent = '➕';
          btn.href        = '#';
          btn.title       = 'Add to MultiKick';
          Object.assign(btn.style, {
            marginLeft: '4px',
            cursor:     'pointer',
            fontSize:   '1em',
            textDecoration: 'none',
            color:      'inherit',
          });

          btn.addEventListener('click', e => {
            e.preventDefault();
            // open (or reuse) the MultiKick tab at its root
            const mkWin = window.open('https://multikick.com', WINDOW_NAME);
            if (!mkWin) return;
            mkWin.focus();
            // tell it to append our slug
            const msg = { type: 'MK_APPEND', slug };
            mkWin.postMessage(msg, 'https://multikick.com');
            // send again after a brief delay in case it's still loading
            setTimeout(() => mkWin.postMessage(msg, 'https://multikick.com'), 500);
          });

          a.parentElement.insertBefore(btn, a.nextSibling);
        });
    }

    addButtons();
    new MutationObserver(addButtons)
      .observe(document.body, { childList: true, subtree: true });
  }


  // ─── MultiKick.com side ────────────────────────────────────────────────
  else if (host === 'multikick.com') {
    // 1) Prevent their router from wiping out deep URLs
    const desired = location.pathname;
    function wrap(orig) {
      return function(state, _title, url) {
        if ((url === '/' || url === '') && desired !== '/') {
          url = desired;
        }
        return orig.call(this, state, '', url);
      };
    }
    history.pushState    = wrap(history.pushState);
    history.replaceState = wrap(history.replaceState);
    window.addEventListener('popstate', () => {
      if (location.pathname === '/' && desired !== '/') {
        history.replaceState(null, '', desired);
      }
    });

    // 2) Listen for “MK_APPEND” messages and do the appending here
    window.addEventListener('message', e => {
      if (!/^https?:\/\/(?:www\.)?kick\.com$/.test(e.origin)) return;
      const msg = e.data || {};
      if (msg.type !== 'MK_APPEND' || typeof msg.slug !== 'string') return;

      // current path segments
      const parts = location.pathname
        .replace(/^\/|\/$/g, '')
        .split('/')
        .filter(Boolean);

      // append if new
      if (!parts.includes(msg.slug)) {
        parts.push(msg.slug);
        const newPath = '/' + parts.join('/');
        history.replaceState(null, '', newPath);
        location.reload();
      }
    });
  }
})();