Initial commit

This commit is contained in:
AverageMarcus committed 2020-03-22 13:51:40 +00:00
commit 974fa1660a
13 files changed
+314

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
node_modules
.env
Makefile
+3
View File
@@ -0,0 +1,3 @@
.env
node_modules
.DS_Store
+15
View File
@@ -0,0 +1,15 @@
FROM node:10-alpine
RUN apk add --no-cache chromium nss freetype freetype-dev harfbuzz ca-certificates ttf-freefont
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
ENV CHROMIUM_PATH "/usr/bin/chromium-browser"
WORKDIR /app
ADD package.json .
RUN npm install
ADD . .
CMD npm start
+18
View File
@@ -0,0 +1,18 @@
.DEFAULT_GOAL := default
IMAGE := docker.cloud.cluster.fun/averagemarcus/website-to-remarkable:latest
.PHONY: docker-build # Build the docker image
docker-build:
@docker build -t $(IMAGE) .
.PHONY: publish # Publish the docker image to the Artifactory registry
publish:
@docker push $(IMAGE)
.PHONY: help # Show this list of commands
help:
@grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1: \2/' | expand -t20
default: format test build
+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel='manifest' href='/manifest.json'>
<title>Website to reMarkable</title>
<style>
* {
box-sizing: border-box;
}
body {
font-size: 2em;
display: flex;
flex-direction: column;
justify-content: center;
height: 100vh;
margin: 0;
padding: 0;
text-align: center;
}
</style>
</head>
<body>
<h1>⚠️</h1>
<h2>Failed to send to reMarkable</h2>
</body>
</html>
+54
View File
@@ -0,0 +1,54 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel='manifest' href='/manifest.json'>
<title>Website to reMarkable</title>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
</script>
<style>
* {
box-sizing: border-box;
}
body {
font-size: 2em;
display: flex;
flex-direction: column;
justify-content: center;
height: 100vh;
margin: 0;
padding: 0;
text-align: center;
}
input, button {
margin: 10px 10px;
font-size: 1.8em;
line-height: 1.5em;
text-align: center;
}
</style>
</head>
<body>
<h1>🚀</h1>
<input type="url" id="URL" />
<button id="sendButton">SEND</button>
<script>
document.getElementById('sendButton').addEventListener('click', () => {
fetch(window.location + `?website=${document.getElementById("URL").value}`)
.then(res => tes.text())
.then(console.log);
})
</script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@pwabuilder/pwainstall"></script>
<pwa-install></pwa-install>
</body>
</html>
+100
View File
@@ -0,0 +1,100 @@
require("dotenv").config();
const http = require('http');
const fs = require("fs");
const puppeteer = require('puppeteer');
const { Remarkable } = require('remarkable-typescript');
const client = new Remarkable({ token: process.env.REMARKABLE_TOKEN });
const server = http.createServer(async (req, res) => {
const incomingURL = new URL(`http://localhost:8000${req.url}`);
if (incomingURL.searchParams.get("website")) {
const website = new URL(incomingURL.searchParams.get("website"));
console.log(`Fetching '${website.toString()}'`);
if (await sendPage(website)) {
fs.readFile(__dirname + "/success.html", function (err,data) {
if (err) {
res.writeHead(404);
res.end(JSON.stringify(err));
return;
}
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data);
});
} else {
fs.readFile(__dirname + "/failure.html", function (err,data) {
if (err) {
res.writeHead(404);
res.end(JSON.stringify(err));
return;
}
res.writeHead(500, {'Content-Type': 'text/html'});
res.end(data);
});
}
}else {
let url = req.url === "/" ? "/index.html": req.url;
fs.readFile(__dirname + url || "/index.html", function (err,data) {
if (err) {
res.writeHead(404);
res.end(JSON.stringify(err));
return;
}
if (url.endsWith(".js")) {
res.writeHead(200, {'Content-Type': 'application/javascript'});
} else if (url.endsWith(".json")) {
res.writeHead(200, {'Content-Type': 'application/json'});
} else if (url.endsWith(".png")) {
res.writeHead(200, {'Content-Type': 'image/png'});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
}
res.end(data);
});
}
});
server.listen(8000);
async function sendPage(website, tries = 0) {
const browser = await puppeteer.launch({
executablePath: process.env.CHROMIUM_PATH,
args: ['--disable-dev-shm-usage', '--no-sandbox']
});
try {
const page = await browser.newPage();
await page.emulate(Object.assign({}, puppeteer.devices["iPad Pro"], { userAgent: "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" }));
await page.goto(website.toString());
const title = await page.title()
console.log("Page loaded. Title - " + title)
await page.evaluate( function(){
[...document.querySelectorAll('*')].forEach(node => {
const pos = window.getComputedStyle(node).getPropertyValue("position");
if (pos == "fixed" || pos == "sticky") {
node.style.position = "unset";
}
})
} );
const myPDF = await page.pdf({ format: 'A3' });
console.log("Saved to PDF")
await client.uploadPDF(title, myPDF);
console.log("Uploaded to reMarkable");
return true;
} catch (ex) {
console.log(ex);
if (tries < 5) {
return await sendPage(website, ++tries);
} else {
return false;
}
} finally {
await browser.close();
}
}
+26
View File
@@ -0,0 +1,26 @@
{
"name": "Website-to-reMarkable",
"short_name": "Website-to-reMarkable",
"description": "Send websites as PDFs to reMarkable",
"theme_color": "#999",
"background_color": "#999",
"display": "standalone",
"scope": "/",
"start_url": "/",
"icons": [
{
"src": "rocket.png",
"sizes": "192x192",
"type": "image/png"
}
],
"splash_pages": null,
"share_target": {
"action": "/",
"method": "GET",
"params": {
"url": "website",
"text": "website"
}
}
}
+18
View File
@@ -0,0 +1,18 @@
{
"name": "website-to-remarkable",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"crypto-random-string": "^3.2.0",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"puppeteer": "^2.1.1",
"remarkable-typescript": "^1.0.5"
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel='manifest' href='/manifest.json'>
<title>Website to reMarkable</title>
<style>
* {
box-sizing: border-box;
}
body {
font-size: 2em;
display: flex;
flex-direction: column;
justify-content: center;
height: 100vh;
margin: 0;
padding: 0;
text-align: center;
}
</style>
</head>
<body>
<h1>🚀</h1>
<h2>Sent to reMarkable</h2>
</body>
</html>
+16
View File
@@ -0,0 +1,16 @@
/*
Copyright 2016 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.toolbox=e()}}(function(){return function e(t,n,r){function o(c,s){if(!n[c]){if(!t[c]){var a="function"==typeof require&&require;if(!s&&a)return a(c,!0);if(i)return i(c,!0);var u=new Error("Cannot find module '"+c+"'");throw u.code="MODULE_NOT_FOUND",u}var f=n[c]={exports:{}};t[c][0].call(f.exports,function(e){var n=t[c][1][e];return o(n||e)},f,f.exports,e,t,n,r)}return n[c].exports}for(var i="function"==typeof require&&require,c=0;c<r.length;c++)o(r[c]);return o}({1:[function(e,t,n){"use strict";function r(e,t){t=t||{},(t.debug||m.debug)&&console.log("[sw-toolbox] "+e)}function o(e){var t;return e&&e.cache&&(t=e.cache.name),t=t||m.cache.name,caches.open(t)}function i(e,t){t=t||{};var n=t.successResponses||m.successResponses;return fetch(e.clone()).then(function(r){return"GET"===e.method&&n.test(r.status)&&o(t).then(function(n){n.put(e,r).then(function(){var r=t.cache||m.cache;(r.maxEntries||r.maxAgeSeconds)&&r.name&&c(e,n,r)})}),r.clone()})}function c(e,t,n){var r=s.bind(null,e,t,n);d=d?d.then(r):r()}function s(e,t,n){var o=e.url,i=n.maxAgeSeconds,c=n.maxEntries,s=n.name,a=Date.now();return r("Updating LRU order for "+o+". Max entries is "+c+", max age is "+i),g.getDb(s).then(function(e){return g.setTimestampForUrl(e,o,a)}).then(function(e){return g.expireEntries(e,c,i,a)}).then(function(e){r("Successfully updated IDB.");var n=e.map(function(e){return t.delete(e)});return Promise.all(n).then(function(){r("Done with cache cleanup.")})}).catch(function(e){r(e)})}function a(e,t,n){return r("Renaming cache: ["+e+"] to ["+t+"]",n),caches.delete(t).then(function(){return Promise.all([caches.open(e),caches.open(t)]).then(function(t){var n=t[0],r=t[1];return n.keys().then(function(e){return Promise.all(e.map(function(e){return n.match(e).then(function(t){return r.put(e,t)})}))}).then(function(){return caches.delete(e)})})})}function u(e,t){return o(t).then(function(t){return t.add(e)})}function f(e,t){return o(t).then(function(t){return t.delete(e)})}function h(e){e instanceof Promise||p(e),m.preCacheItems=m.preCacheItems.concat(e)}function p(e){var t=Array.isArray(e);if(t&&e.forEach(function(e){"string"==typeof e||e instanceof Request||(t=!1)}),!t)throw new TypeError("The precache method expects either an array of strings and/or Requests or a Promise that resolves to an array of strings and/or Requests.");return e}function l(e,t,n){if(!e)return!1;if(t){var r=e.headers.get("date");if(r){if(new Date(r).getTime()+1e3*t<n)return!1}}return!0}var d,m=e("./options"),g=e("./idb-cache-expiration");t.exports={debug:r,fetchAndCache:i,openCache:o,renameCache:a,cache:u,uncache:f,precache:h,validatePrecacheInput:p,isResponseFresh:l}},{"./idb-cache-expiration":2,"./options":4}],2:[function(e,t,n){"use strict";function r(e){return new Promise(function(t,n){var r=indexedDB.open(u+e,f);r.onupgradeneeded=function(){r.result.createObjectStore(h,{keyPath:p}).createIndex(l,l,{unique:!1})},r.onsuccess=function(){t(r.result)},r.onerror=function(){n(r.error)}})}function o(e){return e in d||(d[e]=r(e)),d[e]}function i(e,t,n){return new Promise(function(r,o){var i=e.transaction(h,"readwrite");i.objectStore(h).put({url:t,timestamp:n}),i.oncomplete=function(){r(e)},i.onabort=function(){o(i.error)}})}function c(e,t,n){return t?new Promise(function(r,o){var i=1e3*t,c=[],s=e.transaction(h,"readwrite"),a=s.objectStore(h);a.index(l).openCursor().onsuccess=function(e){var t=e.target.result;if(t&&n-i>t.value[l]){var r=t.value[p];c.push(r),a.delete(r),t.continue()}},s.oncomplete=function(){r(c)},s.onabort=o}):Promise.resolve([])}function s(e,t){return t?new Promise(function(n,r){var o=[],i=e.transaction(h,"readwrite"),c=i.objectStore(h),s=c.index(l),a=s.count();s.count().onsuccess=function(){var e=a.result;e>t&&(s.openCursor().onsuccess=function(n){var r=n.target.result;if(r){var i=r.value[p];o.push(i),c.delete(i),e-o.length>t&&r.continue()}})},i.oncomplete=function(){n(o)},i.onabort=r}):Promise.resolve([])}function a(e,t,n,r){return c(e,n,r).then(function(n){return s(e,t).then(function(e){return n.concat(e)})})}var u="sw-toolbox-",f=1,h="store",p="url",l="timestamp",d={};t.exports={getDb:o,setTimestampForUrl:i,expireEntries:a}},{}],3:[function(e,t,n){"use strict";function r(e){var t=a.match(e.request);t?e.respondWith(t(e.request)):a.default&&"GET"===e.request.method&&0===e.request.url.indexOf("http")&&e.respondWith(a.default(e.request))}function o(e){s.debug("activate event fired");var t=u.cache.name+"$$$inactive$$$";e.waitUntil(s.renameCache(t,u.cache.name))}function i(e){return e.reduce(function(e,t){return e.concat(t)},[])}function c(e){var t=u.cache.name+"$$$inactive$$$";s.debug("install event fired"),s.debug("creating cache ["+t+"]"),e.waitUntil(s.openCache({cache:{name:t}}).then(fLine truncated
//# sourceMappingURL=sw-toolbox.js.map
+3
View File
@@ -0,0 +1,3 @@
importScripts('sw-toolbox.js');
toolbox.precache([]);
toolbox.router.get('/*', toolbox.networkFirst, { networkTimeoutSeconds: 60 });