Files
BRETT/shared/utils/twitch.ts
T
2026-10-03 20:07:49 +02:00

69 lines
2.4 KiB
TypeScript

export interface TwitchTarget {
kind: 'video' | 'channel' | 'clip'
id: string
}
// Twitch-Pfade, die keine Kanalnamen sind
const RESERVED_PATHS = new Set([
'directory', 'downloads', 'drops', 'friends', 'inventory', 'jobs', 'messages',
'moderator', 'notifications', 'p', 'payments', 'popout', 'products', 'settings',
'subscriptions', 'turbo', 'videos', 'wallet', 'broadcast', 'search', 'activate',
])
export function getTwitchTarget(href: string): TwitchTarget | null {
try {
const url = new URL(href)
const host = url.hostname.replace(/^(www\.|m\.)/, '')
// clips.twitch.tv/{slug}
if (host === 'clips.twitch.tv') {
const slug = url.pathname.split('/').filter(Boolean)[0]
return slug ? { kind: 'clip', id: slug } : null
}
if (host !== 'twitch.tv') return null
const seg = url.pathname.split('/').filter(Boolean)
// twitch.tv/videos/{id}
if (seg[0] === 'videos' && /^\d+$/.test(seg[1] ?? '')) {
return { kind: 'video', id: seg[1]! }
}
// twitch.tv/{channel}/clip/{slug}
if (seg.length === 3 && seg[1] === 'clip') {
return { kind: 'clip', id: seg[2]! }
}
// twitch.tv/{channel}
if (seg.length === 1 && /^[\w]{2,25}$/.test(seg[0]!) && !RESERVED_PATHS.has(seg[0]!.toLowerCase())) {
return { kind: 'channel', id: seg[0]! }
}
return null
}
catch {
return null
}
}
export function serializeTwitchTarget(t: TwitchTarget | null): string | null {
return t ? `${t.kind}:${t.id}` : null
}
export function parseTwitchTarget(value: string): TwitchTarget | null {
const i = value.indexOf(':')
if (i < 0) return null
const kind = value.slice(0, i)
const id = value.slice(i + 1)
if ((kind !== 'video' && kind !== 'channel' && kind !== 'clip') || !id) return null
return { kind, id }
}
// Twitch-Embeds brauchen zwingend ?parent=<Hostname der einbettenden Seite>
export function twitchEmbedUrl(target: TwitchTarget | string | null, parent: string): string | null {
const t = typeof target === 'string' ? parseTwitchTarget(target) : target
if (!t) return null
const p = `parent=${encodeURIComponent(parent)}`
const id = encodeURIComponent(t.id)
if (t.kind === 'clip') return `https://clips.twitch.tv/embed?clip=${id}&${p}&autoplay=false`
if (t.kind === 'channel') return `https://player.twitch.tv/?channel=${id}&${p}`
return `https://player.twitch.tv/?video=${id}&${p}&autoplay=false`
}