mirror of
https://github.com/agersant/polaris
synced 2024-11-10 02:04:13 +00:00
Error cleanup
This commit is contained in:
parent
1e9d307a05
commit
4c5a6bc2d6
5 changed files with 89 additions and 81 deletions
|
@ -16,14 +16,6 @@ pub enum QueryError {
|
||||||
SongNotFound(PathBuf),
|
SongNotFound(PathBuf),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Vfs(#[from] vfs::Error),
|
Vfs(#[from] vfs::Error),
|
||||||
#[error("Unspecified")]
|
|
||||||
Unspecified,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<anyhow::Error> for QueryError {
|
|
||||||
fn from(_: anyhow::Error) -> Self {
|
|
||||||
QueryError::Unspecified
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sql_function!(
|
sql_function!(
|
||||||
|
@ -44,8 +36,7 @@ impl Index {
|
||||||
// Browse top-level
|
// Browse top-level
|
||||||
let real_directories: Vec<Directory> = directories::table
|
let real_directories: Vec<Directory> = directories::table
|
||||||
.filter(directories::parent.is_null())
|
.filter(directories::parent.is_null())
|
||||||
.load(&mut connection)
|
.load(&mut connection)?;
|
||||||
.map_err(anyhow::Error::new)?;
|
|
||||||
let virtual_directories = real_directories
|
let virtual_directories = real_directories
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|d| d.virtualize(&vfs));
|
.filter_map(|d| d.virtualize(&vfs));
|
||||||
|
@ -58,8 +49,7 @@ impl Index {
|
||||||
let real_directories: Vec<Directory> = directories::table
|
let real_directories: Vec<Directory> = directories::table
|
||||||
.filter(directories::parent.eq(&real_path_string))
|
.filter(directories::parent.eq(&real_path_string))
|
||||||
.order(sql::<sql_types::Bool>("path COLLATE NOCASE ASC"))
|
.order(sql::<sql_types::Bool>("path COLLATE NOCASE ASC"))
|
||||||
.load(&mut connection)
|
.load(&mut connection)?;
|
||||||
.map_err(anyhow::Error::new)?;
|
|
||||||
let virtual_directories = real_directories
|
let virtual_directories = real_directories
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|d| d.virtualize(&vfs));
|
.filter_map(|d| d.virtualize(&vfs));
|
||||||
|
@ -68,8 +58,7 @@ impl Index {
|
||||||
let real_songs: Vec<Song> = songs::table
|
let real_songs: Vec<Song> = songs::table
|
||||||
.filter(songs::parent.eq(&real_path_string))
|
.filter(songs::parent.eq(&real_path_string))
|
||||||
.order(sql::<sql_types::Bool>("path COLLATE NOCASE ASC"))
|
.order(sql::<sql_types::Bool>("path COLLATE NOCASE ASC"))
|
||||||
.load(&mut connection)
|
.load(&mut connection)?;
|
||||||
.map_err(anyhow::Error::new)?;
|
|
||||||
let virtual_songs = real_songs.into_iter().filter_map(|s| s.virtualize(&vfs));
|
let virtual_songs = real_songs.into_iter().filter_map(|s| s.virtualize(&vfs));
|
||||||
output.extend(virtual_songs.map(CollectionFile::Song));
|
output.extend(virtual_songs.map(CollectionFile::Song));
|
||||||
}
|
}
|
||||||
|
@ -95,20 +84,16 @@ impl Index {
|
||||||
songs
|
songs
|
||||||
.filter(path.like(&song_path_filter))
|
.filter(path.like(&song_path_filter))
|
||||||
.order(path)
|
.order(path)
|
||||||
.load(&mut connection)
|
.load(&mut connection)?
|
||||||
.map_err(anyhow::Error::new)?
|
|
||||||
} else {
|
} else {
|
||||||
songs
|
songs.order(path).load(&mut connection)?
|
||||||
.order(path)
|
|
||||||
.load(&mut connection)
|
|
||||||
.map_err(anyhow::Error::new)?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let virtual_songs = real_songs.into_iter().filter_map(|s| s.virtualize(&vfs));
|
let virtual_songs = real_songs.into_iter().filter_map(|s| s.virtualize(&vfs));
|
||||||
Ok(virtual_songs.collect::<Vec<_>>())
|
Ok(virtual_songs.collect::<Vec<_>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_random_albums(&self, count: i64) -> anyhow::Result<Vec<Directory>> {
|
pub fn get_random_albums(&self, count: i64) -> Result<Vec<Directory>, QueryError> {
|
||||||
use self::directories::dsl::*;
|
use self::directories::dsl::*;
|
||||||
let vfs = self.vfs_manager.get_vfs()?;
|
let vfs = self.vfs_manager.get_vfs()?;
|
||||||
let mut connection = self.db.connect()?;
|
let mut connection = self.db.connect()?;
|
||||||
|
@ -123,7 +108,7 @@ impl Index {
|
||||||
Ok(virtual_directories.collect::<Vec<_>>())
|
Ok(virtual_directories.collect::<Vec<_>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_recent_albums(&self, count: i64) -> anyhow::Result<Vec<Directory>> {
|
pub fn get_recent_albums(&self, count: i64) -> Result<Vec<Directory>, QueryError> {
|
||||||
use self::directories::dsl::*;
|
use self::directories::dsl::*;
|
||||||
let vfs = self.vfs_manager.get_vfs()?;
|
let vfs = self.vfs_manager.get_vfs()?;
|
||||||
let mut connection = self.db.connect()?;
|
let mut connection = self.db.connect()?;
|
||||||
|
@ -138,7 +123,7 @@ impl Index {
|
||||||
Ok(virtual_directories.collect::<Vec<_>>())
|
Ok(virtual_directories.collect::<Vec<_>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn search(&self, query: &str) -> anyhow::Result<Vec<CollectionFile>> {
|
pub fn search(&self, query: &str) -> Result<Vec<CollectionFile>, QueryError> {
|
||||||
let vfs = self.vfs_manager.get_vfs()?;
|
let vfs = self.vfs_manager.get_vfs()?;
|
||||||
let mut connection = self.db.connect()?;
|
let mut connection = self.db.connect()?;
|
||||||
let like_test = format!("%{}%", query);
|
let like_test = format!("%{}%", query);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use anyhow::*;
|
|
||||||
use image::{DynamicImage, GenericImage, GenericImageView, ImageBuffer, ImageOutputFormat};
|
use image::{DynamicImage, GenericImage, GenericImageView, ImageBuffer, ImageOutputFormat};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
|
@ -8,6 +7,24 @@ use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use crate::utils::{get_audio_format, AudioFormat};
|
use crate::utils::{get_audio_format, AudioFormat};
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("No embedded artwork was found in `{0}`")]
|
||||||
|
EmbeddedArtworkNotFound(PathBuf),
|
||||||
|
#[error(transparent)]
|
||||||
|
Id3(#[from] id3::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
Image(#[from] image::error::ImageError),
|
||||||
|
#[error("Filesystem error for `{0}`: `{1}`")]
|
||||||
|
Io(PathBuf, std::io::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
Metaflac(#[from] metaflac::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
Mp4aMeta(#[from] mp4ameta::Error),
|
||||||
|
#[error("This file format is not supported: {0}")]
|
||||||
|
UnsupportedFormat(&'static str),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
pub max_dimension: Option<u32>,
|
pub max_dimension: Option<u32>,
|
||||||
|
@ -37,7 +54,11 @@ impl Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_thumbnail(&self, image_path: &Path, thumbnailoptions: &Options) -> Result<PathBuf> {
|
pub fn get_thumbnail(
|
||||||
|
&self,
|
||||||
|
image_path: &Path,
|
||||||
|
thumbnailoptions: &Options,
|
||||||
|
) -> Result<PathBuf, Error> {
|
||||||
match self.retrieve_thumbnail(image_path, thumbnailoptions) {
|
match self.retrieve_thumbnail(image_path, thumbnailoptions) {
|
||||||
Some(path) => Ok(path),
|
Some(path) => Ok(path),
|
||||||
None => self.create_thumbnail(image_path, thumbnailoptions),
|
None => self.create_thumbnail(image_path, thumbnailoptions),
|
||||||
|
@ -60,13 +81,19 @@ impl Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_thumbnail(&self, image_path: &Path, thumbnailoptions: &Options) -> Result<PathBuf> {
|
fn create_thumbnail(
|
||||||
|
&self,
|
||||||
|
image_path: &Path,
|
||||||
|
thumbnailoptions: &Options,
|
||||||
|
) -> Result<PathBuf, Error> {
|
||||||
let thumbnail = generate_thumbnail(image_path, thumbnailoptions)?;
|
let thumbnail = generate_thumbnail(image_path, thumbnailoptions)?;
|
||||||
let quality = 80;
|
let quality = 80;
|
||||||
|
|
||||||
fs::create_dir_all(&self.thumbnails_dir_path)?;
|
fs::create_dir_all(&self.thumbnails_dir_path)
|
||||||
|
.map_err(|e| Error::Io(self.thumbnails_dir_path.clone(), e))?;
|
||||||
let path = self.get_thumbnail_path(image_path, thumbnailoptions);
|
let path = self.get_thumbnail_path(image_path, thumbnailoptions);
|
||||||
let mut out_file = File::create(&path)?;
|
let mut out_file =
|
||||||
|
File::create(&path).map_err(|e| Error::Io(self.thumbnails_dir_path.clone(), e))?;
|
||||||
thumbnail.write_to(&mut out_file, ImageOutputFormat::Jpeg(quality))?;
|
thumbnail.write_to(&mut out_file, ImageOutputFormat::Jpeg(quality))?;
|
||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
@ -79,7 +106,7 @@ impl Manager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_thumbnail(image_path: &Path, options: &Options) -> Result<DynamicImage> {
|
fn generate_thumbnail(image_path: &Path, options: &Options) -> Result<DynamicImage, Error> {
|
||||||
let source_image = DynamicImage::ImageRgb8(read(image_path)?.into_rgb8());
|
let source_image = DynamicImage::ImageRgb8(read(image_path)?.into_rgb8());
|
||||||
let (source_width, source_height) = source_image.dimensions();
|
let (source_width, source_height) = source_image.dimensions();
|
||||||
let largest_dimension = cmp::max(source_width, source_height);
|
let largest_dimension = cmp::max(source_width, source_height);
|
||||||
|
@ -115,7 +142,7 @@ fn generate_thumbnail(image_path: &Path, options: &Options) -> Result<DynamicIma
|
||||||
Ok(final_image)
|
Ok(final_image)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(image_path: &Path) -> Result<DynamicImage> {
|
fn read(image_path: &Path) -> Result<DynamicImage, Error> {
|
||||||
match get_audio_format(image_path) {
|
match get_audio_format(image_path) {
|
||||||
Some(AudioFormat::AIFF) => read_aiff(image_path),
|
Some(AudioFormat::AIFF) => read_aiff(image_path),
|
||||||
Some(AudioFormat::APE) => read_ape(image_path),
|
Some(AudioFormat::APE) => read_ape(image_path),
|
||||||
|
@ -130,67 +157,53 @@ fn read(image_path: &Path) -> Result<DynamicImage> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_ape(_: &Path) -> Result<DynamicImage> {
|
fn read_ape(_: &Path) -> Result<DynamicImage, Error> {
|
||||||
bail!("Embedded images are not supported in APE files");
|
Err(Error::UnsupportedFormat("ape"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_flac(path: &Path) -> Result<DynamicImage> {
|
fn read_flac(path: &Path) -> Result<DynamicImage, Error> {
|
||||||
let tag = metaflac::Tag::read_from_path(path)?;
|
let tag = metaflac::Tag::read_from_path(path)?;
|
||||||
|
|
||||||
if let Some(p) = tag.pictures().next() {
|
if let Some(p) = tag.pictures().next() {
|
||||||
return Ok(image::load_from_memory(&p.data)?);
|
return Ok(image::load_from_memory(&p.data)?);
|
||||||
}
|
}
|
||||||
|
Err(Error::EmbeddedArtworkNotFound(path.to_owned()))
|
||||||
bail!(
|
|
||||||
"Embedded flac artwork not found for file: {}",
|
|
||||||
path.display()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_mp3(path: &Path) -> Result<DynamicImage> {
|
fn read_mp3(path: &Path) -> Result<DynamicImage, Error> {
|
||||||
let tag = id3::Tag::read_from_path(path)?;
|
let tag = id3::Tag::read_from_path(path)?;
|
||||||
read_id3(path, &tag)
|
read_id3(path, &tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_aiff(path: &Path) -> Result<DynamicImage> {
|
fn read_aiff(path: &Path) -> Result<DynamicImage, Error> {
|
||||||
let tag = id3::Tag::read_from_aiff_path(path)?;
|
let tag = id3::Tag::read_from_aiff_path(path)?;
|
||||||
read_id3(path, &tag)
|
read_id3(path, &tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_wave(path: &Path) -> Result<DynamicImage> {
|
fn read_wave(path: &Path) -> Result<DynamicImage, Error> {
|
||||||
let tag = id3::Tag::read_from_wav_path(path)?;
|
let tag = id3::Tag::read_from_wav_path(path)?;
|
||||||
read_id3(path, &tag)
|
read_id3(path, &tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_id3(path: &Path, tag: &id3::Tag) -> Result<DynamicImage> {
|
fn read_id3(path: &Path, tag: &id3::Tag) -> Result<DynamicImage, Error> {
|
||||||
if let Some(p) = tag.pictures().next() {
|
if let Some(p) = tag.pictures().next() {
|
||||||
return Ok(image::load_from_memory(&p.data)?);
|
return Ok(image::load_from_memory(&p.data)?);
|
||||||
}
|
}
|
||||||
|
Err(Error::EmbeddedArtworkNotFound(path.to_owned()))
|
||||||
bail!(
|
|
||||||
"Embedded id3 artwork not found for file: {}",
|
|
||||||
path.display()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_mp4(path: &Path) -> Result<DynamicImage> {
|
fn read_mp4(path: &Path) -> Result<DynamicImage, Error> {
|
||||||
let tag = mp4ameta::Tag::read_from_path(path)?;
|
let tag = mp4ameta::Tag::read_from_path(path)?;
|
||||||
|
tag.artwork()
|
||||||
match tag.artwork().map(|d| d.data) {
|
.and_then(|d| image::load_from_memory(d.data).ok())
|
||||||
Some(v) => Ok(image::load_from_memory(v)?),
|
.ok_or_else(|| Error::EmbeddedArtworkNotFound(path.to_owned()))
|
||||||
_ => bail!(
|
|
||||||
"Embedded mp4 artwork not found for file: {}",
|
|
||||||
path.display()
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_vorbis(_: &Path) -> Result<DynamicImage> {
|
fn read_vorbis(_: &Path) -> Result<DynamicImage, Error> {
|
||||||
bail!("Embedded images are not supported in Vorbis files");
|
Err(Error::UnsupportedFormat("vorbis"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_opus(_: &Path) -> Result<DynamicImage> {
|
fn read_opus(_: &Path) -> Result<DynamicImage, Error> {
|
||||||
bail!("Embedded images are not supported in Opus files");
|
Err(Error::UnsupportedFormat("opus"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -208,7 +208,7 @@ impl Manager {
|
||||||
.map(AuthToken)
|
.map(AuthToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count(&self) -> anyhow::Result<i64> {
|
pub fn count(&self) -> Result<i64, Error> {
|
||||||
use crate::db::users::dsl::*;
|
use crate::db::users::dsl::*;
|
||||||
let mut connection = self.db.connect()?;
|
let mut connection = self.db.connect()?;
|
||||||
let count = users.count().get_result(&mut connection)?;
|
let count = users.count().get_result(&mut connection)?;
|
||||||
|
|
|
@ -15,7 +15,7 @@ use actix_web_httpauth::extractors::bearer::BearerAuth;
|
||||||
use futures_util::future::err;
|
use futures_util::future::err;
|
||||||
use percent_encoding::percent_decode_str;
|
use percent_encoding::percent_decode_str;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
@ -73,9 +73,11 @@ pub fn make_config() -> impl FnOnce(&mut ServiceConfig) + Clone {
|
||||||
impl ResponseError for APIError {
|
impl ResponseError for APIError {
|
||||||
fn status_code(&self) -> StatusCode {
|
fn status_code(&self) -> StatusCode {
|
||||||
match self {
|
match self {
|
||||||
|
APIError::AdminPermissionRequired => StatusCode::UNAUTHORIZED,
|
||||||
APIError::AudioFileIOError => StatusCode::NOT_FOUND,
|
APIError::AudioFileIOError => StatusCode::NOT_FOUND,
|
||||||
APIError::AuthenticationRequired => StatusCode::UNAUTHORIZED,
|
APIError::AuthenticationRequired => StatusCode::UNAUTHORIZED,
|
||||||
APIError::DeletingOwnAccount => StatusCode::CONFLICT,
|
APIError::DeletingOwnAccount => StatusCode::CONFLICT,
|
||||||
|
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,
|
||||||
APIError::IncorrectCredentials => StatusCode::UNAUTHORIZED,
|
APIError::IncorrectCredentials => StatusCode::UNAUTHORIZED,
|
||||||
|
@ -87,7 +89,6 @@ impl ResponseError for APIError {
|
||||||
APIError::PlaylistNotFound => StatusCode::NOT_FOUND,
|
APIError::PlaylistNotFound => StatusCode::NOT_FOUND,
|
||||||
APIError::SongMetadataNotFound => StatusCode::NOT_FOUND,
|
APIError::SongMetadataNotFound => StatusCode::NOT_FOUND,
|
||||||
APIError::ThumbnailFileIOError => StatusCode::NOT_FOUND,
|
APIError::ThumbnailFileIOError => StatusCode::NOT_FOUND,
|
||||||
APIError::Unspecified => StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
APIError::UserNotFound => StatusCode::NOT_FOUND,
|
APIError::UserNotFound => StatusCode::NOT_FOUND,
|
||||||
APIError::VFSPathNotFound => StatusCode::NOT_FOUND,
|
APIError::VFSPathNotFound => StatusCode::NOT_FOUND,
|
||||||
}
|
}
|
||||||
|
@ -106,7 +107,7 @@ impl FromRequest for Auth {
|
||||||
fn from_request(request: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
fn from_request(request: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||||
let user_manager = match request.app_data::<Data<user::Manager>>() {
|
let user_manager = match request.app_data::<Data<user::Manager>>() {
|
||||||
Some(m) => m.clone(),
|
Some(m) => m.clone(),
|
||||||
None => return Box::pin(err(ErrorInternalServerError(APIError::Unspecified))),
|
None => return Box::pin(err(ErrorInternalServerError(APIError::Internal))),
|
||||||
};
|
};
|
||||||
|
|
||||||
let bearer_auth_future = BearerAuth::from_request(request, payload);
|
let bearer_auth_future = BearerAuth::from_request(request, payload);
|
||||||
|
@ -155,7 +156,7 @@ impl FromRequest for AdminRights {
|
||||||
fn from_request(request: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
fn from_request(request: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||||
let user_manager = match request.app_data::<Data<user::Manager>>() {
|
let user_manager = match request.app_data::<Data<user::Manager>>() {
|
||||||
Some(m) => m.clone(),
|
Some(m) => m.clone(),
|
||||||
None => return Box::pin(err(ErrorInternalServerError(APIError::Unspecified))),
|
None => return Box::pin(err(ErrorInternalServerError(APIError::Internal))),
|
||||||
};
|
};
|
||||||
|
|
||||||
let auth_future = Auth::from_request(request, payload);
|
let auth_future = Auth::from_request(request, payload);
|
||||||
|
@ -164,7 +165,7 @@ impl FromRequest for AdminRights {
|
||||||
let user_manager_count = user_manager.clone();
|
let user_manager_count = user_manager.clone();
|
||||||
let user_count = block(move || user_manager_count.count()).await;
|
let user_count = block(move || user_manager_count.count()).await;
|
||||||
match user_count {
|
match user_count {
|
||||||
Err(_) => return Err(ErrorInternalServerError(APIError::Unspecified)),
|
Err(e) => return Err(e.into()),
|
||||||
Ok(0) => return Ok(AdminRights { auth: None }),
|
Ok(0) => return Ok(AdminRights { auth: None }),
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
@ -175,7 +176,7 @@ impl FromRequest for AdminRights {
|
||||||
if is_admin {
|
if is_admin {
|
||||||
Ok(AdminRights { auth: Some(auth) })
|
Ok(AdminRights { auth: Some(auth) })
|
||||||
} else {
|
} else {
|
||||||
Err(ErrorForbidden(APIError::Unspecified))
|
Err(ErrorForbidden(APIError::AdminPermissionRequired))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -212,7 +213,7 @@ where
|
||||||
{
|
{
|
||||||
actix_web::web::block(f)
|
actix_web::web::block(f)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| APIError::Unspecified)
|
.map_err(|_| APIError::Internal)
|
||||||
.and_then(|r| r.map_err(|e| e.into()))
|
.and_then(|r| r.map_err(|e| e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,13 +523,13 @@ async fn get_thumbnail(
|
||||||
) -> Result<MediaFile, APIError> {
|
) -> Result<MediaFile, APIError> {
|
||||||
let options = thumbnail::Options::from(options_input.0);
|
let options = thumbnail::Options::from(options_input.0);
|
||||||
|
|
||||||
let thumbnail_path = block(move || {
|
let thumbnail_path = block(move || -> Result<PathBuf, APIError> {
|
||||||
let vfs = vfs_manager.get_vfs()?;
|
let vfs = vfs_manager.get_vfs()?;
|
||||||
let path = percent_decode_str(&path).decode_utf8_lossy();
|
let path = percent_decode_str(&path).decode_utf8_lossy();
|
||||||
let image_path = vfs.virtual_to_real(Path::new(path.as_ref()))?;
|
let image_path = vfs.virtual_to_real(Path::new(path.as_ref()))?;
|
||||||
thumbnails_manager
|
thumbnails_manager
|
||||||
.get_thumbnail(&image_path, &options)
|
.get_thumbnail(&image_path, &options)
|
||||||
.map_err(|_| APIError::Unspecified)
|
.map_err(|e| e.into())
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::app::index::QueryError;
|
use crate::app::index::QueryError;
|
||||||
use crate::app::{config, ddns, lastfm, playlist, settings, user, vfs};
|
use crate::app::{config, ddns, lastfm, playlist, settings, thumbnail, user, vfs};
|
||||||
use crate::db;
|
use crate::db;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum APIError {
|
pub enum APIError {
|
||||||
|
#[error("Administrator permission is required")]
|
||||||
|
AdminPermissionRequired,
|
||||||
#[error("Authentication is required")]
|
#[error("Authentication is required")]
|
||||||
AuthenticationRequired,
|
AuthenticationRequired,
|
||||||
#[error("Incorrect Credentials")]
|
#[error("Incorrect Credentials")]
|
||||||
IncorrectCredentials,
|
IncorrectCredentials,
|
||||||
|
#[error("EmbeddedArtworkNotFound")]
|
||||||
|
EmbeddedArtworkNotFound,
|
||||||
#[error("EmptyUsername")]
|
#[error("EmptyUsername")]
|
||||||
EmptyUsername,
|
EmptyUsername,
|
||||||
#[error("EmptyPassword")]
|
#[error("EmptyPassword")]
|
||||||
|
@ -38,14 +42,6 @@ pub enum APIError {
|
||||||
SongMetadataNotFound,
|
SongMetadataNotFound,
|
||||||
#[error("Internal server error")]
|
#[error("Internal server error")]
|
||||||
Internal,
|
Internal,
|
||||||
#[error("Unspecified")]
|
|
||||||
Unspecified,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<anyhow::Error> for APIError {
|
|
||||||
fn from(_: anyhow::Error) -> Self {
|
|
||||||
APIError::Unspecified
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<config::Error> for APIError {
|
impl From<config::Error> for APIError {
|
||||||
|
@ -78,7 +74,6 @@ impl From<QueryError> for APIError {
|
||||||
QueryError::DatabaseConnection(e) => e.into(),
|
QueryError::DatabaseConnection(e) => e.into(),
|
||||||
QueryError::SongNotFound(_) => APIError::SongMetadataNotFound,
|
QueryError::SongNotFound(_) => APIError::SongMetadataNotFound,
|
||||||
QueryError::Vfs(e) => e.into(),
|
QueryError::Vfs(e) => e.into(),
|
||||||
QueryError::Unspecified => APIError::Unspecified,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,3 +153,17 @@ impl From<lastfm::Error> for APIError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<thumbnail::Error> for APIError {
|
||||||
|
fn from(error: thumbnail::Error) -> APIError {
|
||||||
|
match error {
|
||||||
|
thumbnail::Error::EmbeddedArtworkNotFound(_) => APIError::EmbeddedArtworkNotFound,
|
||||||
|
thumbnail::Error::Id3(_) => APIError::Internal,
|
||||||
|
thumbnail::Error::Image(_) => APIError::Internal,
|
||||||
|
thumbnail::Error::Io(_, _) => APIError::Internal,
|
||||||
|
thumbnail::Error::Metaflac(_) => APIError::Internal,
|
||||||
|
thumbnail::Error::Mp4aMeta(_) => APIError::Internal,
|
||||||
|
thumbnail::Error::UnsupportedFormat(_) => APIError::Internal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue