Implements get_album endpoint
This commit is contained in:
parent
b42c6d39e8
commit
332e39876e
6 changed files with 46 additions and 7 deletions
|
@ -65,6 +65,17 @@ impl IndexManager {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_album(
|
||||||
|
&self,
|
||||||
|
album_key: &AlbumKey,
|
||||||
|
) -> Result<collection::Album, collection::Error> {
|
||||||
|
let index = self.index.read().await;
|
||||||
|
let album_id = album_key.into();
|
||||||
|
index
|
||||||
|
.get_album(album_id)
|
||||||
|
.ok_or_else(|| collection::Error::AlbumNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_random_albums(
|
pub async fn get_random_albums(
|
||||||
&self,
|
&self,
|
||||||
count: usize,
|
count: usize,
|
||||||
|
@ -134,7 +145,7 @@ impl IndexBuilder {
|
||||||
|
|
||||||
if !song.album_artists.0.is_empty() {
|
if !song.album_artists.0.is_empty() {
|
||||||
album.artists = song.album_artists.0.clone();
|
album.artists = song.album_artists.0.clone();
|
||||||
} else if !song.album_artists.0.is_empty() {
|
} else if !song.artists.0.is_empty() {
|
||||||
album.artists = song.artists.0.clone();
|
album.artists = song.artists.0.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,15 +177,17 @@ pub(super) struct Index {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index {
|
impl Index {
|
||||||
pub fn get_album(&self, album_id: AlbumID) -> Option<collection::Album> {
|
pub(self) fn get_album(&self, album_id: AlbumID) -> Option<collection::Album> {
|
||||||
self.albums.get(&album_id).map(|a| {
|
self.albums.get(&album_id).map(|a| {
|
||||||
let songs = a
|
let mut songs = a
|
||||||
.songs
|
.songs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|s| self.songs.get(s))
|
.filter_map(|s| self.songs.get(s))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
songs.sort_by_key(|s| (s.disc_number.unwrap_or(-1), s.track_number.unwrap_or(-1)));
|
||||||
|
|
||||||
collection::Album {
|
collection::Album {
|
||||||
name: a.name.clone(),
|
name: a.name.clone(),
|
||||||
artwork: a.artwork.clone(),
|
artwork: a.artwork.clone(),
|
||||||
|
@ -188,7 +201,7 @@ impl Index {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct SongID(u64);
|
struct SongID(u64);
|
||||||
|
|
||||||
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct SongKey {
|
pub struct SongKey {
|
||||||
|
@ -227,10 +240,10 @@ struct Album {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct AlbumID(u64);
|
struct AlbumID(u64);
|
||||||
|
|
||||||
#[derive(Clone, Eq, Hash, PartialEq)]
|
#[derive(Clone, Eq, Hash, PartialEq)]
|
||||||
struct AlbumKey {
|
pub struct AlbumKey {
|
||||||
pub artists: Vec<String>,
|
pub artists: Vec<String>,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ impl From<Option<String>> for MultiString {
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Directory not found: {0}")]
|
#[error("Directory not found: {0}")]
|
||||||
DirectoryNotFound(PathBuf),
|
DirectoryNotFound(PathBuf),
|
||||||
|
#[error("Album not found")]
|
||||||
|
AlbumNotFound,
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Database(#[from] sqlx::Error),
|
Database(#[from] sqlx::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
|
@ -25,6 +25,7 @@ impl TryFrom<i32> for APIMajorVersion {
|
||||||
|
|
||||||
pub const API_MAJOR_VERSION: i32 = 8;
|
pub const API_MAJOR_VERSION: i32 = 8;
|
||||||
pub const API_MINOR_VERSION: i32 = 0;
|
pub const API_MINOR_VERSION: i32 = 0;
|
||||||
|
pub const API_ARRAY_SEPARATOR: &'static str = "\u{000C}";
|
||||||
|
|
||||||
mod axum;
|
mod axum;
|
||||||
pub use axum::*;
|
pub use axum::*;
|
||||||
|
|
|
@ -12,7 +12,10 @@ use percent_encoding::percent_decode_str;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{collection, config, ddns, lastfm, playlist, settings, thumbnail, user, vfs, App},
|
app::{collection, config, ddns, lastfm, playlist, settings, thumbnail, user, vfs, App},
|
||||||
server::{dto, error::APIError, APIMajorVersion, API_MAJOR_VERSION, API_MINOR_VERSION},
|
server::{
|
||||||
|
dto, error::APIError, APIMajorVersion, API_ARRAY_SEPARATOR, API_MAJOR_VERSION,
|
||||||
|
API_MINOR_VERSION,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::auth::{AdminRights, Auth};
|
use super::auth::{AdminRights, Auth};
|
||||||
|
@ -40,6 +43,7 @@ pub fn router() -> Router<App> {
|
||||||
.route("/browse/*path", get(get_browse))
|
.route("/browse/*path", get(get_browse))
|
||||||
.route("/flatten", get(get_flatten_root))
|
.route("/flatten", get(get_flatten_root))
|
||||||
.route("/flatten/*path", get(get_flatten))
|
.route("/flatten/*path", get(get_flatten))
|
||||||
|
.route("/artists/:artists/albums/:name", get(get_album))
|
||||||
.route("/random", get(get_random))
|
.route("/random", get(get_random))
|
||||||
.route("/recent", get(get_recent))
|
.route("/recent", get(get_recent))
|
||||||
.route("/search", get(get_search_root))
|
.route("/search", get(get_search_root))
|
||||||
|
@ -365,6 +369,21 @@ async fn get_flatten(
|
||||||
songs_to_response(songs, api_version)
|
songs_to_response(songs, api_version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_album(
|
||||||
|
_auth: Auth,
|
||||||
|
State(index_manager): State<collection::IndexManager>,
|
||||||
|
Path((artists, name)): Path<(String, String)>,
|
||||||
|
) -> Result<Json<dto::Album>, APIError> {
|
||||||
|
let album_key = collection::AlbumKey {
|
||||||
|
artists: artists
|
||||||
|
.split(API_ARRAY_SEPARATOR)
|
||||||
|
.map(str::to_owned)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
name: (!name.is_empty()).then_some(name),
|
||||||
|
};
|
||||||
|
Ok(Json(index_manager.get_album(&album_key).await?.into()))
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_random(
|
async fn get_random(
|
||||||
_auth: Auth,
|
_auth: Auth,
|
||||||
api_version: APIMajorVersion,
|
api_version: APIMajorVersion,
|
||||||
|
|
|
@ -21,6 +21,7 @@ impl IntoResponse for APIError {
|
||||||
APIError::Database(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
APIError::Database(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
APIError::DeletingOwnAccount => StatusCode::CONFLICT,
|
APIError::DeletingOwnAccount => StatusCode::CONFLICT,
|
||||||
APIError::DirectoryNotFound(_) => StatusCode::NOT_FOUND,
|
APIError::DirectoryNotFound(_) => StatusCode::NOT_FOUND,
|
||||||
|
APIError::AlbumNotFound => StatusCode::NOT_FOUND,
|
||||||
APIError::EmbeddedArtworkNotFound => StatusCode::NOT_FOUND,
|
APIError::EmbeddedArtworkNotFound => StatusCode::NOT_FOUND,
|
||||||
APIError::EmptyPassword => StatusCode::BAD_REQUEST,
|
APIError::EmptyPassword => StatusCode::BAD_REQUEST,
|
||||||
APIError::EmptyUsername => StatusCode::BAD_REQUEST,
|
APIError::EmptyUsername => StatusCode::BAD_REQUEST,
|
||||||
|
|
|
@ -26,6 +26,8 @@ pub enum APIError {
|
||||||
Database(sqlx::Error),
|
Database(sqlx::Error),
|
||||||
#[error("Directory not found: {0}")]
|
#[error("Directory not found: {0}")]
|
||||||
DirectoryNotFound(PathBuf),
|
DirectoryNotFound(PathBuf),
|
||||||
|
#[error("Album not found")]
|
||||||
|
AlbumNotFound,
|
||||||
#[error("DDNS update query failed with HTTP status {0}")]
|
#[error("DDNS update query failed with HTTP status {0}")]
|
||||||
DdnsUpdateQueryFailed(u16),
|
DdnsUpdateQueryFailed(u16),
|
||||||
#[error("Cannot delete your own account")]
|
#[error("Cannot delete your own account")]
|
||||||
|
@ -86,6 +88,7 @@ impl From<collection::Error> for APIError {
|
||||||
fn from(error: collection::Error) -> APIError {
|
fn from(error: collection::Error) -> APIError {
|
||||||
match error {
|
match error {
|
||||||
collection::Error::DirectoryNotFound(d) => APIError::DirectoryNotFound(d),
|
collection::Error::DirectoryNotFound(d) => APIError::DirectoryNotFound(d),
|
||||||
|
collection::Error::AlbumNotFound => APIError::AlbumNotFound,
|
||||||
collection::Error::Database(e) => APIError::Database(e),
|
collection::Error::Database(e) => APIError::Database(e),
|
||||||
collection::Error::DatabaseConnection(e) => e.into(),
|
collection::Error::DatabaseConnection(e) => e.into(),
|
||||||
collection::Error::Vfs(e) => e.into(),
|
collection::Error::Vfs(e) => e.into(),
|
||||||
|
|
Loading…
Add table
Reference in a new issue