several small ui updates, plus hopefully a track-matching fix
This commit is contained in:
@@ -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(
|
||||
¶ms.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(
|
||||
¶ms.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(
|
||||
¶ms.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(
|
||||
¶ms.format,
|
||||
serde_json::json!({ "similarSongs2": { "song": [] } }),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let fetcher = match shanty_data::LastFmSimilarFetcher::new(api_key) {
|
||||
Ok(f) => f,
|
||||
Err(_) => {
|
||||
return response::ok(
|
||||
¶ms.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(
|
||||
¶ms.format,
|
||||
serde_json::json!({
|
||||
"similarSongs2": {
|
||||
"song": songs,
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user