Redesign countdown overlay as compact frosted-glass bottom bar
Countdown preview now anchors to bottom of media container instead of covering the entire video. Uses backdrop-filter blur with theme-aware semi-transparent background (light/dark). Compact single-row grid layout with 60px thumb, title+number, and action buttons inline. Also completes the stalled watch mode v2 changes: static content timer, autoplay toggle persistence, audio container wrapping in hardSwap, and watch_json endpoint accepting non-playable media types.
This commit is contained in:
parent
91fb6f7916
commit
52e2ffc06c
5 changed files with 170 additions and 114 deletions
|
|
@ -1 +1 @@
|
|||
1b704f5
|
||||
d03178b
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
(function() {
|
||||
// Find the active media element (video or audio)
|
||||
// Find the active media element (video or audio), or null for static content
|
||||
var activeMedia = document.getElementById('watch-video') || document.getElementById('watch-audio');
|
||||
if (!activeMedia) return;
|
||||
|
||||
// SPA state
|
||||
var standbyMedia = null;
|
||||
|
|
@ -9,9 +8,35 @@
|
|||
var queue = [];
|
||||
var countdownTimer = null;
|
||||
var crossfadeTimer = null;
|
||||
var staticTimer = null;
|
||||
var COUNTDOWN_SECONDS = 14;
|
||||
var CROSSFADE_DURATION = 3000;
|
||||
var CROSSFADE_STEPS = 60;
|
||||
var STATIC_DISPLAY_SECONDS = 42;
|
||||
|
||||
// Autoplay preference (persisted in localStorage)
|
||||
var autoplayEnabled = true;
|
||||
try {
|
||||
var saved = localStorage.getItem('watchAutoplay');
|
||||
if (saved !== null) autoplayEnabled = saved === '1';
|
||||
} catch (e) {}
|
||||
|
||||
// Set up autoplay toggle
|
||||
var autoplayToggle = document.getElementById('watch-autoplay-toggle');
|
||||
if (autoplayToggle) {
|
||||
autoplayToggle.checked = autoplayEnabled;
|
||||
autoplayToggle.addEventListener('change', function() {
|
||||
autoplayEnabled = this.checked;
|
||||
try { localStorage.setItem('watchAutoplay', autoplayEnabled ? '1' : '0'); } catch (e) {}
|
||||
if (!autoplayEnabled) {
|
||||
cancelCountdown();
|
||||
if (staticTimer) { clearTimeout(staticTimer); staticTimer = null; }
|
||||
} else {
|
||||
// If on a static page, restart the timer
|
||||
if (!activeMedia) startStaticTimer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Restore queue from sessionStorage
|
||||
try {
|
||||
|
|
@ -19,15 +44,17 @@
|
|||
if (savedQueue) queue = JSON.parse(savedQueue);
|
||||
} catch (e) {}
|
||||
|
||||
// --- Autoplay with sound (existing behavior) ---
|
||||
var playPromise = activeMedia.play();
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.catch(function() {
|
||||
activeMedia.muted = true;
|
||||
activeMedia.play().then(function() {
|
||||
showUnmuteOverlay(activeMedia);
|
||||
}).catch(function() {});
|
||||
});
|
||||
// --- Autoplay with sound (for video/audio) ---
|
||||
if (activeMedia) {
|
||||
var playPromise = activeMedia.play();
|
||||
if (playPromise !== undefined) {
|
||||
playPromise.catch(function() {
|
||||
activeMedia.muted = true;
|
||||
activeMedia.play().then(function() {
|
||||
showUnmuteOverlay(activeMedia);
|
||||
}).catch(function() {});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showUnmuteOverlay(media) {
|
||||
|
|
@ -40,8 +67,12 @@
|
|||
});
|
||||
}
|
||||
|
||||
// Determine current media type
|
||||
var currentMediaType = activeMedia ? activeMedia.tagName.toLowerCase() : 'static';
|
||||
|
||||
// --- Create standby media element ---
|
||||
function createStandbyMedia(type) {
|
||||
if (type === 'static') return null;
|
||||
var el = document.createElement(type === 'audio' ? 'audio' : 'video');
|
||||
el.preload = 'auto';
|
||||
el.style.display = 'none';
|
||||
|
|
@ -50,9 +81,9 @@
|
|||
return el;
|
||||
}
|
||||
|
||||
// Determine current media type from the active element
|
||||
var currentMediaType = activeMedia.tagName.toLowerCase();
|
||||
standbyMedia = createStandbyMedia(currentMediaType);
|
||||
if (activeMedia) {
|
||||
standbyMedia = createStandbyMedia(currentMediaType);
|
||||
}
|
||||
|
||||
// --- Queue management ---
|
||||
function saveQueue() {
|
||||
|
|
@ -95,7 +126,6 @@
|
|||
titleSpan.textContent = item.title;
|
||||
titleSpan.style.cursor = 'pointer';
|
||||
titleSpan.addEventListener('click', function() {
|
||||
// Play this item immediately, remove from queue
|
||||
var playItem = queue.splice(i, 1)[0];
|
||||
saveQueue();
|
||||
renderQueue();
|
||||
|
|
@ -129,21 +159,31 @@
|
|||
// --- SPA navigation ---
|
||||
function fetchAndNavigate(productId) {
|
||||
cancelCountdown();
|
||||
if (staticTimer) { clearTimeout(staticTimer); staticTimer = null; }
|
||||
fetchWatchData(productId).then(function(data) {
|
||||
transitionTo(data);
|
||||
}).catch(function() {
|
||||
// Fallback: hard navigate
|
||||
window.location.href = '/watch/' + productId + '/json';
|
||||
// Fallback: hard navigate to the canonical URL
|
||||
// Try to find the link in the related items
|
||||
var link = document.querySelector('[data-watch-id="' + productId + '"]');
|
||||
if (link) {
|
||||
window.location.href = link.getAttribute('href');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function transitionTo(data) {
|
||||
var sameType = (data.media_type === currentMediaType);
|
||||
var isPlayable = (data.media_type === 'video' || data.media_type === 'audio');
|
||||
|
||||
if (sameType) {
|
||||
if (isPlayable && activeMedia && data.media_type === currentMediaType) {
|
||||
crossfade(data);
|
||||
} else {
|
||||
} else if (isPlayable) {
|
||||
hardSwap(data);
|
||||
} else {
|
||||
// Static content (PDF, image, etc.) — hard navigate
|
||||
if (data.canonical_url) {
|
||||
window.location.href = data.canonical_url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,8 +191,7 @@
|
|||
function crossfade(data) {
|
||||
if (crossfadeTimer) clearInterval(crossfadeTimer);
|
||||
|
||||
// Ensure standby matches media type
|
||||
if (standbyMedia.tagName.toLowerCase() !== data.media_type) {
|
||||
if (!standbyMedia || standbyMedia.tagName.toLowerCase() !== data.media_type) {
|
||||
hardSwap(data);
|
||||
return;
|
||||
}
|
||||
|
|
@ -164,7 +203,6 @@
|
|||
var standbyPlayPromise = standbyMedia.play();
|
||||
if (standbyPlayPromise !== undefined) {
|
||||
standbyPlayPromise.catch(function() {
|
||||
// Crossfade failed, hard swap
|
||||
hardSwap(data);
|
||||
return;
|
||||
});
|
||||
|
|
@ -191,12 +229,10 @@
|
|||
activeMedia.style.display = 'none';
|
||||
standbyMedia.style.display = '';
|
||||
|
||||
// Swap references
|
||||
var tmp = activeMedia;
|
||||
activeMedia = standbyMedia;
|
||||
standbyMedia = tmp;
|
||||
|
||||
// Apply correct attributes
|
||||
activeMedia.id = currentMediaType === 'video' ? 'watch-video' : 'watch-audio';
|
||||
activeMedia.controls = true;
|
||||
activeMedia.className = currentMediaType === 'video' ? 'product-main' : '';
|
||||
|
|
@ -209,30 +245,29 @@
|
|||
|
||||
// --- Hard swap (different media types or fallback) ---
|
||||
function hardSwap(data) {
|
||||
activeMedia.pause();
|
||||
if (activeMedia) activeMedia.pause();
|
||||
|
||||
var container = document.getElementById('watch-media-container');
|
||||
if (!container) return;
|
||||
|
||||
// Remove old standby
|
||||
if (standbyMedia && standbyMedia.parentNode) {
|
||||
standbyMedia.parentNode.removeChild(standbyMedia);
|
||||
}
|
||||
|
||||
// Determine new media type
|
||||
var newType = data.media_type;
|
||||
currentMediaType = newType;
|
||||
|
||||
if (newType === 'audio') {
|
||||
// Replace with audio container
|
||||
container.innerHTML = '';
|
||||
|
||||
// Show album art if available
|
||||
var audioWrap = document.createElement('div');
|
||||
audioWrap.className = 'watch-audio-container';
|
||||
|
||||
if (data.thumbnail_url) {
|
||||
var img = document.createElement('img');
|
||||
img.src = data.thumbnail_url;
|
||||
img.className = 'product-main audio-cover';
|
||||
container.appendChild(img);
|
||||
audioWrap.appendChild(img);
|
||||
}
|
||||
|
||||
var audio = document.createElement('audio');
|
||||
|
|
@ -240,11 +275,11 @@
|
|||
audio.src = data.media_url;
|
||||
audio.autoplay = true;
|
||||
audio.controls = true;
|
||||
container.appendChild(audio);
|
||||
audioWrap.appendChild(audio);
|
||||
|
||||
container.appendChild(audioWrap);
|
||||
activeMedia = audio;
|
||||
} else {
|
||||
// Replace with video
|
||||
container.innerHTML = '';
|
||||
|
||||
var videoWrap = document.createElement('div');
|
||||
|
|
@ -268,17 +303,16 @@
|
|||
activeMedia = video;
|
||||
}
|
||||
|
||||
// Create new standby
|
||||
standbyMedia = createStandbyMedia(newType);
|
||||
|
||||
// Re-add countdown overlay
|
||||
// Place countdown inside the positioned wrapper (video or audio container)
|
||||
var countdown = document.getElementById('watch-countdown');
|
||||
if (countdown) container.appendChild(countdown);
|
||||
var positionedWrap = container.querySelector('.watch-video-container, .watch-audio-container');
|
||||
if (countdown && positionedWrap) positionedWrap.appendChild(countdown);
|
||||
|
||||
updatePageContent(data);
|
||||
setupMediaEvents();
|
||||
|
||||
// Try autoplay
|
||||
var p = activeMedia.play();
|
||||
if (p !== undefined) {
|
||||
p.catch(function() {
|
||||
|
|
@ -294,45 +328,34 @@
|
|||
|
||||
// --- Update page content (title, description, related, URL) ---
|
||||
function updatePageContent(data) {
|
||||
// Update page title
|
||||
document.title = data.title;
|
||||
|
||||
// Update the heading
|
||||
var h1 = document.querySelector('.product-images h1, .watch-audio-container + h1, .product-images + h1');
|
||||
if (!h1) {
|
||||
// Try content.j2 layout where h1 is inside product-images
|
||||
h1 = document.querySelector('h1');
|
||||
}
|
||||
// We only update the text node of the title, preserving the subtitle span
|
||||
var h1 = document.querySelector('.product-images h1');
|
||||
if (!h1) h1 = document.querySelector('h1');
|
||||
if (h1) {
|
||||
var titleNode = h1.firstChild;
|
||||
if (titleNode && titleNode.nodeType === Node.TEXT_NODE) {
|
||||
titleNode.textContent = data.title + ' ';
|
||||
titleNode.textContent = data.title;
|
||||
}
|
||||
}
|
||||
|
||||
// Update description
|
||||
var descSection = document.querySelector('.product-description section');
|
||||
if (descSection) {
|
||||
descSection.innerHTML = data.description_html;
|
||||
}
|
||||
|
||||
// Update related content sidebar
|
||||
updateRelated(data.related);
|
||||
|
||||
// Update URL
|
||||
if (data.canonical_url) {
|
||||
history.pushState({productId: data.product_id}, data.title, data.canonical_url);
|
||||
}
|
||||
|
||||
// Re-render queue
|
||||
renderQueue();
|
||||
}
|
||||
|
||||
function updateRelated(related) {
|
||||
var container = document.querySelector('.related-content');
|
||||
if (!container) {
|
||||
// Create if it doesn't exist
|
||||
var productRight = document.querySelector('.product-right');
|
||||
if (!productRight) return;
|
||||
container = document.createElement('div');
|
||||
|
|
@ -373,7 +396,6 @@
|
|||
// --- Countdown timer ---
|
||||
function getNextItem() {
|
||||
if (queue.length > 0) return queue[0];
|
||||
// Get first related item
|
||||
var firstRelated = document.querySelector('.related-content-item[data-watch-id]');
|
||||
if (firstRelated) {
|
||||
return {
|
||||
|
|
@ -387,6 +409,8 @@
|
|||
}
|
||||
|
||||
function startCountdown() {
|
||||
if (!autoplayEnabled) return;
|
||||
|
||||
var next = getNextItem();
|
||||
if (!next) return;
|
||||
|
||||
|
|
@ -431,20 +455,15 @@
|
|||
}
|
||||
|
||||
function navigateToNext(next) {
|
||||
var productId;
|
||||
if (next && next.id) {
|
||||
productId = next.id;
|
||||
// If from queue, remove it
|
||||
if (queue.length > 0 && queue[0].id === productId) {
|
||||
queue.shift();
|
||||
saveQueue();
|
||||
renderQueue();
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
if (!next || !next.id) return;
|
||||
var productId = next.id;
|
||||
|
||||
if (queue.length > 0 && queue[0].id === productId) {
|
||||
queue.shift();
|
||||
saveQueue();
|
||||
renderQueue();
|
||||
}
|
||||
|
||||
// Use preloaded data if available and matches
|
||||
if (preloadedData && preloadedData.product_id === productId) {
|
||||
transitionTo(preloadedData);
|
||||
preloadedData = null;
|
||||
|
|
@ -453,6 +472,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
// --- Static content timer (PDF, images: 42 seconds then advance) ---
|
||||
function startStaticTimer() {
|
||||
if (!autoplayEnabled) return;
|
||||
if (staticTimer) clearTimeout(staticTimer);
|
||||
staticTimer = setTimeout(function() {
|
||||
staticTimer = null;
|
||||
startCountdown();
|
||||
}, STATIC_DISPLAY_SECONDS * 1000);
|
||||
}
|
||||
|
||||
// --- Preload next media ---
|
||||
function preloadNext() {
|
||||
var next = getNextItem();
|
||||
|
|
@ -460,7 +489,7 @@
|
|||
|
||||
fetchWatchData(next.id).then(function(data) {
|
||||
preloadedData = data;
|
||||
if (standbyMedia && data.media_url) {
|
||||
if (standbyMedia && data.media_url && (data.media_type === 'video' || data.media_type === 'audio')) {
|
||||
standbyMedia.src = data.media_url;
|
||||
standbyMedia.preload = 'auto';
|
||||
}
|
||||
|
|
@ -471,6 +500,7 @@
|
|||
|
||||
// --- Media event setup ---
|
||||
function setupMediaEvents() {
|
||||
if (!activeMedia) return;
|
||||
activeMedia.addEventListener('ended', function() {
|
||||
startCountdown();
|
||||
});
|
||||
|
|
@ -480,12 +510,16 @@
|
|||
});
|
||||
}
|
||||
|
||||
// Initial event setup
|
||||
setupMediaEvents();
|
||||
// Initial setup
|
||||
if (activeMedia) {
|
||||
setupMediaEvents();
|
||||
} else {
|
||||
// Static content (PDF, image, etc.) — start 42-second timer
|
||||
startStaticTimer();
|
||||
}
|
||||
|
||||
// --- Event delegation for SPA link interception ---
|
||||
document.addEventListener('click', function(e) {
|
||||
// Queue add button
|
||||
var queueBtn = e.target.closest('.queue-add-btn');
|
||||
if (queueBtn) {
|
||||
e.preventDefault();
|
||||
|
|
@ -500,7 +534,6 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Related content links — SPA intercept
|
||||
var link = e.target.closest('.related-content-item[data-watch-id]');
|
||||
if (link) {
|
||||
e.preventDefault();
|
||||
|
|
@ -509,9 +542,6 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Queue item clicks are handled in renderQueue
|
||||
|
||||
// Countdown play now
|
||||
if (e.target.id === 'countdown-play-now' || e.target.closest('#countdown-play-now')) {
|
||||
e.preventDefault();
|
||||
cancelCountdown();
|
||||
|
|
@ -520,7 +550,6 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Countdown cancel
|
||||
if (e.target.id === 'countdown-cancel' || e.target.closest('#countdown-cancel')) {
|
||||
e.preventDefault();
|
||||
cancelCountdown();
|
||||
|
|
@ -545,9 +574,6 @@
|
|||
);
|
||||
}
|
||||
|
||||
// Render queue on load
|
||||
renderQueue();
|
||||
|
||||
// Preload next on initial load
|
||||
preloadNext();
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -44,15 +44,15 @@
|
|||
<div class="watch-video-container">
|
||||
<video id="watch-video" src="{{ watch_video_url }}" autoplay controls playsinline class="product-main"></video>
|
||||
<button class="unmute-overlay">Tap to unmute</button>
|
||||
</div>
|
||||
<div id="watch-countdown" class="watch-countdown js-only" style="display:none">
|
||||
<img id="countdown-thumb" class="countdown-thumb" />
|
||||
<div class="countdown-text">
|
||||
<span id="countdown-title">Up next: ...</span>
|
||||
<span id="countdown-number">14</span>
|
||||
<div id="watch-countdown" class="watch-countdown js-only" style="display:none">
|
||||
<img id="countdown-thumb" class="countdown-thumb" />
|
||||
<div class="countdown-text">
|
||||
<span id="countdown-title">Up next: ...</span>
|
||||
<span id="countdown-number">14</span>
|
||||
</div>
|
||||
<button id="countdown-play-now" class="mps-button mps-button-blue">Play Now</button>
|
||||
<button id="countdown-cancel" class="mps-button">Cancel</button>
|
||||
</div>
|
||||
<button id="countdown-play-now" class="mps-button mps-button-blue">Play Now</button>
|
||||
<button id="countdown-cancel" class="mps-button">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<noscript>
|
||||
|
|
@ -67,15 +67,15 @@
|
|||
<img src="{{ request.app["bucket.secure_uploads.get_endpoint"] }}/{{ product.s3_path }}/thumbnail1?ts={{ product.updated_timestamp }}" class="product-main audio-cover" />
|
||||
{% endif %}
|
||||
<audio id="watch-audio" src="{{ watch_audio_url }}" autoplay controls></audio>
|
||||
</div>
|
||||
<div id="watch-countdown" class="watch-countdown js-only" style="display:none">
|
||||
<img id="countdown-thumb" class="countdown-thumb" />
|
||||
<div class="countdown-text">
|
||||
<span id="countdown-title">Up next: ...</span>
|
||||
<span id="countdown-number">14</span>
|
||||
<div id="watch-countdown" class="watch-countdown js-only" style="display:none">
|
||||
<img id="countdown-thumb" class="countdown-thumb" />
|
||||
<div class="countdown-text">
|
||||
<span id="countdown-title">Up next: ...</span>
|
||||
<span id="countdown-number">14</span>
|
||||
</div>
|
||||
<button id="countdown-play-now" class="mps-button mps-button-blue">Play Now</button>
|
||||
<button id="countdown-cancel" class="mps-button">Cancel</button>
|
||||
</div>
|
||||
<button id="countdown-play-now" class="mps-button mps-button-blue">Play Now</button>
|
||||
<button id="countdown-cancel" class="mps-button">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<noscript>
|
||||
|
|
@ -100,6 +100,18 @@
|
|||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if request.shop.watch_mode_enabled and product.extensions.get("product") not in video_extensions and product.extensions.get("product") not in audio_extensions %}
|
||||
{# Countdown overlay for static content (PDFs, images) #}
|
||||
<div id="watch-countdown" class="watch-countdown watch-countdown-static js-only" style="display:none">
|
||||
<img id="countdown-thumb" class="countdown-thumb" />
|
||||
<div class="countdown-text">
|
||||
<span id="countdown-title">Up next: ...</span>
|
||||
<span id="countdown-number">14</span>
|
||||
</div>
|
||||
<button id="countdown-play-now" class="mps-button mps-button-blue">Play Now</button>
|
||||
<button id="countdown-cancel" class="mps-button">Cancel</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<br/>
|
||||
|
||||
<h1>{{ product.title }}<br/><span class="subtitle-text">uploaded to <a href="{{ product.shop.absolute_about_url(request) }}" rel="nofollow" class="shop-theme-link-color">{{ product.shop.name }}</a></span></h1>
|
||||
|
|
@ -146,6 +158,11 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if request.shop.watch_mode_enabled %}
|
||||
<label class="watch-autoplay-label js-only">
|
||||
<input type="checkbox" id="watch-autoplay-toggle" checked /> Autoplay
|
||||
</label>
|
||||
{% endif %}
|
||||
<div id="watch-queue" class="js-only" style="display:none">
|
||||
<h4>Queue</h4>
|
||||
<div id="queue-items"></div>
|
||||
|
|
|
|||
|
|
@ -48,15 +48,15 @@
|
|||
<div class="watch-video-container">
|
||||
<video id="watch-video" src="{{ watch_video_url }}" autoplay controls playsinline class="product-main"></video>
|
||||
<button class="unmute-overlay">Tap to unmute</button>
|
||||
</div>
|
||||
<div id="watch-countdown" class="watch-countdown js-only" style="display:none">
|
||||
<img id="countdown-thumb" class="countdown-thumb" />
|
||||
<div class="countdown-text">
|
||||
<span id="countdown-title">Up next: ...</span>
|
||||
<span id="countdown-number">14</span>
|
||||
<div id="watch-countdown" class="watch-countdown js-only" style="display:none">
|
||||
<img id="countdown-thumb" class="countdown-thumb" />
|
||||
<div class="countdown-text">
|
||||
<span id="countdown-title">Up next: ...</span>
|
||||
<span id="countdown-number">14</span>
|
||||
</div>
|
||||
<button id="countdown-play-now" class="mps-button mps-button-blue">Play Now</button>
|
||||
<button id="countdown-cancel" class="mps-button">Cancel</button>
|
||||
</div>
|
||||
<button id="countdown-play-now" class="mps-button mps-button-blue">Play Now</button>
|
||||
<button id="countdown-cancel" class="mps-button">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<noscript>
|
||||
|
|
@ -75,15 +75,15 @@
|
|||
<img src="{{ request.app["bucket.secure_uploads.get_endpoint"] }}/{{ product.s3_path }}/thumbnail1?ts={{ product.updated_timestamp }}" class="product-main audio-cover" />
|
||||
{% endif %}
|
||||
<audio id="watch-audio" src="{{ watch_audio_url }}" autoplay controls></audio>
|
||||
</div>
|
||||
<div id="watch-countdown" class="watch-countdown js-only" style="display:none">
|
||||
<img id="countdown-thumb" class="countdown-thumb" />
|
||||
<div class="countdown-text">
|
||||
<span id="countdown-title">Up next: ...</span>
|
||||
<span id="countdown-number">14</span>
|
||||
<div id="watch-countdown" class="watch-countdown js-only" style="display:none">
|
||||
<img id="countdown-thumb" class="countdown-thumb" />
|
||||
<div class="countdown-text">
|
||||
<span id="countdown-title">Up next: ...</span>
|
||||
<span id="countdown-number">14</span>
|
||||
</div>
|
||||
<button id="countdown-play-now" class="mps-button mps-button-blue">Play Now</button>
|
||||
<button id="countdown-cancel" class="mps-button">Cancel</button>
|
||||
</div>
|
||||
<button id="countdown-play-now" class="mps-button mps-button-blue">Play Now</button>
|
||||
<button id="countdown-cancel" class="mps-button">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<noscript>
|
||||
|
|
@ -112,6 +112,18 @@
|
|||
<img src="{{ request.app["bucket.secure_uploads.get_endpoint"] }}/{{ product.s3_path }}/thumbnail1?ts={{ product.updated_timestamp }}" class="product-main" />
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if request.shop.watch_mode_enabled and product.extensions.get("product") not in video_extensions and product.extensions.get("product") not in audio_extensions %}
|
||||
{# Countdown overlay for static content (PDFs, images) #}
|
||||
<div id="watch-countdown" class="watch-countdown watch-countdown-static js-only" style="display:none">
|
||||
<img id="countdown-thumb" class="countdown-thumb" />
|
||||
<div class="countdown-text">
|
||||
<span id="countdown-title">Up next: ...</span>
|
||||
<span id="countdown-number">14</span>
|
||||
</div>
|
||||
<button id="countdown-play-now" class="mps-button mps-button-blue">Play Now</button>
|
||||
<button id="countdown-cancel" class="mps-button">Cancel</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<br/>
|
||||
|
||||
{% for file_key in product.file_thumbnail_keys %}
|
||||
|
|
@ -232,6 +244,11 @@
|
|||
{% endif %}
|
||||
<div>
|
||||
|
||||
{% if request.shop.watch_mode_enabled %}
|
||||
<label class="watch-autoplay-label js-only">
|
||||
<input type="checkbox" id="watch-autoplay-toggle" checked /> Autoplay
|
||||
</label>
|
||||
{% endif %}
|
||||
<div id="watch-queue" class="js-only" style="display:none">
|
||||
<h4>Queue</h4>
|
||||
<div id="queue-items"></div>
|
||||
|
|
|
|||
|
|
@ -36,11 +36,7 @@ def watch_json(request):
|
|||
|
||||
# Get extension and detect media type
|
||||
extension = product.extensions.get(file_key)
|
||||
media_type = get_media_type(extension)
|
||||
|
||||
if not media_type or media_type not in ("video", "audio"):
|
||||
request.response.status_int = 400
|
||||
return {"error": "Not a playable media file"}
|
||||
media_type = get_media_type(extension) or "other"
|
||||
|
||||
# Generate presigned URL for media
|
||||
bucket_name = request.app["bucket.secure_uploads"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue