use crate::creds::Creds; use crate::sticker_config::{DiscordDeployLocation, Sticker, StickerConfig, StickerType}; use indexmap::IndexMap; use serenity::http::client::Http as DiscordClient; //use serenity::cache::Cache as DiscordCache; use serenity::model::prelude::Emoji; use std::collections::{HashMap, VecDeque}; use serde_json::json; fn split_by( pack_contents: &[String], sticker_type: StickerType, deploy_locations: &[DiscordDeployLocation], pack_emojis: &HashMap<String, Sticker>, ) -> IndexMap<String, Vec<(String, Sticker)>> { let pack_type_emoji_count = pack_emojis .iter() .filter(|emoji| emoji.1.r#type == sticker_type) .count(); let max_type_emoji_total: u64 = deploy_locations .iter() .map(|loc| { return match sticker_type { StickerType::Regular => loc.max_regular_emoji, StickerType::Gif => loc.max_animated_emoji, _ => unreachable!("wrong sticker type for discord"), }; }) .sum(); if pack_type_emoji_count > max_type_emoji_total.try_into().unwrap() { panic!("not enough space in servers for emoji, please add more servers to deploy across") } let mut pack_type_emojis: VecDeque<(String, Sticker)> = pack_contents .iter() .filter(|emoji| { return pack_emojis.get(*emoji).unwrap().r#type == sticker_type; }) .map(|emoji| { return (emoji.clone(), pack_emojis.get(emoji).unwrap().clone()); }) .collect(); let mut emojis_per_server: IndexMap<String, Vec<(String, Sticker)>> = IndexMap::new(); for deploy_location in deploy_locations.iter() { emojis_per_server.insert(deploy_location.deploy_name.clone(), Vec::new()); } 'outer: for deploy_location in deploy_locations.iter() { let mut sticker_count = 0; let max_type_emoji = match sticker_type { StickerType::Regular => deploy_location.max_regular_emoji, StickerType::Gif => deploy_location.max_animated_emoji, _ => unreachable!("wrong sticker type for discord"), }; while sticker_count < max_type_emoji { let emoji = pack_type_emojis.pop_front(); if emoji.is_none() { break 'outer; } emojis_per_server .get_mut(&deploy_location.deploy_name) .unwrap() .push(emoji.unwrap()); sticker_count += 1; } } emojis_per_server } pub async fn deploy_discord( deploy_id: String, sticker_config: StickerConfig, creds: Creds, base_stickerdb_path: String, ) { let discord_token = creds.discord_bot_token.as_str(); let discord_client = DiscordClient::new(discord_token); //let discord_cache = DiscordCache::new() let deploy_where = sticker_config.deploy_where.get(&deploy_id).unwrap(); let deploy_locations = deploy_where.discord.as_ref().unwrap().clone(); let deploy_locations_map: HashMap<_, _> = deploy_locations .iter() .map(|loc| (loc.deploy_name.clone(), loc)) .collect(); let pack_contents = sticker_config.sticker_sets.get(&deploy_where.pack_id).unwrap(); let pack_emojis: HashMap<String, Sticker> = pack_contents .iter() .map(|emoji_name| { return ( emoji_name.clone(), sticker_config.stickers.get(emoji_name).unwrap().clone(), ); }) .collect(); let mut emojis_per_server: IndexMap<String, Vec<(String, Sticker)>> = IndexMap::new(); for deploy_location in deploy_locations.iter() { emojis_per_server.insert(deploy_location.deploy_name.clone(), Vec::new()); } // block only so can hide in IDE { let regular_emoji_per_server = split_by( pack_contents, StickerType::Regular, &deploy_locations, &pack_emojis, ); for loc in regular_emoji_per_server.into_iter() { emojis_per_server .get_mut(&loc.0) .unwrap() .extend(loc.1.into_iter()); } let gif_emoji_per_server = split_by( pack_contents, StickerType::Gif, &deploy_locations, &pack_emojis, ); for loc in gif_emoji_per_server.into_iter() { emojis_per_server .get_mut(&loc.0) .unwrap() .extend(loc.1.into_iter()); } } for server_k_v in emojis_per_server.iter() { let deploy_name = server_k_v.0.to_owned(); let deploy_emojis = server_k_v.1.to_owned(); println!("Deploying to {}", deploy_name); let deploy_location = deploy_locations_map.get(&deploy_name).unwrap(); let deploy_emoji_names: Vec<String> = deploy_emojis .iter() .map(|deploy_emoji| deploy_emoji.0.clone()) .collect(); let discord_emojis = discord_client .get_emojis(deploy_location.id) .await .expect("could not fetch discord emoji"); let discord_emojis_names: Vec<String> = discord_emojis .iter() .map(|emoji| emoji.name.clone()) .collect(); let invalid_emojis: Vec<Emoji> = discord_emojis .clone() .into_iter() .filter(|emoji| !deploy_emoji_names.contains(&emoji.name)) .collect(); if !invalid_emojis.is_empty() { for emoji in invalid_emojis.iter() { println!("Removing Emoji {}", &emoji.name); discord_client .delete_emoji(deploy_location.id, emoji.id.0) .await .expect("could not delete emoji") } } let missing_emojis: Vec<String> = deploy_emoji_names .clone() .into_iter() .filter(|emoji| !discord_emojis_names.contains(emoji)) .collect(); if !missing_emojis.is_empty() { for emoji in missing_emojis.iter() { println!("Uploading Emoji {}", &emoji); let emoji_data = pack_emojis.get(emoji).unwrap(); let image_path = std::path::PathBuf::from(&base_stickerdb_path) .join(std::path::PathBuf::from(emoji_data.file.clone())); let image_data = serenity::utils::read_image(image_path).expect("could not open emoji file"); discord_client .create_emoji( deploy_location.id, &json!({ "name": emoji, "image": image_data, }), None, ) .await .expect("could not upload emoji"); } } println!( "Missing: {:#?}\nInvalid: {:#?}", missing_emojis, invalid_emojis ); } //println!("{:#?}", emojis_per_server); //println!("{} {} {:?}", max_regular_emoji_total, max_animated_emoji_total, deploy_locations); }