From 15e13d9e373472d5412f0675846be81f685ec622 Mon Sep 17 00:00:00 2001 From: xiaji Date: Tue, 9 Jun 2026 20:39:27 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20TvcatHandler=E6=90=9C=E7=B4=A2=E5=92=8C?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E7=94=A8HttpURLConnection=E6=9B=BF=E4=BB=A3J?= =?UTF-8?q?soup=E4=B8=8B=E8=BD=BD=EF=BC=8C=E7=BB=95=E8=BF=87Jsoup=E9=BB=98?= =?UTF-8?q?=E8=AE=A4UA=E8=A2=AB=E5=8F=8D=E7=88=AC=E6=8B=A6=E6=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../videoapp/tv/engine/tvcat/TvcatHandler.kt | 83 ++++++++++++++++++- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/videoapp/tv/engine/tvcat/TvcatHandler.kt b/app/src/main/java/com/videoapp/tv/engine/tvcat/TvcatHandler.kt index 3ad6a55..154587e 100644 --- a/app/src/main/java/com/videoapp/tv/engine/tvcat/TvcatHandler.kt +++ b/app/src/main/java/com/videoapp/tv/engine/tvcat/TvcatHandler.kt @@ -1,5 +1,6 @@ package com.videoapp.tv.engine.tvcat +import com.videoapp.tv.data.SearchResult import com.videoapp.tv.data.SiteConfig import com.videoapp.tv.engine.BaseSourceHandler import com.videoapp.tv.engine.Episode @@ -8,7 +9,9 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.json.JSONObject import org.jsoup.Jsoup +import java.net.HttpURLConnection import java.net.URL +import java.net.URLEncoder class TvcatHandler : BaseSourceHandler( id = "tvcat", @@ -33,12 +36,84 @@ class TvcatHandler : BaseSourceHandler( videoSelector = "video source, video[src]" ) ) { + override suspend fun search( + keyword: String, + onResult: suspend (List) -> Unit, + onError: suspend (String) -> Unit + ) { + try { + val results = withContext(Dispatchers.IO) { + val encoded = URLEncoder.encode(keyword, "UTF-8") + val searchUrl = "https://tvcat.cc/search?q=$encoded" + val conn = URL(searchUrl).openConnection() as HttpURLConnection + conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") + conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.9") + conn.connectTimeout = 15000 + conn.readTimeout = 15000 + val html = if (conn.responseCode == 200) { + conn.inputStream.bufferedReader().use { it.readText() } + } else "" + conn.disconnect() + + if (html.isEmpty()) return@withContext emptyList() + + val doc = Jsoup.parse(html) + val items = doc.select("li.col-md-2.col-sm-3.col-4") + val resultsList = mutableListOf() + + for (item in items) { + try { + val titleEl = item.selectFirst("a[title]") ?: continue + val linkEl = item.selectFirst("a") + val coverEl = item.selectFirst("img") + val categoryEl = item.selectFirst(".text-muted") + + val title = titleEl.text().trim() + val detailUrl = buildFullUrl(linkEl?.attr("href")?.trim() ?: "") + val coverUrl = buildFullUrl(coverEl?.attr("src")?.trim() ?: "") + val category = categoryEl?.text()?.trim() ?: "" + + if (title.isNotEmpty() && detailUrl.isNotEmpty()) { + resultsList.add( + SearchResult( + title = title, + coverUrl = coverUrl, + detailUrl = detailUrl, + category = category, + date = "" + ) + ) + } + } catch (_: Exception) { + } + } + resultsList + } + + if (results.isEmpty()) { + onError("未找到结果") + } else { + onResult(results) + } + } catch (e: Exception) { + onError("搜索失败: ${e.message}") + } + } + override suspend fun extractVideos(detailUrl: String): List = withContext(Dispatchers.IO) { - val doc = Jsoup.connect(detailUrl) - .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") - .header("Accept-Language", "zh-CN,zh;q=0.9") - .timeout(15000).get() + val conn = URL(detailUrl).openConnection() as HttpURLConnection + conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") + conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.9") + conn.connectTimeout = 15000 + conn.readTimeout = 15000 + val html = if (conn.responseCode == 200) { + conn.inputStream.bufferedReader().use { it.readText() } + } else "" + conn.disconnect() + if (html.isEmpty()) return@withContext emptyList() + + val doc = Jsoup.parse(html) val episodes = doc.select("li.list-inline-item a").mapNotNull { ep -> val title = ep.text().trim() val href = ep.attr("href").trim()