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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user