Skip to content

Instantly share code, notes, and snippets.

@NuroDev
Created August 4, 2020 19:59
Show Gist options
  • Save NuroDev/2fa3b72e413136a1691857480ac4dcff to your computer and use it in GitHub Desktop.
Save NuroDev/2fa3b72e413136a1691857480ac4dcff to your computer and use it in GitHub Desktop.
📸 Hubble - A simple twitter bot to screenshot a set number of a users tweets
[package]
name = "hubble"
version = "1.1.1"
authors = ["N U R O ™"]
edition = "2018"
[dependencies]
egg-mode = "0.13.0"
failure = "0.1.6"
headless_chrome = "0.9.0"
structopt = "0.3.7"
tokio = "0.1.22"
use egg_mode::{
tweet::{user_timeline, Timeline},
KeyPair, Token,
};
use failure::Fallible;
use headless_chrome::{protocol::page::ScreenshotFormat, Browser, LaunchOptionsBuilder};
use std::fs::{create_dir_all, write};
use structopt::StructOpt;
use tokio::runtime::current_thread::block_on_all;
const CONSUMER_KEY: &str = "";
const CONSUMER_SECRET: &str = "";
const ACCESS_KEY: &str = "";
const ACCESS_SECRET: &str = "";
#[derive(Debug, StructOpt)]
#[structopt(
name = "hubble",
about = "A simple twitter bot to screenshot a set number of a users tweets"
)]
struct CLI {
/// The Twitter username you wish to screenshot tweets of
#[structopt(name = "username")]
username: String,
/// Number of tweets to screenshot
#[structopt(name = "tweets")]
num_tweets: i32,
}
fn main() -> Fallible<()> {
// Get CLI arguments
let cli = CLI::from_args();
println!("============================================");
// Generate twitter access token using credentials provided above
let token: Token = Token::Access {
consumer: KeyPair::new(CONSUMER_KEY, CONSUMER_SECRET),
access: KeyPair::new(ACCESS_KEY, ACCESS_SECRET),
};
// Output directory name
let output_dir: String = format!("@{}", cli.username);
// Create the output directory if it doesn't already exist
create_dir_all(output_dir.clone()).expect("⛔️ Error creating output directory");
println!("📂 Created output directory");
println!("============================================");
// Get the users timeline
let timeline: Timeline =
user_timeline(&cli.username, true, true, &token).with_page_size(cli.num_tweets);
let (_user, feed) = block_on_all(timeline.start())?;
// Loop through all the fetched tweets & push them into the tweets vector
for status in feed {
// Concat base url with tweet id
let url: String = format!(
"https://twitter.com/{}/status/{}",
cli.username, status.response.id
);
// Create new headless browser instance
let browser: Browser = Browser::new(
LaunchOptionsBuilder::default()
.window_size(Some((1920, 1080)))
.build()
.expect("⛔️ Error building window builder"),
)?;
let tab = browser.wait_for_initial_tab()?;
// Screenshot the tab
let screenshot = tab
.navigate_to(&url.to_owned())?
.wait_until_navigated()?
.capture_screenshot(ScreenshotFormat::PNG, None, true)?;
// Save the screenshot to the output directory
let output_path: String = format!(
"./{}/{}.png",
output_dir,
status.response.created_at.format("%d-%m-%Y-%I-%M-%S%P")
);
write(output_path, &screenshot)?;
println!("📸 Screenshotted: {}", status.response.id);
println!("============================================");
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment