sessions / 948fbc19bfd70ec1dabf181a57e4c9e233e554d6

/home/powellc/src/code.unbl.ink/secstate/vrobbler

This commit has no recorded session.

diff

ignore whitespace

commit 948fbc19bfd70ec1dabf181a57e4c9e233e554d6Author: Colin Powell <colin@unbl.ink>Date:   Sun Jun 21 23:00:09 2026 -0400    [templates] Add HTMX support to Now Playingdiff --git a/PROJECT.org b/PROJECT.orgindex ad34b6a..784ef7d 100644--- a/PROJECT.org+++ b/PROJECT.org@@ -88,7 +88,7 @@ fetching and simple saving. *** Metadata sources **** Scraper -* Backlog [3/26] :vrobbler:project:personal:+* Backlog [4/26] :vrobbler:project:personal: ** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :bug:music:scrobbles: :PROPERTIES: :ID:       702462cf-d54b-48c6-8a7c-78b8de751deb@@ -604,7 +604,7 @@ independent of the email flow it was originally creatdd for  ** TODO [#B] Is there way to create unique slugs for media instances :media_types: -** STRT [#B] Use HTMx to update the Now Playing widget :feature:templates:+** DONE [#B] Use HTMx to update the Now Playing widget :feature:templates: :PROPERTIES: :ID:       5f5631fc-9ee1-d5a5-d0f8-94fea6fbbfa4 :END:diff --git a/vrobbler/apps/profiles/forms.py b/vrobbler/apps/profiles/forms.pyindex 8dc2833..35e10d1 100644--- a/vrobbler/apps/profiles/forms.py+++ b/vrobbler/apps/profiles/forms.py@@ -40,6 +40,7 @@ class UserProfileForm(forms.ModelForm):             "enable_public_widgets",             "widget_custom_css",             "home_scrobble_limit",+            "live_now_playing",             "weigh_in_units",         ]         widgets = {diff --git a/vrobbler/apps/profiles/migrations/0039_userprofile_live_now_playing.py b/vrobbler/apps/profiles/migrations/0039_userprofile_live_now_playing.pynew file mode 100644index 0000000..8c80ad2--- /dev/null+++ b/vrobbler/apps/profiles/migrations/0039_userprofile_live_now_playing.py@@ -0,0 +1,18 @@+# Generated by Django 4.2.29 on 2026-06-22 02:44++from django.db import migrations, models+++class Migration(migrations.Migration):++    dependencies = [+        ("profiles", "0038_userprofile_media_type_visibility"),+    ]++    operations = [+        migrations.AddField(+            model_name="userprofile",+            name="live_now_playing",+            field=models.BooleanField(default=False),+        ),+    ]diff --git a/vrobbler/apps/profiles/models.py b/vrobbler/apps/profiles/models.pyindex cdfa413..4dc467b 100644--- a/vrobbler/apps/profiles/models.py+++ b/vrobbler/apps/profiles/models.py@@ -98,6 +98,8 @@ class UserProfile(TimeStampedModel):      home_scrobble_limit = models.IntegerField(default=20) +    live_now_playing = models.BooleanField(default=False)+     weigh_in_units = models.CharField(         max_length=16,         choices=WeighUnit.choices,diff --git a/vrobbler/apps/scrobbles/urls.py b/vrobbler/apps/scrobbles/urls.pyindex 6679726..41b92b9 100644--- a/vrobbler/apps/scrobbles/urls.py+++ b/vrobbler/apps/scrobbles/urls.py@@ -5,6 +5,7 @@ from tasks.webhooks import EmacsWebhookView, TodoistWebhookView app_name = "scrobbles"  urlpatterns = [+    path("now-playing/", views.NowPlayingPartialView.as_view(), name="now-playing-partial"),     path("calendar/", views.ScrobbleCalendarView.as_view(), name="calendar"),     path("search/", views.ScrobbleSearchView.as_view(), name="search"),     path("status/", views.ScrobbleStatusView.as_view(), name="status"),diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.pyindex 7b2c589..c212e07 100644--- a/vrobbler/apps/scrobbles/views.py+++ b/vrobbler/apps/scrobbles/views.py@@ -361,6 +361,25 @@ class RecentScrobbleList(ListView):         return Scrobble.objects.all().order_by("-timestamp")  +class NowPlayingPartialView(LoginRequiredMixin, TemplateView):+    template_name = "scrobbles/_now_playing.html"++    def get_context_data(self, **kwargs):+        ctx = super().get_context_data(**kwargs)+        from scrobbles.constants import EXCLUDE_FROM_NOW_PLAYING++        ctx["now_playing_list"] = list(+            Scrobble.objects.filter(+                in_progress=True,+                is_paused=False,+                user=self.request.user,+            )+            .exclude(media_type__in=EXCLUDE_FROM_NOW_PLAYING)+            .select_related("track", "video", "podcast_episode")+        )+        return ctx++ class ScrobbleListView(LoginRequiredMixin, ListView):     model = Scrobble     paginate_by = 100diff --git a/vrobbler/apps/trends/migrations/0003_alter_trendresult_period.py b/vrobbler/apps/trends/migrations/0003_alter_trendresult_period.pynew file mode 100644index 0000000..4b11100--- /dev/null+++ b/vrobbler/apps/trends/migrations/0003_alter_trendresult_period.py@@ -0,0 +1,29 @@+# Generated by Django 4.2.29 on 2026-06-22 02:44++from django.db import migrations, models+++class Migration(migrations.Migration):++    dependencies = [+        (+            "trends",+            "0002_alter_trendresult_unique_together_trendresult_period_and_more",+        ),+    ]++    operations = [+        migrations.AlterField(+            model_name="trendresult",+            name="period",+            field=models.CharField(+                choices=[+                    ("last_30", "Last 30 days"),+                    ("last_90", "Last 90 days"),+                    ("last_year", "Last year"),+                ],+                default="last_30",+                max_length=20,+            ),+        ),+    ]diff --git a/vrobbler/templates/base.html b/vrobbler/templates/base.htmlindex 450ee9a..d839749 100644--- a/vrobbler/templates/base.html+++ b/vrobbler/templates/base.html@@ -311,26 +311,13 @@                         {% endblock %}                          {% if now_playing_list and user.is_authenticated %}-                        <ul>-                            <b>Now playing</b>-                            {% for scrobble in now_playing_list %}-                            <div class="now-playing">-                                {% if scrobble.media_obj.primary_image_url %}<div style="float:left;padding-right:10px;padding-bottom:10px;"><img src="{{scrobble.media_obj.primary_image_url}}" /></div>{% endif %}-                                <p><a href="{{scrobble.get_absolute_url}}">{{scrobble.media_obj}}</a></p>-                                {% if scrobble.logdata %}{% if scrobble.logdata.title%}<p><em>{{scrobble.logdata.title}}</em></p>{% endif %}{% endif %}-                                <p><small>{{scrobble.local_timestamp|naturaltime}} from {{scrobble.source}}</small></p>-                                <div class="progress-bar" style="margin-right:5px;">-                                    <span class="progress-bar-fill" style="width: {{scrobble.percent_played}}%;"></span>-                                </div>-                                <p class="action-buttons">-                                    <a href="{% url "scrobbles:cancel" scrobble.id %}">Cancel</a>-                                    <a class="right" href="{% url "scrobbles:finish" scrobble.id %}">Finish</a>-                                </p>-                                {% if not forloop.last %}<hr/>{% endif %}-                            </div>-                            {% endfor %}-                        </ul>-                        {% if now_playing_list|length > 1 %}<hr/>{% endif %}+                        {% if user.profile.live_now_playing %}+                        <div id="now-playing-container" hx-get="{% url 'scrobbles:now-playing-partial' %}" hx-trigger="every 7s" hx-swap="innerHTML">+                            {% include "scrobbles/_now_playing.html" %}+                        </div>+                        {% else %}+                        {% include "scrobbles/_now_playing.html" %}+                        {% endif %}                         {% endif %}                          {% if active_imports %}diff --git a/vrobbler/templates/scrobbles/_now_playing.html b/vrobbler/templates/scrobbles/_now_playing.htmlnew file mode 100644index 0000000..f6b023b--- /dev/null+++ b/vrobbler/templates/scrobbles/_now_playing.html@@ -0,0 +1,21 @@+{% load humanize %}+<ul>+    <b>Now playing</b>+    {% for scrobble in now_playing_list %}+    <div class="now-playing">+        {% if scrobble.media_obj.primary_image_url %}<div style="float:left;padding-right:10px;padding-bottom:10px;"><img src="{{scrobble.media_obj.primary_image_url}}" /></div>{% endif %}+        <p><a href="{{scrobble.get_absolute_url}}">{{scrobble.media_obj}}</a></p>+        {% if scrobble.logdata %}{% if scrobble.logdata.title%}<p><em>{{scrobble.logdata.title}}</em></p>{% endif %}{% endif %}+        <p><small>{{scrobble.local_timestamp|naturaltime}} from {{scrobble.source}}</small></p>+        <div class="progress-bar" style="margin-right:5px;">+            <span class="progress-bar-fill" style="width: {{scrobble.percent_played}}%;"></span>+        </div>+        <p class="action-buttons">+            <a href="{% url "scrobbles:cancel" scrobble.id %}">Cancel</a>+            <a class="right" href="{% url "scrobbles:finish" scrobble.id %}">Finish</a>+        </p>+        {% if not forloop.last %}<hr/>{% endif %}+    </div>+    {% endfor %}+</ul>+{% if now_playing_list|length > 1 %}<hr/>{% endif %}