Compare commits

...

3 Commits

Author SHA1 Message Date
Greg Shuflin
b2dffd4df0 Move some code into a post module 2025-07-21 19:13:19 -07:00
Greg Shuflin
a80e84f0d3 Upgrade colored 2025-07-13 22:45:37 -07:00
Greg Shuflin
8bf90c4f31 cargo upgrade packages 2025-07-13 22:45:15 -07:00
4 changed files with 283 additions and 136 deletions

114
Cargo.lock generated
View File

@@ -94,7 +94,7 @@ dependencies = [
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets",
"windows-targets 0.52.6",
]
[[package]]
@@ -204,11 +204,10 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "colored"
version = "2.2.0"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
dependencies = [
"lazy_static",
"windows-sys 0.59.0",
]
@@ -294,7 +293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -592,12 +591,6 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.174"
@@ -760,7 +753,7 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
"windows-targets 0.52.6",
]
[[package]]
@@ -913,7 +906,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -1084,7 +1077,7 @@ dependencies = [
"getrandom 0.3.3",
"once_cell",
"rustix",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -1284,7 +1277,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
"windows-targets 0.52.6",
]
[[package]]
@@ -1293,7 +1286,16 @@ version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.2",
]
[[package]]
@@ -1302,14 +1304,30 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
dependencies = [
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
"windows_i686_gnullvm 0.53.0",
"windows_i686_msvc 0.53.0",
"windows_x86_64_gnu 0.53.0",
"windows_x86_64_gnullvm 0.53.0",
"windows_x86_64_msvc 0.53.0",
]
[[package]]
@@ -1318,48 +1336,96 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"

View File

