Implemented history position playlist id tracking.

This commit is contained in:
Koen J
2025-11-15 15:22:52 +01:00
parent 727f977672
commit b7a61425ca
9 changed files with 34 additions and 31 deletions
@@ -101,7 +101,7 @@ fun String.isHexColor(): Boolean {
fun IPlatformClient.fromPool(pool: PlatformMultiClientPool) = pool.getClientPooled(this); fun IPlatformClient.fromPool(pool: PlatformMultiClientPool) = pool.getClientPooled(this);
fun IPlatformVideo.withTimestamp(sec: Long) = PlatformVideoWithTime(this, sec); fun IPlatformVideo.withTimestamp(sec: Long) = PlatformVideoWithTime(this, sec);
fun DocumentFile.getInputStream(context: Context) = context.contentResolver.openInputStream(this.uri); fun DocumentFile.getInputStream(context: Context) = context.contentResolver.openInputStream(this.uri);
fun DocumentFile.getOutputStream(context: Context) = context.contentResolver.openOutputStream(this.uri); fun DocumentFile.getOutputStream(context: Context) = context.contentResolver.openOutputStream(this.uri);
@@ -26,6 +26,7 @@ import com.futo.platformplayer.models.HistoryVideo
import com.futo.platformplayer.states.StateHistory import com.futo.platformplayer.states.StateHistory
import com.futo.platformplayer.states.StatePlatform import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StatePlayer import com.futo.platformplayer.states.StatePlayer
import com.futo.platformplayer.states.StatePlaylists
import com.futo.platformplayer.states.StatePlugins import com.futo.platformplayer.states.StatePlugins
import com.futo.platformplayer.views.ToggleBar import com.futo.platformplayer.views.ToggleBar
import com.futo.platformplayer.views.adapters.HistoryListViewHolder import com.futo.platformplayer.views.adapters.HistoryListViewHolder
@@ -243,12 +244,23 @@ class HistoryFragment : MainFragment() {
return; return;
} }
val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager;
val diff = v.video.duration - v.position; val diff = v.video.duration - v.position;
val vid: Any = if (diff > 5) { v.video.withTimestamp(v.position) } else { v.video }; val vid: Any = if (diff > 5) { v.video.withTimestamp(v.position) } else { v.video };
StatePlayer.instance.clearQueue();
_fragment.navigate<VideoDetailFragment>(vid).maximizeVideoDetail(); val playlistId = v.playlistId
val playlist = playlistId?.let { StatePlaylists.instance.getPlaylist(it) }
val playlistIndex = playlist?.videos?.indexOfFirst { it.url == v.video.url }
if (playlist != null && playlistIndex != null && playlistIndex >= 0) {
_fragment.navigate<VideoDetailFragment>(vid).maximizeVideoDetail();
StatePlayer.instance.setPlaylist(playlist, playlistIndex)
} else {
StatePlayer.instance.clearQueue();
_fragment.navigate<VideoDetailFragment>(vid).maximizeVideoDetail();
}
_editSearch.clearFocus(); _editSearch.clearFocus();
val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager;
inputMethodManager.hideSoftInputFromWindow(_editSearch.windowToken, 0); inputMethodManager.hideSoftInputFromWindow(_editSearch.windowToken, 0);
_fragment.lifecycleScope.launch(Dispatchers.Main) { _fragment.lifecycleScope.launch(Dispatchers.Main) {
@@ -1777,7 +1777,8 @@ class VideoDetailView : ConstraintLayout {
false, false,
(toResume.toFloat() / 1000.0f).toLong(), (toResume.toFloat() / 1000.0f).toLong(),
null, null,
true true,
StatePlayer.instance.playlistId
); );
Logger.i( Logger.i(
TAG, TAG,
@@ -3095,7 +3096,7 @@ class VideoDetailView : ConstraintLayout {
if (v !is TutorialFragment.TutorialVideo) { if (v !is TutorialFragment.TutorialVideo) {
fragment.lifecycleScope.launch(Dispatchers.IO) { fragment.lifecycleScope.launch(Dispatchers.IO) {
val history = getHistoryIndex(v) ?: return@launch; val history = getHistoryIndex(v) ?: return@launch;
StateHistory.instance.updateHistoryPosition(v, history, true, (positionMilliseconds.toFloat() / 1000.0f).toLong(), null, true); StateHistory.instance.updateHistoryPosition(v, history, true, (positionMilliseconds.toFloat() / 1000.0f).toLong(), null, true, StatePlayer.instance.playlistId);
} }
} }
_lastPositionSaveTime = currentTime; _lastPositionSaveTime = currentTime;
@@ -14,15 +14,17 @@ import java.time.ZoneOffset
class HistoryVideo { class HistoryVideo {
var video: SerializedPlatformVideo; var video: SerializedPlatformVideo;
var position: Long; var position: Long;
var playlistId: String? = null
@kotlinx.serialization.Serializable(with = OffsetDateTimeSerializer::class) @kotlinx.serialization.Serializable(with = OffsetDateTimeSerializer::class)
var date: OffsetDateTime; var date: OffsetDateTime;
constructor(video: SerializedPlatformVideo, position: Long, date: OffsetDateTime) { constructor(video: SerializedPlatformVideo, position: Long, date: OffsetDateTime, playlistId: String?) {
this.video = video; this.video = video;
this.position = position; this.position = position;
this.date = date; this.date = date;
this.playlistId = playlistId
} }
@@ -59,7 +61,7 @@ class HistoryVideo {
viewCount = -1 viewCount = -1
); );
return HistoryVideo(video, position, OffsetDateTime.of(LocalDateTime.ofEpochSecond(dateSec, 0, ZoneOffset.UTC), ZoneOffset.UTC)); return HistoryVideo(video, position, OffsetDateTime.of(LocalDateTime.ofEpochSecond(dateSec, 0, ZoneOffset.UTC), ZoneOffset.UTC), null);
} }
} }
} }
@@ -365,7 +365,7 @@ class StateBackup {
} }
val hist = StateHistory.instance.getHistoryByVideo(histObj.video, true, histObj.date); val hist = StateHistory.instance.getHistoryByVideo(histObj.video, true, histObj.date);
if(hist != null) if(hist != null)
StateHistory.instance.updateHistoryPosition(histObj.video, hist, true, histObj.position, histObj.date, false); StateHistory.instance.updateHistoryPosition(histObj.video, hist, true, histObj.position, histObj.date, false, histObj.playlistId);
} }
catch(ex: Throwable) { catch(ex: Throwable) {
Logger.e(TAG, "Failed to import subscription group", ex); Logger.e(TAG, "Failed to import subscription group", ex);
@@ -65,7 +65,7 @@ class StateHistory {
} }
private var _lastHistoryBroadcast = ""; private var _lastHistoryBroadcast = "";
fun updateHistoryPosition(liveObj: IPlatformVideo, index: DBHistory.Index, updateExisting: Boolean, position: Long = -1L, date: OffsetDateTime? = null, isUserAction: Boolean = false): Long { fun updateHistoryPosition(liveObj: IPlatformVideo, index: DBHistory.Index, updateExisting: Boolean, position: Long = -1L, date: OffsetDateTime? = null, isUserAction: Boolean = false, playlistId: String? = null): Long {
val pos = if(position < 0) 0 else position; val pos = if(position < 0) 0 else position;
val historyVideo = index.obj; val historyVideo = index.obj;
@@ -86,6 +86,7 @@ class StateHistory {
historyVideo.position = pos; historyVideo.position = pos;
historyVideo.date = date ?: OffsetDateTime.now(); historyVideo.date = date ?: OffsetDateTime.now();
historyVideo.playlistId = playlistId
_historyDBStore.update(index.id!!, historyVideo); _historyDBStore.update(index.id!!, historyVideo);
onHistoricVideoChanged.emit(liveObj, pos); onHistoricVideoChanged.emit(liveObj, pos);
@@ -157,7 +158,7 @@ class StateHistory {
UIDialogs.toast("History item null?\nNo history tracking.."); UIDialogs.toast("History item null?\nNo history tracking..");
} }
else if(create) { else if(create) {
val newHistItem = HistoryVideo(SerializedPlatformVideo.fromVideo(video), 0, watchDate ?: OffsetDateTime.now()); val newHistItem = HistoryVideo(SerializedPlatformVideo.fromVideo(video), 0, watchDate ?: OffsetDateTime.now(), StatePlayer.instance.playlistId);
val id = _historyDBStore.insert(newHistItem); val id = _historyDBStore.insert(newHistItem);
result = _historyDBStore.getOrNull(id); result = _historyDBStore.getOrNull(id);
if(result == null) if(result == null)
@@ -114,6 +114,9 @@ class StatePlayer {
var currentVideo: IPlatformVideo? = null var currentVideo: IPlatformVideo? = null
private set; private set;
private var _currentPlaylistId: String? = null
val playlistId: String? get() = if (_queueType == TYPE_PLAYLIST) _currentPlaylistId else null
init { init {
onQueueChanged.subscribe { onQueueChanged.subscribe {
updateLastQueue() updateLastQueue()
@@ -275,23 +278,6 @@ class StatePlayer {
} }
onQueueChanged.emit(true); onQueueChanged.emit(true);
} }
fun setPlaylist(playlist: IPlatformPlaylistDetails, toPlayIndex: Int = 0, focus: Boolean = false, shuffle: Boolean = false) {
synchronized(_queue) {
_queue.clear();
setQueueType(TYPE_PLAYLIST);
_queueName = playlist.name;
_queue.addAll(playlist.contents.getResults());
queueFocused = focus;
queueShuffle = shuffle;
if (shuffle) {
createShuffledQueue();
}
_queuePosition = toPlayIndex;
}
playlist.id.value?.let { StatePlaylists.instance.didPlay(it); };
onQueueChanged.emit(true);
}
fun setPlaylist(playlist: Playlist, toPlayIndex: Int = 0, focus: Boolean = false, shuffle: Boolean = false) { fun setPlaylist(playlist: Playlist, toPlayIndex: Int = 0, focus: Boolean = false, shuffle: Boolean = false) {
synchronized(_queue) { synchronized(_queue) {
_queue.clear(); _queue.clear();
@@ -305,6 +291,7 @@ class StatePlayer {
} }
_queuePosition = toPlayIndex; _queuePosition = toPlayIndex;
} }
_currentPlaylistId = playlist.id
StatePlaylists.instance.didPlay(playlist.id); StatePlaylists.instance.didPlay(playlist.id);
onQueueChanged.emit(true); onQueueChanged.emit(true);
@@ -200,10 +200,10 @@ class StatePlaylists {
} }
fun getLastPlayedPlaylist() : Playlist? { fun getLastPlayedPlaylist() : Playlist? {
return playlistStore.queryItem { it.maxByOrNull { x -> x.datePlayed } }; return playlistStore.queryItem { it.filter { x -> x.id != StatePlaylists.LAST_QUEUE_PLAYLIST_ID }.maxByOrNull { x -> x.datePlayed } };
} }
fun getLastUpdatedPlaylist() : Playlist? { fun getLastUpdatedPlaylist() : Playlist? {
return playlistStore.queryItem { it.maxByOrNull { x -> x.dateUpdate } }; return playlistStore.queryItem { it.filter { x -> x.id != StatePlaylists.LAST_QUEUE_PLAYLIST_ID }.maxByOrNull { x -> x.dateUpdate } };
} }
fun getPlaylists() : List<Playlist> { fun getPlaylists() : List<Playlist> {
@@ -463,7 +463,7 @@ class StateSync {
for(video in history){ for(video in history){
val hist = StateHistory.instance.getHistoryByVideo(video.video, true, video.date); val hist = StateHistory.instance.getHistoryByVideo(video.video, true, video.date);
if(hist != null) if(hist != null)
StateHistory.instance.updateHistoryPosition(video.video, hist, true, video.position, video.date) StateHistory.instance.updateHistoryPosition(video.video, hist, true, video.position, video.date, false, video.playlistId)
if(lastHistory < video.date) if(lastHistory < video.date)
lastHistory = video.date; lastHistory = video.date;
} }