diff --git a/player/embed.php b/player/embed.php
new file mode 100644
index 0000000..2507e99
--- /dev/null
+++ b/player/embed.php
@@ -0,0 +1,246 @@
+ on third-party sites.
+ *
+ * Usage:
+ */
+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 *');
+?>
+
+
+
+
+
+ = $video ? htmlspecialchars($video['title'], ENT_QUOTES) . ' — TyClifford.com' : 'Video Player' ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
= htmlspecialchars($video['title'], ENT_QUOTES) ?>
+
tyclifford.com
+
+
+
+
+
+
+
+
+
= $slug ? 'video not found' : 'no video specified' ?>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/player/includes/layout.php b/player/includes/layout.php
index acc532f..51204ad 100644
--- a/player/includes/layout.php
+++ b/player/includes/layout.php
@@ -219,7 +219,7 @@ function render_head(string $title = 'Media — TyClifford.com', string $extra_c
function render_topbar(string $active = ''): void {
$title = setting('site_title', 'Ty Clifford');
- $sub = setting('site_sub', 'tyclifford.com / media');
+ $sub = setting('site_sub', 'tyclifford.com / player');
?>
@@ -243,7 +243,7 @@ function render_topbar(string $active = ''): void {
function render_footer(): void { ?>
+
+ ';
+ ?>
+
+
+
+
+
+
+ Recommended: width="560" height="315" — any 16:9 size works. Add style="border:0;border-radius:6px" for no border.
+
+
+
+
+
@@ -305,7 +403,50 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
}
+
+ // Embed panel toggle
+ var toggleBtn = document.getElementById('embed-toggle');
+ var panel = document.getElementById('embed-panel');
+ if (toggleBtn && panel) {
+ toggleBtn.addEventListener('click', function() {
+ var open = panel.classList.toggle('open');
+ toggleBtn.classList.toggle('active', open);
+ toggleBtn.setAttribute('aria-expanded', open ? 'true' : 'false');
+ });
+ }
});
+
+// Copy embed code to clipboard
+function copyEmbed(btn) {
+ var targetId = btn.getAttribute('data-target');
+ var el = document.getElementById(targetId);
+ if (!el) return;
+ var text = el.textContent || el.innerText;
+ navigator.clipboard.writeText(text).then(function() {
+ btn.textContent = 'Copied!';
+ btn.classList.add('copied');
+ setTimeout(function() {
+ btn.textContent = 'Copy';
+ btn.classList.remove('copied');
+ }, 2000);
+ }).catch(function() {
+ // Fallback for older browsers
+ var ta = document.createElement('textarea');
+ ta.value = text;
+ ta.style.position = 'fixed';
+ ta.style.opacity = '0';
+ document.body.appendChild(ta);
+ ta.select();
+ document.execCommand('copy');
+ document.body.removeChild(ta);
+ btn.textContent = 'Copied!';
+ btn.classList.add('copied');
+ setTimeout(function() {
+ btn.textContent = 'Copy';
+ btn.classList.remove('copied');
+ }, 2000);
+ });
+}