@@ -4,14 +4,14 @@ version = "0.1.0"
edition = "2024"
[dependencies]
tokio = { version = "1.0", features = ["full"] }
tokio = { version = "1.46", features = ["full"] }
tokio-tungstenite = { version = "0.20", features = ["native-tls"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
colored = "2.0"
clap = { version = "4.0", features = ["derive"] }
colored = "3.0.0"
clap = { version = "4.5", features = ["derive"] }
futures-util = "0.3"
url = "2.4"
url = "2.5"
log = "0.4"
env_logger = "0.10"
rand = "0.8"

View File

@@ -2,32 +2,12 @@ use clap::Parser;
use colored::*;
use futures_util::StreamExt;
use log::{debug, warn};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
#[derive(Debug, Deserialize, Serialize)]
struct Post {
kind: Option<String>,
#[serde(rename = "type")]
type_: Option<String>,
time_us: Option<u64>,
did: Option<String>,
commit: Option<CommitData>,
}
mod post;
#[derive(Debug, Deserialize, Serialize)]
struct CommitData {
#[serde(rename = "type")]
type_: Option<String>,
operation: Option<String>,
record: Option<RecordData>,
}
#[derive(Debug, Deserialize, Serialize)]
struct RecordData {
text: Option<String>,
}
use post::*;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
@@ -91,17 +71,6 @@ impl BlueskyFirehosePrinter {
colored::Color::TrueColor { r, g, b }
}
fn extract_post_text(&self, post: &Post) -> String {
if let Some(ref commit) = post.commit {
if let Some(ref record) = commit.record {
if let Some(ref text) = record.text {
return text.chars().take(200).collect();
}
}
}
format!("{:?}", post)
}
async fn connect_and_print(
&self,
websocket_url: &str,
@@ -126,79 +95,40 @@ impl BlueskyFirehosePrinter {
match serde_json::from_str::<Post>(&text) {
Ok(mut post) => {
// Handle missing fields
if post.kind.is_none() {
post.kind = post.type_.clone();
}
post.normalize();
// Apply filters
if !onlys.is_empty() {
if let Some(ref kind) = post.kind {
if !onlys.contains(kind) {
continue;
}
}
if !post.matches_only_filter(onlys) {
continue;
}
if let Some(ref kind) = post.kind {
if skips.contains(kind) {
continue;
}
if post.should_skip(skips) {
continue;
}
let ts = post.time_us.unwrap_or(0) / 10_000;
let ts = post.get_time_us().unwrap_or(0) / 10_000;
// Generate HSV color based on timestamp
let h = ((ts as f64 / 4.0) % 255.0) / 255.0 * 360.0;
let mut s = 0.8;
let mut v = 0.8;
let v;
let mut text = String::new();
// Apply commit type filters
if !post.matches_commit_type_filters(cfilters) {
continue;
}
// Handle commit type filtering and text extraction
if post.kind.as_deref() == Some("commit") {
if let Some(ref commit) = post.commit {
if let Some(ref commit_type) = commit.type_ {
// Apply commit type filters
if let Some(excludes) = cfilters.get("-") {
if excludes.iter().any(|w| commit_type.contains(w)) {
continue;
}
}
if let Some(includes) = cfilters.get("+") {
if !includes.iter().any(|w| commit_type.contains(w)) {
continue;
}
}
}
// Extract and filter text
let text = match post.extract_and_filter_text(fkeeps, fdrops) {
Some(text) => text,
None => continue, // Text was filtered out
};
if let Some(ref record) = commit.record {
if let Some(ref record_text) = record.text {
// Apply text filters
if !fdrops.is_empty() {
if fdrops.iter().any(|w| record_text.contains(w)) {
continue;
}
}
if !fkeeps.is_empty() {
if !fkeeps.iter().any(|w| record_text.contains(w)) {
continue;
}
}
text = record_text.clone();
// Adjust brightness based on text length
v = 1.0
- (text.len() as f64)
.ln()
.min(16.0 * 256.0_f64.ln())
/ (16.0 * 256.0_f64.ln());
} else {
text = format!("commit.record={:?}", record);
}
}
}
// Adjust color based on post type and text
if post.get_kind() == Some("commit") {
// Adjust brightness based on text length
v = post.calculate_text_brightness(&text);
} else {
text = self.extract_post_text(&post);
s = 0.8;
v = 120.0 / 255.0;
}
@@ -213,24 +143,15 @@ impl BlueskyFirehosePrinter {
// Print colored output
let hsv_str = format!("{:.1}:{:.1}:{:.1}", h / 360.0, s, v);
let _post_id = post.did.unwrap_or_else(|| {
format!("r:{}", rand::random::<f64>())
});
let _post_id = post.get_post_id();
let type_str = post.type_.as_deref().unwrap_or("None");
let kind_str = post.kind.as_deref().unwrap_or("None");
let type_str = post.get_type().unwrap_or("None");
let kind_str = post.get_kind().unwrap_or("None");
if post.type_.as_deref() == Some("com") {
let commit_type = post
.commit
.as_ref()
.and_then(|c| c.type_.as_deref())
.unwrap_or("None");
let operation = post
.commit
.as_ref()
.and_then(|c| c.operation.as_deref())
.unwrap_or("None");
if post.get_type() == Some("com") {
let (commit_type, operation) = post.get_commit_info();
let commit_type = commit_type.unwrap_or("None");
let operation = operation.unwrap_or("None");
println!(
"{}{}|type:{}|{}{}{}|hsv:{} type:{} kind:{} commit.type={} operation={}",

160
src/post.rs Normal file
View File

@@ -0,0 +1,160 @@
use rand;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Deserialize, Serialize)]
pub struct Post {
kind: Option<String>,
#[serde(rename = "type")]
type_: Option<String>,
time_us: Option<u64>,
did: Option<String>,
commit: Option<CommitData>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct CommitData {
#[serde(rename = "type")]
type_: Option<String>,
operation: Option<String>,
record: Option<RecordData>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct RecordData {
text: Option<String>,
}
impl Post {
/// Normalize the post by ensuring kind field is set
pub fn normalize(&mut self) {
if self.kind.is_none() {
self.kind = self.type_.clone();
}
}
/// Get the type of this post
pub fn get_type(&self) -> Option<&str> {
self.type_.as_deref()
}
/// Get the kind of this post
pub fn get_kind(&self) -> Option<&str> {
self.kind.as_deref()
}
/// Get the timestamp in microseconds
pub fn get_time_us(&self) -> Option<u64> {
self.time_us
}
/// Get the DID or generate a random one
pub fn get_post_id(&self) -> String {
self.did
.clone()
.unwrap_or_else(|| format!("r:{}", rand::random::<f64>()))
}
/// Check if this post matches the "only" filter
pub fn matches_only_filter(&self, onlys: &[String]) -> bool {
if onlys.is_empty() {
return true;
}
if let Some(ref kind) = self.kind {
onlys.contains(kind)
} else {
false
}
}
/// Check if this post should be skipped
pub fn should_skip(&self, skips: &[String]) -> bool {
if let Some(ref kind) = self.kind {
skips.contains(kind)
} else {
false
}
}
/// Check if this post matches commit type filters
pub fn matches_commit_type_filters(&self, cfilters: &HashMap<String, Vec<String>>) -> bool {
if self.kind.as_deref() != Some("commit") {
return true; // Non-commit posts pass commit filters
}
if let Some(ref commit) = self.commit {
if let Some(ref commit_type) = commit.type_ {
// Apply commit type filters
if let Some(excludes) = cfilters.get("-") {
if excludes.iter().any(|w| commit_type.contains(w)) {
return false;
}
}
if let Some(includes) = cfilters.get("+") {
if !includes.iter().any(|w| commit_type.contains(w)) {
return false;
}
}
}
}
true
}
/// Check if this post matches text filters and return the extracted text
pub fn extract_and_filter_text(&self, fkeeps: &[String], fdrops: &[String]) -> Option<String> {
if self.kind.as_deref() == Some("commit") {
if let Some(ref commit) = self.commit {
if let Some(ref record) = commit.record {
if let Some(ref record_text) = record.text {
// Apply text filters
if !fdrops.is_empty() {
if fdrops.iter().any(|w| record_text.contains(w)) {
return None;
}
}
if !fkeeps.is_empty() {
if !fkeeps.iter().any(|w| record_text.contains(w)) {
return None;
}
}
return Some(record_text.clone());
} else {
return Some(format!("commit.record={:?}", record));
}
}
}
} else {
return Some(self.extract_text());
}
None
}
/// Get commit information for display
pub fn get_commit_info(&self) -> (Option<&str>, Option<&str>) {
if let Some(ref commit) = self.commit {
(commit.type_.as_deref(), commit.operation.as_deref())
} else {
(None, None)
}
}
/// Calculate color brightness based on text length
pub fn calculate_text_brightness(&self, text: &str) -> f64 {
1.0 - (text.len() as f64).ln().min(16.0 * 256.0_f64.ln()) / (16.0 * 256.0_f64.ln())
}
pub fn extract_text(&self) -> String {
if let Some(ref commit) = self.commit {
if let Some(ref record) = commit.record {
if let Some(ref text) = record.text {
return text.chars().take(200).collect();
}
}
}
format!("{:?}", self)
}
}