mirror of
https://framagit.org/veretcle/scootaloo.git
synced 2025-07-20 17:11:19 +02:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5fe57f189a | ||
![]() |
83c398cebf | ||
![]() |
8f567ed6b4 | ||
![]() |
d7431862ba | ||
![]() |
f3b13eb62f | ||
![]() |
6b68c8e299 | ||
![]() |
0bb5eabdac | ||
![]() |
3d44bbfb86 | ||
![]() |
9a03c7681b | ||
![]() |
a8a8f8c13f | ||
![]() |
90a9df220a |
40
Cargo.lock
generated
40
Cargo.lock
generated
@@ -776,15 +776,6 @@ dependencies = [
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isolang"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b64fd6448ee8a45ce6e4365c58e4fa7d8740cba2ed70db3e9ab4879ebd93eaaa"
|
||||
dependencies = [
|
||||
"phf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.5"
|
||||
@@ -858,9 +849,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "megalodon"
|
||||
version = "0.3.3"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7bc4427c44dc9c4b439da7bcd15a87b51e21340a12ef5a4f7eac90fc247886"
|
||||
checksum = "3b39bd378603a46216457c1c95c54f8dec37959a02c06a59cc33d00fc71a0ba0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -1082,24 +1073,6 @@ version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
@@ -1343,14 +1316,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "scootaloo"
|
||||
version = "1.1.3"
|
||||
version = "1.1.6"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"clap",
|
||||
"egg-mode",
|
||||
"futures",
|
||||
"html-escape",
|
||||
"isolang",
|
||||
"log",
|
||||
"megalodon",
|
||||
"mime",
|
||||
@@ -1523,12 +1495,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.7"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "scootaloo"
|
||||
version = "1.1.3"
|
||||
version = "1.1.6"
|
||||
authors = ["VC <veretcle+framagit@mateu.be>"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -14,10 +14,9 @@ toml = "^0.5"
|
||||
clap = "^4"
|
||||
egg-mode = "^0.16"
|
||||
rusqlite = "^0.27"
|
||||
isolang = "^2"
|
||||
tokio = { version = "^1", features = ["rt"]}
|
||||
futures = "^0.3"
|
||||
megalodon = "^0.3.3"
|
||||
megalodon = "^0.3.6"
|
||||
html-escape = "^0.2"
|
||||
reqwest = "^0.11"
|
||||
log = "^0.4"
|
||||
|
@@ -43,10 +43,10 @@ pub struct ScootalooConfig {
|
||||
/// Parses the TOML file into a Config Struct
|
||||
pub fn parse_toml(toml_file: &str) -> Config {
|
||||
let toml_config = read_to_string(toml_file)
|
||||
.unwrap_or_else(|e| panic!("Cannot open config file {}: {}", toml_file, e));
|
||||
.unwrap_or_else(|e| panic!("Cannot open config file {toml_file}: {e}"));
|
||||
|
||||
let config: Config = toml::from_str(&toml_config)
|
||||
.unwrap_or_else(|e| panic!("Cannot parse TOML file {}: {}", toml_file, e));
|
||||
.unwrap_or_else(|e| panic!("Cannot parse TOML file {toml_file}: {e}"));
|
||||
|
||||
config
|
||||
}
|
||||
|
@@ -30,12 +30,12 @@ impl Display for ScootalooError {
|
||||
|
||||
impl From<Box<dyn Error>> for ScootalooError {
|
||||
fn from(error: Box<dyn Error>) -> Self {
|
||||
ScootalooError::new(&format!("Error in a subset crate: {}", error))
|
||||
ScootalooError::new(&format!("Error in a subset crate: {error}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<megalodonError> for ScootalooError {
|
||||
fn from(error: megalodonError) -> Self {
|
||||
ScootalooError::new(&format!("Error in megalodon crate: {}", error))
|
||||
ScootalooError::new(&format!("Error in megalodon crate: {error}"))
|
||||
}
|
||||
}
|
||||
|
13
src/lib.rs
13
src/lib.rs
@@ -21,7 +21,6 @@ use state::{read_state, write_state, TweetToToot};
|
||||
|
||||
use futures::StreamExt;
|
||||
use html_escape::decode_html_entities;
|
||||
use isolang::Language;
|
||||
use log::info;
|
||||
use megalodon::{
|
||||
megalodon::PostStatusInputOptions, megalodon::UpdateCredentialsInputOptions, Megalodon,
|
||||
@@ -204,9 +203,7 @@ pub async fn run(config: Config) {
|
||||
|
||||
// language if any
|
||||
if let Some(l) = &tweet.lang {
|
||||
if let Some(r) = Language::from_639_1(l) {
|
||||
post_status.language = Some(r.to_string());
|
||||
}
|
||||
post_status.language = Some(l.to_string());
|
||||
}
|
||||
|
||||
// can be activated for test purposes
|
||||
@@ -238,8 +235,8 @@ pub async fn run(config: Config) {
|
||||
// launch and wait for every handle
|
||||
while let Some(result) = stream.next().await {
|
||||
match result {
|
||||
Ok(Err(e)) => eprintln!("Error within thread: {}", e),
|
||||
Err(e) => eprintln!("Error with thread: {}", e),
|
||||
Ok(Err(e)) => eprintln!("Error within thread: {e}"),
|
||||
Err(e) => eprintln!("Error with thread: {e}"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -307,8 +304,8 @@ pub async fn profile(config: Config, bot: Option<bool>) {
|
||||
|
||||
while let Some(result) = stream.next().await {
|
||||
match result {
|
||||
Ok(Err(e)) => eprintln!("Error within thread: {}", e),
|
||||
Err(e) => eprintln!("Error with thread: {}", e),
|
||||
Ok(Err(e)) => eprintln!("Error within thread: {e}"),
|
||||
Err(e) => eprintln!("Error with thread: {e}"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@@ -63,10 +63,7 @@ fn main() {
|
||||
.short('c')
|
||||
.long("config")
|
||||
.value_name("CONFIG_FILE")
|
||||
.help(format!(
|
||||
"TOML config file for scootaloo (default {})",
|
||||
DEFAULT_CONFIG_PATH
|
||||
))
|
||||
.help("TOML config file for scootaloo")
|
||||
.default_value(DEFAULT_CONFIG_PATH)
|
||||
.num_args(1)
|
||||
.display_order(1),
|
||||
@@ -81,7 +78,7 @@ fn main() {
|
||||
.short('c')
|
||||
.long("config")
|
||||
.value_name("CONFIG_FILE")
|
||||
.help(format!("TOML config file for scootaloo (default {})", DEFAULT_CONFIG_PATH))
|
||||
.help("TOML config file for scootaloo")
|
||||
.default_value(DEFAULT_CONFIG_PATH)
|
||||
.num_args(1)
|
||||
.display_order(1),
|
||||
@@ -104,7 +101,7 @@ fn main() {
|
||||
.short('c')
|
||||
.long("config")
|
||||
.value_name("CONFIG_FILE")
|
||||
.help(format!("TOML config file for scootaloo (default {})", DEFAULT_CONFIG_PATH))
|
||||
.help("TOML config file for scootaloo")
|
||||
.default_value(DEFAULT_CONFIG_PATH)
|
||||
.num_args(1)
|
||||
.display_order(1),
|
||||
|
@@ -83,7 +83,7 @@ pub fn associate_urls(urls: &[UrlEntity], re: &Option<Regex>) -> HashMap<String,
|
||||
pub fn replace_alt_services(urls: &mut HashMap<String, String>, alts: &HashMap<String, String>) {
|
||||
for val in urls.values_mut() {
|
||||
for (k, v) in alts {
|
||||
*val = val.replace(&format!("/{}/", k), &format!("/{}/", v));
|
||||
*val = val.replace(&format!("/{k}/"), &format!("/{v}/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ pub fn replace_tweet_by_toot(
|
||||
twitter_screen_name.to_lowercase(),
|
||||
tweet_id
|
||||
)) {
|
||||
*val = format!("{}/@{}/{}", base_url, mastodon_screen_name, toot_id);
|
||||
*val = format!("{base_url}/@{mastodon_screen_name}/{toot_id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ pub async fn register(host: &str, screen_name: &str) {
|
||||
|
||||
let url = app_data.url.expect("Cannot generate registration URI!");
|
||||
|
||||
println!("Click this link to authorize on Mastodon: {}", url);
|
||||
println!("Click this link to authorize on Mastodon: {url}");
|
||||
println!("Paste the returned authorization code: ");
|
||||
|
||||
let mut input = String::new();
|
||||
|
@@ -21,8 +21,8 @@ pub fn read_state(
|
||||
) -> Result<Option<TweetToToot>, Box<dyn Error>> {
|
||||
debug!("Reading tweet_id {:?}", s);
|
||||
let query: String = match s {
|
||||
Some(i) => format!("SELECT * FROM tweet_to_toot WHERE tweet_id = {} and twitter_screen_name = \"{}\"", i, n),
|
||||
None => format!("SELECT * FROM tweet_to_toot WHERE twitter_screen_name = \"{}\" ORDER BY tweet_id DESC LIMIT 1", n),
|
||||
Some(i) => format!("SELECT * FROM tweet_to_toot WHERE tweet_id = {i} and twitter_screen_name = \"{n}\""),
|
||||
None => format!("SELECT * FROM tweet_to_toot WHERE twitter_screen_name = \"{n}\" ORDER BY tweet_id DESC LIMIT 1"),
|
||||
};
|
||||
|
||||
let mut stmt = conn.prepare(&query)?;
|
||||
@@ -78,8 +78,7 @@ pub fn migrate_db(d: &str, s: &str) -> Result<(), Box<dyn Error>> {
|
||||
&format!(
|
||||
"ALTER TABLE tweet_to_toot
|
||||
ADD COLUMN twitter_screen_name TEXT NOT NULL
|
||||
DEFAULT \"{}\"",
|
||||
s
|
||||
DEFAULT \"{s}\""
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
34
src/util.rs
34
src/util.rs
@@ -6,6 +6,7 @@ use futures::{stream, stream::StreamExt};
|
||||
use log::{error, info, warn};
|
||||
use megalodon::{
|
||||
entities::UploadMedia::{AsyncAttachment, Attachment},
|
||||
error,
|
||||
mastodon::Mastodon,
|
||||
megalodon::Megalodon,
|
||||
};
|
||||
@@ -14,6 +15,7 @@ use std::error::Error;
|
||||
use tokio::{
|
||||
fs::{create_dir_all, remove_file, File},
|
||||
io::copy,
|
||||
time::{sleep, Duration},
|
||||
};
|
||||
|
||||
/// Generate associative table between media ids and tweet extended entities
|
||||
@@ -55,7 +57,7 @@ pub async fn generate_media_ids(
|
||||
|
||||
let id = match mastodon_media {
|
||||
Attachment(m) => m.id,
|
||||
AsyncAttachment(m) => m.id,
|
||||
AsyncAttachment(m) => wait_until_uploaded(&mastodon, &m.id).await?,
|
||||
};
|
||||
|
||||
Ok::<String, ScootalooError>(id)
|
||||
@@ -81,6 +83,24 @@ pub async fn generate_media_ids(
|
||||
(media_url, media_ids)
|
||||
}
|
||||
|
||||
/// Wait on uploaded medias when necessary
|
||||
async fn wait_until_uploaded(client: &Mastodon, id: &str) -> Result<String, error::Error> {
|
||||
loop {
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
let res = client.get_media(id.to_string()).await;
|
||||
return match res {
|
||||
Ok(res) => Ok(res.json.id),
|
||||
Err(err) => match err {
|
||||
error::Error::OwnError(ref own_err) => match own_err.kind {
|
||||
error::Kind::HTTPPartialContentError => continue,
|
||||
_ => Err(err),
|
||||
},
|
||||
_ => Err(err),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Transforms the media into a base64 equivalent
|
||||
pub async fn base64_media(u: &str) -> Result<String, Box<dyn Error>> {
|
||||
let mut response = reqwest::get(u).await?;
|
||||
@@ -94,12 +114,12 @@ pub async fn base64_media(u: &str) -> Result<String, Box<dyn Error>> {
|
||||
let content_type = response
|
||||
.headers()
|
||||
.get("content-type")
|
||||
.ok_or_else(|| ScootalooError::new(&format!("Cannot get media content type for {}", u)))?
|
||||
.ok_or_else(|| ScootalooError::new(&format!("Cannot get media content type for {u}")))?
|
||||
.to_str()?;
|
||||
|
||||
let encoded_f = encode(buffer);
|
||||
|
||||
Ok(format!("data:{};base64,{}", content_type, encoded_f))
|
||||
Ok(format!("data:{content_type};base64,{encoded_f}"))
|
||||
}
|
||||
|
||||
/// Gets and caches Twitter Media inside the determined temp dir
|
||||
@@ -116,19 +136,17 @@ pub async fn cache_media(u: &str, t: &str) -> Result<String, Box<dyn Error>> {
|
||||
.path_segments()
|
||||
.ok_or_else(|| {
|
||||
ScootalooError::new(&format!(
|
||||
"Cannot determine the destination filename for {}",
|
||||
u
|
||||
"Cannot determine the destination filename for {u}"
|
||||
))
|
||||
})?
|
||||
.last()
|
||||
.ok_or_else(|| {
|
||||
ScootalooError::new(&format!(
|
||||
"Cannot determine the destination filename for {}",
|
||||
u
|
||||
"Cannot determine the destination filename for {u}"
|
||||
))
|
||||
})?;
|
||||
|
||||
let dest_filepath = format!("{}/{}", t, dest_filename);
|
||||
let dest_filepath = format!("{t}/{dest_filename}");
|
||||
|
||||
let mut dest_file = File::create(&dest_filepath).await?;
|
||||
|
||||
|
Reference in New Issue
Block a user