feat: Modernisation UI/UX et configuration Flutter multi-plateforme

Phase 1 - Corrections Critiques:
- Fixed memory leaks dans music_provider.dart (stream subscriptions)
- Fixed race conditions dans search_provider.dart (stale results)
- Fixed token refresh errors dans api_service.dart
- Improved error handling avec messages utilisateur
- Changed API URL to HTTPS by default

Phase 2 - Améliorations UX Desktop:
- Ajouté cursor pointers sur tous les éléments cliquables
- Implémenté hover states avec effets néon glow (200ms transitions)
- Créé skeleton loading states avec shimmer animation
- Ajouté widgets: ClickableWrapper, ErrorDisplay, SkeletonLoading
- Enhanced visual feedback pour desktop users

Phase 3 - Configuration Flutter:
- Configuré Android (Gradle 8.1.0, Kotlin 1.9.0, minSdk 21, targetSdk 34)
- Créé launcher icons cyberpunk néon (5 densités)
- Configuré Windows desktop (structure complète)
- Activé Linux desktop support
- Ajouté package équatable pour entités de domaine
- Corrigé imports (colors.dart, auth_provider.dart)
- Fixed Dio API compatibility (RequestOptions)

Documentation:
- STYLE_GUIDE.md: Guide complet (100+ pages)
- DESIGN_IMPLEMENTATION_GUIDE.md: Implémentation Flutter
- BUILD_STATUS.md: Status builds + troubleshooting
- QUICKSTART_BUILDS.md: Guide rapide
- BUILD_INDEX.md: Index documentation
- PHASE_1_CORRECTIONS.md: Corrections Phase 1
- PHASE_2_UX_IMPROVEMENTS.md: Améliorations Phase 2
- PR_REVIEW_SUMMARY.md: Revue code complète
- CODE_ANALYSIS_AND_PRIORITIES.md: Analyse code

Scripts & Builds:
- BUILD_ALL.sh: Script automatisé builds multi-plateforme
- builds/: Structure avec README par plateforme
- design-system/: Système de design complet

Backend:
- Ajouté streaming HTTP Range pour audio progressif
- Enhanced YouTube service avec métadonnées complètes
- Improved error handling et validation

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
root
2026-01-19 07:44:40 +00:00
parent a89c7894cf
commit 85dad89d5b
100 changed files with 13570 additions and 323 deletions
+85
View File
@@ -271,3 +271,88 @@ class MusicService:
related = await self.youtube.get_related_videos(track.youtube_id, max_results=limit)
return related[:limit]
async def get_stream_url_by_youtube_id(self, youtube_id: str) -> Optional[str]:
"""
Get stream URL for a YouTube video by youtube_id.
Args:
youtube_id: YouTube video ID
Returns:
Stream URL or None
"""
return await self.youtube.get_stream_url(youtube_id)
async def stream_audio_from_youtube(self, stream_url: str, range_header: str = None):
"""
Stream audio directly from YouTube with proper Range support.
Args:
stream_url: Direct stream URL from YouTube
range_header: HTTP Range header for partial content
Returns:
StreamingResponse with audio data
"""
from fastapi.responses import StreamingResponse
import httpx
# Fetch from YouTube stream URL
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
if range_header:
headers["Range"] = range_header
async with httpx.AsyncClient(timeout=30.0) as client:
# First, make a HEAD request to get content info
try:
head_response = await client.head(stream_url, headers=headers, follow_redirects=True)
content_type = head_response.headers.get("content-type", "audio/mpeg")
content_length = head_response.headers.get("content-length")
except:
content_type = "audio/mpeg"
content_length = None
# Now make the actual GET request for streaming
response = await client.get(stream_url, headers=headers, follow_redirects=True)
if response.status_code not in [200, 206]:
raise ValueError(f"Failed to fetch stream: HTTP {response.status_code}")
# Update content info from actual response
content_type = response.headers.get("content-type", content_type)
content_length = response.headers.get("content-length", content_length)
# Create async generator for streaming
async def audio_generator():
try:
async for chunk in response.aiter_bytes(chunk_size=8192):
yield chunk
except Exception as e:
print(f"Streaming error: {e}")
response_headers = {
"Accept-Ranges": "bytes",
"Content-Type": content_type,
}
if content_length:
response_headers["Content-Length"] = content_length
if range_header and response.status_code == 206:
content_range = response.headers.get("content-range")
if content_range:
response_headers["Content-Range"] = content_range
return StreamingResponse(
audio_generator(),
status_code=206,
headers=response_headers
)
return StreamingResponse(
audio_generator(),
status_code=200,
headers=response_headers
)