refactor: app -> rave; and some other poking
This commit is contained in:
parent
7198eda4ee
commit
b18d0dd747
29 changed files with 453 additions and 51 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["app", "entities", "migration"]
|
members = ["rave", "entities", "migration"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
use crate::{
|
|
||||||
authentication::Authentication,
|
|
||||||
subsonic::SubsonicResponse,
|
|
||||||
utils::{self},
|
|
||||||
};
|
|
||||||
|
|
||||||
use poem::web::{Data, Query};
|
|
||||||
use poem_ext::db::DbTxn;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
#[poem::handler]
|
|
||||||
pub async fn get_album(
|
|
||||||
Data(txn): Data<&DbTxn>,
|
|
||||||
auth: Authentication,
|
|
||||||
Query(params): Query<GetAlbumParams>,
|
|
||||||
) -> SubsonicResponse {
|
|
||||||
let u = utils::verify_user(txn.clone(), auth).await;
|
|
||||||
|
|
||||||
match u {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => return e,
|
|
||||||
}
|
|
||||||
|
|
||||||
todo!("get_album not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
|
||||||
pub struct GetAlbumParams {
|
|
||||||
pub id: i32,
|
|
||||||
}
|
|
||||||
|
|
@ -9,9 +9,8 @@ pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub artist: Option<String>,
|
|
||||||
pub artist_id: Option<i64>,
|
pub artist_id: Option<i64>,
|
||||||
pub cover_art: Option<String>,
|
pub cover_art_id: Option<i64>,
|
||||||
pub song_count: i32,
|
pub song_count: i32,
|
||||||
pub duration: i64,
|
pub duration: i64,
|
||||||
pub play_count: i64,
|
pub play_count: i64,
|
||||||
|
|
@ -32,6 +31,14 @@ pub enum Relation {
|
||||||
on_delete = "SetNull"
|
on_delete = "SetNull"
|
||||||
)]
|
)]
|
||||||
Artist,
|
Artist,
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::cover_art::Entity",
|
||||||
|
from = "Column::CoverArtId",
|
||||||
|
to = "super::cover_art::Column::Id",
|
||||||
|
on_update = "NoAction",
|
||||||
|
on_delete = "SetNull"
|
||||||
|
)]
|
||||||
|
CoverArt,
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
belongs_to = "super::music_folder::Entity",
|
belongs_to = "super::music_folder::Entity",
|
||||||
from = "Column::MusicFolderId",
|
from = "Column::MusicFolderId",
|
||||||
|
|
@ -40,6 +47,8 @@ pub enum Relation {
|
||||||
on_delete = "Cascade"
|
on_delete = "Cascade"
|
||||||
)]
|
)]
|
||||||
MusicFolder,
|
MusicFolder,
|
||||||
|
#[sea_orm(has_many = "super::track::Entity")]
|
||||||
|
Track,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::artist::Entity> for Entity {
|
impl Related<super::artist::Entity> for Entity {
|
||||||
|
|
@ -48,10 +57,22 @@ impl Related<super::artist::Entity> for Entity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Related<super::cover_art::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::CoverArt.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Related<super::music_folder::Entity> for Entity {
|
impl Related<super::music_folder::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::MusicFolder.def()
|
Relation::MusicFolder.def()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Related<super::track::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Track.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ pub struct Model {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
#[sea_orm(unique)]
|
#[sea_orm(unique)]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub cover_art: Option<String>,
|
pub cover_art_id: Option<i64>,
|
||||||
pub artist_image_url: Option<String>,
|
pub artist_image_url: Option<String>,
|
||||||
pub album_count: i32,
|
pub album_count: i32,
|
||||||
pub starred: bool,
|
pub starred: bool,
|
||||||
|
|
@ -20,6 +20,16 @@ pub struct Model {
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
#[sea_orm(has_many = "super::album::Entity")]
|
#[sea_orm(has_many = "super::album::Entity")]
|
||||||
Album,
|
Album,
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::cover_art::Entity",
|
||||||
|
from = "Column::CoverArtId",
|
||||||
|
to = "super::cover_art::Column::Id",
|
||||||
|
on_update = "NoAction",
|
||||||
|
on_delete = "SetNull"
|
||||||
|
)]
|
||||||
|
CoverArt,
|
||||||
|
#[sea_orm(has_many = "super::track::Entity")]
|
||||||
|
Track,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::album::Entity> for Entity {
|
impl Related<super::album::Entity> for Entity {
|
||||||
|
|
@ -28,4 +38,16 @@ impl Related<super::album::Entity> for Entity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Related<super::cover_art::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::CoverArt.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::track::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Track.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
|
||||||
42
entities/src/cover_art.rs
Normal file
42
entities/src/cover_art.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
|
||||||
|
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||||
|
#[sea_orm(table_name = "cover_art")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub id: i32,
|
||||||
|
pub path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {
|
||||||
|
#[sea_orm(has_many = "super::album::Entity")]
|
||||||
|
Album,
|
||||||
|
#[sea_orm(has_many = "super::artist::Entity")]
|
||||||
|
Artist,
|
||||||
|
#[sea_orm(has_many = "super::track::Entity")]
|
||||||
|
Track,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::album::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Album.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::artist::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Artist.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::track::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Track.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
@ -4,5 +4,7 @@ pub mod prelude;
|
||||||
|
|
||||||
pub mod album;
|
pub mod album;
|
||||||
pub mod artist;
|
pub mod artist;
|
||||||
|
pub mod cover_art;
|
||||||
pub mod music_folder;
|
pub mod music_folder;
|
||||||
|
pub mod track;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,7 @@
|
||||||
|
|
||||||
pub use super::album::Entity as Album;
|
pub use super::album::Entity as Album;
|
||||||
pub use super::artist::Entity as Artist;
|
pub use super::artist::Entity as Artist;
|
||||||
|
pub use super::cover_art::Entity as CoverArt;
|
||||||
pub use super::music_folder::Entity as MusicFolder;
|
pub use super::music_folder::Entity as MusicFolder;
|
||||||
|
pub use super::track::Entity as Track;
|
||||||
pub use super::user::Entity as User;
|
pub use super::user::Entity as User;
|
||||||
|
|
|
||||||
72
entities/src/track.rs
Normal file
72
entities/src/track.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.3
|
||||||
|
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||||
|
#[sea_orm(table_name = "track")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub id: i64,
|
||||||
|
pub title: String,
|
||||||
|
pub album_id: Option<i64>,
|
||||||
|
pub artist_id: Option<i64>,
|
||||||
|
pub is_dir: bool,
|
||||||
|
pub cover_art_id: Option<i64>,
|
||||||
|
pub created: DateTimeWithTimeZone,
|
||||||
|
pub duration: i64,
|
||||||
|
pub bit_rate: i64,
|
||||||
|
pub size: i64,
|
||||||
|
pub suffix: String,
|
||||||
|
pub content_type: String,
|
||||||
|
pub is_video: bool,
|
||||||
|
pub path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::album::Entity",
|
||||||
|
from = "Column::AlbumId",
|
||||||
|
to = "super::album::Column::Id",
|
||||||
|
on_update = "Cascade",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
|
Album,
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::artist::Entity",
|
||||||
|
from = "Column::ArtistId",
|
||||||
|
to = "super::artist::Column::Id",
|
||||||
|
on_update = "Cascade",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
|
Artist,
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::cover_art::Entity",
|
||||||
|
from = "Column::CoverArtId",
|
||||||
|
to = "super::cover_art::Column::Id",
|
||||||
|
on_update = "Cascade",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
|
CoverArt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::album::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Album.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::artist::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Artist.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::cover_art::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::CoverArt.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
@ -2,8 +2,10 @@ pub use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
mod m20220101_000001_create_user;
|
mod m20220101_000001_create_user;
|
||||||
mod m20231009_181004_create_music_folder;
|
mod m20231009_181004_create_music_folder;
|
||||||
mod m20231009_181104_create_artist;
|
mod m20231009_181104_create_cover_art;
|
||||||
|
mod m20231009_181204_create_artist;
|
||||||
mod m20231009_181346_create_album;
|
mod m20231009_181346_create_album;
|
||||||
|
mod m20231009_185712_create_track;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
|
|
@ -13,8 +15,10 @@ impl MigratorTrait for Migrator {
|
||||||
vec![
|
vec![
|
||||||
Box::new(m20220101_000001_create_user::Migration),
|
Box::new(m20220101_000001_create_user::Migration),
|
||||||
Box::new(m20231009_181004_create_music_folder::Migration),
|
Box::new(m20231009_181004_create_music_folder::Migration),
|
||||||
Box::new(m20231009_181104_create_artist::Migration),
|
Box::new(m20231009_181104_create_cover_art::Migration),
|
||||||
|
Box::new(m20231009_181204_create_artist::Migration),
|
||||||
Box::new(m20231009_181346_create_album::Migration),
|
Box::new(m20231009_181346_create_album::Migration),
|
||||||
|
Box::new(m20231009_185712_create_track::Migration),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
40
migration/src/m20231009_181104_create_cover_art.rs
Normal file
40
migration/src/m20231009_181104_create_cover_art.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(CoverArt::Table)
|
||||||
|
.if_not_exists()
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(CoverArt::Id)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.auto_increment()
|
||||||
|
.primary_key()
|
||||||
|
.unique_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(CoverArt::Path).string().not_null())
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(CoverArt::Table).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DeriveIden)]
|
||||||
|
pub enum CoverArt {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
Path,
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use sea_orm_migration::prelude::*;
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
use crate::m20231009_181104_create_cover_art::CoverArt;
|
||||||
|
|
||||||
#[derive(DeriveMigrationName)]
|
#[derive(DeriveMigrationName)]
|
||||||
pub struct Migration;
|
pub struct Migration;
|
||||||
|
|
||||||
|
|
@ -25,7 +27,7 @@ impl MigrationTrait for Migration {
|
||||||
.not_null()
|
.not_null()
|
||||||
.unique_key(),
|
.unique_key(),
|
||||||
)
|
)
|
||||||
.col(ColumnDef::new(Artist::CoverArt).string().null())
|
.col(ColumnDef::new(Artist::CoverArtId).big_integer().null())
|
||||||
.col(ColumnDef::new(Artist::ArtistImageUrl).string().null())
|
.col(ColumnDef::new(Artist::ArtistImageUrl).string().null())
|
||||||
.col(
|
.col(
|
||||||
ColumnDef::new(Artist::AlbumCount)
|
ColumnDef::new(Artist::AlbumCount)
|
||||||
|
|
@ -41,7 +43,21 @@ impl MigrationTrait for Migration {
|
||||||
)
|
)
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
|
|
||||||
|
manager
|
||||||
|
.create_foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.from_tbl(Artist::Table)
|
||||||
|
.from_col(Artist::CoverArtId)
|
||||||
|
.to_tbl(CoverArt::Table)
|
||||||
|
.to_col(CoverArt::Id)
|
||||||
|
.on_delete(ForeignKeyAction::SetNull)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
|
@ -56,7 +72,7 @@ pub enum Artist {
|
||||||
Table,
|
Table,
|
||||||
Id,
|
Id,
|
||||||
Name,
|
Name,
|
||||||
CoverArt,
|
CoverArtId,
|
||||||
ArtistImageUrl,
|
ArtistImageUrl,
|
||||||
AlbumCount,
|
AlbumCount,
|
||||||
Starred,
|
Starred,
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use sea_orm_migration::prelude::*;
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
m20231009_181004_create_music_folder::MusicFolder, m20231009_181104_create_artist::Artist,
|
m20231009_181004_create_music_folder::MusicFolder, m20231009_181104_create_cover_art::CoverArt,
|
||||||
|
m20231009_181204_create_artist::Artist,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(DeriveMigrationName)]
|
#[derive(DeriveMigrationName)]
|
||||||
|
|
@ -23,9 +24,8 @@ impl MigrationTrait for Migration {
|
||||||
.primary_key(),
|
.primary_key(),
|
||||||
)
|
)
|
||||||
.col(ColumnDef::new(Album::Name).string().not_null())
|
.col(ColumnDef::new(Album::Name).string().not_null())
|
||||||
.col(ColumnDef::new(Album::Artist).string().null())
|
|
||||||
.col(ColumnDef::new(Album::ArtistId).big_integer().null())
|
.col(ColumnDef::new(Album::ArtistId).big_integer().null())
|
||||||
.col(ColumnDef::new(Album::CoverArt).string().null())
|
.col(ColumnDef::new(Album::CoverArtId).big_integer().null())
|
||||||
.col(ColumnDef::new(Album::SongCount).integer().not_null())
|
.col(ColumnDef::new(Album::SongCount).integer().not_null())
|
||||||
.col(ColumnDef::new(Album::Duration).big_integer().not_null())
|
.col(ColumnDef::new(Album::Duration).big_integer().not_null())
|
||||||
.col(
|
.col(
|
||||||
|
|
@ -75,6 +75,18 @@ impl MigrationTrait for Migration {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
manager
|
||||||
|
.create_foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.from_tbl(Album::Table)
|
||||||
|
.from_col(Album::CoverArtId)
|
||||||
|
.to_tbl(CoverArt::Table)
|
||||||
|
.to_col(CoverArt::Id)
|
||||||
|
.on_delete(ForeignKeyAction::SetNull)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,9 +102,8 @@ pub enum Album {
|
||||||
Table,
|
Table,
|
||||||
Id,
|
Id,
|
||||||
Name,
|
Name,
|
||||||
Artist,
|
|
||||||
ArtistId,
|
ArtistId,
|
||||||
CoverArt,
|
CoverArtId,
|
||||||
SongCount,
|
SongCount,
|
||||||
Duration,
|
Duration,
|
||||||
PlayCount,
|
PlayCount,
|
||||||
|
|
|
||||||
124
migration/src/m20231009_185712_create_track.rs
Normal file
124
migration/src/m20231009_185712_create_track.rs
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
m20231009_181104_create_cover_art::CoverArt, m20231009_181204_create_artist::Artist,
|
||||||
|
m20231009_181346_create_album::Album,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(Track::Table)
|
||||||
|
.if_not_exists()
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(Track::Id)
|
||||||
|
.big_integer()
|
||||||
|
.not_null()
|
||||||
|
.auto_increment()
|
||||||
|
.primary_key()
|
||||||
|
.unique_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(Track::Title).string().not_null())
|
||||||
|
.col(ColumnDef::new(Track::AlbumId).big_integer().null())
|
||||||
|
.col(ColumnDef::new(Track::ArtistId).big_integer().null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(Track::IsDir)
|
||||||
|
.boolean()
|
||||||
|
.not_null()
|
||||||
|
.default(false),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(Track::CoverArtId).big_integer().null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(Track::Created)
|
||||||
|
.timestamp_with_time_zone()
|
||||||
|
.not_null(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(Track::Duration).big_integer().not_null())
|
||||||
|
.col(ColumnDef::new(Track::BitRate).big_integer().not_null())
|
||||||
|
.col(ColumnDef::new(Track::Size).big_integer().not_null())
|
||||||
|
.col(ColumnDef::new(Track::Suffix).string().not_null())
|
||||||
|
.col(ColumnDef::new(Track::ContentType).string().not_null())
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(Track::IsVideo)
|
||||||
|
.boolean()
|
||||||
|
.not_null()
|
||||||
|
.default(false),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(Track::Path).string().not_null())
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
manager
|
||||||
|
.create_foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.from_tbl(Track::Table)
|
||||||
|
.from_col(Track::AlbumId)
|
||||||
|
.to_tbl(Album::Table)
|
||||||
|
.to_col(Album::Id)
|
||||||
|
.on_delete(ForeignKeyAction::Cascade)
|
||||||
|
.on_update(ForeignKeyAction::Cascade)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
manager
|
||||||
|
.create_foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.from_tbl(Track::Table)
|
||||||
|
.from_col(Track::ArtistId)
|
||||||
|
.to_tbl(Artist::Table)
|
||||||
|
.to_col(Artist::Id)
|
||||||
|
.on_delete(ForeignKeyAction::Cascade)
|
||||||
|
.on_update(ForeignKeyAction::Cascade)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
manager
|
||||||
|
.create_foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.from_tbl(Track::Table)
|
||||||
|
.from_col(Track::CoverArtId)
|
||||||
|
.to_tbl(CoverArt::Table)
|
||||||
|
.to_col(CoverArt::Id)
|
||||||
|
.on_delete(ForeignKeyAction::Cascade)
|
||||||
|
.on_update(ForeignKeyAction::Cascade)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(Track::Table).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DeriveIden)]
|
||||||
|
pub enum Track {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
Title,
|
||||||
|
AlbumId,
|
||||||
|
ArtistId,
|
||||||
|
IsDir,
|
||||||
|
CoverArtId,
|
||||||
|
Created,
|
||||||
|
Duration,
|
||||||
|
BitRate,
|
||||||
|
Size,
|
||||||
|
Suffix,
|
||||||
|
ContentType,
|
||||||
|
IsVideo,
|
||||||
|
Path,
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ name = "rave"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
publish = ["forge-lys-ee"]
|
publish = ["forge-lys-ee"]
|
||||||
|
default-run = "rave"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
56
rave/src/rest/get_album.rs
Normal file
56
rave/src/rest/get_album.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
use crate::{
|
||||||
|
authentication::Authentication,
|
||||||
|
subsonic::{Error, SubsonicResponse},
|
||||||
|
utils,
|
||||||
|
};
|
||||||
|
|
||||||
|
use entities::prelude::{Album, Track};
|
||||||
|
use poem::web::{Data, Query};
|
||||||
|
use poem_ext::db::DbTxn;
|
||||||
|
use sea_orm::{EntityTrait, ModelTrait};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
|
#[poem::handler]
|
||||||
|
pub async fn get_album(
|
||||||
|
Data(txn): Data<&DbTxn>,
|
||||||
|
auth: Authentication,
|
||||||
|
Query(params): Query<GetAlbumParams>,
|
||||||
|
) -> SubsonicResponse {
|
||||||
|
let txn = txn.clone();
|
||||||
|
let u = utils::verify_user(txn.clone(), auth).await;
|
||||||
|
|
||||||
|
match u {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => return e,
|
||||||
|
}
|
||||||
|
|
||||||
|
let album = Album::find_by_id(params.id).one(&*txn).await;
|
||||||
|
let Ok(Some(album)) = album else {
|
||||||
|
match album {
|
||||||
|
Ok(Some(_)) => unreachable!("Some(album) covered by `let .. else`"),
|
||||||
|
Ok(None) => return SubsonicResponse::new_error(Error::RequestedDataWasNotFound(None)),
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Error getting album: {}", e);
|
||||||
|
return SubsonicResponse::new_error(Error::Generic(None));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let tracks = album.find_related(Track).all(&*txn).await;
|
||||||
|
|
||||||
|
let tracks = match tracks {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Error getting tracks: {}", e);
|
||||||
|
return SubsonicResponse::new_error(Error::Generic(None));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SubsonicResponse::new_album(album, tracks)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
|
pub struct GetAlbumParams {
|
||||||
|
pub id: i32,
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,17 @@
|
||||||
#![allow(clippy::unused_async)] // todo: remove
|
#![allow(clippy::unused_async)] // todo: remove
|
||||||
|
|
||||||
use entities::{album, prelude::Album};
|
use entities::{
|
||||||
use poem::web::{Data, Query};
|
album, artist,
|
||||||
|
prelude::{Album, Artist},
|
||||||
|
};
|
||||||
|
use poem::{
|
||||||
|
web::{Data, Query},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
use poem_ext::db::DbTxn;
|
use poem_ext::db::DbTxn;
|
||||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect};
|
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
authentication::Authentication,
|
authentication::Authentication,
|
||||||
|
|
@ -24,6 +31,7 @@ macro_rules! error_or {
|
||||||
|
|
||||||
#[poem::handler]
|
#[poem::handler]
|
||||||
pub async fn get_album_list(
|
pub async fn get_album_list(
|
||||||
|
req: &Request,
|
||||||
Data(txn): Data<&DbTxn>,
|
Data(txn): Data<&DbTxn>,
|
||||||
auth: Authentication,
|
auth: Authentication,
|
||||||
Query(params): Query<GetAlbumListParams>,
|
Query(params): Query<GetAlbumListParams>,
|
||||||
|
|
@ -55,7 +63,14 @@ pub async fn get_album_list(
|
||||||
};
|
};
|
||||||
|
|
||||||
match album_list {
|
match album_list {
|
||||||
Ok(a) => SubsonicResponse::new_album_list(a),
|
Ok(a) => {
|
||||||
|
debug!("uri path: {}", req.uri().path());
|
||||||
|
if req.uri().path().contains("getAlbumList2") {
|
||||||
|
SubsonicResponse::new_album_list2(a)
|
||||||
|
} else {
|
||||||
|
SubsonicResponse::new_album_list(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(e) => SubsonicResponse::new_error(e),
|
Err(e) => SubsonicResponse::new_error(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -141,12 +156,16 @@ async fn get_album_list_alphabetical_by_artist(
|
||||||
params: GetAlbumListParams,
|
params: GetAlbumListParams,
|
||||||
) -> Result<Vec<album::Model>, Error> {
|
) -> Result<Vec<album::Model>, Error> {
|
||||||
let albums = Album::find()
|
let albums = Album::find()
|
||||||
.order_by_desc(album::Column::Artist)
|
.filter(album::Column::ArtistId.is_not_null())
|
||||||
|
.find_also_related(Artist)
|
||||||
|
.order_by_desc(artist::Column::Name)
|
||||||
.limit(params.size)
|
.limit(params.size)
|
||||||
.offset(params.offset)
|
.offset(params.offset)
|
||||||
.all(&*conn)
|
.all(&*conn)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
let albums = albums.map(|c| c.into_iter().map(|c| c.0).collect());
|
||||||
|
|
||||||
error_or!(albums)
|
error_or!(albums)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use entities::album;
|
use entities::{album, track};
|
||||||
use poem::{http::StatusCode, IntoResponse, Response};
|
use poem::{http::StatusCode, IntoResponse, Response};
|
||||||
use serde::{ser::SerializeStruct, Serialize};
|
use serde::{ser::SerializeStruct, Serialize};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
@ -51,7 +51,7 @@ impl SubsonicResponse {
|
||||||
Self::new(SubResponseType::AlbumList2 { albums })
|
Self::new(SubResponseType::AlbumList2 { albums })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_album(album: album::Model, songs: Vec<Child>) -> Self {
|
pub fn new_album(album: album::Model, songs: Vec<track::Model>) -> Self {
|
||||||
Self::new(SubResponseType::Album { album, songs })
|
Self::new(SubResponseType::Album { album, songs })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,7 +98,7 @@ pub enum SubResponseType {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
album: album::Model,
|
album: album::Model,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
songs: Vec<Child>,
|
songs: Vec<track::Model>,
|
||||||
},
|
},
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue