Customize Zeit Online

Entferne unerwünschte Artikel/Abschnitte aus Zeit Online

当前为 2021-12-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Customize Zeit Online
  3. // @namespace https://greasyfork.org/en/users/689160-georg-vogt
  4. // @version 4.13
  5. // @description Entferne unerwünschte Artikel/Abschnitte aus Zeit Online
  6. // @author Georg Vogt
  7. // @match https://www.zeit.de/*
  8. // @icon https://icons.duckduckgo.com/ip2/zeit.de.ico
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @run-at document-body
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. "use strict";
  16.  
  17. function hideNode(node) {
  18. if (node) {
  19. node.style.display = "none";
  20. // node.style.background = "red"; // debug
  21. }
  22. }
  23.  
  24. function clearMainPage() {
  25. // bad single nodes
  26. const queries = new Map([
  27. ["div.cp-region.cp-region--kpi-table", "div"], // Beliebte Artikel
  28. ["div.cp-region.cp-region--kpi-accordion", "div"], // Beliebte Artikel mobile
  29. ["section[data-ct-context='shop']", "div.cp-region"], // Shop
  30. ["section[data-ct-context='headed-spiele']", "div.cp-region"], // Spiele
  31. ["section[data-ct-context='newsticker']", "div.cp-region"], // Newsticker
  32. ["section>div.zg-wiegehtesihnen", "div"], // Stimmungsumfrage
  33. ["a[href*='die-49']", "div"], // Die 49
  34. ]);
  35. const main = document.querySelector("main");
  36. queries.forEach((node, query) => hideNode(main.querySelector(query)?.closest(node)));
  37.  
  38. // remove zeit+
  39. if (GM_getValue("tm_czo_zeitplus", true)) {
  40. const zplusArticles = main.querySelectorAll("article svg.svg-symbol.zplus-logo:not(.invisible)");
  41. zplusArticles.forEach(node => hideNode(node.closest("article")));
  42. }
  43.  
  44. // remove wochenmarkt
  45. if (GM_getValue("tm_czo_wochenmarkt", true)) {
  46. const wochenmarkt = main.querySelectorAll(
  47. "article[data-unique-id^='http://xml.zeit.de/zeit-magazin/wochenmarkt'], article.zon-teaser-wochenmarkt"
  48. );
  49. wochenmarkt.forEach(node => hideNode(node));
  50. }
  51.  
  52. // remove zett
  53. if (GM_getValue("tm_czo_zett", true)) {
  54. const zettArticles = main.querySelectorAll("article>[href^='https://www.zeit.de/zett']");
  55. zettArticles.forEach(node => hideNode(node.closest("article")));
  56. }
  57.  
  58. // remove Verlagsangebot
  59. if (GM_getValue("tm_czo_verlag", true)) {
  60. const verlagsangebotArticles = main.querySelectorAll(":scope>div>*>article.zon-teaser-standard.zon-teaser-standard--ad");
  61. verlagsangebotArticles.forEach(node => hideNode(node));
  62. const veranstaltungen = main.querySelectorAll(":scope>div>*>article>a[href^='https://z2x.zeit.de']");
  63. veranstaltungen.forEach(node => hideNode(node.parentElement));
  64. }
  65.  
  66. // remove podcasts
  67. if (GM_getValue("tm_czo_podcast", true)) {
  68. const podcasts = main.querySelectorAll([
  69. "article.zon-teaser-standard.zon-teaser-standard--podcast",
  70. "article.teaser-podcast-lead",
  71. "article.zon-teaser-wide.zon-teaser-wide--podcast"
  72. ]);
  73. podcasts.forEach(node => hideNode(node));
  74. }
  75.  
  76. // remove videos
  77. if (GM_getValue("tm_czo_video", true)) {
  78. const videos = main.querySelectorAll(":scope>div>*>article[data-video-id]");
  79. videos.forEach(node => hideNode(node));
  80. }
  81.  
  82. // remove newsletter
  83. if (GM_getValue("tm_czo_newsletter", true)) {
  84. const newsletters = main.querySelectorAll(":scope>div>*>article>a[href^='https://www.zeit.de/newsletter']");
  85. newsletters.forEach(node => hideNode(node.parentElement));
  86. main.querySelectorAll(":scope>div>div>aside.newsletter-signup").forEach(node => hideNode(node));
  87. }
  88.  
  89. // remove Känguru Comic
  90. if (GM_getValue("tm_czo_comic", true)) {
  91. const comic = main.querySelector("figure [href^='https://www.zeit.de/serie/die-kaenguru-comics'], figure [src^='https://img.zeit.de/administratives/kaenguru-comics']");
  92. hideNode(comic?.closest("div.scrollable-wrapper, div.collapsible-wrapper"));
  93. }
  94.  
  95. // remove Quiz region
  96. if (GM_getValue("tm_czo_quiz", true)) {
  97. const quiz = main.querySelector(":scope>div>div>section.frame.frame--quiz");
  98. hideNode(quiz?.closest("div.cp-region"));
  99. }
  100.  
  101. // remove Spiele
  102. if (GM_getValue("tm_czo_spiele", true)) {
  103. const quiz = main.querySelector("article a[href*='spiele.zeit.de'], article a[href*='soduko.zeit.de']");
  104. hideNode(quiz?.closest("div.cp-region"));
  105. }
  106.  
  107. // remove offline angebote
  108. if (GM_getValue("tm_czo_offline", true)) {
  109. hideNode(main.querySelector(":scope>div>section[data-ct-context='printkiosk']")?.closest("div.cp-region")); // Jetzt für sie am Kiosk
  110. hideNode(main.querySelector(":scope>div>div>section.zon-teaser-printbox")?.closest("div.cp-region")); // Diese Woche in der ZEIT
  111. }
  112.  
  113. // remove regions without articles
  114. const wantedContent = [
  115. "article:not([style*='display: none'])",
  116. ":scope>div>aside>div.zg-corona-dashboard",
  117. ":scope>div>section>iframe", // Quiz
  118. ":scope>div[class='czo-settings']",
  119. ]
  120. main.querySelectorAll(":scope>div").forEach(node => node.querySelector(wantedContent)? "": hideNode(node));
  121. }
  122.  
  123. function clearArticle() {
  124. // bad single nodes
  125. const queries = new Map([
  126. ["aside.jobbox-ticker", "aside"], // Jobbörse
  127. ]);
  128. queries.forEach((node, query) => hideNode(document.querySelector(query)?.closest(node)));
  129.  
  130. // remove sidebar Zeit+
  131. if (GM_getValue("tm_czo_zeitplus", true)) {
  132. const possibleHeadings = ["DAS BESTE AUS Z+", "Z+"];
  133. const sideBoxes = document.querySelectorAll("article aside.topicbox");
  134. for (const sideBox of sideBoxes) {
  135. if (possibleHeadings.includes(sideBox.firstElementChild?.firstElementChild?.innerText)) {
  136. hideNode(sideBox);
  137. }
  138. }
  139. }
  140.  
  141. // remove videos
  142. if (GM_getValue("tm_czo_video", true)) {
  143. const videos = document.querySelectorAll("figure>div.js-videoplayer");
  144. videos.forEach(node => hideNode(node.parentElement));
  145. }
  146.  
  147. // remove newsletter
  148. if (GM_getValue("tm_czo_newsletter", true)) {
  149. hideNode(document.querySelector("aside.newsletter-signup"));
  150. hideNode(document.querySelector("[action*='community.zeit.de/newsletter']")?.closest("form")); // Newsletter inline
  151. }
  152.  
  153. // offline angebote
  154. if (GM_getValue("tm_czo_offline", true)) {
  155. hideNode(document.querySelectorAll("aside.volume-teaser"));
  156. }
  157.  
  158. // Anzeige
  159. const nextRead = document.querySelector("span.nextread-note__label")
  160. if (nextRead?.innerText == "ANZEIGE") {
  161. hideNode(nextRead?.closest("article"));
  162. }
  163. }
  164.  
  165. document.addEventListener("DOMContentLoaded", () => {
  166. if (document.querySelector("div.cp-region")) {
  167. clearMainPage();
  168. setTimeout(clearMainPage, 2000);
  169. } else {
  170. clearArticle();
  171. };
  172.  
  173. // Create Settings on bottom
  174. function createCheckbox(text, id, defaultValue=true) {
  175. const div = document.createElement("div");
  176. div.innerHTML = `
  177. <input type="checkbox" id="${id}+" name="${id}+" ${GM_getValue(id, defaultValue)? "checked": ""}>
  178. <label for="${id}+">${text}</label>
  179. `;
  180. div.onclick = function () {
  181. GM_setValue(id, div.firstElementChild.checked);
  182. };
  183. return div;
  184. }
  185. const main = document.querySelector("main");
  186. const settings = document.createElement("div");
  187. settings.innerHTML = "<h3>Customize Zeit Online Einstellungen: Blocke</h3>";
  188. const boxes = document.createElement("div");
  189. boxes.className = "czo-settings";
  190. boxes.style = "display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 175px));";
  191. boxes.appendChild(createCheckbox("Zeit+", "tm_czo_zeitplus"));
  192. boxes.appendChild(createCheckbox("Zett", "tm_czo_zett"));
  193. boxes.appendChild(createCheckbox("Verlagsangebote", "tm_czo_verlag"));
  194. boxes.appendChild(createCheckbox("Podcasts", "tm_czo_podcast"));
  195. boxes.appendChild(createCheckbox("Videos", "tm_czo_video"));
  196. boxes.appendChild(createCheckbox("Newsletter", "tm_czo_newsletter"));
  197. boxes.appendChild(createCheckbox("Känguru Comic", "tm_czo_comic"));
  198. boxes.appendChild(createCheckbox("Offline Angebot", "tm_czo_offline"));
  199. boxes.appendChild(createCheckbox("Wochenmarkt", "tm_czo_wochenmarkt"));
  200. boxes.appendChild(createCheckbox("Quiz + Nachbarartikel", "tm_czo_quiz"));
  201. boxes.appendChild(createCheckbox("Spiele", "tm_czo_spiele"));
  202. settings.appendChild(boxes);
  203. main.appendChild(settings);
  204. });
  205.  
  206. // remove paywall footer
  207. const callback = function(mutationsList, observer) {
  208. for(const mutation of mutationsList) {
  209. for (const node of mutation.addedNodes) {
  210. if (node.className?.startsWith("paywall-footer")) {
  211. hideNode(node);
  212. observer.disconnect();
  213. }
  214. }
  215. }
  216. };
  217.  
  218. const observerFooter = new MutationObserver(callback);
  219. observerFooter.observe(document.body, {childList: true});