Greasy Fork is available in English.

BETA4

Final Beta?

بۇ قوليازمىنى بىۋاسىتە قاچىلاشقا بولمايدۇ. بۇ باشقا قوليازمىلارنىڭ ئىشلىتىشى ئۈچۈن تەمىنلەنگەن ئامبار بولۇپ، ئىشلىتىش ئۈچۈن مېتا كۆرسەتمىسىگە قىستۇرىدىغان كود: // @require https://update.greasyfork.org/scripts/528578/1547297/BETA4.js

// ==UserScript==
// @name MyDealz Reactions Viewer 2025
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Zeigt die Reaktionen auf Kommentare eines Benutzers an
// @author MD928835
// @license MIT
// @match https://www.mydealz.de/profile/*
// ==/UserScript==

(function() {
    'use strict';

    function createProgressDialog(username, maxPages) {
      const dialog = document.createElement('div');
      dialog.style.cssText = 'position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); z-index:9999; background:white; padding:20px; border-radius:8px; box-shadow:0 0 10px rgba(0,0,0,0.3); width:450px;';
      
      dialog.innerHTML = `
        <h2 style="margin-top:0; border-bottom:1px solid #ddd; padding-bottom:10px;">Analysiere Kommentare von ${username}</h2>
        <div style="margin:10px 0;">
          <div id="progressText">Untersuche Aktivitätsseite auf Kommentare (1/${maxPages})</div>
          <div style="background:#eee; height:20px; border-radius:4px; margin:10px 0;">
            <div id="progressBar" style="background:#4CAF50; height:100%; width:0; border-radius:4px;"></div>
          </div>
          <div id="progressDetails" style="font-family:monospace; min-height:20px;"></div>
        </div>
        <div style="text-align:right; margin-top:15px;">
          <button id="cancelButton" style="background-color:#5cb85c; border:1px solid #4cae4c; color:white; padding:6px 12px; border-radius:4px; cursor:pointer;">Auswertung abbrechen</button>
        </div>
      `;
      
      document.body.appendChild(dialog);
      
      document.getElementById('cancelButton').addEventListener('click', () => {
        dialog.remove();
        window.stop();
        location.reload(true);
        return false;
      });
      
      let currentPageDots = 0;
      
      return {
        dialog,
        updateProgress: (currentPage) => {
          const percent = Math.min(((currentPage) / (maxPages + 1)) * 100, 100);
          document.getElementById('progressBar').style.width = `${percent}%`;
          document.getElementById('progressText').textContent = `Untersuche Aktivitätsseite auf Kommentare (${currentPage}/${maxPages})`;
          // Zurücksetzen der Punkte bei neuer Seite
          document.getElementById('progressDetails').textContent = '';
          currentPageDots = 0;
        },
        addProgressDetail: (type) => {
          if (currentPageDots >= 20) return; // Maximal 20 Punkte pro Seite
          
          const details = document.getElementById('progressDetails');
          details.textContent += type === 'wait' ? 'W' : '.';
          currentPageDots++;
        }
      };
    }

    // Funktion global verfügbar machen
    window.viewReactions = async function(username) {
      function checkPopups() {
        const popup = window.open(null, '_blank', 'width=100,height=100');
        if (!popup || popup.closed) {
          alert("Bitte PopUps für diese Seite erlauben und erneut versuchen.");
          return false;
        }
        popup.close();
        return true;
      }
      
      if (!checkPopups()) return;
      
      let stopProcessing = false;
      const YEAR_IN_MS = 365 * 864e5;
      const n = username;
      let p = 0;
      const results = [];
      
      async function fetchWithRetry(url, options, maxRetries = 5) {
        for (let i = 0; i < maxRetries; i++) {
          if (stopProcessing) return null;
          try {
            const response = await fetch(url, options);
            if (response.status === 429) {
              progressUI.addProgressDetail('wait');
              if (i === maxRetries - 1) {
                alert("Der Server ist zur Zeit überlastet. Bitte später erneut versuchen.");
                progressUI.dialog.remove();
                window.stop();
                location.reload(true);
                return null;
              }
              await new Promise(t => setTimeout(t, 5000));
              continue;
            }
            return response;
          } catch (e) {
            if (i === maxRetries - 1) {
              progressUI.dialog.remove();
              throw e;
            }
          }
        }
        return null;
      }
      
      const firstPageResponse = await fetchWithRetry(`https://www.mydealz.de/profile/${n}?page=1`);
      if (!firstPageResponse) return;
      const firstPageHtml = await firstPageResponse.text();
      
      if (p === 0) {
        const match = firstPageHtml.match(/window\.__INITIAL_STATE__.*?"lastPage":(\d+)/);
        p = match ? parseInt(match[1]) : 1;
      }
      
      const progressUI = createProgressDialog(username, p);
      
      for (let i = 1; i <= p; i++) {
        if (stopProcessing) break;
        
        const pageResponse = i === 1 ? 
          { text: () => firstPageHtml } : 
          await fetchWithRetry(`https://www.mydealz.de/profile/${n}?page=${i}`);
        
        if (!pageResponse) break;
        const pageText = await pageResponse.text();
        progressUI.updateProgress(i);
        
        const matches = [...pageText.matchAll(/href=(https:\/\/www\.mydealz\.de\/.*?-(\d+)#(?:comment|reply)-(\d+))/g)];
        const wrapper = document.createElement('div');
        wrapper.innerHTML = pageText;
        
        const titles = [];
        wrapper.querySelectorAll('.userHtml').forEach(e => {
          if (e.textContent.includes('kommentiert')) {
            const strong = e.querySelector('strong');
            if (strong) titles.push(strong.textContent);
          }
        });
        
        for (let j = 0; j < matches.length; j++) {
          if (stopProcessing) break;
          
          const match = matches[j];
          try {
            const reactionsResponse = await fetchWithRetry("https://www.mydealz.de/graphql", {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({
                query: `query commentReactions($commentId:ID!){commentReactions(commentId:$commentId){counts{type count}}}`,
                variables: { commentId: match[3] }
              })
            });
            
            if (!reactionsResponse) break;
            progressUI.addProgressDetail('comment');
            
            const reactionsData = await reactionsResponse.json();
            const counts = reactionsData.data.commentReactions.counts;
            const likes = counts.find(x => x.type === "LIKE")?.count || 0;
            const funny = counts.find(x => x.type === "FUNNY")?.count || 0;
            const helpful = counts.find(x => x.type === "HELPFUL")?.count || 0;
            
            const commentDateResponse = await fetchWithRetry("https://www.mydealz.de/graphql", {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({
                query: 'query comment($id:ID!){comment(id:$id){createdAt}}',
                variables: { id: match[3] }
              })
            });
            
            if (!commentDateResponse) break;
            
            const createdAt = (await commentDateResponse.json()).data.comment.createdAt;
            
            if (new Date(createdAt).getTime() < Date.now() - YEAR_IN_MS) {
              progressUI.dialog.remove();
              const resultWindow = window.open("", "", "width=800,height=600");
              resultWindow.document.write(`<style>.hidden{display:none;}.comment-line{line-height:1;}</style><script>function toggleReactionsOnly(){const c=document.getElementById('reactionsOnly');Array.from(document.getElementsByClassName('comment-line')).forEach(e=>{e.classList.toggle('hidden',c.checked&&e.getAttribute('data-reactions')==0);})}</script><pre><div style="position:sticky;top:0;background:white;padding:5px;border-bottom:1px solid #ccc">Auswertung der Reactions für ${n}<label><input type="checkbox" id="reactionsOnly" onclick="toggleReactionsOnly()"> Nur Kommentare mit Reactions anzeigen</label></div>${results.map(x=>`<div class="comment-line" data-reactions="${x.l+x.f+x.h}"><a href="${x.url}" target="_blank">${x.url}</a>${x.isReply?' ':''}  L:${x.l} F:${x.f} H:${x.h}${x.h>2?"*":""} ${x.date} ${x.title}</div>`).join('')}\n\nZusammenfassung:\n${results[results.length-1].date} - ${results[0].date}\n${results.length} Kommentare davon ${results.filter(x=>x.l+x.f+x.h>0).length} mit mindestens einer Reaction\nL:${results.reduce((a,c)=>a+c.l,0)} F:${results.reduce((a,c)=>a+c.f,0)} H:${results.reduce((a,c)=>a+c.h,0)} davon ${results.filter(x=>x.h>2).length} mit * (mindestens 3 Hilfreich-Bewertungen)</pre>`);
              return;
            }
            
            const elementType = match[1].includes('#reply-') ? 'reply' : 'comment';
            const url = `https://www.mydealz.de/${match[2]}#${elementType}-${match[3]}`;
            
            results.push({
              url: url,
              id: match[3],
              l: likes,
              f: funny,
              h: helpful,
              date: createdAt,
              title: titles[j] || '',
              isReply: elementType === 'reply'
            });
            
          } catch (e) {
            if (e.response?.status === 429) {
              await new Promise(resolve => setTimeout(resolve, 5000));
              j--;
              continue;
            }
            console.error(e);
          }
        }
        
        if (i < p) await new Promise(resolve => setTimeout(resolve, 5000));
      }
      
      progressUI.dialog.remove();
      const resultWindow = window.open("", "", "width=800,height=600");
      resultWindow.document.write(`<style>.hidden{display:none;}.comment-line{line-height:1;}</style><script>function toggleReactionsOnly(){const c=document.getElementById('reactionsOnly');Array.from(document.getElementsByClassName('comment-line')).forEach(e=>{e.classList.toggle('hidden',c.checked&&e.getAttribute('data-reactions')==0);})}</script><pre><div style="position:sticky;top:0;background:white;padding:5px;border-bottom:1px solid #ccc">Auswertung der Reactions für ${n}<label><input type="checkbox" id="reactionsOnly" onclick="toggleReactionsOnly()"> Nur Kommentare mit Reactions anzeigen</label></div>${results.map(x=>`<div class="comment-line" data-reactions="${x.l+x.f+x.h}"><a href="${x.url}" target="_blank">${x.url}</a>${x.isReply?' ':''}  L:${x.l} F:${x.f} H:${x.h}${x.h>2?"*":""} ${x.date} ${x.title}</div>`).join('')}\n\nZusammenfassung:\n${results[results.length-1].date} - ${results[0].date}\n${results.length} Kommentare davon ${results.filter(x=>x.l+x.f+x.h>0).length} mit mindestens einer Reaction\nL:${results.reduce((a,c)=>a+c.l,0)} F:${results.reduce((a,c)=>a+c.f,0)} H:${results.reduce((a,c)=>a+c.h,0)} davon ${results.filter(x=>x.h>2).length} mit * (mindestens 3 Hilfreich-Bewertungen)</pre>`);
    };

    // Füge Button zur Profilseite hinzu, aber nur wenn wir auf einer Profilseite sind
    if (window.location.pathname.startsWith('/profile/')) {
      const username = window.location.pathname.split('/')[2];
      const buttonContainer = document.createElement('div');
      buttonContainer.style.cssText = 'margin-top:10px;';
      
      const button = document.createElement('button');
      button.id = 'showReactionsButton';
      button.textContent = 'Reactions anzeigen';
      button.style.cssText = 'background-color:#5cb85c; border:1px solid #4cae4c; color:white; padding:6px 12px; border-radius:4px; cursor:pointer;';
      
      buttonContainer.appendChild(button);
      
      const targetElement = document.querySelector('.userProfile-header');
      if (targetElement) {
        targetElement.appendChild(buttonContainer);
      }
      
      document.getElementById('showReactionsButton')?.addEventListener('click', () => {
        window.viewReactions(username);
      });
    }
})();