From f65e3b9f3502d8c519dad6fc8f26a8706160c148 Mon Sep 17 00:00:00 2001 From: tvmon-dev Date: Thu, 16 Apr 2026 08:17:28 +0900 Subject: [PATCH] Add CategoryContent entity, DAO, and CategoryCacheRepository --- tvmon-app/app/src/main/AndroidManifest.xml | 13 +- .../example/tvmon/data/local/AppDatabase.kt | 8 +- .../data/local/dao/CategoryContentDao.kt | 37 +++ .../data/local/entity/CategoryContent.kt | 16 ++ .../repository/CategoryCacheRepository.kt | 132 ++++++++++ .../java/com/example/tvmon/di/AppModule.kt | 9 +- .../com/example/tvmon/ui/main/MainFragment.kt | 244 +++++------------- .../tvmon/ui/playback/PlaybackActivity.kt | 26 +- 8 files changed, 273 insertions(+), 212 deletions(-) create mode 100644 tvmon-app/app/src/main/java/com/example/tvmon/data/local/dao/CategoryContentDao.kt create mode 100644 tvmon-app/app/src/main/java/com/example/tvmon/data/local/entity/CategoryContent.kt create mode 100644 tvmon-app/app/src/main/java/com/example/tvmon/data/repository/CategoryCacheRepository.kt diff --git a/tvmon-app/app/src/main/AndroidManifest.xml b/tvmon-app/app/src/main/AndroidManifest.xml index 74543c9..c68c3be 100644 --- a/tvmon-app/app/src/main/AndroidManifest.xml +++ b/tvmon-app/app/src/main/AndroidManifest.xml @@ -54,12 +54,13 @@ android:screenOrientation="landscape" android:theme="@style/Theme.Tvmon.Search" /> - + diff --git a/tvmon-app/app/src/main/java/com/example/tvmon/data/local/AppDatabase.kt b/tvmon-app/app/src/main/java/com/example/tvmon/data/local/AppDatabase.kt index c61cf45..f18b958 100644 --- a/tvmon-app/app/src/main/java/com/example/tvmon/data/local/AppDatabase.kt +++ b/tvmon-app/app/src/main/java/com/example/tvmon/data/local/AppDatabase.kt @@ -3,9 +3,11 @@ package com.example.tvmon.data.local import androidx.room.Database import androidx.room.RoomDatabase import com.example.tvmon.data.local.dao.BookmarkDao +import com.example.tvmon.data.local.dao.CategoryContentDao import com.example.tvmon.data.local.dao.SearchHistoryDao import com.example.tvmon.data.local.dao.WatchHistoryDao import com.example.tvmon.data.local.entity.Bookmark +import com.example.tvmon.data.local.entity.CategoryContent import com.example.tvmon.data.local.entity.SearchHistory import com.example.tvmon.data.local.entity.WatchHistory @@ -13,13 +15,15 @@ import com.example.tvmon.data.local.entity.WatchHistory entities = [ WatchHistory::class, Bookmark::class, - SearchHistory::class + SearchHistory::class, + CategoryContent::class ], - version = 1, + version = 2, exportSchema = false ) abstract class AppDatabase : RoomDatabase() { abstract fun watchHistoryDao(): WatchHistoryDao abstract fun bookmarkDao(): BookmarkDao abstract fun searchHistoryDao(): SearchHistoryDao + abstract fun categoryContentDao(): CategoryContentDao } diff --git a/tvmon-app/app/src/main/java/com/example/tvmon/data/local/dao/CategoryContentDao.kt b/tvmon-app/app/src/main/java/com/example/tvmon/data/local/dao/CategoryContentDao.kt new file mode 100644 index 0000000..d6e59df --- /dev/null +++ b/tvmon-app/app/src/main/java/com/example/tvmon/data/local/dao/CategoryContentDao.kt @@ -0,0 +1,37 @@ +package com.example.tvmon.data.local.dao + +import androidx.room.* +import com.example.tvmon.data.local.entity.CategoryContent + +@Dao +interface CategoryContentDao { + @Query("SELECT * FROM category_content WHERE categoryKey = :categoryKey ORDER BY cachedAt ASC") + suspend fun getByCategory(categoryKey: String): List + + @Query("SELECT * FROM category_content WHERE categoryKey = :categoryKey AND pageNumber <= :page ORDER BY cachedAt ASC") + suspend fun getByCategoryUntilPage(categoryKey: String, page: Int): List + + @Query("SELECT MAX(pageNumber) FROM category_content WHERE categoryKey = :categoryKey") + suspend fun getMaxPage(categoryKey: String): Int? + + @Query("SELECT MAX(cachedAt) FROM category_content WHERE categoryKey = :categoryKey") + suspend fun getLastCacheTime(categoryKey: String): Long? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(contents: List) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertOne(content: CategoryContent) + + @Query("DELETE FROM category_content WHERE categoryKey = :categoryKey") + suspend fun deleteByCategory(categoryKey: String) + + @Query("DELETE FROM category_content WHERE categoryKey = :categoryKey AND pageNumber >= :fromPage") + suspend fun deleteFromPage(categoryKey: String, fromPage: Int) + + @Query("SELECT COUNT(*) FROM category_content WHERE categoryKey = :categoryKey") + suspend fun getCount(categoryKey: String): Int + + @Query("DELETE FROM category_content") + suspend fun deleteAll() +} \ No newline at end of file diff --git a/tvmon-app/app/src/main/java/com/example/tvmon/data/local/entity/CategoryContent.kt b/tvmon-app/app/src/main/java/com/example/tvmon/data/local/entity/CategoryContent.kt new file mode 100644 index 0000000..ddd9132 --- /dev/null +++ b/tvmon-app/app/src/main/java/com/example/tvmon/data/local/entity/CategoryContent.kt @@ -0,0 +1,16 @@ +package com.example.tvmon.data.local.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "category_content") +data class CategoryContent( + @PrimaryKey + val contentUrl: String, + val categoryKey: String, + val contentId: String, + val title: String, + val thumbnail: String, + val pageNumber: Int = 1, + val cachedAt: Long = System.currentTimeMillis() +) \ No newline at end of file diff --git a/tvmon-app/app/src/main/java/com/example/tvmon/data/repository/CategoryCacheRepository.kt b/tvmon-app/app/src/main/java/com/example/tvmon/data/repository/CategoryCacheRepository.kt new file mode 100644 index 0000000..9dd1e6b --- /dev/null +++ b/tvmon-app/app/src/main/java/com/example/tvmon/data/repository/CategoryCacheRepository.kt @@ -0,0 +1,132 @@ +package com.example.tvmon.data.repository + +import android.util.Log +import com.example.tvmon.data.local.dao.CategoryContentDao +import com.example.tvmon.data.local.entity.CategoryContent +import com.example.tvmon.data.model.Category +import com.example.tvmon.data.model.Content +import com.example.tvmon.data.model.Pagination +import com.example.tvmon.data.scraper.TvmonScraper +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class CategoryCacheRepository( + private val categoryContentDao: CategoryContentDao +) { + companion object { + private const val TAG = "CategoryCacheRepo" + private const val CACHE_TTL_MS = 30 * 60 * 1000L + } + + private val loadedPages = mutableMapOf() + + suspend fun getCategoryWithCache(categoryKey: String, page: Int = 1): CategoryResultCache { + return withContext(Dispatchers.IO) { + val cachedItems = categoryContentDao.getByCategoryUntilPage(categoryKey, page) + val lastCacheTime = categoryContentDao.getLastCacheTime(categoryKey) + val cachedMaxPage = categoryContentDao.getMaxPage(categoryKey) ?: 1 + + val now = System.currentTimeMillis() + val isCacheValid = lastCacheTime != null && (now - lastCacheTime) < CACHE_TTL_MS + + Log.w(TAG, "getCategoryWithCache: $categoryKey page=$page, cached=${cachedItems.size}, cacheValid=$isCacheValid, cachedMaxPage=$cachedMaxPage") + + if (cachedItems.isNotEmpty() && isCacheValid && page <= cachedMaxPage) { + val contents = cachedItems.map { it.toContent() } + CategoryResultCache( + success = true, + items = contents, + page = page, + pagination = Pagination(page, cachedMaxPage), + fromCache = true + ) + } else { + val result = scraper.getCategory(categoryKey, page) + if (result.success && result.items.isNotEmpty()) { + val entities = result.items.map { it.toEntity(categoryKey, page) } + categoryContentDao.insert(entities) + + val newMaxPage = result.pagination.maxPage + if (page == 1) { + loadedPages[categoryKey] = 1 + } + Log.w(TAG, "getCategoryWithCache: fetched from network, saved ${entities.size} items, maxPage=$newMaxPage") + } + CategoryResultCache( + success = result.success, + items = result.items, + page = result.page, + pagination = result.pagination, + fromCache = false + ) + } + } + } + + suspend fun loadMoreForCategory(categoryKey: String): List { + return withContext(Dispatchers.IO) { + val currentPage = loadedPages[categoryKey] ?: 1 + val nextPage = currentPage + 1 + + Log.w(TAG, "loadMoreForCategory: $categoryKey currentPage=$currentPage, nextPage=$nextPage") + + val result = scraper.getCategory(categoryKey, nextPage) + if (result.success && result.items.isNotEmpty()) { + val entities = result.items.map { it.toEntity(categoryKey, nextPage) } + categoryContentDao.insert(entities) + loadedPages[categoryKey] = nextPage + Log.w(TAG, "loadMoreForCategory: saved ${entities.size} items for page $nextPage") + } else { + Log.w(TAG, "loadMoreForCategory: no more items for $categoryKey") + } + result.items + } + } + + suspend fun getLoadedPageCount(categoryKey: String): Int { + return loadedPages[categoryKey] ?: 0 + } + + suspend fun getCachedItems(categoryKey: String): List { + return withContext(Dispatchers.IO) { + categoryContentDao.getByCategory(categoryKey).map { it.toContent() } + } + } + + suspend fun clearCache() { + categoryContentDao.deleteAll() + loadedPages.clear() + } + + private val scraper = TvmonScraper() +} + +data class CategoryResultCache( + val success: Boolean, + val items: List, + val page: Int, + val pagination: Pagination, + val fromCache: Boolean +) + +private fun CategoryContent.toContent(): Content { + return Content( + id = contentId, + title = title, + url = contentUrl, + thumbnail = thumbnail, + category = categoryKey + ) +} + +private fun Content.toEntity(categoryKey: String, page: Int): CategoryContent { + return CategoryContent( + contentUrl = url, + categoryKey = categoryKey, + contentId = id, + title = title, + thumbnail = thumbnail, + pageNumber = page, + cachedAt = System.currentTimeMillis() + ) +} \ No newline at end of file diff --git a/tvmon-app/app/src/main/java/com/example/tvmon/di/AppModule.kt b/tvmon-app/app/src/main/java/com/example/tvmon/di/AppModule.kt index f73e6f8..62893bf 100644 --- a/tvmon-app/app/src/main/java/com/example/tvmon/di/AppModule.kt +++ b/tvmon-app/app/src/main/java/com/example/tvmon/di/AppModule.kt @@ -3,6 +3,7 @@ package com.example.tvmon.di import androidx.room.Room import com.example.tvmon.data.local.AppDatabase import com.example.tvmon.data.repository.BookmarkRepository +import com.example.tvmon.data.repository.CategoryCacheRepository import com.example.tvmon.data.repository.WatchHistoryRepository import com.example.tvmon.data.scraper.TvmonScraper import org.koin.android.ext.koin.androidContext @@ -15,18 +16,20 @@ val databaseModule = module { AppDatabase::class.java, "tvmon_database" ) - .fallbackToDestructiveMigration() - .build() + .fallbackToDestructiveMigration() + .build() } - + single { get().watchHistoryDao() } single { get().bookmarkDao() } single { get().searchHistoryDao() } + single { get().categoryContentDao() } } val repositoryModule = module { single { WatchHistoryRepository(get()) } single { BookmarkRepository(get()) } + single { CategoryCacheRepository(get()) } } val scraperModule = module { diff --git a/tvmon-app/app/src/main/java/com/example/tvmon/ui/main/MainFragment.kt b/tvmon-app/app/src/main/java/com/example/tvmon/ui/main/MainFragment.kt index 25ed8a1..409cb9a 100644 --- a/tvmon-app/app/src/main/java/com/example/tvmon/ui/main/MainFragment.kt +++ b/tvmon-app/app/src/main/java/com/example/tvmon/ui/main/MainFragment.kt @@ -2,8 +2,6 @@ package com.example.tvmon.ui.main import android.content.Intent import android.os.Bundle -import android.os.Handler -import android.os.Looper import android.util.Log import android.widget.Toast import androidx.core.content.ContextCompat @@ -11,8 +9,8 @@ import androidx.leanback.app.BrowseSupportFragment import androidx.leanback.widget.* import androidx.lifecycle.lifecycleScope import com.example.tvmon.R -import com.example.tvmon.data.model.Category import com.example.tvmon.data.model.Content +import com.example.tvmon.data.repository.CategoryCacheRepository import com.example.tvmon.data.repository.WatchHistoryRepository import com.example.tvmon.data.scraper.TvmonScraper import com.example.tvmon.ui.detail.DetailsActivity @@ -24,33 +22,20 @@ class MainFragment : BrowseSupportFragment(), OnItemViewClickedListener, OnItemV companion object { private const val TAG = "TVMON_MAIN" - private const val PRELOAD_THRESHOLD = 20 } - private val scraper: TvmonScraper by inject() + private val categoryCacheRepository: CategoryCacheRepository by inject() private val watchHistoryRepository: WatchHistoryRepository by inject() private val rowsAdapter = ArrayObjectAdapter(ListRowPresenter()) - private val categoryPages = mutableMapOf() - private val categoryLoading = mutableMapOf() - private val categoryMaxPage = mutableMapOf() - private val categoryItems = mutableMapOf>() private val categoryRowAdapters = mutableMapOf() - private val handler = Handler(Looper.getMainLooper()) - private var currentSelectedRowIndex = -1 + private val loadingStates = mutableMapOf() private var isDataLoaded = false - private var lastPreloadedPage = mutableMapOf() - private var currentCategoryKey: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Log.w(TAG, "=== MainFragment onCreate ===") - try { - setupUI() - setupEventListeners() - Log.w(TAG, "setupUI completed successfully") - } catch (e: Exception) { - Log.e(TAG, "Error in onCreate", e) - } + setupUI() + setupEventListeners() } override fun onStart() { @@ -58,16 +43,9 @@ class MainFragment : BrowseSupportFragment(), OnItemViewClickedListener, OnItemV Log.w(TAG, "=== MainFragment onStart ===") if (!isDataLoaded) { loadData() - } else { - Log.w(TAG, "Data already loaded, skipping reload") } } - override fun onDestroy() { - handler.removeCallbacksAndMessages(null) - super.onDestroy() - } - private fun setupUI() { Log.w(TAG, "setupUI: Setting up UI") headersState = HEADERS_ENABLED @@ -89,114 +67,6 @@ class MainFragment : BrowseSupportFragment(), OnItemViewClickedListener, OnItemV onItemViewClickedListener = this } -private fun handleRowSelection(position: Int) { - if (position == currentSelectedRowIndex) return - currentSelectedRowIndex = position - - if (position >= 0 && position < rowsAdapter.size()) { - val categoryKey = findCategoryKeyForRow(position) - - if (categoryKey != null && categoryLoading[categoryKey] != true) { - val currentPage = categoryPages[categoryKey] ?: 1 - val maxPage = categoryMaxPage[categoryKey] ?: 1 - - Log.w(TAG, "handleRowSelection: $categoryKey currentPage=$currentPage maxPage=$maxPage") - - if (currentPage < maxPage) { - preloadNextPage(categoryKey, currentPage + 1) - } - } - } - } - - private fun preloadNextPage(categoryKey: String, page: Int) { - if (categoryLoading[categoryKey] == true) return - if (categoryPages[categoryKey] ?: 0 >= page) return - categoryLoading[categoryKey] = true - - lifecycleScope.launch { - try { - val result = scraper.getCategory(categoryKey, page) - Log.w(TAG, "preloadNextPage: $categoryKey page $page success=${result.success}, items=${result.items.size}") - - if (result.success && result.items.isNotEmpty()) { - val items = categoryItems.getOrPut(categoryKey) { mutableListOf() } - val existingUrls = items.map { it.url }.toSet() - val newItems = result.items.filter { it.url !in existingUrls } - - if (newItems.isNotEmpty()) { - items.addAll(newItems) - - val adapter = categoryRowAdapters[categoryKey] - activity?.runOnUiThread { - adapter?.let { - newItems.forEach { item -> it.add(item) } - } - } - } - - categoryPages[categoryKey] = page - Log.w(TAG, "Preloaded page $page for $categoryKey, total items=${items.size}") - } - } catch (e: Exception) { - Log.e(TAG, "Error preloading page $page for $categoryKey", e) - } finally { - categoryLoading[categoryKey] = false - } - } - } - - private fun findCategoryKeyForRow(rowIndex: Int): String? { - for ((key, _) in categoryPages) { - val catIndex = TvmonScraper.CATEGORIES.keys.toList().indexOf(key) - if (catIndex == rowIndex) return key - } - - val row = rowsAdapter.get(rowIndex) as? ListRow ?: return null - val headerName = row.headerItem?.name ?: return null - - for ((key, cat) in TvmonScraper.CATEGORIES) { - if (cat.name == headerName) return key - } - return null - } - -private fun loadNextPage(categoryKey: String, page: Int) { - if (categoryLoading[categoryKey] == true) return - categoryLoading[categoryKey] = true - - lifecycleScope.launch { - try { - val result = scraper.getCategory(categoryKey, page) - Log.w(TAG, "loadNextPage: $categoryKey page $page success=${result.success}, items=${result.items.size}") - - if (result.success && result.items.isNotEmpty()) { - val items = categoryItems.getOrPut(categoryKey) { mutableListOf() } - val existingUrls = items.map { it.url }.toSet() - val newItems = result.items.filter { it.url !in existingUrls } - - if (newItems.isNotEmpty()) { - items.addAll(newItems) - - val adapter = categoryRowAdapters[categoryKey] - activity?.runOnUiThread { - adapter?.let { - newItems.forEach { item -> it.add(item) } - } - } - } - - categoryPages[categoryKey] = page - Log.w(TAG, "Loaded page $page for $categoryKey, total items=${items.size}") - } - } catch (e: Exception) { - Log.e(TAG, "Error loading page $page for $categoryKey", e) - } finally { - categoryLoading[categoryKey] = false - } - } - } - private fun loadData() { Log.w(TAG, "=== loadData called ===") lifecycleScope.launch { @@ -213,42 +83,33 @@ private fun loadNextPage(categoryKey: String, page: Int) { private suspend fun loadCategories() { Log.w(TAG, "=== loadCategories: Starting ===") - Log.w(TAG, "Categories to load: ${TvmonScraper.CATEGORIES.keys}") var successCount = 0 var failCount = 0 - TvmonScraper.CATEGORIES.values.forEach { category -> + for (category in TvmonScraper.CATEGORIES.values) { Log.w(TAG, "Loading category: ${category.key} - ${category.name}") - val success = loadCategoryRows(category) + val success = loadCategoryWithCache(category) if (success) successCount++ else failCount++ } Log.w(TAG, "=== loadCategories COMPLETE: success=$successCount, fail=$failCount ===") - Log.w(TAG, "rowsAdapter size: ${rowsAdapter.size()}") - isDataLoaded = true - activity?.runOnUiThread { - if (rowsAdapter.size() == 0) { - Toast.makeText(requireContext(), "카테고리를 불러오지 못했습니다", Toast.LENGTH_LONG).show() - } + if (rowsAdapter.size() == 0) { + Toast.makeText(requireContext(), "카테고리를 불러오지 못했습니다", Toast.LENGTH_LONG).show() } } - private suspend fun loadCategoryRows(category: Category): Boolean { + private suspend fun loadCategoryWithCache(category: com.example.tvmon.data.model.Category): Boolean { return try { - Log.w(TAG, "Fetching: ${category.key} from ${TvmonScraper.BASE_URL}${category.path}") - - val result1 = scraper.getCategory(category.key, page = 1) - Log.w(TAG, "Page 1 for ${category.key}: success=${result1.success}, items=${result1.items.size}") - - val maxPage = result1.pagination.maxPage - - if (result1.success && result1.items.isNotEmpty()) { + Log.w(TAG, "loadCategoryWithCache: ${category.key}") + + val result = categoryCacheRepository.getCategoryWithCache(category.key, page = 1) + + if (result.success && result.items.isNotEmpty()) { val listRowAdapter = ArrayObjectAdapter(ContentCardPresenter()) - result1.items.forEach { content -> - Log.d(TAG, " Item: ${content.title} -> thumb: ${content.thumbnail}") + result.items.forEach { content -> listRowAdapter.add(content) } @@ -257,18 +118,10 @@ private fun loadNextPage(categoryKey: String, page: Int) { activity?.runOnUiThread { rowsAdapter.add(row) - Log.w(TAG, "ADDED ROW: ${category.name} with ${result1.items.size} items") + Log.w(TAG, "ADDED ROW: ${category.name} with ${result.items.size} items (fromCache=${result.fromCache})") } - - categoryPages[category.key] = 1 - categoryMaxPage[category.key] = maxPage - categoryItems[category.key] = result1.items.toMutableList() + categoryRowAdapters[category.key] = listRowAdapter - - if (maxPage > 1) { - categoryLoading[category.key] = false - } - true } else { Log.w(TAG, "No items for ${category.key}") @@ -286,19 +139,14 @@ private fun loadNextPage(categoryKey: String, page: Int) { rowViewHolder: RowPresenter.ViewHolder?, row: Row? ) { - Log.w(TAG, "=== onItemClicked: item=$item, itemViewHolder=$itemViewHolder ===") + Log.w(TAG, "=== onItemClicked: item=$item ===") when (item) { is Content -> { Log.w(TAG, "Content clicked: ${item.title}, url=${item.url}") - try { - val intent = Intent(requireContext(), DetailsActivity::class.java).apply { - putExtra(DetailsActivity.EXTRA_CONTENT, item) - } - startActivity(intent) - Log.w(TAG, "Started DetailsActivity successfully") - } catch (e: Exception) { - Log.e(TAG, "ERROR starting DetailsActivity", e) + val intent = Intent(requireContext(), DetailsActivity::class.java).apply { + putExtra(DetailsActivity.EXTRA_CONTENT, item) } + startActivity(intent) } else -> { Log.w(TAG, "Unknown item type: ${item?.javaClass?.simpleName}") @@ -316,21 +164,45 @@ private fun loadNextPage(categoryKey: String, page: Int) { val rowIndex = rowsAdapter.indexOf(row) if (rowIndex >= 0) { val categoryKey = findCategoryKeyForRow(rowIndex) - currentCategoryKey = categoryKey - handleRowSelection(rowIndex) + if (categoryKey != null && item is Content) { + checkAndLoadMore(categoryKey) + } } } } - private fun checkAndPreload(categoryKey: String, position: Int) { - val currentPage = categoryPages[categoryKey] ?: 1 - val maxPage = categoryMaxPage[categoryKey] ?: 1 - - val thresholdPage = (position / PRELOAD_THRESHOLD) + 1 - - if (thresholdPage > currentPage && thresholdPage <= maxPage) { - Log.w(TAG, "checkAndPreload: $categoryKey at position $position, preloading page $thresholdPage") - preloadNextPage(categoryKey, thresholdPage) + private fun checkAndLoadMore(categoryKey: String) { + val adapter = categoryRowAdapters[categoryKey] ?: return + if (loadingStates[categoryKey] == true) return + + val position = adapter.size() - 1 + if (position < 5) return + + lifecycleScope.launch { + try { + loadingStates[categoryKey] = true + val items = categoryCacheRepository.loadMoreForCategory(categoryKey) + if (items.isNotEmpty()) { + activity?.runOnUiThread { + items.forEach { adapter.add(it) } + Log.w(TAG, "checkAndLoadMore: $categoryKey added ${items.size} items, total=${adapter.size()}") + } + } + } catch (e: Exception) { + Log.e(TAG, "checkAndLoadMore error: ${e.message}") + } finally { + loadingStates[categoryKey] = false + } } } -} + + private fun findCategoryKeyForRow(rowIndex: Int): String? { + val row = rowsAdapter.get(rowIndex) as? ListRow ?: return null + val headerName = row.headerItem?.name ?: return null + + for ((key, cat) in TvmonScraper.CATEGORIES) { + if (cat.name == headerName) return key + } + return null + } +} \ No newline at end of file diff --git a/tvmon-app/app/src/main/java/com/example/tvmon/ui/playback/PlaybackActivity.kt b/tvmon-app/app/src/main/java/com/example/tvmon/ui/playback/PlaybackActivity.kt index a5e36f5..60991db 100644 --- a/tvmon-app/app/src/main/java/com/example/tvmon/ui/playback/PlaybackActivity.kt +++ b/tvmon-app/app/src/main/java/com/example/tvmon/ui/playback/PlaybackActivity.kt @@ -159,6 +159,7 @@ class PlaybackActivity : AppCompatActivity() { webSettings.javaScriptEnabled = true webSettings.domStorageEnabled = true + webSettings.databaseEnabled = true webSettings.allowFileAccess = true webSettings.allowContentAccess = true webSettings.mediaPlaybackRequiresUserGesture = false @@ -167,7 +168,7 @@ class PlaybackActivity : AppCompatActivity() { webSettings.userAgentString = USER_AGENT webSettings.useWideViewPort = true webSettings.loadWithOverviewMode = true - webSettings.cacheMode = WebSettings.LOAD_NO_CACHE + webSettings.cacheMode = WebSettings.LOAD_DEFAULT webSettings.allowUniversalAccessFromFileURLs = true webSettings.allowFileAccessFromFileURLs = true @@ -283,21 +284,16 @@ class PlaybackActivity : AppCompatActivity() { super.onPageFinished(view, url) android.util.Log.i("PlaybackActivity", "Page finished: $url") - handler.postDelayed({ - injectFullscreenScript() - android.util.Log.i("PlaybackActivity", "Fullscreen script injected") - }, 300) + handler.postDelayed({ + injectFullscreenScript() + injectEnhancedAutoPlayScript() + }, 200) - handler.postDelayed({ - injectEnhancedAutoPlayScript() - android.util.Log.i("PlaybackActivity", "Enhanced AutoPlay script injected") - }, 800) - - handler.postDelayed({ - runOnUiThread { - loadingOverlay.visibility = View.GONE - } - }, 1500) + handler.postDelayed({ + runOnUiThread { + loadingOverlay.visibility = View.GONE + } + }, 1000) } }