fix(auth,download): playlists/likes 401, suppression downloads, 429 formats
CI / build-and-test (push) Failing after 8m20s

- likes + playlists: authMiddlewareCookieAware (cookies + Bearer) au lieu
  du Bearer seul -> corrige 401 Unauthorized meme connecte (creation
  playlist, ajout video, bouton J'aime)
- add-to-playlist/like-button/search-box: retire HttpClientModule local
  qui court-circuitait les intercepteurs fonctionnels
- intercepteur: refresh+retry sur 401 meme sans token en memoire (F5)
- UserService: apiBase() au lieu de /proxy/api en dur (prod :4000)
- J'aime: envoie titre/miniature, erreur visible au lieu de bouton mort
- download: seaux separes (lectures 120/min, ecritures 30/min, formats
  30/min) + reponses limiter en JSON rate_limited + Retry-After
- formats: cache memoire 10 min + ytdlpNetOpts + retry front avec backoff
- polling allege (downloads 5s, suivi job 4s, 429 transitoire non fatal)
- erreurs FR precises (http-error.util): 401/403/404/410/429/quota/500
  avec compte a rebours + bouton Reessayer
This commit is contained in:
2026-09-26 09:26:44 -04:00
parent 2db1f2deee
commit d5ceab7115
11 changed files with 482 additions and 73 deletions
+15 -3
View File
@@ -24,19 +24,31 @@ export class UserService {
return this._preferences();
}
/** Même règle que les autres services : /proxy/api en dev (proxy Angular),
* /api quand on est servi par le backend :4000 (prod/docker). L'URL codée
* en dur cassait loadMe/loadPreferences en prod (-> currentUser null). */
private apiBase(): string {
try {
const port = window?.location?.port || '';
return port && port !== '4000' ? '/proxy/api' : '/api';
} catch {
return '/api';
}
}
loadPreferences(): Observable<UserPreferences> {
return this.http.get<UserPreferences>('/proxy/api/user/preferences', { withCredentials: true }).pipe(
return this.http.get<UserPreferences>(`${this.apiBase()}/user/preferences`, { withCredentials: true }).pipe(
tap(p => this._preferences.set(p || {}))
);
}
updatePreferences(patch: Partial<UserPreferences>): Observable<UserPreferences> {
return this.http.patch<UserPreferences>('/proxy/api/user/preferences', patch, { withCredentials: true }).pipe(
return this.http.patch<UserPreferences>(`${this.apiBase()}/user/preferences`, patch, { withCredentials: true }).pipe(
tap(p => this._preferences.set(p || {}))
);
}
loadMe(): Observable<AuthUser> {
return this.http.get<AuthUser>('/proxy/api/user/me', { withCredentials: true });
return this.http.get<AuthUser>(`${this.apiBase()}/user/me`, { withCredentials: true });
}
}