EmbedCast Link Extractor (Sidebar Edition)

Collapsible sidebar that centralizes all detected video/iframe links.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         EmbedCast Link Extractor (Sidebar Edition)
// @namespace    https://github.com/MoriNo23/embedCast
// @version      2.0
// @description  Collapsible sidebar that centralizes all detected video/iframe links.
// @author       mori
// @match        *://*/*
// @grant        none
// @license MIT
// @run-at       document-end
// @icon         https://raw.githubusercontent.com/MoriNo23/embedCast/main/assets/logo.png
// ==/UserScript==

(function() {
    'use strict';

    // --- COMMUNICATION SETUP ---
    const MESSAGE_TYPE = 'EMBEDCAST_FOUND_URL';

    // --- LOGIC FOR IFRAMES (CHILDREN) ---
    if (window.self !== window.top) {
        const notifyTop = (url) => {
            if (url && url.startsWith('http') && !url.includes('about:blank')) {
                // Send the URL to the main page
                window.top.postMessage({ type: MESSAGE_TYPE, url: url }, '*');
            }
        };

        // Notify the current iframe URL
        notifyTop(window.location.href);

        // Look for lazyload elements inside the iframe
        const checkLazyInIframe = () => {
            const lazy = document.querySelector('iframe, .lazyload, .lazyloade, [data-src]');
            if (lazy) {
                const url = lazy.src || lazy.getAttribute('data-src') || lazy.getAttribute('data-lazy-src');
                notifyTop(url);
            }
        };
        setInterval(checkLazyInIframe, 3000);
        return; // Stop execution here for iframes
    }

    // --- LOGIC FOR MAIN WINDOW (PARENT) ---
    const capturedUrls = new Set();
    let sidebar, listContainer;

    const createSidebar = () => {
        if (document.getElementById('embedcast-sidebar')) return;

        // Create the sidebar container
        sidebar = document.createElement('div');
        sidebar.id = 'embedcast-sidebar';
        Object.assign(sidebar.style, {
            position: 'fixed',
            right: '-260px', // Hidden by default
            top: '0',
            width: '260px',
            height: '100vh',
            background: '#1a1a2e',
            borderLeft: '2px solid #00ffcc',
            zIndex: '2147483647', // Always on top
            transition: 'right 0.3s ease',
            display: 'flex',
            flexDirection: 'column',
            boxShadow: '-5px 0 15px rgba(0,0,0,0.5)',
            color: '#fff',
            fontFamily: 'sans-serif'
        });

        sidebar.innerHTML = `
            <div style="padding: 15px; background: #16213e; border-bottom: 1px solid #00ffcc; display: flex; align-items: center; justify-content: space-between;">
                <div style="display:flex; align-items:center;">
                    <img src="https://raw.githubusercontent.com/MoriNo23/embedCast/main/assets/logo.png" style="width:20px; margin-right:8px;">
                    <span style="color:#00ffcc; font-weight:bold; font-size:14px;">EmbedCast</span>
                </div>
                <button id="ec-close" style="background:none; border:none; color:#00ffcc; cursor:pointer; font-size:18px;">×</button>
            </div>
            <div id="ec-list" style="flex:1; overflow-y:auto; padding:10px;">
                <p id="ec-empty" style="color:#666; font-size:12px; text-align:center; margin-top:20px;">Searching links...</p>
            </div>
            <div id="ec-toggle" style="position:absolute; left:-40px; top:50%; width:40px; height:60px; background:#1a1a2e; border:2px solid #00ffcc; border-right:none; border-radius:10px 0 0 10px; cursor:pointer; display:flex; align-items:center; justify-content:center; color:#00ffcc; font-weight:bold;">
                <img src="https://raw.githubusercontent.com/MoriNo23/embedCast/main/assets/logo.png" style="width:25px;">
            </div>
        `;

        document.body.appendChild(sidebar);
        listContainer = document.getElementById('ec-list');

        // UI Events
        const toggleBtn = document.getElementById('ec-toggle');
        const closeBtn = document.getElementById('ec-close');
        
        const toggleSidebar = () => {
            const isOpen = sidebar.style.right === '0px';
            sidebar.style.right = isOpen ? '-260px' : '0px';
        };

        toggleBtn.onclick = toggleSidebar;
        closeBtn.onclick = toggleSidebar;
    };

    const addUrlToList = (url) => {
        // Avoid duplicate links
        if (capturedUrls.has(url)) return;
        capturedUrls.add(url);

        const emptyMsg = document.getElementById('ec-empty');
        if (emptyMsg) emptyMsg.remove();

        // Create link item in the list
        const item = document.createElement('div');
        Object.assign(item.style, {
            background: '#16213e',
            padding: '10px',
            marginBottom: '8px',
            borderRadius: '5px',
            border: '1px solid #30475e',
            fontSize: '11px'
        });

        item.innerHTML = `
            <div style="color:#00ffcc; margin-bottom:5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${url}">
                ${url}
            </div>
            <button class="ec-copy-btn" style="width:100%; background:#0f3460; color:#00ffcc; border:1px solid #00ffcc; padding:5px; cursor:pointer; border-radius:3px; font-weight:bold;">
                COPY
            </button>
        `;

        item.querySelector('.ec-copy-btn').onclick = function() {
            navigator.clipboard.writeText(url);
            this.innerText = 'COPIED!';
            setTimeout(() => this.innerText = 'COPY', 2000);
        };

        listContainer.appendChild(item);
        
        // Auto-open sidebar when the first link is found
        if (capturedUrls.size === 1) {
            sidebar.style.right = '0px';
        }
    };

    // Listen for messages from iframes
    window.addEventListener('message', (event) => {
        if (event.data && event.data.type === MESSAGE_TYPE) {
            addUrlToList(event.data.url);
        }
    });

    // Initialize sidebar
    createSidebar();

    // Also search in the main page for links
    setInterval(() => {
        const potential = document.querySelectorAll('iframe, .lazyload, .lazyloade, [data-src]');
        potential.forEach(el => {
            const url = el.src || el.getAttribute('data-src') || el.getAttribute('data-lazy-src');
            if (url && url.startsWith('http')) addUrlToList(url);
        });
    }, 3000);

})();