Dzen Auto Expander (Comments & More)

Автоматически разворачивает ветки комментариев Dzen, нажимает «читать дальше» в комментариях и нажимает главную кнопку «показать больше комментариев».

目前為 2025-04-13 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Dzen Auto Expander (Comments & More)
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Автоматически разворачивает ветки комментариев Dzen, нажимает «читать дальше» в комментариях и нажимает главную кнопку «показать больше комментариев».
// @author       Your Name Here
// @match        *://dzen.ru/*
// @license MIT
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    const CHECK_INTERVAL_MS = 1500; // Check every 1.5 seconds
    const MAX_CHECKS_WITHOUT_ACTION = 5; // Stop if nothing found for ~7.5 seconds consecutive checks

    let checksWithoutAction = 0;
    let intervalId = null;
    let stopped = false;

    // --- Selectors ---
    // Selectors are based on the provided HTML structure and common Dzen patterns.
    // They might need adjustment if Dzen changes its layout significantly.
    const SELECTORS = {
        // Button like "Показать еще 8 ответов" under a root comment
        expandReplies: '.comments2--root-comment__btnWithSpinner-jK > button[aria-label^="Показать"]',
        // The clickable "ещё" span/element within a long comment that needs expansion
        expandLongComment: '.comments2--rich-text-clamp__isInteractive-1s span.comments2--rich-text__expandWord-2_',
        // The main button at the bottom to load more root comments, usually "Показать ещё"
        loadMoreRootComments: 'button[data-gvdytw8xp="show-more-comments"][aria-label="Показать ещё"]'
    };

    function clickElement(element, elementType) {
        // Basic visibility check: element exists, has click method, and is rendered (has size/position)
        if (element && typeof element.click === 'function' && element.offsetParent !== null) {
            console.log(`[Dzen Expander] Clicking ${elementType}:`, element);
            try {
                 element.click();
                 return true; // Click attempt successful
            } catch (e) {
                 console.error(`[Dzen Expander] Error clicking ${elementType}:`, e, element);
                 return false; // Click failed
            }
        }
        return false; // Element not found, not clickable, or not visible
    }

    function runExpansionCycle() {
        if (stopped) return;

        let actionPerformed = false;

        console.log("[Dzen Expander] Running check cycle...");

        // 1. Expand long comment texts ("ещё")
        // We query all potential elements each time as new ones might appear.
        document.querySelectorAll(SELECTORS.expandLongComment).forEach(element => {
            // Check again if it's still visible/relevant before clicking
            if (element.offsetParent !== null) {
                 if (clickElement(element, "long comment 'ещё'")) {
                     actionPerformed = true;
                     // Small pause might help if rapid clicks cause issues, but usually not needed here
                     // await new Promise(resolve => setTimeout(resolve, 50));
                 }
            }
        });

        // 2. Expand replies ("Показать еще X ответов")
        // Click only *one* reply button per cycle to allow the DOM to update before the next check.
        // Otherwise, clicking multiple rapidly might interfere with each other.
        const replyButton = document.querySelector(SELECTORS.expandReplies);
        if (replyButton) { // Check if *any* such button exists
            if (clickElement(replyButton, "expand replies button")) {
                actionPerformed = true;
            }
        }

        // 3. Load more root comments ("Показать ещё")
        const loadMoreButton = document.querySelector(SELECTORS.loadMoreRootComments);
        if (loadMoreButton) { // Check if the main load more button exists
            if (clickElement(loadMoreButton, "load more comments button")) {
                actionPerformed = true;
            }
        }


        // --- Stop condition check ---
        if (actionPerformed) {
            checksWithoutAction = 0; // Reset counter if we performed an action
        } else {
            checksWithoutAction++;
            console.log(`[Dzen Expander] No expandable elements found (Check ${checksWithoutAction}/${MAX_CHECKS_WITHOUT_ACTION})`);
            if (checksWithoutAction >= MAX_CHECKS_WITHOUT_ACTION) {
                stopScript("No actions performed for several checks.");
            }
        }
    }

    function stopScript(reason) {
        if (intervalId) {
            clearInterval(intervalId);
            intervalId = null;
            stopped = true;
            console.log(`[Dzen Expander] Script stopped. Reason: ${reason}`);
        }
    }

    // --- Initialization ---
    console.log("[Dzen Expander] Script loaded. Waiting for page idle...");

    // Use setTimeout to delay the start slightly after document idle, ensuring more elements are ready.
    setTimeout(() => {
        if (stopped) return; // Check if manually stopped before starting
        console.log("[Dzen Expander] Starting expansion checks...");
        // Run one initial check immediately
        runExpansionCycle();
        // Then start the interval
        intervalId = setInterval(runExpansionCycle, CHECK_INTERVAL_MS);
    }, 2000); // Start checks 2 seconds after page idle

    // --- Manual Stop Function ---
    // You can type `stopDzenExpander()` in the console to stop the script manually.
    window.stopDzenExpander = () => {
         stopScript("Manually stopped by user via console command.");
    };
    console.log("[Dzen Expander] Run `window.stopDzenExpander()` in the console to stop the script manually at any time.");

})();