[templates] Add calendar view
This commit is contained in:
@ -5,6 +5,7 @@ from tasks.webhooks import EmacsWebhookView, TodoistWebhookView
|
||||
app_name = "scrobbles"
|
||||
|
||||
urlpatterns = [
|
||||
path("calendar/", views.ScrobbleCalendarView.as_view(), name="calendar"),
|
||||
path("search/", views.ScrobbleSearchView.as_view(), name="search"),
|
||||
path("status/", views.ScrobbleStatusView.as_view(), name="status"),
|
||||
path(
|
||||
|
||||
@ -2,6 +2,7 @@ import calendar
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from uuid import uuid4
|
||||
|
||||
import pendulum
|
||||
import pytz
|
||||
@ -1281,6 +1282,129 @@ class EmbeddableTopArtistsWidget(TemplateView):
|
||||
return context
|
||||
|
||||
|
||||
class ScrobbleCalendarView(LoginRequiredMixin, TemplateView):
|
||||
template_name = "scrobbles/calendar.html"
|
||||
|
||||
CALENDAR_MEDIA_TYPES = [
|
||||
"Task",
|
||||
"BirdingLocation",
|
||||
"Food",
|
||||
"Trail",
|
||||
"VideoGame",
|
||||
"Book",
|
||||
"Mood",
|
||||
]
|
||||
|
||||
MEDIA_EMOJI = {
|
||||
"Task": "✅",
|
||||
"BirdingLocation": "🐦",
|
||||
"Food": "🍽️",
|
||||
"Trail": "🥾",
|
||||
"VideoGame": "🎮",
|
||||
"Book": "📚",
|
||||
"Mood": "🥰",
|
||||
}
|
||||
|
||||
MONTH_COLORS = [
|
||||
"#db7a7a", # Jan
|
||||
"#db847a", # Feb
|
||||
"#b0db7a", # Mar
|
||||
"#7adb82", # Apr
|
||||
"#7adbb3", # May
|
||||
"#7ab6db", # Jun
|
||||
"#7a8edb", # Jul
|
||||
"#977adb", # Aug
|
||||
"#c47adb", # Sep
|
||||
"#db7ac5", # Oct
|
||||
"#db7a90", # Nov
|
||||
"#db7a7a", # Dec
|
||||
]
|
||||
|
||||
def _day_color(self, month_index, day_num, total_days):
|
||||
import colorsys
|
||||
hue = (month_index - 1) * 30 / 360
|
||||
lightness = 0.80 + (day_num / total_days) * 0.15
|
||||
r, g, b = colorsys.hls_to_rgb(hue, lightness, 0.5)
|
||||
return f"#{int(r*255):02x}{int(g*255):02x}{int(b*255):02x}"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
|
||||
today = timezone.localdate()
|
||||
date_param = self.request.GET.get("date", today.isoformat()[:7])
|
||||
try:
|
||||
year, month = [int(x) for x in date_param.split("-")]
|
||||
except (ValueError, IndexError):
|
||||
year, month = today.year, today.month
|
||||
|
||||
_, total_days = calendar.monthrange(year, month)
|
||||
month_start = datetime(year, month, 1).date()
|
||||
month_end = datetime(year, month, total_days).date()
|
||||
first_weekday = month_start.weekday()
|
||||
|
||||
prev_month = month_start - timedelta(days=1)
|
||||
next_month = month_end + timedelta(days=1)
|
||||
|
||||
scrobbles = (
|
||||
Scrobble.objects.filter(
|
||||
user=self.request.user,
|
||||
timestamp__date__gte=month_start,
|
||||
timestamp__date__lte=month_end,
|
||||
media_type__in=self.CALENDAR_MEDIA_TYPES,
|
||||
)
|
||||
.select_related("task", "birding_location", "food", "trail", "video_game", "book", "mood")
|
||||
.order_by("timestamp")
|
||||
)
|
||||
|
||||
day_map = {d: [] for d in range(1, total_days + 1)}
|
||||
for scrobble in scrobbles:
|
||||
day_map[scrobble.timestamp.day].append(scrobble)
|
||||
|
||||
missing_uuids = [s for s in scrobbles if not s.uuid]
|
||||
if missing_uuids:
|
||||
for scrobble in missing_uuids:
|
||||
scrobble.uuid = uuid4()
|
||||
Scrobble.objects.bulk_update(missing_uuids, ["uuid"])
|
||||
|
||||
calendar_days = []
|
||||
month_color = self.MONTH_COLORS[(month - 1) % 12]
|
||||
for day_num in range(1, total_days + 1):
|
||||
day_scrobbles = []
|
||||
for scrobble in day_map[day_num]:
|
||||
day_scrobbles.append(
|
||||
{
|
||||
"uuid": scrobble.uuid,
|
||||
"emoji": self.MEDIA_EMOJI.get(scrobble.media_type, "📌"),
|
||||
"title": str(scrobble.media_obj) if scrobble.media_obj else scrobble.media_type,
|
||||
"media_type": scrobble.media_type,
|
||||
}
|
||||
)
|
||||
calendar_days.append({
|
||||
"day": day_num,
|
||||
"scrobbles": day_scrobbles,
|
||||
"is_today": year == today.year and month == today.month and day_num == today.day,
|
||||
"color": self._day_color(month, day_num, total_days),
|
||||
})
|
||||
|
||||
ctx.update(
|
||||
{
|
||||
"year": year,
|
||||
"month": month,
|
||||
"month_name": month_start.strftime("%B"),
|
||||
"total_days": total_days,
|
||||
"first_weekday": first_weekday,
|
||||
"calendar_days": calendar_days,
|
||||
"prev_month": prev_month.isoformat()[:7],
|
||||
"next_month": next_month.isoformat()[:7],
|
||||
"today": today,
|
||||
"current_month": today.isoformat()[:7],
|
||||
"day_names": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
||||
"month_color": month_color,
|
||||
}
|
||||
)
|
||||
return ctx
|
||||
|
||||
|
||||
class ScrobbleSearchView(LoginRequiredMixin, TemplateView):
|
||||
template_name = "scrobbles/scrobble_search.html"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user