MyDealz Reactions anzeigen

Erhaltene Reactions auf Userkommentare

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

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

QingJ © 2025

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