Paywall redirect to Archive.today

Redirect spiegel.de faz.net zeit.de zerohedge.com Süddeutsche Zeitung SZPlus tagesspiegel paywall pages to archive.today

  1. // ==UserScript==
  2. // @name Paywall redirect to Archive.today
  3. // @name:de Paywall weiterleitung auf Archive.today
  4. // @namespace https://greatest.deepsurf.us/en/users/20068-cuzi
  5. // @version 2.17
  6. // @description Redirect spiegel.de faz.net zeit.de zerohedge.com Süddeutsche Zeitung SZPlus tagesspiegel paywall pages to archive.today
  7. // @description:de Leitet Spiegel.de faz.net zerohedge.com zeit.de/ Online Plus/Paywall/S+ Süddeutsche Zeitung SZPlus tagesspiegel Seiten automatisch auf archive.today
  8. // @icon https://spiegel.de/favicon.ico
  9. // @author cuzi
  10. // @license GPL-3.0-or-later
  11.  
  12. // @match https://www.spiegel.de/*
  13. // @match https://www.zeit.de/*
  14. // @match https://www.zerohedge.com/*
  15. // @match https://www.faz.net/*
  16. // @match https://m.faz.net/*
  17. // @match https://www.sueddeutsche.de/*
  18. // @match https://sz-magazin.sueddeutsche.de/*
  19. // @match https://www.tagesspiegel.de/*
  20.  
  21. // @match https://archive.today/*
  22. // @match https://archive.ph/*
  23. // @match https://archive.is/*
  24. // @match https://archive.fp/*
  25. // @match https://archive.li/*
  26. // @match https://archive.md/*
  27. // @match https://archive.vn/*
  28. // @grant GM.registerMenuCommand
  29. // @grant GM.xmlHttpRequest
  30. // @connect archive.today
  31. // @connect archive.ph
  32. // @connect archive.is
  33. // @connect archive.fp
  34. // @connect archive.li
  35. // @connect archive.md
  36. // @connect archive.vn
  37. // ==/UserScript==
  38.  
  39. /* global GM */
  40. /* jshint asi: true, esversion: 8 */
  41.  
  42. (async function () {
  43. 'use strict'
  44.  
  45. const scriptName = 'Paywall redirect to Archive.today'
  46.  
  47. const hostnames = [
  48. 'archive.is',
  49. 'archive.ph',
  50. 'archive.today',
  51. 'archive.fp',
  52. 'archive.li',
  53. 'archive.md',
  54. 'archive.vn'
  55. ]
  56.  
  57. function sleep (t) {
  58. return new Promise(resolve => setTimeout(resolve, t))
  59. }
  60.  
  61. function checkAvailability (hostname) {
  62. return new Promise(function (resolve, reject) {
  63. const onResponse = function (response) {
  64. if ((response.status >= 200 && response.status <= 400) || response.status === 429) {
  65. resolve(response)
  66. } else {
  67. reject(new Error('HOST_UNAVAILABLE'))
  68. }
  69. }
  70. GM.xmlHttpRequest({
  71. url: `https://${hostname}/`,
  72. method: 'GET',
  73. timeout: 5000,
  74. headers: {
  75. Range: 'bytes=0-63'
  76. },
  77. onload: onResponse,
  78. ontimeout: onResponse,
  79. onerror: onResponse
  80. })
  81. })
  82. }
  83.  
  84. function showSpinner (msg) {
  85. let style = document.getElementById('check_host_style')
  86. if (!style) {
  87. style = document.head.appendChild(document.createElement('style'))
  88. style.setAttribute('id', 'check_host_style')
  89. style.textContent = `
  90. #check_host_spinner {
  91. position: fixed;
  92. background: #fff;
  93. height: 2.2em;
  94. top: 1em;
  95. left: 50%;
  96. transform: translate(-50%, 0);
  97. z-index: 1000;
  98. border-radius: 5px;
  99. border: 1px solid black;
  100. color: black;
  101. min-width: 7em;
  102. padding:3px;
  103. }
  104. #check_host_spinner .spinner-element {
  105. animation-duration: 1s;
  106. animation-iteration-count: infinite;
  107. animation-name: slide;
  108. animation-timing-function: linear;
  109. animation-direction: alternate-reverse;
  110. animation-play-state: running;
  111. background-color: #000;
  112. border-radius: 50%;
  113. border: 2px solid #fff;
  114. color: #fff;
  115. height: 1em;
  116. margin: auto;
  117. margin-left: 0;
  118. width: 1em;
  119. margin-top: -0.5em;
  120. }
  121.  
  122. @keyframes slide {
  123. from {
  124. margin-left:0
  125. }
  126. to {
  127. margin-left:80%
  128. }
  129. }
  130. `
  131. }
  132.  
  133. let div = document.getElementById('check_host_spinner')
  134. if (!div) {
  135. div = document.body.appendChild(document.createElement('div'))
  136. div.setAttribute('id', 'check_host_spinner')
  137. const text = div.appendChild(document.createElement('span'))
  138. text.setAttribute('id', 'check_host_text')
  139. const spinner = div.appendChild(document.createElement('div'))
  140. spinner.classList.add('spinner-element')
  141. }
  142. document.getElementById('check_host_text').innerHTML = msg || ''
  143. document.querySelector('#check_host_spinner .spinner-element').style.display = 'block'
  144. }
  145.  
  146. function stopSpinner () {
  147. const e = document.querySelector('#check_host_spinner .spinner-element')
  148. if (e) {
  149. e.style.display = 'none'
  150. }
  151. }
  152.  
  153. async function archivePage (url) {
  154. window.setTimeout(() => showSpinner('archive'), 0)
  155.  
  156. // Check which hostname of archive is currently available
  157. let workingHostname = null
  158. for (const hostname of hostnames) {
  159. try {
  160. window.setTimeout(() => showSpinner(hostname), 0)
  161. await checkAvailability(hostname)
  162. workingHostname = hostname
  163. break
  164. } catch (err) {
  165. if (err && 'message' in err && err.message === 'HOST_UNAVAILABLE') {
  166. console.debug(`${hostname} is NOT available`)
  167. } else {
  168. throw err
  169. }
  170. }
  171. }
  172.  
  173. if (workingHostname) {
  174. document.location.href = `https://${workingHostname}/?run=1&url=${encodeURIComponent(url)}`
  175. } else {
  176. window.setTimeout(() => {
  177. showSpinner(`<a href="https://archive.today/?run=1&url=${encodeURIComponent(url)}">Try archive.today</a>`)
  178. stopSpinner()
  179. }, 200)
  180. window.alert(scriptName +
  181. '\n\nSorry, all of the archive.today domains seem to be down.\n\nChecked:\n' +
  182. hostnames.join('\n') +
  183. '\n\nIf you are using a Cloudflare DNS, try to switch to another DNS provider or use a VPN. Currently Cloudflare can\'t reliably resolve archive.today.')
  184. }
  185. }
  186.  
  187. GM.registerMenuCommand(scriptName + ' - Archive.today page', () => archivePage(document.location.href))
  188.  
  189. let running = false
  190. let firstRun = true
  191. async function main () {
  192. if (running) {
  193. return
  194. }
  195. if (
  196. document.location.hostname.indexOf('spiegel') !== -1 && document.location.pathname.length > 1 && (
  197. document.querySelector('[data-area="paywall"]') || (
  198. document.querySelector('#Inhalt article header #spon-spplus-flag-l') && document.querySelectorAll('article h2').length === 1
  199. )
  200. )
  201. ) {
  202. running = true
  203. archivePage(document.location.href)
  204. } else if (
  205. document.location.hostname.indexOf('tagesspiegel') !== -1 && document.querySelector('#paywal').length !== 0) {
  206. running = true
  207. archivePage(document.location.href)
  208. } else if (
  209. document.location.hostname.indexOf('zeit.de') !== -1 &&
  210. document.location.pathname.length > 1 && (
  211. document.querySelector('.zplus-badge__link') ||
  212. document.getElementById('paywall').childElementCount != 0 ||
  213. ('k5aMeta' in window && window.k5aMeta.paywall === 'hard')
  214. )
  215. ) {
  216. running = true
  217. archivePage(document.location.href)
  218. } else if (
  219. document.location.hostname.indexOf('.faz.net') !== -1 &&
  220. document.location.pathname.endsWith('.html') &&
  221. document.querySelectorAll('.atc-HeadlineText').length === 1 && (
  222. document.querySelector('[class*=atc-ContainerPaywall]') || // desktop www.faz.net
  223. document.querySelector('[id*=paywall]')) // mobile m.faz.net
  224. ) {
  225. if (firstRun) {
  226. // Wait a little the first time to let bypass-paywalls-firefox-clean do the job
  227. // if it fails to unblock the page, we will archive it in the second run
  228. firstRun = false
  229. await sleep(3000)
  230. } else {
  231. running = true
  232. archivePage(document.location.href)
  233. }
  234. } else if (
  235. document.location.hostname.indexOf('zerohedge.com') !== -1 &&
  236. document.location.pathname.length > 1 && (
  237. document.querySelector('[class*=PremiumOverlay] [class*=PremiumOverlay]') ||
  238. ('__NEXT_DATA__' in window && window.__NEXT_DATA__.props.pageProps.node.isPremium === true)
  239. )
  240. ) {
  241. running = true
  242. archivePage(document.location.href)
  243. } else if (
  244. document.location.hostname.indexOf('sz-magazin.sueddeutsche.de') !== -1 &&
  245. document.location.search.indexOf('reduced=true') !== -1 &&
  246. document.querySelector('.articlemain__inner--reduced .paragraph--reduced')
  247. ) {
  248. running = true
  249. archivePage(document.location.href)
  250. } else if (
  251. document.location.hostname.indexOf('sueddeutsche.de') !== -1 &&
  252. document.location.search.indexOf('reduced=true') !== -1 &&
  253. document.querySelector('#sz-paywall iframe')
  254. ) {
  255. running = true
  256. archivePage(document.location.href)
  257. } else if (
  258. document.location.hostname.indexOf('archive') !== -1 &&
  259. document.querySelector('form#submiturl [type=submit]')
  260. ) {
  261. running = true
  262. // Insert url and press submit button
  263. const m = document.location.search.match('url=([^&]+)')
  264. if (m) {
  265. const url = decodeURIComponent(m[1])
  266. document.querySelector('form#submiturl input#url').value = url
  267. document.querySelector('form#submiturl [type=submit]').click()
  268. }
  269. } else if (
  270. document.location.hostname.indexOf('archive') !== -1 &&
  271. document.querySelector('[data-area="paywall"]')
  272. ) {
  273. running = true
  274. // Redirect to history of this page, if there is also a paywall in this archive
  275. // Only redirect once for this session
  276. const key = document.location.href
  277. const alreadyRedirected = window.sessionStorage.getItem(key)
  278. const historyLink = Array.from(document.querySelectorAll('#HEADER form a')).filter(e => e.textContent.indexOf('history') !== -1).shift()
  279. if (!alreadyRedirected && historyLink) {
  280. window.sessionStorage.setItem(key, '1')
  281. historyLink.click()
  282. }
  283. }
  284. firstRun = false
  285. }
  286. await main()
  287. await sleep(1000)
  288. await main()
  289. await sleep(5000)
  290. await main()
  291. })()