Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name NWZonline – Volltext im Original-Style
- // @namespace https://www.nwzonline.de/
- // @version 3.0.0
- // @description Plus-Artikel vollstaendig im Original-Layout: blockiert Piano und neutralisiert die Paywall-Flags in Fusion.globalContent, bevor die Seite rendert. Kein eigener Reader.
- // @match https://www.nwzonline.de/*
- // @match https://nwzonline.de/*
- // @run-at document-start
- // @grant none
- // @noframes
- // ==/UserScript==
- (() => {
- "use strict";
- /* ---------- 1) Piano-Tag blockieren, bevor es laden kann ---------- */
- const BLOCK = /tinypass|piano\.io/i;
- const isBlocked = n => n && n.nodeType === 1 && n.tagName === "SCRIPT" && BLOCK.test(n.src || "");
- function patch(proto, name) {
- const orig = proto && proto[name];
- if (!orig) return;
- proto[name] = function (...args) {
- if (name === "appendChild") return isBlocked(args[0]) ? args[0] : orig.call(this, args[0]);
- if (name === "insertBefore") return isBlocked(args[0]) ? args[0] : orig.call(this, args[0], args[1]);
- const clean = args.filter(a => !isBlocked(a));
- return clean.length ? orig.apply(this, clean) : undefined;
- };
- }
- patch(Node.prototype, "appendChild");
- patch(Node.prototype, "insertBefore");
- [Element.prototype, Document.prototype, DocumentFragment.prototype].forEach(p => patch(p, "append"));
- /* ---------- 2) Paywall-Flags neutralisieren (vor dem Rendern) ---------- */
- function patchGC(gc) {
- try {
- if (gc && typeof gc === "object" && gc.type === "story") {
- gc.isPaid = false;
- gc.isMarkedAsPaid = false;
- gc.allowDynamicPaywall = false;
- gc.isPianoDisabled = true;
- }
- } catch (e) {}
- return gc;
- }
- let _fusion;
- try {
- Object.defineProperty(window, "Fusion", {
- configurable: true,
- get() { return _fusion; },
- set(v) {
- _fusion = v;
- if (v && typeof v === "object") {
- let _gc = patchGC(v.globalContent);
- try {
- Object.defineProperty(v, "globalContent", {
- configurable: true,
- get() { return _gc; },
- set(nv) { _gc = patchGC(nv); }
- });
- } catch (e) {}
- }
- }
- });
- } catch (e) {}
- function getGC() {
- const gc = window.Fusion && window.Fusion.globalContent;
- return gc && gc.type === "story" && Array.isArray(gc.elements) ? gc : null;
- }
- /* ---------- 3) Sicherheitsnetz: Paywall-Reste entfernen, Scroll entsperren ---------- */
- const PW = '.tp-modal,.tp-backdrop,.tp-iframe-wrapper,[class^="tp-"],[id^="tp-"],[class*="ianoWrapper"],iframe[src*="tinypass"],iframe[src*="piano"]';
- function sweep() {
- document.querySelectorAll(PW).forEach(n => n.remove());
- document.querySelectorAll('dialog[open],[role="dialog"]').forEach(n => {
- if (/freischalten|Jetzt abonnieren|Abo abschließen/i.test(n.textContent || "")) n.remove();
- });
- for (const el of [document.body, document.documentElement]) {
- if (!el) continue;
- el.classList.remove("tp-modal-open", "tp-modal-close");
- el.style.removeProperty("overflow");
- el.style.removeProperty("position");
- }
- }
- let pending = false;
- new MutationObserver(muts => {
- let need = false;
- for (const m of muts) {
- if (m.type === "childList" && m.addedNodes.length) { need = true; break; }
- if (m.type === "attributes" && (m.target === document.body || m.target === document.documentElement)) { need = true; break; }
- }
- if (need && !pending) { pending = true; setTimeout(() => { pending = false; sweep(); }, 50); }
- }).observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ["class", "style"] });
- /* ---------- 4) Fallback: fehlenden Text im Original-Container ergaenzen ---------- */
- const esc = s => String(s ?? "").replace(/[&<>"']/g,
- c => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
- const plain = s => String(s || "").replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
- const ALLOW = new Set(["P","BR","B","STRONG","I","EM","U","S","SUB","SUP","A","UL","OL","LI","BLOCKQUOTE","H2","H3","H4","SPAN"]);
- const DROP = new Set(["SCRIPT","STYLE","IFRAME","OBJECT","EMBED","FORM","LINK","META","NOSCRIPT"]);
- function sanitize(html) {
- const tpl = document.createElement("template");
- tpl.innerHTML = String(html ?? "");
- (function walk(node) {
- for (const el of Array.from(node.children)) {
- walk(el);
- if (DROP.has(el.tagName)) { el.remove(); continue; }
- if (!ALLOW.has(el.tagName)) { el.replaceWith(...el.childNodes); continue; }
- for (const a of Array.from(el.attributes)) {
- if (el.tagName === "A" && a.name === "href" && /^(https?:|mailto:|\/)/i.test(a.value)) continue;
- el.removeAttribute(a.name);
- }
- if (el.tagName === "A") { el.target = "_blank"; el.rel = "noopener noreferrer"; }
- }
- })(tpl.content);
- return tpl.innerHTML;
- }
- function imgUrl(info) {
- if (!info || !info.id || !info.auth) return null;
- const token = info.auth["1"] || Object.values(info.auth)[0];
- return token ? `${location.origin}/resizer/v2/${info.id}.${info.fileExtension || "jpg"}?auth=${token}&quality=80&width=1200` : null;
- }
- function otherNode(e) {
- const t = (e.type || "").toLowerCase();
- if (t === "header") { const h = document.createElement("h2"); h.innerHTML = sanitize(e.text || ""); return h; }
- if (t === "quote") {
- const b = document.createElement("blockquote");
- const parts = (e.elements || []).map(q => typeof q === "string" ? q : (q.text || "")).filter(Boolean);
- const who = [e.author, e.authorDescription].filter(Boolean).join(" ");
- b.innerHTML = parts.map(p => `<p>${sanitize(p)}</p>`).join("") + (who ? `<footer>— ${esc(who)}</footer>` : "");
- return b;
- }
- if (t === "image") {
- const info = e.imageInfo || e, url = imgUrl(info), f = document.createElement("figure");
- if (url) f.innerHTML = `<img src="${esc(url)}" alt="${esc(info.alt || "")}" loading="lazy" style="max-width:100%;height:auto">` + (info.caption ? `<figcaption>${esc(info.caption)}</figcaption>` : "");
- return f;
- }
- if (t === "list") {
- const el = document.createElement(e.list_type === "ordered" ? "ol" : "ul");
- el.innerHTML = (e.items || []).map(i => `<li>${sanitize(i.text || i.content || "")}</li>`).join("");
- return el;
- }
- const p = document.createElement("p"); p.innerHTML = sanitize(e.text || e.content || ""); return p;
- }
- function ensureFull(gc) {
- const art = document.querySelector('article[data-element-selector="article"]');
- if (!art || art.dataset.nwzFull) return;
- const texts = gc.elements.filter(e => e.type === "text" && (e.text || "").trim());
- if (!texts.length) return;
- const probe = plain(texts[texts.length - 1].text).slice(0, 40);
- if (probe && art.textContent.includes(probe)) return; // bereits vollstaendig
- // Container + Absatz-Vorlage aus dem bereits gerenderten Text finden
- let container = art, tmpl = null;
- for (const p of art.querySelectorAll("p")) {
- const pt = plain(p.textContent);
- if (pt.length > 40 && texts.some(e => plain(e.text).slice(0, 40) === pt.slice(0, 40))) {
- container = p.parentElement; tmpl = p; break;
- }
- }
- const domText = plain(container.textContent);
- const frag = document.createDocumentFragment();
- let started = false;
- for (const e of gc.elements) {
- if (e.type === "text") {
- const t = plain(e.text);
- if (!started) { if (t && domText.includes(t.slice(0, 40))) continue; started = true; }
- const p = tmpl ? tmpl.cloneNode(false) : document.createElement("p");
- p.innerHTML = sanitize(e.text || "");
- frag.appendChild(p);
- } else if (started && !["piano", "ad", "newsletterad", "moreitems"].includes((e.type || "").toLowerCase())) {
- frag.appendChild(otherNode(e));
- }
- }
- container.appendChild(frag);
- art.dataset.nwzFull = "1";
- }
- /* ---------- 5) Timing / SPA-Navigation ---------- */
- let checkedId = null, timers = [];
- setInterval(() => {
- const gc = getGC();
- if (!gc) return;
- const id = gc._id || gc.canonicalUrl || location.href;
- if (id === checkedId) return;
- checkedId = id;
- timers.forEach(clearTimeout);
- timers = [2500, 5000, 8000].map(ms => setTimeout(() => { const g = getGC(); if (g) ensureFull(g); }, ms));
- }, 800);
- })();
Advertisement
Add Comment
Please, Sign In to add comment