From 41875dc50dc3f7e4ceb1acaca222bb2c8bc4185d Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Sat, 26 Sep 2026 23:01:10 -0400 Subject: [PATCH] =?UTF-8?q?fix(sync):=20403=20InnerTube=20=3D=20version=20?= =?UTF-8?q?client=20invent=C3=A9e;=20aligne=20WEB=202.20260623.01.00=20+?= =?UTF-8?q?=20expose=20ytReason?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/index.mjs | 1 + server/oauth.mjs | 11 +++++++++-- src/components/library/import/import.component.ts | 4 +++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/server/index.mjs b/server/index.mjs index 50dc6fd..50ade20 100644 --- a/server/index.mjs +++ b/server/index.mjs @@ -716,6 +716,7 @@ r.get('/oauth/google/yt-history', authMiddlewareCookieAware, oauthLimiter, async return res.json({ items, count: items.length, hasMore }); } catch (error) { const out = { error: error?.message || 'ythistory_fetch_failed' }; + if (error?.ytReason) out.ytReason = error.ytReason; if (error?.status === 401) { out.hint = 'Session Google expirée : déconnectez puis reconnectez Google.'; } diff --git a/server/oauth.mjs b/server/oauth.mjs index 8bf6a52..cf4bd59 100644 --- a/server/oauth.mjs +++ b/server/oauth.mjs @@ -506,7 +506,12 @@ async function innertubePost(path, apiKey, accessToken, body, label = 'innertube if (!resp.ok) { const err = new Error(`${label}_failed_${resp.status}`); err.status = resp.status === 401 ? 401 : resp.status; - err.details = data?.error || undefined; + // Motif YouTube (sans PII) pour diagnostiquer : ex. rateLimitExceeded, + // botGuard, authError... remonte jusqu'à l'UI. + try { + const e0 = data?.error?.errors?.[0] || {}; + err.ytReason = String(e0.reason || data?.error?.message || '').slice(0, 160) || undefined; + } catch {} throw err; } return data; @@ -522,7 +527,9 @@ async function innertubePost(path, apiKey, accessToken, body, label = 'innertube } function innertubeContext() { - return { client: { clientName: 'WEB', clientVersion: '2.20260101.00.00', hl: 'fr', gl: 'FR' } }; + // Version du client WEB alignée sur youtubei.js (dépendance du projet) : + // une version inconnue/inventée est rejetée en 403 par l'anti-bot. + return { client: { clientName: 'WEB', clientVersion: '2.20260623.01.00', hl: 'fr', gl: 'FR' } }; } /** Boucle browse + continuations générique (FEhistory, WL, ...). */ diff --git a/src/components/library/import/import.component.ts b/src/components/library/import/import.component.ts index ba53f8d..cfbdea9 100644 --- a/src/components/library/import/import.component.ts +++ b/src/components/library/import/import.component.ts @@ -157,7 +157,9 @@ export class ImportComponent implements OnInit { } catch (e: any) { const code = e?.error?.error || e?.message || 'ythistory_fetch_failed'; const hint = e?.error?.hint; - this.ytAutoError.set(hint ? `${code} — ${hint}` : code); + const ytReason = e?.error?.ytReason; + const extra = [hint, ytReason ? `YouTube: ${ytReason}` : ''].filter(Boolean).join(' — '); + this.ytAutoError.set(extra ? `${code} — ${extra}` : code); } finally { this.ytAutoLoading.set(false); }