Created
August 4, 2020 19:59
-
-
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
This file contains 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
[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" |
This file contains 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
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