Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ee400fe4eb | |||
|
ecd5705272
|
|||
|
226a475e75
|
|||
|
c8108cfb39
|
|||
|
3deb6983b0
|
@@ -3,6 +3,8 @@ name: Release Tagging
|
||||
on:
|
||||
push:
|
||||
branches: [ "v0.2" ]
|
||||
pull_request:
|
||||
branches: [ "v0.2" ]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"dev": {
|
||||
"migrations": "./migrations"
|
||||
},
|
||||
"test": {
|
||||
"migrations": "./test_migrations"
|
||||
}
|
||||
}
|
||||
Generated
+3
-18
@@ -630,16 +630,6 @@ dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hdrhistogram"
|
||||
version = "7.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@@ -762,7 +752,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icarus"
|
||||
version = "0.1.96"
|
||||
version = "0.1.93"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"common-multipart-rfc7578",
|
||||
@@ -770,7 +760,6 @@ dependencies = [
|
||||
"icarus_envy",
|
||||
"icarus_meta",
|
||||
"icarus_models",
|
||||
"mime_guess",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
@@ -804,8 +793,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icarus_models"
|
||||
version = "0.5.1"
|
||||
source = "git+ssh://git@git.kundeng.us/phoenix/icarus_models.git?tag=v0.5.1-devel-1c5de9dc26-111#1c5de9dc26099ac5f21e1dc7a1f7d0dbb892b34b"
|
||||
version = "0.4.5"
|
||||
source = "git+ssh://git@git.kundeng.us/phoenix/icarus_models.git?tag=v0.4.5-devel-655d05dabb-111#655d05dabbdadb9b28940564a1eb82470aa4f166"
|
||||
dependencies = [
|
||||
"rand 0.9.1",
|
||||
"serde",
|
||||
@@ -2136,13 +2125,9 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"hdrhistogram",
|
||||
"indexmap",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
|
||||
+4
-5
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "icarus"
|
||||
version = "0.1.96"
|
||||
version = "0.1.93"
|
||||
edition = "2024"
|
||||
rust-version = "1.88"
|
||||
|
||||
@@ -8,18 +8,17 @@ rust-version = "1.88"
|
||||
axum = { version = "0.8.4", features = ["multipart"] }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = { version = "1.0.140" }
|
||||
tower = { version = "0.5.2", features = ["full"] }
|
||||
tower = { version = "0.5.2" }
|
||||
tokio = { version = "1.45.1", features = ["full"] }
|
||||
tokio-util = { version = "0.7.15", features = ["io"] }
|
||||
tokio-util = { version = "0.7.15" }
|
||||
tower-http = { version = "0.6.6", features = ["timeout"] }
|
||||
tracing-subscriber = "0.3.19"
|
||||
futures = { version = "0.3.31" }
|
||||
mime_guess = { version = "2.0.5" }
|
||||
uuid = { version = "1.17.0", features = ["v4", "serde"] }
|
||||
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "time", "uuid"] }
|
||||
time = { version = "0.3.41", features = ["formatting", "macros", "parsing", "serde"] }
|
||||
icarus_meta = { git = "ssh://git@git.kundeng.us/phoenix/icarus_meta.git", tag = "v0.3.0-devel-f4b71de969-680" }
|
||||
icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.5.1-devel-1c5de9dc26-111" }
|
||||
icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.4.5-devel-655d05dabb-111" }
|
||||
icarus_envy = { git = "ssh://git@git.kundeng.us/phoenix/icarus_envy.git", tag = "v0.3.0-devel-d73fba9899-006" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -45,13 +45,6 @@ pub mod request {
|
||||
pub coverart_queue_id: uuid::Uuid,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod get_coverart {
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Params {
|
||||
pub id: Option<uuid::Uuid>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod response {
|
||||
@@ -106,14 +99,6 @@ pub mod response {
|
||||
pub data: Vec<uuid::Uuid>,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod get_coverart {
|
||||
#[derive(Debug, Default, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Response {
|
||||
pub message: String,
|
||||
pub data: Vec<icarus_models::coverart::CoverArt>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod db {
|
||||
@@ -336,46 +321,6 @@ pub mod cov_db {
|
||||
Err(_err) => Err(sqlx::Error::RowNotFound),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_coverart(
|
||||
pool: &sqlx::PgPool,
|
||||
id: &uuid::Uuid,
|
||||
) -> Result<icarus_models::coverart::CoverArt, sqlx::Error> {
|
||||
let result = sqlx::query(
|
||||
r#"
|
||||
SELECT id, title, path, song_id FROM "coverart" WHERE id = $1;
|
||||
"#,
|
||||
)
|
||||
.bind(id)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
eprintln!("Error querying data: {e:?}");
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(row) => Ok(icarus_models::coverart::CoverArt {
|
||||
id: row
|
||||
.try_get("id")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
title: row
|
||||
.try_get("title")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
path: row
|
||||
.try_get("path")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
data: Vec::new(),
|
||||
song_id: row
|
||||
.try_get("song_id")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
}),
|
||||
Err(_) => Err(sqlx::Error::RowNotFound),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod endpoint {
|
||||
@@ -562,10 +507,7 @@ pub mod endpoint {
|
||||
|
||||
match super::cov_db::create(&pool, &coverart, &song.id).await {
|
||||
Ok(id) => {
|
||||
// TODO: Populate song_id
|
||||
coverart.id = id;
|
||||
println!("Cover Art created");
|
||||
|
||||
response.message = String::from("Successful");
|
||||
response.data.push(coverart);
|
||||
|
||||
@@ -618,32 +560,4 @@ pub mod endpoint {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_coverart(
|
||||
axum::Extension(pool): axum::Extension<sqlx::PgPool>,
|
||||
axum::extract::Query(params): axum::extract::Query<super::request::get_coverart::Params>,
|
||||
) -> (
|
||||
axum::http::StatusCode,
|
||||
axum::Json<super::response::get_coverart::Response>,
|
||||
) {
|
||||
let mut response = super::response::get_coverart::Response::default();
|
||||
|
||||
match params.id {
|
||||
Some(id) => match super::cov_db::get_coverart(&pool, &id).await {
|
||||
Ok(coverart) => {
|
||||
response.data.push(coverart);
|
||||
response.message = String::from(super::super::response::SUCCESSFUL);
|
||||
(axum::http::StatusCode::OK, axum::Json(response))
|
||||
}
|
||||
Err(err) => {
|
||||
response.message = err.to_string();
|
||||
(axum::http::StatusCode::BAD_REQUEST, axum::Json(response))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
response.message = String::from("Invalid parameters");
|
||||
(axum::http::StatusCode::BAD_REQUEST, axum::Json(response))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,7 @@ pub mod endpoints {
|
||||
pub const QUEUECOVERARTDATAWIPE: &str = "/api/v2/coverart/queue/data/wipe";
|
||||
|
||||
pub const CREATESONG: &str = "/api/v2/song";
|
||||
pub const GETSONGS: &str = "/api/v2/song";
|
||||
pub const STREAMSONG: &str = "/api/v2/song/stream/{id}";
|
||||
pub const CREATECOVERART: &str = "/api/v2/coverart";
|
||||
pub const GETCOVERART: &str = "/api/v2/coverart";
|
||||
}
|
||||
|
||||
pub mod response {
|
||||
|
||||
@@ -92,13 +92,6 @@ pub mod request {
|
||||
pub user_id: uuid::Uuid,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod get_songs {
|
||||
#[derive(Debug, Default, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Params {
|
||||
pub id: Option<uuid::Uuid>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod response {
|
||||
@@ -165,14 +158,6 @@ pub mod response {
|
||||
pub data: Vec<uuid::Uuid>,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod get_songs {
|
||||
#[derive(Debug, Default, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Response {
|
||||
pub message: String,
|
||||
pub data: Vec<icarus_models::song::Song>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Might make a distinction between year and date in a song's tag at some point
|
||||
@@ -745,7 +730,6 @@ pub mod endpoint {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Rename
|
||||
pub async fn download_flac(
|
||||
axum::Extension(pool): axum::Extension<sqlx::PgPool>,
|
||||
axum::extract::Path(id): axum::extract::Path<uuid::Uuid>,
|
||||
@@ -984,79 +968,4 @@ pub mod endpoint {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_songs(
|
||||
axum::Extension(pool): axum::Extension<sqlx::PgPool>,
|
||||
axum::extract::Query(params): axum::extract::Query<super::request::get_songs::Params>,
|
||||
) -> (
|
||||
axum::http::StatusCode,
|
||||
Json<super::response::get_songs::Response>,
|
||||
) {
|
||||
let mut response = super::response::get_songs::Response::default();
|
||||
|
||||
match params.id {
|
||||
Some(id) => match super::song_db::get_song(&pool, &id).await {
|
||||
Ok(song) => {
|
||||
response.message = String::from(super::super::response::SUCCESSFUL);
|
||||
response.data.push(song);
|
||||
(axum::http::StatusCode::OK, axum::Json(response))
|
||||
}
|
||||
Err(err) => {
|
||||
response.message = err.to_string();
|
||||
(axum::http::StatusCode::BAD_REQUEST, axum::Json(response))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
response.message = String::from("Invalid parameters");
|
||||
(axum::http::StatusCode::BAD_REQUEST, axum::Json(response))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn stream_song(
|
||||
axum::Extension(pool): axum::Extension<sqlx::PgPool>,
|
||||
axum::extract::Path(id): axum::extract::Path<uuid::Uuid>,
|
||||
) -> impl IntoResponse {
|
||||
match super::song_db::get_song(&pool, &id).await {
|
||||
Ok(song) => {
|
||||
let song_path = song.song_path().unwrap();
|
||||
let path = std::path::Path::new(&song_path);
|
||||
|
||||
if !path.starts_with(&song.directory) || !path.exists() {
|
||||
return Err((axum::http::StatusCode::NOT_FOUND, "File not found"));
|
||||
}
|
||||
|
||||
let file = match tokio::fs::File::open(&path).await {
|
||||
Ok(file) => file,
|
||||
Err(_) => return Err((axum::http::StatusCode::NOT_FOUND, "File not found")),
|
||||
};
|
||||
|
||||
let file_size = match file.metadata().await {
|
||||
Ok(meta) => meta.len(),
|
||||
Err(_) => {
|
||||
return Err((
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"Could not read file",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let mime = mime_guess::from_path(path).first_or_octet_stream();
|
||||
let stream = tokio_util::io::ReaderStream::new(file);
|
||||
|
||||
let rep = axum::response::Response::builder()
|
||||
.header("content-type", mime.to_string())
|
||||
.header("accept-ranges", "bytes")
|
||||
.header("content-length", file_size.to_string())
|
||||
.body(axum::body::Body::from_stream(stream))
|
||||
.unwrap();
|
||||
|
||||
Ok(rep)
|
||||
}
|
||||
Err(_err) => Err((
|
||||
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"Could not find file",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-232
@@ -115,25 +115,12 @@ pub mod init {
|
||||
crate::callers::endpoints::CREATECOVERART,
|
||||
post(crate::callers::coverart::endpoint::create_coverart),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::GETSONGS,
|
||||
get(crate::callers::song::endpoint::get_songs),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::GETCOVERART,
|
||||
get(crate::callers::coverart::endpoint::get_coverart),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::STREAMSONG,
|
||||
get(crate::callers::song::endpoint::stream_song),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn app() -> axum::Router {
|
||||
let pool = crate::db::create_pool()
|
||||
.await
|
||||
.expect("Failed to create pool");
|
||||
// TODO: Look into handling this. Seems redundant to run migrations multiple times
|
||||
crate::db::migrations(&pool).await;
|
||||
|
||||
routes()
|
||||
@@ -240,15 +227,6 @@ mod tests {
|
||||
Err("Error parsing".into())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn migrations(pool: &sqlx::PgPool) {
|
||||
// Run migrations using the sqlx::migrate! macro
|
||||
// Assumes your test migrations are in a ./test_migrations folder relative to Cargo.toml
|
||||
sqlx::migrate!("./test_migrations")
|
||||
.run(pool)
|
||||
.await
|
||||
.expect("Failed to run migrations");
|
||||
}
|
||||
}
|
||||
|
||||
mod init {
|
||||
@@ -269,7 +247,7 @@ mod tests {
|
||||
) -> Result<axum::response::Response, std::convert::Infallible> {
|
||||
// Create multipart form
|
||||
let mut form = MultipartForm::default();
|
||||
let _ = form.add_file("flac", "tests/I/track01.flac");
|
||||
let _ = form.add_file("flac", "tests/Machine_gun/track01.flac");
|
||||
|
||||
// Create request
|
||||
let content_type = form.content_type();
|
||||
@@ -353,7 +331,7 @@ mod tests {
|
||||
app: &axum::Router,
|
||||
) -> Result<axum::response::Response, std::convert::Infallible> {
|
||||
let mut form = MultipartForm::default();
|
||||
let _ = form.add_file("jpg", "tests/I/Coverart.jpg");
|
||||
let _ = form.add_file("jpg", "tests/Machine_gun/160809_machinegun.jpg");
|
||||
|
||||
// Create request
|
||||
let content_type = form.content_type();
|
||||
@@ -429,7 +407,22 @@ mod tests {
|
||||
song_queue_id: &uuid::Uuid,
|
||||
user_id: &uuid::Uuid,
|
||||
) -> Result<axum::response::Response, std::convert::Infallible> {
|
||||
let payload = payload_data::create_song(song_queue_id, user_id).await;
|
||||
let payload = serde_json::json!({
|
||||
"title": "Power of Soul",
|
||||
"artist": "Jimmi Hendrix",
|
||||
"album_artist": "Jimmi Hendrix",
|
||||
"album": "Machine Gun",
|
||||
"genre": "Psychadelic Rock",
|
||||
"date": "2016-01-01",
|
||||
"track": 1,
|
||||
"disc": 1,
|
||||
"track_count": 11,
|
||||
"disc_count": 1,
|
||||
"duration": 330,
|
||||
"audio_type": "flac",
|
||||
"user_id": user_id,
|
||||
"song_queue_id": song_queue_id
|
||||
});
|
||||
|
||||
let req = axum::http::Request::builder()
|
||||
.method(axum::http::Method::POST)
|
||||
@@ -660,39 +653,17 @@ mod tests {
|
||||
serde_json::json!(
|
||||
{
|
||||
"song_queue_id": song_queue_id,
|
||||
"album" : "I",
|
||||
"album_artist" : "Kuoth",
|
||||
"artist" : "Kuoth",
|
||||
"album" : "Machine Gun: The FillMore East First Show",
|
||||
"album_artist" : "Jimi Hendrix",
|
||||
"artist" : "Jimi Hendrix",
|
||||
"disc" : 1,
|
||||
"disc_count" : 1,
|
||||
"duration" : 139,
|
||||
"genre" : "Alternative Hip-Hop",
|
||||
"title" : "Hypocrite Like The Rest",
|
||||
"duration" : 330,
|
||||
"genre" : "Psychadelic Rock",
|
||||
"title" : "Power of Soul",
|
||||
"track" : 1,
|
||||
"track_count" : 9,
|
||||
"year" : 2020
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn create_song(
|
||||
song_queue_id: &uuid::Uuid,
|
||||
user_id: &uuid::Uuid,
|
||||
) -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"title" : "Hypocrite Like The Rest",
|
||||
"artist" : "Kuoth",
|
||||
"album_artist": "Kuoth",
|
||||
"album": "I",
|
||||
"genre" : "Alternative Hip-Hop",
|
||||
"date": "2020-01-01",
|
||||
"track": 1,
|
||||
"disc": 1,
|
||||
"track_count": 9,
|
||||
"disc_count": 1,
|
||||
"duration": 139,
|
||||
"audio_type": "flac",
|
||||
"user_id": user_id,
|
||||
"song_queue_id": song_queue_id
|
||||
"track_count" : 11,
|
||||
"year" : 2016
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1821,181 +1792,4 @@ mod tests {
|
||||
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
pub mod after_song_queue {
|
||||
use futures::StreamExt;
|
||||
use tower::ServiceExt;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_songs() {
|
||||
let tm_pool = super::db_mgr::get_pool().await.unwrap();
|
||||
let db_name = super::db_mgr::generate_db_name().await;
|
||||
|
||||
match super::db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let pool = super::db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
super::db_mgr::migrations(&pool).await;
|
||||
|
||||
let app = super::init::app(pool).await;
|
||||
|
||||
let id = test_data::song_id().await.unwrap();
|
||||
|
||||
let uri = format!("{}?id={id}", crate::callers::endpoints::GETSONGS);
|
||||
|
||||
match app
|
||||
.clone()
|
||||
.oneshot(
|
||||
axum::http::Request::builder()
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(response) => {
|
||||
let resp = super::get_resp_data::<
|
||||
crate::callers::song::response::get_songs::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
|
||||
let song = resp.data[0].clone();
|
||||
assert_eq!(id, song.id, "Id does not match {song:?}");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {err:?}");
|
||||
}
|
||||
}
|
||||
|
||||
let _ = super::db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_coverart() {
|
||||
let tm_pool = super::db_mgr::get_pool().await.unwrap();
|
||||
let db_name = super::db_mgr::generate_db_name().await;
|
||||
|
||||
match super::db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let pool = super::db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
super::db_mgr::migrations(&pool).await;
|
||||
|
||||
let app = super::init::app(pool).await;
|
||||
|
||||
let id = test_data::coverart_id().await.unwrap();
|
||||
|
||||
let uri = format!("{}?id={id}", crate::callers::endpoints::GETCOVERART);
|
||||
|
||||
match app
|
||||
.clone()
|
||||
.oneshot(
|
||||
axum::http::Request::builder()
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(response) => {
|
||||
let resp = super::get_resp_data::<
|
||||
crate::callers::coverart::response::get_coverart::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
|
||||
let coverart = resp.data[0].clone();
|
||||
assert_eq!(id, coverart.id, "Id does not match {coverart:?}");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {err:?}");
|
||||
}
|
||||
}
|
||||
|
||||
let _ = super::db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
pub mod test_data {
|
||||
pub async fn song_id() -> Result<uuid::Uuid, uuid::Error> {
|
||||
uuid::Uuid::parse_str("44cf7940-34ff-489f-9124-d0ec90a55af9")
|
||||
}
|
||||
|
||||
pub async fn coverart_id() -> Result<uuid::Uuid, uuid::Error> {
|
||||
uuid::Uuid::parse_str("996122cd-5ae9-4013-9934-60768d3006ed")
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_stream_song() {
|
||||
let tm_pool = super::db_mgr::get_pool().await.unwrap();
|
||||
let db_name = super::db_mgr::generate_db_name().await;
|
||||
|
||||
match super::db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let pool = super::db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
super::db_mgr::migrations(&pool).await;
|
||||
|
||||
let app = super::init::app(pool).await;
|
||||
|
||||
let id = test_data::song_id().await.unwrap();
|
||||
|
||||
let my_url = crate::callers::endpoints::STREAMSONG;
|
||||
let last = my_url.len() - 5;
|
||||
let uri = format!("{}/{id}", &my_url[0..last]);
|
||||
|
||||
match app
|
||||
.clone()
|
||||
.oneshot(
|
||||
axum::http::Request::builder()
|
||||
.method(axum::http::Method::GET)
|
||||
.uri(&uri)
|
||||
.body(axum::body::Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(response) => {
|
||||
let e = response.into_body();
|
||||
let mut data = e.into_data_stream();
|
||||
while let Some(chunk) = data.next().await {
|
||||
match chunk {
|
||||
Ok(_data) => {}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {err:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {err:?}");
|
||||
}
|
||||
}
|
||||
|
||||
let _ = super::db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
-- Add migration script here
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
|
||||
-- Table to store queued songs to process
|
||||
CREATE TABLE IF NOT EXISTS "songQueue" (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
filename TEXT NOT NULL,
|
||||
status TEXT CHECK (status IN ('pending', 'ready', 'processing', 'done')),
|
||||
data BYTEA NULL,
|
||||
user_id UUID NULL
|
||||
);
|
||||
|
||||
-- Table to store queued metadata
|
||||
CREATE TABLE IF NOT EXISTS "metadataQueue" (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
metadata jsonb NOT NULL,
|
||||
created_at timestamptz DEFAULT now(),
|
||||
song_queue_id UUID NOT NULL
|
||||
);
|
||||
|
||||
-- Table to store queued coverart
|
||||
CREATE TABLE IF NOT EXISTS "coverartQueue" (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
data BYTEA NULL,
|
||||
song_queue_id UUID NULL
|
||||
);
|
||||
|
||||
-- Create an index for better query performance
|
||||
CREATE INDEX metadata_queue_data_metadata ON "metadataQueue" USING gin (metadata);
|
||||
|
||||
-- Table to store a song's info
|
||||
CREATE TABLE IF NOT EXISTS "song" (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
title TEXT NOT NULL,
|
||||
artist TEXT NOT NULL,
|
||||
album_artist TEXT NOT NULL,
|
||||
album TEXT NOT NULL,
|
||||
genre TEXT NOT NULL,
|
||||
year INT NOT NULL,
|
||||
track INT NOT NULL,
|
||||
disc INT NOT NULL,
|
||||
track_count INT NOT NULL,
|
||||
disc_count INT NOT NULL,
|
||||
duration INT NOT NULL,
|
||||
audio_type TEXT NOT NULL,
|
||||
date_created timestamptz DEFAULT now(),
|
||||
filename TEXT NOT NULL,
|
||||
directory TEXT NOT NULL,
|
||||
user_id UUID NULL
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "coverart" (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
title TEXT NOT NULL,
|
||||
path TEXT NOT NULL,
|
||||
song_id UUID NOT NULL
|
||||
);
|
||||
@@ -1,3 +0,0 @@
|
||||
-- Add migration script here
|
||||
INSERT INTO "song" (id, title, artist, album_artist, album, genre, year, track, disc, track_count, disc_count, duration, audio_type, date_created, filename, directory, user_id) VALUES('44cf7940-34ff-489f-9124-d0ec90a55af9', 'Hypocrite Like The Rest', 'Kuoth', 'Kuoth', 'I', 'Alternative Hip-Hop', 2020, 1, 1, 9, 1, 139, 'flac', '2020-01-01 13:00:00-05', 'track01.flac', 'tests/I', '47491f9b-725a-4ba4-b9a5-711e1be46670');
|
||||
INSERT INTO "coverart" VALUES('996122cd-5ae9-4013-9934-60768d3006ed', 'I', 'tests/I/Coverart.jpg', '44cf7940-34ff-489f-9124-d0ec90a55af9');
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 MiB |
@@ -1,73 +0,0 @@
|
||||
{
|
||||
"album": "I",
|
||||
"album_artist": "Kuoth",
|
||||
"disc_count": 1,
|
||||
"genre": "Alternative Hip-Hop",
|
||||
"year": 2020,
|
||||
"track_count": 9,
|
||||
"tracks": [
|
||||
{
|
||||
"artist": "Kuoth",
|
||||
"disc": 1,
|
||||
"title": "Hypocrite Like the Rest",
|
||||
"duration": 139,
|
||||
"track": 1
|
||||
},
|
||||
{
|
||||
"artist": "Kuoth",
|
||||
"disc": 1,
|
||||
"title": "It's Too Late",
|
||||
"duration": 116,
|
||||
"track": 2
|
||||
},
|
||||
{
|
||||
"artist": "Kuoth",
|
||||
"disc": 1,
|
||||
"title": "Hell Might be Nice",
|
||||
"duration": 229,
|
||||
"track": 3
|
||||
},
|
||||
{
|
||||
"artist": "Kuoth",
|
||||
"disc": 1,
|
||||
"title": "Dark Side of Progress",
|
||||
"duration": 187,
|
||||
"track": 4
|
||||
},
|
||||
{
|
||||
"artist": "Kuoth",
|
||||
"disc": 1,
|
||||
"title": "Distractions",
|
||||
"duration": 141,
|
||||
"track": 5
|
||||
},
|
||||
{
|
||||
"artist": "Kuoth",
|
||||
"disc": 1,
|
||||
"title": "But You Won't Listen",
|
||||
"duration": 184,
|
||||
"track": 6
|
||||
},
|
||||
{
|
||||
"artist": "Kuoth",
|
||||
"disc": 1,
|
||||
"title": "Guidance",
|
||||
"duration": 121,
|
||||
"track": 7
|
||||
},
|
||||
{
|
||||
"artist": "Kuoth",
|
||||
"disc": 1,
|
||||
"title": "M",
|
||||
"duration": 98,
|
||||
"track": 8
|
||||
},
|
||||
{
|
||||
"artist": "Kuoth",
|
||||
"disc": 1,
|
||||
"title": "Social Acceptance",
|
||||
"duration": 169,
|
||||
"track": 9
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 271 KiB |
Binary file not shown.
Reference in New Issue
Block a user