v3.1.1
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
/**
|
||||
* embed.php — Standalone embeddable player page.
|
||||
* Designed to be used inside an <iframe> on third-party sites.
|
||||
*
|
||||
* Usage: <iframe src="https://yoursite.com/embed.php?v=video-slug"></iframe>
|
||||
*/
|
||||
require_once __DIR__ . '/includes/db.php';
|
||||
|
||||
$slug = trim($_GET['v'] ?? '');
|
||||
$video = $slug ? get_video_by_slug($slug) : null;
|
||||
|
||||
// Determine absolute base URL for media files.
|
||||
// We need absolute URLs here because the embed lives on a foreign domain.
|
||||
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
||||
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
|
||||
$script = dirname($_SERVER['SCRIPT_NAME'] ?? '/');
|
||||
$script = rtrim($script, '/');
|
||||
$base_url = $scheme . '://' . $host . $script . '/'; // e.g. https://tyclifford.com/live/
|
||||
|
||||
// X-Frame-Options: allow embedding from any origin.
|
||||
// If you want to restrict, change ALLOWALL to SAMEORIGIN or remove for CSP header instead.
|
||||
header('X-Frame-Options: ALLOWALL');
|
||||
header('Content-Security-Policy: frame-ancestors *');
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= $video ? htmlspecialchars($video['title'], ENT_QUOTES) . ' — TyClifford.com' : 'Video Player' ?></title>
|
||||
<link href="https://vjs.zencdn.net/8.10.0/video-js.css" rel="stylesheet"/>
|
||||
<script src="https://vjs.zencdn.net/8.10.0/video.min.js"></script>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
:root {
|
||||
--green: #00e87a;
|
||||
--purple: #b060ff;
|
||||
--bg: #09090f;
|
||||
--text: #e8e8f8;
|
||||
--text-2: #9898c0;
|
||||
--text-3: #58587a;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100%; height: 100%;
|
||||
background: var(--bg);
|
||||
overflow: hidden;
|
||||
font-family: 'Inter', system-ui, sans-serif;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.player-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Top shimmer bar — matches site theme */
|
||||
.shimmer-bar {
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 2px;
|
||||
z-index: 10;
|
||||
background: linear-gradient(90deg,
|
||||
#ff424d, #b060ff, #00c8ff, #00e87a,
|
||||
#00c8ff, #b060ff, #ff424d);
|
||||
background-size: 300% 100%;
|
||||
animation: shimmer 5s linear infinite;
|
||||
}
|
||||
@keyframes shimmer {
|
||||
from { background-position: 0% 50%; }
|
||||
to { background-position: 200% 50%; }
|
||||
}
|
||||
|
||||
/* Video.js fills the whole container */
|
||||
.video-js {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
position: absolute !important;
|
||||
inset: 0 !important;
|
||||
}
|
||||
|
||||
/* Custom VJS skin to match site */
|
||||
.video-js .vjs-big-play-button {
|
||||
background: rgba(176,96,255,.8) !important;
|
||||
border: 2px solid rgba(176,96,255,.95) !important;
|
||||
border-radius: 50% !important;
|
||||
width: 64px !important; height: 64px !important;
|
||||
top: 50% !important; left: 50% !important;
|
||||
transform: translate(-50%, -50%) !important;
|
||||
margin: 0 !important;
|
||||
line-height: 64px !important;
|
||||
transition: background .2s !important;
|
||||
}
|
||||
.video-js:hover .vjs-big-play-button {
|
||||
background: rgba(176,96,255,1) !important;
|
||||
}
|
||||
.video-js .vjs-control-bar {
|
||||
background: linear-gradient(transparent, rgba(0,0,0,.9)) !important;
|
||||
height: 3.2em !important;
|
||||
}
|
||||
.video-js .vjs-play-progress { background: var(--green) !important; }
|
||||
.video-js .vjs-volume-level { background: var(--green) !important; }
|
||||
.video-js .vjs-slider { background: rgba(255,255,255,.15) !important; }
|
||||
.video-js .vjs-load-progress { background: rgba(255,255,255,.1) !important; }
|
||||
.video-js .vjs-current-time,
|
||||
.video-js .vjs-duration,
|
||||
.video-js .vjs-time-divider { color: rgba(255,255,255,.8) !important; font-size: .7em !important; }
|
||||
|
||||
/* Title + branding overlay at top (fades out) */
|
||||
.title-overlay {
|
||||
position: absolute;
|
||||
top: 8px; left: 12px; right: 12px;
|
||||
z-index: 5;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
pointer-events: none;
|
||||
opacity: 1;
|
||||
transition: opacity .5s;
|
||||
}
|
||||
.title-overlay.hidden { opacity: 0; }
|
||||
|
||||
.title-text {
|
||||
font-size: .78rem;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
text-shadow: 0 1px 6px rgba(0,0,0,.8);
|
||||
line-height: 1.3;
|
||||
max-width: 70%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.brand-link {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: .6rem;
|
||||
letter-spacing: .12em;
|
||||
color: rgba(255,255,255,.55);
|
||||
text-decoration: none;
|
||||
text-shadow: 0 1px 4px rgba(0,0,0,.8);
|
||||
pointer-events: all;
|
||||
white-space: nowrap;
|
||||
transition: color .2s;
|
||||
}
|
||||
.brand-link:hover { color: var(--green); }
|
||||
|
||||
/* No-video state */
|
||||
.no-video {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%; height: 100%;
|
||||
gap: .75rem;
|
||||
background: var(--bg);
|
||||
}
|
||||
.no-video p {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: .72rem;
|
||||
color: var(--text-3);
|
||||
letter-spacing: .1em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="player-wrap" id="player-wrap">
|
||||
<div class="shimmer-bar"></div>
|
||||
|
||||
<?php if ($video && !empty($video['sources'])): ?>
|
||||
|
||||
<!-- Title + brand overlay -->
|
||||
<div class="title-overlay" id="title-overlay">
|
||||
<span class="title-text"><?= htmlspecialchars($video['title'], ENT_QUOTES) ?></span>
|
||||
<a class="brand-link" href="<?= $base_url ?>index.php?v=<?= urlencode($video['slug']) ?>"
|
||||
target="_blank" rel="noopener">tyclifford.com</a>
|
||||
</div>
|
||||
|
||||
<video id="embed-player"
|
||||
class="video-js vjs-default-skin vjs-big-play-centered"
|
||||
controls preload="metadata"
|
||||
<?php if ($video['thumbnail']): ?>
|
||||
poster="<?= htmlspecialchars($base_url . MEDIA_URL . $video['thumbnail'], ENT_QUOTES) ?>"
|
||||
<?php endif; ?>>
|
||||
<?php foreach ($video['sources'] as $src): ?>
|
||||
<source
|
||||
src="<?= htmlspecialchars($base_url . MEDIA_URL . $src['file_path'], ENT_QUOTES) ?>"
|
||||
type="<?= htmlspecialchars($src['mime_type'], ENT_QUOTES) ?>">
|
||||
<?php endforeach; ?>
|
||||
<p class="vjs-no-js">Your browser does not support HTML5 video.</p>
|
||||
</video>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<div class="no-video">
|
||||
<svg width="40" height="40" viewBox="0 0 24 24" fill="none"
|
||||
stroke="#58587a" stroke-width="1.5">
|
||||
<rect x="2" y="3" width="20" height="14" rx="2"/>
|
||||
<line x1="8" y1="21" x2="16" y2="21"/>
|
||||
<line x1="12" y1="17" x2="12" y2="21"/>
|
||||
</svg>
|
||||
<p><?= $slug ? 'video not found' : 'no video specified' ?></p>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($video && !empty($video['sources'])): ?>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var player = videojs('embed-player', {
|
||||
controls: true,
|
||||
autoplay: false,
|
||||
preload: 'metadata',
|
||||
fluid: false,
|
||||
responsive: false,
|
||||
playbackRates: [0.5, 1, 1.25, 1.5, 2],
|
||||
controlBar: {
|
||||
children: [
|
||||
'playToggle', 'volumePanel', 'currentTimeDisplay',
|
||||
'timeDivider', 'durationDisplay', 'progressControl',
|
||||
'playbackRateMenuButton', 'fullscreenToggle'
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
// Hide title overlay once user starts playing
|
||||
var overlay = document.getElementById('title-overlay');
|
||||
player.on('play', function () {
|
||||
if (overlay) overlay.classList.add('hidden');
|
||||
});
|
||||
player.on('pause', function () {
|
||||
if (overlay) overlay.classList.remove('hidden');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user