Embed voting clips on landing page
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
export type ClipEmbedKind = 'twitch' | 'youtube'
|
||||
|
||||
export interface ClipEmbed {
|
||||
kind: ClipEmbedKind
|
||||
src: string
|
||||
title: string
|
||||
}
|
||||
|
||||
export function buildClipEmbed(clipUrl: string, parentHost = currentParentHost()): ClipEmbed | null {
|
||||
const url = parseUrl(clipUrl)
|
||||
if (!url) return null
|
||||
|
||||
const twitchSlug = parseTwitchClipSlug(url)
|
||||
if (twitchSlug && parentHost) {
|
||||
const params = new URLSearchParams({ clip: twitchSlug, parent: parentHost })
|
||||
return {
|
||||
kind: 'twitch',
|
||||
src: `https://clips.twitch.tv/embed?${params.toString()}`,
|
||||
title: 'Twitch Clip Player',
|
||||
}
|
||||
}
|
||||
|
||||
const youtubeId = parseYoutubeVideoId(url)
|
||||
if (youtubeId) {
|
||||
return {
|
||||
kind: 'youtube',
|
||||
src: `https://www.youtube-nocookie.com/embed/${encodeURIComponent(youtubeId)}`,
|
||||
title: 'YouTube Video Player',
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function currentParentHost() {
|
||||
if (typeof window === 'undefined') return ''
|
||||
return window.location.hostname
|
||||
}
|
||||
|
||||
function parseUrl(value: string) {
|
||||
try {
|
||||
return new URL(value)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function parseTwitchClipSlug(url: URL) {
|
||||
const host = normalizeHost(url.hostname)
|
||||
const segments = pathSegments(url.pathname)
|
||||
|
||||
if (host === 'clips.twitch.tv') {
|
||||
return sanitizeSlug(segments[0])
|
||||
}
|
||||
|
||||
if (host === 'twitch.tv' && segments.length >= 3 && segments[1] === 'clip') {
|
||||
return sanitizeSlug(segments[2])
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function parseYoutubeVideoId(url: URL) {
|
||||
const host = normalizeHost(url.hostname)
|
||||
const segments = pathSegments(url.pathname)
|
||||
|
||||
if (host === 'youtu.be') {
|
||||
return sanitizeYoutubeId(segments[0])
|
||||
}
|
||||
|
||||
if (host === 'youtube.com') {
|
||||
if (segments[0] === 'watch') {
|
||||
return sanitizeYoutubeId(url.searchParams.get('v'))
|
||||
}
|
||||
|
||||
if (segments[0] === 'embed' || segments[0] === 'shorts' || segments[0] === 'live') {
|
||||
return sanitizeYoutubeId(segments[1])
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function normalizeHost(hostname: string) {
|
||||
return hostname.toLowerCase().replace(/^www\./, '').replace(/^m\./, '')
|
||||
}
|
||||
|
||||
function pathSegments(pathname: string) {
|
||||
return pathname.split('/').map((item) => item.trim()).filter(Boolean)
|
||||
}
|
||||
|
||||
function sanitizeSlug(value: string | null | undefined) {
|
||||
const slug = value?.trim()
|
||||
return slug && /^[A-Za-z0-9_-]+$/.test(slug) ? slug : null
|
||||
}
|
||||
|
||||
function sanitizeYoutubeId(value: string | null | undefined) {
|
||||
const id = value?.trim()
|
||||
return id && /^[A-Za-z0-9_-]{6,}$/.test(id) ? id : null
|
||||
}
|
||||
Reference in New Issue
Block a user