// ==UserScript== // @name MyDealz Kommentarvolltextsuche // @namespace https://mydealz.de/ // @version 1.0 // @description Suchbox fĂĽr Volltextsuche in allen Kommentaren eines Deals / einer Diskussion // @match https://www.mydealz.de/deals/* // @match https://www.mydealz.de/diskussion/* // @match https://www.mydealz.de/feedback/* // @license MIT // @grant none // @downloadURL none // ==/UserScript== (function() { 'use strict'; let newWindow; const API_URL = 'https://www.mydealz.de/graphql'; // Basis-Funktionen function getDealId() { const match = window.location.href.match(/-(\d+)(?=[/?#]|$)/); return match ? match[1] : null; } function extractThreadId() { const mainElement = document.getElementById('main'); if (!mainElement) return null; const dataAttribute = mainElement.getAttribute('data-t-d'); if (!dataAttribute) return null; return JSON.parse(dataAttribute.replace(/"/g, '"')).threadId; } function cleanHTML(html) { return html.replace(/<.*?>/g, ''); } function highlightSearchTerm(text, searchTerm) { return text.replace( new RegExp(searchTerm, 'gi'), match => `${match}` ); } // GraphQL-Funktionen async function fetchGraphQLData(query, variables) { const response = await fetch(API_URL, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({query, variables}) }); if (response.status === 429) { await new Promise(resolve => setTimeout(resolve, 10000)); return fetchGraphQLData(query, variables); } const data = await response.json(); if (data.errors) throw new Error(data.errors[0].message); return data.data.comments; } async function fetchAllPages(query, variables) { let currentPage = 1; let allData = []; while (true) { const data = await fetchGraphQLData(query, {...variables, page: currentPage}); allData.push(...data.items); if (!data.pagination.next) break; currentPage++; } return allData; } async function fetchAllComments() { let allComments = []; let currentPage = 1; let hasMorePages = true; const threadId = extractThreadId(); while (hasMorePages) { const query = ` query comments($filter: CommentFilter!, $limit: Int, $page: Int) { comments(filter: $filter, limit: $limit, page: $page) { items { commentId replyCount } pagination { current next } } } `; const variables = { filter: { threadId: {eq: threadId} }, limit: 100, page: currentPage }; const response = await fetch(API_URL, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({query, variables}) }); const data = await response.json(); if (data.errors) throw new Error(data.errors[0].message); allComments = allComments.concat(data.data.comments.items); hasMorePages = !!data.data.comments.pagination.next; if (hasMorePages) currentPage++; } return allComments; } async function fetchReplies(commentId, threadId) { const query = ` query comments($filter: CommentFilter!, $limit: Int, $page: Int) { comments(filter: $filter, limit: $limit, page: $page) { items { commentId preparedHtmlContent user { userId username } replyCount createdAt parentReply { user { username } } } pagination { current next } } } `; return await fetchAllPages(query, { filter: { mainCommentId: commentId, threadId: {eq: threadId}, order: {direction: "Ascending"} }, limit: 100 }); } async function fetchDataAndReplies(forceReload = false) { const dealId = getDealId(); const threadId = extractThreadId(); const savedComments = JSON.parse(localStorage.getItem('dealComments_' + dealId)) || []; if (!forceReload && savedComments.length > 0) { const allComments = await fetchAllComments(); let totalReplies = 0; allComments.forEach(comment => { totalReplies += comment.replyCount || 0; }); const onlineCommentCount = allComments.length + totalReplies; const localCommentCount = savedComments.reduce((acc, comment) => acc + 1 + (comment.replies?.length || 0), 0); if (localCommentCount < onlineCommentCount) { const newCommentCount = onlineCommentCount - localCommentCount; newWindow.document.getElementById('newCommentsStatus').innerHTML = `Es sind ${newCommentCount} neue Kommentare vorhanden. `; return savedComments; } return savedComments; } const query = ` query comments($filter: CommentFilter!, $limit: Int, $page: Int) { comments(filter: $filter, limit: $limit, page: $page) { items { commentId preparedHtmlContent user { userId username } replyCount createdAt } pagination { current next } } } `; newWindow.document.getElementById('progressBar').style.display = 'block'; let allData = await fetchAllPages(query, { filter: { threadId: {eq: threadId}, order: {direction: "Ascending"} }, limit: 100 }); let totalItems = allData.length + allData.reduce((acc, c) => acc + (c.replyCount || 0), 0); let processedItems = 0; for (const comment of allData) { processedItems++; updateProgress(processedItems, totalItems); if (comment.replyCount > 0) { const replies = await fetchReplies(comment.commentId, threadId); comment.replies = replies; processedItems += replies.length; updateProgress(processedItems, totalItems); } } localStorage.setItem('dealComments_' + dealId, JSON.stringify(allData)); localStorage.setItem('dealComments_' + dealId + '_timestamp', new Date().toISOString()); return allData; } function updateProgress(processed, total) { const percentage = Math.round((processed / total) * 100); newWindow.document.getElementById('progress').innerText = processed === total ? 'Alle Kommentare durchsucht' : `Fortschritt: ${percentage}%`; newWindow.document.getElementById('progressBarFill').style.width = `${percentage}%`; } function processComments(allData, searchTerm) { const outputType = newWindow.document.querySelector('input[name="outputType"]:checked').value; const sortType = newWindow.document.querySelector('input[name="sortType"]:checked').value; const filteredComments = []; let totalComments = allData.length; allData.forEach(comment => { if (comment.preparedHtmlContent.toLowerCase().includes(searchTerm.toLowerCase())) { filteredComments.push({...comment, type: 'comment'}); } if (comment.replies) { comment.replies.forEach(reply => { totalComments++; if (reply.preparedHtmlContent.toLowerCase().includes(searchTerm.toLowerCase())) { filteredComments.push({...reply, type: 'reply'}); } }); } }); filteredComments.sort((a, b) => { return sortType === 'newest' ? b.commentId - a.commentId : a.commentId - b.commentId; }); let html = '
Es wurden ${totalComments} Kommentare durchsucht und ${filteredComments.length} Kommentare mit '${searchTerm}' gefunden.
`; filteredComments.forEach(item => { const dealId = getDealId(); const url = `https://www.mydealz.de/${dealId}#${item.type}-${item.commentId}`; html += `