feat: threads

This commit is contained in:
VC
2023-11-11 10:25:41 +01:00
parent eba13ba095
commit b9179d8cce
2 changed files with 45 additions and 23 deletions

View File

@@ -44,6 +44,7 @@ pub async fn run(config: &Config) {
// if we wanted to cut toot in half, now would be the right time to do so
// treats media
for media in toot.media_attachments {
let id = match media.r#type {
AttachmentType::Image => {
@@ -77,12 +78,20 @@ pub async fn run(config: &Config) {
medias.push(id);
}
println!("{:?}", medias);
// threads if necessary
let 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 tweet_id = post_tweet(&config.twitter, &tweet_content, &medias)
// posts corresponding tweet
let tweet_id = post_tweet(&config.twitter, &tweet_content, &medias, &reply_to)
.await
.unwrap_or_else(|e| panic!("Cannot Tweet {}: {}", toot.id, e));
// writes the current state of the tweet
write_state(
&conn,
TweetToToot {

View File

@@ -7,7 +7,7 @@ use reqwest::{
Body, Client,
};
use serde::{Deserialize, Serialize};
use std::error::Error;
use std::{error::Error, ops::Not};
use tokio::time::{sleep, Duration};
const TWITTER_API_TWEET_URL: &str = "https://api.twitter.com/2/tweets";
@@ -20,24 +20,32 @@ const TWITTER_METADATA_MEDIA_URL: &str =
struct EmptyRequest {}
#[derive(Serialize, Debug)]
pub struct Tweet {
pub text: String,
pub media: TweetMediasIds,
struct Tweet {
text: String,
#[serde(skip_serializing_if = "Option::is_none")]
media: Option<TweetMediasIds>,
#[serde(skip_serializing_if = "Option::is_none")]
reply: Option<TweetReply>,
}
#[derive(Serialize, Debug)]
pub struct TweetMediasIds {
pub media_ids: Vec<String>,
struct TweetMediasIds {
media_ids: Vec<String>,
}
#[derive(Serialize, Debug)]
struct TweetReply {
in_reply_to_tweet_id: String,
}
#[derive(Deserialize, Debug)]
pub struct TweetResponse {
pub data: TweetResponseData,
struct TweetResponse {
data: TweetResponseData,
}
#[derive(Deserialize, Debug)]
pub struct TweetResponseData {
pub id: String,
struct TweetResponseData {
id: String,
}
#[derive(Deserialize, Debug)]
@@ -112,7 +120,7 @@ pub async fn upload_simple_media(
// upload the media
let client = Client::new();
let res: UploadMediaResponse = client
let res = client
.post(TWITTER_UPLOAD_MEDIA_URL)
.header(
"Authorization",
@@ -129,7 +137,7 @@ pub async fn upload_simple_media(
))
.send()
.await?
.json()
.json::<UploadMediaResponse>()
.await?;
debug!("Media ID: {}", res.media_id);
@@ -201,7 +209,7 @@ pub async fn upload_chunk_media(
debug!("Init the slot for uploading media: {}", u);
// init the slot for uploading
let client = Client::new();
let orig_media_id: UploadMediaResponse = client
let orig_media_id = client
.post(TWITTER_UPLOAD_MEDIA_URL)
.header(
"Authorization",
@@ -221,7 +229,7 @@ pub async fn upload_chunk_media(
)
.send()
.await?
.json()
.json::<UploadMediaResponse>()
.await?;
debug!("Slot initiated with ID: {}", orig_media_id.media_id);
@@ -267,7 +275,7 @@ pub async fn upload_chunk_media(
debug!("Finalize media ID: {}", orig_media_id.media_id);
// Finalizing task
let fin: UploadMediaResponse = client
let fin = client
.post(TWITTER_UPLOAD_MEDIA_URL)
.header(
"Authorization",
@@ -285,7 +293,7 @@ pub async fn upload_chunk_media(
)
.send()
.await?
.json()
.json::<UploadMediaResponse>()
.await?;
if let Some(p_info) = fin.processing_info {
@@ -310,7 +318,7 @@ pub async fn upload_chunk_media(
orig_media_id.media_id, wait_sec
);
let status: UploadMediaResponse = client
let status = client
.get(TWITTER_UPLOAD_MEDIA_URL)
.header(
"Authorization",
@@ -324,7 +332,7 @@ pub async fn upload_chunk_media(
.query(&command)
.send()
.await?
.json()
.json::<UploadMediaResponse>()
.await?;
let p_status = status.processing_info.unwrap(); // shouldnt be None at this point
@@ -347,7 +355,8 @@ pub async fn upload_chunk_media(
"Processing still pending, waiting {} secs more…",
p_status.check_after_secs.unwrap() // unwrap is safe here,
// check_after_secs is only present
// when status is pending
// when status is pending or in
// progress
);
sleep(Duration::from_secs(p_status.check_after_secs.unwrap())).await;
continue;
@@ -365,15 +374,19 @@ pub async fn post_tweet(
config: &TwitterConfig,
content: &str,
medias: &[u64],
reply_to: &Option<u64>,
) -> Result<u64, Box<dyn Error>> {
let empty_request = EmptyRequest {}; // Why? Because fuck you, thats why!
let token = get_token(config);
let tweet = Tweet {
text: content.to_string(),
media: TweetMediasIds {
media: medias.is_empty().not().then(|| TweetMediasIds {
media_ids: medias.iter().map(|m| m.to_string()).collect(),
},
}),
reply: reply_to.map(|s| TweetReply {
in_reply_to_tweet_id: s.to_string(),
}),
};
let client = Client::new();