fix(player): resume from saved position and protect it across keep-alive

Clicking a video from history (or any cached watch page) restarted it from 0
instead of resuming, and history bars showed stale positions. Four shared-path
bugs, all engine-agnostic:

- The resume position was computed but never applied: Shaka's load(uri, startTime)
  doesn't perform the initial seek for lazily-fetched segment indexes, so playback
  began at 0. Apply the resume explicitly with a runtime seek once load() resolves.

- initialSeekComplete (gates progress saving until the resume seek lands) was never
  reset per-load. On a reactivated player it stayed true from the previous play, so
  a timeupdate at currentTime=0 during rebuild churn overwrote the saved position
  before the resume read ran. Reset it at the start of loadVideo.

- Leaving a watch page (destroy) empties the media element -> currentTime snaps to
  0 and a stray timeupdate fires while initialSeekComplete is still true, clobbering
  the saved position. Gate the save on destroying as well.

- HistoryPage: re-read watch_history in onActivated so progress bars reflect the
  current saved position instead of a stale first-mount snapshot. Kept off onMounted
  to avoid double-loading (both fire on first keep-alive mount).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
LogicalKarma
2026-05-28 23:19:48 +03:00
parent de44e80a5c
commit 174ca1a072
2 changed files with 21 additions and 17 deletions

View File

@@ -61,7 +61,7 @@
</template>
<script setup>
import { ref, onMounted, onActivated, onDeactivated } from "vue";
import { ref, onActivated, onDeactivated } from "vue";
import VideoItem from "./VideoItem.vue";
import SortingSelector from "./SortingSelector.vue";
import ExportHistoryModal from "./ExportHistoryModal.vue";
@@ -73,8 +73,8 @@ let currentVideoCount = 0;
const videoStep = 100;
const videosStore = [];
const videos = ref([]);
const autoDeleteHistory = ref(false);
const autoDeleteDelayHours = ref("24");
const autoDeleteHistory = ref(getPreferenceBoolean("autoDeleteWatchHistory", false));
const autoDeleteDelayHours = ref(getPreferenceString("autoDeleteWatchHistoryDelayHours", "24"));
const showExportModal = ref(false);
const showImportModal = ref(false);
@@ -109,11 +109,12 @@ function onChange() {
setPreference("autoDeleteWatchHistoryDelayHours", autoDeleteDelayHours.value);
}
onMounted(() => {
autoDeleteHistory.value = getPreferenceBoolean("autoDeleteWatchHistory", false);
autoDeleteDelayHours.value = getPreferenceString("autoDeleteWatchHistoryDelayHours", "24");
function loadHistory() {
videosStore.length = 0;
currentVideoCount = 0;
videos.value = [];
(async () => {
return (async () => {
if (window.db && getPreferenceBoolean("watchHistory", false)) {
var tx = window.db.transaction("watch_history", "readwrite");
var store = tx.objectStore("watch_history");
@@ -148,10 +149,11 @@ onMounted(() => {
})().then(() => {
loadMoreVideos();
});
});
}
onActivated(() => {
document.title = "Watch History - Piped";
loadHistory();
window.addEventListener("scroll", handleScroll);
});