forked from BRETT/BRETT
69 lines
2.4 KiB
TypeScript
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`
|
|
}
|