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
55 lines
1.8 KiB
TypeScript
55 lines
1.8 KiB
TypeScript
import { Injectable, signal } from '@angular/core';
|
|
import { HttpClient } from '@angular/common/http';
|
|
import { Observable } from 'rxjs';
|
|
import { tap } from 'rxjs/operators';
|
|
import type { AuthUser } from './auth.service';
|
|
|
|
export interface UserPreferences {
|
|
language?: string | null;
|
|
defaultProvider?: string | null;
|
|
defaultProviders?: string[] | null;
|
|
theme?: 'light' | 'dark' | 'black' | 'system' | string | null;
|
|
videoQuality?: string | null;
|
|
region?: string | null;
|
|
version?: number | null;
|
|
}
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
export class UserService {
|
|
private _preferences = signal<UserPreferences | null>(null);
|
|
|
|
constructor(private http: HttpClient) {}
|
|
|
|
preferences() {
|
|
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>(`${this.apiBase()}/user/preferences`, { withCredentials: true }).pipe(
|
|
tap(p => this._preferences.set(p || {}))
|
|
);
|
|
}
|
|
|
|
updatePreferences(patch: Partial<UserPreferences>): Observable<UserPreferences> {
|
|
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>(`${this.apiBase()}/user/me`, { withCredentials: true });
|
|
}
|
|
}
|