Created
October 13, 2025 23:10
-
-
Save bbarker/9f9c2ce7bac9a9d890984e5b351fc30a to your computer and use it in GitHub Desktop.
Retrieve posts for a bluesky account - useful for checking if a bot, etc. Written in Nu (nushell)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env nu | |
| # Bluesky Reply Post Fetcher for Nushell | |
| # No authentication required for public posts | |
| # Run with: nu script.nu | |
| let handle = 'amy1017-99.bsky.social' | |
| let api_base = 'https://public.api.bsky.app/xrpc' | |
| print $"\n🔍 Analyzing account: ($handle)\n" | |
| print "Fetching posts...\n" | |
| # Fetch the author feed | |
| let data = http get $"($api_base)/app.bsky.feed.getAuthorFeed?actor=($handle)&limit=100" | |
| let posts = $data.feed | |
| if ($posts | length) == 0 { | |
| print "No posts found for this account." | |
| exit | |
| } | |
| # Filter for replies | |
| let replies = $posts | where { |item| | |
| ($item.post.record.reply? | is-not-empty) | |
| } | |
| # Statistics | |
| print "=== ACCOUNT STATISTICS ===" | |
| print $"Total posts retrieved: ($posts | length)" | |
| print $"Reply posts: ($replies | length)" | |
| print $"Original posts: (($posts | length) - ($replies | length))" | |
| let reply_ratio = (($replies | length) / ($posts | length) * 100) | |
| print $"Reply ratio: ($reply_ratio | into string | str substring 0..4)%" | |
| print "\n=== RECENT REPLIES ===\n" | |
| # Show details of recent replies | |
| $replies | first 20 | enumerate | each { |item| | |
| let post = $item.item.post | |
| let text = $post.record.text? | default "[no text]" | |
| let created_at = $post.record.createdAt? | default "" | |
| let reply_uri = $post.record.reply?.parent?.uri? | default "unknown" | |
| let replying_to = $reply_uri | split row "/" | last | |
| print $"($item.index + 1). Posted: ($created_at)" | |
| let short_text = if ($text | str length) > 100 { | |
| $"($text | str substring 0..100)..." | |
| } else { | |
| $text | |
| } | |
| print $" Text: ($short_text)" | |
| print $" Replying to: ($replying_to)" | |
| print $" Likes: ($post.likeCount? | default 0) | Replies: ($post.replyCount? | default 0) | Reposts: ($post.repostCount? | default 0)" | |
| print "" | |
| } | |
| # Bot indicators analysis | |
| print "\n=== BOT INDICATOR ANALYSIS ===" | |
| # Check posting time patterns | |
| print "\nPosting distribution by hour (UTC):" | |
| let hour_counts = $posts | each { |item| | |
| let created = $item.post.record.createdAt? | default "" | |
| if ($created | is-not-empty) { | |
| $created | into datetime | format date "%H" | into int | |
| } | |
| } | compact | group-by { |hour| $hour } | transpose hour count | update count { |row| $row.count | length } | |
| let max_count = $hour_counts | get count | math max | |
| $hour_counts | each { |row| | |
| let bar_length = (($row.count / $max_count) * 20 | math floor) | |
| let bar = ("█" | fill -w $bar_length -c "█" -a left | str substring 0..$bar_length) | |
| print $" ($row.hour | into string | fill -a right -c '0' -w 2):00 - ($bar) (($row.count))" | |
| } | |
| # Check for repetitive content | |
| let texts = $posts | each { |item| $item.post.record.text? | default "" } | |
| let unique_texts = $texts | uniq | length | |
| let total_posts = $posts | length | |
| let duplicate_rate = (($total_posts - $unique_texts) / $total_posts * 100) | |
| print $"\nContent diversity: ($unique_texts) unique posts out of ($total_posts) total" | |
| print $"Duplicate rate: ($duplicate_rate | into string | str substring 0..4)%" | |
| # Check average engagement | |
| let avg_likes = $posts | each { |item| $item.post.likeCount? | default 0 } | math avg | |
| let avg_replies = $posts | each { |item| $item.post.replyCount? | default 0 } | math avg | |
| print $"\nAverage likes per post: ($avg_likes | into string | str substring 0..4)" | |
| print $"Average replies per post: ($avg_replies | into string | str substring 0..4)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment