[templates] Adding some aggregation widgets
This commit is contained in:
@ -1,5 +1,8 @@
|
|||||||
|
import datetime
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.utils import timezone
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
from scrobbles.models import Scrobble
|
||||||
from videos.models import Channel, Series, Video
|
from videos.models import Channel, Series, Video
|
||||||
from scrobbles.views import ScrobbleableListView, ScrobbleableDetailView
|
from scrobbles.views import ScrobbleableListView, ScrobbleableDetailView
|
||||||
|
|
||||||
@ -50,6 +53,74 @@ class ChannelDetailView(LoginRequiredMixin, generic.DetailView):
|
|||||||
class VideoListView(ScrobbleableListView):
|
class VideoListView(ScrobbleableListView):
|
||||||
model = Video
|
model = Video
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context_data = super().get_context_data(**kwargs)
|
||||||
|
user = self.request.user
|
||||||
|
now = timezone.now()
|
||||||
|
start_day_of_week = now - datetime.timedelta(days=now.weekday())
|
||||||
|
start_day_of_month = now.replace(day=1)
|
||||||
|
|
||||||
|
movie_scrobbles = Scrobble.objects.filter(
|
||||||
|
user=user,
|
||||||
|
video__video_type=Video.VideoType.MOVIE,
|
||||||
|
played_to_completion=True,
|
||||||
|
)
|
||||||
|
context_data["videos_this_week"] = movie_scrobbles.filter(
|
||||||
|
timestamp__gte=start_day_of_week
|
||||||
|
).order_by("-timestamp")
|
||||||
|
context_data["videos_this_month"] = movie_scrobbles.filter(
|
||||||
|
timestamp__gte=start_day_of_month
|
||||||
|
).order_by("-timestamp")
|
||||||
|
|
||||||
|
youtube_scrobbles_this_week = Scrobble.objects.filter(
|
||||||
|
user=user,
|
||||||
|
video__video_type=Video.VideoType.YOUTUBE,
|
||||||
|
video__channel__isnull=False,
|
||||||
|
timestamp__gte=start_day_of_week,
|
||||||
|
).select_related("video", "video__channel")
|
||||||
|
|
||||||
|
youtube_scrobbles_this_month = Scrobble.objects.filter(
|
||||||
|
user=user,
|
||||||
|
video__video_type=Video.VideoType.YOUTUBE,
|
||||||
|
video__channel__isnull=False,
|
||||||
|
timestamp__gte=start_day_of_month,
|
||||||
|
).select_related("video", "video__channel")
|
||||||
|
|
||||||
|
channels_this_week = {}
|
||||||
|
for scrobble in youtube_scrobbles_this_week:
|
||||||
|
channel = scrobble.video.channel
|
||||||
|
if channel:
|
||||||
|
channels_this_week[channel.id] = {
|
||||||
|
"channel": channel,
|
||||||
|
"count": channels_this_week.get(channel.id, {}).get(
|
||||||
|
"count", 0
|
||||||
|
)
|
||||||
|
+ 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
channels_this_month = {}
|
||||||
|
for scrobble in youtube_scrobbles_this_month:
|
||||||
|
channel = scrobble.video.channel
|
||||||
|
if channel:
|
||||||
|
channels_this_month[channel.id] = {
|
||||||
|
"channel": channel,
|
||||||
|
"count": channels_this_month.get(channel.id, {}).get(
|
||||||
|
"count", 0
|
||||||
|
)
|
||||||
|
+ 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
context_data["channels_this_week"] = sorted(
|
||||||
|
channels_this_week.values(), key=lambda x: x["count"], reverse=True
|
||||||
|
)
|
||||||
|
context_data["channels_this_month"] = sorted(
|
||||||
|
channels_this_month.values(),
|
||||||
|
key=lambda x: x["count"],
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
return context_data
|
||||||
|
|
||||||
|
|
||||||
class VideoDetailView(ScrobbleableDetailView):
|
class VideoDetailView(ScrobbleableDetailView):
|
||||||
model = Video
|
model = Video
|
||||||
|
|||||||
@ -1,17 +1,72 @@
|
|||||||
|
import datetime
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils import timezone
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from webpages.forms import WebPageReadForm
|
from webpages.forms import WebPageReadForm
|
||||||
from webpages.models import WebPage
|
from webpages.models import WebPage
|
||||||
|
|
||||||
|
from scrobbles.models import Scrobble
|
||||||
from scrobbles.views import ScrobbleableListView, ScrobbleableDetailView
|
from scrobbles.views import ScrobbleableListView, ScrobbleableDetailView
|
||||||
|
|
||||||
|
|
||||||
class WebPageListView(ScrobbleableListView):
|
class WebPageListView(ScrobbleableListView):
|
||||||
model = WebPage
|
model = WebPage
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context_data = super().get_context_data(**kwargs)
|
||||||
|
user = self.request.user
|
||||||
|
now = timezone.now()
|
||||||
|
start_day_of_week = now - datetime.timedelta(days=now.weekday())
|
||||||
|
start_day_of_month = now.replace(day=1)
|
||||||
|
|
||||||
|
scrobbles_this_week = Scrobble.objects.filter(
|
||||||
|
user=user,
|
||||||
|
web_page__isnull=False,
|
||||||
|
timestamp__gte=start_day_of_week,
|
||||||
|
).select_related("web_page", "web_page__domain")
|
||||||
|
|
||||||
|
scrobbles_this_month = Scrobble.objects.filter(
|
||||||
|
user=user,
|
||||||
|
web_page__isnull=False,
|
||||||
|
timestamp__gte=start_day_of_month,
|
||||||
|
).select_related("web_page", "web_page__domain")
|
||||||
|
|
||||||
|
domains_this_week = {}
|
||||||
|
for scrobble in scrobbles_this_week:
|
||||||
|
domain = scrobble.web_page.domain
|
||||||
|
if domain:
|
||||||
|
domains_this_week[domain.id] = {
|
||||||
|
"domain": domain,
|
||||||
|
"count": domains_this_week.get(domain.id, {}).get(
|
||||||
|
"count", 0
|
||||||
|
)
|
||||||
|
+ 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
domains_this_month = {}
|
||||||
|
for scrobble in scrobbles_this_month:
|
||||||
|
domain = scrobble.web_page.domain
|
||||||
|
if domain:
|
||||||
|
domains_this_month[domain.id] = {
|
||||||
|
"domain": domain,
|
||||||
|
"count": domains_this_month.get(domain.id, {}).get(
|
||||||
|
"count", 0
|
||||||
|
)
|
||||||
|
+ 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
context_data["domains_this_week"] = sorted(
|
||||||
|
domains_this_week.values(), key=lambda x: x["count"], reverse=True
|
||||||
|
)
|
||||||
|
context_data["domains_this_month"] = sorted(
|
||||||
|
domains_this_month.values(), key=lambda x: x["count"], reverse=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return context_data
|
||||||
|
|
||||||
|
|
||||||
class WebPageDetailView(ScrobbleableDetailView):
|
class WebPageDetailView(ScrobbleableDetailView):
|
||||||
model = WebPage
|
model = WebPage
|
||||||
|
|||||||
@ -5,9 +5,21 @@
|
|||||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
<h1 class="h2">{% block title %}{% endblock %} </h1>
|
<h1 class="h2">{% block title %}{% endblock %} </h1>
|
||||||
<div class="btn-toolbar mb-2 mb-md-0">
|
<div class="btn-toolbar mb-2 mb-md-0">
|
||||||
|
{% if user.is_authenticated %}
|
||||||
<div class="btn-group me-2">
|
<div class="btn-group me-2">
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary">Export</button>
|
<form action="/admin/" method="get">
|
||||||
|
<button type="submit" class="btn btn-sm btn-outline-secondary">
|
||||||
|
<span data-feather="key"></span>
|
||||||
|
Admin
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="btn-group me-2">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal"
|
||||||
|
data-bs-target="#exportModal">Export</button>
|
||||||
|
{% block charts_button %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -16,3 +28,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_modals %}
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
@ -7,14 +7,24 @@
|
|||||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
<h1 class="h2">{% block title %}{% endblock %} </h1>
|
<h1 class="h2">{% block title %}{% endblock %} </h1>
|
||||||
<div class="btn-toolbar mb-2 mb-md-0">
|
<div class="btn-toolbar mb-2 mb-md-0">
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<div class="btn-group me-2">
|
||||||
|
<form action="/admin/" method="get">
|
||||||
|
<button type="submit" class="btn btn-sm btn-outline-secondary">
|
||||||
|
<span data-feather="key"></span>
|
||||||
|
Admin
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="btn-group me-2">
|
<div class="btn-group me-2">
|
||||||
{% if view == 'grid' %}
|
{% if view == 'grid' %}
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary"><a href="?{% urlreplace view='list' %}">List View</a>
|
<button type="button" class="btn btn-sm btn-outline-secondary"><a href="?{% urlreplace view='list' %}">List View</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary"><a href="?{% urlreplace view='grid' %}">Grid View</a>
|
<button type="button" class="btn btn-sm btn-outline-secondary"><a href="?{% urlreplace view='grid' %}">Grid View</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary">Export</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
{% block charts_button %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -642,47 +642,3 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if videos_this_week or videos_this_month %}
|
|
||||||
<div class="col-md">
|
|
||||||
<h2>Movies Watched</h2>
|
|
||||||
|
|
||||||
{% if videos_this_week %}
|
|
||||||
<h3>This Week</h3>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-striped table-sm">
|
|
||||||
<tbody>
|
|
||||||
{% for scrobble in videos_this_week %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{{scrobble.video.get_absolute_url}}">{{scrobble.video}}</a></td>
|
|
||||||
<td>{{scrobble.timestamp|date:"N d"}}</td>
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr><td>No movies watched this week</td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if videos_this_month %}
|
|
||||||
<h3>This Month</h3>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-striped table-sm">
|
|
||||||
<tbody>
|
|
||||||
{% for scrobble in videos_this_month %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{{scrobble.video.get_absolute_url}}">{{scrobble.video}}</a></td>
|
|
||||||
<td>{{scrobble.timestamp|date:"N d"}}</td>
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr><td>No movies watched this month</td></tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|||||||
@ -95,7 +95,9 @@
|
|||||||
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal"
|
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal"
|
||||||
data-bs-target="#exportModal">Export</button>
|
data-bs-target="#exportModal">Export</button>
|
||||||
</div>
|
</div>
|
||||||
|
{% block charts_button %}
|
||||||
<a href="{% url 'scrobbles:charts-home' %}" class="btn btn-sm btn-outline-secondary">Charts</a>
|
<a href="{% url 'scrobbles:charts-home' %}" class="btn btn-sm btn-outline-secondary">Charts</a>
|
||||||
|
{% endblock %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle" id="graphDateButton"
|
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle" id="graphDateButton"
|
||||||
|
|||||||
@ -24,6 +24,94 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block lists %}
|
{% block lists %}
|
||||||
|
{% if videos_this_week or videos_this_month or channels_this_week or channels_this_month %}
|
||||||
|
<div class="row">
|
||||||
|
{% if videos_this_week or videos_this_month %}
|
||||||
|
<div class="col-md">
|
||||||
|
<h2>Movies Watched</h2>
|
||||||
|
|
||||||
|
{% if videos_this_week %}
|
||||||
|
<h3>This Week</h3>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-sm">
|
||||||
|
<tbody>
|
||||||
|
{% for scrobble in videos_this_week %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{{scrobble.video.get_absolute_url}}">{{scrobble.video}}</a></td>
|
||||||
|
<td>{{scrobble.timestamp|date:"N d"}}</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td>No movies watched this week</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if videos_this_month %}
|
||||||
|
<h3>This Month</h3>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-sm">
|
||||||
|
<tbody>
|
||||||
|
{% for scrobble in videos_this_month %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{{scrobble.video.get_absolute_url}}">{{scrobble.video}}</a></td>
|
||||||
|
<td>{{scrobble.timestamp|date:"N d"}}</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td>No movies watched this month</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if channels_this_week or channels_this_month %}
|
||||||
|
<div class="col-md">
|
||||||
|
<h2>YouTube Channels</h2>
|
||||||
|
|
||||||
|
{% if channels_this_week %}
|
||||||
|
<h3>This Week</h3>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-sm">
|
||||||
|
<tbody>
|
||||||
|
{% for item in channels_this_week %}
|
||||||
|
<tr>
|
||||||
|
<td>{{item.channel}}</td>
|
||||||
|
<td>{{item.count}} videos</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td>No YouTube videos watched this week</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if channels_this_month %}
|
||||||
|
<h3>This Month</h3>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-sm">
|
||||||
|
<tbody>
|
||||||
|
{% for item in channels_this_month %}
|
||||||
|
<tr>
|
||||||
|
<td>{{item.channel}}</td>
|
||||||
|
<td>{{item.count}} videos</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td>No YouTube videos watched this month</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md">
|
<div class="col-md">
|
||||||
<div class="table-responsive">{% include "_scrobblable_list.html" %}</div>
|
<div class="table-responsive">{% include "_scrobblable_list.html" %}</div>
|
||||||
|
|||||||
@ -4,6 +4,51 @@
|
|||||||
{% block title %}Webpages{% endblock %}
|
{% block title %}Webpages{% endblock %}
|
||||||
|
|
||||||
{% block lists %}
|
{% block lists %}
|
||||||
|
{% if domains_this_week or domains_this_month %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md">
|
||||||
|
<h2>Domains Read</h2>
|
||||||
|
|
||||||
|
{% if domains_this_week %}
|
||||||
|
<h3>This Week</h3>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-sm">
|
||||||
|
<tbody>
|
||||||
|
{% for item in domains_this_week %}
|
||||||
|
<tr>
|
||||||
|
<td>{{item.domain}}</td>
|
||||||
|
<td>{{item.count}} pages</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td>No pages read this week</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if domains_this_month %}
|
||||||
|
<h3>This Month</h3>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-sm">
|
||||||
|
<tbody>
|
||||||
|
{% for item in domains_this_month %}
|
||||||
|
<tr>
|
||||||
|
<td>{{item.domain}}</td>
|
||||||
|
<td>{{item.count}} pages</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr><td>No pages read this month</td></tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<p class="pagination">
|
<p class="pagination">
|
||||||
<span class="page-links">
|
<span class="page-links">
|
||||||
|
|||||||
Reference in New Issue
Block a user