Greasy Fork

4chan Gallery

4chan grid based Image Gallery for threads that can load images, images with sounds, webms with sounds (Button on the Bottom Right)

目前为 2024-03-26 提交的版本。查看 最新版本

// ==UserScript==
// @name         4chan Gallery
// @namespace    http://tampermonkey.net/
// @version      2024-03-26
// @description  4chan grid based Image Gallery for threads that can load images, images with sounds, webms with sounds (Button on the Bottom Right)
// @author       TheDarkEnjoyer
// @match        http://boards.4chan.org/vt/thread/*
// @match        https://boards.4chan.org/vt/thread/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @license      GNU GPLv3 
// ==/UserScript==

(function () {
    "use strict";

    // Function to load the button
    const loadButton = () => {
        const posts = document.querySelectorAll(".postContainer");

        // Check if there are at least two posts
        if (posts.length >= 2) {
            const button = document.createElement("button");
            button.textContent = "Open Image Gallery";
            button.style.position = "fixed";
            button.style.bottom = "20px";
            button.style.right = "20px";
            button.style.zIndex = "1000";
            button.style.backgroundColor = "var(--main-color)"; // Dark mode compatible background
            button.style.color = "var(--text-color)"; // Dark mode compatible text color

            // Append the button to the body after 2 seconds
            setTimeout(() => document.body.appendChild(button), 2000);

            const openImageGallery = () => {
                const gallery = document.createElement("div");
                gallery.style.position = "fixed";
                gallery.style.top = "0";
                gallery.style.left = "0";
                gallery.style.width = "100%";
                gallery.style.height = "100%";
                gallery.style.backgroundColor = "rgba(0, 0, 0, 0.8)";
                gallery.style.display = "flex";
                gallery.style.justifyContent = "center";
                gallery.style.alignItems = "center";
                gallery.style.zIndex = "9999";

                const gridContainer = document.createElement("div");
                gridContainer.style.display = "grid";
                gridContainer.style.gridTemplateColumns = "repeat(auto-fit, minmax(200px, 1fr))";
                gridContainer.style.gridGap = "10px";
                gridContainer.style.padding = "20px";
                gridContainer.style.backgroundColor = "var(--main-color)"; // Dark mode compatible background
                gridContainer.style.color = "var(--text-color)"; // Dark mode compatible text color
                gridContainer.style.maxWidth = "80%";
                gridContainer.style.maxHeight = "80%";
                gridContainer.style.overflowY = "auto";
                gridContainer.style.resize = "both"; // Make the grid resizable
                gridContainer.style.overflow = "auto"; // Add scrollbars when resized
                gridContainer.style.border = "1px solid var(--text-color)"; // Add border to the grid container

                // Loop through each post and add its image/video to the grid
                posts.forEach((post) => {
                    const mediaLink = post.querySelector(".fileText a");
                    const comment = post.querySelector(".postMessage");

                    if (mediaLink) {
                        const isVideo = mediaLink.href.includes(".webm");
                        const fileName = mediaLink.href.split("/").pop();
                        const soundLink = mediaLink.title.match(/\[sound=(.+?)\]/);

                        const cell = document.createElement("div");
                        cell.style.border = "1px solid var(--text-color)"; // Add border to each cell
                        cell.style.position = "relative"; // Make the cell position relative

                        const buttonDiv = document.createElement("div");
                        buttonDiv.style.display = "flex";
                        buttonDiv.style.justifyContent = "space-between";
                        buttonDiv.style.alignItems = "center";
                        buttonDiv.style.padding = "5px";

                        if (isVideo) {
                            const videoContainer = document.createElement("div");
                            videoContainer.style.position = "relative";

                            const video = document.createElement("video");
                            video.src = mediaLink.href;
                            video.style.maxWidth = "100%";
                            video.style.maxHeight = "200px";
                            video.style.objectFit = "contain";
                            video.muted = true;
                            video.style.cursor = "pointer";
                            video.addEventListener("click", () => {
                                post.scrollIntoView({ behavior: "smooth" });
                                document.body.removeChild(gallery);
                            });
                            video.controls = true;
                            video.title = comment.textContent;

                            videoContainer.appendChild(video);

                            if (soundLink) {
                                const audio = document.createElement("audio");
                                audio.src = decodeURIComponent(soundLink[1].startsWith("http") ? soundLink[1] : `https://${soundLink[1]}`);
                                videoContainer.appendChild(audio);

                                const playPauseButton = document.createElement("button");
                                playPauseButton.textContent = "Play/Pause";
                                playPauseButton.addEventListener("click", () => {
                                    if (video.paused && audio.paused) {
                                        video.play();
                                        audio.play();
                                    } else {
                                        video.pause();
                                        audio.pause();
                                    }
                                });
                                buttonDiv.appendChild(playPauseButton);

                                const resetButton = document.createElement("button");
                                resetButton.textContent = "Reset";
                                resetButton.addEventListener("click", () => {
                                    video.currentTime = 0;
                                    audio.currentTime = 0;
                                });
                                buttonDiv.appendChild(resetButton);
                            }

                            const cellButton = document.createElement("button");
                            cellButton.textContent = "View Post";
                            cellButton.style.backgroundColor = "var(--main-color)";
                            cellButton.style.color = "var(--text-color)";
                            cellButton.addEventListener("click", () => {
                                post.scrollIntoView({ behavior: "smooth" });
                                document.body.removeChild(gallery);
                            });

                            buttonDiv.appendChild(cellButton);
                            cell.appendChild(videoContainer);
                            cell.appendChild(buttonDiv);
                        } else {
                            const image = document.createElement("img");
                            image.src = mediaLink.href;
                            image.style.maxWidth = "100%";
                            image.style.maxHeight = "200px";
                            image.style.objectFit = "contain";
                            image.style.cursor = "pointer";
                            image.addEventListener("click", () => {
                                post.scrollIntoView({ behavior: "smooth" });
                                document.body.removeChild(gallery);
                            });
                            image.title = comment.textContent;

                            if (soundLink) {
                                const audio = document.createElement("audio");
                                audio.src = decodeURIComponent(soundLink[1].startsWith("http") ? soundLink[1] : `https://${soundLink[1]}`);

                                const playPauseButton = document.createElement("button");
                                playPauseButton.textContent = "Play/Pause";
                                playPauseButton.style.position = "absolute";
                                playPauseButton.style.bottom = "10px";
                                playPauseButton.style.left = "10px";
                                playPauseButton.addEventListener("click", () => {
                                    if (audio.paused) {
                                        audio.play();
                                    } else {
                                        audio.pause();
                                    }
                                });
                                buttonDiv.appendChild(playPauseButton);
                            }

                            cell.appendChild(image);
                            cell.appendChild(buttonDiv);
                        }
                        gridContainer.appendChild(cell);
                    }
                });

                gallery.appendChild(gridContainer);

                const closeButton = document.createElement("button");
                closeButton.textContent = "Close";
                closeButton.style.position = "absolute";
                closeButton.style.top = "10px";
                closeButton.style.right = "10px";
                closeButton.style.zIndex = "10000";
                closeButton.style.backgroundColor = "var(--main-color)";
                closeButton.style.color = "var(--text-color)";
                closeButton.addEventListener("click", () => {
                    document.body.removeChild(gallery);
                });
                gallery.appendChild(closeButton);

                document.body.appendChild(gallery);
            };

            button.addEventListener("click", openImageGallery);
        } else {
            // If there are less than two posts, try again after 5 seconds
            setTimeout(loadButton, 5000);
        }
    };

    loadButton();
    console.log("4chan Gallery loaded successfully!");
})();