prod: UI Optimisée mise en production

- Documentation archivée et réorganisée
- Backend: Ajout tests, migrations, library service, rate limiting
- Frontend: Suppression Flutter, focus sur interface web HTML/JS
- Tailwind CSS ajouté pour le style
- Améliorations UX et corrections bugs

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-20 09:56:39 +00:00
parent bc03225e47
commit 801e6a050b
263 changed files with 33100 additions and 23058 deletions
+77 -1
View File
@@ -1,4 +1,5 @@
"""Music service."""
import logging
from typing import List, Optional
from uuid import UUID
@@ -8,6 +9,8 @@ from sqlalchemy.orm import selectinload
from app.models.track import Track
from app.models.artist import Artist
logger = logging.getLogger(__name__)
from app.models.album import Album
from app.services.youtube_service import YouTubeService
@@ -331,7 +334,7 @@ class MusicService:
async for chunk in response.aiter_bytes(chunk_size=8192):
yield chunk
except Exception as e:
print(f"Streaming error: {e}")
logger.error(f"Streaming error: {e}")
response_headers = {
"Accept-Ranges": "bytes",
@@ -356,3 +359,76 @@ class MusicService:
status_code=200,
headers=response_headers
)
async def get_trending(
self,
limit: int = 20,
days: int = 7,
) -> List[dict]:
"""
Get trending tracks based on play count and recent listens.
Args:
limit: Maximum number of tracks
days: Number of days to look back for trending
Returns:
List of trending tracks with metadata
"""
from datetime import datetime, timedelta
from app.models.listening_history import ListeningHistory
# Calculate date threshold
threshold = datetime.now() - timedelta(days=days)
# Get tracks with most plays in the recent period
# Count recent plays from ListeningHistory
from sqlalchemy import func
stmt = (
select(
Track.id,
Track.title,
Track.duration,
Track.youtube_id,
Track.image_url,
Track.play_count,
func.count(ListeningHistory.id).label("recent_plays"),
Artist.id.label("artist_id"),
Artist.name.label("artist_name"),
)
.join(Track.artist)
.outerjoin(
ListeningHistory,
(ListeningHistory.track_id == Track.id) &
(ListeningHistory.created_at >= threshold)
)
.group_by(Track.id, Artist.id)
.order_by(
func.count(ListeningHistory.id).desc(), # Order by recent plays
Track.created_at.desc()
)
.limit(limit)
)
result = await self.db.execute(stmt)
rows = result.all()
# Convert to dict format
tracks = []
for row in rows:
tracks.append({
"id": str(row.id),
"title": row.title,
"duration": row.duration,
"youtube_id": row.youtube_id,
"image_url": row.image_url,
"play_count": row.play_count,
"artist": {
"id": str(row.artist_id),
"name": row.artist_name
} if row.artist_id else None,
"artist_name": row.artist_name,
})
return tracks