Pixiv Auto Expand Multiple Images

Auto Expand Pixiv multiple images without clicking. Works for both illustrations and manga.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Pixiv Auto Expand Multiple Images
// @namespace    http://tampermonkey.net/
// @version      1.6
// @description  Auto Expand Pixiv multiple images without clicking. Works for both illustrations and manga.
// @author       CHATGPT + GEMINI - jarsang010
// @license      None
// @match        https://www.pixiv.net/en/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function () {
    'use strict';

    let hasClickedExpandButtonThisPage = false; // Tracks if we've clicked the expand button for the current artwork
    let isMangaViewerCurrentlyActive = false; // Tracks if the manga viewer modal is open
    let currentArtworkId = null;

    // Function to click the "Show all" or "Start reading" button
    function tryClickExpandButton() {
        // Only proceed if the current URL is an artwork page
        if (!window.location.pathname.startsWith('/en/artworks/')) {
            console.log("[PixivScript] Not on an artwork page. Skipping click attempts.");
            return false;
        }

        if (hasClickedExpandButtonThisPage || isMangaViewerCurrentlyActive) {
            console.log("[PixivScript] Already clicked expand button for this page or manga viewer active - skipping click attempt.");
            return false;
        }

        console.log("[PixivScript] Checking for expand buttons...");
        const buttons = Array.from(document.querySelectorAll("button, a"));

        for (const btn of buttons) {
            const text = btn.textContent.trim();
            if (text === "Show all" || text === "Reading works" || text === "Start reading") {
                console.log(`[PixivScript] Clicking "${text}"`);
                btn.click();
                hasClickedExpandButtonThisPage = true; // Mark that we've clicked it for this page
                return true;
            }
        }
        return false;
    }

    // Observer to detect when the manga viewer is opened or closed
    const viewerObserver = new MutationObserver(function (mutations) {
        const viewerModal = document.querySelector(".sc-fgvYmX.hCqDkB, ._viewer, ._modal.ui-modal");

        if (viewerModal && !isMangaViewerCurrentlyActive) {
            console.log("[PixivScript] Manga viewer modal detected as opened.");
            isMangaViewerCurrentlyActive = true;
            hasClickedExpandButtonThisPage = true;
        } else if (!viewerModal && isMangaViewerCurrentlyActive) {
            console.log("[PixivScript] Manga viewer modal detected as closed.");
            isMangaViewerCurrentlyActive = false;
        }
    });

    // Start observing the body for changes that indicate viewer state
    setTimeout(() => {
        viewerObserver.observe(document.body, { childList: true, subtree: true });
        console.log("[PixivScript] Viewer observer started.");
    }, 500);

    // Function to handle initial clicks and clicks on URL change
    function activateAutoClick() {
        let attempts = 0;
        const maxAttempts = 20; // Try for up to 10 seconds (20 * 500ms)
        const clickInterval = setInterval(() => {
            if (hasClickedExpandButtonThisPage || isMangaViewerCurrentlyActive || attempts >= maxAttempts) {
                clearInterval(clickInterval);
                if (attempts >= maxAttempts && !hasClickedExpandButtonThisPage && !isMangaViewerCurrentlyActive) {
                    console.log("[PixivScript] Max click attempts reached, no expand button found or viewer active.");
                }
                return;
            }
            attempts++;
            console.log(`[PixivScript] Click attempt ${attempts}...`);
            tryClickExpandButton();
        }, 500);
    }

    // Reset state and activate auto-click when URL changes (user navigates to a new artwork)
    function handleUrlChange() {
        const newArtworkIdMatch = window.location.pathname.match(/\/artworks\/(\d+)/);
        const newArtworkId = newArtworkIdMatch ? newArtworkIdMatch[1] : null;

        if (newArtworkId && newArtworkId !== currentArtworkId) {
            console.log(`[PixivScript] Navigated to new artwork (ID: ${newArtworkId}). Resetting state.`);
            currentArtworkId = newArtworkId;
            hasClickedExpandButtonThisPage = false;
            isMangaViewerCurrentlyActive = false;
            setTimeout(activateAutoClick, 800);
        } else if (!newArtworkId) {
            currentArtworkId = null;
            hasClickedExpandButtonThisPage = false;
            isMangaViewerCurrentlyActive = false;
            console.log("[PixivScript] Navigated away from artwork page. State reset.");
        } else {
            console.log("[PixivScript] URL change detected, but it's the same artwork ID. No full reset.");
        }
    }

    // Hook browser history API to detect URL changes within Pixiv's SPA
    function hookHistory(fn) {
        return function () {
            const ret = fn.apply(this, arguments);
            window.dispatchEvent(new Event("customurlchange"));
            return ret;
        };
    }
    history.pushState = hookHistory(history.pushState);
    history.replaceState = hookHistory(history.replaceState);
    window.addEventListener("popstate", () => window.dispatchEvent(new Event("customurlchange")));
    window.addEventListener("customurlchange", handleUrlChange);

    // Initial run when the script loads
    console.log("[PixivScript] Initializing...");
    handleUrlChange();
    activateAutoClick();

})();