This commit is contained in:
parent
ccf8c65c80
commit
485d44c56f
|
@ -1,3 +1,4 @@
|
|||
# 0.2.5
|
||||
- DATABASE FORMAT CHANGE!
|
||||
- memes will now have their file name as the image description.
|
||||
- add sendmeme feature
|
||||
|
|
|
@ -5,6 +5,9 @@ password = "xxx"
|
|||
# path to store databases
|
||||
store_path = "store"
|
||||
|
||||
# !sendmeme <id> to make ruff send the meme with the given id
|
||||
sendmeme_command = "!sendmeme"
|
||||
|
||||
# MEMES!!
|
||||
memes = [
|
||||
# random stuff
|
||||
|
|
|
@ -12,6 +12,7 @@ pub struct Config {
|
|||
pub user_id: String,
|
||||
pub password: String,
|
||||
pub device_name: Option<String>,
|
||||
pub sendmeme_command: Option<String>,
|
||||
pub memes: Vec<Meme>,
|
||||
pub store_path: PathBuf,
|
||||
#[serde(default = "default_clear_threshold")]
|
||||
|
|
35
src/meme.rs
35
src/meme.rs
|
@ -1,4 +1,5 @@
|
|||
use crate::Bot;
|
||||
use log::error;
|
||||
use rand::seq::IteratorRandom;
|
||||
use serde::Deserialize;
|
||||
|
||||
|
@ -56,18 +57,32 @@ impl Meme {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn get_meme(&self, bot: &Bot) -> anyhow::Result<Option<jm_client_core::api::Meme>> {
|
||||
pub async fn get_id(&self, bot: &Bot) -> anyhow::Result<Option<u32>> {
|
||||
let memes = bot.jm_client.read().await.get_memes().await?;
|
||||
match &self.ident {
|
||||
MemeIdent::Id(i) => Ok(memes
|
||||
.iter()
|
||||
.find(|m| m.id.parse::<u32>().ok() == Some(*i))
|
||||
.cloned()),
|
||||
MemeIdent::RandomCat(c) => Ok(memes
|
||||
.iter()
|
||||
.filter(|m| &m.category == c)
|
||||
.choose(&mut *bot.rng.lock().await)
|
||||
.cloned()),
|
||||
MemeIdent::Id(i) => Ok(Some(*i)),
|
||||
MemeIdent::RandomCat(c) => {
|
||||
let meme = memes
|
||||
.iter()
|
||||
.filter(|m| &m.category == c)
|
||||
.choose(&mut *bot.rng.lock().await);
|
||||
|
||||
if let Some(meme) = meme {
|
||||
let id = meme.id.parse::<u32>();
|
||||
match id {
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Error parsing meme ID {} for meme {:?} thanks to tilera's PHP api",
|
||||
&meme.id, &meme
|
||||
);
|
||||
Err(e.into())
|
||||
}
|
||||
Ok(id) => Ok(Some(id)),
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
177
src/responder.rs
177
src/responder.rs
|
@ -83,86 +83,117 @@ pub async fn on_msg(msg: &str, room: Room, bot: &Bot) -> anyhow::Result<()> {
|
|||
}
|
||||
};
|
||||
|
||||
if let Some(ref sendmeme_cmd) = bot.config.sendmeme_command {
|
||||
let mut words = msg.split(' ');
|
||||
if words.next() == Some(sendmeme_cmd) {
|
||||
if let Some(id) = words.next() {
|
||||
let id = if let Ok(id) = id.parse::<u32>() {
|
||||
id
|
||||
} else {
|
||||
room.send(
|
||||
AnyMessageEventContent::RoomMessage(MessageEventContent::text_plain(
|
||||
"Invalid ID!",
|
||||
)),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
cache_send_meme(id, bot, room).await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for meme in &bot.config.memes {
|
||||
if meme.matches(msg) {
|
||||
bot.meme_count.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
if let Some(meme) = meme.get_meme(bot).await? {
|
||||
match meme.id.parse::<u32>() {
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Meme {:?} has invalid ID! tilera, you messed up with your stupid php \
|
||||
again: {}",
|
||||
&meme, e
|
||||
);
|
||||
}
|
||||
Ok(id) => {
|
||||
if let Some(ivec) = bot.memecache.get(id.to_le_bytes())? {
|
||||
let cached = bincode::deserialize::<CachedMeme>(&ivec)?;
|
||||
send_meme(&room, cached).await?;
|
||||
} else {
|
||||
info!("Meme {} not found in cache, uploading...", id);
|
||||
let resp = bot
|
||||
.jm_client
|
||||
.read()
|
||||
.await
|
||||
.http
|
||||
.get(&meme.link)
|
||||
.send()
|
||||
.await
|
||||
.context("error downloading meme")?;
|
||||
let resp = resp.bytes().await?;
|
||||
|
||||
if let Some(mime) = mime_guess::from_path(&meme.link).first() {
|
||||
let size = resp.len();
|
||||
let create_content::Response { content_uri, .. } = bot
|
||||
.client
|
||||
.read()
|
||||
.await
|
||||
.upload(&mime, &mut Cursor::new(resp))
|
||||
.await?;
|
||||
|
||||
let cached = CachedMeme {
|
||||
mxc: content_uri,
|
||||
mime,
|
||||
size: UInt::new(size as u64)
|
||||
.context("Meme has file size over allowed limit!")?,
|
||||
meme_name: meme
|
||||
.link
|
||||
.split('/')
|
||||
.last()
|
||||
.unwrap_or(&meme.link)
|
||||
.to_string(),
|
||||
};
|
||||
|
||||
bot.memecache
|
||||
.insert(id.to_le_bytes(), bincode::serialize(&cached)?)?;
|
||||
|
||||
send_meme(&room, cached).await?;
|
||||
} else {
|
||||
error!(
|
||||
"Couldn't guess MIME type of meme '{}', skipping.",
|
||||
&meme.link
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!("Found meme with invalid id! {:?}", &meme);
|
||||
if let Some(id) = meme.get_id(bot).await? {
|
||||
cache_send_meme(id, bot, room).await?;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// we do this after we have responded, in order to not delay the response
|
||||
if bot.meme_count.load(Ordering::SeqCst) >= bot.config.clear_cache_threshold {
|
||||
let mut client = bot.jm_client.write().await;
|
||||
bot.meme_count.store(0, Ordering::SeqCst);
|
||||
client.clear_cache().await;
|
||||
// memes requested but not used, but they will be cached
|
||||
client.get_memes().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cache_send_meme(meme_id: u32, bot: &Bot, room: Joined) -> anyhow::Result<()> {
|
||||
bot.meme_count.fetch_add(1, Ordering::SeqCst);
|
||||
let memes = bot.jm_client.read().await.get_memes().await?;
|
||||
let meme = memes
|
||||
.iter()
|
||||
.find(|m| m.id.parse::<u32>().ok() == Some(meme_id))
|
||||
.cloned();
|
||||
|
||||
if let Some(meme) = meme {
|
||||
if let Some(ivec) = bot.memecache.get(meme_id.to_be_bytes())? {
|
||||
let cached = bincode::deserialize::<CachedMeme>(&ivec)?;
|
||||
send_meme(&room, cached).await?;
|
||||
} else {
|
||||
info!("Meme {} not found in cache, uploading...", meme_id);
|
||||
let resp = bot
|
||||
.jm_client
|
||||
.read()
|
||||
.await
|
||||
.http
|
||||
.get(&meme.link)
|
||||
.send()
|
||||
.await
|
||||
.context("error downloading meme")?;
|
||||
let resp = resp.bytes().await?;
|
||||
|
||||
if let Some(mime) = mime_guess::from_path(&meme.link).first() {
|
||||
let size = resp.len();
|
||||
let create_content::Response { content_uri, .. } = bot
|
||||
.client
|
||||
.read()
|
||||
.await
|
||||
.upload(&mime, &mut Cursor::new(resp))
|
||||
.await?;
|
||||
|
||||
let cached = CachedMeme {
|
||||
mxc: content_uri,
|
||||
mime,
|
||||
size: UInt::new(size as u64)
|
||||
.context("Meme has file size over allowed limit!")?,
|
||||
meme_name: meme
|
||||
.link
|
||||
.split('/')
|
||||
.last()
|
||||
.unwrap_or(&meme.link)
|
||||
.to_string(),
|
||||
};
|
||||
|
||||
bot.memecache
|
||||
.insert(meme_id.to_be_bytes(), bincode::serialize(&cached)?)?;
|
||||
|
||||
send_meme(&room, cached).await?;
|
||||
//
|
||||
// we do this after we have responded, in order to not delay the response
|
||||
if bot.meme_count.load(Ordering::SeqCst) >= bot.config.clear_cache_threshold {
|
||||
let mut client = bot.jm_client.write().await;
|
||||
bot.meme_count.store(0, Ordering::SeqCst);
|
||||
client.clear_cache().await;
|
||||
// memes requested but not used, but they will be cached
|
||||
client.get_memes().await?;
|
||||
}
|
||||
} else {
|
||||
error!(
|
||||
"Couldn't guess MIME type of meme '{}', skipping.",
|
||||
&meme.link
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
room.send(
|
||||
AnyMessageEventContent::RoomMessage(MessageEventContent::text_plain(&format!(
|
||||
"No meme with id '{}'",
|
||||
meme_id
|
||||
))),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue