feat: unify listening widget with Funkwhale + Last.fm sources
Show 2 recent tracks from each source (4 total) instead of only Funkwhale. Removed stats section — users can visit /listening/ for full statistics. Now Playing indicator works from either source.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{# Funkwhale Now Playing Widget #}
|
{# Listening Widget — combined Funkwhale + Last.fm recent tracks #}
|
||||||
{% if funkwhaleActivity and (funkwhaleActivity.nowPlaying or funkwhaleActivity.stats) %}
|
{% set hasListening = (funkwhaleActivity and (funkwhaleActivity.nowPlaying or funkwhaleActivity.listenings.length)) or (lastfmActivity and (lastfmActivity.nowPlaying or lastfmActivity.scrobbles.length)) %}
|
||||||
<is-land on:visible>
|
{% if hasListening %}
|
||||||
<div class="widget">
|
<div class="widget">
|
||||||
<h3 class="widget-title flex items-center gap-2">
|
<h3 class="widget-title flex items-center gap-2">
|
||||||
<svg class="w-5 h-5 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="w-5 h-5 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
@@ -9,10 +9,15 @@
|
|||||||
Listening
|
Listening
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{# Now Playing / Recently Played #}
|
{# Now Playing — show if either source is actively playing #}
|
||||||
{% if funkwhaleActivity.nowPlaying and funkwhaleActivity.nowPlaying.track %}
|
{% set fwNow = funkwhaleActivity.nowPlaying if funkwhaleActivity and funkwhaleActivity.nowPlaying and funkwhaleActivity.nowPlaying.status == 'now-playing' else null %}
|
||||||
<div class="{% if funkwhaleActivity.nowPlaying.status == 'now-playing' %}bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800{% else %}bg-surface-50 dark:bg-surface-800{% endif %} rounded-lg p-3 mb-3">
|
{% set lfmNow = lastfmActivity.nowPlaying if lastfmActivity and lastfmActivity.nowPlaying and lastfmActivity.nowPlaying.status == 'now-playing' else null %}
|
||||||
{% if funkwhaleActivity.nowPlaying.status == 'now-playing' %}
|
|
||||||
|
{% if fwNow or lfmNow %}
|
||||||
|
{% set np = fwNow or lfmNow %}
|
||||||
|
{% set npSource = "Funkwhale" if fwNow else "Last.fm" %}
|
||||||
|
{% set npColor = "purple" if fwNow else "red" %}
|
||||||
|
<div class="bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg p-3 mb-3">
|
||||||
<div class="flex items-center gap-1.5 text-xs text-green-600 dark:text-green-400 mb-2">
|
<div class="flex items-center gap-1.5 text-xs text-green-600 dark:text-green-400 mb-2">
|
||||||
<span class="flex gap-0.5 items-end h-2.5">
|
<span class="flex gap-0.5 items-end h-2.5">
|
||||||
<span class="w-0.5 bg-green-500 animate-pulse" style="height: 30%;"></span>
|
<span class="w-0.5 bg-green-500 animate-pulse" style="height: 30%;"></span>
|
||||||
@@ -20,54 +25,89 @@
|
|||||||
<span class="w-0.5 bg-green-500 animate-pulse" style="height: 50%; animation-delay: 0.4s;"></span>
|
<span class="w-0.5 bg-green-500 animate-pulse" style="height: 50%; animation-delay: 0.4s;"></span>
|
||||||
</span>
|
</span>
|
||||||
Now Playing
|
Now Playing
|
||||||
|
<span class="text-{{ npColor }}-600 dark:text-{{ npColor }}-400 ml-1">({{ npSource }})</span>
|
||||||
</div>
|
</div>
|
||||||
{% elif funkwhaleActivity.nowPlaying.status == 'recently-played' %}
|
|
||||||
<div class="text-xs text-surface-500 mb-2">Recently Played</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
{% if funkwhaleActivity.nowPlaying.coverUrl %}
|
{% if np.coverUrl %}
|
||||||
<img src="{{ funkwhaleActivity.nowPlaying.coverUrl }}" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
|
<img src="{{ np.coverUrl }}" alt="" class="w-10 h-10 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<p class="font-medium text-sm text-surface-900 dark:text-surface-100 truncate">
|
<p class="font-medium text-sm text-surface-900 dark:text-surface-100 truncate">
|
||||||
{% if funkwhaleActivity.nowPlaying.trackUrl %}
|
{% if np.trackUrl %}
|
||||||
<a href="{{ funkwhaleActivity.nowPlaying.trackUrl }}" class="hover:text-primary-600 dark:hover:text-primary-400" target="_blank" rel="noopener">
|
<a href="{{ np.trackUrl }}" class="hover:text-primary-600 dark:hover:text-primary-400" target="_blank" rel="noopener">{{ np.track }}</a>
|
||||||
{{ funkwhaleActivity.nowPlaying.track }}
|
|
||||||
</a>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ funkwhaleActivity.nowPlaying.track }}
|
{{ np.track }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs text-surface-600 dark:text-surface-400 truncate">{{ funkwhaleActivity.nowPlaying.artist }}</p>
|
<p class="text-xs text-surface-600 dark:text-surface-400 truncate">{{ np.artist }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# Quick Stats #}
|
{# Recent tracks — 2 from each source #}
|
||||||
{% if funkwhaleActivity.stats and funkwhaleActivity.stats.summary %}
|
<ul class="space-y-2">
|
||||||
{% set stats = funkwhaleActivity.stats.summary.all %}
|
{% if funkwhaleActivity and funkwhaleActivity.listenings.length %}
|
||||||
<div class="grid grid-cols-3 gap-2 text-center mb-3">
|
{% for listening in funkwhaleActivity.listenings | head(2) %}
|
||||||
<div class="p-2 bg-surface-50 dark:bg-surface-800 rounded">
|
<li class="flex items-center gap-2">
|
||||||
<span class="text-lg font-bold text-primary-600 dark:text-primary-400 block">{{ stats.totalPlays or 0 }}</span>
|
{% if listening.coverUrl %}
|
||||||
<span class="text-[10px] text-surface-500 uppercase">plays</span>
|
<img src="{{ listening.coverUrl }}" alt="" class="w-8 h-8 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
|
||||||
</div>
|
{% else %}
|
||||||
<div class="p-2 bg-surface-50 dark:bg-surface-800 rounded">
|
<div class="w-8 h-8 rounded bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center flex-shrink-0">
|
||||||
<span class="text-lg font-bold text-primary-600 dark:text-primary-400 block">{{ stats.uniqueArtists or 0 }}</span>
|
<svg class="w-4 h-4 text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<span class="text-[10px] text-surface-500 uppercase">artists</span>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19V6l12-3v13"/>
|
||||||
</div>
|
</svg>
|
||||||
<div class="p-2 bg-surface-50 dark:bg-surface-800 rounded">
|
</div>
|
||||||
<span class="text-lg font-bold text-primary-600 dark:text-primary-400 block">{{ stats.totalDurationFormatted or '0m' }}</span>
|
{% endif %}
|
||||||
<span class="text-[10px] text-surface-500 uppercase">listened</span>
|
<div class="min-w-0 flex-1">
|
||||||
</div>
|
<p class="text-sm text-surface-900 dark:text-surface-100 truncate">
|
||||||
</div>
|
{% if listening.trackUrl %}
|
||||||
{% endif %}
|
<a href="{{ listening.trackUrl }}" class="hover:text-purple-600 dark:hover:text-purple-400" target="_blank" rel="noopener">{{ listening.track }}</a>
|
||||||
|
{% else %}
|
||||||
|
{{ listening.track }}
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-surface-500 truncate">{{ listening.artist }}
|
||||||
|
<span class="text-purple-500 ml-1">Funkwhale</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<a href="/listening/" class="text-sm text-primary-600 dark:text-primary-400 hover:underline flex items-center gap-1">
|
{% if lastfmActivity and lastfmActivity.scrobbles.length %}
|
||||||
|
{% for scrobble in lastfmActivity.scrobbles | head(2) %}
|
||||||
|
<li class="flex items-center gap-2">
|
||||||
|
{% if scrobble.coverUrl %}
|
||||||
|
<img src="{{ scrobble.coverUrl }}" alt="" class="w-8 h-8 rounded object-cover flex-shrink-0" loading="lazy" eleventy:ignore>
|
||||||
|
{% else %}
|
||||||
|
<div class="w-8 h-8 rounded bg-red-100 dark:bg-red-900/30 flex items-center justify-center flex-shrink-0">
|
||||||
|
<svg class="w-4 h-4 text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19V6l12-3v13"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="min-w-0 flex-1">
|
||||||
|
<p class="text-sm text-surface-900 dark:text-surface-100 truncate">
|
||||||
|
{% if scrobble.trackUrl %}
|
||||||
|
<a href="{{ scrobble.trackUrl }}" class="hover:text-red-600 dark:hover:text-red-400" target="_blank" rel="noopener">{{ scrobble.track }}</a>
|
||||||
|
{% else %}
|
||||||
|
{{ scrobble.track }}
|
||||||
|
{% endif %}
|
||||||
|
{% if scrobble.loved %}<span class="text-red-500 ml-0.5">♥</span>{% endif %}
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-surface-500 truncate">{{ scrobble.artist }}
|
||||||
|
<span class="text-red-500 ml-1">Last.fm</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a href="/listening/" class="text-sm text-primary-600 dark:text-primary-400 hover:underline flex items-center gap-1 mt-3">
|
||||||
View full listening history
|
View full listening history
|
||||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</is-land>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Reference in New Issue
Block a user