this repo has no description
at main 72 lines 2.6 kB view raw
1#!/usr/bin/env bun 2import { AtpAgent } from '@atproto/api' 3 4// Read credentials from .env 5const username = process.env.BSKY_USERNAME 6const password = process.env.BSKY_PASSWORD 7 8if (!username || !password) { 9 console.error('Please provide BSKY_USERNAME and BSKY_PASSWORD in .env file') 10 process.exit(1) 11} 12 13const agent = new AtpAgent({ service: 'https://bsky.social' }) 14 15console.log('Logging in...') 16await agent.login({ 17 identifier: username, 18 password: password 19}) 20 21console.log('Fetching timeline...\n') 22 23// Get the user's timeline 24const timeline = await agent.getTimeline({ limit: 50 }) 25 26// Filter posts that mention Chicago or ATProto 27const chicagoPosts = timeline.data.feed.filter(item => { 28 const text = item.post.record?.text?.toLowerCase() || '' 29 return text.includes('chicago') || 30 text.includes('atproto') || 31 text.includes('#atprotochicago') 32}) 33 34console.log(`Found ${chicagoPosts.length} posts mentioning Chicago/ATProto out of ${timeline.data.feed.length} recent posts:\n`) 35 36if (chicagoPosts.length === 0) { 37 console.log('No matching posts found. Try posting with #ATProtoChicago!') 38} else { 39 chicagoPosts.forEach((item, index) => { 40 const author = item.post.author.displayName || item.post.author.handle 41 const text = item.post.record?.text || '' 42 const time = new Date(item.post.record?.createdAt).toLocaleString() 43 44 console.log(`${index + 1}. ${author} (${time})`) 45 console.log(` ${text.substring(0, 100)}${text.length > 100 ? '...' : ''}`) 46 console.log(` Likes: ${item.post.likeCount || 0}, Reposts: ${item.post.repostCount || 0}`) 47 console.log('') 48 }) 49} 50 51// Bonus: Show posts with the most engagement 52console.log('\n📊 Bonus: Top 5 posts by engagement:') 53console.log('=====================================') 54 55const sortedByEngagement = timeline.data.feed 56 .sort((a, b) => { 57 const aEngagement = (a.post.likeCount || 0) + (a.post.repostCount || 0) * 2 58 const bEngagement = (b.post.likeCount || 0) + (b.post.repostCount || 0) * 2 59 return bEngagement - aEngagement 60 }) 61 .slice(0, 5) 62 63sortedByEngagement.forEach((item, index) => { 64 const author = item.post.author.displayName || item.post.author.handle 65 const text = item.post.record?.text || '' 66 const engagement = (item.post.likeCount || 0) + (item.post.repostCount || 0) * 2 67 68 console.log(`${index + 1}. ${author} (score: ${engagement})`) 69 console.log(` ${text.substring(0, 80)}${text.length > 80 ? '...' : ''}`) 70 console.log(` Likes: ${item.post.likeCount || 0}, Reposts: ${item.post.repostCount || 0}`) 71 console.log('') 72})