Mydealz User Profil Enhancer

Erweitert die Profilbuttons um zusätzliche Funktionen

  1. // ==UserScript==
  2. // @name Mydealz User Profil Enhancer
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.5.2
  5. // @description Erweitert die Profilbuttons um zusätzliche Funktionen
  6. // @author MD928835
  7. // @license MIT
  8. // @match https://www.mydealz.de/*
  9. // @require https://update.gf.qytechs.cn/scripts/528796/1560683/MyDealz%20Comment%20Viewer.js
  10. // @require https://update.gf.qytechs.cn/scripts/528580/1545878/MyDealz%20Reactions%20Viewer%202025.js
  11. // @grant GM_xmlhttpRequest
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. 'use strict';
  16.  
  17. // Funktion zum Dekodieren von URL-codierten Benutzernamen
  18. function decodeUsername(encodedUsername) {
  19. try {
  20. return decodeURIComponent(encodedUsername);
  21. } catch (e) {
  22. console.error('Fehler beim Dekodieren des Benutzernamens:', e);
  23. return encodedUsername;
  24. }
  25. }
  26.  
  27. // CSS bestehende Elemente ausblenden
  28. const style = document.createElement('style');
  29. style.textContent = `
  30. /* Originalen Button sofort ausblenden */
  31. .popover a.width--all-12.space--mt-2.button:not(.custom-button) {
  32. display: none !important;
  33. }
  34.  
  35. /* Badges sofort ausblenden */
  36. .popover .flex.gap-1 {
  37. visibility: hidden !important;
  38. }
  39.  
  40. /* Neue Buttons normal anzeigen */
  41. .popover .custom-buttons .button {
  42. display: flex !important;
  43. }
  44. `;
  45. document.head.appendChild(style);
  46.  
  47. const observer = new MutationObserver((mutations) => {
  48. mutations.forEach((mutation) => {
  49. const popover = document.querySelector('.popover--visible');
  50. if (popover) {
  51. setTimeout(() => modifyPopup(popover), 100);
  52. }
  53. });
  54. });
  55.  
  56. async function modifyPopup(popover) {
  57. const profileBtn = popover.querySelector('a.width--all-12.space--mt-2.button');
  58. if (!profileBtn || popover.querySelector('.custom-buttons')) return;
  59.  
  60. const encodedUsername = profileBtn.href.split('/profile/')[1];
  61. const username = decodeUsername(encodedUsername);
  62. const container = profileBtn.parentElement;
  63. container.classList.add('custom-buttons');
  64.  
  65. // GraphQL User Metadaten
  66. const query = `query userProfile($username: String) {
  67. user(username: $username) {
  68. joinedAgo isOnline mutable isMuted allowToBeMessaged
  69. }
  70. }`;
  71.  
  72. try {
  73. const response = await fetch('/graphql', {
  74. method: 'POST',
  75. headers: {
  76. 'Content-Type': 'application/json'
  77. },
  78. body: JSON.stringify({
  79. query,
  80. variables: {
  81. username
  82. }
  83. })
  84. });
  85. const data = await response.json();
  86. const {
  87. isOnline,
  88. joinedAgo,
  89. mutable,
  90. isMuted,
  91. allowToBeMessaged
  92. } = data.data.user;
  93.  
  94. // Mitgliedschaftsdauer aktualisieren
  95. const membershipElement = popover.querySelector('.overflow--wrap-off.size--all-s');
  96. if (membershipElement) {
  97. membershipElement.textContent = `Dabei seit ${joinedAgo}`;
  98. }
  99.  
  100. // Zeitangabe von der Profilseite holen
  101. let lastActivityTime = 'unbekannt';
  102. try {
  103. const profileHtml = await fetch(`https://www.mydealz.de/profile/${encodedUsername}`);
  104. const tempDiv = document.createElement('div');
  105. tempDiv.innerHTML = await profileHtml.text();
  106.  
  107. // Den relevanten Bereich finden
  108. const timeElement = tempDiv.querySelector('.userProfile-action-text .color--text-AccentBrand.text--b');
  109. if (timeElement) {
  110. const zeitText = timeElement.parentNode.innerHTML
  111. .split('</span>')[1] // Trennt am schließenden </span>
  112. .split('</div>')[0] // Trennt am schließenden </div>
  113. .trim(); // Entfernt überflüssige Leerzeichen
  114. lastActivityTime = zeitText;
  115. }
  116. } catch (error) {
  117. console.error('Fehler beim Abrufen der Profilseite:', error);
  118. }
  119.  
  120. // Badge-Container durch Online-Status ersetzen
  121. const badgeContainer = popover.querySelector('.flex.gap-1');
  122. if (badgeContainer) {
  123. const statusContainer = document.createElement('div');
  124. statusContainer.className = 'size--all-s space--mt-2 space--mb-4';
  125. const status = isOnline ? 'ON_line' : 'OFF_line';
  126. statusContainer.textContent = `${status}, zuletzt aktiv ${lastActivityTime}`;
  127. badgeContainer.replaceWith(statusContainer);
  128. }
  129.  
  130. // Buttons Container erstellen
  131. const btnContainer = document.createElement('div');
  132. btnContainer.className = 'flex flex--grow-1 gap--all-2';
  133. btnContainer.style.gap = '5px';
  134. btnContainer.style.width = '100%';
  135.  
  136. // Profil Button
  137. const profileButton = document.createElement('a');
  138. profileButton.href = `/profile/${encodedUsername}`;
  139. profileButton.className = 'flex button button--shape-circle button--type-secondary button--mode-default';
  140. profileButton.style.flex = '1';
  141. profileButton.innerHTML = `<svg width="17" height="14" class="icon icon--mail"><use xlink:href="/assets/img/ico_632f5.svg#person"></use></svg><span class="space--ml-2"> Profil </span>`;
  142.  
  143. // Nachricht Button
  144. const messageButton = document.createElement('button');
  145. messageButton.type = 'button';
  146. messageButton.className = 'flex button button--shape-circle button--type-secondary button--mode-default';
  147. messageButton.style.flex = '1';
  148. messageButton.innerHTML = `<svg width="17" height="14" class="icon icon--mail"><use xlink:href="/assets/img/ico_632f5.svg#mail"></use></svg><span class="space--ml-2"> Nachricht </span>`;
  149.  
  150. // Styling für nicht anschreibbar
  151. if (!allowToBeMessaged) {
  152. messageButton.style.color = '#e02020';
  153. messageButton.style.borderColor = '#e02020';
  154. messageButton.style.cursor = 'not-allowed';
  155. messageButton.disabled = true;
  156. messageButton.title = 'Dieser Nutzer möchte keine Nachrichten empfangen';
  157. }
  158. if (allowToBeMessaged) {
  159. messageButton.onclick = async () => {
  160. const encodedUsername = document.querySelector('.popover--visible a[href^="/profile/"]')?.href.split('/profile/')[1];
  161. if (!encodedUsername) return;
  162.  
  163. try {
  164. // GET-Request zur Prüfung des Inhalts
  165. const response = await fetch(`/profile/messages/${encodedUsername}`);
  166. const html = await response.text();
  167. const decodedUsername = decodeUsername(encodedUsername);
  168.  
  169. // Prüfen, ob der Username im HTML vorkommt
  170. const isSpecificMessagePage = html.includes(`<span class="size--all-l text--b space--mr-1">${decodedUsername}</span>`);
  171.  
  172. if (isSpecificMessagePage) {
  173. // Bei existierendem User direkt zur Nachrichtenseite
  174. const win = window.open(`/profile/messages/${encodedUsername}`, '_blank');
  175.  
  176. if (win) {
  177. win.addEventListener('load', () => {
  178. const observer = new MutationObserver((mutations, obs) => {
  179. const sendButton = win.document.querySelector('button[data-t="sendButton"]');
  180. if (sendButton) {
  181. sendButton.click();
  182. obs.disconnect();
  183. }
  184. });
  185.  
  186. observer.observe(win.document.body, {
  187. childList: true,
  188. subtree: true
  189. });
  190.  
  191. setTimeout(() => observer.disconnect(), 3000);
  192. });
  193. }
  194. } else {
  195. // Bei nicht-existierendem User zur Profilseite
  196. const win = window.open(`/profile/${encodedUsername}`, '_blank');
  197.  
  198. if (win) {
  199. win.addEventListener('load', () => {
  200. const observer = new MutationObserver((mutations, obs) => {
  201. const sendButton = win.document.querySelector('button[data-t="sendButton"]');
  202. if (sendButton) {
  203. sendButton.click();
  204. obs.disconnect();
  205. }
  206. });
  207.  
  208. observer.observe(win.document.body, {
  209. childList: true,
  210. subtree: true
  211. });
  212.  
  213. setTimeout(() => observer.disconnect(), 3000);
  214. });
  215. }
  216. }
  217. } catch (error) {
  218. console.error('Fehler beim Prüfen der Nachrichtenseite:', error);
  219. window.open(`/profile/${encodedUsername}`, '_blank');
  220. }
  221. };
  222. };
  223.  
  224. // Buttons hinzufügen
  225. btnContainer.appendChild(profileButton);
  226. btnContainer.appendChild(messageButton);
  227.  
  228. // Alten Button ersetzen
  229. profileBtn.replaceWith(btnContainer);
  230.  
  231. // Statistikbereich finden und "letzte anzeigen" Link hinzufügen
  232. setTimeout(() => {
  233. const kommentareElement = Array.from(popover.querySelectorAll('li.lbox--f.lbox--v-3 .size--all-s'))
  234. .find(el => el.textContent.includes('Kommentare'));
  235.  
  236. if (kommentareElement) {
  237. // "letzte anzeigen" Link erstellen
  238. const linkElement = document.createElement('span');
  239. linkElement.className = 'showCommentsBtn';
  240. linkElement.textContent = 'anzeigen';
  241. linkElement.style.backgroundColor = '#e6f7e6';
  242. linkElement.style.padding = '0 4px';
  243. linkElement.style.borderRadius = '3px';
  244. linkElement.style.cursor = 'pointer';
  245. linkElement.style.marginLeft = '5px';
  246. linkElement.style.fontSize = '14px';
  247.  
  248. linkElement.onclick = () => {
  249. const p = document.querySelector('.popover--visible');
  250. const encodedUsername = p?.querySelector('a[href^="/profile/"]')?.getAttribute('href')?.split('/')[2];
  251. if (!encodedUsername) return;
  252. const username = decodeUsername(encodedUsername);
  253. window.viewUserComments(username);
  254. };
  255.  
  256. // Link zum Kommentare-Element hinzufügen
  257. kommentareElement.appendChild(document.createTextNode(' '));
  258. kommentareElement.appendChild(linkElement);
  259. }
  260. const reactionsElement = Array.from(popover.querySelectorAll('li.lbox--f.lbox--v-3 .size--all-s'))
  261. .find(el => el.textContent.includes('Reaktionen'));
  262.  
  263. if (reactionsElement) {
  264. const linkElement = document.createElement('span');
  265. linkElement.className = 'showReactionsBtn';
  266. linkElement.textContent = 'anzeigen';
  267. linkElement.style.backgroundColor = '#e6f7e6';
  268. linkElement.style.padding = '0 4px';
  269. linkElement.style.borderRadius = '3px';
  270. linkElement.style.cursor = 'pointer';
  271. linkElement.style.marginLeft = '5px';
  272. linkElement.style.fontSize = '14px';
  273.  
  274. linkElement.onclick = () => {
  275. const p = document.querySelector('.popover--visible');
  276. const encodedUsername = p?.querySelector('a[href^="/profile/"]')?.getAttribute('href')?.split('/')[2];
  277. if (!encodedUsername) return;
  278. const username = decodeUsername(encodedUsername);
  279. viewReactions(username);
  280. };
  281.  
  282. reactionsElement.appendChild(document.createTextNode(' '));
  283. reactionsElement.appendChild(linkElement);
  284. }
  285. }, 500);
  286. } catch (error) {
  287. console.error('Fehler:', error);
  288. }
  289. }
  290.  
  291. observer.observe(document.body, {
  292. childList: true,
  293. subtree: true,
  294. attributes: true,
  295. attributeFilter: ['class']
  296. });
  297. })();

QingJ © 2025

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