From 523ed3a4997a9f0e7445da934bdddca789ecbd23 Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Fri, 3 Apr 2026 11:59:39 -0400 Subject: [PATCH] [scrobbles] Add overlap map --- vrobbler/apps/scrobbles/views.py | 57 ++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.py index c75c830..e19d097 100644 --- a/vrobbler/apps/scrobbles/views.py +++ b/vrobbler/apps/scrobbles/views.py @@ -331,10 +331,67 @@ class ScrobbleListView(LoginRequiredMixin, ListView): self.tag_list = tag_list return qs + def _compute_overlap_groups(self, scrobbles): + parent = {} + + def find(x): + while parent[x] != x: + parent[x] = parent[parent[x]] + x = parent[x] + return x + + def union(x, y): + rx, ry = find(x), find(y) + if rx != ry: + parent[rx] = ry + + for s in scrobbles: + parent[s.pk] = s.pk + + def range_for(s): + start = s.timestamp + end = s.stop_timestamp + if end is None: + end = start + datetime.timedelta(hours=12) + return start, end + + for i, a in enumerate(scrobbles): + a_start, a_end = range_for(a) + for b in scrobbles[i + 1 :]: + b_start, b_end = range_for(b) + if a_start <= b_end and b_start <= a_end: + union(a.pk, b.pk) + + groups = {} + for s in scrobbles: + root = find(s.pk) + groups.setdefault(root, []).append(s.pk) + + overlap_map = {} + color_idx = 0 + COLORS = [ + "border-start border-3 border-info", + "border-start border-3 border-success", + "border-start border-3 border-warning", + "border-start border-3 border-primary", + "border-start border-3 border-danger", + "border-start border-3 border-secondary", + ] + for root, members in groups.items(): + if len(members) >= 2: + color = COLORS[color_idx % len(COLORS)] + for pk in members: + overlap_map[pk] = color + color_idx += 1 + + return overlap_map + def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) ctx["tags_param"] = self.request.GET.get("tags", "") ctx["tag_list"] = getattr(self, "tag_list", []) + scrobbles = list(ctx.get("object_list", [])) + ctx["overlap_map"] = self._compute_overlap_groups(scrobbles) return ctx