From f3bfed9b565d10d06d3abb709b92a344a9538b5d Mon Sep 17 00:00:00 2001 From: xRangerDE Date: Fri, 13 Feb 2026 09:31:08 +0100 Subject: [PATCH] Fix VOD loading by reconnecting Twitch auth on demand Refresh Twitch authentication automatically when selecting streamers and retry Helix calls after 401 responses so valid streamers no longer show empty VOD states due to stale connection state. --- typescript-version/src/index.html | 11 +++-- typescript-version/src/main.ts | 70 ++++++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/typescript-version/src/index.html b/typescript-version/src/index.html index b16e108..57b6844 100644 --- a/typescript-version/src/index.html +++ b/typescript-version/src/index.html @@ -1628,8 +1628,11 @@ document.getElementById('pageTitle').textContent = name; if (!isConnected) { - updateStatus('Nicht verbunden', false); - return; + await connect(); + if (!isConnected) { + document.getElementById('vodGrid').innerHTML = '

Nicht verbunden

Bitte Twitch API Daten in den Einstellungen prufen.

'; + return; + } } document.getElementById('vodGrid').innerHTML = '

Lade VODs...

'; @@ -1887,8 +1890,8 @@ // Settings async function saveSettings() { - const clientId = document.getElementById('clientId').value; - const clientSecret = document.getElementById('clientSecret').value; + const clientId = document.getElementById('clientId').value.trim(); + const clientSecret = document.getElementById('clientSecret').value.trim(); const downloadPath = document.getElementById('downloadPath').value; const downloadMode = document.getElementById('downloadMode').value; const partMinutes = parseInt(document.getElementById('partMinutes').value); diff --git a/typescript-version/src/main.ts b/typescript-version/src/main.ts index 3d67f8f..e88fe4a 100644 --- a/typescript-version/src/main.ts +++ b/typescript-version/src/main.ts @@ -291,11 +291,19 @@ async function twitchLogin(): Promise { } } -async function getUserId(username: string): Promise { - if (!accessToken) return null; +async function ensureTwitchAuth(forceRefresh = false): Promise { + if (!forceRefresh && accessToken) { + return true; + } - try { - const response = await axios.get('https://api.twitch.tv/helix/users', { + return await twitchLogin(); +} + +async function getUserId(username: string): Promise { + if (!(await ensureTwitchAuth())) return null; + + const fetchUser = async () => { + return await axios.get('https://api.twitch.tv/helix/users', { params: { login: username }, headers: { 'Client-ID': config.client_id, @@ -303,18 +311,32 @@ async function getUserId(username: string): Promise { }, timeout: API_TIMEOUT }); + }; + + try { + const response = await fetchUser(); return response.data.data[0]?.id || null; } catch (e) { + if (axios.isAxiosError(e) && e.response?.status === 401 && (await ensureTwitchAuth(true))) { + try { + const retryResponse = await fetchUser(); + return retryResponse.data.data[0]?.id || null; + } catch (retryError) { + console.error('Error getting user after relogin:', retryError); + return null; + } + } + console.error('Error getting user:', e); return null; } } async function getVODs(userId: string): Promise { - if (!accessToken) return []; + if (!(await ensureTwitchAuth())) return []; - try { - const response = await axios.get('https://api.twitch.tv/helix/videos', { + const fetchVods = async () => { + return await axios.get('https://api.twitch.tv/helix/videos', { params: { user_id: userId, type: 'archive', @@ -326,18 +348,32 @@ async function getVODs(userId: string): Promise { }, timeout: API_TIMEOUT }); + }; + + try { + const response = await fetchVods(); return response.data.data; } catch (e) { + if (axios.isAxiosError(e) && e.response?.status === 401 && (await ensureTwitchAuth(true))) { + try { + const retryResponse = await fetchVods(); + return retryResponse.data.data; + } catch (retryError) { + console.error('Error getting VODs after relogin:', retryError); + return []; + } + } + console.error('Error getting VODs:', e); return []; } } async function getClipInfo(clipId: string): Promise { - if (!accessToken) return null; + if (!(await ensureTwitchAuth())) return null; - try { - const response = await axios.get('https://api.twitch.tv/helix/clips', { + const fetchClip = async () => { + return await axios.get('https://api.twitch.tv/helix/clips', { params: { id: clipId }, headers: { 'Client-ID': config.client_id, @@ -345,8 +381,22 @@ async function getClipInfo(clipId: string): Promise { }, timeout: API_TIMEOUT }); + }; + + try { + const response = await fetchClip(); return response.data.data[0] || null; } catch (e) { + if (axios.isAxiosError(e) && e.response?.status === 401 && (await ensureTwitchAuth(true))) { + try { + const retryResponse = await fetchClip(); + return retryResponse.data.data[0] || null; + } catch (retryError) { + console.error('Error getting clip after relogin:', retryError); + return null; + } + } + console.error('Error getting clip:', e); return null; }