From 1c51cc0b30b89b0b108fa42b9fa953fd44e1c712 Mon Sep 17 00:00:00 2001 From: Ty Clifford Date: Wed, 17 Jun 2026 23:44:39 -0400 Subject: [PATCH] - Lone Embed --- lone-embed.php | 1322 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1322 insertions(+) create mode 100644 lone-embed.php diff --git a/lone-embed.php b/lone-embed.php new file mode 100644 index 0000000..9495269 --- /dev/null +++ b/lone-embed.php @@ -0,0 +1,1322 @@ + 'video/mp4', + 'm4v' => 'video/mp4', + 'webm' => 'video/webm', + 'ogv' => 'video/ogg', + 'ogg' => 'video/ogg', + 'mov' => 'video/quicktime', + 'mkv' => 'video/x-matroska', + 'avi' => 'video/x-msvideo', + 'wmv' => 'video/x-ms-wmv', + 'flv' => 'video/x-flv', + 'ts' => 'video/mp2t', + '3gp' => 'video/3gpp', + '3g2' => 'video/3gpp2', + 'm3u8' => 'application/vnd.apple.mpegurl', + 'mpd' => 'application/dash+xml', + 'mp3' => 'audio/mpeg', + 'm4a' => 'audio/mp4', + 'aac' => 'audio/aac', + 'wav' => 'audio/wav', + 'flac' => 'audio/flac', + 'oga' => 'audio/ogg', + 'opus' => 'audio/ogg', + ]; + + $ext = extension_from_url($url); + return $map[$ext] ?? ''; +} + +function classify_kind(string $url, string $mime, string $forced_mode): string +{ + $forced = strtolower($forced_mode); + if (in_array($forced, ['video', 'audio', 'hls', 'dash', 'iframe'], true)) { + return $forced; + } + + $ext = extension_from_url($url); + $mime_lc = strtolower($mime); + + if ($ext === 'm3u8' || in_array($mime_lc, ['application/x-mpegurl', 'application/vnd.apple.mpegurl'], true)) { + return 'hls'; + } + + if ($ext === 'mpd' || $mime_lc === 'application/dash+xml') { + return 'dash'; + } + + if (starts_with($mime_lc, 'audio/')) { + return 'audio'; + } + + if (starts_with($mime_lc, 'video/')) { + return 'video'; + } + + if (in_array($ext, ['mp3', 'm4a', 'aac', 'wav', 'flac', 'oga', 'opus'], true)) { + return 'audio'; + } + + if (in_array($ext, ['mp4', 'm4v', 'webm', 'ogv', 'ogg', 'mov', 'mkv', 'avi', 'wmv', 'flv', 'ts', '3gp', '3g2'], true)) { + return 'video'; + } + + return 'unknown'; +} + +function normalize_url(string $url): string +{ + $url = trim(html_entity_decode($url, ENT_QUOTES | ENT_HTML5, 'UTF-8')); + if ($url === '') { + return ''; + } + + if (starts_with($url, '//')) { + $url = 'https:' . $url; + } + + $scheme = parse_url($url, PHP_URL_SCHEME); + if (!is_string($scheme) || $scheme === '') { + return $url; + } + + $scheme = strtolower($scheme); + if (!in_array($scheme, ['http', 'https'], true)) { + return ''; + } + + return $url; +} + +function append_query(string $base, array $params): string +{ + $query = http_build_query($params, '', '&', PHP_QUERY_RFC3986); + if ($query === '') { + return $base; + } + + return $base . (strpos($base, '?') === false ? '?' : '&') . $query; +} + +function parse_youtube_time(string $value): int +{ + $value = trim($value); + if ($value === '') { + return 0; + } + + if (ctype_digit($value)) { + return max(0, (int) $value); + } + + $seconds = 0; + if (preg_match_all('/(\d+)\s*([hms])/i', $value, $matches, PREG_SET_ORDER)) { + foreach ($matches as $match) { + $amount = (int) $match[1]; + $unit = strtolower($match[2]); + if ($unit === 'h') { + $seconds += $amount * 3600; + } elseif ($unit === 'm') { + $seconds += $amount * 60; + } else { + $seconds += $amount; + } + } + } + + return max(0, $seconds); +} + +function clean_token(string $value, string $pattern = '/[^A-Za-z0-9_-]/'): string +{ + $clean = preg_replace($pattern, '', trim($value)); + return is_string($clean) ? $clean : ''; +} + +function twitch_parent_host(): string +{ + $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost'; + $host = strtolower(trim((string) $host)); + $host = preg_replace('/:\d+$/', '', $host); + $host = is_string($host) ? $host : 'localhost'; + return $host !== '' ? $host : 'localhost'; +} + +function provider_embed(string $url): ?array +{ + $parts = @parse_url($url); + if (!is_array($parts) || empty($parts['host'])) { + return null; + } + + $host = strtolower((string) $parts['host']); + $path = isset($parts['path']) ? (string) $parts['path'] : ''; + $segments = path_segments($url); + $query = get_query_values($url); + + if (host_matches($host, 'youtu.be') || host_matches($host, 'youtube.com') || host_matches($host, 'youtube-nocookie.com')) { + $id = ''; + if (host_matches($host, 'youtu.be') && isset($segments[0])) { + $id = $segments[0]; + } + if ($id === '' && isset($query['v'])) { + $id = scalar_string($query['v']); + } + if ($id === '' && preg_match('#/(?:embed|shorts|live|v)/([^/?#]+)#', $path, $m)) { + $id = $m[1]; + } + + $id = clean_token($id); + if ($id !== '') { + $params = ['rel' => '0', 'modestbranding' => '1', 'playsinline' => '1']; + $start = 0; + if (isset($query['start'])) { + $start = parse_youtube_time(scalar_string($query['start'])); + } elseif (isset($query['t'])) { + $start = parse_youtube_time(scalar_string($query['t'])); + } + if ($start > 0) { + $params['start'] = (string) $start; + } + + return [ + 'provider' => 'youtube', + 'embed' => append_query('https://www.youtube-nocookie.com/embed/' . rawurlencode($id), $params), + ]; + } + + if (isset($query['list'])) { + $list = clean_token(scalar_string($query['list'])); + if ($list !== '') { + return [ + 'provider' => 'youtube', + 'embed' => append_query('https://www.youtube-nocookie.com/embed/videoseries', [ + 'list' => $list, + 'rel' => '0', + 'modestbranding' => '1', + 'playsinline' => '1', + ]), + ]; + } + } + } + + if (host_matches($host, 'vimeo.com')) { + $id = ''; + if (preg_match('#/(?:video/)?(\d+)#', $path, $m)) { + $id = $m[1]; + } + + if ($id !== '') { + return [ + 'provider' => 'vimeo', + 'embed' => append_query('https://player.vimeo.com/video/' . rawurlencode($id), [ + 'title' => '0', + 'byline' => '0', + 'portrait' => '0', + ]), + ]; + } + } + + if (host_matches($host, 'dailymotion.com') || host_matches($host, 'dai.ly')) { + $id = ''; + if (host_matches($host, 'dai.ly') && isset($segments[0])) { + $id = $segments[0]; + } + if ($id === '' && preg_match('#/(?:embed/)?video/([^/?#_]+)#', $path, $m)) { + $id = $m[1]; + } + + $id = clean_token($id); + if ($id !== '') { + return [ + 'provider' => 'dailymotion', + 'embed' => 'https://www.dailymotion.com/embed/video/' . rawurlencode($id), + ]; + } + } + + if (host_matches($host, 'twitch.tv')) { + $parent = twitch_parent_host(); + + if (preg_match('#/videos/(\d+)#', $path, $m)) { + return [ + 'provider' => 'twitch', + 'embed' => append_query('https://player.twitch.tv/', [ + 'video' => $m[1], + 'parent' => $parent, + 'autoplay' => 'false', + ]), + ]; + } + + if (preg_match('#/([^/]+)/clip/([^/?#]+)#', $path, $m)) { + return [ + 'provider' => 'twitch', + 'embed' => append_query('https://clips.twitch.tv/embed', [ + 'clip' => clean_token($m[2]), + 'parent' => $parent, + 'autoplay' => 'false', + ]), + ]; + } + + if (isset($segments[0]) && $segments[0] !== '') { + return [ + 'provider' => 'twitch', + 'embed' => append_query('https://player.twitch.tv/', [ + 'channel' => clean_token($segments[0]), + 'parent' => $parent, + 'autoplay' => 'false', + ]), + ]; + } + } + + if (host_matches($host, 'clips.twitch.tv') && isset($segments[0])) { + return [ + 'provider' => 'twitch', + 'embed' => append_query('https://clips.twitch.tv/embed', [ + 'clip' => clean_token($segments[0]), + 'parent' => twitch_parent_host(), + 'autoplay' => 'false', + ]), + ]; + } + + if (host_matches($host, 'facebook.com') || host_matches($host, 'fb.watch')) { + return [ + 'provider' => 'facebook', + 'embed' => append_query('https://www.facebook.com/plugins/video.php', [ + 'href' => $url, + 'show_text' => 'false', + 'width' => '1280', + ]), + ]; + } + + if (host_matches($host, 'tiktok.com') && preg_match('#/video/(\d+)#', $path, $m)) { + return [ + 'provider' => 'tiktok', + 'embed' => 'https://www.tiktok.com/embed/v2/' . rawurlencode($m[1]), + ]; + } + + if (host_matches($host, 'instagram.com') && preg_match('#/(p|reel|tv)/([^/?#]+)#', $path, $m)) { + return [ + 'provider' => 'instagram', + 'embed' => 'https://www.instagram.com/' . rawurlencode($m[1]) . '/' . rawurlencode($m[2]) . '/embed', + ]; + } + + if ((host_matches($host, 'twitter.com') || host_matches($host, 'x.com')) && preg_match('#/status/(\d+)#', $path, $m)) { + return [ + 'provider' => 'twitter', + 'embed' => append_query('https://platform.twitter.com/embed/Tweet.html', ['id' => $m[1]]), + ]; + } + + if (host_matches($host, 'soundcloud.com')) { + return [ + 'provider' => 'soundcloud', + 'embed' => append_query('https://w.soundcloud.com/player/', [ + 'url' => $url, + 'auto_play' => 'false', + 'show_teaser' => 'true', + ]), + ]; + } + + if (host_matches($host, 'open.spotify.com') && isset($segments[0], $segments[1])) { + $type = clean_token($segments[0]); + $id = clean_token($segments[1]); + if (in_array($type, ['album', 'artist', 'episode', 'playlist', 'show', 'track'], true) && $id !== '') { + return [ + 'provider' => 'spotify', + 'embed' => 'https://open.spotify.com/embed/' . rawurlencode($type) . '/' . rawurlencode($id), + ]; + } + } + + if (host_matches($host, 'drive.google.com')) { + $id = ''; + if (preg_match('#/file/d/([^/]+)#', $path, $m)) { + $id = $m[1]; + } elseif (isset($query['id'])) { + $id = scalar_string($query['id']); + } + + $id = clean_token($id); + if ($id !== '') { + return [ + 'provider' => 'google-drive', + 'embed' => 'https://drive.google.com/file/d/' . rawurlencode($id) . '/preview', + ]; + } + } + + if ((host_matches($host, 'wistia.com') || host_matches($host, 'wi.st')) && preg_match('#/(?:medias/)?([A-Za-z0-9]+)#', $path, $m)) { + return [ + 'provider' => 'wistia', + 'embed' => 'https://fast.wistia.net/embed/iframe/' . rawurlencode($m[1]), + ]; + } + + if (host_matches($host, 'streamable.com') && isset($segments[0])) { + return [ + 'provider' => 'streamable', + 'embed' => 'https://streamable.com/e/' . rawurlencode(clean_token($segments[0])), + ]; + } + + if (host_matches($host, 'loom.com') && isset($segments[0], $segments[1]) && $segments[0] === 'share') { + return [ + 'provider' => 'loom', + 'embed' => 'https://www.loom.com/embed/' . rawurlencode(clean_token($segments[1])), + ]; + } + + return null; +} + +function rewrite_direct_url(string $url): string +{ + $host = strtolower((string) (parse_url($url, PHP_URL_HOST) ?? '')); + $path = (string) (parse_url($url, PHP_URL_PATH) ?? ''); + + if (host_matches($host, 'dropbox.com')) { + $parts = @parse_url($url); + if (is_array($parts)) { + $query = []; + if (isset($parts['query'])) { + parse_str((string) $parts['query'], $query); + } + unset($query['dl'], $query['raw']); + $query['raw'] = '1'; + + $rebuilt = ($parts['scheme'] ?? 'https') . '://' . ($parts['host'] ?? 'www.dropbox.com'); + $rebuilt .= $parts['path'] ?? ''; + $rebuilt = append_query($rebuilt, $query); + if (isset($parts['fragment'])) { + $rebuilt .= '#' . $parts['fragment']; + } + return $rebuilt; + } + } + + if (host_matches($host, 'github.com') && preg_match('#^/([^/]+)/([^/]+)/blob/([^/]+)/(.+)$#', $path, $m)) { + return 'https://raw.githubusercontent.com/' . rawurlencode($m[1]) . '/' . rawurlencode($m[2]) . '/' . rawurlencode($m[3]) . '/' . str_replace('%2F', '/', rawurlencode($m[4])); + } + + return $url; +} + +function source_from_raw(string $raw, string $forced_mode): ?array +{ + $raw = trim($raw); + if ($raw === '') { + return null; + } + + $mime = ''; + if (strpos($raw, '|') !== false) { + [$raw, $mime] = explode('|', $raw, 2); + $mime = trim($mime); + } + + $original_url = normalize_url($raw); + if ($original_url === '') { + return null; + } + + $provider = provider_embed($original_url); + $url = $provider ? $original_url : rewrite_direct_url($original_url); + if ($mime === '') { + $mime = guess_mime($url); + } + + $kind = classify_kind($url, $mime, $forced_mode); + if ($provider && strtolower($forced_mode) === 'auto') { + $kind = 'iframe'; + } + + if (strtolower($forced_mode) === 'iframe') { + $kind = 'iframe'; + } + + $ext = extension_from_url($url); + $label = $provider['provider'] ?? ($ext !== '' ? $ext : ($kind === 'unknown' ? 'url' : $kind)); + + return [ + 'url' => $url, + 'originalUrl' => $original_url, + 'embed' => $provider['embed'] ?? $url, + 'provider' => $provider['provider'] ?? '', + 'mime' => $mime, + 'kind' => $kind, + 'label' => $label, + ]; +} + +function query_bool(string $name, bool $default = false): bool +{ + if (!array_key_exists($name, $_GET)) { + return $default; + } + + $value = strtolower(trim((string) $_GET[$name])); + if (in_array($value, ['1', 'true', 'yes', 'on'], true)) { + return true; + } + if (in_array($value, ['0', 'false', 'no', 'off'], true)) { + return false; + } + + return $default; +} + +function media_type_attr(array $source): string +{ + $mime = isset($source['mime']) ? trim((string) $source['mime']) : ''; + return $mime !== '' ? ' type="' . h($mime) . '"' : ''; +} + +function media_common_attrs(array $config): string +{ + $attrs = []; + + if (($config['controls'] ?? true) !== false) { + $attrs[] = 'controls'; + } + if (($config['autoplay'] ?? false) === true) { + $attrs[] = 'autoplay'; + } + if (($config['muted'] ?? false) === true || ($config['autoplay'] ?? false) === true) { + $attrs[] = 'muted'; + } + if (($config['loop'] ?? false) === true) { + $attrs[] = 'loop'; + } + + $attrs[] = 'preload="metadata"'; + + $crossorigin = trim((string) ($config['crossorigin'] ?? '')); + if ($crossorigin !== '') { + $attrs[] = 'crossorigin="' . h($crossorigin) . '"'; + } + + return implode(' ', $attrs); +} + +$title = trim((string) ($_GET['title'] ?? '')); +$poster = normalize_url((string) ($_GET['poster'] ?? '')); +$mode = strtolower(trim((string) ($_GET['mode'] ?? 'auto'))); +if (!in_array($mode, ['auto', 'video', 'audio', 'hls', 'dash', 'iframe'], true)) { + $mode = 'auto'; +} + +$primary_raw = ''; +foreach (['video', 'url', 'src', 'v', 'slug'] as $key) { + if (isset($_GET[$key]) && trim((string) $_GET[$key]) !== '') { + $primary_raw = trim((string) $_GET[$key]); + break; + } +} + +$sources = []; +if ($primary_raw !== '') { + $source = source_from_raw($primary_raw, $mode); + if ($source !== null) { + $sources[] = $source; + } +} + +for ($i = 2; $i <= 10; $i++) { + foreach (["video{$i}", "url{$i}", "src{$i}"] as $key) { + if (isset($_GET[$key]) && trim((string) $_GET[$key]) !== '') { + $source = source_from_raw(trim((string) $_GET[$key]), $mode); + if ($source !== null) { + $sources[] = $source; + } + break; + } + } +} + +$crossorigin = strtolower(trim((string) ($_GET['crossorigin'] ?? ''))); +if (!in_array($crossorigin, ['anonymous', 'use-credentials'], true)) { + $crossorigin = ''; +} + +$config = [ + 'sources' => $sources, + 'title' => $title, + 'poster' => $poster, + 'autoplay' => query_bool('autoplay', false), + 'muted' => query_bool('muted', false), + 'loop' => query_bool('loop', false), + 'controls' => query_bool('controls', true), + 'playsinline' => true, + 'iframeFallback' => query_bool('iframe_fallback', true), + 'crossorigin' => $crossorigin, + 'withCredentials' => query_bool('with_credentials', false), +]; + +$primary_source = $sources[0] ?? null; + +$json_config = json_encode( + $config, + JSON_UNESCAPED_SLASHES + | JSON_UNESCAPED_UNICODE + | JSON_HEX_TAG + | JSON_HEX_AMP + | JSON_HEX_APOS + | JSON_HEX_QUOT +); +if (!is_string($json_config)) { + $json_config = '{"sources":[]}'; +} + +header_remove('X-Frame-Options'); +header_remove('Content-Security-Policy'); +header_remove('X-Content-Security-Policy'); +header('Content-Type: text/html; charset=utf-8'); +header("Content-Security-Policy: default-src * data: blob: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: 'unsafe-inline' 'unsafe-eval'; style-src * 'unsafe-inline'; img-src * data: blob:; media-src * data: blob:; frame-src *; connect-src *"); +header('Referrer-Policy: no-referrer-when-downgrade'); +header('Cross-Origin-Resource-Policy: cross-origin'); +header('X-Content-Type-Options: nosniff'); +?> + + + + + + <?= $title !== '' ? h($title) . ' - Player' : 'Player' ?> + + + + + +
+
+ + 0): ?> +
+
+ +
+ +
+ +
+ + +
+
+
style="background-image:url('')">
+ +
+
+ + + + +
+
+ + + +
+
+ + + + + + + +
+
+

No media URL supplied

+

Use ?video=https%3A%2F%2Fexample.com%2Fclip.mp4 or ?url=....

+
+
+ +
+ + 0): ?> + + + +