···1515image = { version = "0.25.9", default-features = false, features = ["default-formats"] }
1616imageproc = { version = "0.26.0", default-features = false }
1717jacquard = { version = "0.9.5", default-features = false, features = ["api_bluesky", "cache"] }
1818+sha2 = { version = "0.10.9", default-features = false, features = ["std"] }
1819tokio = "1.49.0"
+3-3
README.md
···10101111the identifier can be your handle or DID.
12121313-the program rotates your profile picture to the time of day, at 06:00 it'll be
1414-90 degrees, at 12:00 it'll be 180 degrees, at 18:00 it'll be 270 degrees, at 00:00
1515-it'll be 0 degrees.
1313+the program rotates your profile picture throughout the day, in accordance with
1414+the current time of day (so 12:00 -> 180, 18:00 -> 270), plus a random offset based
1515+on your DID.
16161717the sanctioned way of running this program is as follows:
1818
+30-17
src/main.rs
···1313 identity::JacquardResolver,
1414 types::{aturi::AtUri, blob::MimeType},
1515};
1616+use sha2::{Digest, Sha256};
1617use std::{
1718 env,
1819 io::Cursor,
···4748 process::exit(1);
4849}
49505050-fn compute_angle() -> i32 {
5151- const MS_PER_DAY: i128 = 86_400_000;
5252- let now_ms = match SystemTime::now().duration_since(UNIX_EPOCH) {
5353- Ok(dur) => dur.as_secs() as i128 * 1000 + dur.subsec_millis() as i128,
5454- Err(e) => -((e.duration().as_secs() as i128) * 1000 + e.duration().subsec_millis() as i128),
5555- };
5151+fn calculate_offset_from_did<S: AsRef<str>>(did: S) -> i32 {
5252+ let mut hasher = Sha256::new();
5353+ hasher.update(did.as_ref().to_lowercase().as_bytes());
56545757- // make sure issa positive. i love spreading positivity everywhere i go!!! :D
5858- let days = (now_ms).div_euclid(MS_PER_DAY);
5959- let reference_ms = days * MS_PER_DAY;
5555+ let digest = hasher.finalize();
5656+ let arr: [u8; 8] = digest[0..8].try_into().unwrap();
5757+ let v = u64::from_le_bytes(arr);
60586161- let elapsed = now_ms - reference_ms;
6262- let ms_today = ((elapsed % MS_PER_DAY) + MS_PER_DAY) % MS_PER_DAY;
5959+ (v % 360) as i32
6060+}
63616464- let fraction_of_day = (ms_today as f64) / (MS_PER_DAY as f64);
6565- let angle = (fraction_of_day * 360.0).floor() as i32;
6262+fn compute_angle<S: AsRef<str>>(did: S) -> i32 {
6363+ const MS_PER_DAY: u128 = 86_400_000;
6464+ let now_ms = SystemTime::now()
6565+ .duration_since(UNIX_EPOCH)
6666+ .unwrap_or_else(|e| {
6767+ eprintln!("warning: system time before epoch: {:?}", e);
6868+ std::time::Duration::from_millis(0)
6969+ })
7070+ .as_millis();
66716767- ((angle % 360) + 360) % 360
7272+ let ms_today = now_ms % MS_PER_DAY;
7373+ let time_angle = ((ms_today * 360) / MS_PER_DAY) as i32;
7474+7575+ let did_offset = calculate_offset_from_did(did);
7676+ let final_angle = (time_angle + did_offset) % 360;
7777+7878+ println!(
7979+ "computed angle: time_angle={} did_offset={} final_angle={}",
8080+ time_angle, did_offset, final_angle
8181+ );
8282+ final_angle
6883}
69847085fn rotate_image(image: DynamicImage, degrees: i32, bg_color: image::Rgba<u8>) -> image::RgbaImage {
···206221 process::exit(1);
207222 });
208223209209- let angle = compute_angle();
224224+ let angle = compute_angle(&auth.did);
210225 if let Some(prev) = read_state() {
211226 if prev == angle {
212227 println!("profile picture is already at {} degrees", angle);
···224239 }
225240226241 update_avatar(rotated, &agent, &mime_type).await;
227227-228242 write_state(angle);
229229- println!("rotated profile picture by {} degrees", angle);
230243}