Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow prefixing the syncing toots and tweets #50

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ delete_older_favs = true
sync_reblogs = true
# Restrict sync to a hashtag (leave empty to sync all posts)
sync_hashtag = "#sync"
# Add the prefix of toots to send (leave empty to add nothing)
sync_prefix = "[twitter] "

[mastodon.app]
base = "https://mastodon.social"
Expand All @@ -108,6 +110,8 @@ delete_older_favs = true
sync_retweets = true
# Restrict sync to a hashtag (leave empty to sync all posts)
sync_hashtag = "#sync"
# Add the prefix of tweets to send (leave empty to add nothing)
sync_prefix = "[mastodon] "
```

## Preview what's going to be synced
Expand Down
38 changes: 38 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub struct MastodonConfig {
#[serde_as(as = "NoneAsEmptyString")]
#[serde(default = "config_none_default")]
pub sync_hashtag: Option<String>,
#[serde(default)] // empty string
pub sync_prefix: String,
pub app: Data,
}

Expand All @@ -51,6 +53,8 @@ pub struct TwitterConfig {
#[serde_as(as = "NoneAsEmptyString")]
#[serde(default = "config_none_default")]
pub sync_hashtag: Option<String>,
#[serde(default)] // empty string
pub sync_prefix: String,
}

fn config_false_default() -> bool {
Expand Down Expand Up @@ -123,6 +127,40 @@ delete_older_statuses = true
delete_older_favs = true
sync_reblogs = false
sync_hashtag = "#test"
sync_prefix = "[T] "
[mastodon.app]
base = "https://mastodon.social"
client_id = "abcd"
client_secret = "abcd"
redirect = "urn:ietf:wg:oauth:2.0:oob"
token = "1234"
[twitter]
consumer_key = "abcd"
consumer_secret = "abcd"
access_token = "1234"
access_token_secret = "1234"
user_id = 0
user_name = " "
delete_older_statuses = true
delete_older_favs = true
sync_retweets = false
sync_hashtag = "#test"
sync_prefix = "[M] "
"##;
let config: Config = toml::from_str(toml_config).unwrap();
toml::to_string(&config).unwrap();
}

// Ensure that serializing/deserializing of the TOML config does not throw
// errors.
#[test]
fn serialize_config_v1_8_0() {
let toml_config = r##"
[mastodon]
delete_older_statuses = true
delete_older_favs = true
sync_reblogs = false
sync_hashtag = "#test"
[mastodon.app]
base = "https://mastodon.social"
client_id = "abcd"
Expand Down
12 changes: 10 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub fn run(args: Args) -> Result<()> {
delete_older_favs: false,
sync_reblogs: true,
sync_hashtag: None,
sync_prefix: Default::default(),
},
twitter: twitter_config,
};
Expand Down Expand Up @@ -136,7 +137,9 @@ pub fn run(args: Args) -> Result<()> {

for toot in posts.toots {
if !args.skip_existing_posts {
if let Err(e) = post_to_mastodon(&mastodon, &toot, args.dry_run) {
if let Err(e) =
post_to_mastodon(&mastodon, &toot, args.dry_run, &config.mastodon.sync_prefix)
{
println!("Error posting toot to Mastodon: {:#?}", e);
process::exit(5);
}
Expand All @@ -151,7 +154,12 @@ pub fn run(args: Args) -> Result<()> {

for tweet in posts.tweets {
if !args.skip_existing_posts {
if let Err(e) = rt.block_on(post_to_twitter(&token, &tweet, args.dry_run)) {
if let Err(e) = rt.block_on(post_to_twitter(
&token,
&tweet,
args.dry_run,
&config.twitter.sync_prefix,
)) {
println!("Error posting tweet to Twitter: {:#?}", e);
process::exit(6);
}
Expand Down
71 changes: 55 additions & 16 deletions src/post.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,25 @@ use tempfile::tempdir;
use tokio::time::sleep;

/// Send new status with any given replies to Mastodon.
pub fn post_to_mastodon(mastodon: &Mastodon, toot: &NewStatus, dry_run: bool) -> Result<()> {
///
/// The prefix can be an empty string, a.k.a: Add no prefix.
pub fn post_to_mastodon(
mastodon: &Mastodon,
toot: &NewStatus,
dry_run: bool,
prefix: &str,
) -> Result<()> {
if let Some(reply_to) = toot.in_reply_to_id {
println!(
"Posting thread reply for {} to Mastodon: {}",
"Posting thread reply for {} to Mastodon: {prefix}{}",
reply_to, toot.text
);
} else {
println!("Posting to Mastodon: {}", toot.text);
println!("Posting to Mastodon: {prefix}{}", toot.text);
}
let mut status_id = 0;
if !dry_run {
status_id = send_single_post_to_mastodon(mastodon, toot)?;
status_id = send_single_post_to_mastodon(mastodon, toot, prefix)?;
}

// Recursion does not work well with async functions, so we use iteration
Expand All @@ -49,12 +56,12 @@ pub fn post_to_mastodon(mastodon: &Mastodon, toot: &NewStatus, dry_run: bool) ->
new_reply.in_reply_to_id = Some(parent_id);

println!(
"Posting thread reply for {} to Mastodon: {}",
"Posting thread reply for {} to Mastodon: {prefix}{}",
parent_id, reply.text
);
let mut parent_status_id = 0;
if !dry_run {
parent_status_id = send_single_post_to_mastodon(mastodon, &new_reply)?;
parent_status_id = send_single_post_to_mastodon(mastodon, &new_reply, prefix)?;
}
for remaining_reply in &reply.replies {
replies.push((parent_status_id, remaining_reply));
Expand All @@ -65,7 +72,14 @@ pub fn post_to_mastodon(mastodon: &Mastodon, toot: &NewStatus, dry_run: bool) ->
}

/// Sends the given new status to Mastodon.
fn send_single_post_to_mastodon(mastodon: &Mastodon, toot: &NewStatus) -> Result<u64> {
///
/// The prefix can be an empty string, a.k.a: Add no prefix.
fn send_single_post_to_mastodon(
mastodon: &Mastodon,
toot: &NewStatus,
prefix: &str,
) -> Result<u64> {
let prefix_text = prefix_message(&toot.text, prefix);
let mut media_ids = Vec::new();
// Temporary directory where we will download any file attachments to.
let temp_dir = tempdir()?;
Expand Down Expand Up @@ -104,7 +118,7 @@ fn send_single_post_to_mastodon(mastodon: &Mastodon, toot: &NewStatus) -> Result
}

let mut status_builder = StatusBuilder::new();
status_builder.status(&toot.text);
status_builder.status(&prefix_text);
status_builder.media_ids(media_ids);
if let Some(parent_id) = toot.in_reply_to_id {
status_builder.in_reply_to(parent_id.to_string());
Expand All @@ -122,18 +136,25 @@ fn send_single_post_to_mastodon(mastodon: &Mastodon, toot: &NewStatus) -> Result

/// Send a new status update to Twitter, including thread replies and
/// attachments.
pub async fn post_to_twitter(token: &Token, tweet: &NewStatus, dry_run: bool) -> Result<()> {
///
/// The prefix can be an empty string, a.k.a: Add no prefix.
pub async fn post_to_twitter(
token: &Token,
tweet: &NewStatus,
dry_run: bool,
prefix: &str,
) -> Result<()> {
if let Some(reply_to) = tweet.in_reply_to_id {
println!(
"Posting thread reply for {} to Twitter: {}",
"Posting thread reply for {} to Twitter: {prefix}{}",
reply_to, tweet.text
);
} else {
println!("Posting to Twitter: {}", tweet.text);
println!("Posting to Twitter: {prefix}{}", tweet.text);
}
let mut status_id = 0;
if !dry_run {
status_id = send_single_post_to_twitter(token, tweet).await?;
status_id = send_single_post_to_twitter(token, tweet, prefix).await?;
}

// Recursion does not work well with async functions, so we use iteration
Expand All @@ -150,12 +171,12 @@ pub async fn post_to_twitter(token: &Token, tweet: &NewStatus, dry_run: bool) ->
new_reply.in_reply_to_id = Some(parent_id);

println!(
"Posting thread reply for {} to Twitter: {}",
"Posting thread reply for {} to Twitter: {prefix}{}",
parent_id, reply.text
);
let mut parent_status_id = 0;
if !dry_run {
parent_status_id = send_single_post_to_twitter(token, &new_reply).await?;
parent_status_id = send_single_post_to_twitter(token, &new_reply, prefix).await?;
}
for remaining_reply in &reply.replies {
replies.push((parent_status_id, remaining_reply));
Expand All @@ -166,8 +187,15 @@ pub async fn post_to_twitter(token: &Token, tweet: &NewStatus, dry_run: bool) ->
}

/// Sends the given new status to Twitter.
async fn send_single_post_to_twitter(token: &Token, tweet: &NewStatus) -> Result<u64> {
let mut draft = DraftTweet::new(tweet.text.clone());
///
/// The prefix can be an empty string, a.k.a: Add no prefix.
async fn send_single_post_to_twitter(
token: &Token,
tweet: &NewStatus,
prefix: &str,
) -> Result<u64> {
let prefix_text = prefix_message(&tweet.text, prefix);
let mut draft = DraftTweet::new(prefix_text);
'attachments: for attachment in &tweet.attachments {
let response = reqwest::get(&attachment.attachment_url).await?;
let media_type = response
Expand Down Expand Up @@ -227,3 +255,14 @@ async fn send_single_post_to_twitter(token: &Token, tweet: &NewStatus) -> Result

Ok(created_tweet.id)
}

/// Add prefix to the specified string.
///
/// The prefix can be an empty string, means
/// that we won't add any prefix.
fn prefix_message(message: &str, prefix: &str) -> String {
let mut m = String::with_capacity(message.len() + prefix.len());
m.push_str(prefix);
m.push_str(message);
m
}
1 change: 1 addition & 0 deletions src/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub async fn twitter_register() -> Result<TwitterConfig> {
delete_older_favs: false,
sync_retweets: true,
sync_hashtag: None,
sync_prefix: Default::default(),
}),
_ => unreachable!(),
}
Expand Down