update
This commit is contained in:
parent
a5d3c14f0c
commit
11a862f6c7
6 changed files with 158 additions and 1 deletions
|
@ -166,6 +166,127 @@ impl Libary {
|
||||||
Track::get(track_id).await
|
Track::get(track_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn reload_metadata(&self, track_id: &str) -> Result<(), ()> {
|
||||||
|
let mut track = Track::get(track_id).await.ok_or_else(|| ())?;
|
||||||
|
let path = &track.path;
|
||||||
|
log::info!("Rescanning metadata for {path}");
|
||||||
|
|
||||||
|
let metadata = metadata::get_metadata(path);
|
||||||
|
|
||||||
|
let mut update = json!({});
|
||||||
|
|
||||||
|
if let Some(meta) = &metadata {
|
||||||
|
if let Some(artist) = meta.artist() {
|
||||||
|
let artist_id = self.find_or_create_artist(artist).await;
|
||||||
|
update
|
||||||
|
.as_object_mut()
|
||||||
|
.unwrap()
|
||||||
|
.insert("artist_id".into(), artist_id.into());
|
||||||
|
} else {
|
||||||
|
log::warn!("{path} has no artist");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(album) = meta.album() {
|
||||||
|
let album_id = self
|
||||||
|
.find_or_create_album(
|
||||||
|
album,
|
||||||
|
update
|
||||||
|
.as_object()
|
||||||
|
.unwrap()
|
||||||
|
.get("artist_id")
|
||||||
|
.map(|x| x.as_str().unwrap()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
update
|
||||||
|
.as_object_mut()
|
||||||
|
.unwrap()
|
||||||
|
.insert("album_id".into(), album_id.into());
|
||||||
|
} else {
|
||||||
|
log::warn!("{path} has no album and will be treated as single");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(title) = meta.title() {
|
||||||
|
update
|
||||||
|
.as_object_mut()
|
||||||
|
.unwrap()
|
||||||
|
.insert("title".into(), title.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(metadata) = metadata {
|
||||||
|
update
|
||||||
|
.as_object_mut()
|
||||||
|
.unwrap()
|
||||||
|
.insert("meta".into(), metadata.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no title in metadata use file name
|
||||||
|
if update.as_object().unwrap().get("title").is_none() {
|
||||||
|
update.as_object_mut().unwrap().insert(
|
||||||
|
"title".into(),
|
||||||
|
std::path::Path::new(&path)
|
||||||
|
.file_stem()
|
||||||
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
track.update(&update).await.unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn clean_lost_files(&self) {
|
||||||
|
// todo : clean
|
||||||
|
// tracks
|
||||||
|
for track in Track::find(doc! {}, None).await.unwrap() {
|
||||||
|
if !std::path::Path::new(&track.path).exists() {
|
||||||
|
log::info!("Cleaning lost {}", track.path);
|
||||||
|
track.delete().await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// albums
|
||||||
|
for album in Album::find_partial(doc! {}, json!({"title": 1}), None)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
if Track::find_partial(doc! { "album_id": album.reference() }, json!({}), None)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.is_empty()
|
||||||
|
{
|
||||||
|
log::info!(
|
||||||
|
"Cleaning album {} with no tracks",
|
||||||
|
album.title.as_ref().unwrap()
|
||||||
|
);
|
||||||
|
Album::remove(album.id()).await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// artists
|
||||||
|
for artist in Artist::find_partial(doc! {}, json!({"name": 1}), None)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
if Track::find_partial(doc! { "artist_id": artist.reference()}, json!({}), None)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.is_empty()
|
||||||
|
&& Album::find_partial(doc! { "artist_id": artist.reference()}, json!({}), None)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.is_empty()
|
||||||
|
{
|
||||||
|
log::info!(
|
||||||
|
"Cleaning artist {} with no tracks or albums",
|
||||||
|
artist.name.as_ref().unwrap()
|
||||||
|
);
|
||||||
|
Artist::remove(artist.id()).await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn rescan(&self, cache: &RouteCache) {
|
pub async fn rescan(&self, cache: &RouteCache) {
|
||||||
cache.invalidate("albums", "latest").await;
|
cache.invalidate("albums", "latest").await;
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ async fn rocket() -> _ {
|
||||||
route::album::latest_albums_route,
|
route::album::latest_albums_route,
|
||||||
route::track::track_route,
|
route::track::track_route,
|
||||||
route::track::track_audio_route,
|
route::track::track_audio_route,
|
||||||
|
route::track::track_reload_meta_route,
|
||||||
route::album::album_cover_route,
|
route::album::album_cover_route,
|
||||||
route::user::login_route,
|
route::user::login_route,
|
||||||
route::user::passwd_route,
|
route::user::passwd_route,
|
||||||
|
@ -64,7 +65,8 @@ async fn rocket() -> _ {
|
||||||
route::playlist::playlist_route,
|
route::playlist::playlist_route,
|
||||||
route::playlist::playlist_add_route,
|
route::playlist::playlist_add_route,
|
||||||
route::playlist::playlist_edit_route,
|
route::playlist::playlist_edit_route,
|
||||||
route::playlist::playlist_tracks_route
|
route::playlist::playlist_tracks_route,
|
||||||
|
route::admin::clean_library
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.manage(lib)
|
.manage(lib)
|
||||||
|
|
16
src/route/admin.rs
Normal file
16
src/route/admin.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use super::api_error;
|
||||||
|
use super::FallibleApiResponse;
|
||||||
|
use mongodb::bson::doc;
|
||||||
|
use rocket::{get, State};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
use crate::check_admin;
|
||||||
|
use crate::library::user::User;
|
||||||
|
use crate::library::Libary;
|
||||||
|
|
||||||
|
#[get("/library/clean")]
|
||||||
|
pub async fn clean_library(lib: &State<Libary>, u: User) -> FallibleApiResponse {
|
||||||
|
check_admin!(u);
|
||||||
|
lib.clean_lost_files().await;
|
||||||
|
Ok(json!({"ok": 1}))
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ use rocket::{
|
||||||
};
|
};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
|
pub mod admin;
|
||||||
pub mod album;
|
pub mod album;
|
||||||
pub mod artist;
|
pub mod artist;
|
||||||
pub mod playlist;
|
pub mod playlist;
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
use super::api_error;
|
use super::api_error;
|
||||||
use super::FallibleApiResponse;
|
use super::FallibleApiResponse;
|
||||||
use super::ToAPI;
|
use super::ToAPI;
|
||||||
|
use crate::library::user::User;
|
||||||
use fs::NamedFile;
|
use fs::NamedFile;
|
||||||
use mongodb::bson::doc;
|
use mongodb::bson::doc;
|
||||||
use rocket::{fs, get, State};
|
use rocket::{fs, get, State};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
use crate::check_admin;
|
||||||
use crate::library::Libary;
|
use crate::library::Libary;
|
||||||
|
|
||||||
#[get("/track/<track_id>")]
|
#[get("/track/<track_id>")]
|
||||||
|
@ -17,6 +20,19 @@ pub async fn track_route(track_id: &str, lib: &State<Libary>) -> FallibleApiResp
|
||||||
.await)
|
.await)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/track/<track_id>/reload")]
|
||||||
|
pub async fn track_reload_meta_route(
|
||||||
|
track_id: &str,
|
||||||
|
lib: &State<Libary>,
|
||||||
|
u: User,
|
||||||
|
) -> FallibleApiResponse {
|
||||||
|
check_admin!(u);
|
||||||
|
lib.reload_metadata(track_id)
|
||||||
|
.await
|
||||||
|
.map_err(|_| api_error("Error reloading metadata"))?;
|
||||||
|
Ok(json!({"ok": 1}))
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/track/<track_id>/audio")]
|
#[get("/track/<track_id>/audio")]
|
||||||
pub async fn track_audio_route(track_id: &str, lib: &State<Libary>) -> Option<NamedFile> {
|
pub async fn track_audio_route(track_id: &str, lib: &State<Libary>) -> Option<NamedFile> {
|
||||||
let track = lib.get_track_by_id(track_id).await?;
|
let track = lib.get_track_by_id(track_id).await?;
|
||||||
|
|
|
@ -16,6 +16,7 @@ use serde_json::json;
|
||||||
use super::api_error;
|
use super::api_error;
|
||||||
use super::FallibleApiResponse;
|
use super::FallibleApiResponse;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
macro_rules! check_admin {
|
macro_rules! check_admin {
|
||||||
($u:ident) => {
|
($u:ident) => {
|
||||||
if !$u.is_admin() {
|
if !$u.is_admin() {
|
||||||
|
|
Loading…
Reference in a new issue