294 lines
9.5 KiB
Rust
294 lines
9.5 KiB
Rust
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<String, String>,
|
|
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<dyn Error>> {
|
|
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<String, String> = serde_yaml::from_reader(file)?;
|
|
self.data.extend(data.into_iter());
|
|
Ok(())
|
|
}
|
|
pub fn save(&self) -> Result<(), Box<dyn Error>> {
|
|
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<String, Sticker> = 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 max = match deploy_location.r#type {
|
|
StickerType::Regular => 120,
|
|
StickerType::TelegramVideo => 50,
|
|
StickerType::TelegramAnimated => 50,
|
|
_ => {
|
|
unreachable!();
|
|
}
|
|
};
|
|
|
|
if pack_contents.len() >= max - 1 {
|
|
panic!("too many stickers in pack");
|
|
}
|
|
println!("{}", pack_contents.len());
|
|
|
|
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<TelegramSticker> = 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<String> = Vec::new();
|
|
|
|
// add stickers that arent in tg_stickers
|
|
{
|
|
let missing_stickers: Vec<String> = 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<u8> = Vec::new();
|
|
file.read_to_end(&mut file_data)
|
|
.expect("could not read file");
|
|
|
|
let mut png_sticker: Option<Vec<u8>> = None;
|
|
let mut tgs_sticker: Option<Vec<u8>> = None;
|
|
let mut webm_sticker: Option<Vec<u8>> = 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());
|
|
}
|
|
}
|
|
|
|
// 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<usize> = 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");
|
|
}
|
|
}
|
|
}
|
|
}
|