// ==UserScript== // @name Isoliertes Load All Comments & Expand Replies kann als snippet dienen // @namespace violentmonkey // @version 4.0.1 // @description Load all comments from all pages on MyDealz with optimized performance // @author optimized version // @license MIT // @match https://www.mydealz.de/deals/* // @match https://www.mydealz.de/diskussion/* // @icon https://www.google.com/s2/favicons?sz=64&domain=mydealz.de // @grant none // @downloadURL https://update.greasyfork.icu/scripts/538836/Isoliertes%20Load%20All%20Comments%20%20Expand%20Replies%20kann%20als%20snippet%20dienen.user.js // @updateURL https://update.greasyfork.icu/scripts/538836/Isoliertes%20Load%20All%20Comments%20%20Expand%20Replies%20kann%20als%20snippet%20dienen.meta.js // ==/UserScript== (function() { 'use strict'; // Konfiguration basierend auf dem funktionierenden Original const CONFIG = { REPLY_CHECK_INTERVAL: 500, MAX_CHECKS_WITHOUT_ACTION: 5, CLICK_COOLDOWN_MS: 200, PAGE_TRANSITION_DELAY: 2000, DOM_CHECK_INTERVAL: 100, DOM_TIMEOUT: 10000 }; const REPLY_BUTTON_SELECTOR = 'button[data-t="moreReplies"]:not([disabled])'; // Button-Styles const BUTTON_STYLES = { default: ` position: fixed; bottom: 20px; right: 20px; padding: 8px 16px; background-color: #007bff; color: white; border: none; border-radius: 5px; cursor: pointer; z-index: 9999; font-size: 12px; `, processing: ` position: fixed; bottom: 20px; right: 20px; padding: 8px 16px; background-color: #ff0000; color: white; border: none; border-radius: 5px; cursor: not-allowed; z-index: 9999; font-size: 12px; `, success: ` position: fixed; bottom: 20px; right: 20px; padding: 8px 16px; background-color: #00ff00; color: black; border: none; border-radius: 5px; cursor: default; z-index: 9999; font-size: 12px; ` }; // Button erstellen oder aktualisieren function ensureButton(className, text, style, clickHandler) { let button = document.querySelector(`button.${className}`); if (!button) { button = document.createElement('button'); button.className = className; button.textContent = text; button.style.cssText = style; button.addEventListener('click', clickHandler); document.body.appendChild(button); console.log(`${text} button hinzugefügt.`); } return button; } // Button-Status aktualisieren function updateButtonState(button, state, text, clickCount = 0) { switch (state) { case 'processing': button.textContent = text || 'Verarbeitung...'; button.style.cssText = BUTTON_STYLES.processing; button.disabled = true; break; case 'success': button.textContent = clickCount ? `Fertig (${clickCount} Klicks)` : 'Erfolgreich!'; button.style.cssText = BUTTON_STYLES.success; button.disabled = true; break; default: button.textContent = text; button.style.cssText = BUTTON_STYLES.default; button.disabled = false; } } // Warten auf DOM-Element function waitForElement(selector, minChildren = 1, timeout = CONFIG.DOM_TIMEOUT) { return new Promise((resolve, reject) => { const startTime = Date.now(); const check = () => { const element = document.querySelector(selector); if (element && element.children.length >= minChildren) { resolve(element); } else if (Date.now() - startTime > timeout) { reject(new Error(`Timeout beim Warten auf ${selector} mit mindestens ${minChildren} Kindern`)); } else { setTimeout(check, CONFIG.DOM_CHECK_INTERVAL); } }; check(); }); } // Antworten auf aktueller Seite erweitern async function expandAllReplies() { return new Promise((resolve) => { let totalClicks = 0; let consecutiveChecksWithoutAction = 0; const checkAndClick = async () => { // Nur sichtbare Buttons berücksichtigen const buttons = Array.from(document.querySelectorAll(REPLY_BUTTON_SELECTOR)) .filter(btn => btn.offsetParent !== null); if (buttons.length > 0) { consecutiveChecksWithoutAction = 0; const buttonToClick = buttons[0]; console.log(`Klicke Button: "${buttonToClick.textContent.trim()}"`); try { buttonToClick.click(); totalClicks++; await new Promise(res => setTimeout(res, CONFIG.CLICK_COOLDOWN_MS)); setTimeout(checkAndClick, 0); } catch (e) { console.error("Fehler beim Klicken:", e, buttonToClick); await new Promise(res => setTimeout(res, CONFIG.REPLY_CHECK_INTERVAL)); setTimeout(checkAndClick, 0); } } else { consecutiveChecksWithoutAction++; console.log(`Keine klickbaren Buttons gefunden. Check ${consecutiveChecksWithoutAction}/${CONFIG.MAX_CHECKS_WITHOUT_ACTION}. Warte ${CONFIG.REPLY_CHECK_INTERVAL}ms...`); if (consecutiveChecksWithoutAction < CONFIG.MAX_CHECKS_WITHOUT_ACTION) { setTimeout(checkAndClick, CONFIG.REPLY_CHECK_INTERVAL); } else { console.log(`Erweiterung abgeschlossen. Gesamt Klicks: ${totalClicks}.`); resolve(totalClicks); } } }; checkAndClick(); }); } // Hauptfunktion: Alle Kommentare laden und Antworten erweitern async function loadAllCommentsAndExpandReplies() { const loadButton = ensureButton( 'mydealz-load-all-button', 'Alle Kommentare laden & Antworten erweitern', BUTTON_STYLES.default, loadAllCommentsAndExpandReplies ); // URL normalisieren const baseUrl = window.location.pathname + '?#comments'; if (window.location.href !== window.location.origin + baseUrl) { console.log(`Lade normalisierte URL: ${baseUrl}`); localStorage.setItem('mydealz_script_triggered', 'true'); updateButtonState(loadButton, 'processing', 'Verarbeitung...'); window.location.href = baseUrl; return; } updateButtonState(loadButton, 'processing', 'Verarbeitung...'); let masterCommentList; try { masterCommentList = await waitForElement('ol.commentList.commentList--anchored', 1); } catch (error) { console.log('Keine Kommentarliste gefunden. Skript kann nicht fortfahren.'); updateButtonState(loadButton, 'default', 'Alle Kommentare laden & Antworten erweitern'); return; } const pagination = document.querySelector('nav[role="navigation"][aria-label="Nummerierung"]'); let totalPages = 1; if (pagination) { const pageButtons = pagination.querySelectorAll('.comments-pagi-page'); if (pageButtons.length > 0) { const lastPageButton = pageButtons[pageButtons.length - 1]; totalPages = parseInt(lastPageButton.textContent.trim(), 10) || 1; console.log(`Gesamtseiten erkannt: ${totalPages}`); } } const allComments = new Map(); // Kommentare von jeder Seite mit erweiterten Antworten sammeln for (let page = 1; page <= totalPages; page++) { console.log(`Verarbeite Seite ${page}...`); try { masterCommentList = await waitForElement('ol.commentList.commentList--anchored', 1); console.log(`Erweitere Antworten auf Seite ${page}...`); await expandAllReplies(); const comments = masterCommentList.querySelectorAll('.commentList-item'); console.log(`${comments.length} Kommentare auf Seite ${page} gefunden (mit Antworten)`); comments.forEach(comment => { const commentId = comment.getAttribute('data-id'); if (commentId && !allComments.has(commentId)) { allComments.set(commentId, comment.cloneNode(true)); } }); if (page < totalPages) { const nextButton = pagination.querySelector('button[aria-label="Nächste Seite"]'); if (!nextButton || nextButton.hasAttribute('disabled')) { console.log(`Kein "Nächste Seite" Button verfügbar oder deaktiviert auf Seite ${page}. Stoppe.`); break; } console.log(`Klicke "Nächste Seite" für Seite ${page + 1}...`); nextButton.click(); await new Promise(res => setTimeout(res, CONFIG.PAGE_TRANSITION_DELAY)); } } catch (error) { console.error(`Fehler beim Verarbeiten von Seite ${page}:`, error); } } // Alle gesammelten Kommentare anhängen masterCommentList = document.querySelector('ol.commentList.commentList--anchored'); if (masterCommentList) { console.log(`Vor dem Hinzufügen hat die Master-Liste ${masterCommentList.children.length} Elemente`); masterCommentList.innerHTML = ''; allComments.forEach(comment => { masterCommentList.appendChild(comment); }); console.log(`Nach dem Hinzufügen hat die Master-Liste ${masterCommentList.children.length} Elemente`); console.log(`${allComments.size} eindeutige Kommentare mit Antworten hinzugefügt.`); updateButtonState(loadButton, 'success', 'Erfolgreich!', allComments.size); } else { console.log('Master-Kommentarliste nach Verarbeitung nicht gefunden. Kann Kommentare nicht anhängen.'); updateButtonState(loadButton, 'default', 'Alle Kommentare laden & Antworten erweitern'); } localStorage.removeItem('mydealz_script_triggered'); } // Buttons initialisieren function initializeButtons() { ensureButton( 'mydealz-load-all-button', 'Alle Kommentare laden & Antworten erweitern', BUTTON_STYLES.default, loadAllCommentsAndExpandReplies ); } // Auto-Run nur wenn von vorheriger Seite ausgelöst if (window.location.hash === '#comments' && localStorage.getItem('mydealz_script_triggered') === 'true') { console.log('Button wurde zuvor geklickt. Auto-Run des Skripts auf #comments...'); loadAllCommentsAndExpandReplies(); } else if (document.readyState === 'complete') { initializeButtons(); } else { window.addEventListener('load', () => { initializeButtons(); }); } console.log('MyDealz Comment Enhancer Skript (Optimiert) initialisiert.'); })();