from datetime import datetime, timedelta, time from django.core.cache import caches from django.conf import settings from django.db.models import Count, Q, Sum from django.shortcuts import render from django.utils import timezone from queues.models import PlaylistSong from songs.models import Song from marietje.models import User def recache_stats(): new_stats = compute_stats() caches['default'].delete('stats') caches['default'].set('stats', new_stats, 2 * 3600) return new_stats def recache_user_stats(): users = User.objects.exclude(Q(id=None) | Q(id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values('id') for user in users: new_stats = user_stats(user['id']) cacheloc = 'userstats_{}'.format(user['id']) caches['userstats'].delete(cacheloc) caches['userstats'].set(cacheloc, new_stats, 48 * 3600) return new_stats def time_convert(time): for tr in time: tr['duration'] = str(round(tr['total'] / 86400, 2)) + ' days' avg_dur_sec = tr['avg_dur']%60 avg_dur_min = int((tr['avg_dur']-avg_dur_sec)/60) tr['avg_dur'] = '{}:{}'.format(avg_dur_min, avg_dur_sec) return time def compute_stats(): # We want to grab the time now, because otherwise we would be reporting a minute too late last_updated = datetime.now() total_uploads = Song.objects.filter(deleted=False).exclude( user_id=None).count() upload_stats = Song.objects.filter(deleted=False).exclude( user_id=None).values( 'user__id', 'user__name').annotate(total=Count('id')).order_by( '-total', 'user__name')[:settings.STATS_TOP_COUNT] total_requests = PlaylistSong.objects.filter(state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).count() request_stats = PlaylistSong.objects.filter(state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( 'user__id', 'user__name').annotate(total=Count('id')).order_by( '-total', 'user__name')[:settings.STATS_TOP_COUNT] unique_request_stats = PlaylistSong.objects.filter(state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( 'user__id', 'user__name').annotate( total_requests=Count('id', distinct=True), unique_requests=Count('song__id', distinct=True)).order_by( '-unique_requests')[:settings.STATS_TOP_COUNT] total_unique_requests = PlaylistSong.objects.filter(state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).aggregate( total=Count('song__id', distinct=True)) most_played_songs = PlaylistSong.objects.filter(state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( 'song__artist', 'song__title').annotate(total=Count('id')).order_by( '-total', 'song__artist')[:settings.STATS_TOP_COUNT] most_played_songs_14_days = PlaylistSong.objects.filter( state=2, played_at__gte=timezone.now() - timedelta(days=14)).exclude(user_id=None).values( 'song__artist', 'song__title').annotate(total=Count('id')).order_by( '-total', 'song__artist')[:settings.STATS_TOP_COUNT] time_requested = PlaylistSong.objects.filter(state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( 'user__id', 'user__name').annotate(total=Sum('song__duration'), avg_dur=Sum('song__duration')/Count('id')).order_by( '-total')[:settings.STATS_TOP_COUNT] total_time_requested = PlaylistSong.objects.all().filter(state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).aggregate( total=Sum('song__duration')) most_requested_uploaders = PlaylistSong.objects.filter(state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( 'song__user__id', 'song__user__name').annotate(total=Count( 'song__user__id')).order_by('-total')[:settings.STATS_TOP_COUNT] return { 'last_updated': last_updated, 'total_uploads': total_uploads, 'upload_stats': list(upload_stats), 'total_requests': total_requests, 'request_stats': list(request_stats), 'unique_request_stats': list(unique_request_stats), 'total_unique_requests': total_unique_requests, 'most_played_songs': list(most_played_songs), 'most_played_songs_14_days': list(most_played_songs_14_days), 'time_requested': time_convert(list(time_requested)), 'total_time_requested': str(round(float(total_time_requested['total']) / 86400, 2)) + ' days', 'stats_top_count': settings.STATS_TOP_COUNT, 'most_requested_uploaders': list(most_requested_uploaders), } def user_stats(request): last_updated = datetime.now() total_uploads = Song.objects.filter( user__id=request, deleted=False).count() total_requests = PlaylistSong.objects.filter( user__id=request, state=2).count() unique_requests = PlaylistSong.objects.filter( user__id=request, state=2, song_id__isnull=False).values('song_id').distinct().count() most_played_songs = PlaylistSong.objects.filter( user__id=request, state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( 'song__artist', 'song__title').annotate(total=Count('id')).order_by( '-total', 'song__artist', 'song__title')[:settings.STATS_TOP_COUNT] most_played_uploaders = PlaylistSong.objects.filter( user__id=request, state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( 'song__user__id', 'song__user__name').annotate( total=Count('song__user__id')).order_by( '-total')[:settings.STATS_TOP_COUNT] most_played_uploads = PlaylistSong.objects.filter( state=2, song_id__in=Song.objects.filter(user__id=request)).exclude(user__id=None).values( 'song__artist', 'song__title').annotate(total=Count('id', filter=~Q(user__id=request)), user_total=Count('id', filter=Q(user__id=request))).order_by( '-total', 'song__artist', 'song__title')[:settings.STATS_TOP_COUNT] most_played = list(most_played_uploads) total_played_uploads = 0 total_played_user_uploads = 0 for x in most_played: total_played_uploads += x['total'] total_played_user_uploads += x['user_total'] return { 'last_updated': last_updated, 'total_uploads': total_uploads, 'total_requests': total_requests, 'unique_requests': unique_requests, 'most_played_songs': list(most_played_songs), 'most_played_uploaders': list(most_played_uploaders), 'most_played_uploads': list(most_played_uploads), 'stats_top_count': settings.STATS_TOP_COUNT, 'total_played_uploads': total_played_uploads, 'total_played_user_uploads': total_played_user_uploads, }