Implements get_album endpoint

This commit is contained in:
Antoine Gersant 2024-07-30 00:24:25 -07:00
parent b42c6d39e8
commit 332e39876e
6 changed files with 46 additions and 7 deletions

View file

@ -65,6 +65,17 @@ impl IndexManager {
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(
&self,
count: usize,
@ -134,7 +145,7 @@ impl IndexBuilder {
if !song.album_artists.0.is_empty() {
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();
}
@ -166,15 +177,17 @@ pub(super) struct 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| {
let songs = a
let mut songs = a
.songs
.iter()
.filter_map(|s| self.songs.get(s))
.cloned()
.collect::<Vec<_>>();
songs.sort_by_key(|s| (s.disc_number.unwrap_or(-1), s.track_number.unwrap_or(-1)));
collection::Album {
name: a.name.clone(),
artwork: a.artwork.clone(),
@ -188,7 +201,7 @@ impl Index {
}
#[derive(Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct SongID(u64);
struct SongID(u64);
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct SongKey {
@ -227,10 +240,10 @@ struct Album {
}
#[derive(Clone, Copy, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct AlbumID(u64);
struct AlbumID(u64);
#[derive(Clone, Eq, Hash, PartialEq)]
struct AlbumKey {
pub struct AlbumKey {
pub artists: Vec<String>,
pub name: Option<String>,
}

View file

@ -28,6 +28,8 @@ impl From<Option<String>> for MultiString {
pub enum Error {
#[error("Directory not found: {0}")]
DirectoryNotFound(PathBuf),
#[error("Album not found")]
AlbumNotFound,
#[error(transparent)]
Database(#[from] sqlx::Error),
#[error(transparent)]

View file

@ -25,6 +25,7 @@ impl TryFrom<i32> for APIMajorVersion {
pub const API_MAJOR_VERSION: i32 = 8;
pub const API_MINOR_VERSION: i32 = 0;
pub const API_ARRAY_SEPARATOR: &'static str = "\u{000C}";
mod axum;
pub use axum::*;

View file

@ -12,7 +12,10 @@ use percent_encoding::percent_decode_str;
use crate::{
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};
@ -40,6 +43,7 @@ pub fn router() -> Router<App> {
.route("/browse/*path", get(get_browse))
.route("/flatten", get(get_flatten_root))
.route("/flatten/*path", get(get_flatten))
.route("/artists/:artists/albums/:name", get(get_album))
.route("/random", get(get_random))
.route("/recent", get(get_recent))
.route("/search", get(get_search_root))
@ -365,6 +369,21 @@ async fn get_flatten(
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(
_auth: Auth,
api_version: APIMajorVersion,

View file

@ -21,6 +21,7 @@ impl IntoResponse for APIError {
APIError::Database(_) => StatusCode::INTERNAL_SERVER_ERROR,
APIError::DeletingOwnAccount => StatusCode::CONFLICT,
APIError::DirectoryNotFound(_) => StatusCode::NOT_FOUND,
APIError::AlbumNotFound => StatusCode::NOT_FOUND,
APIError::EmbeddedArtworkNotFound => StatusCode::NOT_FOUND,
APIError::EmptyPassword => StatusCode::BAD_REQUEST,
APIError::EmptyUsername => StatusCode::BAD_REQUEST,

View file

@ -26,6 +26,8 @@ pub enum APIError {
Database(sqlx::Error),
#[error("Directory not found: {0}")]
DirectoryNotFound(PathBuf),
#[error("Album not found")]
AlbumNotFound,
#[error("DDNS update query failed with HTTP status {0}")]
DdnsUpdateQueryFailed(u16),
#[error("Cannot delete your own account")]
@ -86,6 +88,7 @@ impl From<collection::Error> for APIError {
fn from(error: collection::Error) -> APIError {
match error {
collection::Error::DirectoryNotFound(d) => APIError::DirectoryNotFound(d),
collection::Error::AlbumNotFound => APIError::AlbumNotFound,
collection::Error::Database(e) => APIError::Database(e),
collection::Error::DatabaseConnection(e) => e.into(),
collection::Error::Vfs(e) => e.into(),