Browse Source

move public files into public dir, remove googlebot spoof.

Jason Schwarzenberger 1 year ago
parent
commit
dcb63d5343
7 changed files with 228 additions and 220 deletions
  1. 0 167
      index.html
  2. 4 5
      index.js
  3. 28 0
      public/index.html
  4. 0 0
      public/loading.svg
  5. 54 0
      public/script.js
  6. 89 0
      public/style.css
  7. 53 48
      utils/declutter.js

+ 0 - 167
index.html

@@ -1,167 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
-	<title>Declutter</title>
-	<style>
-		body {
-			margin: 3.5rem auto 0.5rem;
-			max-width: 42rem;
-			font: 1.2em/1.62 sans-serif;
-		}
-
-		h1,
-		h2 {
-			margin: 0 auto;
-			padding: 0;
-			text-align: center;
-		}
-
-		h2 {
-			font-size: 1rem;
-			font-style: oblique;
-			font-weight: normal;
-		}
-
-		p {
-			text-align: center;
-			font-size: 0.7rem;
-			margin: 0 auto 1.5rem;
-		}
-
-		form {
-			text-align: center;
-			width: 95%;
-			border: solid 1px #aaa;
-			margin: 8rem auto 0.5rem;
-			border-radius: 3px;
-			overflow: hidden;
-		}
-
-		input {
-			width: 85%;
-			box-sizing: border-box;
-			padding: 0.5rem;
-			margin: 0;
-			font-size: 1.25rem;
-			line-height: 1.5;
-			border: none;
-			border-radius: 0;
-			background: #fff;
-			vertical-align: middle;
-		}
-
-		form:has(input:focus) {
-			box-shadow: inset 0 0 0.2rem rgba(0, 0, 0, 0.2);
-		}
-
-		button {
-			width: 15%;
-			box-sizing: border-box;
-			padding: 0.5rem;
-			margin: 0;
-			font-size: 1.25rem;
-			line-height: 1.5;
-			border: none;
-			border-left: solid 1px #aaa;
-			border-radius: 0;
-			background: #f1f1f1;
-			vertical-align: middle;
-		}
-
-		.loading,
-		.is-loading form,
-		.is-loading form+p,
-		.is-loading .error {
-			display: none;
-		}
-
-		.is-loading .loading {
-			display: block;
-			text-align: center;
-			margin: 5rem auto;
-		}
-
-		.error {
-			display: none;
-		}
-
-		.is-error .error {
-			padding: 0;
-			color: darkred;
-			display: block;
-			width: 100%;
-			text-align: center;
-		}
-	</style>
-</head>
-
-<body>
-	<h1>Declutter</h1>
-	<h2>Keep <em>only</em> what matters.</h2>
-	<div class="loading">
-		<img src="/loading.svg" alt="loading..." width="200" height="200" />
-	</div>
-	<h3 class="error">ERROR</h3>
-	<form action="/" method="POST" accept-charset="UTF-8"><input required name="url"
-			placeholder="Enter article link" /><button value="true" name="redirect" type="submit">view</button></form>
-	<p>
-		Pictures, video, polls and other <em>rich content</em> are unlikely to be displayed.
-		<br />
-		No article content is stored or hosted by Declutter.
-	</p>
-	<script>
-		document.querySelector('form').addEventListener('submit', e => {
-			e.preventDefault();
-			document.querySelector('html').classList.add('is-loading');
-			document.querySelector('html').classList.remove('is-error');
-			fetch('/', {
-				method: 'POST',
-				headers: {
-					'Content-Type': 'application/json'
-				},
-				body: JSON.stringify({
-					url: e.target.url.value
-				})
-			})
-				.then(response => {
-					if (response.ok) {
-						return response.text();
-					}
-					throw response.status;
-				})
-				.then(url => {
-					window.location = url;
-				}).catch(status => {
-					let message = 'ERROR';
-
-					switch (status) {
-						case 400:
-							message = 'Unsupported website.';
-							break;
-					}
-
-					document.querySelector('.error').innerText = message;
-					document.querySelector('html').classList.add('is-error');
-					document.querySelector('html').classList.remove('is-loading');
-				});
-		});
-
-		(function () {
-			const query = window.location.search.substring(1).split('&').reduce((m, p) => {
-				const [key, value] = p.split('=')
-				return ({
-					...m,
-					[key]: decodeURIComponent(value)
-				});
-			}, {});
-			if (!query.url) {
-				return;
-			}
-			document.querySelector('input[name="url"]').value = query.url;
-			document.querySelector('button').click();
-		})();
-	</script>
-</body>
-
-</html>

