Skip to content

Instantly share code, notes, and snippets.

@Wikinaut
Last active June 5, 2025 15:15
Show Gist options
  • Save Wikinaut/2237d5fcf9db551e31222f7206a10bbf to your computer and use it in GitHub Desktop.
Save Wikinaut/2237d5fcf9db551e31222f7206a10bbf to your computer and use it in GitHub Desktop.
Get TAGESSPIEGEL Kommentare as text (Greasemonkey Script)
// ==UserScript==
// @name Coral Talk Auto Load All Comments mit Autor, Zeit, Zustimmungen und Download (mit Thread-Erkennung)
// @namespace http://tampermonkey.net/
// @version 2.3
// @description Automatisch „weitere Kommentare anzeigen“ klicken mit Autor, Zeit, Zustimmungen und Thread-Einrückung im Download-Text.
// @author ChatGPT
// @match https://coral.tagesspiegel.de/embed/stream*
// @grant none
// ==/UserScript==
(function() {
'use strict';
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const statusBtn = document.createElement('button');
statusBtn.style.position = 'fixed';
statusBtn.style.top = '10px';
statusBtn.style.right = '10px';
statusBtn.style.padding = '10px 20px';
statusBtn.style.borderRadius = '5px';
statusBtn.style.fontSize = '14px';
statusBtn.style.fontWeight = 'bold';
statusBtn.style.boxShadow = '0 2px 6px rgba(0,0,0,0.3)';
statusBtn.style.zIndex = 9999;
statusBtn.style.color = 'white';
statusBtn.style.border = 'none';
statusBtn.style.cursor = 'default';
statusBtn.disabled = true;
document.body.appendChild(statusBtn);
let blinkInterval;
function startLoadingStatus() {
statusBtn.textContent = 'Lade Kommentare...';
statusBtn.style.backgroundColor = '#d32f2f';
statusBtn.disabled = true;
statusBtn.style.cursor = 'default';
blinkInterval = setInterval(() => {
statusBtn.style.opacity = statusBtn.style.opacity === '0.5' ? '1' : '0.5';
}, 600);
}
function showFinishedStatus(count) {
clearInterval(blinkInterval);
statusBtn.style.opacity = '1';
statusBtn.textContent = `✅ ${count} Kommentare geladen. Klicke für Textdownload`;
statusBtn.style.backgroundColor = '#4caf50';
statusBtn.disabled = false;
statusBtn.style.cursor = 'pointer';
}
function gatherAllCommentsText() {
const commentContainers = document.querySelectorAll('.talk-stream-comment');
let allText = '';
let count = 0;
commentContainers.forEach((container) => {
// Autor
let author = 'Unbekannter Autor';
const header = container.querySelector('.talk-stream-comment-header');
if (header) {
const authorSpan = header.querySelector('span');
if (authorSpan && authorSpan.innerText.trim() !== '') {
author = authorSpan.innerText.trim();
}
}
// Zeitpunkt
let date = 'Unbekannter Zeitpunkt';
const timeEl = container.querySelector('time');
if (timeEl && timeEl.innerText.trim() !== '') {
date = timeEl.innerText.trim();
} else if (header) {
const headerText = header.innerText.trim();
const afterAuthor = headerText.replace(author, '').trim();
if (afterAuthor.length > 0) date = afterAuthor;
}
// Kommentartext
const textEl = container.querySelector('.talk-stream-comment-content');
const text = textEl ? textEl.innerText.trim() : '';
// Zustimmung
let votes = '0 Zustimmungen';
const voteEls = Array.from(container.querySelectorAll('span, button')).filter(el =>
el.textContent.toLowerCase().includes('zustimmen')
);
for (const el of voteEls) {
const match = el.textContent.match(/(\d+)/);
if (match && match[1]) {
votes = match[1] + ' Zustimmungen';
break;
}
}
if (text) {
count++;
// Prüfe auf @Erwähnung als Zeichen für Antwort
const isReply = /^@\S+/.test(text.split('\n')[0].trim());
const prefix = isReply ? '| ' : '';
allText += `${prefix}Kommentar ${count} von ${author} am ${date} (${votes}):\n${prefix}${text.replace(/\n/g, '\n' + prefix)}\n\n---\n\n`;
}
});
return { text: allText.trim(), count };
}
function downloadTextFile(filename, text) {
const blob = new Blob([text], {type: 'text/plain;charset=utf-8'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 0);
}
statusBtn.addEventListener('click', () => {
if (statusBtn.disabled) return;
const { text, count } = gatherAllCommentsText();
if (!text) {
alert('Keine Kommentare gefunden zum Download.');
return;
}
const filename = 'Kommentare_Tagesspiegel.txt';
downloadTextFile(filename, text);
});
async function clickLoadMoreLoop() {
console.log('Starte automatisches Laden aller Kommentare...');
startLoadingStatus();
let attemptsWithoutButton = 0;
let noNewCountAttempts = 0;
while (true) {
const buttons = Array.from(document.querySelectorAll('button'));
const button = buttons.find(b => {
const text = b.textContent.trim().toLowerCase();
return text.startsWith('weitere kommentare anzeigen') || text.startsWith('alle antworten anzeigen')
});
if (button && !button.disabled) {
console.log('„weitere Kommentare anzeigen“-Button gefunden, klicke...');
const lastCount = document.querySelectorAll('.talk-stream-comment').length;
button.click();
// Warte bis neue Kommentare sichtbar sind oder Timeout (max 10s)
const maxWait = 20000; // 10 Sekunden max warten
const interval = 5000; // alle 5000 ms prüfen
let waited = 0;
while (waited < maxWait) {
await wait(interval);
waited += interval;
const currentCount = document.querySelectorAll('.talk-stream-comment').length;
if (currentCount > lastCount) {
// neue Kommentare da, weiter
break;
}
}
noNewCountAttempts = 0; // Reset weil neue Kommentare kamen
attemptsWithoutButton = 0; // Reset
} else {
attemptsWithoutButton++;
noNewCountAttempts++;
if (attemptsWithoutButton >= 10 || noNewCountAttempts >= 10) {
console.log('Kein „weitere Kommentare anzeigen“-Button mehr gefunden oder keine neuen Kommentare, fertig.');
const { count } = gatherAllCommentsText();
showFinishedStatus(count);
break;
}
await wait(2000);
}
}
}
window.addEventListener('load', () => {
setTimeout(() => {
clickLoadMoreLoop();
}, 2000);
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment