diff options
Diffstat (limited to 'src/bin')
-rw-r--r-- | src/bin/kittybox_bulk_import.rs | 50 | ||||
-rw-r--r-- | src/bin/pyindieblog_to_kittybox.rs | 48 |
2 files changed, 98 insertions, 0 deletions
diff --git a/src/bin/kittybox_bulk_import.rs b/src/bin/kittybox_bulk_import.rs new file mode 100644 index 0000000..652a4c2 --- /dev/null +++ b/src/bin/kittybox_bulk_import.rs @@ -0,0 +1,50 @@ +use std::io::{self, Read}; +use std::fs::File; +use anyhow::{anyhow, Context, Result, bail}; + +#[async_std::main] +async fn main() -> Result<()> { + let args = std::env::args().collect::<Vec<String>>(); + if args.iter().skip(1).any(|s| s == "--help") { + println!("Usage: {} <url> [file]", args[0]); + println!("\nIf launched with no arguments, reads from stdin."); + println!("\nUse KITTYBOX_AUTH_TOKEN environment variable to authorize to the Micropub endpoint."); + std::process::exit(0); + } + + let token = std::env::var("KITTYBOX_AUTH_TOKEN").map_err(|_| anyhow!("No auth token found! Use KITTYBOX_AUTH_TOKEN env variable."))?; + let data: Vec<serde_json::Value> = (if args.len() == 2 || (args.len() == 3 && args[2] == "-") { + serde_json::from_reader(io::stdin()) + } else if args.len() == 3 { + serde_json::from_reader(File::open(&args[2]).with_context(|| "Error opening input file")?) + } else { + bail!("See `{} --help` for usage.", args[0]); + }).with_context(|| "Error while loading the input file")?; + + let url = surf::Url::parse(&args[1])?; + let client = surf::Client::new(); + + let mut iter = data.into_iter(); + + while let Some(post) = iter.next() { + println!("Processing {}...", post["properties"]["url"][0].as_str().or(post["properties"]["published"][0].as_str().or(post["properties"]["name"][0].as_str().or(Some("<unidentified post>")))).unwrap()); + match client.post(&url) + .body(surf::http::Body::from_string( + serde_json::to_string(&post)?)) + .header("Content-Type", "application/json") + .header("Authorization", format!("Bearer {}", &token)) + .send().await { + Ok(mut response) => { + if response.status() == 201 || response.status() == 202 { + println!("Posted at {}", response.header("location").unwrap().last()); + } else { + println!("Error: {:?}", response.body_string().await); + } + } + Err(err) => { + println!("{}", err); + } + } + } + Ok(()) +} diff --git a/src/bin/pyindieblog_to_kittybox.rs b/src/bin/pyindieblog_to_kittybox.rs new file mode 100644 index 0000000..7935da5 --- /dev/null +++ b/src/bin/pyindieblog_to_kittybox.rs @@ -0,0 +1,48 @@ +use std::collections::HashMap; +use std::fs::File; +use anyhow::{Error, Result, Context, anyhow, bail}; +use mobc_redis::redis; +use mobc_redis::redis::AsyncCommands; +use serde::{Serialize, Deserialize}; +use serde_json::json; + +#[derive(Default, Serialize, Deserialize)] +struct PyindieblogData { + posts: Vec<serde_json::Value>, + cards: Vec<serde_json::Value> +} + +#[async_std::main] +async fn main() -> Result<()> { + let mut args = std::env::args(); + args.next(); // skip argv[0] which is the name + let redis_uri = args.next().ok_or(anyhow!("No Redis URI provided"))?; + let client = redis::Client::open(redis_uri.as_str()).with_context(|| format!("Failed to construct Redis client on {}", redis_uri))?; + + let filename = args.next().ok_or(anyhow!("No filename provided for export"))?; + + let mut data: Vec<serde_json::Value>; + + let file = File::create(filename)?; + + let mut conn = client.get_async_std_connection().await.with_context(|| "Failed to connect to the Redis server")?; + + data = conn.hgetall::<&str, HashMap<String, String>>("posts").await? + .values() + .map(|s| serde_json::from_str::<serde_json::Value>(s) + .with_context(|| format!("Failed to parse the following entry: {:?}", s))) + .collect::<std::result::Result<Vec<serde_json::Value>, anyhow::Error>>() + .with_context(|| "Failed to export h-entries from pyindieblog")?; + data.extend(conn.hgetall::<&str, HashMap<String, String>>("hcards").await? + .values() + .map(|s| serde_json::from_str::<serde_json::Value>(s) + .with_context(|| format!("Failed to parse the following card: {:?}", s))) + .collect::<std::result::Result<Vec<serde_json::Value>, anyhow::Error>>() + .with_context(|| "Failed to export h-cards from pyindieblog")?); + + data.sort_by_key(|v| v["properties"]["published"][0].as_str().map(|s| s.to_string())); + + serde_json::to_writer(file, &data)?; + + Ok(()) +} |