I confused StreamInfo (the big single-video struct, has uploader_avatars: ImageSet) with StreamInfoItem (the card struct used in search results / channel video lists / related streams — no uploader_avatars field). cargoBuildHost caught it: E0609 no field `uploader_avatars`. Drop the field from SearchItem (and from the Kotlin construction sites). For the subs feed and "more from this channel" we already use the channel-level avatar from ChannelInfo.avatar, which is the right granularity anyway (every video from one channel shares one avatar). Per-card uploader avatars on search/related stay null until strawcore-core extracts them on StreamInfoItem too.
66 lines
2.1 KiB
Rust
66 lines
2.1 KiB
Rust
// Phase 7 — search via Sulkta-Coop/strawcore-core. Exposed to Kotlin
|
|
// as a suspend fun. SearchItem field shape is unchanged from Phase U-2
|
|
// so Kotlin callers (SearchViewModel) keep working with no code
|
|
// changes.
|
|
|
|
use strawcore_core::stream::StreamInfoItem;
|
|
use strawcore_core::youtube::linkhandler::search::SearchFilter;
|
|
use strawcore_core::youtube::search_extractor;
|
|
|
|
use crate::error::StrawcoreError;
|
|
|
|
#[derive(Debug, Clone, uniffi::Record)]
|
|
pub struct SearchItem {
|
|
pub url: String,
|
|
pub title: String,
|
|
pub uploader: String,
|
|
pub uploader_url: Option<String>,
|
|
pub thumbnail: Option<String>,
|
|
/// Duration in seconds. 0 = live/unknown.
|
|
pub duration_seconds: i64,
|
|
/// Reported view count. 0 = unknown.
|
|
pub view_count: i64,
|
|
/// Relative upload date as YT renders it ("2 days ago", "3 weeks
|
|
/// ago"). Empty if not extracted. Strawcore-core already populates
|
|
/// this on StreamInfoItem; we just pass it through.
|
|
pub upload_date_relative: String,
|
|
}
|
|
|
|
pub(crate) fn from_core(item: StreamInfoItem) -> SearchItem {
|
|
let uploader_url = if item.uploader_url.is_empty() {
|
|
None
|
|
} else {
|
|
Some(item.uploader_url)
|
|
};
|
|
let thumbnail = item
|
|
.thumbnails
|
|
.last()
|
|
.map(|i| i.url().to_string());
|
|
SearchItem {
|
|
url: item.url,
|
|
title: item.name,
|
|
uploader: item.uploader_name,
|
|
uploader_url,
|
|
thumbnail,
|
|
duration_seconds: item.duration_seconds,
|
|
view_count: if item.view_count < 0 {
|
|
0
|
|
} else {
|
|
item.view_count
|
|
},
|
|
upload_date_relative: item.upload_date_relative,
|
|
}
|
|
}
|
|
|
|
#[uniffi::export(async_runtime = "tokio")]
|
|
pub async fn search(query: String) -> Result<Vec<SearchItem>, StrawcoreError> {
|
|
log::info!("strawcore::search query={}", query);
|
|
let result = tokio::task::spawn_blocking(move || {
|
|
search_extractor::search(&query, SearchFilter::Videos)
|
|
})
|
|
.await
|
|
.map_err(|e| StrawcoreError::Extractor {
|
|
msg: format!("join: {e}"),
|
|
})??;
|
|
Ok(result.videos.into_iter().map(from_core).collect())
|
|
}
|