Small Cams Stumblechat

Makes stumblechat webcams 320x240

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Small Cams Stumblechat
// @namespace    http://tampermonkey.net/
// @version      0.8
// @description  Makes stumblechat webcams 320x240
// @author       You
// @match        https://stumblechat.com/*
// @grant        GM_addStyle
// @license      none
// ==/UserScript==
(function() {
    'use strict';

    console.log("Script started.");

    // Add styles using GM_addStyle for compacting video wrappers and camera badges
    let css = `
        #videos-content {
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
        }
        .videos-items > .js-video {
            width: 100%;
        }
        .video-wrapper {
            position: relative;
            width: 100%;
            height: 100%;
        }
        #regularvideos {
            display: grid;
            grid-template-columns: repeat(5, 320px);  // 5 columns of 320px each
            grid-template-rows: repeat(5, 240px);  // 5 rows of 240px each
            gap: 5px;
            width: 100%;
            height: 100%;
        }
        .video-cell {
            box-sizing: border-box;
            position: relative;
        }
        .video-badge {
            width: 16px;
            height: 16px;
            background-image: url(../styles/svg/webcam.svg);
            background-position: center center;
            background-repeat: no-repeat;
            position: absolute;
            top: 5px;
            left: 5px;
        }
    `;
    if (typeof GM_addStyle !== "undefined") {
        GM_addStyle(css);
    } else {
        let styleNode = document.createElement("style");
        styleNode.appendChild(document.createTextNode(css));
        (document.querySelector("head") || document.documentElement).appendChild(styleNode);
    }

    // Create a 5x5 grid table for webcam videos
    const videosContent = document.getElementById("videos-content");

    // Adjust positioning of the videos-content div
    videosContent.style.position = 'absolute';
    videosContent.style.bottom = '0';
    videosContent.style.left = '0';
    videosContent.style.width = '100%';

    const table = document.createElement("table");
    table.style.borderCollapse = 'collapse';
    table.style.width = '100%';

    // Create rows and cells in a 5x5 grid (320x240 per cell)
    for (let i = 0; i < 5; i++) {
        const row = document.createElement("tr");
        for (let j = 0; j < 5; j++) {
            const cell = document.createElement("td");
            cell.style.padding = '5px';
            cell.style.textAlign = 'center';
            cell.style.border = '1px solid #ddd';
            cell.style.height = '240px';
            cell.style.width = '320px';
            cell.classList.add('video-cell');
            row.appendChild(cell);
        }
        table.appendChild(row);
    }

    // Insert the table into the "regularvideos" div inside the "videos-content" container
    const regularVideosDiv = videosContent.querySelector("#regularvideos");
    if (!regularVideosDiv) {
        console.error("Could not find #regularvideos container.");
        return;
    }
    regularVideosDiv.appendChild(table);

    // Function to find the first empty cell in the grid
    function findEmptyCell() {
        const cells = table.getElementsByTagName("td");
        for (let cell of cells) {
            if (!cell.hasChildNodes()) {
                return cell;
            }
        }
        return null; // If no empty cells are found
    }

    // Function to add the camera badge
    function addCameraBadge(userElement) {
        const videoBadge = document.createElement('div');
        videoBadge.classList.add('video-badge');
        const statusElement = userElement.querySelector('.status');
        if (statusElement) {
            statusElement.appendChild(videoBadge); // Append it to the user's status element
        }
    }

    // MutationObserver to monitor DOM for video-wrapper additions
    const observer = new MutationObserver(mutations => {
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === 1 && node.classList.contains('js-video') && !node.classList.contains('hidden')) {
                    console.log("New video-wrapper detected:", node);

                    // Modify the video element within the wrapper
                    const videoElement = node.querySelector('video');
                    if (videoElement) {
                        console.log("Video element found:", videoElement);

                        // Find an empty cell in the 5x5 grid and place the entire video wrapper
                        const emptyCell = findEmptyCell();
                        if (emptyCell) {
                            console.log("Placing video wrapper in empty cell...");
                            // Move the entire js-video element into the table cell
                            emptyCell.appendChild(node);

                            // Ensure the video takes up 100% of the cell's width and height
                            videoElement.style.width = '100%';
                            videoElement.style.height = '100%';

                            // Adjust video wrapper styles if needed
                            const videoWrapper = node.querySelector('.video-wrapper');
                            if (videoWrapper) {
                                videoWrapper.style.width = '100%';
                                videoWrapper.style.height = '100%';
                            }

                            // Add camera badge if the user has their camera on
                            const userElement = node.closest('.user-item'); // Replace with the correct selector for user elements
                            const cameraStatus = userElement ? userElement.getAttribute('data-camera-status') : null; // Replace with the appropriate attribute or logic
                            if (cameraStatus === 'active') { // Check if camera is active
                                addCameraBadge(userElement);
                            }
                        }

                    } else {
                        console.warn("No video element found inside video-wrapper.");
                    }
                }
            });
        });
    });

    // Start observing the DOM
    const targetNode = document.body;
    const config = { childList: true, subtree: true };
    observer.observe(targetNode, config);

    console.log("Observer initialized. Watching for js-video elements.");

    // Adding placeholder if needed (ensure vertical <br> appears in empty cells)
    function addPlaceholders() {
        const cells = table.getElementsByTagName("td");
        for (let cell of cells) {
            if (!cell.hasChildNodes()) {
                const placeholder = document.createElement('br');
                cell.appendChild(placeholder);
            }
        }
    }

    // Periodically check for empty cells and add placeholders
    setInterval(addPlaceholders, 1000);

})();