Auto-embed Twitter links.

Find Twitter links and embed them directly into a post.

Versión del día 06/05/2023. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Auto-embed Twitter links.
// @author       Joshh
// @namespace    https://tljoshh.com
// @version      0.5.2
// @description  Find Twitter links and embed them directly into a post.
// @match        *://*.websight.blue/thread/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=websight.blue
// @license MIT
// ==/UserScript==

(function() {
    'use strict';
    const storageKey = 'twitterWidgetTheme';
    main();

    function main() {
        // Setup widget's default color scheme
        let theme = localStorage.getItem(storageKey);
        if(localStorage.getItem(storageKey) === null) {
            localStorage.setItem(storageKey, 'dark');
            theme = 'dark';
        }

        // Look for twitter links
        const postsContainer = document.querySelector('#messages');
        const posts = document.querySelectorAll('.post');
        for (const post of posts) {
            handlePost(post, theme);
        };
        // Look for twitter links in posts added by livelinks
        startMutationObserver(postsContainer);
    }

    // Add event listener to any posts added to DOM via livelinks
    function startMutationObserver(targetNode) {
        // Options for the observer (which mutations to observe)
        const config = { childList: true };

        // Callback function to execute when mutations are observed
        const callback = (mutationList, observer) => {
            // For all mutations made to the target node, check if any nodes were added...
            for (const mutation of mutationList) {
                handleMutation(mutation);
            }
        };

        // Create an observer instance linked to the callback function
        const observer = new MutationObserver(callback);

        // Start observing the target node for configured mutations
        observer.observe(targetNode, config);
    }

    // Handle any changes made to the messages container (usually via livelinks)
    function handleMutation(mutation) {
        if(mutation.addedNodes.length) {
            const theme = localStorage.getItem(storageKey);
            for (const addedNode of mutation.addedNodes) {
                if (!addedNode.tagName) continue; // Not an element
                if(addedNode.classList.contains('post')) {
                    handlePost(addedNode, theme);
                }
            }
        }
    }

    function handlePost(post, theme) {
        const links = post.querySelectorAll('.message-contents a[href*="twitter.com"]');
        const twitterLinkRegex = new RegExp('http(?:s)?:\/\/(?:www\.)?(?:mobile\.)?twitter.com\/(?:.*)\/status\/(\\d+)(?:.*)?');
        const twitterLinks = [...links].filter(link => link.href.match(twitterLinkRegex) !== null);
        if(twitterLinks.length) {
            if(typeof twttr === 'undefined') {
                createTwitterScript();
            }
            twttr.ready((twttr) => {
                for (const link of twitterLinks) {
                    link.style.display = "none";
                    const matchGroups = link.href.match(twitterLinkRegex);
                    const tweetId = matchGroups[1];
                    const node = createEmbedNode(tweetId);
                    link.parentNode.insertBefore(node, link.nextSibling);
                    twttr.widgets.createTweet(tweetId, node, { theme });
                    const swapThemeNode = createSwapThemeNode(theme);
                    node.parentNode.insertBefore(swapThemeNode, node.nextSibling);
                }
            });
        }
    }

    function createEmbedNode(tweetId) {
        const node = document.createElement('div');
        node.setAttribute('id', `tweet-${tweetId}`);
        return node;
    }

    function createTwitterScript() {
        const script = document.createElement('script');
        script.setAttribute('type', 'text/javascript');
        script.appendChild(document.createTextNode('window.twttr=function(t,e,r){var n,s=t.getElementsByTagName(e)[0],i=window.twttr||{};return t.getElementById(r)||((n=t.createElement(e)).id=r,n.src="https://platform.twitter.com/widgets.js",s.parentNode.insertBefore(n,s),i._e=[],i.ready=function(t){i._e.push(t)}),i}(document,"script","twitter-wjs");'));
        document.head.appendChild(script);
    }

    function createSwapThemeNode(theme) {
        const node = document.createElement('div');
        node.innerText = `Swap to ${theme === 'light' ? 'dark' : 'light'} mode (requires refresh)`;
        node.style = 'cursor:pointer;font-size: 11px;position: relative; top: -8px; text-decoration: underline;';
        node.addEventListener('click', (e) => {
            if(theme === 'light') {
                localStorage.setItem(storageKey, 'dark');
            } else {
                localStorage.setItem(storageKey, 'light');
            }
            if(confirm('Changes will take effect the next time the page is loaded. Refresh the page now?')) {
                window.location.reload();
            }
        });
        return node;
    }
})();