|
|
@ -1,38 +1,17 @@ |
|
|
|
use std::fs::File; |
|
|
|
|
|
|
|
use std::io; |
|
|
|
use std::io; |
|
|
|
use std::io::prelude::*; |
|
|
|
|
|
|
|
use std::path::Path; |
|
|
|
|
|
|
|
use std::path::PathBuf; |
|
|
|
|
|
|
|
use std::time::Duration; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use elefren::entities::attachment::Attachment; |
|
|
|
use crate::storage::storage::Storage; |
|
|
|
use elefren::entities::status::Status; |
|
|
|
|
|
|
|
use elefren::helpers::cli; |
|
|
|
use elefren::helpers::cli; |
|
|
|
use elefren::helpers::toml as elefren_toml; |
|
|
|
use elefren::helpers::toml as elefren_toml; |
|
|
|
use elefren::prelude::*; |
|
|
|
use elefren::prelude::*; |
|
|
|
|
|
|
|
|
|
|
|
use reqwest; |
|
|
|
mod config; |
|
|
|
|
|
|
|
mod storage; |
|
|
|
use serde_derive::Deserialize; |
|
|
|
|
|
|
|
use serde_derive::Serialize; |
|
|
|
|
|
|
|
use toml; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug)] |
|
|
|
|
|
|
|
struct JoplinConfig { |
|
|
|
|
|
|
|
port: u32, |
|
|
|
|
|
|
|
folder: String, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug)] |
|
|
|
|
|
|
|
struct Config { |
|
|
|
|
|
|
|
last_favorite: String, |
|
|
|
|
|
|
|
joplin: Option<JoplinConfig>, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn main() { |
|
|
|
fn main() { |
|
|
|
let config = dbg!(get_config()); |
|
|
|
let config = dbg!(config::Config::get()); |
|
|
|
let client = get_mastodon_connection(); |
|
|
|
let client = dbg!(get_mastodon_connection()); |
|
|
|
let top = config.last_favorite.to_string(); |
|
|
|
let top = dbg!(config.last_favorite.to_string()); |
|
|
|
|
|
|
|
|
|
|
|
let most_recent_favourite = client |
|
|
|
let most_recent_favourite = client |
|
|
|
.favourites() |
|
|
|
.favourites() |
|
|
@ -40,7 +19,9 @@ fn main() { |
|
|
|
.items_iter() |
|
|
|
.items_iter() |
|
|
|
.take_while(|record| record.id != top) |
|
|
|
.take_while(|record| record.id != top) |
|
|
|
.map(|record| { |
|
|
|
.map(|record| { |
|
|
|
dump_record(&record); |
|
|
|
let storage = dbg!(storage::filesystem::Filesystem::from(&record)); |
|
|
|
|
|
|
|
storage.open(); |
|
|
|
|
|
|
|
storage.save(); |
|
|
|
record |
|
|
|
record |
|
|
|
}) |
|
|
|
}) |
|
|
|
.fold(None, { |
|
|
|
.fold(None, { |
|
|
@ -53,34 +34,16 @@ fn main() { |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
save_config(&config, most_recent_favourite) |
|
|
|
config.save(most_recent_favourite); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn save_config(config: &Config, most_recent_favourite: Option<String>) -> () { |
|
|
|
|
|
|
|
if let Some(id) = most_recent_favourite { |
|
|
|
|
|
|
|
let new_configuration = Config { |
|
|
|
|
|
|
|
last_favorite: id, |
|
|
|
|
|
|
|
joplin: match &config.joplin { |
|
|
|
|
|
|
|
None => None, |
|
|
|
|
|
|
|
Some(x) => Some(JoplinConfig { |
|
|
|
|
|
|
|
folder: x.folder.to_string(), |
|
|
|
|
|
|
|
port: x.port, |
|
|
|
|
|
|
|
}), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
let content = toml::to_string(&new_configuration).unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let Ok(mut fp) = File::create("downfav.toml") { |
|
|
|
|
|
|
|
fp.write_all(content.as_bytes()).unwrap(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Get a connection with Mastodon; if there is no set up with any account yet,
|
|
|
|
|
|
|
|
/// requests one.
|
|
|
|
fn get_mastodon_connection() -> Mastodon { |
|
|
|
fn get_mastodon_connection() -> Mastodon { |
|
|
|
if let Ok(data) = elefren_toml::from_file("mastodon.toml") { |
|
|
|
if let Ok(data) = elefren_toml::from_file("mastodon.toml") { |
|
|
|
Mastodon::from(data) |
|
|
|
Mastodon::from(data) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
print!("Your server URL: "); |
|
|
|
println!("Your server URL: "); |
|
|
|
let mut server = String::new(); |
|
|
|
let mut server = String::new(); |
|
|
|
io::stdin() |
|
|
|
io::stdin() |
|
|
|
.read_line(&mut server) |
|
|
|
.read_line(&mut server) |
|
|
@ -95,82 +58,3 @@ fn get_mastodon_connection() -> Mastodon { |
|
|
|
mastodon |
|
|
|
mastodon |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn get_config() -> Config { |
|
|
|
|
|
|
|
if let Ok(mut fp) = File::open("downfav.toml") { |
|
|
|
|
|
|
|
let mut contents = String::new(); |
|
|
|
|
|
|
|
fp.read_to_string(&mut contents).unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let config: Config = toml::from_str(&contents).unwrap_or(Config { |
|
|
|
|
|
|
|
last_favorite: "".to_string(), |
|
|
|
|
|
|
|
joplin: None, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
config |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
Config { |
|
|
|
|
|
|
|
last_favorite: "".to_string(), |
|
|
|
|
|
|
|
joplin: None, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn dump_record(record: &Status) { |
|
|
|
|
|
|
|
println!("Downloading {}/{}", &record.account.acct, &record.id); |
|
|
|
|
|
|
|
create_structure(dbg!(&record)); |
|
|
|
|
|
|
|
save_content(&record); |
|
|
|
|
|
|
|
save_attachments(&record); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn toot_dir(record: &Status) -> PathBuf { |
|
|
|
|
|
|
|
Path::new("data") |
|
|
|
|
|
|
|
.join(&record.account.acct) |
|
|
|
|
|
|
|
.join(&record.id) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn create_structure(record: &Status) { |
|
|
|
|
|
|
|
println!("Current ID: {}", record.id); |
|
|
|
|
|
|
|
std::fs::create_dir_all(toot_dir(record)).expect("Failed to create the storage path"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn save_content(record: &Status) { |
|
|
|
|
|
|
|
if let Ok(mut fp) = File::create(toot_dir(&record).join("toot.md")) { |
|
|
|
|
|
|
|
fp.write_all(html2md::parse_html(&record.content).as_bytes()) |
|
|
|
|
|
|
|
.expect("Failed to save content"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn save_attachments(record: &Status) { |
|
|
|
|
|
|
|
let base_path = toot_dir(&record); |
|
|
|
|
|
|
|
record |
|
|
|
|
|
|
|
.media_attachments |
|
|
|
|
|
|
|
.iter() |
|
|
|
|
|
|
|
.for_each(move |x| save_attachment(dbg!(&x), &base_path)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn save_attachment(attachment: &Attachment, base_path: &PathBuf) { |
|
|
|
|
|
|
|
let filename = get_attachment_filename(dbg!(&attachment.url)); |
|
|
|
|
|
|
|
println!("\tAttachment: {:?}", &filename); |
|
|
|
|
|
|
|
let saving_target = dbg!(base_path.join(filename)); |
|
|
|
|
|
|
|
if let Ok(mut fp) = File::create(saving_target) { |
|
|
|
|
|
|
|
let client = reqwest::Client::builder() |
|
|
|
|
|
|
|
.timeout(Duration::from_secs(600)) |
|
|
|
|
|
|
|
.build() |
|
|
|
|
|
|
|
.unwrap(); |
|
|
|
|
|
|
|
client |
|
|
|
|
|
|
|
.get(&attachment.url) |
|
|
|
|
|
|
|
.send() |
|
|
|
|
|
|
|
.expect("Failed to connect to server") |
|
|
|
|
|
|
|
.copy_to(&mut fp) |
|
|
|
|
|
|
|
.expect("Failed to save attachment"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn get_attachment_filename(url: &str) -> String { |
|
|
|
|
|
|
|
let mut frags = url.rsplitn(2, '/'); |
|
|
|
|
|
|
|
if let Some(path_part) = frags.next() { |
|
|
|
|
|
|
|
dbg!(path_part.split('?').next().unwrap_or(url).to_string()) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// this is, most of the time, bad (due special characters -- like '?' -- and path)
|
|
|
|
|
|
|
|
dbg!(url.to_string()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|