Avatar

panphora

8 public vals
Joined February 16, 2023
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { fetch } from "https://esm.town/v/std/fetch";
export let canvasText = (async (req: Request) => {
const query = new URL(req.url).searchParams;
const { loadImage, createCanvas } = await import(
"https://deno.land/x/canvas/mod.ts"
);
const canvas = createCanvas(1200, 675);
const ctx = canvas.getContext("2d");
const boldFontRes = await fetch(
`https://websharebox.s3.amazonaws.com/SpaceGrotesk-Bold.ttf`,
);
const boldFont = await boldFontRes.arrayBuffer();
canvas.loadFont(boldFont, {
family: "Space Grotesk",
weight: "bold",
});
const normalFontRes = await fetch(
`https://websharebox.s3.amazonaws.com/SpaceGrotesk-Medium.ttf`,
);
const normalFont = await normalFontRes.arrayBuffer();
canvas.loadFont(normalFont, {
family: "Space Grotesk",
weight: "normal",
});
function roundedRect(
x,
y,
width,
height,
radius,
stroke,
color,
backgroundColor,
) {
ctx.strokeStyle = color;
ctx.lineWidth = stroke;
ctx.fillStyle = backgroundColor;
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
function wrapText(context, text, x, y, maxWidth, lineHeight) {
const words = text.split(" ");
let line = "";
for (let n = 0; n < words.length; n++) {
const testLine = line + words[n] + " ";
const metrics = context.measureText(testLine);
const testWidth = metrics.width / 1.8;
if (testWidth > maxWidth && n > 0) {
context.fillText(line, x, y);
line = words[n] + " ";
y += lineHeight;
}
else {
line = testLine;
}
}
context.fillText(line, x, y);
}
let canvasWidth = canvas.width;
let canvasHeight = canvas.height;
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.font = "64px Space Grotesk";
// gradient
let gradient = ctx.createLinearGradient(0, 0, canvasWidth, canvasHeight);
gradient.addColorStop(0, "#7a005a");
gradient.addColorStop(.11, "#920258");
gradient.addColorStop(.22, "#a81054");
gradient.addColorStop(.33, "#bf2251");
gradient.addColorStop(.44, "#d3364b");
gradient.addColorStop(.56, "#e24b40");
gradient.addColorStop(.67, "#ef6339");
gradient.addColorStop(.78, "#f8792a");
gradient.addColorStop(.89, "#fd941c");
gradient.addColorStop(1, "#ffaa00");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
// browser
roundedRect(90, 86, 1200 - 90 - 90, 1000, 20, 0, "transparent", "#202124");
// browser inner
let browserInnerDistanceFromEdge = 98;
let browserInnerWidth = 1200 - 90 - 90 - 16;
roundedRect(
browserInnerDistanceFromEdge,
140,
browserInnerWidth,
1000,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { set } from "https://esm.town/v/std/set?v=11";
import { email } from "https://esm.town/v/std/email?v=9";
import { formatAsCurrency } from "https://esm.town/v/panphora/formatAsCurrency";
let { lastBtcPrice } = await import("https://esm.town/v/panphora/lastBtcPrice");
import process from "node:process";
import { fetchJSON } from "https://esm.town/v/panphora/fetchJSON";
export async function btcPrice() {
let btc = await fetchJSON(
`https://rest.coinapi.io/v1/quotes/COINBASE_SPOT_BTC_USD/current`,
{
headers: {
"X-CoinAPI-Key": process.env.COIN_API,
},
},
);
let btcPrice = btc.last_trade.price; // this is a number
if (Math.abs(btcPrice - lastBtcPrice) > 2500) {
// only alert me when the price changes +/- $2500
let formattedBtcPrice = formatAsCurrency(btcPrice);
await email({
text: formattedBtcPrice,
subject: "BTC PRICE ALERT: " + formattedBtcPrice,
});
// set the new price to compare to to the current price
lastBtcPrice = btcPrice;
await set("lastBtcPrice", lastBtcPrice);
}
return btcPrice;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import process from "node:process";
export let twitterOpenGraphImage = (async (req: Request) => {
const query = new URL(req.url).searchParams;
const site = query.get("site");
const scale = query.get("scale");
const scrollTo = query.get("scrollTo");
const darkMode = query.get("darkMode");
const removeSelectors = query.get("remove");
const { PuppeteerDeno } = await import(
"https://deno.land/x/puppeteer@16.2.0/src/deno/Puppeteer.ts"
);
const puppeteer = new PuppeteerDeno({
productName: "chrome",
});
const browser = await puppeteer.connect({
browserWSEndpoint:
`wss://chrome.browserless.io?token=${process.env.BROWSERLESS_API_KEY}`,
});
const page = await browser.newPage();
await page.setViewport({ width: 600, height: 340, deviceScaleFactor: 2 });
if (darkMode) {
await page.emulateMediaFeatures([{
name: "prefers-color-scheme",
value: "dark",
}]);
}
await page.goto(site, { waitUntil: ["load", "domcontentloaded"] });
await page.evaluate(
(scale, scrollTo, removeSelectors) => {
document.body.insertAdjacentHTML(
"beforeend",
`<div style="z-index:9999999;position:fixed;bottom:28px;right:24px;display:flex;align-items:center;background:#1B73E8;padding:7px 21px 8px;font-weight:bold;font-size:20px;font-family:Arial;color:#fff;border-radius:8px;"><div style="position:relativ
);
if (scale) {
document.body.style.zoom = scale;
}
if (scrollTo) {
document.querySelector(scrollTo).scrollIntoView({ block: "start" });
window.scrollBy(0, -32);
}
if (removeSelectors) {
removeSelectors.split(",").forEach((removeSelector) => {
const removeElems = document.querySelectorAll(removeSelector);
removeElems.forEach((el) => {
el.remove();
});
});
}
},
scale,
scrollTo,
removeSelectors,
);
const screenshotBuffer = await page.screenshot({
type: "png",
captureBeyondViewport: false,
});
await browser.close();
return new Response(screenshotBuffer, {
headers: {
"Content-Type": "image/png",
"Content-Length": screenshotBuffer.length,
},
});
});
1
2
3
4
5
6
7
export function formatAsCurrency(num) {
let formatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
});
return formatter.format(num);
}
1
2
3
4
5
6
7
8
9
import { fetch } from "https://esm.town/v/std/fetch";
export let map = async (zipA, latB, longB) => {
let f = await fetch(
`https://maps.googleapis.com/maps/api/staticmap?auto=&scale=2&size=600x300&maptype=roadmap&format=png&key=AIzaSyBkrVgpa0Ul-_LN7cVq8ws6oYfQi3zCjuU&markers=size:mid%7Ccolor:0xdc2626%7Clabel:1%7CLos%20Angeles%2CCA%2C${zipA}&markers=size:mid%7Ccolor:0xdc26
);
let res = await f.blob();
return res;
};
1
2
3
4
5
6
7
8
9
10
11
12
export const get = (value, path, defaultValue) => {
return String(path)
.split(".")
.reduce((acc, v) => {
try {
acc = acc[v];
} catch (e) {
return defaultValue;
}
return acc;
}, value);
};
1
2
3
4
5
6
7
8
9
10
11
12
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
import process from "node:process";
export const distance = async (req) => {
const searchParams = new URL(req.url).searchParams;
const destinationA = encodeURIComponent(String(searchParams.get("a")).trim());
const destinationB = encodeURIComponent(String(searchParams.get("b")).trim());
const obj = await fetchJSON(
`https://maps.googleapis.com/maps/api/distancematrix/json?destinations=${destinationA}&origins=${destinationB}&units=imperial&key=${process.env.GOOGLE_MAPS_API_KEY}`,
);
return Response.json(obj);
};
1
2
3
export let webhook1 = (a, b) => {
return a + b;
};
Next