Initial commit - SoundWave v1.0
- Full PWA support with offline capabilities - Comprehensive search across songs, playlists, and channels - Offline playlist manager with download tracking - Pre-built frontend for zero-build deployment - Docker-based deployment with docker compose - Material-UI dark theme interface - YouTube audio download and management - Multi-user authentication support
This commit is contained in:
commit
51679d1943
254 changed files with 37281 additions and 0 deletions
0
backend/stats/__init__.py
Normal file
0
backend/stats/__init__.py
Normal file
5
backend/stats/admin.py
Normal file
5
backend/stats/admin.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
"""Stats admin"""
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
# No models to register for stats
|
||||
0
backend/stats/migrations/__init__.py
Normal file
0
backend/stats/migrations/__init__.py
Normal file
5
backend/stats/models.py
Normal file
5
backend/stats/models.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
"""Stats models"""
|
||||
|
||||
from django.db import models
|
||||
|
||||
# Stats are calculated from aggregations, no models needed
|
||||
24
backend/stats/serializers.py
Normal file
24
backend/stats/serializers.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
"""Stats serializers"""
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class AudioStatsSerializer(serializers.Serializer):
|
||||
"""Audio statistics"""
|
||||
total_count = serializers.IntegerField()
|
||||
total_duration = serializers.IntegerField(help_text="Total duration in seconds")
|
||||
total_size = serializers.IntegerField(help_text="Total size in bytes")
|
||||
total_plays = serializers.IntegerField()
|
||||
|
||||
|
||||
class ChannelStatsSerializer(serializers.Serializer):
|
||||
"""Channel statistics"""
|
||||
total_channels = serializers.IntegerField()
|
||||
subscribed_channels = serializers.IntegerField()
|
||||
|
||||
|
||||
class DownloadStatsSerializer(serializers.Serializer):
|
||||
"""Download statistics"""
|
||||
pending = serializers.IntegerField()
|
||||
completed = serializers.IntegerField()
|
||||
failed = serializers.IntegerField()
|
||||
10
backend/stats/urls.py
Normal file
10
backend/stats/urls.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
"""Stats URL patterns"""
|
||||
|
||||
from django.urls import path
|
||||
from stats.views import AudioStatsView, ChannelStatsView, DownloadStatsView
|
||||
|
||||
urlpatterns = [
|
||||
path('audio/', AudioStatsView.as_view(), name='audio-stats'),
|
||||
path('channel/', ChannelStatsView.as_view(), name='channel-stats'),
|
||||
path('download/', DownloadStatsView.as_view(), name='download-stats'),
|
||||
]
|
||||
61
backend/stats/views.py
Normal file
61
backend/stats/views.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
"""Stats API views"""
|
||||
|
||||
from django.db.models import Sum, Count
|
||||
from rest_framework.response import Response
|
||||
from audio.models import Audio
|
||||
from channel.models import Channel
|
||||
from download.models import DownloadQueue
|
||||
from stats.serializers import (
|
||||
AudioStatsSerializer,
|
||||
ChannelStatsSerializer,
|
||||
DownloadStatsSerializer,
|
||||
)
|
||||
from common.views import ApiBaseView
|
||||
|
||||
|
||||
class AudioStatsView(ApiBaseView):
|
||||
"""Audio statistics endpoint"""
|
||||
|
||||
def get(self, request):
|
||||
"""Get audio statistics"""
|
||||
stats = Audio.objects.aggregate(
|
||||
total_count=Count('id'),
|
||||
total_duration=Sum('duration'),
|
||||
total_size=Sum('file_size'),
|
||||
total_plays=Sum('play_count'),
|
||||
)
|
||||
|
||||
# Handle None values
|
||||
stats = {k: v or 0 for k, v in stats.items()}
|
||||
|
||||
serializer = AudioStatsSerializer(stats)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
class ChannelStatsView(ApiBaseView):
|
||||
"""Channel statistics endpoint"""
|
||||
|
||||
def get(self, request):
|
||||
"""Get channel statistics"""
|
||||
stats = {
|
||||
'total_channels': Channel.objects.count(),
|
||||
'subscribed_channels': Channel.objects.filter(subscribed=True).count(),
|
||||
}
|
||||
|
||||
serializer = ChannelStatsSerializer(stats)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
class DownloadStatsView(ApiBaseView):
|
||||
"""Download statistics endpoint"""
|
||||
|
||||
def get(self, request):
|
||||
"""Get download statistics"""
|
||||
stats = {
|
||||
'pending': DownloadQueue.objects.filter(status='pending').count(),
|
||||
'completed': DownloadQueue.objects.filter(status='completed').count(),
|
||||
'failed': DownloadQueue.objects.filter(status='failed').count(),
|
||||
}
|
||||
|
||||
serializer = DownloadStatsSerializer(stats)
|
||||
return Response(serializer.data)
|
||||
Loading…
Add table
Add a link
Reference in a new issue