Fix episode number matching, add scroll-based preloading, and fix search UI

This commit is contained in:
tvmon-dev
2026-04-15 20:45:28 +09:00
parent 9a7ea53c1e
commit dae2fa6082
7 changed files with 75 additions and 36 deletions

View File

@@ -58,7 +58,8 @@
android:name=".ui.search.SearchActivity"
android:exported="true"
android:label="@string/search_title"
android:theme="@style/Theme.Tvmon.Search">
android:screenOrientation="landscape"
android:theme="@style/Theme.Leanback">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>

View File

@@ -410,6 +410,7 @@ class TvmonScraper {
val episodes = mutableListOf<Episode>()
val videoLinks = mutableListOf<VideoLink>()
val seenEpisodeIds = mutableSetOf<String>()
val seenNumbers = mutableSetOf<String>()
val seriesId = seriesUrl.substringAfterLast("/").substringBefore("?")
@@ -437,14 +438,18 @@ val episodes = mutableListOf<Episode>()
val episodeNumMatch = Pattern.compile("(\\d+)\\s*화|(\\d+)\\s*회|EP\\.?(\\d+)|제\\s*(\\d+)\\s*부").matcher(linkText)
val episodeTitle = if (episodeNumMatch.find()) {
episodeNumMatch.group(1) ?: episodeNumMatch.group(2) ?: episodeNumMatch.group(3) ?: episodeNumMatch.group(4) ?: episodeId
episodeNumMatch.group(1) ?: episodeNumMatch.group(2) ?: episodeNumMatch.group(3) ?: episodeNumMatch.group(4)
} else {
episodeId
null
}
val finalNumber = episodeTitle ?: episodeId
if (finalNumber in seenNumbers) continue
seenNumbers.add(finalNumber)
episodes.add(Episode(
number = episodeTitle,
title = linkText.ifBlank { episodeTitle },
number = finalNumber,
title = linkText.ifBlank { finalNumber },
url = fullUrl,
type = "webview"
))
@@ -452,7 +457,7 @@ val episodes = mutableListOf<Episode>()
videoLinks.add(VideoLink(
type = "play_page",
url = fullUrl,
title = linkText.ifBlank { episodeTitle }
title = linkText.ifBlank { finalNumber }
))
}

View File

@@ -24,7 +24,7 @@ class MainFragment : BrowseSupportFragment(), OnItemViewClickedListener, OnItemV
companion object {
private const val TAG = "TVMON_MAIN"
private const val PRELOAD_THRESHOLD = 5 // 로딩 시작 위치
private const val PRELOAD_THRESHOLD = 20
}
private val scraper: TvmonScraper by inject()
@@ -38,6 +38,8 @@ class MainFragment : BrowseSupportFragment(), OnItemViewClickedListener, OnItemV
private val handler = Handler(Looper.getMainLooper())
private var currentSelectedRowIndex = -1
private var isDataLoaded = false
private var lastPreloadedPage = mutableMapOf<String, Int>()
private var currentCategoryKey: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -312,8 +314,24 @@ private fun loadNextPage(categoryKey: String, page: Int) {
if (row is ListRow) {
val rowIndex = rowsAdapter.indexOf(row)
if (rowIndex >= 0) {
val categoryKey = findCategoryKeyForRow(rowIndex)
currentCategoryKey = categoryKey
handleRowSelection(rowIndex)
}
}
}
private fun checkAndPreload(categoryKey: String, position: Int) {
if (position >= PRELOAD_THRESHOLD) {
val currentPage = categoryPages[categoryKey] ?: 1
val maxPage = categoryMaxPage[categoryKey] ?: 1
val lastPreload = lastPreloadedPage[categoryKey] ?: 0
if (currentPage < maxPage && currentPage > lastPreload) {
Log.w(TAG, "checkAndPreload: $categoryKey at position $position, preloading page ${currentPage + 1}")
lastPreloadedPage[categoryKey] = currentPage
preloadNextPage(categoryKey, currentPage + 1)
}
}
}
}

View File

@@ -1,6 +1,5 @@
package com.example.tvmon.ui.search
import android.app.SearchManager
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
@@ -17,23 +16,20 @@ import org.koin.android.ext.android.inject
class SearchActivity : AppCompatActivity() {
companion object {
private const val TAG = "TVMON_SEARCH"
}
private val scraper: TvmonScraper by inject()
private lateinit var searchView: SearchView
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: SearchResultsAdapter
private lateinit var searchView: SearchView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search)
setupUI()
if (Intent.ACTION_SEARCH == intent.action) {
val query = intent.getStringExtra(SearchManager.QUERY)
if (!query.isNullOrBlank()) {
search(query)
}
}
}
private fun setupUI() {
@@ -43,19 +39,27 @@ class SearchActivity : AppCompatActivity() {
adapter = SearchResultsAdapter { content ->
openDetail(content)
}
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
if (!query.isNullOrBlank()) {
search(query)
query?.let {
if (it.isNotBlank()) {
search(it)
}
}
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
return false
newText?.let {
if (it.length >= 2) {
search(it)
}
}
return true
}
})
@@ -65,11 +69,13 @@ class SearchActivity : AppCompatActivity() {
private fun search(query: String) {
lifecycleScope.launch {
val result = scraper.search(query)
runOnUiThread {
if (result.success) {
adapter.updateResults(result.results)
}
}
}
}
private fun openDetail(content: Content) {
val intent = Intent(this, DetailsActivity::class.java).apply {

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#333333" />
<corners android:radius="8dp" />
<padding android:left="16dp" android:right="16dp" android:top="12dp" android:bottom="12dp" />
</shape>

View File

@@ -3,7 +3,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
android:background="@color/default_background"
android:padding="32dp">
<androidx.appcompat.widget.SearchView
android:id="@+id/search_view"
@@ -16,5 +17,6 @@
android:id="@+id/search_results"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp" />
android:layout_marginTop="24dp" />
</LinearLayout>

View File

@@ -1,6 +1,6 @@
{
"versionCode": 1,
"versionName": "1.0.0",
"apkUrl": "https://git.webpluss.net/sanjeok77/NeFLIX_release/releases/download/v1.0.0/app-release.apk",
"updateMessage": "tvmon v1.0.0 - Android TV app with pagination fix and cast display improvements"
"versionCode": 2,
"versionName": "1.0.1",
"apkUrl": "https://git.webpluss.net/sanjeok77/tvmon_release/releases/download/v1.0.1/app-release.apk",
"updateMessage": "v1.0.1 - Bug fixes"
}