add database
All checks were successful
tests / fmt (push) Successful in 1m46s
tests / clippy (push) Successful in 1m48s
tests / test (push) Successful in 1m50s
tests / pre-commit (push) Successful in 2m5s
tests / build (push) Successful in 2m31s
deploy / release-image (push) Successful in 5m44s

This commit is contained in:
2024-06-20 20:16:19 +02:00
parent 4a69e0f578
commit 8985945659
11 changed files with 920 additions and 2 deletions

View File

@@ -1,7 +1,7 @@
use crate::colors;
use crate::commands::join::join_channel;
use crate::metadata::{Metadata, MetadataMap};
use crate::state::State;
use crate::{colors, db};
use serde::{Deserialize, Serialize};
use songbird::input::{Compose, YoutubeDl};
@@ -180,12 +180,51 @@ pub(crate) async fn play(
.clone()
.or(yttrack.url.clone())
.ok_or("Could not find url")?;
let mut src = YoutubeDl::new(reqwest::Client::new(), url.clone());
let src_copy = src.clone();
let track: Track = src_copy.into();
if let Ok(metadata) = src.aux_metadata().await {
debug!("metadata: {:?}", metadata);
let (author_name, author_global_name) = if let Some(author) = interaction.author() {
(author.name.clone(), author.global_name.clone())
} else {
("".to_string(), None)
};
db::track::insert_guild(&state.pool, db::track::Guild::new(guild_id.to_string()))
.await
.expect("failed to insert guild: {e}");
db::track::insert_user(
&state.pool,
db::track::User::new(user_id.to_string(), author_name, author_global_name),
)
.await
.expect("failed to insert user: {e}");
let track_id = db::track::insert_track(
&state.pool,
db::track::Track::new(
url.clone(),
yttrack.title.clone(),
yttrack.channel.clone(),
yttrack.duration_string.clone(),
metadata.thumbnail.clone().unwrap_or_default(),
),
)
.await
.expect("failed to insert track: {e}");
db::track::insert_query(
&state.pool,
db::track::Query::new(user_id.to_string(), guild_id.to_string(), track_id),
)
.await
.expect("failed to insert track: {e}");
tracks_added.push(TrackType {
url: url.clone(),
title: metadata.title.clone(),

1
src/db/mod.rs Normal file
View File

@@ -0,0 +1 @@
pub mod track;

146
src/db/track.rs Normal file
View File

@@ -0,0 +1,146 @@
use chrono::{DateTime, Utc};
use sqlx::FromRow;
#[derive(Debug, FromRow)]
pub(crate) struct Track {
#[allow(dead_code)]
pub(crate) id: i64,
pub(crate) url: String,
pub(crate) title: String,
pub(crate) channel: String,
pub(crate) duration: String,
pub(crate) thumbnail: String,
pub(crate) updated: DateTime<Utc>,
}
impl Track {
pub(crate) fn new(
url: String,
title: String,
channel: String,
duration: String,
thumbnail: String,
) -> Self {
Self {
id: 0,
url,
title,
channel,
duration,
thumbnail,
updated: chrono::offset::Utc::now(),
}
}
}
pub(crate) async fn insert_track(
pool: &sqlx::SqlitePool,
track: Track,
) -> Result<i64, sqlx::Error> {
let query =
"INSERT OR REPLACE INTO tracks (url, title, channel, duration, thumbnail, updated) VALUES ($1, $2, $3, $4, $5, $6)";
let res = sqlx::query(query)
.bind(track.url)
.bind(track.title)
.bind(track.channel)
.bind(track.duration)
.bind(track.thumbnail)
.bind(track.updated)
.execute(pool)
.await?;
Ok(res.last_insert_rowid())
}
#[derive(Debug, FromRow)]
pub(crate) struct User {
pub(crate) id: String,
pub(crate) name: String,
pub(crate) global_name: Option<String>,
pub(crate) updated: DateTime<Utc>,
}
impl User {
pub(crate) fn new(id: String, name: String, global_name: Option<String>) -> Self {
Self {
id,
name,
global_name,
updated: chrono::offset::Utc::now(),
}
}
}
pub(crate) async fn insert_user(pool: &sqlx::SqlitePool, user: User) -> Result<(), sqlx::Error> {
let query =
"INSERT OR REPLACE INTO users (id, name, global_name, updated) VALUES ($1, $2, $3, $4)";
sqlx::query(query)
.bind(user.id)
.bind(user.name)
.bind(user.global_name)
.bind(user.updated)
.execute(pool)
.await?;
Ok(())
}
#[derive(Debug, FromRow)]
pub(crate) struct Query {
#[allow(dead_code)]
pub(crate) id: i64,
pub(crate) user_id: String,
pub(crate) guild_id: String,
pub(crate) track_id: i64,
pub(crate) updated: DateTime<Utc>,
}
impl Query {
pub(crate) fn new(user_id: String, guild_id: String, track_id: i64) -> Self {
Self {
id: 0,
user_id,
guild_id,
track_id,
updated: chrono::offset::Utc::now(),
}
}
}
pub(crate) async fn insert_query(pool: &sqlx::SqlitePool, q: Query) -> Result<i64, sqlx::Error> {
let query =
"INSERT OR REPLACE INTO queries (user_id, guild_id, track_id, updated) VALUES ($1, $2, $3, $4)";
let res = sqlx::query(query)
.bind(q.user_id)
.bind(q.guild_id)
.bind(q.track_id)
.bind(q.updated)
.execute(pool)
.await?;
Ok(res.last_insert_rowid())
}
#[derive(Debug, FromRow)]
pub(crate) struct Guild {
pub(crate) id: String,
pub(crate) updated: DateTime<Utc>,
}
impl Guild {
pub(crate) fn new(id: String) -> Self {
Self {
id,
updated: chrono::offset::Utc::now(),
}
}
}
pub(crate) async fn insert_guild(
pool: &sqlx::SqlitePool,
guild: Guild,
) -> Result<i64, sqlx::Error> {
let query = "INSERT OR REPLACE INTO guilds (id, updated) VALUES ($1, $2)";
let res = sqlx::query(query)
.bind(guild.id)
.bind(guild.updated)
.execute(pool)
.await?;
Ok(res.last_insert_rowid())
}

View File

@@ -1,7 +1,9 @@
mod handler;
use handler::Handler;
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
mod colors;
mod commands;
mod db;
mod interaction_commands;
mod metadata;
mod signal;
@@ -38,6 +40,16 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
info!("Starting up...");
let (mut shards, state) = {
let db = env::var("DATABASE_URL").map_err(|_| "DATABASE_URL is not set")?;
let options = SqliteConnectOptions::new()
.create_if_missing(true)
.filename(&db);
let pool = SqlitePoolOptions::new()
.max_connections(5)
.connect_with(options)
.await?;
sqlx::migrate!().run(&pool).await?;
let token = env::var("DISCORD_TOKEN").map_err(|_| "DISCORD_TOKEN is not set")?;
let app_id = env::var("DISCORD_APP_ID")
.map_err(|_| "DISCORD_APP_ID is not set")?
@@ -80,6 +92,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
songbird,
standby: Standby::new(),
guild_settings: Default::default(),
pool,
}),
)
};

View File

@@ -32,4 +32,5 @@ pub(crate) struct StateRef {
pub(crate) songbird: Songbird,
pub(crate) standby: Standby,
pub(crate) guild_settings: DashMap<Id<GuildMarker>, Settings>,
pub(crate) pool: sqlx::SqlitePool,
}