a tool for shared writing and social publishing

use cloudflare browser api instead of microlink

+57 -25
+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 + import { 16 + getMicroLinkOgImage, 17 + getWebpageImage, 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 - let preview_image = await fetch( 35 - `https://pro.microlink.io/?url=${newPostUrl}&screenshot=true&viewport.width=1400&viewport.height=733&meta=false&embed=screenshot.url&force=true`, 36 - { 37 - headers: { 38 - "x-api-key": process.env.MICROLINK_API_KEY!, 39 - }, 40 - }, 41 - ); 38 + let preview_image = await getWebpageImage(newPostUrl, { 39 + width: 1400, 40 + height: 733, 41 + noCache: true, 42 + }); 42 43 43 44 let binary = await preview_image.blob(); 44 45 let resized_preview_image = await sharp(await binary.arrayBuffer())
+43 -6
src/utils/getMicroLinkOgImage.ts
··· 2 2 3 3 export async function getMicroLinkOgImage( 4 4 path: string, 5 - options?: { width?: number; height?: number; deviceScaleFactor?: number }, 5 + options?: { 6 + width?: number; 7 + height?: number; 8 + deviceScaleFactor?: number; 9 + noCache?: boolean; 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 + return getWebpageImage(full_path, options); 17 + } 18 + 19 + export async function getWebpageImage( 20 + url: string, 21 + options?: { 22 + width?: number; 23 + height?: number; 24 + deviceScaleFactor?: number; 25 + noCache?: boolean; 26 + }, 27 + ) { 11 28 let response = await fetch( 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 + `https://api.cloudflare.com/client/v4/accounts/${process.env.CLOUDFLARE_ACCOUNT}/browser-rendering/screenshot`, 13 30 { 31 + method: "POST", 14 32 headers: { 15 - "x-api-key": process.env.MICROLINK_API_KEY!, 33 + "Content-type": "application/json", 34 + Authorization: `Bearer ${process.env.CLOUDFLARE_API_TOKEN}`, 16 35 }, 17 - next: { 18 - revalidate: 600, 19 - }, 36 + body: JSON.stringify({ 37 + url, 38 + addStyleTag: [ 39 + { 40 + content: `* {overflow: hidden !important; }`, 41 + }, 42 + ], 43 + gotoOptions: { 44 + waitUntil: "load", 45 + }, 46 + viewport: { 47 + width: options?.width || 1400, 48 + height: options?.height || 733, 49 + deviceScaleFactor: options?.deviceScaleFactor, 50 + }, 51 + }), 52 + next: !options?.noCache 53 + ? undefined 54 + : { 55 + revalidate: 600, 56 + }, 20 57 }, 21 58 ); 22 59 const clonedResponse = response.clone();