您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Zeigt die letzten Kommentare eines Benutzers an
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/528796/1586404/MyDealz%20Comment%20Viewer.js
// ==UserScript== // @name MyDealz Comment Viewer // @namespace http://tampermonkey.net/ // @version 2.3 // @description Zeigt die letzten Kommentare eines Benutzers an // @author MD928835 // @license MIT // ==/UserScript== (function() { 'use strict'; // Globale Funktion definieren window.viewUserComments = async function(username) { // SessionStorage für Kommentare leeren sessionStorage.removeItem('mydealz_comments'); const fetchDealTitle = async (threadId) => { const query = ` query getThread($filter: IDFilter!) { thread(threadId: $filter) { title } }`; try { const response = await fetch("https://www.mydealz.de/graphql", { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query, variables: { filter: { eq: threadId } } }) }); const result = await response.json(); return result.data.thread.title || "Titel nicht verfügbar"; } catch (error) { console.error(`Fehler beim Abrufen des Titels für threadId ${threadId}:`, error); return "Titel nicht verfügbar"; } }; try { // Profilseite abrufen const response = await fetch(`https://www.mydealz.de/profile/${username}?page=1`); if (!response.ok) throw new Error(`HTTP Fehler! Status: ${response.status}`); const html = await response.text(); // Kommentar- und Thread-IDs extrahieren const pattern = /href=https:\/\/www\.mydealz\.de\/.*?-(\d+)#(?:comment|reply)-(\d+)/g; const matches_raw = [...html.matchAll(pattern)]; const ids = matches_raw.map(match => ({ threadId: match[1], commentId: match[2], url: match[0].replace('href=', '') })); // Parallelisierte Anfragen für Kommentare und Titel const fetchPromises = ids.map(async ({ threadId, commentId, url }) => { const commentQuery = ` query comment($id: ID!) { comment(id: $id) { preparedHtmlContent createdAt createdAtTs } }`; try { const [commentResponse, title] = await Promise.all([ fetch("https://www.mydealz.de/graphql", { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: commentQuery, variables: { id: commentId } }) }).then(res => res.json()), fetchDealTitle(threadId) ]); const commentData = commentResponse?.data?.comment; if (commentData) { const comment = commentData.preparedHtmlContent.replace(/]*>/g, ''); const date = new Date(commentData.createdAtTs * 1000) .toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: '2-digit', hour: '2-digit', minute: '2-digit' }) .replace(',', ''); return { html: `<div class="comment-item"> <div class="comment-header"> <a href="${url}" target="_blank" class="comment-title">${title}</a> <span class="comment-date">${date}</span> </div> <div class="comment-content">${comment}</div> <div class="comment-footer"> <a href="${url}" target="_blank" class="comment-link">Zum Kommentar</a> </div> </div>`, date: commentData.createdAtTs }; } return null; } catch (error) { console.error(`Fehler beim Abrufen des Kommentars ${commentId}:`, error); return null; } }); // Alle Kommentare abrufen und sortieren const comments = (await Promise.all(fetchPromises)) .filter(Boolean) .sort((a, b) => b.date - a.date); // Popup erstellen und anzeigen const popup = document.createElement('div'); popup.id = 'comment-popup'; popup.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 80%; max-width: 800px; max-height: 80vh; background: white; border-radius: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); z-index: 10000; display: flex; flex-direction: column; overflow: hidden; `; // Header const header = document.createElement('div'); header.className = 'bubble-button-background'; header.style.cssText = ` padding: 15px; background: #0277bd; color: white; font-weight: bold; display: flex; justify-content: space-between; align-items: center; `; header.innerHTML = ` <span>Kommentare von ${username}</span> <button id="close-popup" style="background: none; border: none; color: white; cursor: pointer; font-size: 20px;">×</button> `; // Sortieroptionen const sortOptions = document.createElement('div'); sortOptions.className = 'comment-sorting-options'; sortOptions.style.cssText = ` padding: 10px 15px; border-bottom: 1px solid #eee; display: flex; gap: 10px; `; sortOptions.innerHTML = ` <span>Kommentare sortieren nach</span> <label> <input type="radio" name="sort" value="all" checked> alle </label> <label> <input type="radio" name="sort" value="chrono"> chronologisch </label> <label> <input type="radio" name="sort" value="thread"> beitragschronologisch </label> `; // Kommentare Container const commentsContainer = document.createElement('div'); commentsContainer.style.cssText = ` padding: 15px; overflow-y: auto; flex-grow: 1; `; // Kommentare anzeigen commentsContainer.innerHTML = comments.map(comment => comment.html).join('<hr style="margin: 15px 0; border: 0; border-top: 1px solid #eee;">'); // Komponenten zusammenfügen popup.appendChild(header); popup.appendChild(sortOptions); popup.appendChild(commentsContainer); document.body.appendChild(popup); // Event-Listener für Schließen-Button document.getElementById('close-popup').addEventListener('click', () => { document.body.removeChild(popup); }); // Event-Listener für Sortierung const sortRadios = sortOptions.querySelectorAll('input[name="sort"]'); sortRadios.forEach(radio => { radio.addEventListener('change', () => { const sortValue = radio.value; let sortedComments; if (sortValue === 'chrono') { sortedComments = [...comments].sort((a, b) => b.date - a.date); } else if (sortValue === 'thread') { // Hier müsste eine threadbasierte Sortierung implementiert werden sortedComments = [...comments]; } else { sortedComments = [...comments]; } commentsContainer.innerHTML = sortedComments.map(comment => comment.html).join('<hr style="margin: 15px 0; border: 0; border-top: 1px solid #eee;">'); }); }); // Schließen bei Klick außerhalb document.addEventListener('click', function closePopup(e) { if (!popup.contains(e.target) && e.target.id !== 'view-comments-btn') { document.body.removeChild(popup); document.removeEventListener('click', closePopup); } }); // Escape-Taste zum Schließen document.addEventListener('keydown', function escapeClose(e) { if (e.key === 'Escape') { document.body.removeChild(popup); document.removeEventListener('keydown', escapeClose); } }); } catch (error) { console.error('Fehler beim Abrufen der Kommentare:', error); alert('Fehler beim Abrufen der Kommentare: ' + error.message); } }; // Button zu Benutzerprofilen hinzufügen const addViewCommentsButton = () => { const userProfileHeader = document.querySelector('.userProfile-header'); if (userProfileHeader) { const username = window.location.pathname.split('/').pop(); const buttonContainer = document.createElement('div'); buttonContainer.style.marginTop = '10px'; buttonContainer.innerHTML = ` <button id="view-comments-btn" class="userProfile-actionButton" style="margin-right: 10px;"> Kommentare anzeigen </button> `; userProfileHeader.appendChild(buttonContainer); document.getElementById('view-comments-btn').addEventListener('click', (e) => { e.stopPropagation(); viewUserComments(username); }); } }; // MutationObserver für dynamisch geladene Inhalte const observer = new MutationObserver((mutations) => { if (window.location.pathname.includes('/profile/')) { addViewCommentsButton(); observer.disconnect(); } }); // Beobachtung starten observer.observe(document.body, { childList: true, subtree: true }); // Initiale Prüfung if (window.location.pathname.includes('/profile/')) { addViewCommentsButton(); } })();