forked from BRETT/BRETT
54 lines
1.9 KiB
TypeScript
54 lines
1.9 KiB
TypeScript
import type { TwitchTarget } from '../../../shared/utils/twitch'
|
|
|
|
// Öffentliche Client-ID der Twitch-Web-App (gql.twitch.tv wird von twitch.tv selbst genutzt)
|
|
const TWITCH_CLIENT_ID = 'kimne78kx3ncx6brgo4mv6wki5h1ko'
|
|
|
|
function gqlStr(value: string): string {
|
|
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
|
}
|
|
|
|
interface TwitchPreview {
|
|
image: string | null
|
|
title: string | null
|
|
}
|
|
|
|
// Echtes Twitch-Thumbnail/-Titel via öffentlicher GQL-API — og:image liefert
|
|
// bei Twitch nur das generische Logo
|
|
export async function fetchTwitchPreview(target: TwitchTarget): Promise<TwitchPreview> {
|
|
try {
|
|
const query = target.kind === 'video'
|
|
? `{ video(id: "${gqlStr(target.id)}") { previewThumbnailURL(height: 360, width: 640) title } }`
|
|
: target.kind === 'clip'
|
|
? `{ clip(slug: "${gqlStr(target.id)}") { thumbnailURL title } }`
|
|
: `{ user(login: "${gqlStr(target.id.toLowerCase())}") { displayName broadcastSettings { title } profileImageURL(width: 300) stream { previewImageURL(width: 640, height: 360) } } }`
|
|
|
|
const res = await fetch('https://gql.twitch.tv/gql', {
|
|
method: 'POST',
|
|
signal: AbortSignal.timeout(5000),
|
|
headers: {
|
|
'content-type': 'application/json',
|
|
'client-id': TWITCH_CLIENT_ID,
|
|
},
|
|
body: JSON.stringify({ query }),
|
|
})
|
|
if (!res.ok) return { image: null, title: null }
|
|
const data = (await res.json())?.data
|
|
if (!data) return { image: null, title: null }
|
|
|
|
if (target.kind === 'video') {
|
|
return { image: data.video?.previewThumbnailURL ?? null, title: data.video?.title ?? null }
|
|
}
|
|
if (target.kind === 'clip') {
|
|
return { image: data.clip?.thumbnailURL ?? null, title: data.clip?.title ?? null }
|
|
}
|
|
const u = data.user
|
|
return {
|
|
image: u?.stream?.previewImageURL ?? u?.profileImageURL ?? null,
|
|
title: u?.broadcastSettings?.title ?? u?.displayName ?? null,
|
|
}
|
|
}
|
|
catch {
|
|
return { image: null, title: null }
|
|
}
|
|
}
|