tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
28
pulls
pipelines
use cloudflare browser api instead of microlink
awarm.space
3 months ago
b70eb51d
a613e397
+57
-25
3 changed files
expand all
collapse all
unified
split
app
[leaflet_id]
publish
publishBskyPost.ts
api
link_previews
route.ts
src
utils
getMicroLinkOgImage.ts
+9
-8
app/[leaflet_id]/publish/publishBskyPost.ts
···
12
12
import { createOauthClient } from "src/atproto-oauth";
13
13
import { supabaseServerClient } from "supabase/serverClient";
14
14
import { Json } from "supabase/database.types";
15
15
+
import {
16
16
+
getMicroLinkOgImage,
17
17
+
getWebpageImage,
18
18
+
} from "src/utils/getMicroLinkOgImage";
15
19
16
20
export async function publishPostToBsky(args: {
17
21
text: string;
···
31
35
credentialSession.fetchHandler.bind(credentialSession),
32
36
);
33
37
let newPostUrl = args.url;
34
34
-
let preview_image = await fetch(
35
35
-
`https://pro.microlink.io/?url=${newPostUrl}&screenshot=true&viewport.width=1400&viewport.height=733&meta=false&embed=screenshot.url&force=true`,
36
36
-
{
37
37
-
headers: {
38
38
-
"x-api-key": process.env.MICROLINK_API_KEY!,
39
39
-
},
40
40
-
},
41
41
-
);
38
38
+
let preview_image = await getWebpageImage(newPostUrl, {
39
39
+
width: 1400,
40
40
+
height: 733,
41
41
+
noCache: true,
42
42
+
});
42
43
43
44
let binary = await preview_image.blob();
44
45
let resized_preview_image = await sharp(await binary.arrayBuffer())
+5
-11
app/api/link_previews/route.ts
···
5
5
import * as z from "zod";
6
6
import { createClient } from "@supabase/supabase-js";
7
7
import { Database } from "supabase/database.types";
8
8
+
import {
9
9
+
getMicroLinkOgImage,
10
10
+
getWebpageImage,
11
11
+
} from "src/utils/getMicroLinkOgImage";
8
12
let supabase = createClient<Database>(
9
13
process.env.NEXT_PUBLIC_SUPABASE_API_URL as string,
10
14
process.env.SUPABASE_SERVICE_ROLE_KEY as string,
···
27
31
export type LinkPreviewImageResult = ReturnType<typeof get_link_image_preview>;
28
32
29
33
async function get_link_image_preview(url: string) {
30
30
-
let image = await fetch(
31
31
-
`https://pro.microlink.io/?url=${url}&screenshot&viewport.width=1400&viewport.height=1213&embed=screenshot.url&meta=false&force=true`,
32
32
-
{
33
33
-
headers: {
34
34
-
"x-api-key": process.env.MICROLINK_API_KEY!,
35
35
-
},
36
36
-
next: {
37
37
-
revalidate: 600,
38
38
-
},
39
39
-
},
40
40
-
);
34
34
+
let image = await getWebpageImage(url, { width: 1400, height: 1213 });
41
35
let key = await hash(url);
42
36
if (image.status === 200) {
43
37
await supabase.storage
+43
-6
src/utils/getMicroLinkOgImage.ts
···
2
2
3
3
export async function getMicroLinkOgImage(
4
4
path: string,
5
5
-
options?: { width?: number; height?: number; deviceScaleFactor?: number },
5
5
+
options?: {
6
6
+
width?: number;
7
7
+
height?: number;
8
8
+
deviceScaleFactor?: number;
9
9
+
noCache?: boolean;
10
10
+
},
6
11
) {
7
12
const headersList = await headers();
8
13
const hostname = headersList.get("x-forwarded-host");
9
14
let protocol = headersList.get("x-forwarded-proto");
10
15
let full_path = `${protocol}://${hostname}${path}`;
16
16
+
return getWebpageImage(full_path, options);
17
17
+
}
18
18
+
19
19
+
export async function getWebpageImage(
20
20
+
url: string,
21
21
+
options?: {
22
22
+
width?: number;
23
23
+
height?: number;
24
24
+
deviceScaleFactor?: number;
25
25
+
noCache?: boolean;
26
26
+
},
27
27
+
) {
11
28
let response = await fetch(
12
12
-
`https://pro.microlink.io/?url=${encodeURIComponent(full_path)}&screenshot=true&viewport.width=${options?.width || 1400}&viewport.height=${options?.height || 733}&viewport.deviceScaleFactor=${options?.deviceScaleFactor || 1}&meta=false&embed=screenshot.url&force=true`,
29
29
+
`https://api.cloudflare.com/client/v4/accounts/${process.env.CLOUDFLARE_ACCOUNT}/browser-rendering/screenshot`,
13
30
{
31
31
+
method: "POST",
14
32
headers: {
15
15
-
"x-api-key": process.env.MICROLINK_API_KEY!,
33
33
+
"Content-type": "application/json",
34
34
+
Authorization: `Bearer ${process.env.CLOUDFLARE_API_TOKEN}`,
16
35
},
17
17
-
next: {
18
18
-
revalidate: 600,
19
19
-
},
36
36
+
body: JSON.stringify({
37
37
+
url,
38
38
+
addStyleTag: [
39
39
+
{
40
40
+
content: `* {overflow: hidden !important; }`,
41
41
+
},
42
42
+
],
43
43
+
gotoOptions: {
44
44
+
waitUntil: "load",
45
45
+
},
46
46
+
viewport: {
47
47
+
width: options?.width || 1400,
48
48
+
height: options?.height || 733,
49
49
+
deviceScaleFactor: options?.deviceScaleFactor,
50
50
+
},
51
51
+
}),
52
52
+
next: !options?.noCache
53
53
+
? undefined
54
54
+
: {
55
55
+
revalidate: 600,
56
56
+
},
20
57
},
21
58
);
22
59
const clonedResponse = response.clone();