Auto-embed Twitter links.

Find Twitter links and embed them directly into a post.

// ==UserScript==
// @name         Auto-embed Twitter links.
// @author       Joshh
// @namespace    https://tljoshh.com
// @version      0.5.3
// @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 > p 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(currentTheme) {
        const node = document.createElement('div');
        node.innerText = `Swap to ${currentTheme === '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(currentTheme === '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;
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址