// ==UserScript== // @name Bypass Paywalls Clean - fi/se // @version 4.0.8.1 // @description Bypass Paywalls of news sites // @author magnolia1234 // @downloadURL https://gitflic.ru/project/magnolia1234/bypass-paywalls-clean-filters/blob/raw?file=userscript/bpc.fi.se.user.js // @updateURL https://gitflic.ru/project/magnolia1234/bypass-paywalls-clean-filters/blob/raw?file=userscript/bpc.fi.se.user.js // @homepageURL https://gitflic.ru/project/magnolia1234/bypass-paywalls-clean-filters // @supportURL https://gitflic.ru/project/magnolia1234/bypass-paywalls-clean-filters // @license MIT; https://gitflic.ru/project/magnolia1234/bypass-paywalls-clean-filters/blob/raw?file=LICENSE // @match *://*.berlingske.dk/* // @match *://*.dn.se/* // @match *://*.etc.se/* // @match *://*.suomensotilas.fi/* // @connect archive.fo // @connect archive.is // @connect archive.li // @connect archive.md // @connect archive.ph // @connect archive.vn // @grant GM.xmlHttpRequest // ==/UserScript== (function() { //'use strict'; var func_post; var fetch_headers = {}; window.setTimeout(function () { var domain; var mobile = window.navigator.userAgent.toLowerCase().includes('mobile'); var csDoneOnce; var cs_param = {}; var overlay = document.querySelector('body.didomi-popup-open'); if (overlay) overlay.classList.remove('didomi-popup-open'); var ads = 'div.OUTBRAIN, div[id^="taboola-"], div.ad-container, div[class*="-ad-container"], div[class*="_ad-container"], div.arc_ad, div[id^="poool-"], amp-ad, amp-embed[type="mgid"], amp-embed[type="outbrain"], amp-embed[type="taboola"]'; hideDOMStyle(ads, 10); if (matchDomain('berlingske.dk')) { let paywall = document.querySelector('div#paywall'); removeDOMElement(paywall); let ads = 'div.advert-unit'; hideDOMStyle(ads); } else if (matchDomain('dn.se')) { let url = window.location.href; getArchive(url, 'div.paywall-wrapper', '', 'article'); let ads = 'div.bad'; hideDOMStyle(ads); } else if (matchDomain('etc.se')) { let paywall = document.querySelector('section.prose-feature > section.teaser-section'); if (paywall) { paywall.classList.remove('teaser-section'); paywall.parentNode.querySelectorAll('.hidden').forEach(e => e.classList.remove('hidden')); } let ads = 'div[class$="-ad"], article section.font-sans'; hideDOMStyle(ads); let video_iframes = document.querySelectorAll('div.embed-block > iframe[width][height]'); for (let elem of video_iframes) { if (elem.width > 1000) { let ratio = elem.width / (mobile ? 320 : 640); elem.width = elem.width / ratio; elem.height = elem.height / ratio; } } } else if (matchDomain('suomensotilas.fi')) { let obscured = document.querySelector('div.epfl-pw-obscured'); if (obscured) obscured.classList.remove('epfl-pw-obscured'); } }, 1000); // General Functions function matchDomain(domains, hostname) { var matched_domain = false; if (!hostname) hostname = window.location.hostname; if (typeof domains === 'string') domains = [domains]; domains.some(domain => (hostname === domain || hostname.endsWith('.' + domain)) && (matched_domain = domain)); return matched_domain; } function removeDOMElement(...elements) { for (let element of elements) { if (element) element.remove(); } } function hideDOMElement(...elements) { for (let element of elements) { if (element) element.style = 'display:none !important;'; } } function hideDOMStyle(selector, id = 1) { let style = document.querySelector('head > style#ext'+ id); if (!style && document.head) { let sheet = document.createElement('style'); sheet.id = 'ext' + id; sheet.innerText = selector + ' {display: none !important;}'; document.head.appendChild(sheet); } } function addStyle(css, id = 1) { let style = document.querySelector('head > style#add'+ id); if (!style && document.head) { let sheet = document.createElement('style'); sheet.id = 'add' + id; sheet.innerText = css; document.head.appendChild(sheet); } } function clearPaywall(paywall, paywall_action) { if (paywall) { if (!paywall_action) removeDOMElement(...paywall); else { for (let elem of paywall) { if (paywall_action.rm_class) elem.classList.remove(paywall_action.rm_class); else if (paywall_action.rm_attrib) elem.removeAttribute(paywall_action.rm_attrib); } } } } function getSelectorLevel(selector) { if (selector.replace(/,\s+/g, ',').match(/[>\s]+/)) selector = selector.replace(/,\s+/g, ',').split(',').map(x => x.match(/[>\s]+/) ? x + ', ' + x.split(/[>\s]+/).pop() : x).join(', '); return selector; } function getArticleSrc(url, url_src, proxy, base64, selector, text_fail = '', selector_source = selector, selector_archive = selector) { let url_fetch = url_src || url; GM.xmlHttpRequest({ method: "GET", url: url_fetch, headers: fetch_headers, onload: function (response) { let html = response.responseText; if (proxy && base64) { html = decode_utf8(atob(html)); selector_source = 'body'; } let recursive; if (url.startsWith('https://archive.')) { if (url_fetch.includes('/https')) { if (html.includes('<div class="TEXT-BLOCK"')) { url_src = html.split('<div class="TEXT-BLOCK"')[1].split('</div>')[0].split('href="')[1].split('"')[0]; getArticleSrc(url, url_src, proxy, base64, selector, text_fail, selector_source, selector_archive); recursive = true; } else html = ''; } } if (!recursive) replaceDomElementExtSrc(url, url_src, html, proxy, base64, selector, text_fail, selector_source, selector_archive); } }); } function replaceDomElementExt(url, proxy, base64, selector, text_fail = '', selector_source = selector, selector_archive = selector) { let article = document.querySelector(selector); if (!article) return; if (proxy) { if (!text_fail) { if (url.startsWith('https://archive.')) text_fail = 'BPC > Try for full article text (no need to report issue for external site):\r\n'; else if (!matchUrlDomain(window.location.hostname, url)) text_fail = 'BPC > failed to load from external site:\r\n'; } getArticleSrc(url, '', proxy, base64, selector, text_fail, selector_source, selector_archive); } else { fetch(url, {headers: fetch_headers}) .then(response => { let article = document.querySelector(selector); if (response.ok) { response.text().then(html => { replaceDomElementExtSrc(url, '', html, false, base64, selector, text_fail, selector_source); }); } else { replaceTextFail(url, article, proxy, text_fail); } }).catch(function (err) { replaceTextFail(url, article, proxy, text_fail); }); } } var selector_level = false; function replaceDomElementExtSrc(url, url_src, html, proxy, base64, selector, text_fail = '', selector_source = selector, selector_archive = selector) { let article = document.querySelector(selector); let article_link = document.querySelector(selector_archive); let no_content_msg = ' | no article content found! | :'; if (html) { if (!proxy && base64) { html = decode_utf8(atob(html)); selector_source = 'body'; } let parser = new DOMParser(); window.setTimeout(function () { if (url.startsWith('https://archive.') && url_src) { let domain_archive = url.match(/^https:\/\/(archive\.\w{2})/)[1]; let pathname = new URL(url_src).pathname; html = html.replace(new RegExp('https:\\/\\/' + domain_archive.replace('.', '\\.') + '\\/o\\/\\w+\\/', 'g'), '').replace(new RegExp("(src=\"|background-image:url\\(')" + pathname.replace('/', '\\/'), 'g'), "$1" + 'https://' + domain_archive + pathname); } let doc = parser.parseFromString(html, 'text/html'); if (selector_level) selector_source = getSelectorLevel(selector_source); let article_new = doc.querySelector(selector_source); if (article_new) { if (article && article.parentNode) { if (url.startsWith('https://archive.')) { let arch_dom = (selector_archive !== selector) ? (article_new.querySelector(selector_archive) || document.querySelector(selector_archive)) : article_new; if (arch_dom) { if (arch_dom.firstChild) arch_dom = arch_dom.firstChild; let arch_div = document.createElement('div'); arch_div.appendChild(archiveLink_renew(url_src)); arch_div.appendChild(archiveLink(window.location.href, 'BPC > Full article text fetched from (no need to report issue for external site):\r\n')); arch_div.style = 'margin: 0px 0px 50px;'; arch_dom.before(arch_div); } let targets = article_new.querySelectorAll('a[target="_blank"][href^="' + window.location.origin + '"]'); for (let elem of targets) elem.removeAttribute('target'); let invalid_links = article_new.querySelectorAll('link[rel*="preload"]:not([href])'); removeDOMElement(...invalid_links); } window.setTimeout(function () { if (article.parentNode) { article.parentNode.replaceChild(article_new, article); if (func_post) func_post(); } }, 200); } } else replaceTextFail(url, article_link, proxy, text_fail.replace(':', no_content_msg)); }, 200); } else { replaceTextFail(url, article_link, proxy, url_src ? text_fail.replace(':', no_content_msg) : text_fail); } } function replaceTextFail(url, article, proxy, text_fail) { if (text_fail && article) { let text_fail_div = document.createElement('div'); text_fail_div.id = 'bpc_fail'; text_fail_div.setAttribute('style', 'margin: 0px 50px; font-weight: bold; color: red;'); text_fail_div.appendChild(document.createTextNode(text_fail)); if (proxy) { if (url.startsWith('https://archive.')) { text_fail_div = archiveLink(url.replace(/^https:\/\/archive\.\w{2}\//, ''), text_fail); } else { let a_link = document.createElement('a'); a_link.innerText = url; a_link.href = url; a_link.target = '_blank'; text_fail_div.appendChild(a_link); } } if (article.firstChild) article.firstChild.before(text_fail_div); else article.appendChild(text_fail_div); } } function randomInt(max) { return Math.floor(Math.random() * Math.floor(max)); } function archiveRandomDomain() { let tld_array = ['fo', 'is', 'li', 'md', 'ph', 'vn']; let tld = tld_array[randomInt(6)]; return 'archive.' + tld; } function getArchive(url, paywall_sel, paywall_action = '', selector, text_fail = '', selector_source = selector, selector_archive = selector) { let url_archive = 'https://' + archiveRandomDomain() + '/' + url.split(/[#\?]/)[0]; let paywall = document.querySelectorAll(paywall_sel); if (paywall.length) { clearPaywall(paywall, paywall_action); replaceDomElementExt(url_archive, true, false, selector, text_fail, selector_source, selector_archive); } } function archiveLink(url, text_fail = 'BPC > Try for full article text (no need to report issue for external site):\r\n') { return externalLink(['archive.today', 'archive.is'], 'https://{domain}?run=1&url={url}', url, text_fail); } function archiveLink_renew(url, text_fail = 'BPC > Only use to renew if text is incomplete or updated:\r\n') { return externalLink([new URL(url).hostname], '{url}/again?url=' + window.location.href, url, text_fail); } function nftLink(url, text_fail = 'BPC > Full article text:\r\n') { return externalLink(['1ft.io'], 'https://{domain}/{url}', url, text_fail); } function externalLink(domains, ext_url_templ, url, text_fail = 'BPC > Full article text:\r\n') { let text_fail_div = document.createElement('div'); text_fail_div.id = 'bpc_archive'; text_fail_div.setAttribute('style', 'margin: 20px; font-size: 20px; font-weight: bold; color: red;'); let parser = new DOMParser(); text_fail = text_fail.replace(/\[(?<url>[^\]]+)\]/g, function (match, url) { return "<a href='" + url + "' target='_blank' style='color: red'>" + new URL(url).hostname + "</a>"; }); let doc = parser.parseFromString('<span>' + text_fail + '</span>', 'text/html'); let elem = doc.querySelector('span'); text_fail_div.appendChild(elem); for (let domain of domains) { let ext_url = ext_url_templ.replace('{domain}', domain).replace('{url}', url.split('?')[0]); let a_link = document.createElement('a'); a_link.innerText = domain; a_link.href = ext_url; a_link.target = '_blank'; text_fail_div.appendChild(document.createTextNode(' | ')); text_fail_div.appendChild(a_link); } return text_fail_div; } function encode_utf8(str) { return unescape(encodeURIComponent(str)); } function decode_utf8(str) { return decodeURIComponent(escape(str)); } })();