mirror of
https://gitlab.science.ru.nl/technicie/MarietjeDjango.git
synced 2025-12-09 22:32:21 +01:00
Compare commits
19 Commits
search
...
oslomp/qui
| Author | SHA1 | Date | |
|---|---|---|---|
| 371334326b | |||
| 40e2245d39 | |||
| c9ba37d291 | |||
| 6ec3d57a39 | |||
| 59993aa1c0 | |||
| a1116ca4cd | |||
| 95bd47c46a | |||
| af6031c3a5 | |||
| a3f501273f | |||
| 7af7127612 | |||
| 4c9a431f8a | |||
| 581e14f7ef | |||
| d0ed0a0a62 | |||
| ce3bfb02d5 | |||
| 065f29fe55 | |||
| 3bdac86bfb | |||
| a864e8f535 | |||
| 48dd3bd0df | |||
| 2fcd827b85 |
@ -39,4 +39,10 @@ deploy:
|
||||
"\$PYTHON" "\$MANAGE" migrate --noinput
|
||||
"\$PYTHON" "\$MANAGE" collectstatic --noinput
|
||||
systemctl start MarietjeDjango.service
|
||||
|
||||
# Regenerate caches
|
||||
(
|
||||
sudo -u www-data /srv/MarietjeDjango/django_env/bin/python /srv/MarietjeDjango/marietje/manage.py recache_stats
|
||||
sudo -u www-data /srv/MarietjeDjango/django_env/bin/python /srv/MarietjeDjango/marietje/manage.py recache_user_stats
|
||||
) &
|
||||
EOF
|
||||
|
||||
@ -20,6 +20,7 @@ from prometheus_client import Counter
|
||||
from marietje.utils import song_to_dict, playlist_song_to_dict, send_to_bertha
|
||||
from queues.models import PlaylistSong, QueueCommand
|
||||
from songs.models import Song
|
||||
from marietje.settings import MAX_MINUTES_IN_A_ROW
|
||||
|
||||
request_counter = Counter('marietje_requests', 'Queue requests on marietje', ['queue'])
|
||||
upload_counter = Counter('marietje_uploads', 'Songs uploaded to marietje')
|
||||
@ -168,7 +169,7 @@ def managesongs(request):
|
||||
@api_auth_required
|
||||
def queue(request):
|
||||
queue = request.user.queue
|
||||
infobar = {"start_personal_queue": 0, "length_personal_queue": 0, "length_total_queue": 0, "end_personal_queue": 0}
|
||||
infobar = {"start_personal_queue": 0, "length_personal_queue": 0, "length_total_queue": 0, "end_personal_queue": 0, 'max_length': MAX_MINUTES_IN_A_ROW}
|
||||
for song in queue.queue():
|
||||
infobar["length_total_queue"] += song.song.duration
|
||||
if song.user == request.user:
|
||||
@ -177,7 +178,6 @@ def queue(request):
|
||||
if infobar["start_personal_queue"] == 0:
|
||||
infobar["start_personal_queue"] = infobar["length_total_queue"] - song.song.duration
|
||||
|
||||
|
||||
json = {
|
||||
'current_song': playlist_song_to_dict(queue.current_song()),
|
||||
'queue': [playlist_song_to_dict(playlist_song, user=request.user) for playlist_song in queue.queue()],
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.contrib.auth.models import PermissionsMixin
|
||||
from django.contrib.auth.validators import ASCIIUsernameValidator, UnicodeUsernameValidator
|
||||
from django.contrib.auth.validators import UnicodeUsernameValidator
|
||||
from django.core.mail import send_mail
|
||||
from django.db import models
|
||||
from django.utils import six, timezone
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from marietje.utils import get_first_queue
|
||||
@ -46,7 +46,7 @@ class UserManager(BaseUserManager):
|
||||
|
||||
|
||||
class User(AbstractBaseUser, PermissionsMixin):
|
||||
username_validator = UnicodeUsernameValidator() if six.PY3 else ASCIIUsernameValidator()
|
||||
username_validator = UnicodeUsernameValidator()
|
||||
|
||||
username = models.CharField(
|
||||
_('username'),
|
||||
|
||||
@ -40,8 +40,8 @@ footer {
|
||||
border-bottom: 1px solid #DDDDDD;
|
||||
}
|
||||
|
||||
.requested_song .plays-at, .requested_song .requested-by {
|
||||
font-weight: bold;
|
||||
tr.requested_song{
|
||||
border-left: 1px solid #777777;
|
||||
}
|
||||
|
||||
.table-header-style td, .table-header-style{
|
||||
|
||||
@ -183,6 +183,11 @@ function updateTime() {
|
||||
}
|
||||
if (infobar['end_personal_queue'] !== 0){
|
||||
$('.start-queue').text("First song starts " + showExactOrRelative(infobar['start_personal_queue']));
|
||||
if (infobar['length_personal_queue'] > infobar['max_length'] * 60) {
|
||||
$('.duration-queue').addClass('text-danger');
|
||||
} else {
|
||||
$('.duration-queue').removeClass('text-danger');
|
||||
}
|
||||
$('.duration-queue').text( " (" + (infobar['length_personal_queue']).secondsToMMSS() + ")");
|
||||
$('.end-queue').text("Last song ends " + showExactOrRelative(infobar['end_personal_queue']));
|
||||
}
|
||||
|
||||
@ -36,9 +36,11 @@
|
||||
<ul class="nav navbar-nav navbar-right hidden-xs">
|
||||
<li>
|
||||
<div class="infobar">
|
||||
<p class="navbar-text start-queue"></p>
|
||||
<p class="navbar-text start-queue hidden-sm hidden-xs"></p>
|
||||
<p class="navbar-text end-queue"></p>
|
||||
<p class="navbar-text duration-queue"></p>
|
||||
<div class="navbar-text">
|
||||
<p class="duration-queue"></p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
@ -93,7 +95,9 @@
|
||||
<td class="col-md-4">Artist</td>
|
||||
<td class="col-md-4">Title</td>
|
||||
<td class="col-md-2 hidden-xs">Requested By</td>
|
||||
<td id="timeswitch" class="col-md-1 hidden-xs text-info" >Plays In</td>
|
||||
<td class="col-md-1 hidden-xs text-info" style="cursor: pointer;">
|
||||
<span id="timeswitch" class="btn-link" >Plays In</span>
|
||||
</td>
|
||||
<td class="col-md-1 control-icons">Control</td>
|
||||
</tr>
|
||||
<tr class="currentsong" style="font-weight: bold">
|
||||
|
||||
@ -72,7 +72,7 @@
|
||||
<h2>Time requested</h2>
|
||||
<p>In total <strong> {{ stats.total_time_requested }} </strong> of music have been requested, with an
|
||||
average song length of <strong>{{ stats.total_average }}</strong>.
|
||||
These are the {{ stats.stats_top_count }} people with the longest total time queued</p>
|
||||
These are the {{ stats.stats_top_count }} people with the longest total time queued.</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
@ -148,11 +148,34 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>Most played Artists</h2>
|
||||
<p>These are the {{ stats.stats_top_count }} most played artists ever.</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Artist</th>
|
||||
<th style="text-align: right;"># Requests</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for stat in stats.most_played_artists %}
|
||||
<tr>
|
||||
<th>{{ forloop.counter }}</th>
|
||||
<td>{{ stat.song__artist }}</td>
|
||||
<td style="text-align: right;">{{ stat.total }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>Most played uploaders</h2>
|
||||
<p>The left column shows the {{ stats.stats_top_count }} people whose songs are requested most often by other people
|
||||
people. The right column shows how many times that person has queued his own songs.</p>
|
||||
<p>These are the {{ stats.stats_top_count }} people whose songs are requested most often by other people, as shown in the left column. The right column shows how many times that person has queued his own songs.</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
|
||||
@ -48,7 +48,30 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h2>Most played Artists</h2>
|
||||
<h4>Top {{ stats.stats_top_count }}:</h4>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Artist</th>
|
||||
<th style="text-align: right;"># Requests</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for stat in stats.most_played_artists %}
|
||||
<tr>
|
||||
<th>{{ forloop.counter }}</th>
|
||||
<td>{{ stat.song__artist }}</td>
|
||||
<td style="text-align: right;">{{ stat.total }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>Uploads requested</h2>
|
||||
<p> You have uploaded a total of <strong> {{stats.total_uploads }} </strong> songs. The left column
|
||||
@ -82,6 +105,34 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>Upload artists requested</h2>
|
||||
<p> The left column shows how many times songs from artists uploaded by you have been requested by
|
||||
other people. The right column shows how many times you requested those songs.
|
||||
<h4>Top {{ stats.stats_top_count }}:</h4>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Artist</th>
|
||||
<th style="text-align: right;">Others</th>
|
||||
<th>You</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for stat in stats.most_played_uploaded_artists %}
|
||||
<tr>
|
||||
<th>{{ forloop.counter }}</th>
|
||||
<td>{{ stat.song__artist }}</td>
|
||||
<td style="text-align: right;">{{ stat.total }}</td>
|
||||
<td>{{ stat.user_total }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>Most played uploaders</h2>
|
||||
<p> The people whose songs you have queued the most are:</p>
|
||||
@ -107,6 +158,30 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>Biggest fans</h2>
|
||||
<p> The people that queued your songs the most are:</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>User</th>
|
||||
<th style="text-align: right;"># Requests</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for stat in stats.biggest_fans %}
|
||||
<tr>
|
||||
<th>{{ forloop.counter }}</th>
|
||||
<td>{{ stat.user__name }}</td>
|
||||
<td style="text-align: right;">{{ stat.total }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@ -10,10 +10,12 @@ 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, 2 * 3600)
|
||||
caches['default'].set('stats', new_stats, CACHE_TTL)
|
||||
return new_stats
|
||||
|
||||
|
||||
@ -25,7 +27,7 @@ def recache_user_stats():
|
||||
new_stats = user_stats(user['id'])
|
||||
cacheloc = 'userstats_{}'.format(user['id'])
|
||||
caches['userstats'].delete(cacheloc)
|
||||
caches['userstats'].set(cacheloc, new_stats, 48 * 3600)
|
||||
caches['userstats'].set(cacheloc, new_stats, CACHE_TTL)
|
||||
return new_stats
|
||||
|
||||
|
||||
@ -104,6 +106,12 @@ def compute_stats():
|
||||
'song__title').annotate(total=Count('id')).order_by(
|
||||
'-total', 'song__artist')[:settings.STATS_TOP_COUNT]
|
||||
|
||||
stats['most_played_artists'] = PlaylistSong.objects.filter(state=2).exclude(
|
||||
Q(user_id=None)
|
||||
| Q(user_id__in=settings.STATS_REQUEST_IGNORE_USER_IDS)).values(
|
||||
'song__artist').annotate(total=Count('song__artist')).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(
|
||||
@ -163,6 +171,7 @@ def compute_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_artists': list(stats['most_played_artists']),
|
||||
'most_played_songs_14_days': list(stats['most_played_songs_14_days']),
|
||||
'time_requested': stats['time_requested'],
|
||||
'total_time_requested': str(round(float(
|
||||
@ -195,6 +204,12 @@ def user_stats(request):
|
||||
'-total', 'song__artist',
|
||||
'song__title')[:settings.STATS_TOP_COUNT]
|
||||
|
||||
most_played_artists = PlaylistSong.objects.filter(
|
||||
user__id=request, state=2,
|
||||
song_id__isnull=False).values('song__artist').annotate(
|
||||
total=Count('song__artist')).order_by(
|
||||
'-total', 'song__artist')[:settings.STATS_TOP_COUNT]
|
||||
|
||||
most_played_uploaders = PlaylistSong.objects.filter(
|
||||
user__id=request, state=2).exclude(
|
||||
Q(user_id=None)
|
||||
@ -203,31 +218,50 @@ def user_stats(request):
|
||||
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')
|
||||
'-total', 'song__artist', 'song__title')
|
||||
|
||||
most_played_uploaded_artists = PlaylistSong.objects.filter(
|
||||
state=2, song_id__in=Song.objects.filter(user__id=request)).exclude(
|
||||
user__id=None).values('song__artist').annotate(total=Count(
|
||||
'song__artist', filter=~Q(user__id=request)), user_total=Count(
|
||||
'id', filter=Q(user__id=request))).order_by(
|
||||
'-total', 'song__artist')
|
||||
|
||||
most_played = list(most_played_uploads)
|
||||
total_played_uploads = 0
|
||||
total_played_user_uploads = 0
|
||||
total_played = {}
|
||||
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']
|
||||
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]
|
||||
most_played_uploaded_artists = sorted(list(most_played_uploaded_artists), 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_artists': list(most_played_artists),
|
||||
'most_played_uploaders': list(most_played_uploaders),
|
||||
'most_played_uploads': most_played_uploads_list,
|
||||
'most_played_uploaded_artists': most_played_uploaded_artists,
|
||||
'stats_top_count': settings.STATS_TOP_COUNT,
|
||||
'total_played_uploads': total_played_uploads,
|
||||
'total_played_user_uploads': total_played_user_uploads,
|
||||
'total_played_uploads': total_played['uploads'],
|
||||
'total_played_user_uploads': total_played['user_uploads'],
|
||||
'biggest_fans': list(biggest_fans),
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
setuptools
|
||||
django==2.1
|
||||
django>=2.2,<2.3
|
||||
mysqlclient
|
||||
https://projects.unbit.it/downloads/uwsgi-lts.tar.gz
|
||||
mutagen
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
django
|
||||
django>=2.2,<2.3
|
||||
mutagen
|
||||
argon2-cffi
|
||||
prometheus_client
|
||||
|
||||
Reference in New Issue
Block a user