Refresh presigned media URL every 7 minutes to prevent TTL expiry
Long videos (>15 min) would die mid-playback when the 15-minute presigned URL expired. Now a timer fetches a fresh URL from the watch JSON endpoint every 7 minutes, swaps the src, and seeks back to the saved position. Timer resets on every product transition.
This commit is contained in:
parent
204bca813d
commit
6eb4b3ca95
1 changed files with 49 additions and 0 deletions
|
|
@ -18,6 +18,9 @@
|
|||
var djCrossfadeActive = false;
|
||||
var djCrossfadeData = null;
|
||||
var preloadingId = null;
|
||||
var currentProductId = null;
|
||||
var urlRefreshTimer = null;
|
||||
var URL_REFRESH_MS = 7 * 60 * 1000; // 7 minutes
|
||||
|
||||
// --- Ring state (persisted in localStorage) ---
|
||||
var ringProductIds = [];
|
||||
|
|
@ -161,6 +164,7 @@
|
|||
var initialProductEl = document.querySelector('[data-watch-product-id]');
|
||||
if (initialProductEl) {
|
||||
var initialId = initialProductEl.getAttribute('data-watch-product-id');
|
||||
currentProductId = initialId;
|
||||
markWatched(initialId);
|
||||
syncRingPosition(initialId);
|
||||
if (initialProductEl.getAttribute('data-watch-is-mod') === '1') {
|
||||
|
|
@ -514,8 +518,10 @@
|
|||
ringProductIds = data.ring;
|
||||
}
|
||||
if (data.is_mod) isMod = true;
|
||||
currentProductId = data.product_id;
|
||||
markWatched(data.product_id);
|
||||
syncRingPosition(data.product_id);
|
||||
scheduleUrlRefresh();
|
||||
|
||||
document.title = data.title;
|
||||
|
||||
|
|
@ -1056,6 +1062,48 @@
|
|||
standbyMedia.load();
|
||||
}
|
||||
|
||||
// --- Presigned URL refresh: swap src every 7 min to prevent TTL expiry ---
|
||||
function scheduleUrlRefresh() {
|
||||
if (urlRefreshTimer) clearTimeout(urlRefreshTimer);
|
||||
urlRefreshTimer = setTimeout(refreshMediaUrl, URL_REFRESH_MS);
|
||||
}
|
||||
|
||||
function refreshMediaUrl() {
|
||||
urlRefreshTimer = null;
|
||||
if (!activeMedia || !currentProductId) return;
|
||||
// Skip refresh during crossfade — the new media already has a fresh URL
|
||||
if (djCrossfadeActive) { scheduleUrlRefresh(); return; }
|
||||
|
||||
fetchWatchData(currentProductId).then(function(data) {
|
||||
if (!data || !data.media_url) { scheduleUrlRefresh(); return; }
|
||||
// Only refresh if still on the same product
|
||||
if (data.product_id !== currentProductId) { scheduleUrlRefresh(); return; }
|
||||
|
||||
var wasPlaying = !activeMedia.paused;
|
||||
var savedTime = activeMedia.currentTime;
|
||||
var savedVolume = activeMedia.volume;
|
||||
var savedMuted = activeMedia.muted;
|
||||
|
||||
activeMedia.src = data.media_url;
|
||||
|
||||
activeMedia.addEventListener('loadeddata', function onLoaded() {
|
||||
activeMedia.removeEventListener('loadeddata', onLoaded);
|
||||
activeMedia.currentTime = savedTime;
|
||||
activeMedia.volume = savedVolume;
|
||||
activeMedia.muted = savedMuted;
|
||||
if (wasPlaying) activeMedia.play().catch(function() {});
|
||||
scheduleUrlRefresh();
|
||||
});
|
||||
|
||||
// Fallback: if loadeddata never fires, reschedule anyway
|
||||
setTimeout(function() {
|
||||
if (!urlRefreshTimer) scheduleUrlRefresh();
|
||||
}, 10000);
|
||||
}).catch(function() {
|
||||
scheduleUrlRefresh();
|
||||
});
|
||||
}
|
||||
|
||||
// --- Named event handlers (must be named so removeEventListener works) ---
|
||||
function onMediaEnded() {
|
||||
// Fallback: only start countdown if DJ crossfade didn't handle it
|
||||
|
|
@ -1113,6 +1161,7 @@
|
|||
// Initial setup
|
||||
if (activeMedia) {
|
||||
setupMediaEvents();
|
||||
scheduleUrlRefresh();
|
||||
} else {
|
||||
// Static content (PDF, image, etc.) — start 42-second timer
|
||||
// Reset on scroll — scrolling means the user is still reading
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue