🎉 Initial commit: AudiOhm - Alternative à Spotify avec streaming YouTube
Features: - Frontend Flutter avec thème néon cyberpunk - Backend FastAPI avec streaming YouTube - Base de données PostgreSQL + Redis - Authentification JWT complète - Recherche multi-source (DB + YouTube) - Playlists CRUD avec drag & drop - Queue management - Settings avec audio quality - Interface adaptative (Desktop + Mobile) Tech Stack: - Frontend: Flutter 3.2+, Riverpod - Backend: Python 3.11+, FastAPI - Database: PostgreSQL 15+ - Cache: Redis 7+ - Streaming: yt-dlp + FFmpeg 🚀 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
/// API Service - Main HTTP client using Dio
|
||||
library;
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
|
||||
|
||||
import '../../../core/constants/api_constants.dart';
|
||||
import '../../providers/auth_provider.dart';
|
||||
|
||||
/// API Service provider
|
||||
final apiServiceProvider = Provider<Dio>((ref) {
|
||||
final authState = ref.watch(authProvider);
|
||||
final token = authState?.accessToken;
|
||||
|
||||
final options = BaseOptions(
|
||||
baseUrl: ApiConstants.baseUrl,
|
||||
connectTimeout: const Duration(milliseconds: ApiConstants.connectionTimeoutMs),
|
||||
receiveTimeout: const Duration(milliseconds: ApiConstants.receiveTimeoutMs),
|
||||
sendTimeout: const Duration(milliseconds: ApiConstants.sendTimeoutMs),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
if (token != null) 'Authorization': 'Bearer $token',
|
||||
},
|
||||
);
|
||||
|
||||
final dio = Dio(options);
|
||||
|
||||
// Add logger in debug mode
|
||||
dio.interceptors.add(
|
||||
PrettyDioLogger(
|
||||
requestHeader: true,
|
||||
requestBody: true,
|
||||
responseBody: true,
|
||||
responseHeader: false,
|
||||
error: true,
|
||||
compact: true,
|
||||
),
|
||||
);
|
||||
|
||||
// Add token refresh interceptor
|
||||
dio.interceptors.add(
|
||||
InterceptorsWrapper(
|
||||
onError: (error, handler) async {
|
||||
if (error.response?.statusCode == 401) {
|
||||
// Try to refresh token
|
||||
try {
|
||||
final newToken = await ref.read(authProvider.notifier).refreshToken();
|
||||
if (newToken != null) {
|
||||
// Retry original request with new token
|
||||
final opts = options.copyWith(
|
||||
headers: {
|
||||
...options.headers,
|
||||
'Authorization': 'Bearer $newToken',
|
||||
},
|
||||
);
|
||||
final clonedReq = await dio.fetch(opts..path = error.requestOptions.path);
|
||||
return handler.resolve(clonedReq);
|
||||
}
|
||||
} catch (e) {
|
||||
// Refresh failed, logout user
|
||||
ref.read(authProvider.notifier).logout();
|
||||
}
|
||||
}
|
||||
return handler.next(error);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
return dio;
|
||||
});
|
||||
|
||||
/// Get API client
|
||||
Dio getDio(Ref ref) {
|
||||
return ref.read(apiServiceProvider);
|
||||
}
|
||||
Reference in New Issue
Block a user