use std::io::Read; use std::ops::Index; use std::{collections::HashMap, error::Error}; use crate::{ creds::Creds, sticker_config::{Sticker, StickerConfig, StickerType}, tg_api::{TelegramAPI, TelegramSticker}, }; struct TelegramStickerIDState { // File ID to Sticker Name data: HashMap, base_stickerdb_path: String, } impl TelegramStickerIDState { pub fn new(base_stickerdb_path: &str) -> Self { TelegramStickerIDState { data: HashMap::new(), base_stickerdb_path: base_stickerdb_path.to_owned(), } } pub fn load(&mut self) -> Result<(), Box> { let path = std::path::PathBuf::from(&self.base_stickerdb_path).join("telegram_state.yml"); let file = std::fs::OpenOptions::new() .write(true) .read(true) .create(true) .open(path)?; let data: HashMap = serde_yaml::from_reader(file)?; self.data.extend(data.into_iter()); Ok(()) } pub fn save(&self) -> Result<(), Box> { let path = std::path::PathBuf::from(&self.base_stickerdb_path).join("telegram_state.yml"); let file = std::fs::OpenOptions::new() .write(true) .create(true) .open(path)?; serde_yaml::to_writer(file, &self.data)?; Ok(()) } pub fn get(&self, file_id: &String) -> Option<&String> { self.data.get(file_id) } pub fn set(&mut self, file_id: &str, sticker_name: &str) { self.data .insert(file_id.to_owned(), sticker_name.to_owned()); } } pub async fn deploy_telegram( deploy_id: String, sticker_config: StickerConfig, creds: Creds, base_stickerdb_path: String, ) { let mut tg_state = TelegramStickerIDState::new(&base_stickerdb_path); tg_state.load().expect("could not load sticker state"); let deploy_where = sticker_config.deploy_where.get(&deploy_id).unwrap(); let deploy_location = deploy_where.telegram.as_ref().unwrap(); if deploy_location.r#type == StickerType::Gif { panic!("gif stickers not supported on telegram, bodge it into video") } let pack_contents = sticker_config .sticker_sets .get(&deploy_where.pack_id) .unwrap(); let pack_stickers: HashMap = pack_contents .iter() .map(|sticker_name| { return ( sticker_name.clone(), sticker_config.stickers.get(sticker_name).unwrap().clone(), ); }) .collect(); let contains_invalid_stickers = pack_stickers .iter() .find(|sticker| sticker.1.r#type != deploy_location.r#type); if contains_invalid_stickers.is_some() { panic!("pack contains a invalid type of emoji for pack type") } let tg_bot = TelegramAPI::new(creds.telegram_bot_token); let tg_sticker_set = tg_bot .get_sticker_set(&deploy_location.name) .await .expect("could not get sticker pack"); let mut tg_stickers: Vec<(String, TelegramSticker)> = Vec::new(); // Delete stickers that arent in state // add valid stickers to tg_stickers { let mut tg_sticker_set_iter = tg_sticker_set.stickers.iter(); // Skip the first sticker tg_sticker_set_iter.next(); for sticker in tg_sticker_set_iter { match tg_state.get(&sticker.file_unique_id) { Some(sticker_name) => tg_stickers.push((sticker_name.clone(), sticker.clone())), None => { println!( "Deleting sticker with unique_id {} as is not in state", &sticker.file_unique_id ); tg_bot .delete_sticker(&sticker.file_id) .await .expect("could not delete sticker"); } } } } // Delete stickers that have a name but are no longer in the new pack { let invalid_stickers: Vec = tg_stickers .clone() .into_iter() .filter(|sticker| !pack_contents.contains(&sticker.0)) .map(|sticker| sticker.1) .collect(); for invalid_sticker in invalid_stickers.iter() { println!( "Deleting sticker with name {} as is not in pack", &invalid_sticker.file_unique_id ); tg_bot .delete_sticker(&invalid_sticker.file_id) .await .expect("could not delete sticker"); tg_stickers.retain(|sticker| { // keep if true sticker.1.file_unique_id != invalid_sticker.file_unique_id }) } } // +1 for skipping the first sticker let new_sticker_position_base = tg_stickers.len() + 1; let mut new_stickers: Vec = Vec::new(); // add stickers that arent in tg_stickers { let missing_stickers: Vec = pack_contents .clone() .into_iter() .filter(|sticker| { for tg_sticker in tg_stickers.iter() { if tg_sticker.0 == sticker.clone() { return false; } } true }) .collect(); for sticker_name in missing_stickers.iter() { println!("Uploading Sticker: {}", sticker_name); let sticker_data = pack_stickers.get(sticker_name).unwrap(); let file_path = std::path::PathBuf::from(&base_stickerdb_path).join(&sticker_data.file); let mut file = std::fs::File::open(file_path).unwrap(); let mut file_data: Vec = Vec::new(); file.read_to_end(&mut file_data) .expect("could not read file"); let mut png_sticker: Option> = None; let mut tgs_sticker: Option> = None; let mut webm_sticker: Option> = None; match deploy_location.r#type { StickerType::Regular => { png_sticker = Some(file_data); } StickerType::TelegramVideo => { webm_sticker = Some(file_data); } StickerType::TelegramAnimated => { tgs_sticker = Some(file_data); } _ => {} } tg_bot .upload_sticker( deploy_location.user_id, deploy_location.name.clone(), Some(sticker_data.emojis.concat()), png_sticker, tgs_sticker, webm_sticker, ) .await .expect("could not upload sticker"); new_stickers.push(sticker_name.clone()); } println!("{:#?}", missing_stickers); } // Update tg_stickers with current sticker contents { let tg_new_sticker_set = tg_bot .get_sticker_set(&deploy_location.name) .await .expect("could not get sticker pack"); for (i, sticker_name) in new_stickers.iter().enumerate() { let new_sticker = tg_new_sticker_set .stickers .index(new_sticker_position_base + i) .clone(); tg_state.set(&new_sticker.file_unique_id, sticker_name); tg_stickers.push(( sticker_name.clone(), tg_new_sticker_set .stickers .index(new_sticker_position_base + i) .clone(), )); } } tg_state.save().expect("could not save state"); // Reorder stickers using order of pack_contents { for (correct_sticker_i, sticker_name) in pack_contents.iter().enumerate() { let pack_sticker = sticker_name.clone(); let tg_sticker = tg_stickers.index(correct_sticker_i).0.clone(); if pack_sticker != tg_sticker { println!( "Sticker in position {} is the wrong sticker", correct_sticker_i ); let mut sticker_incorrect_pos: Option = None; for (sticker_i, sticker) in tg_stickers.iter().enumerate() { if sticker.0 == pack_sticker { sticker_incorrect_pos = Some(sticker_i); } } if sticker_incorrect_pos.is_none() { unreachable!() } println!( "Moving sticker at position {} to {}", sticker_incorrect_pos.unwrap(), correct_sticker_i ); let sticker = tg_stickers.remove(sticker_incorrect_pos.unwrap()); tg_stickers.insert(correct_sticker_i, sticker.clone()); tg_bot .set_sticker_position(sticker.1.file_id.clone(), correct_sticker_i + 1) .await .expect("could not move sticker"); } } } }