46 releases (14 breaking)

0.16.5 May 23, 2024
0.16.0 Apr 28, 2024
0.15.1 Mar 27, 2024
0.14.1 Dec 26, 2023
0.6.3 Jul 28, 2023

#574 in Web programming

Apache-2.0

345KB
9K SLoC

Aerostream

Aerostream is Bluesky client using EventStream.

It can be used as a library or as a command line tool.

To use as a command line tool

cargo install aerostream -F terminal
aerostream

Notes

  • Only CUI, No need to log in.
  • Instead, you can't post, repost and like.
  • Configuration file must be edited in a text editor, and there is no configuration screen in the application.

Edit filters.yaml

filters:
  - name: <Column Name>
    subscribes:
      dids:
        - <DID to identify the repository to subscribe to>
      handles:
        - <Handle to identify the repository to subscribe to>
    keywords:
      includes:
        - <Keywords to include in Column even if you are not subscribed>
      excludes:
        - <Keywords to exclude in Column even if you are subscribed>
    langs:
      includes:
        - <Languages to include in Column even if you are not subscribed>
      excludes:
        - <Languages to exclude in Column even if you are subscribed>

Operation

  • q or Ctrl+c : quit this application
  • F5 or Ctrl+r : redraw screen
  • s : subscribe to the repository of the focused post in "Favorites" filter
  • u : unsubscribe to the repository of the focused post in "Favorites" filter
  • LEFT or RIGHT : change the filter in focus
  • UP or DOWN : change the post in focus
  • ESC : take the focus off the post
  • i : view attached image
  • j : view next attached image
  • k : view previous attached image
  • Backspace : leave image view
  • Enter : open bsky.app in the default browser with current post or image

To use as a library

use std::{
  io::{stdout, Write},
  time::Duration,
};

use aerostream::Client;
use anyhow::Result;
use chrono::Local;

fn main() -> Result<()> {
  let mut client = Client::default();
  client.set_timeout(5);
  client.connect_ws()?;
  for (filter, event) in client.next_event_filtered_all()?.iter() {
    let Some(commit) = event.as_commit() else {
      continue;
    };
    let posts = commit.get_post_text();
    if posts.is_empty() {
      continue;
    }
    let text = posts.join(" ").replace("\n", " ");
    let time = commit.time.with_timezone(&Local).format("%m/%d %H:%M");
    let handle = match client.get_repo(&commit.repo) {
      Ok(r) => r.handle.clone(),
      _ => String::from("UNKNOWN"),
    };
    let blobs = commit
      .blobs
      .iter()
      .map(|b| b.to_string())
      .collect::<Vec<_>>();
    print!("{} : {} : {} : {}", filter, time, handle, text);
    if !commit.blobs.is_empty() {
      println!(" : {}", blobs.join(","));
    } else {
      println!("");
    }
    stdout().flush().ok();
  }
  Ok(())
}

Dependencies

~10–26MB
~380K SLoC