[templates] Add HTMX support to Now Playing
This commit is contained in:
@ -88,7 +88,7 @@ fetching and simple saving.
|
|||||||
*** Metadata sources
|
*** Metadata sources
|
||||||
**** Scraper
|
**** 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:
|
** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :bug:music:scrobbles:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:ID: 702462cf-d54b-48c6-8a7c-78b8de751deb
|
: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:
|
** 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:
|
:PROPERTIES:
|
||||||
:ID: 5f5631fc-9ee1-d5a5-d0f8-94fea6fbbfa4
|
:ID: 5f5631fc-9ee1-d5a5-d0f8-94fea6fbbfa4
|
||||||
:END:
|
:END:
|
||||||
|
|||||||
@ -40,6 +40,7 @@ class UserProfileForm(forms.ModelForm):
|
|||||||
"enable_public_widgets",
|
"enable_public_widgets",
|
||||||
"widget_custom_css",
|
"widget_custom_css",
|
||||||
"home_scrobble_limit",
|
"home_scrobble_limit",
|
||||||
|
"live_now_playing",
|
||||||
"weigh_in_units",
|
"weigh_in_units",
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
|
|||||||
@ -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),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -98,6 +98,8 @@ class UserProfile(TimeStampedModel):
|
|||||||
|
|
||||||
home_scrobble_limit = models.IntegerField(default=20)
|
home_scrobble_limit = models.IntegerField(default=20)
|
||||||
|
|
||||||
|
live_now_playing = models.BooleanField(default=False)
|
||||||
|
|
||||||
weigh_in_units = models.CharField(
|
weigh_in_units = models.CharField(
|
||||||
max_length=16,
|
max_length=16,
|
||||||
choices=WeighUnit.choices,
|
choices=WeighUnit.choices,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ from tasks.webhooks import EmacsWebhookView, TodoistWebhookView
|
|||||||
app_name = "scrobbles"
|
app_name = "scrobbles"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path("now-playing/", views.NowPlayingPartialView.as_view(), name="now-playing-partial"),
|
||||||
path("calendar/", views.ScrobbleCalendarView.as_view(), name="calendar"),
|
path("calendar/", views.ScrobbleCalendarView.as_view(), name="calendar"),
|
||||||
path("search/", views.ScrobbleSearchView.as_view(), name="search"),
|
path("search/", views.ScrobbleSearchView.as_view(), name="search"),
|
||||||
path("status/", views.ScrobbleStatusView.as_view(), name="status"),
|
path("status/", views.ScrobbleStatusView.as_view(), name="status"),
|
||||||
|
|||||||
@ -361,6 +361,25 @@ class RecentScrobbleList(ListView):
|
|||||||
return Scrobble.objects.all().order_by("-timestamp")
|
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):
|
class ScrobbleListView(LoginRequiredMixin, ListView):
|
||||||
model = Scrobble
|
model = Scrobble
|
||||||
paginate_by = 100
|
paginate_by = 100
|
||||||
|
|||||||
@ -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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -311,26 +311,13 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% if now_playing_list and user.is_authenticated %}
|
{% if now_playing_list and user.is_authenticated %}
|
||||||
<ul>
|
{% if user.profile.live_now_playing %}
|
||||||
<b>Now playing</b>
|
<div id="now-playing-container" hx-get="{% url 'scrobbles:now-playing-partial' %}" hx-trigger="every 7s" hx-swap="innerHTML">
|
||||||
{% for scrobble in now_playing_list %}
|
{% include "scrobbles/_now_playing.html" %}
|
||||||
<div class="now-playing">
|
</div>
|
||||||
{% 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 %}
|
{% else %}
|
||||||
<p><a href="{{scrobble.get_absolute_url}}">{{scrobble.media_obj}}</a></p>
|
{% include "scrobbles/_now_playing.html" %}
|
||||||
{% if scrobble.logdata %}{% if scrobble.logdata.title%}<p><em>{{scrobble.logdata.title}}</em></p>{% endif %}{% 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 %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if active_imports %}
|
{% if active_imports %}
|
||||||
|
|||||||
21
vrobbler/templates/scrobbles/_now_playing.html
Normal file
21
vrobbler/templates/scrobbles/_now_playing.html
Normal file
@ -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 %}
|
||||||
Reference in New Issue
Block a user