from datetime import datetime, timedelta from django.core.cache import caches from django.conf import settings from django.db.models import Count, Q, Sum from django.utils import timezone from queues.models import PlaylistSong from songs.models import Song from marietje.models import User CACHE_TTL = 2 * 24 * 3600 def recache_stats(): new_stats = compute_stats() caches['default'].delete('stats') caches['default'].set('stats', new_stats, CACHE_TTL) 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, CACHE_TTL) return new_stats def best_uploaders_list(requests_uploader, most_requested_uploaders): for requests in requests_uploader: a = len(most_requested_uploaders) b = 0 while b <= a: if b == a: adding_list_item(most_requested_uploaders, requests) elif requests[ 'song__user__id'] == most_requested_uploaders[b]['id']: if requests['song__user__name'] == requests['user__name']: most_requested_uploaders[b][ 'own_total'] = requests['total'] else: most_requested_uploaders[b]['total'] += requests['total'] break b += 1 def adding_list_item(most_requested_list, requests): # adds a single item to the best_uploaders list most_requested_list.append({ 'id': requests['song__user__id'], 'name': requests['song__user__name'], 'total': 0, 'own_total': 0 }) if requests['song__user__id'] == requests['user__id']: most_requested_list[-1]['own_total'] = requests['total'] else: most_requested_list[-1]['total'] = requests['total'] def compute_stats(): # We want to grab the time now, because otherwise we would be reporting a minute too late last_updated = datetime.now() stats = {} stats['total_uploads'] = Song.objects.filter(deleted=False).exclude( user_id=None).count() stats['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] stats['total_requests'] = PlaylistSong.objects.filter(state=2).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).count() stats['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] stats['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] stats['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)) stats['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] stats['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] stats['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] stats['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')) total_time_overall = sum(x['avg_dur'] for x in list(stats['time_requested'])) total_average = total_time_overall / len(stats['time_requested']) avg_dur_min, avg_dur_sec = divmod(total_average, 60) total_average = '{:.0f} minutes and {:.0f} seconds'.format( avg_dur_min, avg_dur_sec) requests_uploader = 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', 'user__name', 'user__id').annotate(total=Count('song__user__name')) most_requested_uploaders = [] best_uploaders_list(list(requests_uploader), most_requested_uploaders) most_requested_uploaders = sorted(most_requested_uploaders, key=lambda x: x['total'], reverse=True)[:settings.STATS_TOP_COUNT] for time in list(stats['time_requested']): # converts total time and average time in respectively days and minutes, seconds time['duration'] = str(round(time['total'] / 86400, 2)) + ' days' avg_dur_min, avg_dur_sec = divmod(time['avg_dur'], 60) if avg_dur_sec < 10: avg_dur_sec = '0' + str(avg_dur_sec) time['avg_dur'] = '{}:{}'.format(avg_dur_min, avg_dur_sec) # Convert requested time to days time_requested = list(stats['time_requested']) for tr in time_requested: tr['duration'] = "{:5.2f} days".format(tr['total'] / 86400) return { 'last_updated': last_updated, 'total_uploads': "{0:,.0f}".format(stats['total_uploads']), 'total_uploads_perc': stats['total_uploads'], 'upload_stats': list(stats['upload_stats']), 'total_requests': "{0:,.0f}".format(stats['total_requests']), 'total_requests_perc': stats['total_requests'], 'request_stats': list(stats['request_stats']), 'unique_request_stats': list(stats['unique_request_stats']), 'total_unique_requests': "{0:,.0f}".format(stats['total_unique_requests']['total']), 'most_played_songs': list(stats['most_played_songs']), 'most_played_songs_14_days': list(stats['most_played_songs_14_days']), 'time_requested': stats['time_requested'], 'total_time_requested': str(round(float( stats['total_time_requested']['total']) / 86400, 2)) + ' days', 'stats_top_count': settings.STATS_TOP_COUNT, 'most_requested_uploaders': list(most_requested_uploaders), 'total_average': total_average, } 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] biggest_fans = PlaylistSong.objects.filter( state=2, song_id__in=Song.objects.filter(user__id=request)).exclude( Q(user_id=None) | Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values( 'user__id', 'user__name').annotate( total=Count('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') 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'] most_played_uploads_list = sorted(most_played_uploads, key=lambda x: (x['song__artist'], x['song__title'])) most_played_uploads_list = sorted(most_played_uploads_list, key=lambda x: x["total"], reverse=True)[:settings.STATS_TOP_COUNT] 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': most_played_uploads_list, 'stats_top_count': settings.STATS_TOP_COUNT, 'total_played_uploads': total_played_uploads, 'total_played_user_uploads': total_played_user_uploads, 'biggest_fans': list(biggest_fans), }