您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Exportiert alle Kommentare eines MyDealz-Threads über alle Seiten als TXT (inkl. Fortschritt, Copy-All, Save-TXT, Popup-Blocker-Erkennung)
当前为
// ==UserScript== // @name MyDealz | Kommentar-Export über alle Seiten // @namespace violentmonkey // @version 2.0 // @description Exportiert alle Kommentare eines MyDealz-Threads über alle Seiten als TXT (inkl. Fortschritt, Copy-All, Save-TXT, Popup-Blocker-Erkennung) // @match https://www.mydealz.de/diskussion/* // @match https://www.mydealz.de/deals/* // @match https://www.mydealz.de/gutscheine/* // @icon https://www.mydealz.de/assets/img/emojis/cool_b7b27.svg // @grant none // ==/UserScript== (function () { 'use strict'; // Selektoren const SELECTORS = { REPLY_BTN: 'button[data-t="moreReplies"]:not([disabled])', NEXT_PAGE: 'button[aria-label="Nächste Seite"]:not([disabled])', FIRST_PAGE: 'button[aria-label="Erste Seite"]:not([disabled])', LAST_PAGE: 'button[aria-label="Letzte Seite"]', CURRENT_PAGE: 'button[aria-label="Aktuelle Seite"]', COMMENT_LINK: 'a[href*="#comments"].button--type-text', COMMENT_ARTICLE: 'article.comment', THREAD_TITLE: '.thread-title .text--b.size--all-xl.size--fromW3-xxl' }; const INTERVAL = { CHECK: 500, CLICK: 200, PAGE: 2000 }; let collectedComments = []; let totalComments = 0; let exportBtn = null; const KI_LINKS = [ { id: 'chatgptBtn', label: 'chatgpt', url: 'https://chatgpt.com/' }, { id: 'perplexityBtn', label: 'perplexity', url: 'https://www.perplexity.ai/' }, { id: 'grokBtn', label: 'grok', url: 'https://grok.com/' }, { id: 'geminiBtn', label: 'gemini', url: 'https://gemini.google.com/' }, { id: 'mistralBtn', label: 'mistral', url: 'https://chat.mistral.ai/chat' }, { id: 'claudeBtn', label: 'claude', url: 'https://claude.ai/' } ]; const sleep = ms => new Promise(r => setTimeout(r, ms)); function pageNum(sel) { const el = document.querySelector(sel); if (!el) return null; const m = el.textContent.match(/\d+/); return m ? parseInt(m[0], 10) : null; } function getTotalComments() { const a = document.querySelector(SELECTORS.COMMENT_LINK); if (!a) return 0; const m = a.textContent.match(/\d+/); return m ? parseInt(m[0], 10) : 0; } async function clickAllReplies() { while (true) { const btn = document.querySelector(SELECTORS.REPLY_BTN); if (!btn || btn.disabled || btn.offsetParent === null) break; btn.click(); await sleep(INTERVAL.CLICK); } } function collectCommentsOnPage() { const articles = document.querySelectorAll(SELECTORS.COMMENT_ARTICLE); for (const article of articles) { const bodyNode = article.querySelector('.comment-body .userHtml-content'); const text = bodyNode ? bodyNode.textContent.replace(/\s+/g, ' ').trim() : ''; const reactionsBtn = article.querySelector('button.comment-reactions'); let like = 0, helpful = 0, funny = 0; if (reactionsBtn) { const likeSpan = reactionsBtn.querySelector('.comment-like'); const helpfulSpan = reactionsBtn.querySelector('.comment-helpful'); const funnySpan = reactionsBtn.querySelector('.comment-funny'); like = likeSpan ? parseInt(likeSpan.textContent.trim(), 10) || 0 : 0; helpful = helpfulSpan ? parseInt(helpfulSpan.textContent.trim(), 10) || 0 : 0; funny = funnySpan ? parseInt(funnySpan.textContent.trim(), 10) || 0 : 0; } collectedComments.push( `(Gefällt mir: ${like} | Hilfreich: ${helpful} | Lustig: ${funny} | ${text})` ); } return articles.length; } function updateProgress(pageCollected, page, last) { const pct = totalComments ? Math.round(collectedComments.length / totalComments * 100) : 0; exportBtn.textContent = `Kommentare exportieren (${collectedComments.length} von ${totalComments} | Seite ${page}/${last} | ${pct}%)`; } async function goNextPage() { const btn = document.querySelector(SELECTORS.NEXT_PAGE); if (btn) { btn.click(); await sleep(INTERVAL.PAGE); return true; } return false; } function getThreadTitleAndUrl() { let title = ''; const el = document.querySelector(SELECTORS.THREAD_TITLE); if (el) { title = el.textContent.trim(); } else { title = document.title.replace(/\|.*$/, '').trim(); } const url = window.location.href.replace(/#.*$/, ''); return { title, url }; } function buildIntroText() { const { title, url } = getThreadTitleAndUrl(); return ( `# Zusammenfassung der Kommentare zur MyDealz-Diskussion [${title}](${url}) ## Anweisung Fasse die bereitgestellten Benutzerkommentare zu der Diskussion zusammen, indem du die Hauptpunkte und gemeinsamen Themen identifizierst, die diskutiert werden. Füge relevante Zitate aus den Kommentaren hinzu, um die Schlüsselpunkte zu illustrieren, und formatiere diese Zitate als Markdown-Zitat-Blöcke (mit > ). Falls zutreffend, erwähne unterschiedliche Meinungen oder besonders aufschlussreiche Beiträge. Präsentiere die Zusammenfassung strikt im Markdown-Format, wobei du Überschriften (mit #, ## etc.) und Aufzählungspunkte (mit - oder * ) verwendest, um die Informationen klar zu organisieren. Stelle sicher, dass die Formatierung konsistent ist und den Markdown-Syntax-Regeln entspricht, sodass sie direkt in einen Markdown-Interpreter eingefügt werden kann. Erstelle die Zusammenfassung in derselben Sprache wie die Kommentare. Die zusammenzufassenden Daten liegen im Format (Gefällt mir: n | Hilfreich: n | Lustig: n | Kommentar) vor. Besonders häufig bewertete Kommentare kannst du auch mit ✅👍😅 kennzeichnen. ## Daten ---` ); } function openExportWindow(text) { // Fenstergröße: breiter und höher, kein Browser-Scrollbalken const w = window.open('', 'blank', 'width=900,height=700,resizable=yes,scrollbars=no'); if (!w) { alert('Popup blockiert! Bitte Popup-Blocker für diese Seite deaktivieren.'); return; } const { title } = getThreadTitleAndUrl(); const filename = title || 'mydealz-comments'; w.document.title = 'MyDealz Kommentar-Export'; w.document.head.innerHTML = ` <style> html, body { height: 100%; margin: 0; padding: 0; box-sizing: border-box; overflow: hidden; } body { font-family: sans-serif; margin: 20px; min-width: 600px; min-height: 400px; box-sizing: border-box; display: flex; flex-direction: column; align-items: stretch; height: 100vh; } .export-btns { display: flex; align-items: center; margin-bottom: 8px; flex-wrap: wrap; } .ki-btn-row { display: flex; align-items: center; margin-bottom: 16px; flex-wrap: wrap; } button { display: inline-flex; align-items: center; padding: 10px 16px; margin-right: 8px; margin-bottom: 0; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; } #copyBtn { background: #d32f2f; color: #fff; } #saveBtn { background: #007bff; color: #fff; } #copiedMsg { min-width: 60px; display: inline-block; margin-right: 8px; margin-left: 0; color: #4caf50; font-weight: bold; opacity: 0; transition: opacity .3s; text-align: left; } .ki-btn { background: #eee; color: #333; margin-bottom: 0; } .main-content { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; } pre { flex: 1 1 auto; min-height: 200px; max-height: 70vh; white-space: pre-wrap; word-wrap: break-word; border: 1px solid #ccc; padding: 12px; border-radius: 4px; overflow: auto; margin: 0; background: #fafafa; } </style> `; w.document.body.innerHTML = ` <div class="export-btns"> <button id="copyBtn">Copy All</button> <button id="saveBtn">Save .txt</button> <span id="copiedMsg"> </span> </div> <div class="ki-btn-row"> ${KI_LINKS.map(btn => `<button class="ki-btn" id="${btn.id}">${btn.label}</button>`).join('')} </div> <div class="main-content"> <pre id="exportText"></pre> </div> `; const pre = w.document.getElementById('exportText'); pre.textContent = text; const btnC = w.document.getElementById('copyBtn'); const btnS = w.document.getElementById('saveBtn'); const msg = w.document.getElementById('copiedMsg'); btnC.onclick = () => { w.navigator.clipboard.writeText(text).then(() => { msg.textContent = 'Copied!'; msg.style.opacity = 1; setTimeout(() => { msg.style.opacity = 0; msg.textContent = '\xa0'; // Platzhalter (White Space) }, 2000); }); }; btnS.onclick = () => { const blob = new Blob([text], { type: 'text/plain;charset=utf-8' }); const url = w.URL.createObjectURL(blob); const a = w.document.createElement('a'); a.href = url; a.download = filename + '.txt'; w.document.body.appendChild(a); a.click(); w.URL.revokeObjectURL(url); w.document.body.removeChild(a); }; // KI-Buttons KI_LINKS.forEach(btn => { const el = w.document.getElementById(btn.id); if (el) el.onclick = () => window.open(btn.url, '_blank'); }); } async function runExport() { totalComments = getTotalComments(); collectedComments = []; const first = document.querySelector(SELECTORS.FIRST_PAGE); if (first) { first.click(); await sleep(INTERVAL.PAGE); } while (true) { await clickAllReplies(); const pageCollected = collectCommentsOnPage(); const page = pageNum(SELECTORS.CURRENT_PAGE) || 1; const last = pageNum(SELECTORS.LAST_PAGE) || 1; updateProgress(pageCollected, page, last); if (page >= last) break; const next = await goNextPage(); if (!next) break; } const fullText = buildIntroText() + '\n' + collectedComments.join('\n'); openExportWindow(fullText); exportBtn.textContent = 'Fertig!'; exportBtn.disabled = false; } function injectExportBtn() { exportBtn = document.createElement('button'); exportBtn.textContent = 'Kommentare exportieren'; Object.assign(exportBtn.style, { position: 'fixed', top: '20px', right: '20px', padding: '10px 16px', background: '#d32f2f', color: '#fff', border: 'none', borderRadius: '4px', fontSize: '14px', cursor: 'pointer', zIndex: 9999 }); exportBtn.onclick = () => { exportBtn.disabled = true; exportBtn.textContent = 'Lade...'; runExport(); }; document.body.appendChild(exportBtn); } function ensureStartOnPageOne() { const url = new URL(window.location.href); const isCommentPage = url.hash.includes('comments'); const pageParam = url.searchParams.get('page'); if (pageParam && pageParam !== '1' && isCommentPage) { url.searchParams.set('page', '1'); url.hash = 'comments'; window.location.href = url.toString(); } else { injectExportBtn(); } } if (document.readyState === 'complete') { ensureStartOnPageOne(); } else { window.addEventListener('load', ensureStartOnPageOne); } })();