Added the mb db download. Big upsides and downsides
This commit is contained in:
@@ -374,3 +374,13 @@ pub async fn ytauth_refresh() -> Result<serde_json::Value, ApiError> {
|
||||
pub async fn ytauth_clear_cookies() -> Result<(), ApiError> {
|
||||
delete(&format!("{BASE}/ytauth/cookies")).await
|
||||
}
|
||||
|
||||
// --- MusicBrainz Local DB ---
|
||||
|
||||
pub async fn get_mb_status() -> Result<MbStatus, ApiError> {
|
||||
get_json(&format!("{BASE}/mb-status")).await
|
||||
}
|
||||
|
||||
pub async fn trigger_mb_import() -> Result<TaskRef, ApiError> {
|
||||
post_empty(&format!("{BASE}/mb-import")).await
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use web_sys::HtmlSelectElement;
|
||||
use yew::prelude::*;
|
||||
|
||||
use crate::api;
|
||||
use crate::types::{AppConfig, SubsonicPasswordStatus, YtAuthStatus};
|
||||
use crate::types::{AppConfig, MbStatus, SubsonicPasswordStatus, YtAuthStatus};
|
||||
|
||||
#[function_component(SettingsPage)]
|
||||
pub fn settings_page() -> Html {
|
||||
@@ -15,12 +15,15 @@ pub fn settings_page() -> Html {
|
||||
let subsonic_status = use_state(|| None::<SubsonicPasswordStatus>);
|
||||
let subsonic_password = use_state(String::new);
|
||||
let subsonic_saving = use_state(|| false);
|
||||
let mb_status = use_state(|| None::<MbStatus>);
|
||||
let mb_importing = use_state(|| false);
|
||||
|
||||
{
|
||||
let config = config.clone();
|
||||
let error = error.clone();
|
||||
let ytauth = ytauth.clone();
|
||||
let subsonic_status = subsonic_status.clone();
|
||||
let mb_status = mb_status.clone();
|
||||
use_effect_with((), move |_| {
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
match api::get_config().await {
|
||||
@@ -38,6 +41,11 @@ pub fn settings_page() -> Html {
|
||||
subsonic_status.set(Some(status));
|
||||
}
|
||||
});
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
if let Ok(status) = api::get_mb_status().await {
|
||||
mb_status.set(Some(status));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -596,6 +604,92 @@ pub fn settings_page() -> Html {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
// MusicBrainz Local Database
|
||||
<div class="card">
|
||||
<h3>{ "MusicBrainz Database" }</h3>
|
||||
<p class="text-sm text-muted mb-1">
|
||||
{ "Import the MusicBrainz database locally for instant artist/album lookups instead of rate-limited API calls. " }
|
||||
{ "Makes browsing and watching artists dramatically faster." }
|
||||
</p>
|
||||
<div class="card" style="border-color: var(--warning); background: rgba(234, 179, 8, 0.08); margin: 0.5rem 0;">
|
||||
<p class="text-sm" style="margin:0;">
|
||||
<strong style="color: var(--warning);">{ "Heads up: " }</strong>
|
||||
{ "This downloads ~24 GB of data and builds a ~10 GB local database. " }
|
||||
{ "The initial import can take 3-6 hours depending on your hardware. " }
|
||||
{ "Total disk usage: ~35 GB (downloads + database). " }
|
||||
{ "After the initial import, the database is automatically refreshed weekly to stay current." }
|
||||
</p>
|
||||
</div>
|
||||
{
|
||||
if let Some(ref status) = *mb_status {
|
||||
if status.has_local_db {
|
||||
if let Some(ref stats) = status.stats {
|
||||
let import_date = stats.last_import_date.clone().unwrap_or_else(|| "unknown".into());
|
||||
html! {
|
||||
<>
|
||||
<p>
|
||||
<span class="badge badge-success">{ "Loaded" }</span>
|
||||
<span class="text-muted text-sm" style="margin-left: 0.5rem;">
|
||||
{ format!("imported {}", import_date) }
|
||||
</span>
|
||||
</p>
|
||||
<p class="text-sm">
|
||||
{ format!("{} artists, {} release groups, {} releases, {} recordings",
|
||||
stats.artists, stats.release_groups, stats.releases, stats.recordings) }
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
} else {
|
||||
html! {
|
||||
<p><span class="badge badge-success">{ "Loaded" }</span></p>
|
||||
}
|
||||
}
|
||||
} else {
|
||||
html! {
|
||||
<p class="text-sm text-muted">
|
||||
{ "Not configured. Import data to enable instant lookups." }
|
||||
</p>
|
||||
}
|
||||
}
|
||||
} else {
|
||||
html! { <p class="text-sm text-muted">{ "Loading..." }</p> }
|
||||
}
|
||||
}
|
||||
<button type="button" class="btn btn-primary"
|
||||
disabled={*mb_importing}
|
||||
onclick={{
|
||||
let mb_importing = mb_importing.clone();
|
||||
let mb_status = mb_status.clone();
|
||||
let message = message.clone();
|
||||
let error = error.clone();
|
||||
Callback::from(move |_: MouseEvent| {
|
||||
let mb_importing = mb_importing.clone();
|
||||
let mb_status = mb_status.clone();
|
||||
let message = message.clone();
|
||||
let error = error.clone();
|
||||
mb_importing.set(true);
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
match api::trigger_mb_import().await {
|
||||
Ok(task_ref) => {
|
||||
message.set(Some(format!(
|
||||
"MusicBrainz import started (task {}). This will take a while.",
|
||||
task_ref.task_id
|
||||
)));
|
||||
// Refresh status after a short delay
|
||||
if let Ok(s) = api::get_mb_status().await {
|
||||
mb_status.set(Some(s));
|
||||
}
|
||||
}
|
||||
Err(e) => error.set(Some(e.0)),
|
||||
}
|
||||
mb_importing.set(false);
|
||||
});
|
||||
})
|
||||
}}>
|
||||
{ if *mb_importing { "Starting import..." } else { "Import MusicBrainz Data" } }
|
||||
</button>
|
||||
</div>
|
||||
|
||||
// Metadata Providers
|
||||
<div class="card">
|
||||
<h3>{ "Metadata Providers" }</h3>
|
||||
|
||||
@@ -400,6 +400,8 @@ pub struct AppConfig {
|
||||
pub metadata: MetadataConfigFe,
|
||||
#[serde(default)]
|
||||
pub scheduling: SchedulingConfigFe,
|
||||
#[serde(default)]
|
||||
pub musicbrainz: MusicBrainzConfigFe,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
|
||||
@@ -513,3 +515,36 @@ fn default_lyrics_source() -> String {
|
||||
fn default_cover_art_source() -> String {
|
||||
"coverartarchive".into()
|
||||
}
|
||||
|
||||
// --- MusicBrainz local DB ---
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
|
||||
pub struct MusicBrainzConfigFe {
|
||||
#[serde(default)]
|
||||
pub local_db_path: Option<String>,
|
||||
#[serde(default)]
|
||||
pub auto_update: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
pub struct MbStatus {
|
||||
pub has_local_db: bool,
|
||||
#[serde(default)]
|
||||
pub stats: Option<MbLocalStats>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
pub struct MbLocalStats {
|
||||
#[serde(default)]
|
||||
pub artists: u64,
|
||||
#[serde(default)]
|
||||
pub release_groups: u64,
|
||||
#[serde(default)]
|
||||
pub releases: u64,
|
||||
#[serde(default)]
|
||||
pub recordings: u64,
|
||||
#[serde(default)]
|
||||
pub tracks: u64,
|
||||
#[serde(default)]
|
||||
pub last_import_date: Option<String>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user