|
1 | 1 | package org.schabi.newpipe.viewmodels |
2 | 2 |
|
| 3 | +import android.util.Log |
3 | 4 | import androidx.lifecycle.SavedStateHandle |
4 | 5 | import androidx.lifecycle.ViewModel |
5 | 6 | import androidx.lifecycle.viewModelScope |
6 | 7 | import androidx.paging.Pager |
7 | 8 | import androidx.paging.PagingConfig |
| 9 | +import androidx.paging.PagingData |
8 | 10 | import androidx.paging.cachedIn |
9 | 11 | import kotlinx.coroutines.Dispatchers |
10 | 12 | import kotlinx.coroutines.ExperimentalCoroutinesApi |
| 13 | +import kotlinx.coroutines.delay |
| 14 | +import kotlinx.coroutines.flow.Flow |
11 | 15 | import kotlinx.coroutines.flow.SharingStarted |
12 | 16 | import kotlinx.coroutines.flow.filterIsInstance |
13 | 17 | import kotlinx.coroutines.flow.flatMapLatest |
| 18 | +import kotlinx.coroutines.flow.flow |
14 | 19 | import kotlinx.coroutines.flow.flowOn |
15 | 20 | import kotlinx.coroutines.flow.map |
16 | 21 | import kotlinx.coroutines.flow.stateIn |
| 22 | +import org.schabi.newpipe.extractor.NewPipe |
17 | 23 | import org.schabi.newpipe.extractor.comments.CommentsInfo |
| 24 | +import org.schabi.newpipe.extractor.comments.CommentsInfoItem |
18 | 25 | import org.schabi.newpipe.paging.CommentsSource |
19 | 26 | import org.schabi.newpipe.ui.components.video.comment.CommentInfo |
20 | 27 | import org.schabi.newpipe.util.KEY_URL |
21 | 28 | import org.schabi.newpipe.viewmodels.util.Resource |
22 | 29 |
|
23 | 30 | class CommentsViewModel(savedStateHandle: SavedStateHandle) : ViewModel() { |
| 31 | + companion object { |
| 32 | + private const val TAG = "CommentsViewModel" |
| 33 | + } |
| 34 | + |
24 | 35 | val uiState = savedStateHandle.getStateFlow(KEY_URL, "") |
25 | 36 | .map { |
26 | 37 | try { |
27 | | - Resource.Success(CommentInfo(CommentsInfo.getInfo(it))) |
| 38 | + val info = CommentsInfo.getInfo(it) |
| 39 | + Log.i( |
| 40 | + TAG, |
| 41 | + "Loaded CommentsInfo: disabled=${info.isCommentsDisabled}, " + |
| 42 | + "liveChat=${info.isLiveChat}, items=${info.relatedItems.size}, " + |
| 43 | + "nextPage=${info.nextPage != null}" |
| 44 | + ) |
| 45 | + Resource.Success(CommentInfo(info)) |
28 | 46 | } catch (e: Exception) { |
| 47 | + Log.e(TAG, "Failed to load comments", e) |
29 | 48 | Resource.Error(e) |
30 | 49 | } |
31 | 50 | } |
32 | 51 | .flowOn(Dispatchers.IO) |
33 | 52 | .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Resource.Loading) |
34 | 53 |
|
| 54 | + // Live chat via PagingData (broken approach) |
35 | 55 | @OptIn(ExperimentalCoroutinesApi::class) |
36 | | - val comments = uiState |
| 56 | + val comments: Flow<PagingData<CommentsInfoItem>> = uiState |
37 | 57 | .filterIsInstance<Resource.Success<CommentInfo>>() |
38 | 58 | .flatMapLatest { |
39 | | - Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) { |
40 | | - CommentsSource(it.data) |
41 | | - }.flow |
| 59 | + val info = it.data |
| 60 | + Log.i(TAG, "flatMapLatest: isLiveChat=${info.isLiveChat}, items=${info.comments.size}") |
| 61 | + if (info.isLiveChat) { |
| 62 | + liveChatPagingData(info) |
| 63 | + } else { |
| 64 | + Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) { |
| 65 | + CommentsSource(info) |
| 66 | + }.flow |
| 67 | + } |
42 | 68 | } |
43 | 69 | .cachedIn(viewModelScope) |
| 70 | + |
| 71 | + private fun liveChatPagingData(info: CommentInfo): Flow<PagingData<CommentsInfoItem>> = flow { |
| 72 | + val allItems = info.comments.toMutableList() |
| 73 | + emit(PagingData.from(allItems)) |
| 74 | + var nextPage = info.nextPage |
| 75 | + while (true) { |
| 76 | + delay(3000) |
| 77 | + if (nextPage == null) { |
| 78 | + Log.d(TAG, "liveChatPolling: nextPage is null, skipping") |
| 79 | + continue |
| 80 | + } |
| 81 | + try { |
| 82 | + Log.d(TAG, "liveChatPolling: fetching more items...") |
| 83 | + val result = CommentsInfo.getMoreItems( |
| 84 | + NewPipe.getService(info.serviceId), |
| 85 | + info.url, |
| 86 | + nextPage |
| 87 | + ) |
| 88 | + Log.i(TAG, "liveChatPolling: fetched ${result.items.size} items") |
| 89 | + allItems.addAll(result.items) |
| 90 | + emit(PagingData.from(allItems)) |
| 91 | + nextPage = result.nextPage |
| 92 | + } catch (e: Exception) { |
| 93 | + Log.e(TAG, "liveChatPolling: failed to fetch more items", e) |
| 94 | + } |
| 95 | + } |
| 96 | + } |
44 | 97 | } |
0 commit comments