Skip to content

Commit

Permalink
Got images to miitopia
Browse files Browse the repository at this point in the history
  • Loading branch information
nin-jat committed Sep 26, 2022
1 parent f9c5cc6 commit 891a531
Show file tree
Hide file tree
Showing 8 changed files with 340 additions and 30 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
.env
*.kra

/resources/music/*.ogg
/resources/music/*.ogg
resources/*.tar.xz
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cSpell.words": [
"Miitopia"
]
}
39 changes: 39 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ serenity = { version = "0.11.5", default-features = false, features = [
"gateway",
"rustls_backend",
"model",
"cache"
"cache",
] }
tokio = { version = "1.21.1", features = ["full"] }
ogg_metadata = "0.4.1"
glob = "0.3.0"
rand = { version = "0.8.5", features = ["small_rng"] }
indexmap = "1.9.1"
ffmpeg-cli = "0.1.0"
2 changes: 2 additions & 0 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[toolchain]
channel = "stable"
36 changes: 36 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use core::fmt;
use std::io;

use serenity::prelude::*;

#[derive(Debug)]
pub enum MiitopiaError {
Serenity(SerenityError),
Ffmpeg(String),
Io(io::Error),
InvalidFileType,
UnsupportedFileType,
}

impl fmt::Display for MiitopiaError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MiitopiaError::Serenity(e) => write!(f, "Serenity Error: {}", e),
MiitopiaError::Ffmpeg(e) => write!(f, "Ffmpeg Error: {}", e),
MiitopiaError::Io(e) => write!(f, "IO Error: {}", e),
MiitopiaError::InvalidFileType => write!(f, "Invalid File Type"),
MiitopiaError::UnsupportedFileType => write!(f, "File Type not supported."),
}
}
}

impl From<io::Error> for MiitopiaError {
fn from(e: io::Error) -> Self {
MiitopiaError::Io(e)
}
}
impl From<SerenityError> for MiitopiaError {
fn from(e: SerenityError) -> Self {
MiitopiaError::Serenity(e)
}
}
102 changes: 79 additions & 23 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
use std::collections::HashMap;
use std::env;
use std::path::PathBuf;
use std::sync::Arc;

use processor::scan_music;
use serenity::async_trait;
use indexmap::IndexMap;
use processor::{apply_music, get_rand_track, scan_music};
use rand::prelude::SmallRng;
use rand::{Rng, SeedableRng};
use serenity::http::CacheHttp;
use serenity::model::channel::Message;
use serenity::model::channel::{AttachmentType, Message};
use serenity::model::gateway::Ready;
use serenity::prelude::*;
use serenity::utils::colours;
use serenity::{async_trait, futures, prelude::*};

mod error;
mod processor;

struct Handler;

const MAX_LENGTH: f32 = 10.0;

#[async_trait]
impl EventHandler for Handler {
// Set a handler for the `message` event - so that whenever a new message
Expand All @@ -26,35 +31,86 @@ impl EventHandler for Handler {
// Broadcast that we are typing.
let _ = ctx.http().broadcast_typing(msg.channel_id.0);

// get our tracks.
let data_read = ctx.data.read().await;
let tracks = data_read
.get::<Music>()
.expect("Expected Music in TypeMap")
.read()
.await;

let mut rng = SmallRng::from_entropy();

// Start processing the attachments.
let mut raw_futures = Vec::new();
for attachment in msg.attachments {
if let Some(content_type) = attachment.content_type {
match content_type.as_str() {
"image/png" | "image/jpeg" | "image/webp" | "image/bmp" | "image/gif" => {}
_ => {
if let Err(why) =
msg.channel_id.say(&ctx.http, "Unsupported file type").await
{
println!("Error sending message: {:?}", why);
}
continue;
// Get a random track and duration.
let (track, track_duration) =
get_rand_track(&tracks, &mut rng).expect("No track found");

// start at zero and clip the duration to our MAX.
let mut start: f32 = 0.0;
let duration = track_duration.min(MAX_LENGTH);

// only update start if the track is longer than our max.
if track_duration > MAX_LENGTH {
start = rng.gen_range(0.0..track_duration - duration);
}
raw_futures.push(apply_music(track, start, duration, attachment));
}
let unpin_futures: Vec<_> = raw_futures.into_iter().map(Box::pin).collect();
let mut futures = unpin_futures;

while !futures.is_empty() {
match futures::future::select_all(futures).await {
(Ok(file_bytes), _index, remaining) => {
futures = remaining;
if let Err(why) = msg
.channel_id
.send_message(&ctx.http, |m| {
m.add_file(AttachmentType::Bytes {
data: file_bytes.into(),
filename: "miitopia.webm".to_string(),
})
})
.await
{
println!("Error sending message: {:?}", why);
}
}
(Err(error), _index, remaining) => {
// Update the futures.
futures = remaining;

// Do something about the error.
println!("Error: {:?}", error);

// Create an error.
if let Err(why) = msg
.channel_id
.send_message(&ctx.http, |m| {
m.add_embed(|em| {
em.description(error.to_string())
.colour(colours::css::DANGER)
.title("⚠️ Error")
})
})
.await
{
println!("Error sending message: {:?}", why);
}
}
}
}

if let Err(why) = msg.channel_id.say(&ctx.http, "What?").await {
println!("Error sending message: {:?}", why);
};
}
}

// Set a handler to be called on the `ready` event. This is called when a
// shard is booted, and a READY payload is sent by Discord. This payload
// contains data like the current user's guild Ids, current user data,
// private channels, and more.
//
// In this case, just print what the current user's username is.
async fn ready(&self, _: Context, ready: Ready) {
async fn ready(&self, _ctx: Context, ready: Ready) {
println!("{} is connected!", ready.user.name);
}
}
Expand All @@ -69,7 +125,7 @@ async fn main() {
// Scan all our music
println!("Scanning /resources/music");
let music = scan_music();
println!("Found {} suitable tracks", music.len(),);
println!("Found {} tracks", music.len(),);

// Create a new instance of the Client, logging in as a bot. This will
// automatically prepend your bot token with "Bot ", which is a requirement
Expand All @@ -96,5 +152,5 @@ async fn main() {
struct Music;

impl TypeMapKey for Music {
type Value = Arc<RwLock<HashMap<PathBuf, f32>>>;
type Value = Arc<RwLock<IndexMap<PathBuf, f32>>>;
}
Loading

0 comments on commit 891a531

Please sign in to comment.