// ==UserScript==
// @name Kick ↔ MultiKick Enhancer
// @namespace http://tampermonkey.net/
// @version 1.3
// @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() {
//
// 1) Streamer‑list pages
//
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();
const mkWin = window.open('https://multikick.com', WINDOW_NAME);
if (!mkWin) return;
mkWin.focus();
const msg = { type: 'MK_APPEND', slug };
mkWin.postMessage(msg, 'https://multikick.com');
setTimeout(() => mkWin.postMessage(msg, 'https://multikick.com'), 500);
});
a.parentElement.insertBefore(btn, a.nextSibling);
});
//
// 2) Single‑streamer pages: inject *after* the <h1 id="channel-username">
//
const header = document.getElementById('channel-username');
if (header && !header.dataset.mkDone) {
header.dataset.mkDone = '1';
const slug = location.pathname.replace(/^\/|\/$/g, '');
const btn = document.createElement('a');
btn.textContent = '➕';
btn.href = '#';
btn.title = 'Add to MultiKick';
Object.assign(btn.style, {
marginLeft: '8px',
cursor: 'pointer',
fontSize: '0.9em',
textDecoration:'none',
color: 'inherit',
verticalAlign: 'middle',
});
btn.addEventListener('click', e => {
e.preventDefault();
const mkWin = window.open('https://multikick.com', WINDOW_NAME);
if (!mkWin) return;
mkWin.focus();
const msg = { type: 'MK_APPEND', slug };
mkWin.postMessage(msg, 'https://multikick.com');
setTimeout(() => mkWin.postMessage(msg, 'https://multikick.com'), 500);
});
// insert the button right after the <h1>
header.insertAdjacentElement('afterend', btn);
}
}
addButtons();
new MutationObserver(addButtons)
.observe(document.body, { childList: true, subtree: true });
}
// ─── MultiKick.com side ────────────────────────────────────────────────
else if (host === 'multikick.com') {
// 0) Name the window so window.open(..., WINDOW_NAME) reuses 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 to merge and reload
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();
}
});
}
})();