+ 4 - 5
index.js

@@ -11,11 +11,10 @@ app.use(bodyParser.json());
 app.use(bodyParser.urlencoded({ extended: true }));
 
 app.get('/favicon.ico', async (req, res) => res.sendStatus(404));
-app.get('/loading.svg', async (req, res) => res.sendFile(path.join(__dirname, '/loading.svg')));
-
-app.get('/', async (req, res) => {
-  return res.sendFile(path.join(__dirname, '/index.html'));
-});
+app.get('/loading.svg', async (req, res) => res.sendFile(path.join(__dirname, '/public/loading.svg')));
+app.get('/style.css', async (req, res) => res.sendFile(path.join(__dirname, '/public/style.css')));
+app.get('/script.js', async (req, res) => res.sendFile(path.join(__dirname, '/public/script.js')));
+app.get('/', async (req, res) => res.sendFile(path.join(__dirname, '/public/index.html')));
 
 const declutterRequest = async (res, url, redirect) => {
   try {

+ 28 - 0
public/index.html

@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+	<meta charset="utf-8">
+	<meta name="viewport" content="width=device-width, initial-scale=1">
+	<title>Declutter</title>
+	<link rel="stylesheet" href="/style.css" />
+</head>
+
+<body>
+	<h1>Declutter</h1>
+	<h2>Keep <em>only</em> what matters.</h2>
+	<div class="loading">
+		<img src="/loading.svg" alt="loading..." width="200" height="200" />
+	</div>
+	<h3 class="error">ERROR</h3>
+	<form action="/" method="POST" accept-charset="UTF-8"><input required name="url"
+			placeholder="Enter article link" /><button value="true" name="redirect" type="submit">view</button></form>
+	<p>
+		Pictures, video, polls and other <em>rich content</em> are unlikely to be displayed.
+		<br />
+		No article content is stored or hosted by Declutter.
+	</p>
+	<script src="/script.js" type="text/javascript"></script>
+</body>
+
+</html>

loading.svg → public/loading.svg


+ 54 - 0
public/script.js

@@ -0,0 +1,54 @@
+(function() {
+  document.querySelector('form').addEventListener('submit', e => {
+    e.preventDefault();
+    document.querySelector('html').classList.add('is-loading');
+    document.querySelector('html').classList.remove('is-error');
+    fetch('/', {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json'
+      },
+      body: JSON.stringify({
+        url: e.target.url.value
+      })
+    })
+      .then(response => {
+        if (response.ok) {
+          return response.text();
+        }
+        throw response.status;
+      })
+      .then(url => {
+        window.location = url;
+      })
+      .catch(status => {
+        let message = 'ERROR';
+
+        switch (status) {
+          case 400:
+            message = 'Unsupported website.';
+            break;
+        }
+
+        document.querySelector('.error').innerText = message;
+        document.querySelector('html').classList.add('is-error');
+        document.querySelector('html').classList.remove('is-loading');
+      });
+  });
+
+  const query = window.location.search
+    .substring(1)
+    .split('&')
+    .reduce((m, p) => {
+      const [key, value] = p.split('=');
+      return {
+        ...m,
+        [key]: decodeURIComponent(value)
+      };
+    }, {});
+  if (!query.url) {
+    return;
+  }
+  document.querySelector('input[name="url"]').value = query.url;
+  document.querySelector('button').click();
+})();

+ 89 - 0
public/style.css

@@ -0,0 +1,89 @@
+body {
+  margin: 3.5rem auto 0.5rem;
+  max-width: 42rem;
+  font: 1.2em/1.62 sans-serif;
+}
+
+h1,
+h2 {
+  margin: 0 auto;
+  padding: 0;
+  text-align: center;
+}
+
+h2 {
+  font-size: 1rem;
+  font-style: oblique;
+  font-weight: normal;
+}
+
+p {
+  text-align: center;
+  font-size: 0.7rem;
+  margin: 0 auto 1.5rem;
+}
+
+form {
+  text-align: center;
+  width: 95%;
+  border: solid 1px #aaa;
+  margin: 8rem auto 0.5rem;
+  border-radius: 3px;
+  overflow: hidden;
+}
+
+input {
+  width: 85%;
+  box-sizing: border-box;
+  padding: 0.5rem;
+  margin: 0;
+  font-size: 1.25rem;
+  line-height: 1.5;
+  border: none;
+  border-radius: 0;
+  background: #fff;
+  vertical-align: middle;
+}
+
+form:has(input:focus) {
+  box-shadow: inset 0 0 0.2rem rgba(0, 0, 0, 0.2);
+}
+
+button {
+  width: 15%;
+  box-sizing: border-box;
+  padding: 0.5rem;
+  margin: 0;
+  font-size: 1.25rem;
+  line-height: 1.5;
+  border: none;
+  border-left: solid 1px #aaa;
+  border-radius: 0;
+  background: #f1f1f1;
+  vertical-align: middle;
+}
+
+.loading,
+.is-loading form,
+.is-loading form + p,
+.is-loading .error {
+  display: none;
+}
+
+.is-loading .loading {
+  display: block;
+  text-align: center;
+  margin: 5rem auto;
+}
+
+.error {
+  display: none;
+}
+
+.is-error .error {
+  padding: 0;
+  color: darkred;
+  display: block;
+  width: 100%;
+  text-align: center;
+}

+ 53 - 48
utils/declutter.js

@@ -126,55 +126,60 @@ const buildReadableContent = async (tab, url) => {
 };
 
 module.exports = async url => {
-  const site = sites.find(s => s.host.test(url));
-
   const browser = await puppeteer.launch();
   const tab = await browser.newPage();
-  await tab.setUserAgent('Googlebot/2.1 (+http://www.google.com/bot.html)');
-  await tab.setViewport({ width: 2000, height: 10000 });
-  await tab.goto(url, {
-    timeout: site ? site.timeout : 30000,
-    waitUntil: site ? site.waitUntil : 'domcontentloaded'
-  });
-  await fixRelativeLinks(tab, url);
-  await bypass(tab, url);
-
-  let premium = '';
-  let { content, title } = await buildReadableContent(tab, url);
-  let { author, publisher } = await tab.evaluate(url => {
-    const $author = document.querySelector('meta[property="og:site_name"]');
-    return {
-      author: $author && $author.content ? $author.content : '',
-      publisher: new URL(url).host
-    };
-  }, url);
-
-  if (site) {
-    const meta = await Promise.all([
-      buildContent(tab, site, url),
-      getText(tab, site.selectors.title),
-      getAuthorName(tab, site.selectors.authorName),
-      getPublisherName(tab, site),
-      getPremiumTag(tab, site)
-    ]);
-    content = meta[0];
-    title = meta[1];
-    author = meta[2];
-    publisher = meta[3];
-    premium = meta[4] || '';
+  try {
+    const site = sites.find(s => s.host.test(url));
+
+    await tab.setViewport({ width: 2000, height: 10000 });
+    await tab.goto(url, {
+      timeout: site ? site.timeout : 60000,
+      waitUntil: site ? site.waitUntil : 'networkidle0'
+    });
+    await fixRelativeLinks(tab, url);
+    await bypass(tab, url);
+
+    let premium = '';
+    let { content, title } = await buildReadableContent(tab, url);
+    let { author, publisher } = await tab.evaluate(url => {
+      const $author = document.querySelector('meta[property="og:site_name"]');
+      return {
+        author: $author && $author.content ? $author.content : '',
+        publisher: new URL(url).host
+      };
+    }, url);
+
+    if (site) {
+      const meta = await Promise.all([
+        buildContent(tab, site, url),
+        getText(tab, site.selectors.title),
+        getAuthorName(tab, site.selectors.authorName),
+        getPublisherName(tab, site),
+        getPremiumTag(tab, site)
+      ]);
+      content = meta[0];
+      title = meta[1];
+      author = meta[2];
+      publisher = meta[3];
+      premium = meta[4] || '';
+    }
+
+    await tab.close();
+    await browser.close();
+
+    const authorName = cleanHtmlText([author, publisher + premium].filter(s => !!s && !!s.trim()).join(' &bull; '));
+
+    const account = await telegraph.createAccount({
+      author_name: authorName,
+      author_url: url,
+      short_name: (author || publisher || authorName).substring(0, 31)
+    });
+    const page = await telegraph.createPage(title, content, account);
+
+    return page.url;
+  } catch (e) {
+    await tab.close();
+    await browser.close();
+    throw e;
   }
-
-  const authorName = cleanHtmlText([author, publisher + premium].filter(s => !!s && !!s.trim()).join(' &bull; '));
-
-  await tab.close();
-  await browser.close();
-
-  const account = await telegraph.createAccount({
-    author_name: authorName,
-    author_url: url,
-    short_name: (author || publisher || authorName).substring(0, 31)
-  });
-  const page = await telegraph.createPage(title, content, account);
-
-  return page.url;
 };