Files
svemagie 02f13db22c feat: convert Funkwhale/Last.fm to client-side Alpine.js
Replaces build-time Eleventy data fetches with live client-side fetches
so listening data is always current without requiring a blog rebuild.

- Add js/listening.js with three Alpine.data components:
  listeningWidget, funkwhalePage, listeningPage
- Replace _data/funkwhaleActivity.js and lastfmActivity.js with sync
  stubs (source: 'indiekit') — keeps slashes.njk links and widget
  guard working at build time
- Rewrite widgets/funkwhale.njk, funkwhale.njk, listening.njk as
  Alpine-driven templates with loading skeletons and error states
- Load listening.js globally in base.njk before Alpine core

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 08:23:05 +02:00

365 lines
23 KiB
Plaintext

---
layout: layouts/base.njk
title: Listening Activity
permalink: /listening/
withSidebar: true
---
<div class="listening-page" x-data="listeningPage()" x-init="init()">
<header class="mb-6 sm:mb-8">
<h1 class="text-2xl sm:text-3xl md:text-4xl font-bold text-surface-900 dark:text-surface-100 mb-2">Listening Activity</h1>
<p class="text-surface-600 dark:text-surface-400">What I've been listening to.</p>
</header>
{# Source Filter Tabs #}
<div class="flex gap-2 mb-8 flex-wrap">
<button
@click="activeSource = 'all'"
:class="activeSource === 'all' ? 'bg-purple-600 text-white' : 'bg-surface-100 dark:bg-surface-800 text-surface-700 dark:text-surface-300 hover:bg-surface-200 dark:hover:bg-surface-700'"
class="px-4 py-2 rounded-full text-sm font-medium transition-colors"
>All Sources</button>
<button
@click="activeSource = 'funkwhale'"
:class="activeSource === 'funkwhale' ? 'bg-purple-600 text-white' : 'bg-surface-100 dark:bg-surface-800 text-surface-700 dark:text-surface-300 hover:bg-surface-200 dark:hover:bg-surface-700'"
class="px-4 py-2 rounded-full text-sm font-medium transition-colors flex items-center gap-2"
><span class="w-2 h-2 rounded-full bg-purple-500"></span>Funkwhale</button>
<button
@click="activeSource = 'lastfm'"
:class="activeSource === 'lastfm' ? 'bg-red-600 text-white' : 'bg-surface-100 dark:bg-surface-800 text-surface-700 dark:text-surface-300 hover:bg-surface-200 dark:hover:bg-surface-700'"
class="px-4 py-2 rounded-full text-sm font-medium transition-colors flex items-center gap-2"
><span class="w-2 h-2 rounded-full bg-red-500"></span>Last.fm</button>
</div>
{# Loading skeleton #}
<div x-show="loading" class="space-y-4 animate-pulse">
<div class="h-32 bg-surface-200 dark:bg-surface-700 rounded-xl"></div>
<div class="h-40 bg-surface-200 dark:bg-surface-700 rounded-xl"></div>
<div class="space-y-3">
<div class="h-16 bg-surface-200 dark:bg-surface-700 rounded-lg"></div>
<div class="h-16 bg-surface-200 dark:bg-surface-700 rounded-lg"></div>
<div class="h-16 bg-surface-200 dark:bg-surface-700 rounded-lg"></div>
</div>
</div>
{# Now Playing — Funkwhale #}
<template x-if="!loading && fwNowPlaying && (activeSource === 'all' || activeSource === 'funkwhale')">
<section class="mb-6">
<div class="relative p-4 sm:p-6 rounded-xl sm:rounded-2xl overflow-hidden"
:class="fwNowPlaying.status === 'now-playing'
? 'bg-gradient-to-br from-green-500/10 to-green-600/5 border-2 border-green-500/30'
: 'bg-gradient-to-br from-purple-500/10 to-purple-600/5 border border-purple-500/20'">
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-4 sm:gap-5">
<template x-if="fwNowPlaying.coverUrl">
<img :src="fwNowPlaying.coverUrl" alt="" class="w-20 h-20 sm:w-24 sm:h-24 rounded-lg shadow-lg object-cover flex-shrink-0" loading="lazy">
</template>
<template x-if="!fwNowPlaying.coverUrl">
<div class="w-20 h-20 sm:w-24 sm:h-24 rounded-lg bg-surface-200 dark:bg-surface-700 flex items-center justify-center flex-shrink-0">
<svg class="w-8 h-8 sm:w-10 sm:h-10 text-surface-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"/>
</svg>
</div>
</template>
<div class="flex-1 min-w-0 w-full sm:w-auto">
<div class="flex items-center gap-2 mb-2">
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-purple-500/20 text-purple-700 dark:text-purple-400 rounded-full">Funkwhale</span>
<template x-if="fwNowPlaying.status === 'now-playing'">
<span class="inline-flex items-center gap-1.5 px-2 py-1 text-xs font-medium bg-purple-500/20 text-purple-700 dark:text-purple-400 rounded-full">
<span class="flex gap-0.5 items-end h-3">
<span class="w-0.5 bg-purple-500 animate-pulse" style="height: 30%;"></span>
<span class="w-0.5 bg-purple-500 animate-pulse" style="height: 70%; animation-delay: 0.2s;"></span>
<span class="w-0.5 bg-purple-500 animate-pulse" style="height: 50%; animation-delay: 0.4s;"></span>
</span>
Now Playing
</span>
</template>
<template x-if="fwNowPlaying.status !== 'now-playing'">
<span class="inline-flex items-center gap-1.5 px-2 py-1 text-xs font-medium bg-purple-500/20 text-purple-700 dark:text-purple-400 rounded-full">Recently Played</span>
</template>
</div>
<h2 class="text-lg sm:text-xl font-bold text-surface-900 dark:text-surface-100 truncate">
<template x-if="fwNowPlaying.trackUrl">
<a :href="fwNowPlaying.trackUrl" class="hover:text-purple-600 dark:hover:text-purple-400" target="_blank" rel="noopener" x-text="fwNowPlaying.track"></a>
</template>
<template x-if="!fwNowPlaying.trackUrl"><span x-text="fwNowPlaying.track"></span></template>
</h2>
<p class="text-surface-600 dark:text-surface-400" x-text="fwNowPlaying.artist"></p>
<p x-show="fwNowPlaying.album" class="text-sm text-surface-600 dark:text-surface-400 mt-1" x-text="fwNowPlaying.album"></p>
<p class="text-xs text-surface-600 dark:text-surface-400 mt-2" x-text="fwNowPlaying.relativeTime"></p>
</div>
</div>
</div>
</section>
</template>
{# Now Playing — Last.fm #}
<template x-if="!loading && lfmNowPlaying && (activeSource === 'all' || activeSource === 'lastfm')">
<section class="mb-6">
<div class="relative p-4 sm:p-6 rounded-xl sm:rounded-2xl overflow-hidden"
:class="lfmNowPlaying.status === 'now-playing'
? 'bg-gradient-to-br from-green-500/10 to-green-600/5 border-2 border-green-500/30'
: 'bg-gradient-to-br from-red-500/10 to-red-600/5 border border-red-500/20'">
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-4 sm:gap-5">
<template x-if="lfmNowPlaying.coverUrl">
<img :src="lfmNowPlaying.coverUrl" alt="" class="w-20 h-20 sm:w-24 sm:h-24 rounded-lg shadow-lg object-cover flex-shrink-0" loading="lazy">
</template>
<template x-if="!lfmNowPlaying.coverUrl">
<div class="w-20 h-20 sm:w-24 sm:h-24 rounded-lg bg-surface-200 dark:bg-surface-700 flex items-center justify-center flex-shrink-0">
<svg class="w-8 h-8 sm:w-10 sm:h-10 text-surface-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"/>
</svg>
</div>
</template>
<div class="flex-1 min-w-0 w-full sm:w-auto">
<div class="flex items-center gap-2 mb-2">
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-red-500/20 text-red-700 dark:text-red-400 rounded-full">Last.fm</span>
<template x-if="lfmNowPlaying.status === 'now-playing'">
<span class="inline-flex items-center gap-1.5 px-2 py-1 text-xs font-medium bg-red-500/20 text-red-700 dark:text-red-400 rounded-full">
<span class="flex gap-0.5 items-end h-3">
<span class="w-0.5 bg-red-500 animate-pulse" style="height: 30%;"></span>
<span class="w-0.5 bg-red-500 animate-pulse" style="height: 70%; animation-delay: 0.2s;"></span>
<span class="w-0.5 bg-red-500 animate-pulse" style="height: 50%; animation-delay: 0.4s;"></span>
</span>
Now Playing
</span>
</template>
<template x-if="lfmNowPlaying.status !== 'now-playing'">
<span class="inline-flex items-center gap-1.5 px-2 py-1 text-xs font-medium bg-red-500/20 text-red-700 dark:text-red-400 rounded-full">Recently Played</span>
</template>
<template x-if="lfmNowPlaying.loved">
<span class="text-red-500" title="Loved">&#9829;</span>
</template>
</div>
<h2 class="text-lg sm:text-xl font-bold text-surface-900 dark:text-surface-100 truncate">
<template x-if="lfmNowPlaying.trackUrl">
<a :href="lfmNowPlaying.trackUrl" class="hover:text-red-600 dark:hover:text-red-400" target="_blank" rel="noopener" x-text="lfmNowPlaying.track"></a>
</template>
<template x-if="!lfmNowPlaying.trackUrl"><span x-text="lfmNowPlaying.track"></span></template>
</h2>
<p class="text-surface-600 dark:text-surface-400" x-text="lfmNowPlaying.artist"></p>
<p x-show="lfmNowPlaying.album" class="text-sm text-surface-600 dark:text-surface-400 mt-1" x-text="lfmNowPlaying.album"></p>
<p class="text-xs text-surface-600 dark:text-surface-400 mt-2" x-text="lfmNowPlaying.relativeTime"></p>
</div>
</div>
</div>
</section>
</template>
{# Combined Stats Section #}
<template x-if="!loading && (fw.stats || lfm.stats)">
<section class="mb-12">
<h2 class="text-xl sm:text-2xl font-bold text-surface-900 dark:text-surface-100 mb-4 sm:mb-6 flex items-center gap-2">
<svg class="w-6 h-6 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
</svg>
Listening Statistics
</h2>
<div class="grid gap-4 sm:gap-6 md:grid-cols-2">
{# Funkwhale Stats Card #}
<template x-if="fw.stats && (activeSource === 'all' || activeSource === 'funkwhale')">
<div class="bg-surface-50 dark:bg-surface-800 rounded-xl p-6 border border-purple-200 dark:border-purple-800 shadow-sm">
<h3 class="text-lg font-semibold text-purple-700 dark:text-purple-400 mb-4 flex items-center gap-2">
<span class="w-3 h-3 rounded-full bg-purple-500"></span>Funkwhale
</h3>
<div class="grid grid-cols-3 gap-4 text-center">
<div>
<div class="text-2xl font-bold text-surface-900 dark:text-surface-100" x-text="fwStatsAll.totalPlays || 0"></div>
<div class="text-xs text-surface-600 dark:text-surface-400 uppercase">Plays</div>
</div>
<div>
<div class="text-2xl font-bold text-surface-900 dark:text-surface-100" x-text="fwStatsAll.uniqueArtists || 0"></div>
<div class="text-xs text-surface-600 dark:text-surface-400 uppercase">Artists</div>
</div>
<div>
<div class="text-2xl font-bold text-surface-900 dark:text-surface-100" x-text="fwStatsAll.uniqueTracks || 0"></div>
<div class="text-xs text-surface-600 dark:text-surface-400 uppercase">Tracks</div>
</div>
</div>
<template x-if="fwTopArtists.length">
<div class="mt-4 pt-4 border-t border-surface-200 dark:border-surface-700">
<h4 class="text-sm font-medium text-surface-700 dark:text-surface-300 mb-2">Top Artists</h4>
<div class="space-y-1">
<template x-for="artist in fwTopArtists" :key="artist.name">
<div class="flex justify-between text-sm">
<span class="text-surface-600 dark:text-surface-400 truncate" x-text="artist.name"></span>
<span class="text-surface-600 dark:text-surface-400 ml-2" x-text="artist.playCount"></span>
</div>
</template>
</div>
</div>
</template>
</div>
</template>
{# Last.fm Stats Card #}
<template x-if="lfm.stats && (activeSource === 'all' || activeSource === 'lastfm')">
<div class="bg-surface-50 dark:bg-surface-800 rounded-xl p-6 border border-red-200 dark:border-red-800 shadow-sm">
<h3 class="text-lg font-semibold text-red-700 dark:text-red-400 mb-4 flex items-center gap-2">
<span class="w-3 h-3 rounded-full bg-red-500"></span>Last.fm
</h3>
<div class="grid grid-cols-3 gap-4 text-center">
<div>
<div class="text-2xl font-bold text-surface-900 dark:text-surface-100" x-text="lfmStatsAll.totalPlays || 0"></div>
<div class="text-xs text-surface-600 dark:text-surface-400 uppercase">Scrobbles</div>
</div>
<div>
<div class="text-2xl font-bold text-surface-900 dark:text-surface-100" x-text="lfmStatsAll.uniqueArtists || 0"></div>
<div class="text-xs text-surface-600 dark:text-surface-400 uppercase">Artists</div>
</div>
<div>
<div class="text-2xl font-bold text-surface-900 dark:text-surface-100" x-text="lfmStatsAll.lovedCount || 0"></div>
<div class="text-xs text-surface-600 dark:text-surface-400 uppercase">Loved</div>
</div>
</div>
<template x-if="lfmTopArtists.length">
<div class="mt-4 pt-4 border-t border-surface-200 dark:border-surface-700">
<h4 class="text-sm font-medium text-surface-700 dark:text-surface-300 mb-2">Top Artists</h4>
<div class="space-y-1">
<template x-for="artist in lfmTopArtists" :key="artist.name">
<div class="flex justify-between text-sm">
<span class="text-surface-600 dark:text-surface-400 truncate" x-text="artist.name"></span>
<span class="text-surface-600 dark:text-surface-400 ml-2" x-text="artist.playCount"></span>
</div>
</template>
</div>
</div>
</template>
</div>
</template>
</div>
</section>
</template>
{# Combined Recent Listens Timeline #}
<section class="mb-12">
<h2 class="text-xl sm:text-2xl font-bold text-surface-900 dark:text-surface-100 mb-4 sm:mb-6 flex items-center gap-2">
<svg class="w-6 h-6 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
Recent Listens
</h2>
<div class="space-y-3">
<template x-if="!loading && combinedListens.length">
<template x-for="item in combinedListens.filter(i => activeSource === 'all' || i._source === activeSource)" :key="item._ts + item.track">
<div class="flex items-center gap-4 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 hover:border-purple-400 dark:hover:border-purple-600 transition-colors shadow-sm">
<template x-if="item.coverUrl">
<img :src="item.coverUrl" alt="" class="w-12 h-12 rounded object-cover flex-shrink-0" loading="lazy">
</template>
<template x-if="!item.coverUrl">
<div class="w-12 h-12 rounded bg-surface-200 dark:bg-surface-700 flex items-center justify-center flex-shrink-0">
<svg class="w-6 h-6 text-surface-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2z"/>
</svg>
</div>
</template>
<div class="flex-1 min-w-0">
<h3 class="font-medium text-surface-900 dark:text-surface-100 truncate">
<template x-if="item.trackUrl">
<a :href="item.trackUrl" class="hover:text-purple-600 dark:hover:text-purple-400" target="_blank" rel="noopener" x-text="item.track"></a>
</template>
<template x-if="!item.trackUrl"><span x-text="item.track"></span></template>
<template x-if="item.favorite || item.loved">
<span class="text-purple-500 ml-1" :title="item._source === 'funkwhale' ? 'Favorite' : 'Loved'">&#9829;</span>
</template>
</h3>
<p class="text-sm text-surface-600 dark:text-surface-400 truncate" x-text="item.artist"></p>
</div>
<div class="text-right flex-shrink-0">
<span class="inline-block px-2 py-0.5 text-xs font-medium rounded-full mb-1"
:class="item._source === 'funkwhale' ? 'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-400' : 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400'"
x-text="item._source === 'funkwhale' ? 'Funkwhale' : 'Last.fm'"></span>
<span class="text-xs text-surface-600 dark:text-surface-400 block" x-text="item.relativeTime"></span>
<template x-if="item.trackUrl">
<button
class="share-post-btn mt-1"
:data-share-url="item.trackUrl"
:data-share-title="item.track + ' — ' + item.artist"
title="Create post"
aria-label="Create post"
><span class="share-post-icon">✏️</span></button>
</template>
</div>
</div>
</template>
</template>
<p x-show="!loading && !combinedListens.length" class="text-surface-600 dark:text-surface-400">No recent listening history available.</p>
</div>
</section>
{# Loved Tracks — Last.fm #}
<template x-if="!loading && lfm.loved.length && (activeSource === 'all' || activeSource === 'lastfm')">
<section class="mb-12">
<h2 class="text-xl sm:text-2xl font-bold text-surface-900 dark:text-surface-100 mb-4 sm:mb-6 flex items-center gap-2">
<svg class="w-6 h-6 text-red-500" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
</svg>
Loved Tracks <span class="text-sm font-normal text-surface-600 dark:text-surface-400">(Last.fm)</span>
</h2>
<div class="grid gap-3 sm:gap-4 md:grid-cols-2">
<template x-for="track in lfm.loved.slice(0,10)" :key="track.track + track.artist">
<div class="flex items-center gap-3 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm">
<template x-if="track.coverUrl">
<img :src="track.coverUrl" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy">
</template>
<template x-if="!track.coverUrl">
<div class="w-14 h-14 rounded bg-surface-200 dark:bg-surface-700 flex items-center justify-center flex-shrink-0">
<svg class="w-6 h-6 text-red-400" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
</svg>
</div>
</template>
<div class="flex-1 min-w-0">
<h3 class="font-medium text-surface-900 dark:text-surface-100 truncate">
<template x-if="track.trackUrl">
<a :href="track.trackUrl" class="hover:text-red-600 dark:hover:text-red-400" target="_blank" rel="noopener" x-text="track.track"></a>
</template>
<template x-if="!track.trackUrl"><span x-text="track.track"></span></template>
</h3>
<p class="text-sm text-surface-600 dark:text-surface-400 truncate" x-text="track.artist"></p>
</div>
<span class="text-red-500 flex-shrink-0">&#9829;</span>
</div>
</template>
</div>
</section>
</template>
{# Favorites — Funkwhale #}
<template x-if="!loading && fw.favorites.length && (activeSource === 'all' || activeSource === 'funkwhale')">
<section class="mb-12">
<h2 class="text-xl sm:text-2xl font-bold text-surface-900 dark:text-surface-100 mb-4 sm:mb-6 flex items-center gap-2">
<svg class="w-6 h-6 text-purple-500" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
</svg>
Favorite Tracks <span class="text-sm font-normal text-surface-600 dark:text-surface-400">(Funkwhale)</span>
</h2>
<div class="grid gap-3 sm:gap-4 md:grid-cols-2">
<template x-for="favorite in fw.favorites.slice(0,10)" :key="favorite.track + favorite.artist">
<div class="flex items-center gap-3 p-3 bg-surface-50 dark:bg-surface-800 rounded-lg border border-surface-200 dark:border-surface-700 shadow-sm">
<template x-if="favorite.coverUrl">
<img :src="favorite.coverUrl" alt="" class="w-14 h-14 rounded object-cover flex-shrink-0" loading="lazy">
</template>
<template x-if="!favorite.coverUrl">
<div class="w-14 h-14 rounded bg-surface-200 dark:bg-surface-700 flex items-center justify-center flex-shrink-0">
<svg class="w-6 h-6 text-purple-400" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
</svg>
</div>
</template>
<div class="flex-1 min-w-0">
<h3 class="font-medium text-surface-900 dark:text-surface-100 truncate">
<template x-if="favorite.trackUrl">
<a :href="favorite.trackUrl" class="hover:text-purple-600 dark:hover:text-purple-400" target="_blank" rel="noopener" x-text="favorite.track"></a>
</template>
<template x-if="!favorite.trackUrl"><span x-text="favorite.track"></span></template>
</h3>
<p class="text-sm text-surface-600 dark:text-surface-400 truncate" x-text="favorite.artist"></p>
<p x-show="favorite.album" class="text-xs text-surface-600 dark:text-surface-400 truncate" x-text="favorite.album"></p>
</div>
</div>
</template>
</div>
</section>
</template>
</div>