MyDealz User Reactions

Userreactions auf die Kommentare eines User ermitteln

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/531609/1564456/MyDealz%20User%20Reactions.js

  1. async function viewReactions(username) {
  2. function checkPopups() {
  3. const popup = window.open(null, '_blank', 'width=100,height=100');
  4. if (!popup || popup.closed) {
  5. alert("Bitte PopUps für diese Seite erlauben und erneut versuchen.");
  6. return false;
  7. }
  8. popup.close();
  9. return true;
  10. }
  11. if (!checkPopups()) return;
  12. let stopProcessing = false;
  13. const YEAR_IN_MS = 365 * 864e5;
  14. const n = username;
  15. let p = 0;
  16. const results = [];
  17. async function fetchWithRetry(url, options, maxRetries = 5) {
  18. for (let i = 0; i < maxRetries; i++) {
  19. if (stopProcessing) return null;
  20. try {
  21. const response = await fetch(url, options);
  22. if (response.status === 429) {
  23. progressUI.addProgressDetail('wait');
  24. if (i === maxRetries - 1) {
  25. alert("Der Server ist zur Zeit überlastet. Bitte später erneut versuchen.");
  26. progressUI.dialog.remove();
  27. window.stop();
  28. location.reload(true);
  29. return null;
  30. }
  31. await new Promise(t => setTimeout(t, 5000));
  32. continue;
  33. }
  34. return response;
  35. } catch (e) {
  36. if (i === maxRetries - 1) {
  37. progressUI.dialog.remove();
  38. throw e;
  39. }
  40. }
  41. }
  42. return null;
  43. }
  44. const firstPageResponse = await fetchWithRetry(`https://www.mydealz.de/profile/${n}?page=1`);
  45. if (!firstPageResponse) return;
  46. const firstPageHtml = await firstPageResponse.text();
  47. if (p === 0) {
  48. const match = firstPageHtml.match(/window\.__INITIAL_STATE__.*?"lastPage":(\d+)/);
  49. p = match ? parseInt(match[1]) : 1;
  50. }
  51. const progressUI = createProgressDialog(username, p);
  52. for (let i = 1; i <= p; i++) {
  53. if (stopProcessing) break;
  54. const pageResponse = i === 1 ?
  55. { text: () => firstPageHtml } :
  56. await fetchWithRetry(`https://www.mydealz.de/profile/${n}?page=${i}`);
  57. if (!pageResponse) break;
  58. const pageText = await pageResponse.text();
  59. progressUI.updateProgress(i);
  60. const matches = [...pageText.matchAll(/href=(https:\/\/www\.mydealz\.de\/.*?-(\d+)#(?:comment|reply)-(\d+))/g)];
  61. const wrapper = document.createElement('div');
  62. wrapper.innerHTML = pageText;
  63. // Neue Methode zur Titelextraktion
  64. const titles = [];
  65. const titleElements = wrapper.querySelectorAll('.size--all-xs.color--text-TranslucentSecondary.space--mt-1');
  66. titleElements.forEach(element => {
  67. titles.push(element.textContent);
  68. });
  69. for (let j = 0; j < matches.length; j++) {
  70. if (stopProcessing) break;
  71. const match = matches[j];
  72. try {
  73. const reactionsResponse = await fetchWithRetry("https://www.mydealz.de/graphql", {
  74. method: 'POST',
  75. headers: { 'Content-Type': 'application/json' },
  76. body: JSON.stringify({
  77. query: `query commentReactions($commentId:ID!){commentReactions(commentId:$commentId){counts{type count}}}`,
  78. variables: { commentId: match[3] }
  79. })
  80. });
  81. if (!reactionsResponse) break;
  82. progressUI.addProgressDetail('comment');
  83. const reactionsData = await reactionsResponse.json();
  84. const counts = reactionsData.data.commentReactions.counts;
  85. const likes = counts.find(x => x.type === "LIKE")?.count || 0;
  86. const funny = counts.find(x => x.type === "FUNNY")?.count || 0;
  87. const helpful = counts.find(x => x.type === "HELPFUL")?.count || 0;
  88. const commentDateResponse = await fetchWithRetry("https://www.mydealz.de/graphql", {
  89. method: 'POST',
  90. headers: { 'Content-Type': 'application/json' },
  91. body: JSON.stringify({
  92. query: 'query comment($id:ID!){comment(id:$id){createdAt}}',
  93. variables: { id: match[3] }
  94. })
  95. });
  96. if (!commentDateResponse) break;
  97. const createdAt = (await commentDateResponse.json()).data.comment.createdAt;
  98. if (new Date(createdAt).getTime() < Date.now() - YEAR_IN_MS) {
  99. progressUI.dialog.remove();
  100. const resultWindow = window.open("", "", "width=800,height=600");
  101. resultWindow.document.write(`
  102. <style>
  103. body { font-family: Arial, sans-serif; font-size: 14px; color: #333; background-color: #f5f5f5; }
  104. .result-container { background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
  105. .result-item { border-bottom: 1px solid #ddd; padding: 10px 0; display: flex; }
  106. .result-item:last-child { border-bottom: none; }
  107. .reactions { min-width: 100px; }
  108. .date { min-width: 150px; margin: 0 15px; }
  109. a { color: #2c7cbc; text-decoration: none; }
  110. a:hover { text-decoration: underline; }
  111. h2 { color: #2c7cbc; }
  112. .title { flex-grow: 1; }
  113. </style>
  114. <div class="result-container">
  115. <h2>Auswertung der Reactions für ${n}</h2>
  116. ${results.map(x => `
  117. <div class="result-item">
  118. <span class="reactions">L:${x.l} F:${x.f} H:${x.h}${x.h > 2 ? "*" : ""}</span>
  119. <span class="date">${x.date}</span>
  120. <a href="${x.url}" target="_blank" class="title">${x.title}</a>
  121. </div>
  122. `).join('')}
  123. <h3>Zusammenfassung:</h3>
  124. <p>${results[results.length-1].date} - ${results[0].date}</p>
  125. <p>${results.length} Kommentare davon ${results.filter(x => x.l + x.f + x.h > 0).length} mit mindestens einer Reaction</p>
  126. <p>L:${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)</p>
  127. </div>
  128. `);
  129. return;
  130. }
  131. const elementType = match[1].includes('#reply-') ? 'reply' : 'comment';
  132. const url = `https://www.mydealz.de/${match[2]}#${elementType}-${match[3]}`;
  133. results.push({
  134. url: url,
  135. id: match[3],
  136. l: likes,
  137. f: funny,
  138. h: helpful,
  139. date: createdAt,
  140. title: titles[j] || '',
  141. isReply: elementType === 'reply'
  142. });
  143. } catch (e) {
  144. if (e.response?.status === 429) {
  145. await new Promise(resolve => setTimeout(resolve, 5000));
  146. j--;
  147. continue;
  148. }
  149. console.error(e);
  150. }
  151. }
  152. if (i < p) await new Promise(resolve => setTimeout(resolve, 5000));
  153. }
  154. progressUI.dialog.remove();
  155. const resultWindow = window.open("", "", "width=800,height=600");
  156. resultWindow.document.write(`
  157. <style>
  158. body { font-family: Arial, sans-serif; font-size: 14px; color: #333; background-color: #f5f5f5; }
  159. .result-container { background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
  160. .result-item { border-bottom: 1px solid #ddd; padding: 10px 0; display: flex; }
  161. .result-item:last-child { border-bottom: none; }
  162. .reactions { min-width: 100px; }
  163. .date { min-width: 150px; margin: 0 15px; }
  164. a { color: #2c7cbc; text-decoration: none; }
  165. a:hover { text-decoration: underline; }
  166. h2 { color: #2c7cbc; }
  167. .title { flex-grow: 1; }
  168. .checkbox-container { position: sticky; top: 0; background: white; padding: 10px; border-bottom: 1px solid #ddd; margin-bottom: 15px; }
  169. </style>
  170. <div class="result-container">
  171. <div class="checkbox-container">
  172. <h2>Auswertung der Reactions für ${n}</h2>
  173. <label><input type="checkbox" id="reactionsOnly" onclick="toggleReactionsOnly()"> Nur Kommentare mit Reactions anzeigen</label>
  174. </div>
  175. <div id="results-list">
  176. ${results.map(x => `
  177. <div class="result-item" data-reactions="${x.l+x.f+x.h}">
  178. <span class="reactions">L:${x.l} F:${x.f} H:${x.h}${x.h > 2 ? "*" : ""}</span>
  179. <span class="date">${x.date}</span>
  180. <a href="${x.url}" target="_blank" class="title">${x.title}</a>
  181. </div>
  182. `).join('')}
  183. </div>
  184. <h3>Zusammenfassung:</h3>
  185. <p>${results[results.length-1].date} - ${results[0].date}</p>
  186. <p>${results.length} Kommentare davon ${results.filter(x => x.l + x.f + x.h > 0).length} mit mindestens einer Reaction</p>
  187. <p>L:${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)</p>
  188. </div>
  189. <script>
  190. function toggleReactionsOnly() {
  191. const checkbox = document.getElementById('reactionsOnly');
  192. const items = document.querySelectorAll('.result-item');
  193. items.forEach(item => {
  194. if (checkbox.checked && item.getAttribute('data-reactions') == 0) {
  195. item.style.display = 'none';
  196. } else {
  197. item.style.display = 'flex';
  198. }
  199. });
  200. }
  201. </script>
  202. `);
  203. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址