Mydealz Bookmark Button

Bringt auf Übersichtsseiten das Bookmark Icon zurück, um einen Deal per Klick für später zu speichern

  1. // ==UserScript==
  2. // @name Mydealz Bookmark Button
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1.3
  5. // @description Bringt auf Übersichtsseiten das Bookmark Icon zurück, um einen Deal per Klick für später zu speichern
  6. // @match https://www.mydealz.de/*
  7. // @exclude https://www.mydealz.de/profile/*
  8. // @exclude /https:\/\/www\.mydealz\.de\/.*-[0-9]+/
  9. // @license MIT
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. const ICON = {
  17. active: '/assets/img/ico_707ed.svg#bookmark-active',
  18. inactive: '/assets/img/ico_707ed.svg#bookmark'
  19. };
  20.  
  21. function getBookmarkState(thread) {
  22. try {
  23. const vueData = JSON.parse(thread.querySelector('[data-vue2]').dataset.vue2);
  24. return vueData.props.thread.isBookmarked;
  25. } catch (e) {
  26. console.error('Metadaten-Parsing fehlgeschlagen:', e);
  27. return false;
  28. }
  29. }
  30.  
  31. function updateButtonState(button, isBookmarked) {
  32. button.dataset.bookmarked = isBookmarked;
  33. button.querySelector('use').setAttribute('xlink:href',
  34. isBookmarked ? ICON.active : ICON.inactive
  35. );
  36. }
  37.  
  38. function createBookmarkButton() {
  39. const button = document.createElement('button');
  40. button.className = 'button button--type-text button--mode-secondary';
  41. button.innerHTML = `
  42. <span class="flex--inline boxAlign-ai--all-c">
  43. <svg width="16" height="20" class="icon icon--bookmark">
  44. <use xlink:href="${ICON.inactive}"></use>
  45. </svg>
  46. </span>
  47. `;
  48. return button;
  49. }
  50.  
  51. function handleBookmarkClick(button, threadId) {
  52. const currentState = button.dataset.bookmarked === 'true';
  53. const newState = !currentState;
  54.  
  55. toggleBookmark(threadId, newState).then(success => {
  56. if (success) {
  57. updateButtonState(button, newState);
  58. }
  59. });
  60. }
  61.  
  62. async function toggleBookmark(threadId, state) {
  63. try {
  64. const xsrfToken = document.cookie
  65. .split('; ')
  66. .find(row => row.startsWith('xsrf_t='))
  67. ?.split('=')[1]
  68. .replace(/"/g, '');
  69.  
  70. const response = await fetch('https://www.mydealz.de/threads/thread-save/toggle', {
  71. method: 'POST',
  72. headers: {
  73. 'Content-Type': 'application/json',
  74. 'X-XSRF-TOKEN': xsrfToken
  75. },
  76. body: JSON.stringify({
  77. threadId,
  78. state
  79. })
  80. });
  81.  
  82. return response.ok;
  83. } catch (error) {
  84. console.error('Fehler beim Toggle:', error);
  85. return false;
  86. }
  87. }
  88.  
  89. function initBookmarks() {
  90. document.querySelectorAll('.thread:not([data-bm-init])').forEach(thread => {
  91. const button = createBookmarkButton();
  92. const threadId = thread.id.replace('thread_', '');
  93.  
  94. // Initialzustand setzen
  95. updateButtonState(button, getBookmarkState(thread));
  96.  
  97. // Click-Handler
  98. button.addEventListener('click', (e) => {
  99. e.preventDefault();
  100. e.stopPropagation();
  101. handleBookmarkClick(button, threadId);
  102. });
  103.  
  104. thread.querySelector('.threadListCard-footer').prepend(button);
  105. thread.dataset.bmInit = 'true';
  106. });
  107. }
  108.  
  109. // Mutation Observer für dynamische Inhalte
  110. new MutationObserver(initBookmarks)
  111. .observe(document.body, {
  112. childList: true,
  113. subtree: true
  114. });
  115.  
  116. initBookmarks();
  117. })();