Schedule posts to Bluesky with Cloudflare workers. skyscheduler.work
cf tool bsky-tool cloudflare bluesky schedule bsky service social-media cloudflare-workers
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 66 lines 2.7 kB view raw
1import isEmpty from 'just-is-empty'; 2import split from 'just-split'; 3import type { AllContext } from '../../types'; 4import { getAllPostedPosts, getAllPostedPostsOfUser } from '../db/data'; 5import { getPostRecords } from './bskyApi'; 6 7// This looks for a bunch of posts that are posted and determines if the posts 8// are still on the network or not. If they are not, then this prunes the posts from 9// the database. This call is quite expensive and should only be ran on a weekly 10// cron job. 11export const pruneBskyPosts = async (c: AllContext, userId?: string) => { 12 const allPostedPosts = (userId !== undefined) ? await getAllPostedPostsOfUser(c, userId) : await getAllPostedPosts(c); 13 let removePostIds: string[] = []; 14 let postedGroups = split(allPostedPosts, 25); 15 while (!isEmpty(postedGroups)) { 16 const currentGroup = postedGroups.pop(); 17 // This technically shouldn't be possible because we do a check in the while loop beforehand. 18 if (currentGroup === undefined) { 19 console.error("current group was somehow undefined..."); 20 break; 21 } 22 23 // Create a map and an array so we can do lookups for reconciliation later 24 // to figure out what posts can be removed. 25 let urisOnly: string[] = []; 26 const postMap: Map<string, string> = new Map(); 27 currentGroup.forEach((itm) => { 28 if (itm.uri === null) { 29 console.log(`Skipping a "posted" post that does not have an uri: ${itm.id}`); 30 return; 31 } 32 postMap.set(itm.uri, itm.id); 33 urisOnly.push(itm.uri); 34 }); 35 36 try { 37 // Records from the public bsky api service 38 const bskyLookupResults = await getPostRecords(urisOnly); 39 if (bskyLookupResults !== null) { 40 // There is a discrepancy, we need to find which record it is. 41 if (bskyLookupResults.length !== urisOnly.length) { 42 // Go through the entire lookup results 43 while (!isEmpty(bskyLookupResults)) { 44 // remove the object at the end so we can try to figure out what's left 45 const currentRecord = bskyLookupResults.pop(); 46 if (currentRecord === undefined) 47 break; 48 49 // if this record exists, remove it from our post map 50 // we will reconcile outside of this loop to delete the posts. 51 postMap.delete(currentRecord.uri); 52 } 53 // Add all the deleted keys to the main array. 54 postMap.forEach((value, key) => { 55 removePostIds.push(value); 56 }); 57 } 58 } 59 } catch(err) { 60 console.error(`encountered error trying to prune: ${err}`); 61 // Remove all the posts in the current post group. 62 continue; 63 } 64 } 65 return removePostIds; 66};