tangled
alpha
login
or
join now
timtinkers.online
/
onomatopoeia
0
fork
atom
bluesky quote bot
0
fork
atom
overview
issues
pulls
pipelines
Deleted astralUtils, updated other files
timtinkers.online
1 year ago
de77a632
e1a2ddff
+68
-176
5 changed files
expand all
collapse all
unified
split
.gitignore
deno.lock
main.ts
utils
astralUtils.ts
canvasUtils.ts
+2
-2
.gitignore
···
1
1
.vscode
2
2
.env
3
3
/public/*.js
4
4
-
lastIndex.txt
5
5
-
*.png
4
4
+
*.png
5
5
+
*.svg
+62
-65
deno.lock
···
1
1
{
2
2
"version": "4",
3
3
"specifiers": {
4
4
-
"jsr:@astral/astral@*": "0.4.8",
5
5
-
"jsr:@deno-library/progress@1.4.9": "1.4.9",
6
6
-
"jsr:@std/assert@0.223": "0.223.0",
7
7
-
"jsr:@std/async@0.223.0": "0.223.0",
4
4
+
"jsr:@denosaurs/plug@1.0.5": "1.0.5",
5
5
+
"jsr:@gfx/canvas@0.5.7": "0.5.7",
6
6
+
"jsr:@std/assert@0.214": "0.214.0",
7
7
+
"jsr:@std/assert@0.217": "0.217.0",
8
8
"jsr:@std/dotenv@*": "0.225.2",
9
9
-
"jsr:@std/fmt@0.221.0": "0.221.0",
10
10
-
"jsr:@std/fs@0.223.0": "0.223.0",
11
11
-
"jsr:@std/path@0.223.0": "0.223.0",
12
12
-
"jsr:@zip-js/zip-js@2.7.41": "2.7.41",
9
9
+
"jsr:@std/encoding@0.214": "0.214.0",
10
10
+
"jsr:@std/encoding@0.217.0": "0.217.0",
11
11
+
"jsr:@std/fmt@0.214": "0.214.0",
12
12
+
"jsr:@std/fs@0.214": "0.214.0",
13
13
+
"jsr:@std/fs@0.217.0": "0.217.0",
14
14
+
"jsr:@std/path@0.214": "0.214.0",
15
15
+
"jsr:@std/path@0.217": "0.217.0",
16
16
+
"jsr:@std/path@0.217.0": "0.217.0",
13
17
"npm:@atcute/bluesky-richtext-builder@*": "1.0.1_@atcute+bluesky@1.0.7__@atcute+client@2.0.3_@atcute+client@2.0.3",
14
14
-
"npm:@atcute/client@^2.0.3": "2.0.3"
18
18
+
"npm:@atcute/client@^2.0.3": "2.0.3",
19
19
+
"npm:tex-linebreak@*": "0.7.1"
15
20
},
16
21
"jsr": {
17
17
-
"@astral/astral@0.4.8": {
18
18
-
"integrity": "7eb1f4e6d56ec9d5f4565cb2b7f166dc43ab0cbeffd49e5a9248094d2666fdd4",
22
22
+
"@denosaurs/plug@1.0.5": {
23
23
+
"integrity": "04cd988da558adc226202d88c3a434d5fcc08146eaf4baf0cea0c2284b16d2bf",
19
24
"dependencies": [
20
20
-
"jsr:@deno-library/progress",
21
21
-
"jsr:@std/async",
22
22
-
"jsr:@std/fs",
23
23
-
"jsr:@std/path",
24
24
-
"jsr:@zip-js/zip-js"
25
25
+
"jsr:@std/encoding@0.214",
26
26
+
"jsr:@std/fmt",
27
27
+
"jsr:@std/fs@0.214",
28
28
+
"jsr:@std/path@0.214"
25
29
]
26
30
},
27
27
-
"@deno-library/progress@1.4.9": {
28
28
-
"integrity": "86db695ae338cb1ae3ffa46d6f2e6a9cdef33a15c2ace6fa25354a91a9dd3909",
31
31
+
"@gfx/canvas@0.5.7": {
32
32
+
"integrity": "cd054e34f64763c7e6958bedc5fef00def929c20ebb89da5687112b5d402dbe3",
29
33
"dependencies": [
30
30
-
"jsr:@std/fmt"
34
34
+
"jsr:@denosaurs/plug",
35
35
+
"jsr:@std/encoding@0.217.0",
36
36
+
"jsr:@std/fs@0.217.0",
37
37
+
"jsr:@std/path@0.217.0"
31
38
]
32
39
},
33
33
-
"@std/assert@0.223.0": {
34
34
-
"integrity": "eb8d6d879d76e1cc431205bd346ed4d88dc051c6366365b1af47034b0670be24"
40
40
+
"@std/assert@0.214.0": {
41
41
+
"integrity": "55d398de76a9828fd3b1aa653f4dba3eee4c6985d90c514865d2be9bd082b140"
35
42
},
36
36
-
"@std/async@0.223.0": {
37
37
-
"integrity": "b42f635d89fb8f9e0e7dc258fbc8f33233e4977f61e0b20da08a8b51fd7b2c5d",
38
38
-
"dependencies": [
39
39
-
"jsr:@std/assert"
40
40
-
]
43
43
+
"@std/assert@0.217.0": {
44
44
+
"integrity": "c98e279362ca6982d5285c3b89517b757c1e3477ee9f14eb2fdf80a45aaa9642"
41
45
},
42
46
"@std/dotenv@0.225.2": {
43
47
"integrity": "e2025dce4de6c7bca21dece8baddd4262b09d5187217e231b033e088e0c4dd23"
44
48
},
45
45
-
"@std/fmt@0.221.0": {
46
46
-
"integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a"
49
49
+
"@std/encoding@0.214.0": {
50
50
+
"integrity": "30a8713e1db22986c7e780555ffd2fefd1d4f9374d734bb41f5970f6c3352af5"
51
51
+
},
52
52
+
"@std/encoding@0.217.0": {
53
53
+
"integrity": "b03e8ff94c98d6b6a02c02c5cf8e5d203400155516248964fc4559abc04669dc"
54
54
+
},
55
55
+
"@std/fmt@0.214.0": {
56
56
+
"integrity": "40382cff88a0783b347b4d69b94cf931ab8e549a733916718cb866c08efac4d4"
47
57
},
48
48
-
"@std/fs@0.223.0": {
49
49
-
"integrity": "3b4b0550b2c524cbaaa5a9170c90e96cbb7354e837ad1bdaf15fc9df1ae9c31c"
58
58
+
"@std/fs@0.214.0": {
59
59
+
"integrity": "bc880fea0be120cb1550b1ed7faf92fe071003d83f2456a1e129b39193d85bea",
60
60
+
"dependencies": [
61
61
+
"jsr:@std/assert@0.214",
62
62
+
"jsr:@std/path@0.214"
63
63
+
]
50
64
},
51
51
-
"@std/path@0.223.0": {
52
52
-
"integrity": "593963402d7e6597f5a6e620931661053572c982fc014000459edc1f93cc3989",
65
65
+
"@std/fs@0.217.0": {
66
66
+
"integrity": "0bfff5f3618d68c385b28b4ffbf3a15c98293a0f1186444458b62e0111ce77b2",
53
67
"dependencies": [
54
54
-
"jsr:@std/assert"
68
68
+
"jsr:@std/assert@0.217",
69
69
+
"jsr:@std/path@0.217"
55
70
]
56
71
},
57
57
-
"@zip-js/zip-js@2.7.41": {
58
58
-
"integrity": "a883116c1b46673de643f9cd3b6619d746271b96cd9a8e2b9d0bb8353d764d3d"
72
72
+
"@std/path@0.214.0": {
73
73
+
"integrity": "d5577c0b8d66f7e8e3586d864ebdf178bb326145a3611da5a51c961740300285",
74
74
+
"dependencies": [
75
75
+
"jsr:@std/assert@0.214"
76
76
+
]
77
77
+
},
78
78
+
"@std/path@0.217.0": {
79
79
+
"integrity": "1217cc25534bca9a2f672d7fe7c6f356e4027df400c0e85c0ef3e4343bc67d11",
80
80
+
"dependencies": [
81
81
+
"jsr:@std/assert@0.217"
82
82
+
]
59
83
}
60
84
},
61
85
"npm": {
···
74
98
},
75
99
"@atcute/client@2.0.3": {
76
100
"integrity": "sha512-j9GryA5l+4F0BTQWa6/1XmsuSPSq+bqNCY3mrHUGD592hMqUZxgpYDLgRWL+719V287AW/56AwvFYlbjlENp7A=="
101
101
+
},
102
102
+
"tex-linebreak@0.7.1": {
103
103
+
"integrity": "sha512-DioAcgbUGvacQSNJBcHoIUl2MnjWpNGz3R9tDX6gjtn/c+59ySW1dyFGMhIpl+u7sT+ywRwYAoAtk+wA5xUIsg=="
77
104
}
78
78
-
},
79
79
-
"remote": {
80
80
-
"https://deno.land/x/imagescript@1.3.0/ImageScript.js": "cf90773c966031edd781ed176c598f7ed495e7694cd9b86c986d2d97f783cca0",
81
81
-
"https://deno.land/x/imagescript@1.3.0/mod.ts": "18a6cb83c55e690c873505f6fe867364c678afb64934fe7aef593a6b92f79995",
82
82
-
"https://deno.land/x/imagescript@1.3.0/png/src/crc.mjs": "5cf50de181d61dd00e66a240d811018ba5070afa8bba302f393604404604de84",
83
83
-
"https://deno.land/x/imagescript@1.3.0/png/src/mem.mjs": "4968d400dae069b4bf0ef4767c1802fd2cc7d15d90eda4cfadf5b4cd19b96c6d",
84
84
-
"https://deno.land/x/imagescript@1.3.0/png/src/png.mjs": "96ef0ceff1b5a6cd9304749e5f187b4ab238509fb5f9a8be8ee934240271ed8d",
85
85
-
"https://deno.land/x/imagescript@1.3.0/png/src/zlib.mjs": "9867dc3fab1d31b664f9344b0d7e977f493d9c912a76c760d012ed2b89f7061c",
86
86
-
"https://deno.land/x/imagescript@1.3.0/utils/buffer.js": "952cb1beb8827e50a493a5d1f29a4845e8c648789406d389dd51f51205ba02d8",
87
87
-
"https://deno.land/x/imagescript@1.3.0/utils/crc32.js": "573d6222b3605890714ebc374e687ec2aa3e9a949223ea199483e47ca4864f7d",
88
88
-
"https://deno.land/x/imagescript@1.3.0/utils/png.js": "fbed9117e0a70602645d70df9c103ff6e79c03e987bd5c1685dcb4200729b6de",
89
89
-
"https://deno.land/x/imagescript@1.3.0/utils/wasm/font.js": "9e75d842608c057045698d6a7cdf5ffd27241b5cdea0391c89a1917b31294524",
90
90
-
"https://deno.land/x/imagescript@1.3.0/utils/wasm/gif.js": "8b86f7b96486bb8ff50fbc7c7487f86cb5cef85e6acd71e1def78a1aa2f12e4f",
91
91
-
"https://deno.land/x/imagescript@1.3.0/utils/wasm/jpeg.js": "75295e2fcf96b4f7bb894b3844fdaa8140d63169d28b466b5d5be89d59a7b6e6",
92
92
-
"https://deno.land/x/imagescript@1.3.0/utils/wasm/png.js": "0659536a8dd8f892c8346e268b2754b4414fad0ec1e9794dfcde1ba1c804ee02",
93
93
-
"https://deno.land/x/imagescript@1.3.0/utils/wasm/svg.js": "f5c8a9d1977b51a7c07549ceb6bbbaca9497321a193f28b3dc229a42d91bcf14",
94
94
-
"https://deno.land/x/imagescript@1.3.0/utils/wasm/tiff.js": "c2d7bdaef094df25aae1752e75167f485e89275d76a1379e39d8949580b7af4f",
95
95
-
"https://deno.land/x/imagescript@1.3.0/utils/wasm/zlib.js": "749875f83abffe24d3b977475a0cbd5f9b52bee1fbdbef61ec183cbfc17805f6",
96
96
-
"https://deno.land/x/imagescript@1.3.0/v2/framebuffer.mjs": "add44ff184636659714b3c6d4b896f628545451abffbc30b5bcc2e8d9a73d012",
97
97
-
"https://deno.land/x/imagescript@1.3.0/v2/ops/blur.mjs": "80716f1ffab8a2aeb54a036f583bf51a2b9dd37e005adc000add803df8e8a12f",
98
98
-
"https://deno.land/x/imagescript@1.3.0/v2/ops/color.mjs": "5e72cdcbf97dc939a2795223f01e3cb0544c0c56b03ea2aa026050df58348814",
99
99
-
"https://deno.land/x/imagescript@1.3.0/v2/ops/crop.mjs": "69431fa6f687fd9f0c31eff0ec27d7ac925275005e53a37f0c3fab4cc4d9a9ea",
100
100
-
"https://deno.land/x/imagescript@1.3.0/v2/ops/fill.mjs": "cf1b9488314753fbc9ebf03410ac74c2a34ea5a69fb6892cd6e8366cd1930d93",
101
101
-
"https://deno.land/x/imagescript@1.3.0/v2/ops/flip.mjs": "825a34a66567dcf15e76a719f1bf2f66fb106503cd69942292b1b0ae05c5718e",
102
102
-
"https://deno.land/x/imagescript@1.3.0/v2/ops/index.mjs": "423ba687119be2bba8cec72890577d3afa3621b6b8108912242fe937a183f2aa",
103
103
-
"https://deno.land/x/imagescript@1.3.0/v2/ops/iterator.mjs": "c2adf3d90ce00719a02c48c97634574176a3501ff026676259bd71aa8f5d69b9",
104
104
-
"https://deno.land/x/imagescript@1.3.0/v2/ops/overlay.mjs": "7e6e2c2ffd25006d52597ab8babc5f8f503d388a3fdf2fbc0eaea02799a020c9",
105
105
-
"https://deno.land/x/imagescript@1.3.0/v2/ops/resize.mjs": "814e78ebce8eaf8f1f918688db7b52a141405e06a36ed4b25d04413d69e7d17b",
106
106
-
"https://deno.land/x/imagescript@1.3.0/v2/ops/rotate.mjs": "a1b65616717bd2eed8db406affea3263b4674dada46b56441ef38167a187455d",
107
107
-
"https://deno.land/x/imagescript@1.3.0/v2/util/mem.mjs": "4968d400dae069b4bf0ef4767c1802fd2cc7d15d90eda4cfadf5b4cd19b96c6d"
108
105
}
109
106
}
+2
-2
main.ts
···
1
1
-
import { generateScreenshot } from "./utils/astralUtils.ts";
1
1
+
import { generatePng } from "./utils/canvasUtils.ts";
2
2
import { createBskyPost } from "./utils/blueskyUtils.ts";
3
3
import { load } from "jsr:@std/dotenv";
4
4
···
64
64
let index = result.value ?? 0;
65
65
66
66
// Generate screenshot and upload it to Bluesky
67
67
-
const { image, aspectRatio } = await generateScreenshot(
67
67
+
const { image, aspectRatio } = generatePng(
68
68
data[index].quote, // "image.png"
69
69
);
70
70
await createBskyPost(data[0], image, aspectRatio);
-106
utils/astralUtils.ts
···
1
1
-
import { launch } from "jsr:@astral/astral";
2
2
-
import { decode, Image } from "https://deno.land/x/imagescript@1.3.0/mod.ts";
3
3
-
import { generateStyledHTML } from "./textUtils.ts";
4
4
-
5
5
-
interface AspectRatio {
6
6
-
width: number;
7
7
-
height: number;
8
8
-
}
9
9
-
interface ResponseData {
10
10
-
image: Uint8Array;
11
11
-
aspectRatio: AspectRatio;
12
12
-
}
13
13
-
14
14
-
async function addPaddingToImage(
15
15
-
imageData: Uint8Array,
16
16
-
padding: number,
17
17
-
): Promise<{ paddedImage: Uint8Array; newAspectRatio: AspectRatio }> {
18
18
-
// Decode the original image
19
19
-
const decodedImage = await decode(imageData);
20
20
-
if (!(decodedImage instanceof Image)) {
21
21
-
throw new Error("Decoded image is not a static image");
22
22
-
}
23
23
-
const originalImage = decodedImage;
24
24
-
25
25
-
// Create a new image with padding
26
26
-
const paddedWidth = originalImage.width + (padding * 2);
27
27
-
const paddedHeight = originalImage.height + (padding * 2);
28
28
-
const newImage = new Image(paddedWidth, paddedHeight);
29
29
-
30
30
-
// Fill with ivory color (255, 255, 240)
31
31
-
newImage.fill(0xFFFFF0FF);
32
32
-
33
33
-
// Composite the original image onto the new one with padding offset
34
34
-
newImage.composite(originalImage, padding, padding);
35
35
-
36
36
-
// Encode the result back to PNG
37
37
-
const paddedImage = await newImage.encode();
38
38
-
39
39
-
return {
40
40
-
paddedImage,
41
41
-
newAspectRatio: {
42
42
-
width: paddedWidth,
43
43
-
height: paddedHeight,
44
44
-
},
45
45
-
};
46
46
-
}
47
47
-
48
48
-
export async function generateScreenshot(
49
49
-
string: string,
50
50
-
outputPath: string | undefined = undefined,
51
51
-
): Promise<ResponseData> {
52
52
-
const browser = await launch({
53
53
-
args: ["--no-sandbox"],
54
54
-
});
55
55
-
56
56
-
const page = await browser.newPage();
57
57
-
58
58
-
const styledHTML = generateStyledHTML(string)
59
59
-
.replace(/padding:\s*40px;/g, "padding: 0;")
60
60
-
.replace(
61
61
-
/font-size:\s*clamp\(14px,\s*12px\s*\+\s*0.75vw,\s*20px\);/,
62
62
-
"font-size: 20px;",
63
63
-
);
64
64
-
65
65
-
await page.setContent(`
66
66
-
<!DOCTYPE html>
67
67
-
<html lang="en">
68
68
-
<head>
69
69
-
<meta charset="UTF-8">
70
70
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
71
71
-
<title>HTML Screenshot</title>
72
72
-
<link href="https://fonts.googleapis.com/css2?family=Merriweather&display=swap" rel="stylesheet" />
73
73
-
<style>
74
74
-
body {
75
75
-
margin: 0;
76
76
-
padding: 0;
77
77
-
}
78
78
-
</style>
79
79
-
</head>
80
80
-
<body>
81
81
-
${styledHTML}
82
82
-
</body>
83
83
-
</html>
84
84
-
`);
85
85
-
86
86
-
await page.waitForSelector(".styled-container");
87
87
-
88
88
-
// Select the element
89
89
-
const element = await page.$(".styled-container");
90
90
-
if (!element) {
91
91
-
throw new Error("Element not found!");
92
92
-
}
93
93
-
94
94
-
const screenshot = await element.screenshot();
95
95
-
96
96
-
await browser.close();
97
97
-
98
98
-
// Add padding in post-processing using ImageScript
99
99
-
const { paddedImage, newAspectRatio } = await addPaddingToImage(
100
100
-
screenshot,
101
101
-
40,
102
102
-
);
103
103
-
if (outputPath) Deno.writeFileSync(outputPath, paddedImage);
104
104
-
105
105
-
return { image: paddedImage, aspectRatio: newAspectRatio };
106
106
-
}
+2
-1
utils/canvasUtils.ts
···
211
211
};
212
212
213
213
const pngCanvas: Canvas = generateCanvas(createLocalCanvas, quote);
214
214
+
const aspectRatio = { width: pngCanvas.width, height: pngCanvas.height };
214
215
if (path) {
215
216
pngCanvas.save(path);
216
217
}
217
217
-
return pngCanvas.encode("png");
218
218
+
return { image: pngCanvas.encode("png"), aspectRatio};
218
219
}