Adds a “➕” on Kick.com to view multiple streams at once on MultiKick.com
目前為
// ==UserScript==
// @name Kick ↔ MultiKick Enhancer
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Adds a “➕” on Kick.com to view multiple streams at once on MultiKick.com
// @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);
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');
// in case it's still loading, send again
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') {
// 0) Name the window immediately so future window.open() calls reuse it
if (window.name !== WINDOW_NAME) {
window.name = WINDOW_NAME;
}
// 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 append+reload 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;
const parts = location.pathname
.replace(/^\/|\/$/g, '')
.split('/')
.filter(Boolean);
if (!parts.includes(msg.slug)) {
parts.push(msg.slug);
const newPath = '/' + parts.join('/');
history.replaceState(null, '', newPath);
location.reload();
}
});
}
})();