From 93297ad0a026f382baeace6fee3b9077d20ade07 Mon Sep 17 00:00:00 2001 From: Kayos Date: Sun, 24 May 2026 12:56:32 -0700 Subject: [PATCH] Path C-3: SearchViewModel swap to uniffi.strawcore.search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops NewPipeExtractor from the search code path. The bindgen-generated `search()` is a Kotlin suspend fun running on the tokio runtime baked into libstrawcore.so — no Dispatchers.IO wrapper needed. NPE still drives VideoDetail / Player / Channel / sub feed; those move to rustypipe in C-4 / C-5 / C-6. --- .../straw/feature/search/SearchViewModel.kt | 44 +++++++------------ 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/strawApp/src/main/kotlin/com/sulkta/straw/feature/search/SearchViewModel.kt b/strawApp/src/main/kotlin/com/sulkta/straw/feature/search/SearchViewModel.kt index 5ef859be4..338388af9 100644 --- a/strawApp/src/main/kotlin/com/sulkta/straw/feature/search/SearchViewModel.kt +++ b/strawApp/src/main/kotlin/com/sulkta/straw/feature/search/SearchViewModel.kt @@ -8,17 +8,10 @@ package com.sulkta.straw.feature.search import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.sulkta.straw.data.History -import com.sulkta.straw.util.bestThumbnail -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.schabi.newpipe.extractor.NewPipe -import org.schabi.newpipe.extractor.ServiceList -import org.schabi.newpipe.extractor.search.SearchInfo -import org.schabi.newpipe.extractor.stream.StreamInfoItem data class SearchUiState( val query: String = "", @@ -52,7 +45,23 @@ class SearchViewModel : ViewModel() { _ui.value = _ui.value.copy(loading = true, error = null, results = emptyList()) viewModelScope.launch { try { - val items = withContext(Dispatchers.IO) { search(q) } + // Phase U-2 / Path C-3: rustypipe via UniFFI. The bindgen-generated + // `search()` is already a suspend fun running on the tokio runtime + // baked into libstrawcore.so — no Dispatchers.IO wrapper needed, + // the JNI call returns to us on the caller dispatcher when the + // future completes. + val rustItems = uniffi.strawcore.search(q) + val items = rustItems.map { r -> + StreamItem( + url = r.url, + title = r.title.ifBlank { "(no title)" }, + uploader = r.uploader, + uploaderUrl = r.uploaderUrl, + thumbnail = r.thumbnail, + durationSeconds = r.durationSeconds, + viewCount = r.viewCount, + ) + } _ui.value = _ui.value.copy(loading = false, results = items) } catch (t: Throwable) { _ui.value = _ui.value.copy( @@ -62,23 +71,4 @@ class SearchViewModel : ViewModel() { } } } - - private fun search(query: String): List { - val service = NewPipe.getService(ServiceList.YouTube.serviceId) - val qh = service.searchQHFactory.fromQuery(query, emptyList(), "") - val info = SearchInfo.getInfo(service, qh) - return info.relatedItems - .filterIsInstance() - .map { - StreamItem( - url = it.url, - title = it.name ?: "(no title)", - uploader = it.uploaderName ?: "", - uploaderUrl = it.uploaderUrl, - thumbnail = bestThumbnail(it.thumbnails), - durationSeconds = it.duration, - viewCount = it.viewCount, - ) - } - } }