fix(auth,download): playlists/likes 401, suppression downloads, 429 formats
CI / build-and-test (push) Failing after 8m20s
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:
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
|
||||
import { Observable, map } from 'rxjs';
|
||||
import { HttpClient, HttpErrorResponse, HttpParams, HttpResponse } from '@angular/common/http';
|
||||
import { Observable, map, retry, timer, throwError } from 'rxjs';
|
||||
|
||||
export interface DownloadFormat {
|
||||
id: string;
|
||||
@@ -61,6 +61,19 @@ export class DownloadService {
|
||||
return this.http.get<{ url: string; formats: DownloadFormat[]; title: string; duration: number }>(
|
||||
`/proxy/api/download/${encodeURIComponent(provider)}/${encodeURIComponent(videoId)}/formats`,
|
||||
{ params, withCredentials: true }
|
||||
).pipe(
|
||||
// La liste des formats dépend de yt-dlp/YouTube (parfois 429/5xx
|
||||
// transitoires) : 2 nouveaux essais espacés, jamais sur les 4xx
|
||||
// définitives (401/403/404) pour ne pas marteler le seau anti-abus.
|
||||
retry({
|
||||
count: 2,
|
||||
delay: (err: unknown, retryCount: number) => {
|
||||
const status = (err as HttpErrorResponse)?.status;
|
||||
const retryable = status === 0 || status === 429 || (typeof status === 'number' && status >= 500);
|
||||
if (!retryable) return throwError(() => err);
|
||||
return timer(1500 * retryCount);
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user