fix: resolve emulator crash - thread safety and icon fallback

- NativeSearch: move onResult/onError callbacks outside withContext(Dispatchers.IO) to prevent CalledFromWrongThreadException
- SearchStrategy: change callback types to suspend to enable proper coroutine chaining
- SearchCoordinator: remove leaked CoroutineScope, rely on suspend callback chaining for fallback flow
- Resources: add mipmap-hdpi/mdpi/xhdpi/xxhdpi icon fallbacks for API < 26 devices
This commit is contained in:
xiaji
2026-05-24 21:09:05 +08:00
commit 98d05aa90a
57 changed files with 2366 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
package com.videoapp.tv.util
import com.videoapp.tv.data.SiteConfig
import org.jsoup.Jsoup
object JsoupHelper {
fun escapeCssSelector(selector: String): String {
return selector.replace("\"", "\\\"").replace("'", "\\'")
}
suspend fun testSelector(
url: String,
selector: String
): List<String> = kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) {
try {
val doc = Jsoup.connect(url).timeout(10000).get()
doc.select(selector).map { it.text().trim() }
} catch (e: Exception) {
emptyList()
}
}
fun buildSearchPostData(config: SiteConfig, keyword: String): Map<String, String> {
val data = mutableMapOf<String, String>()
data[config.keywordParam] = keyword
data.putAll(config.extraParams)
return data
}
}

View File

@@ -0,0 +1,25 @@
package com.videoapp.tv.util
import android.content.Context
import android.webkit.WebView
object WebViewPool {
private var sharedWebView: WebView? = null
fun get(context: Context): WebView {
return sharedWebView ?: createNew(context).also { sharedWebView = it }
}
private fun createNew(context: Context): WebView {
return WebView(context.applicationContext).apply {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.mediaPlaybackRequiresUserGesture = false
}
}
fun release() {
sharedWebView?.destroy()
sharedWebView = null
}
}