Clippy
This commit is contained in:
@@ -85,18 +85,6 @@ pub async fn get_me() -> Result<UserInfo, ApiError> {
|
|||||||
get_json(&format!("{BASE}/auth/me")).await
|
get_json(&format!("{BASE}/auth/me")).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_users() -> Result<Vec<UserInfo>, ApiError> {
|
|
||||||
get_json(&format!("{BASE}/auth/users")).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_user(username: &str, password: &str) -> Result<UserInfo, ApiError> {
|
|
||||||
let body = serde_json::json!({"username": username, "password": password}).to_string();
|
|
||||||
post_json(&format!("{BASE}/auth/users"), &body).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn delete_user(id: i32) -> Result<(), ApiError> {
|
|
||||||
delete(&format!("{BASE}/auth/users/{id}")).await
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Lyrics ---
|
// --- Lyrics ---
|
||||||
pub async fn get_lyrics(artist: &str, title: &str) -> Result<LyricsResult, ApiError> {
|
pub async fn get_lyrics(artist: &str, title: &str) -> Result<LyricsResult, ApiError> {
|
||||||
@@ -142,10 +130,6 @@ pub async fn list_artists(limit: u64, offset: u64) -> Result<Vec<ArtistListItem>
|
|||||||
get_json(&format!("{BASE}/artists?limit={limit}&offset={offset}")).await
|
get_json(&format!("{BASE}/artists?limit={limit}&offset={offset}")).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_artist(id: i32) -> Result<ArtistDetail, ApiError> {
|
|
||||||
get_json(&format!("{BASE}/artists/{id}")).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_artist_full(id: &str) -> Result<FullArtistDetail, ApiError> {
|
pub async fn get_artist_full(id: &str) -> Result<FullArtistDetail, ApiError> {
|
||||||
get_json(&format!("{BASE}/artists/{id}/full")).await
|
get_json(&format!("{BASE}/artists/{id}/full")).await
|
||||||
}
|
}
|
||||||
@@ -158,9 +142,6 @@ pub async fn get_album(mbid: &str) -> Result<MbAlbumDetail, ApiError> {
|
|||||||
get_json(&format!("{BASE}/albums/{mbid}")).await
|
get_json(&format!("{BASE}/albums/{mbid}")).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_tracks(limit: u64, offset: u64) -> Result<Vec<Track>, ApiError> {
|
|
||||||
get_json(&format!("{BASE}/tracks?limit={limit}&offset={offset}")).await
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Watchlist ---
|
// --- Watchlist ---
|
||||||
pub async fn add_artist(name: &str, mbid: Option<&str>) -> Result<AddSummary, ApiError> {
|
pub async fn add_artist(name: &str, mbid: Option<&str>) -> Result<AddSummary, ApiError> {
|
||||||
@@ -183,13 +164,6 @@ pub async fn add_album(
|
|||||||
post_json(&format!("{BASE}/albums"), &body).await
|
post_json(&format!("{BASE}/albums"), &body).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_watchlist() -> Result<Vec<WatchListEntry>, ApiError> {
|
|
||||||
get_json(&format!("{BASE}/watchlist")).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn remove_watchlist(id: i32) -> Result<(), ApiError> {
|
|
||||||
delete(&format!("{BASE}/watchlist/{id}")).await
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Downloads ---
|
// --- Downloads ---
|
||||||
pub async fn get_downloads(status: Option<&str>) -> Result<Vec<DownloadItem>, ApiError> {
|
pub async fn get_downloads(status: Option<&str>) -> Result<Vec<DownloadItem>, ApiError> {
|
||||||
@@ -249,9 +223,6 @@ pub async fn trigger_organize() -> Result<TaskRef, ApiError> {
|
|||||||
post_empty(&format!("{BASE}/organize")).await
|
post_empty(&format!("{BASE}/organize")).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_task(id: &str) -> Result<TaskInfo, ApiError> {
|
|
||||||
get_json(&format!("{BASE}/tasks/{id}")).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_config() -> Result<AppConfig, ApiError> {
|
pub async fn get_config() -> Result<AppConfig, ApiError> {
|
||||||
get_json(&format!("{BASE}/config")).await
|
get_json(&format!("{BASE}/config")).await
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
pub mod navbar;
|
pub mod navbar;
|
||||||
pub mod status_badge;
|
pub mod status_badge;
|
||||||
pub mod watch_indicator;
|
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
use yew::prelude::*;
|
|
||||||
|
|
||||||
#[derive(Properties, PartialEq)]
|
|
||||||
pub struct Props {
|
|
||||||
pub status: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component(WatchIndicator)]
|
|
||||||
pub fn watch_indicator(props: &Props) -> Html {
|
|
||||||
let (icon, color, title) = match props.status.as_str() {
|
|
||||||
"owned" => ("●", "var(--success)", "Owned"),
|
|
||||||
"partial" => ("◐", "var(--warning)", "Partial"),
|
|
||||||
"wanted" => ("○", "var(--accent)", "Wanted"),
|
|
||||||
"downloading" => ("↓", "var(--accent)", "Downloading"),
|
|
||||||
"fully_watched" => ("●", "var(--accent)", "Fully watched"),
|
|
||||||
"unwatched" => ("○", "var(--text-muted)", "Not watched"),
|
|
||||||
_ => ("○", "var(--text-muted)", "Unknown"),
|
|
||||||
};
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<span style={format!("color: {color}; font-size: 1.1em; cursor: help;")} title={title}>
|
|
||||||
{ icon }
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -82,7 +82,7 @@ pub fn album_page(props: &Props) -> Html {
|
|||||||
<tbody>
|
<tbody>
|
||||||
{ for d.tracks.iter().map(|t| {
|
{ for d.tracks.iter().map(|t| {
|
||||||
let duration = t.duration_ms
|
let duration = t.duration_ms
|
||||||
.map(|ms| fmt_duration(ms))
|
.map(&fmt_duration)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let track_key = t.recording_mbid.clone();
|
let track_key = t.recording_mbid.clone();
|
||||||
|
|||||||
@@ -58,14 +58,11 @@ pub fn artist_page(props: &Props) -> Html {
|
|||||||
|
|
||||||
// Phase 2: if not enriched, fetch full data in background
|
// Phase 2: if not enriched, fetch full data in background
|
||||||
if needs_enrich && !user_acted.get() {
|
if needs_enrich && !user_acted.get() {
|
||||||
match api::get_artist_full(&id).await {
|
if let Ok(full) = api::get_artist_full(&id).await {
|
||||||
Ok(full) => {
|
// Only apply if user hasn't triggered a refresh
|
||||||
// Only apply if user hasn't triggered a refresh
|
if !user_acted.get() {
|
||||||
if !user_acted.get() {
|
detail.set(Some(full));
|
||||||
detail.set(Some(full));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(_) => {} // quick data is still showing, don't overwrite with error
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -326,8 +323,7 @@ pub fn artist_page(props: &Props) -> Html {
|
|||||||
<td>
|
<td>
|
||||||
if tc > 0 {
|
if tc > 0 {
|
||||||
<span class="text-sm" style={
|
<span class="text-sm" style={
|
||||||
if album.watched_tracks >= tc { "color: var(--accent);" }
|
if album.watched_tracks > 0 { "color: var(--accent);" }
|
||||||
else if album.watched_tracks > 0 { "color: var(--accent);" }
|
|
||||||
else { "color: var(--text-muted);" }
|
else { "color: var(--text-muted);" }
|
||||||
}>
|
}>
|
||||||
{ format!("{}/{}", album.watched_tracks, tc) }
|
{ format!("{}/{}", album.watched_tracks, tc) }
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ pub fn downloads_page() -> Html {
|
|||||||
let items = use_state(|| None::<Vec<DownloadItem>>);
|
let items = use_state(|| None::<Vec<DownloadItem>>);
|
||||||
let error = use_state(|| None::<String>);
|
let error = use_state(|| None::<String>);
|
||||||
let message = use_state(|| None::<String>);
|
let message = use_state(|| None::<String>);
|
||||||
let dl_query = use_state(|| String::new());
|
let dl_query = use_state(String::new);
|
||||||
|
|
||||||
let refresh = {
|
let refresh = {
|
||||||
let items = items.clone();
|
let items = items.clone();
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use yew::prelude::*;
|
|||||||
use yew_router::prelude::*;
|
use yew_router::prelude::*;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::components::watch_indicator::WatchIndicator;
|
|
||||||
use crate::pages::Route;
|
use crate::pages::Route;
|
||||||
use crate::types::ArtistListItem;
|
use crate::types::ArtistListItem;
|
||||||
|
|
||||||
@@ -73,8 +72,7 @@ pub fn library_page() -> Html {
|
|||||||
<td>
|
<td>
|
||||||
if a.total_items > 0 {
|
if a.total_items > 0 {
|
||||||
<span class="text-sm" style={
|
<span class="text-sm" style={
|
||||||
if a.total_watched >= a.total_items { "color: var(--accent);" }
|
if a.total_watched > 0 { "color: var(--accent);" }
|
||||||
else if a.total_watched > 0 { "color: var(--accent);" }
|
|
||||||
else { "color: var(--text-muted);" }
|
else { "color: var(--text-muted);" }
|
||||||
}>
|
}>
|
||||||
{ format!("{}/{}", a.total_watched, a.total_items) }
|
{ format!("{}/{}", a.total_watched, a.total_items) }
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ enum SearchResults {
|
|||||||
|
|
||||||
#[function_component(SearchPage)]
|
#[function_component(SearchPage)]
|
||||||
pub fn search_page() -> Html {
|
pub fn search_page() -> Html {
|
||||||
let query = use_state(|| String::new());
|
let query = use_state(String::new);
|
||||||
let search_type = use_state(|| "artist".to_string());
|
let search_type = use_state(|| "artist".to_string());
|
||||||
let results = use_state(|| SearchResults::None);
|
let results = use_state(|| SearchResults::None);
|
||||||
let error = use_state(|| None::<String>);
|
let error = use_state(|| None::<String>);
|
||||||
|
|||||||
@@ -97,16 +97,6 @@ pub struct LyricsResult {
|
|||||||
pub synced_lyrics: Option<String>,
|
pub synced_lyrics: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
|
||||||
pub struct Album {
|
|
||||||
pub id: i32,
|
|
||||||
pub name: String,
|
|
||||||
pub album_artist: String,
|
|
||||||
pub year: Option<i32>,
|
|
||||||
pub genre: Option<String>,
|
|
||||||
pub musicbrainz_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct Track {
|
pub struct Track {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
@@ -120,18 +110,6 @@ pub struct Track {
|
|||||||
pub codec: Option<String>,
|
pub codec: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct ArtistDetail {
|
|
||||||
pub artist: Artist,
|
|
||||||
pub albums: Vec<Album>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct AlbumDetail {
|
|
||||||
pub album: Album,
|
|
||||||
pub tracks: Vec<Track>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Album detail from MusicBrainz (the primary album view).
|
/// Album detail from MusicBrainz (the primary album view).
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
pub struct MbAlbumDetail {
|
pub struct MbAlbumDetail {
|
||||||
@@ -182,17 +160,6 @@ pub struct TrackResult {
|
|||||||
pub score: u8,
|
pub score: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Watchlist ---
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
pub struct WatchListEntry {
|
|
||||||
pub id: i32,
|
|
||||||
pub item_type: String,
|
|
||||||
pub name: String,
|
|
||||||
pub artist_name: Option<String>,
|
|
||||||
pub status: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Downloads ---
|
// --- Downloads ---
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
|
|||||||
@@ -623,16 +623,16 @@ async fn fetch_wikipedia_data(
|
|||||||
let cache_key = format!("artist_wiki:{mbid}");
|
let cache_key = format!("artist_wiki:{mbid}");
|
||||||
|
|
||||||
// Check cache first
|
// Check cache first
|
||||||
if let Ok(Some(json)) = queries::cache::get(state.db.conn(), &cache_key).await {
|
if let Ok(Some(json)) = queries::cache::get(state.db.conn(), &cache_key).await
|
||||||
if let Ok(cached) = serde_json::from_str::<serde_json::Value>(&json) {
|
&& let Ok(cached) = serde_json::from_str::<serde_json::Value>(&json)
|
||||||
return (
|
{
|
||||||
cached
|
return (
|
||||||
.get("photo_url")
|
cached
|
||||||
.and_then(|v| v.as_str())
|
.get("photo_url")
|
||||||
.map(String::from),
|
.and_then(|v| v.as_str())
|
||||||
cached.get("bio").and_then(|v| v.as_str()).map(String::from),
|
.map(String::from),
|
||||||
);
|
cached.get("bio").and_then(|v| v.as_str()).map(String::from),
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find Wikipedia URL from artist info — try direct link first, then resolve via Wikidata
|
// Find Wikipedia URL from artist info — try direct link first, then resolve via Wikidata
|
||||||
@@ -641,7 +641,7 @@ async fn fetch_wikipedia_data(
|
|||||||
Some(u.url.clone())
|
Some(u.url.clone())
|
||||||
} else if let Some(wd) = info.urls.iter().find(|u| u.link_type == "wikidata") {
|
} else if let Some(wd) = info.urls.iter().find(|u| u.link_type == "wikidata") {
|
||||||
// Extract Wikidata entity ID and resolve to Wikipedia URL
|
// Extract Wikidata entity ID and resolve to Wikipedia URL
|
||||||
let entity_id = wd.url.split('/').last().unwrap_or("");
|
let entity_id = wd.url.split('/').next_back().unwrap_or("");
|
||||||
resolve_wikidata_to_wikipedia(entity_id).await
|
resolve_wikidata_to_wikipedia(entity_id).await
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|||||||
Reference in New Issue
Block a user