fix(api): call /albums/releaseWatch as REST, not signed RPC

Third try's the charm. The previous attempt called the endpoint via
signed_get_auth (RPC-style with request_sig + request_ts), which
yielded 'no Service found with those values' — the RPC dispatcher
simply doesn't know this path.

The /albums/* plural namespace (releaseWatch, favoriteAlbums,
purchasedAlbums, similarTo, essential, artistAlbums, discoverAlbums)
is REST-style, not RPC. QBZ already uses the same pattern for the
/radio/* endpoints in src-tauri/src/api/client.rs: plain
.get(url).headers(authenticated_headers()).query(...) with X-App-Id
and X-User-Auth-Token, and no signing. Same pattern here.

Also reverted the release_watch container addition to
DiscoverContainers — /discover/index does not return it alongside
the editorial sections, confirmed by the empty result when reading
from there even with follows set.

Radio and Artist Spotlight work in QBZ via this same REST + auth
headers pattern despite being 'mobile' features; Release Watch
should too.

cc
This commit is contained in:
vicrodh committed 2026-04-13 23:23:07 -06:00
1 parent 60e0861e1d
commit b0e724d428
10 files changed
+174 -47

No files matched your search

+45
View File
@@ -258,6 +258,51 @@ pub async fn v2_get_featured_albums(
Ok(results)
}
/// Get Release Watch (V2 — releases from followed artists, labels and awards).
///
/// Calls the mobile "Radar de Novedades" endpoint (`/albums/releaseWatch`)
/// with authenticated headers (no RPC signing). Runs the result through the
/// artist blacklist filter.
#[tauri::command]
#[allow(non_snake_case)]
pub async fn v2_get_release_watch(
limit: Option<u32>,
offset: Option<u32>,
bridge: State<'_, CoreBridgeState>,
blacklist_state: State<'_, BlacklistState>,
runtime: State<'_, RuntimeManagerState>,
) -> Result<SearchResultsPage<Album>, RuntimeError> {
runtime
.manager()
.check_requirements(CommandRequirement::RequiresCoreBridgeAuth)
.await?;
let limit = limit.unwrap_or(20);
let offset = offset.unwrap_or(0);
log::info!("[V2] get_release_watch: limit={}, offset={}", limit, offset);
let bridge = bridge.get().await;
let mut results = bridge
.get_release_watch(limit, offset)
.await
.map_err(RuntimeError::Internal)?;
let original_count = results.items.len();
results
.items
.retain(|album| !blacklist_state.is_blacklisted(album.artist.id));
let filtered_count = original_count - results.items.len();
if filtered_count > 0 {
log::debug!(
"[V2/Blacklist] Filtered {} albums from release watch",
filtered_count
);
results.total = results.total.saturating_sub(filtered_count as u32);
}
Ok(results)
}
/// Get artist page (V2 - uses QbzCore)
#[tauri::command]
#[allow(non_snake_case)]
+12
View File
@@ -498,6 +498,18 @@ impl CoreBridge {
.map_err(|e| e.to_string())
}
/// Get Release Watch — releases from followed artists, labels and awards.
pub async fn get_release_watch(
&self,
limit: u32,
offset: u32,
) -> Result<SearchResultsPage<Album>, String> {
self.core
.get_release_watch(limit, offset)
.await
.map_err(|e| e.to_string())
}
/// Get artist page (full artist details with albums, tracks, similar)
pub async fn get_artist_page(
&self,
+1
View File
@@ -1594,6 +1594,7 @@ pub fn run() {
commands_v2::v2_get_playlist_tags,
commands_v2::v2_get_discover_albums,
commands_v2::v2_get_featured_albums,
commands_v2::v2_get_release_watch,
commands_v2::v2_get_artist_page,
commands_v2::v2_get_similar_artists,
commands_v2::v2_get_artist_with_albums,