several small ui updates, plus hopefully a track-matching fix

This commit is contained in:
Connor Johnstone
2026-04-01 22:32:52 -04:00
parent 4c42cf0131
commit 8193eebf13
5 changed files with 268 additions and 45 deletions
+119
View File
@@ -2,6 +2,7 @@ use actix_web::{HttpRequest, HttpResponse, web};
use std::collections::BTreeMap;
use shanty_db::queries;
use shanty_playlist::SimilarConfig;
use crate::state::AppState;
@@ -995,3 +996,121 @@ pub async fn get_artist_info2(req: HttpRequest, state: web::Data<AppState>) -> H
}),
)
}
/// GET /rest/getSimilarSongs2[.view]
pub async fn get_similar_songs2(req: HttpRequest, state: web::Data<AppState>) -> HttpResponse {
let (params, _user) = match authenticate(&req, &state).await {
Ok(v) => v,
Err(resp) => return resp,
};
let id_str = match get_query_param(&req, "id") {
Some(id) => id,
None => {
return response::error(
&params.format,
response::ERROR_MISSING_PARAM,
"missing required parameter: id",
);
}
};
let (_prefix, artist_id) = match parse_subsonic_id(&id_str) {
Some(v) => v,
None => {
return response::error(
&params.format,
response::ERROR_NOT_FOUND,
"invalid artist id",
);
}
};
let artist = match queries::artists::get_by_id(state.db.conn(), artist_id).await {
Ok(a) => a,
Err(_) => {
return response::error(
&params.format,
response::ERROR_NOT_FOUND,
"artist not found",
);
}
};
let count: usize = get_query_param(&req, "count")
.and_then(|v| v.parse().ok())
.unwrap_or(50);
// Need a Last.fm API key for similar artist lookups
let config = state.config.read().await;
let lastfm_key = config.metadata.lastfm_api_key.clone();
drop(config);
let api_key = match lastfm_key {
Some(k) if !k.is_empty() => k,
_ => {
return response::ok(
&params.format,
serde_json::json!({ "similarSongs2": { "song": [] } }),
);
}
};
let fetcher = match shanty_data::LastFmSimilarFetcher::new(api_key) {
Ok(f) => f,
Err(_) => {
return response::ok(
&params.format,
serde_json::json!({ "similarSongs2": { "song": [] } }),
);
}
};
let similar_config = SimilarConfig {
count,
popularity_bias: 5,
ordering: "random".to_string(),
discovery_range: 5,
global_popularity: 0,
country_filter: false,
seed_weight: 3,
max_tracks_per_artist: None,
max_artists: None,
};
let result = shanty_playlist::similar_artists(
state.db.conn(),
&fetcher,
vec![artist.name],
&similar_config,
None,
)
.await;
let songs: Vec<serde_json::Value> = match result {
Ok(playlist) => {
let mut songs = Vec::new();
for pt in &playlist.tracks {
if let Ok(track) =
queries::tracks::get_by_id(state.db.conn(), pt.track_id).await
{
songs.push(
serde_json::to_value(SubsonicChild::from_track(&track))
.unwrap_or_default(),
);
}
}
songs
}
Err(_) => vec![],
};
response::ok(
&params.format,
serde_json::json!({
"similarSongs2": {
"song": songs,
}
}),
)
}
+8
View File
@@ -73,6 +73,14 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
"/getArtistInfo2.view",
web::get().to(browsing::get_artist_info2),
)
.route(
"/getSimilarSongs2",
web::get().to(browsing::get_similar_songs2),
)
.route(
"/getSimilarSongs2.view",
web::get().to(browsing::get_similar_songs2),
)
// Search
.route("/search3", web::get().to(search::search3))
.route("/search3.view", web::get().to(search::search3))