Add parent page navigation and PDF support
- PiP now controls parent page: clicking prev/next in PiP navigates the parent page URL - Add 'Go to Page' button (G key) to open current product page - Add PDF support: renders PDFs in iframe, opens in pop-out (not PiP) - PDFs and images fall back to pop-out player window - Pass product URLs through playerData for navigation - Audio gets small floating player, video gets PiP, PDFs get window
This commit is contained in:
parent
962a89c3a6
commit
f0b23ec0ff
6 changed files with 83 additions and 9 deletions
|
|
@ -62,10 +62,11 @@ DEFAULT_BUNDLE_METADATA = unicode(
|
|||
VIDEO_EXTENSIONS = ["mp4", "webm", "mkv", "avi", "mov", "wmv", "flv", "m4v", "ogv"]
|
||||
AUDIO_EXTENSIONS = ["mp3", "wav", "ogg", "m4a", "flac", "aac", "wma", "opus"]
|
||||
IMAGE_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "webp", "bmp", "svg"]
|
||||
DOCUMENT_EXTENSIONS = ["pdf"]
|
||||
|
||||
|
||||
def get_media_type(extension):
|
||||
"""Returns 'video', 'audio', 'image', or None based on file extension."""
|
||||
"""Returns 'video', 'audio', 'image', 'document', or None based on file extension."""
|
||||
if not extension:
|
||||
return None
|
||||
ext = extension.lower()
|
||||
|
|
@ -75,6 +76,8 @@ def get_media_type(extension):
|
|||
return "audio"
|
||||
elif ext in IMAGE_EXTENSIONS:
|
||||
return "image"
|
||||
elif ext in DOCUMENT_EXTENSIONS:
|
||||
return "document"
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -302,6 +302,20 @@
|
|||
e.preventDefault();
|
||||
toggleAutoResize();
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
e.preventDefault();
|
||||
if (typeof goToProductPage === 'function') {
|
||||
goToProductPage();
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
case 'P':
|
||||
e.preventDefault();
|
||||
if (typeof togglePip === 'function') {
|
||||
togglePip();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,11 @@ async function loadMedia(mediaElement, productId) {
|
|||
const match = scriptContent.match(/window\.playerData\s*=\s*(\{[^}]+\})/);
|
||||
if (match) {
|
||||
currentPlayerData = eval('(' + match[1] + ')');
|
||||
|
||||
// Navigate parent page to show the new product
|
||||
if (currentPlayerData.productUrl) {
|
||||
window.history.pushState({}, '', currentPlayerData.productUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -175,7 +180,7 @@ async function openMediaPlayer(productId) {
|
|||
}
|
||||
}
|
||||
|
||||
// Enter Picture-in-Picture mode
|
||||
// Enter Picture-in-Picture mode (only for video)
|
||||
if (document.pictureInPictureEnabled && media.tagName === 'VIDEO') {
|
||||
await media.play();
|
||||
await media.requestPictureInPicture();
|
||||
|
|
@ -199,9 +204,13 @@ async function openMediaPlayer(productId) {
|
|||
media.addEventListener('leavepictureinpicture', () => {
|
||||
document.body.removeChild(media);
|
||||
});
|
||||
} else {
|
||||
// Fallback: keep small floating player on page
|
||||
} else if (media.tagName === 'AUDIO') {
|
||||
// Audio: keep small floating player on page
|
||||
media.play();
|
||||
} else {
|
||||
// For non-media (PDFs, images), open in pop-out player window
|
||||
document.body.removeChild(media);
|
||||
window.open(`/player/${productId}`, 'mediaPlayer', 'width=800,height=600,menubar=no,toolbar=no,location=no,status=no,scrollbars=no');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error opening media player:', err);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
/* For documents (PDFs), fill the viewport */
|
||||
iframe#media {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Mobile optimizations */
|
||||
@media (max-width: 600px) {
|
||||
.controls-grid {
|
||||
|
|
@ -186,6 +191,10 @@
|
|||
</audio>
|
||||
{% elif media_type == 'image' %}
|
||||
<img id="media" src="{{ presigned_url }}" alt="{{ product.title }}" />
|
||||
{% elif media_type == 'document' %}
|
||||
<iframe id="media" src="{{ presigned_url }}" frameborder="0">
|
||||
Your browser does not support PDF viewing.
|
||||
</iframe>
|
||||
{% endif %}
|
||||
|
||||
<div class="product-title">{{ product.title }}</div>
|
||||
|
|
@ -214,8 +223,8 @@
|
|||
|
||||
<!-- Row 3: More options -->
|
||||
<button id="autoResizeBtn" onclick="toggleAutoResize()" title="Auto-Resize Window (R)">↔ Resize</button>
|
||||
<button onclick="goToProductPage()" title="Go to Product Page (G)">🔗 Page</button>
|
||||
<button onclick="window.close()" title="Close Window (ESC)">✕ Close</button>
|
||||
<div></div><!-- Empty cell for grid alignment -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -226,8 +235,24 @@
|
|||
window.playerData = {
|
||||
prevProductId: {{ ('"%s"' % prev_product_id) if prev_product_id else 'null' }},
|
||||
nextProductId: {{ ('"%s"' % next_product_id) if next_product_id else 'null' }},
|
||||
mediaType: "{{ media_type }}"
|
||||
mediaType: "{{ media_type }}",
|
||||
productId: "{{ product.id }}",
|
||||
productUrl: "{{ product_url }}",
|
||||
prevProductUrl: {{ ('"%s"' % prev_product_url) if prev_product_url else 'null' }},
|
||||
nextProductUrl: {{ ('"%s"' % next_product_url) if next_product_url else 'null' }}
|
||||
};
|
||||
|
||||
// Go to the product page
|
||||
function goToProductPage() {
|
||||
if (window.opener && !window.opener.closed) {
|
||||
// If opened from another window, navigate that window
|
||||
window.opener.location.href = window.playerData.productUrl;
|
||||
window.opener.focus();
|
||||
} else {
|
||||
// Otherwise open in new tab
|
||||
window.open(window.playerData.productUrl, '_blank');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -197,6 +197,11 @@ async function loadMedia(mediaElement, productId) {
|
|||
const match = scriptContent.match(/window\.playerData\s*=\s*(\{[^}]+\})/);
|
||||
if (match) {
|
||||
currentPlayerData = eval('(' + match[1] + ')');
|
||||
|
||||
// Navigate parent page to show the new product
|
||||
if (currentPlayerData.productUrl) {
|
||||
window.history.pushState({}, '', currentPlayerData.productUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -253,7 +258,7 @@ async function openMediaPlayer(productId) {
|
|||
}
|
||||
}
|
||||
|
||||
// Enter Picture-in-Picture mode
|
||||
// Enter Picture-in-Picture mode (only for video)
|
||||
if (document.pictureInPictureEnabled && media.tagName === 'VIDEO') {
|
||||
await media.play();
|
||||
await media.requestPictureInPicture();
|
||||
|
|
@ -277,9 +282,13 @@ async function openMediaPlayer(productId) {
|
|||
media.addEventListener('leavepictureinpicture', () => {
|
||||
document.body.removeChild(media);
|
||||
});
|
||||
} else {
|
||||
// Fallback: keep small floating player on page
|
||||
} else if (media.tagName === 'AUDIO') {
|
||||
// Audio: keep small floating player on page
|
||||
media.play();
|
||||
} else {
|
||||
// For non-media (PDFs, images), open in pop-out player window
|
||||
document.body.removeChild(media);
|
||||
window.open(`/player/${productId}`, 'mediaPlayer', 'width=800,height=600,menubar=no,toolbar=no,location=no,status=no,scrollbars=no');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error opening media player:', err);
|
||||
|
|
|
|||
|
|
@ -105,6 +105,17 @@ def player(request):
|
|||
if current_index < len(media_products) - 1:
|
||||
next_product_id = str(media_products[current_index + 1].id)
|
||||
|
||||
# Get product URLs for navigation
|
||||
product_url = product.absolute_url(request)
|
||||
prev_product_url = None
|
||||
next_product_url = None
|
||||
|
||||
if prev_product_id and current_index is not None and current_index > 0:
|
||||
prev_product_url = media_products[current_index - 1].absolute_url(request)
|
||||
|
||||
if next_product_id and current_index is not None and current_index < len(media_products) - 1:
|
||||
next_product_url = media_products[current_index + 1].absolute_url(request)
|
||||
|
||||
return {
|
||||
"product": product,
|
||||
"presigned_url": presigned_url,
|
||||
|
|
@ -112,4 +123,7 @@ def player(request):
|
|||
"extension": extension,
|
||||
"prev_product_id": prev_product_id,
|
||||
"next_product_id": next_product_id,
|
||||
"product_url": product_url,
|
||||
"prev_product_url": prev_product_url,
|
||||
"next_product_url": next_product_url,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue