Main: Add support for fetching all media from a element chat export
This commit is contained in:
parent
528e75cf95
commit
ef7fc3c6a9
1 changed files with 53 additions and 9 deletions
62
src/main.rs
62
src/main.rs
|
@ -1,4 +1,6 @@
|
||||||
use std::{collections::HashSet, fs};
|
use std::path::PathBuf;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fs;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
|
@ -9,7 +11,8 @@ use log::{info, debug, error};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use rustyline_async::{Readline, ReadlineEvent};
|
use rustyline_async::{Readline, ReadlineEvent};
|
||||||
|
|
||||||
use matrix_sdk::{matrix_auth::{MatrixSession, MatrixSessionTokens}, Client, SessionMeta};
|
use matrix_sdk::{Client, SessionMeta};
|
||||||
|
use matrix_sdk::matrix_auth::{MatrixSession, MatrixSessionTokens};
|
||||||
use matrix_sdk::ruma::events::room::{MediaSource, message::{MessageType, RoomMessageEventContent}};
|
use matrix_sdk::ruma::events::room::{MediaSource, message::{MessageType, RoomMessageEventContent}};
|
||||||
use matrix_sdk::ruma::api::client::error::{ErrorBody, ErrorKind};
|
use matrix_sdk::ruma::api::client::error::{ErrorBody, ErrorKind};
|
||||||
use matrix_sdk::ruma::api::client::{authenticated_media, media};
|
use matrix_sdk::ruma::api::client::{authenticated_media, media};
|
||||||
|
@ -139,7 +142,7 @@ async fn supports_authenticated_media(client: &Client) -> Result<bool> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_media(source: MediaSource, body: Option<String>, server: Option<String>) -> Result<()> {
|
async fn process_media(source: MediaSource, body: Option<String>, server: &Option<String>) -> Result<()> {
|
||||||
let uri = match source.clone() {
|
let uri = match source.clone() {
|
||||||
MediaSource::Plain(uri) => uri,
|
MediaSource::Plain(uri) => uri,
|
||||||
MediaSource::Encrypted(encrypted) => encrypted.url,
|
MediaSource::Encrypted(encrypted) => encrypted.url,
|
||||||
|
@ -239,6 +242,10 @@ struct Arguments {
|
||||||
#[clap(long, env)]
|
#[clap(long, env)]
|
||||||
server: Option<String>,
|
server: Option<String>,
|
||||||
|
|
||||||
|
/// The path to a JSON export from Element's export feature
|
||||||
|
#[clap(long, env)]
|
||||||
|
element_export_path: Option<PathBuf>,
|
||||||
|
|
||||||
mxc_url: Option<String>,
|
mxc_url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,10 +256,47 @@ async fn main() -> Result<()> {
|
||||||
let Arguments {
|
let Arguments {
|
||||||
server,
|
server,
|
||||||
mxc_url,
|
mxc_url,
|
||||||
|
element_export_path
|
||||||
} = Arguments::parse();
|
} = Arguments::parse();
|
||||||
|
|
||||||
if mxc_url.is_some() {
|
if let Some(element_export_path) = element_export_path {
|
||||||
if let Err(error) = process_media(MediaSource::Plain(OwnedMxcUri::from(mxc_url.unwrap())), None, server).await {
|
let file_contents = fs::read_to_string(element_export_path).expect("to be able to read the element export json");
|
||||||
|
let file_json: serde_json::Value = serde_json::from_str(&file_contents).expect("to be able to parse the json");
|
||||||
|
|
||||||
|
let events = file_json
|
||||||
|
.as_object().expect("the top level json to be an object")
|
||||||
|
.get("messages").expect("the top level json object to have a property 'messages'")
|
||||||
|
.as_array().expect("the messages property to be an array");
|
||||||
|
|
||||||
|
for event in events {
|
||||||
|
let event_object = event.as_object().expect("event to be an object");
|
||||||
|
let event_type = event_object.get("type").expect("event to have a type")
|
||||||
|
.as_str().expect("event type to be a string");
|
||||||
|
|
||||||
|
if event_type != "m.room.message" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let message_event: DecryptedEventSource = serde_json::from_value(event.clone()).expect("event to be parsable");
|
||||||
|
|
||||||
|
debug!("Parsed event with {} content", message_event.content.msgtype.msgtype());
|
||||||
|
|
||||||
|
if let Err(error) = match message_event.content.msgtype {
|
||||||
|
MessageType::Audio(content) => process_media(content.source, Some(content.body), &server).await,
|
||||||
|
MessageType::File(content) => process_media(content.source, Some(content.body), &server).await,
|
||||||
|
MessageType::Image(content) => process_media(content.source, Some(content.body), &server).await,
|
||||||
|
MessageType::Video(content) => process_media(content.source, Some(content.body), &server).await,
|
||||||
|
_ => continue
|
||||||
|
} {
|
||||||
|
error!("Unable to process media: {}", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mxc_url) = mxc_url {
|
||||||
|
if let Err(error) = process_media(MediaSource::Plain(OwnedMxcUri::from(mxc_url)), None, &server).await {
|
||||||
error!("Unable to process media: {}", error);
|
error!("Unable to process media: {}", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,10 +349,10 @@ async fn main() -> Result<()> {
|
||||||
debug!("Parsed event with {} content", event.content.msgtype.msgtype());
|
debug!("Parsed event with {} content", event.content.msgtype.msgtype());
|
||||||
|
|
||||||
if let Err(error) = match event.content.msgtype {
|
if let Err(error) = match event.content.msgtype {
|
||||||
MessageType::Audio(content) => process_media(content.source, Some(content.body), server).await,
|
MessageType::Audio(content) => process_media(content.source, Some(content.body), &server).await,
|
||||||
MessageType::File(content) => process_media(content.source, Some(content.body), server).await,
|
MessageType::File(content) => process_media(content.source, Some(content.body), &server).await,
|
||||||
MessageType::Image(content) => process_media(content.source, Some(content.body), server).await,
|
MessageType::Image(content) => process_media(content.source, Some(content.body), &server).await,
|
||||||
MessageType::Video(content) => process_media(content.source, Some(content.body), server).await,
|
MessageType::Video(content) => process_media(content.source, Some(content.body), &server).await,
|
||||||
_ => {
|
_ => {
|
||||||
error!("Event content is not known to contain media, exiting");
|
error!("Event content is not known to contain media, exiting");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
Loading…
Reference in a new issue