Fix duplicate rows, episode missing, and latest episode number mismatch bugs

This commit is contained in:
tvmon-dev
2026-04-15 20:31:52 +09:00
parent f4db19329f
commit 9a7ea53c1e
3 changed files with 30 additions and 15 deletions

View File

@@ -412,35 +412,39 @@ val episodes = mutableListOf<Episode>()
val seenEpisodeIds = mutableSetOf<String>() val seenEpisodeIds = mutableSetOf<String>()
val seriesId = seriesUrl.substringAfterLast("/").substringBefore("?") val seriesId = seriesUrl.substringAfterLast("/").substringBefore("?")
val allEpisodeLinks = doc.select(".next-ep-list-scroll .ep-item, .ep-item, .bo_v_list li a, #bo_v_list li a, .list_body .item a, .ep-list a")
val allEpisodeLinks = doc.select(
".next-ep-list-scroll .ep-item, .ep-item, .bo_v_list li a, #bo_v_list li a, " +
".list_body .item a, .ep-list a, .episode-list a, .ep-link a, " +
"a[href*='/$seriesId/'], a[href*='/${seriesId}/']"
)
for (link in allEpisodeLinks) { for (link in allEpisodeLinks) {
val href = link.attr("href") val href = link.attr("href")
if (href.isBlank()) continue if (href.isBlank()) continue
if (!href.contains("/$seriesId/")) continue
val fullUrl = resolveUrl(href) val fullUrl = resolveUrl(href)
val episodeIdMatch = Pattern.compile("/(\\d+)/(\\d+)$").matcher(href) val episodeIdMatch = Pattern.compile("/$seriesId/(\\d+)").matcher(href)
if (!episodeIdMatch.find()) continue if (!episodeIdMatch.find()) continue
val episodeId = episodeIdMatch.group(2) ?: "" val episodeId = episodeIdMatch.group(1) ?: ""
if (episodeId in seenEpisodeIds) continue if (episodeId in seenEpisodeIds) continue
seenEpisodeIds.add(episodeId) seenEpisodeIds.add(episodeId)
val titleEl = link.selectFirst(".ep-item-title, .item-title, strong, span") val titleEl = link.selectFirst(".ep-item-title, .item-title, strong, span, .title")
val linkText = titleEl?.text()?.trim() ?: link.text().trim() val linkText = titleEl?.text()?.trim() ?: link.text().trim()
val episodeNumMatch = Pattern.compile("(\\d+ 화|\\d+ 회|EP?\\d+|제?\\d+부?|\\d+)").matcher(linkText) val episodeNumMatch = Pattern.compile("(\\d+)\\s*화|(\\d+)\\s*회|EP\\.?(\\d+)|제\\s*(\\d+)\\s*부").matcher(linkText)
val episodeTitle = if (episodeNumMatch.find()) { val episodeTitle = if (episodeNumMatch.find()) {
episodeNumMatch.group(1) episodeNumMatch.group(1) ?: episodeNumMatch.group(2) ?: episodeNumMatch.group(3) ?: episodeNumMatch.group(4) ?: episodeId
} else { } else {
"Episode ${episodes.size + 1}" episodeId
} }
episodes.add(Episode( episodes.add(Episode(
number = episodeTitle ?: "Episode ${episodes.size + 1}", number = episodeTitle,
title = linkText.ifBlank { episodeTitle ?: "Episode ${episodes.size + 1}" }, title = linkText.ifBlank { episodeTitle },
url = fullUrl, url = fullUrl,
type = "webview" type = "webview"
)) ))
@@ -448,7 +452,7 @@ val episodes = mutableListOf<Episode>()
videoLinks.add(VideoLink( videoLinks.add(VideoLink(
type = "play_page", type = "play_page",
url = fullUrl, url = fullUrl,
title = linkText.ifBlank { episodeTitle ?: "Episode ${videoLinks.size + 1}" } title = linkText.ifBlank { episodeTitle }
)) ))
} }

View File

@@ -255,11 +255,15 @@ class DetailsFragment : DetailsSupportFragment() {
val row = ListRow(header, episodesRowAdapter) val row = ListRow(header, episodesRowAdapter)
activity?.runOnUiThread { activity?.runOnUiThread {
if (episodesRowIndex >= 0 && episodesRowIndex < rowsAdapter.size()) { if (existingRowIndex >= 0 && existingRowIndex < rowsAdapter.size()) {
rowsAdapter.add(existingRowIndex, row)
} else {
if (episodesRowIndex >= 0 && episodesRowIndex <= rowsAdapter.size()) {
rowsAdapter.add(episodesRowIndex, row) rowsAdapter.add(episodesRowIndex, row)
} else { } else {
rowsAdapter.add(row) rowsAdapter.add(row)
} }
}
Log.w(TAG, "loadDetailInfo: Added episodes row at index $episodesRowIndex, rowsAdapter size=${rowsAdapter.size()}") Log.w(TAG, "loadDetailInfo: Added episodes row at index $episodesRowIndex, rowsAdapter size=${rowsAdapter.size()}")
} }
} }

View File

@@ -37,6 +37,7 @@ class MainFragment : BrowseSupportFragment(), OnItemViewClickedListener, OnItemV
private val categoryRowAdapters = mutableMapOf<String, ArrayObjectAdapter>() private val categoryRowAdapters = mutableMapOf<String, ArrayObjectAdapter>()
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private var currentSelectedRowIndex = -1 private var currentSelectedRowIndex = -1
private var isDataLoaded = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -53,7 +54,11 @@ class MainFragment : BrowseSupportFragment(), OnItemViewClickedListener, OnItemV
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
Log.w(TAG, "=== MainFragment onStart ===") Log.w(TAG, "=== MainFragment onStart ===")
if (!isDataLoaded) {
loadData() loadData()
} else {
Log.w(TAG, "Data already loaded, skipping reload")
}
} }
override fun onDestroy() { override fun onDestroy() {
@@ -219,6 +224,8 @@ private fun loadNextPage(categoryKey: String, page: Int) {
Log.w(TAG, "=== loadCategories COMPLETE: success=$successCount, fail=$failCount ===") Log.w(TAG, "=== loadCategories COMPLETE: success=$successCount, fail=$failCount ===")
Log.w(TAG, "rowsAdapter size: ${rowsAdapter.size()}") Log.w(TAG, "rowsAdapter size: ${rowsAdapter.size()}")
isDataLoaded = true
activity?.runOnUiThread { activity?.runOnUiThread {
if (rowsAdapter.size() == 0) { if (rowsAdapter.size() == 0) {
Toast.makeText(requireContext(), "카테고리를 불러오지 못했습니다", Toast.LENGTH_LONG).show() Toast.makeText(requireContext(), "카테고리를 불러오지 못했습니다", Toast.LENGTH_LONG).show()