mirror of
https://framagit.org/veretcle/oolatoocs.git
synced 2025-07-21 13:24:18 +02:00
✨: add bluesky support
This commit is contained in:
147
src/lib.rs
147
src/lib.rs
@@ -1,3 +1,5 @@
|
||||
use log::debug;
|
||||
|
||||
mod error;
|
||||
pub use error::OolatoocsError;
|
||||
|
||||
@@ -5,8 +7,7 @@ mod config;
|
||||
pub use config::{parse_toml, Config};
|
||||
|
||||
mod state;
|
||||
#[allow(unused_imports)]
|
||||
use state::{delete_state, read_all_tweet_state, read_state, write_state, TweetToToot};
|
||||
use state::{delete_state, read_all_state, read_state, write_state, TootTweetRecord};
|
||||
pub use state::{init_db, migrate_db};
|
||||
|
||||
mod mastodon;
|
||||
@@ -17,9 +18,11 @@ mod utils;
|
||||
use utils::{generate_multi_tweets, strip_everything};
|
||||
|
||||
mod twitter;
|
||||
#[allow(unused_imports)]
|
||||
use twitter::{delete_tweet, generate_media_ids, post_tweet, transform_poll};
|
||||
|
||||
mod bsky;
|
||||
use bsky::{build_post_record, generate_media_records, get_session, BskyReply};
|
||||
|
||||
use rusqlite::Connection;
|
||||
|
||||
#[tokio::main]
|
||||
@@ -29,6 +32,10 @@ pub async fn run(config: &Config) {
|
||||
|
||||
let mastodon = get_mastodon_instance(&config.mastodon);
|
||||
|
||||
let bluesky = get_session(&config.bluesky.handle, &config.bluesky.password)
|
||||
.await
|
||||
.unwrap_or_else(|e| panic!("Cannot connect to Bsky: {}", e));
|
||||
|
||||
let last_entry =
|
||||
read_state(&conn, None).unwrap_or_else(|e| panic!("Cannot get last toot id: {}", e));
|
||||
|
||||
@@ -40,23 +47,29 @@ pub async fn run(config: &Config) {
|
||||
Some(d) => {
|
||||
// a date has been found
|
||||
if d > t.datetime.unwrap() {
|
||||
// said date is posterior to the previously
|
||||
// written tweet, we need to delete/rewrite
|
||||
for local_tweet_id in read_all_tweet_state(&conn, t.toot_id)
|
||||
debug!("Last toot date is posterior to the previously written tweet, deleting…");
|
||||
let (local_tweet_ids, local_record_uris) = read_all_state(&conn, t.toot_id)
|
||||
.unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"Cannot fetch all tweets associated with Toot ID {}: {}",
|
||||
t.toot_id, e
|
||||
)
|
||||
})
|
||||
.into_iter()
|
||||
{
|
||||
});
|
||||
for local_tweet_id in local_tweet_ids.into_iter() {
|
||||
delete_tweet(&config.twitter, local_tweet_id)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
panic!("Cannot delete Tweet ID ({}): {}", t.tweet_id, e)
|
||||
});
|
||||
}
|
||||
for local_record_uri in local_record_uris.into_iter() {
|
||||
bluesky
|
||||
.delete_record(&local_record_uri)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
panic!("Cannot delete record ID ({}): {}", &t.record_uri, e)
|
||||
});
|
||||
}
|
||||
delete_state(&conn, t.toot_id).unwrap_or_else(|e| {
|
||||
panic!("Cannot delete Toot ID ({}): {}", t.toot_id, e)
|
||||
});
|
||||
@@ -87,52 +100,132 @@ pub async fn run(config: &Config) {
|
||||
};
|
||||
|
||||
// threads if necessary
|
||||
let mut reply_to = toot.in_reply_to_id.and_then(|t| {
|
||||
read_state(&conn, Some(t.parse::<u64>().unwrap()))
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|s| s.tweet_id)
|
||||
});
|
||||
let (mut tweet_reply_to, mut record_reply_to) = toot
|
||||
.in_reply_to_id
|
||||
.and_then(|t| {
|
||||
read_state(&conn, Some(t.parse::<u64>().unwrap()))
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|s| {
|
||||
(
|
||||
s.tweet_id,
|
||||
BskyReply {
|
||||
record_uri: s.record_uri.to_owned(),
|
||||
root_record_uri: s.root_record_uri.to_owned(),
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
.unzip();
|
||||
|
||||
// if the toot is too long, we cut it in half here
|
||||
if let Some((first_half, second_half)) = generate_multi_tweets(&tweet_content) {
|
||||
tweet_content = second_half;
|
||||
// post the first half
|
||||
let reply_id = post_tweet(&config.twitter, first_half, vec![], reply_to, None)
|
||||
.await
|
||||
.unwrap_or_else(|e| panic!("Cannot post the first half of {}: {}", &toot.id, e));
|
||||
let tweet_reply_id =
|
||||
post_tweet(&config.twitter, &first_half, vec![], tweet_reply_to, None)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"Cannot post the first half of {} for Twitter: {}",
|
||||
&toot.id, e
|
||||
)
|
||||
});
|
||||
|
||||
let record = build_post_record(
|
||||
&config.bluesky,
|
||||
&first_half,
|
||||
&toot.language,
|
||||
None,
|
||||
&record_reply_to,
|
||||
)
|
||||
.await
|
||||
.unwrap_or_else(|e| panic!("Cannot create valid record for {}: {}", &toot.id, e));
|
||||
let record_reply_id = bluesky.create_record(record).await.unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"Cannot post the first half of {} for Bluesky: {}",
|
||||
&toot.id, e
|
||||
)
|
||||
});
|
||||
// write it to db
|
||||
write_state(
|
||||
&conn,
|
||||
TweetToToot {
|
||||
tweet_id: reply_id,
|
||||
TootTweetRecord {
|
||||
toot_id: toot.id.parse::<u64>().unwrap(),
|
||||
tweet_id: tweet_reply_id,
|
||||
record_uri: record_reply_id.data.uri.to_owned(),
|
||||
root_record_uri: record_reply_to
|
||||
.as_ref()
|
||||
.map_or(record_reply_id.data.uri.to_owned(), |v| {
|
||||
v.root_record_uri.to_owned()
|
||||
}),
|
||||
datetime: None,
|
||||
},
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
panic!("Cannot store Toot/Tweet ({}/{}): {}", &toot.id, reply_id, e)
|
||||
panic!(
|
||||
"Cannot store Toot/Tweet/Record ({}/{}/{}): {}",
|
||||
&toot.id, tweet_reply_id, &record_reply_id.data.uri, e
|
||||
)
|
||||
});
|
||||
reply_to = Some(reply_id);
|
||||
|
||||
record_reply_to = Some(BskyReply {
|
||||
record_uri: record_reply_id.data.uri.to_owned(),
|
||||
root_record_uri: record_reply_to
|
||||
.as_ref()
|
||||
.map_or(record_reply_id.data.uri.clone(), |v| {
|
||||
v.root_record_uri.clone()
|
||||
}),
|
||||
});
|
||||
|
||||
tweet_reply_to = Some(tweet_reply_id);
|
||||
};
|
||||
|
||||
// treats poll if any
|
||||
let in_poll = toot.poll.map(|p| transform_poll(&p));
|
||||
|
||||
// treats medias
|
||||
let medias = generate_media_ids(&config.twitter, &toot.media_attachments).await;
|
||||
let record_medias = generate_media_records(&bluesky, &toot.media_attachments).await;
|
||||
let tweet_medias = generate_media_ids(&config.twitter, &toot.media_attachments).await;
|
||||
|
||||
// posts corresponding tweet
|
||||
let tweet_id = post_tweet(&config.twitter, tweet_content, medias, reply_to, in_poll)
|
||||
let tweet_id = post_tweet(
|
||||
&config.twitter,
|
||||
&tweet_content,
|
||||
tweet_medias,
|
||||
tweet_reply_to,
|
||||
in_poll,
|
||||
)
|
||||
.await
|
||||
.unwrap_or_else(|e| panic!("Cannot Tweet {}: {}", toot.id, e));
|
||||
|
||||
let record = build_post_record(
|
||||
&config.bluesky,
|
||||
&tweet_content,
|
||||
&toot.language,
|
||||
record_medias,
|
||||
&record_reply_to,
|
||||
)
|
||||
.await
|
||||
.unwrap_or_else(|e| panic!("Cannot build record for {}: {}", &toot.id, e));
|
||||
|
||||
let created_record = bluesky
|
||||
.create_record(record)
|
||||
.await
|
||||
.unwrap_or_else(|e| panic!("Cannot Tweet {}: {}", toot.id, e));
|
||||
.unwrap_or_else(|e| panic!("Cannot put record {}: {}", &toot.id, e));
|
||||
|
||||
// writes the current state of the tweet
|
||||
write_state(
|
||||
&conn,
|
||||
TweetToToot {
|
||||
tweet_id,
|
||||
TootTweetRecord {
|
||||
toot_id: toot.id.parse::<u64>().unwrap(),
|
||||
tweet_id,
|
||||
record_uri: created_record.data.uri.clone(),
|
||||
root_record_uri: record_reply_to
|
||||
.as_ref()
|
||||
.map_or(created_record.data.uri.clone(), |v| {
|
||||
v.root_record_uri.clone()
|
||||
}),
|
||||
datetime: None,
|
||||
},
|
||||
)
|
||||
|
Reference in New Issue
Block a user